mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-03-12 18:16:55 -04:00
PoC: Add basic syscall example firmware
Adds a basic example firmware that copies an app to app RAM. The app triggers syscall interrupts and tries to execute ROM code from app mode. A make target (`tb_application_fpga_irqpoc_with_app`) that simulates a Tkey running the firmware is added.
This commit is contained in:
parent
e4d19e83ce
commit
a871d23d5d
@ -152,6 +152,10 @@ IRQPOC_LED_TOGGLE_OBJS = \
|
|||||||
$(P)/fw/irqpoc_led_toggle/main.o \
|
$(P)/fw/irqpoc_led_toggle/main.o \
|
||||||
$(P)/fw/irqpoc_led_toggle/start.o
|
$(P)/fw/irqpoc_led_toggle/start.o
|
||||||
|
|
||||||
|
IRQPOC_WITH_APP_OBJS = \
|
||||||
|
$(P)/fw/irqpoc_with_app/main.o \
|
||||||
|
$(P)/fw/irqpoc_with_app/start.o
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
# All: Complete build of HW and FW.
|
# All: Complete build of HW and FW.
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
@ -190,6 +194,7 @@ $(FIRMWARE_OBJS): $(FIRMWARE_DEPS)
|
|||||||
$(TESTFW_OBJS): $(FIRMWARE_DEPS)
|
$(TESTFW_OBJS): $(FIRMWARE_DEPS)
|
||||||
$(IRQPOC_OBJS): $(FIRMWARE_DEPS)
|
$(IRQPOC_OBJS): $(FIRMWARE_DEPS)
|
||||||
$(IRQPOC_LED_TOGGLE_OBJS): $(FIRMWARE_DEPS)
|
$(IRQPOC_LED_TOGGLE_OBJS): $(FIRMWARE_DEPS)
|
||||||
|
$(IRQPOC_WITH_APP_OBJS): $(FIRMWARE_DEPS)
|
||||||
|
|
||||||
firmware.elf: $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds
|
firmware.elf: $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds
|
||||||
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@
|
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@
|
||||||
@ -238,6 +243,9 @@ irqpoc.elf: $(IRQPOC_OBJS) $(P)/fw/tk1/firmware.lds
|
|||||||
irqpoc_led_toggle.elf: $(IRQPOC_LED_TOGGLE_OBJS) $(P)/fw/tk1/firmware.lds
|
irqpoc_led_toggle.elf: $(IRQPOC_LED_TOGGLE_OBJS) $(P)/fw/tk1/firmware.lds
|
||||||
$(CC) $(CFLAGS) $(IRQPOC_LED_TOGGLE_OBJS) $(LDFLAGS) -o $@
|
$(CC) $(CFLAGS) $(IRQPOC_LED_TOGGLE_OBJS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
irqpoc_with_app.elf: $(IRQPOC_WITH_APP_OBJS) $(P)/fw/tk1/firmware.lds
|
||||||
|
$(CC) $(CFLAGS) $(IRQPOC_WITH_APP_OBJS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
# Generate a fake BRAM file that will be filled in later after place-n-route
|
# Generate a fake BRAM file that will be filled in later after place-n-route
|
||||||
bram_fw.hex:
|
bram_fw.hex:
|
||||||
$(ICESTORM_PATH)icebram -v -g 32 $(BRAM_FW_SIZE) > $@
|
$(ICESTORM_PATH)icebram -v -g 32 $(BRAM_FW_SIZE) > $@
|
||||||
@ -250,6 +258,9 @@ testfw.hex: testfw.bin testfw_size_mismatch
|
|||||||
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
||||||
irqpoc.hex: irqpoc.bin
|
irqpoc.hex: irqpoc.bin
|
||||||
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
||||||
|
irqpoc_with_app.hex: irqpoc_with_app.bin
|
||||||
|
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
||||||
|
|
||||||
|
|
||||||
.PHONY: check-binary-hashes
|
.PHONY: check-binary-hashes
|
||||||
check-binary-hashes:
|
check-binary-hashes:
|
||||||
@ -465,6 +476,10 @@ emptyapp:
|
|||||||
tb_application_fpga_irqpoc: SIMFIRMWARE=irqpoc.hex
|
tb_application_fpga_irqpoc: SIMFIRMWARE=irqpoc.hex
|
||||||
tb_application_fpga_irqpoc: irqpoc.hex emptyapp tb_application_fpga
|
tb_application_fpga_irqpoc: irqpoc.hex emptyapp tb_application_fpga
|
||||||
|
|
||||||
|
.PHONY: tb_application_fpga_irqpoc_with_app
|
||||||
|
tb_application_fpga_irqpoc_with_app: SIMFIRMWARE=irqpoc_with_app.hex
|
||||||
|
tb_application_fpga_irqpoc_with_app: irqpoc_with_app.hex emptyapp tb_application_fpga
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
# FPGA device programming.
|
# FPGA device programming.
|
||||||
@ -514,6 +529,7 @@ clean_fw:
|
|||||||
rm -f $(TESTFW_OBJS)
|
rm -f $(TESTFW_OBJS)
|
||||||
rm -f $(IRQPOC_OBJS)
|
rm -f $(IRQPOC_OBJS)
|
||||||
rm -f $(IRQPOC_LED_TOGGLE_OBJS)
|
rm -f $(IRQPOC_LED_TOGGLE_OBJS)
|
||||||
|
rm -f $(IRQPOC_WITH_APP_OBJS)
|
||||||
rm -f qemu_firmware.elf
|
rm -f qemu_firmware.elf
|
||||||
.PHONY: clean_fw
|
.PHONY: clean_fw
|
||||||
|
|
||||||
|
9
hw/application_fpga/fw/irqpoc_with_app/Makefile
Normal file
9
hw/application_fpga/fw/irqpoc_with_app/Makefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# Uses ../.clang-format
|
||||||
|
FMTFILES=main.c
|
||||||
|
.PHONY: fmt
|
||||||
|
fmt:
|
||||||
|
clang-format --dry-run --ferror-limit=0 $(FMTFILES)
|
||||||
|
clang-format --verbose -i $(FMTFILES)
|
||||||
|
.PHONY: checkfmt
|
||||||
|
checkfmt:
|
||||||
|
clang-format --dry-run --ferror-limit=0 --Werror $(FMTFILES)
|
102
hw/application_fpga/fw/irqpoc_with_app/custom_ops.S
Normal file
102
hw/application_fpga/fw/irqpoc_with_app/custom_ops.S
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// This is free and unencumbered software released into the public domain.
|
||||||
|
//
|
||||||
|
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
// distribute this software, either in source code form or as a compiled
|
||||||
|
// binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
// means.
|
||||||
|
|
||||||
|
#define regnum_q0 0
|
||||||
|
#define regnum_q1 1
|
||||||
|
#define regnum_q2 2
|
||||||
|
#define regnum_q3 3
|
||||||
|
|
||||||
|
#define regnum_x0 0
|
||||||
|
#define regnum_x1 1
|
||||||
|
#define regnum_x2 2
|
||||||
|
#define regnum_x3 3
|
||||||
|
#define regnum_x4 4
|
||||||
|
#define regnum_x5 5
|
||||||
|
#define regnum_x6 6
|
||||||
|
#define regnum_x7 7
|
||||||
|
#define regnum_x8 8
|
||||||
|
#define regnum_x9 9
|
||||||
|
#define regnum_x10 10
|
||||||
|
#define regnum_x11 11
|
||||||
|
#define regnum_x12 12
|
||||||
|
#define regnum_x13 13
|
||||||
|
#define regnum_x14 14
|
||||||
|
#define regnum_x15 15
|
||||||
|
#define regnum_x16 16
|
||||||
|
#define regnum_x17 17
|
||||||
|
#define regnum_x18 18
|
||||||
|
#define regnum_x19 19
|
||||||
|
#define regnum_x20 20
|
||||||
|
#define regnum_x21 21
|
||||||
|
#define regnum_x22 22
|
||||||
|
#define regnum_x23 23
|
||||||
|
#define regnum_x24 24
|
||||||
|
#define regnum_x25 25
|
||||||
|
#define regnum_x26 26
|
||||||
|
#define regnum_x27 27
|
||||||
|
#define regnum_x28 28
|
||||||
|
#define regnum_x29 29
|
||||||
|
#define regnum_x30 30
|
||||||
|
#define regnum_x31 31
|
||||||
|
|
||||||
|
#define regnum_zero 0
|
||||||
|
#define regnum_ra 1
|
||||||
|
#define regnum_sp 2
|
||||||
|
#define regnum_gp 3
|
||||||
|
#define regnum_tp 4
|
||||||
|
#define regnum_t0 5
|
||||||
|
#define regnum_t1 6
|
||||||
|
#define regnum_t2 7
|
||||||
|
#define regnum_s0 8
|
||||||
|
#define regnum_s1 9
|
||||||
|
#define regnum_a0 10
|
||||||
|
#define regnum_a1 11
|
||||||
|
#define regnum_a2 12
|
||||||
|
#define regnum_a3 13
|
||||||
|
#define regnum_a4 14
|
||||||
|
#define regnum_a5 15
|
||||||
|
#define regnum_a6 16
|
||||||
|
#define regnum_a7 17
|
||||||
|
#define regnum_s2 18
|
||||||
|
#define regnum_s3 19
|
||||||
|
#define regnum_s4 20
|
||||||
|
#define regnum_s5 21
|
||||||
|
#define regnum_s6 22
|
||||||
|
#define regnum_s7 23
|
||||||
|
#define regnum_s8 24
|
||||||
|
#define regnum_s9 25
|
||||||
|
#define regnum_s10 26
|
||||||
|
#define regnum_s11 27
|
||||||
|
#define regnum_t3 28
|
||||||
|
#define regnum_t4 29
|
||||||
|
#define regnum_t5 30
|
||||||
|
#define regnum_t6 31
|
||||||
|
|
||||||
|
// x8 is s0 and also fp
|
||||||
|
#define regnum_fp 8
|
||||||
|
|
||||||
|
#define r_type_insn(_f7, _rs2, _rs1, _f3, _rd, _opc) \
|
||||||
|
.word (((_f7) << 25) | ((_rs2) << 20) | ((_rs1) << 15) | ((_f3) << 12) | ((_rd) << 7) | ((_opc) << 0))
|
||||||
|
|
||||||
|
#define picorv32_getq_insn(_rd, _qs) \
|
||||||
|
r_type_insn(0b0000000, 0, regnum_ ## _qs, 0b100, regnum_ ## _rd, 0b0001011)
|
||||||
|
|
||||||
|
#define picorv32_setq_insn(_qd, _rs) \
|
||||||
|
r_type_insn(0b0000001, 0, regnum_ ## _rs, 0b010, regnum_ ## _qd, 0b0001011)
|
||||||
|
|
||||||
|
#define picorv32_retirq_insn() \
|
||||||
|
r_type_insn(0b0000010, 0, 0, 0b000, 0, 0b0001011)
|
||||||
|
|
||||||
|
#define picorv32_maskirq_insn(_rd, _rs) \
|
||||||
|
r_type_insn(0b0000011, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
|
||||||
|
|
||||||
|
#define picorv32_waitirq_insn(_rd) \
|
||||||
|
r_type_insn(0b0000100, 0, 0, 0b100, regnum_ ## _rd, 0b0001011)
|
||||||
|
|
||||||
|
#define picorv32_timer_insn(_rd, _rs) \
|
||||||
|
r_type_insn(0b0000101, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
|
||||||
|
|
10
hw/application_fpga/fw/irqpoc_with_app/main.c
Normal file
10
hw/application_fpga/fw/irqpoc_with_app/main.c
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
}
|
||||||
|
}
|
75
hw/application_fpga/fw/irqpoc_with_app/start.S
Normal file
75
hw/application_fpga/fw/irqpoc_with_app/start.S
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This firmware copies an app from ROM to app RAM. The app triggers both
|
||||||
|
// IRQ_SYSCALL_HI and IRQ_SYSCALL_LO. One after the other. Finally, the
|
||||||
|
// app tries to jump firmware. This should result in a trap since the
|
||||||
|
// app in executing in app mode.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "custom_ops.S" // PicoRV32 custom instructions
|
||||||
|
|
||||||
|
.section ".text.init"
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
j init
|
||||||
|
|
||||||
|
//
|
||||||
|
// IRQ handler
|
||||||
|
//
|
||||||
|
.=0x10 // IRQ handler at fixed address 0x10
|
||||||
|
irq_handler:
|
||||||
|
// PicoRV32 stores the IRQ bitmask in x4.
|
||||||
|
// If bit 31 is 1: IRQ31 was triggered.
|
||||||
|
// If bit 30 is 1: IRQ30 was triggered.
|
||||||
|
|
||||||
|
nop // NOPs are not necessary. Only added to make it easier to find
|
||||||
|
nop // when simulating.
|
||||||
|
nop
|
||||||
|
picorv32_retirq_insn() // Return from interrupt
|
||||||
|
|
||||||
|
//
|
||||||
|
// Init
|
||||||
|
//
|
||||||
|
.=0x20 // Setting location of init to 0x20. Makes it easier to find when
|
||||||
|
// simulating.
|
||||||
|
init:
|
||||||
|
li t0, 0x3fffffff // IRQ31 & IRQ30 mask
|
||||||
|
picorv32_maskirq_insn(zero, t0) // Enable IRQs
|
||||||
|
|
||||||
|
// Copy app to App RAM
|
||||||
|
la t0, app_start
|
||||||
|
la t1, app_end
|
||||||
|
li t2, 0x40000000 // 0x40000000: App RAM
|
||||||
|
copy_app:
|
||||||
|
lw t3, 0(t0)
|
||||||
|
sw t3, 0(t2)
|
||||||
|
addi t0, t0, 4
|
||||||
|
addi t2, t2, 4
|
||||||
|
bleu t0, t1, copy_app
|
||||||
|
|
||||||
|
// Jump to app
|
||||||
|
li t2, 0x40000000 // 0x40000000: App RAM
|
||||||
|
jalr zero, 0(t2)
|
||||||
|
|
||||||
|
//
|
||||||
|
// App
|
||||||
|
//
|
||||||
|
.align 4
|
||||||
|
app_start:
|
||||||
|
li t0, 0xe1000000 // IRQ_SYSCALL_HI (IRQ31) trigger address
|
||||||
|
sw zero, 0(t0) // Raise IRQ by writing to interrupt trigger address.
|
||||||
|
// Writing any data triggers an interrupt.
|
||||||
|
|
||||||
|
li t0, 0xe0000000 // IRQ_SYSCALL_LO (IRQ30) trigger address
|
||||||
|
sw zero, 0(t0) // Raise IRQ by writing to interrupt trigger address.
|
||||||
|
// Writing any data triggers an interrupt.
|
||||||
|
|
||||||
|
jalr zero, 0(zero) // Jumping to firmware. Expecting trap
|
||||||
|
app_loop:
|
||||||
|
j app_loop
|
||||||
|
.align 4
|
||||||
|
app_end:
|
||||||
|
|
@ -80,7 +80,7 @@ module tb_application_fpga_sim ();
|
|||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
initial begin
|
initial begin
|
||||||
// End simulation after XXX time units (set by timescale)
|
// End simulation after XXX time units (set by timescale)
|
||||||
#700;
|
#1600;
|
||||||
$display("TIMEOUT");
|
$display("TIMEOUT");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user