mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-03-12 18:16:55 -04:00
Compare commits
32 Commits
b02c2d67d6
...
c0a98196b6
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c0a98196b6 | ||
![]() |
f34b4c3eb1 | ||
![]() |
3665c3e245 | ||
![]() |
52694b5c4f | ||
![]() |
ea7f7107f0 | ||
![]() |
d1b8b6eee8 | ||
![]() |
1a505f4a21 | ||
![]() |
926f3c68ed | ||
![]() |
e851efd35e | ||
![]() |
97005bb83c | ||
![]() |
8c6e4a3352 | ||
![]() |
6c2a7ef6c7 | ||
![]() |
5c56304b5d | ||
![]() |
a646c8bfb4 | ||
![]() |
007aa69052 | ||
![]() |
93a74bcd1b | ||
![]() |
3269d25617 | ||
![]() |
7f95e0912f | ||
![]() |
82d408f405 | ||
![]() |
14f266e506 | ||
![]() |
052029236d | ||
![]() |
2ec2196e92 | ||
![]() |
7f34f5db91 | ||
![]() |
ecdbb25013 | ||
![]() |
4877e0ab99 | ||
![]() |
62dba7c4fe | ||
![]() |
a871d23d5d | ||
![]() |
e4d19e83ce | ||
![]() |
b53666e497 | ||
![]() |
2d762faba7 | ||
![]() |
d36e9c9e3d | ||
![]() |
5535323b06 |
@ -127,7 +127,10 @@ FIRMWARE_OBJS = \
|
|||||||
$(P)/fw/tk1/lib.o \
|
$(P)/fw/tk1/lib.o \
|
||||||
$(P)/fw/tk1/assert.o \
|
$(P)/fw/tk1/assert.o \
|
||||||
$(P)/fw/tk1/led.o \
|
$(P)/fw/tk1/led.o \
|
||||||
$(P)/fw/tk1/blake2s/blake2s.o
|
$(P)/fw/tk1/blake2s/blake2s.o \
|
||||||
|
$(P)/fw/tk1/syscall.o \
|
||||||
|
$(P)/fw/tk1/spi.o \
|
||||||
|
$(P)/fw/tk1/flash.o
|
||||||
|
|
||||||
FIRMWARE_SOURCES = \
|
FIRMWARE_SOURCES = \
|
||||||
$(P)/fw/tk1/main.c \
|
$(P)/fw/tk1/main.c \
|
||||||
@ -135,14 +138,36 @@ FIRMWARE_SOURCES = \
|
|||||||
$(P)/fw/tk1/lib.c \
|
$(P)/fw/tk1/lib.c \
|
||||||
$(P)/fw/tk1/assert.c \
|
$(P)/fw/tk1/assert.c \
|
||||||
$(P)/fw/tk1/led.c \
|
$(P)/fw/tk1/led.c \
|
||||||
$(P)/fw/tk1/blake2s/blake2s.c
|
$(P)/fw/tk1/blake2s/blake2s.c \
|
||||||
|
$(P)/fw/tk1/syscall.c \
|
||||||
|
$(P)/fw/tk1/spi.c \
|
||||||
|
$(P)/fw/tk1/flash.c
|
||||||
|
|
||||||
TESTFW_OBJS = \
|
TESTFW_OBJS = \
|
||||||
$(P)/fw/testfw/main.o \
|
$(P)/fw/testfw/main.o \
|
||||||
$(P)/fw/testfw/start.o \
|
$(P)/fw/testfw/start.o \
|
||||||
$(P)/fw/tk1/proto.o \
|
$(P)/fw/tk1/proto.o \
|
||||||
$(P)/fw/tk1/lib.o \
|
$(P)/fw/tk1/lib.o \
|
||||||
$(P)/fw/tk1/blake2s/blake2s.o
|
$(P)/fw/tk1/spi.o \
|
||||||
|
$(P)/fw/tk1/flash.o
|
||||||
|
|
||||||
|
IRQPOC_OBJS = \
|
||||||
|
$(P)/fw/irqpoc/main.o \
|
||||||
|
$(P)/fw/irqpoc/start.o
|
||||||
|
|
||||||
|
IRQPOC_LED_TOGGLE_OBJS = \
|
||||||
|
$(P)/fw/irqpoc_led_toggle/main.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
|
||||||
|
|
||||||
|
IRQPOC_C_EXAMPLE_OBJS = \
|
||||||
|
$(P)/fw/irqpoc_c_example/main.o \
|
||||||
|
$(P)/fw/irqpoc_c_example/start.o \
|
||||||
|
$(P)/fw/tk1/led.o \
|
||||||
|
$(P)/fw/tk1/assert.o
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
# All: Complete build of HW and FW.
|
# All: Complete build of HW and FW.
|
||||||
@ -180,6 +205,10 @@ LDFLAGS = -T $(P)/fw/tk1/firmware.lds
|
|||||||
|
|
||||||
$(FIRMWARE_OBJS): $(FIRMWARE_DEPS)
|
$(FIRMWARE_OBJS): $(FIRMWARE_DEPS)
|
||||||
$(TESTFW_OBJS): $(FIRMWARE_DEPS)
|
$(TESTFW_OBJS): $(FIRMWARE_DEPS)
|
||||||
|
$(IRQPOC_OBJS): $(FIRMWARE_DEPS)
|
||||||
|
$(IRQPOC_LED_TOGGLE_OBJS): $(FIRMWARE_DEPS)
|
||||||
|
$(IRQPOC_WITH_APP_OBJS): $(FIRMWARE_DEPS)
|
||||||
|
$(IRQPOC_C_EXAMPLE_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 $@
|
||||||
@ -222,6 +251,18 @@ splint:
|
|||||||
testfw.elf: $(TESTFW_OBJS) $(P)/fw/tk1/firmware.lds
|
testfw.elf: $(TESTFW_OBJS) $(P)/fw/tk1/firmware.lds
|
||||||
$(CC) $(CFLAGS) $(TESTFW_OBJS) $(LDFLAGS) -o $@
|
$(CC) $(CFLAGS) $(TESTFW_OBJS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
irqpoc.elf: $(IRQPOC_OBJS) $(P)/fw/tk1/firmware.lds
|
||||||
|
$(CC) $(CFLAGS) $(IRQPOC_OBJS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
irqpoc_led_toggle.elf: $(IRQPOC_LED_TOGGLE_OBJS) $(P)/fw/tk1/firmware.lds
|
||||||
|
$(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 $@
|
||||||
|
|
||||||
|
irqpoc_c_example.elf: $(IRQPOC_C_EXAMPLE_OBJS) $(P)/fw/tk1/firmware.lds
|
||||||
|
$(CC) $(CFLAGS) $(IRQPOC_C_EXAMPLE_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) > $@
|
||||||
@ -232,6 +273,13 @@ simfirmware.hex: simfirmware.bin simfirmware_size_mismatch
|
|||||||
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
||||||
testfw.hex: testfw.bin testfw_size_mismatch
|
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
|
||||||
|
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) > $@
|
||||||
|
irqpoc_c_example.hex: irqpoc_c_example.bin
|
||||||
|
python3 $(P)/tools/makehex/makehex.py $< $(BRAM_FW_SIZE) > $@
|
||||||
|
|
||||||
|
|
||||||
.PHONY: check-binary-hashes
|
.PHONY: check-binary-hashes
|
||||||
check-binary-hashes:
|
check-binary-hashes:
|
||||||
@ -401,11 +449,13 @@ application_fpga_testfw.bin: application_fpga.asc bram_fw.hex testfw.hex
|
|||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
# Build testbench simulation for the design
|
# Build testbench simulation for the design
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
|
SIMFIRMWARE = simfirmware.hex
|
||||||
|
|
||||||
tb_application_fpga: $(SIM_VERILOG_SRCS) \
|
tb_application_fpga: $(SIM_VERILOG_SRCS) \
|
||||||
$(VERILOG_SRCS) \
|
$(VERILOG_SRCS) \
|
||||||
$(PICORV32_SRCS) \
|
$(PICORV32_SRCS) \
|
||||||
$(ICE40_SIM_CELLS) \
|
$(ICE40_SIM_CELLS) \
|
||||||
simfirmware.hex
|
$(SIMFIRMWARE)
|
||||||
python3 ./tools/app_bin_to_spram_hex.py \
|
python3 ./tools/app_bin_to_spram_hex.py \
|
||||||
./tb/app.bin \
|
./tb/app.bin \
|
||||||
./tb/output_spram0.hex \
|
./tb/output_spram0.hex \
|
||||||
@ -429,7 +479,7 @@ tb_application_fpga: $(SIM_VERILOG_SRCS) \
|
|||||||
-DNO_ICE40_DEFAULT_ASSIGNMENTS \
|
-DNO_ICE40_DEFAULT_ASSIGNMENTS \
|
||||||
-DAPP_SIZE=$(shell ls -l tb/app.bin| awk '{print $$5}') \
|
-DAPP_SIZE=$(shell ls -l tb/app.bin| awk '{print $$5}') \
|
||||||
-DBRAM_FW_SIZE=$(BRAM_FW_SIZE) \
|
-DBRAM_FW_SIZE=$(BRAM_FW_SIZE) \
|
||||||
-DFIRMWARE_HEX=\"$(P)/simfirmware.hex\" \
|
-DFIRMWARE_HEX=\"$(P)/$(SIMFIRMWARE)\" \
|
||||||
-DUDS_HEX=\"$(P)/data/uds.hex\" \
|
-DUDS_HEX=\"$(P)/data/uds.hex\" \
|
||||||
-DUDI_HEX=\"$(P)/data/udi.hex\" \
|
-DUDI_HEX=\"$(P)/data/udi.hex\" \
|
||||||
$(filter %.v, $^)
|
$(filter %.v, $^)
|
||||||
@ -437,6 +487,23 @@ tb_application_fpga: $(SIM_VERILOG_SRCS) \
|
|||||||
./tb_verilated/Vtb_application_fpga_sim \
|
./tb_verilated/Vtb_application_fpga_sim \
|
||||||
&& { echo -e "\n -- Wave simulation saved to tb_application_fpga_sim.fst\n"; true; }
|
&& { echo -e "\n -- Wave simulation saved to tb_application_fpga_sim.fst\n"; true; }
|
||||||
|
|
||||||
|
.PHONY: emptyapp
|
||||||
|
emptyapp:
|
||||||
|
dd if=/dev/zero of=tb/app.bin bs=1024 count=128
|
||||||
|
|
||||||
|
.PHONY: tb_application_fpga_irqpoc
|
||||||
|
tb_application_fpga_irqpoc: SIMFIRMWARE=irqpoc.hex
|
||||||
|
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
|
||||||
|
|
||||||
|
.PHONY: tb_application_fpga_irqpoc_c_example
|
||||||
|
tb_application_fpga_irqpoc_c_example: SIMFIRMWARE=irqpoc_c_example.hex
|
||||||
|
tb_application_fpga_irqpoc_c_example: irqpoc_c_example.hex emptyapp tb_application_fpga
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
# FPGA device programming.
|
# FPGA device programming.
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
@ -483,6 +550,10 @@ clean_fw:
|
|||||||
rm -f $(FIRMWARE_OBJS)
|
rm -f $(FIRMWARE_OBJS)
|
||||||
rm -f testfw.{elf,elf.map,bin,hex}
|
rm -f testfw.{elf,elf.map,bin,hex}
|
||||||
rm -f $(TESTFW_OBJS)
|
rm -f $(TESTFW_OBJS)
|
||||||
|
rm -f $(IRQPOC_OBJS)
|
||||||
|
rm -f $(IRQPOC_LED_TOGGLE_OBJS)
|
||||||
|
rm -f $(IRQPOC_WITH_APP_OBJS)
|
||||||
|
rm -f $(IRQPOC_C_EXAMPLE_OBJS)
|
||||||
rm -f qemu_firmware.elf
|
rm -f qemu_firmware.elf
|
||||||
.PHONY: clean_fw
|
.PHONY: clean_fw
|
||||||
|
|
||||||
|
@ -11,9 +11,10 @@ The design top level is in `rtl/application_fpga.v`. It contains
|
|||||||
instances of all cores as well as the memory system.
|
instances of all cores as well as the memory system.
|
||||||
|
|
||||||
The memory system allows the CPU to access cores in different ways
|
The memory system allows the CPU to access cores in different ways
|
||||||
given the current execution mode. There are two execution modes -
|
given the current execution mode. There are three execution modes -
|
||||||
firmware and application. Basically, in application mode the access is
|
firmware, application and system call. Each mode give access to a
|
||||||
more restrictive.
|
different set of resources. Where app mode is the most restrictive and
|
||||||
|
firmware mode is the least restrictive.
|
||||||
|
|
||||||
The rest of the components are under `cores`. They typically have
|
The rest of the components are under `cores`. They typically have
|
||||||
their own `README.md` file documenting them and their API in detail.
|
their own `README.md` file documenting them and their API in detail.
|
||||||
@ -25,7 +26,7 @@ and bitmasks, see the file `fw/tk1_mem.h`.
|
|||||||
Rough memory map:
|
Rough memory map:
|
||||||
|
|
||||||
| *name* | *prefix* |
|
| *name* | *prefix* |
|
||||||
|---------|----------|
|
|------------|----------|
|
||||||
| ROM | 0x00 |
|
| ROM | 0x00 |
|
||||||
| RAM | 0x40 |
|
| RAM | 0x40 |
|
||||||
| TRNG | 0xc0 |
|
| TRNG | 0xc0 |
|
||||||
@ -34,6 +35,7 @@ Rough memory map:
|
|||||||
| UART | 0xc3 |
|
| UART | 0xc3 |
|
||||||
| Touch | 0xc4 |
|
| Touch | 0xc4 |
|
||||||
| FW\_RAM | 0xd0 |
|
| FW\_RAM | 0xd0 |
|
||||||
|
| IRQ31\_SET | 0xe1 |
|
||||||
| TK1 | 0xff |
|
| TK1 | 0xff |
|
||||||
|
|
||||||
## `clk_reset_gen`
|
## `clk_reset_gen`
|
||||||
@ -96,6 +98,71 @@ hours, days) there is also a 32 bit prescaler.
|
|||||||
|
|
||||||
The timer is available to use by firmware and applications.
|
The timer is available to use by firmware and applications.
|
||||||
|
|
||||||
|
## `irq31_set`
|
||||||
|
|
||||||
|
Interrupt 31 trigger area. A 32-bit write to the IRQ31\_SET memory
|
||||||
|
area will trigger interrupt 31.
|
||||||
|
|
||||||
|
## Interrupts
|
||||||
|
|
||||||
|
Triggering an interrupt will cause the CPU to execute the interrupt
|
||||||
|
handler att address 0x10.
|
||||||
|
|
||||||
|
The interrupt handler is shared by all PicoRV32 interrupts but only
|
||||||
|
interrupt 31 is enabled on the Tkey. Register `x4` can be inspected to
|
||||||
|
determine the interrupt source. Each interrupt source is assigned one
|
||||||
|
bit in x4. Triggered interrupts have their bit set to `1`.
|
||||||
|
|
||||||
|
| *Interrupt Name* | *Source* | *x4 Bit* |
|
||||||
|
|------------------|------------|----------|
|
||||||
|
| IRQ_SYSCALL | IRQ31\_SET | 31 |
|
||||||
|
|
||||||
|
The return address is located in register `x3`. Calling the PicoRV32
|
||||||
|
specific instruction `retirq` exits the interrupt handler and clears
|
||||||
|
the interrupt source.
|
||||||
|
|
||||||
|
No registers are stored/restored when entering/exiting the interrupt
|
||||||
|
handler. It is up to the software to store/restore as necessary.
|
||||||
|
|
||||||
|
Interrupts can be enabled/disabled using the PicoRV32 specific
|
||||||
|
`maskirq` instruction.
|
||||||
|
|
||||||
|
## Restricted resources
|
||||||
|
|
||||||
|
The following table shows resource availablility for each execution
|
||||||
|
mode:
|
||||||
|
|
||||||
|
| *Execution Mode* | *ROM* | *FW RAM* | *SPI* | *Sensitive assets* |
|
||||||
|
|------------------|--------|----------|-------|--------------------|
|
||||||
|
| Firmware mode | r/x | r/w | r/w | r/w* |
|
||||||
|
| IRQ_SYSCALL | r/x | r/w | r/w | r* |
|
||||||
|
| Application mode | r | i | i | r* |
|
||||||
|
|
||||||
|
Legend:
|
||||||
|
r = readable
|
||||||
|
w = writeable
|
||||||
|
x = executable
|
||||||
|
i = invisible
|
||||||
|
* = read-/writeability varies, see below
|
||||||
|
|
||||||
|
These sensitive assets are only readable and/or writeable in firmware
|
||||||
|
mode:
|
||||||
|
- APP_START
|
||||||
|
- APP_SIZE
|
||||||
|
- CDI_FIRST
|
||||||
|
- CDI_LAST
|
||||||
|
- RAM_ADDR_RAND
|
||||||
|
- RAM_DATA_RAND
|
||||||
|
- UDI_FIRST
|
||||||
|
- UDI_LAST
|
||||||
|
- UDS_FIRST
|
||||||
|
- UDS_LAST
|
||||||
|
|
||||||
|
Note that these assets have different properties, some are read-only
|
||||||
|
and some are write-only. The list above only shows if they are
|
||||||
|
restricted in app mode. See each individual API to find out more about
|
||||||
|
their properties.
|
||||||
|
|
||||||
## `tk1`
|
## `tk1`
|
||||||
|
|
||||||
See [tk1 README](core/tk1/README.md) for details.
|
See [tk1 README](core/tk1/README.md) for details.
|
||||||
@ -107,7 +174,6 @@ Contains:
|
|||||||
- RGB LED control.
|
- RGB LED control.
|
||||||
- General purpose input/output (GPIO) pin control.
|
- General purpose input/output (GPIO) pin control.
|
||||||
- Application introspection: start address and size of binary.
|
- Application introspection: start address and size of binary.
|
||||||
- BLAKE2s function access.
|
|
||||||
- Compound Device Identity (CDI).
|
- Compound Device Identity (CDI).
|
||||||
- Unique Device Identity (UDI).
|
- Unique Device Identity (UDI).
|
||||||
- RAM memory protection.
|
- RAM memory protection.
|
||||||
|
@ -17,8 +17,7 @@ module fw_ram (
|
|||||||
input wire clk,
|
input wire clk,
|
||||||
input wire reset_n,
|
input wire reset_n,
|
||||||
|
|
||||||
input wire system_mode,
|
input wire en,
|
||||||
|
|
||||||
input wire cs,
|
input wire cs,
|
||||||
input wire [ 3 : 0] we,
|
input wire [ 3 : 0] we,
|
||||||
input wire [ 8 : 0] address,
|
input wire [ 8 : 0] address,
|
||||||
@ -35,7 +34,6 @@ module fw_ram (
|
|||||||
reg [31 : 0] mem_read_data0;
|
reg [31 : 0] mem_read_data0;
|
||||||
reg [31 : 0] mem_read_data1;
|
reg [31 : 0] mem_read_data1;
|
||||||
reg ready_reg;
|
reg ready_reg;
|
||||||
wire system_mode_cs;
|
|
||||||
reg bank0;
|
reg bank0;
|
||||||
reg bank1;
|
reg bank1;
|
||||||
|
|
||||||
@ -45,7 +43,6 @@ module fw_ram (
|
|||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
assign read_data = tmp_read_data;
|
assign read_data = tmp_read_data;
|
||||||
assign ready = ready_reg;
|
assign ready = ready_reg;
|
||||||
assign system_mode_cs = cs && ~system_mode;
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
@ -56,12 +53,12 @@ module fw_ram (
|
|||||||
.RADDR({3'h0, address[7 : 0]}),
|
.RADDR({3'h0, address[7 : 0]}),
|
||||||
.RCLK(clk),
|
.RCLK(clk),
|
||||||
.RCLKE(1'h1),
|
.RCLKE(1'h1),
|
||||||
.RE(system_mode_cs & bank0),
|
.RE(en & cs & bank0),
|
||||||
.WADDR({3'h0, address[7 : 0]}),
|
.WADDR({3'h0, address[7 : 0]}),
|
||||||
.WCLK(clk),
|
.WCLK(clk),
|
||||||
.WCLKE(1'h1),
|
.WCLKE(1'h1),
|
||||||
.WDATA(write_data[15 : 0]),
|
.WDATA(write_data[15 : 0]),
|
||||||
.WE((|we & system_mode_cs & bank0)),
|
.WE((|we & en & cs & bank0)),
|
||||||
.MASK({{8{~we[1]}}, {8{~we[0]}}})
|
.MASK({{8{~we[1]}}, {8{~we[0]}}})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -70,12 +67,12 @@ module fw_ram (
|
|||||||
.RADDR({3'h0, address[7 : 0]}),
|
.RADDR({3'h0, address[7 : 0]}),
|
||||||
.RCLK(clk),
|
.RCLK(clk),
|
||||||
.RCLKE(1'h1),
|
.RCLKE(1'h1),
|
||||||
.RE(system_mode_cs & bank0),
|
.RE(en & cs & bank0),
|
||||||
.WADDR({3'h0, address[7 : 0]}),
|
.WADDR({3'h0, address[7 : 0]}),
|
||||||
.WCLK(clk),
|
.WCLK(clk),
|
||||||
.WCLKE(1'h1),
|
.WCLKE(1'h1),
|
||||||
.WDATA(write_data[31 : 16]),
|
.WDATA(write_data[31 : 16]),
|
||||||
.WE((|we & system_mode_cs & bank0)),
|
.WE((|we & en & cs & bank0)),
|
||||||
.MASK({{8{~we[3]}}, {8{~we[2]}}})
|
.MASK({{8{~we[3]}}, {8{~we[2]}}})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -85,12 +82,12 @@ module fw_ram (
|
|||||||
.RADDR({3'h0, address[7 : 0]}),
|
.RADDR({3'h0, address[7 : 0]}),
|
||||||
.RCLK(clk),
|
.RCLK(clk),
|
||||||
.RCLKE(1'h1),
|
.RCLKE(1'h1),
|
||||||
.RE(system_mode_cs & bank1),
|
.RE(en & cs & bank1),
|
||||||
.WADDR({3'h0, address[7 : 0]}),
|
.WADDR({3'h0, address[7 : 0]}),
|
||||||
.WCLK(clk),
|
.WCLK(clk),
|
||||||
.WCLKE(1'h1),
|
.WCLKE(1'h1),
|
||||||
.WDATA(write_data[15 : 0]),
|
.WDATA(write_data[15 : 0]),
|
||||||
.WE((|we & system_mode_cs & bank1)),
|
.WE((|we & en & cs & bank1)),
|
||||||
.MASK({{8{~we[1]}}, {8{~we[0]}}})
|
.MASK({{8{~we[1]}}, {8{~we[0]}}})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -99,12 +96,12 @@ module fw_ram (
|
|||||||
.RADDR({3'h0, address[7 : 0]}),
|
.RADDR({3'h0, address[7 : 0]}),
|
||||||
.RCLK(clk),
|
.RCLK(clk),
|
||||||
.RCLKE(1'h1),
|
.RCLKE(1'h1),
|
||||||
.RE(system_mode_cs & bank1),
|
.RE(en & cs & bank1),
|
||||||
.WADDR({3'h0, address[7 : 0]}),
|
.WADDR({3'h0, address[7 : 0]}),
|
||||||
.WCLK(clk),
|
.WCLK(clk),
|
||||||
.WCLKE(1'h1),
|
.WCLKE(1'h1),
|
||||||
.WDATA(write_data[31 : 16]),
|
.WDATA(write_data[31 : 16]),
|
||||||
.WE((|we & system_mode_cs & bank1)),
|
.WE((|we & en & cs & bank1)),
|
||||||
.MASK({{8{~we[3]}}, {8{~we[2]}}})
|
.MASK({{8{~we[3]}}, {8{~we[2]}}})
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -129,7 +126,7 @@ module fw_ram (
|
|||||||
bank1 = 1'h0;
|
bank1 = 1'h0;
|
||||||
tmp_read_data = 32'h0;
|
tmp_read_data = 32'h0;
|
||||||
|
|
||||||
if (system_mode_cs) begin
|
if (en & cs) begin
|
||||||
if (address[8]) begin
|
if (address[8]) begin
|
||||||
bank1 = 1'h1;
|
bank1 = 1'h1;
|
||||||
tmp_read_data = mem_read_data1;
|
tmp_read_data = mem_read_data1;
|
||||||
|
@ -78,18 +78,6 @@ FW as part of the loading of the app. The registers can't be written
|
|||||||
when the `ADDR_SYSTEM_MODE_CTRL` has been set.
|
when the `ADDR_SYSTEM_MODE_CTRL` has been set.
|
||||||
|
|
||||||
|
|
||||||
### Access to Blake2s
|
|
||||||
|
|
||||||
```
|
|
||||||
ADDR_BLAKE2S: 0x10
|
|
||||||
```
|
|
||||||
|
|
||||||
This register provides the 32-bit function pointer address to the
|
|
||||||
Blake2s hash function in the FW. It is written by FW during boot. The
|
|
||||||
register can't be written to when the `ADDR_SYSTEM_MODE_CTRL` has been
|
|
||||||
set.
|
|
||||||
|
|
||||||
|
|
||||||
### Access to CDI
|
### Access to CDI
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -20,7 +20,7 @@ module tk1 #(
|
|||||||
input wire reset_n,
|
input wire reset_n,
|
||||||
|
|
||||||
input wire cpu_trap,
|
input wire cpu_trap,
|
||||||
output wire system_mode,
|
output wire rw_locked,
|
||||||
|
|
||||||
input wire [31 : 0] cpu_addr,
|
input wire [31 : 0] cpu_addr,
|
||||||
input wire cpu_instr,
|
input wire cpu_instr,
|
||||||
@ -45,6 +45,10 @@ module tk1 #(
|
|||||||
output wire gpio3,
|
output wire gpio3,
|
||||||
output wire gpio4,
|
output wire gpio4,
|
||||||
|
|
||||||
|
input wire access_level_hi,
|
||||||
|
|
||||||
|
output wire fw_ram_en,
|
||||||
|
|
||||||
input wire cs,
|
input wire cs,
|
||||||
input wire we,
|
input wire we,
|
||||||
input wire [ 7 : 0] address,
|
input wire [ 7 : 0] address,
|
||||||
@ -79,8 +83,6 @@ module tk1 #(
|
|||||||
localparam ADDR_APP_START = 8'h0c;
|
localparam ADDR_APP_START = 8'h0c;
|
||||||
localparam ADDR_APP_SIZE = 8'h0d;
|
localparam ADDR_APP_SIZE = 8'h0d;
|
||||||
|
|
||||||
localparam ADDR_BLAKE2S = 8'h10;
|
|
||||||
|
|
||||||
localparam ADDR_CDI_FIRST = 8'h20;
|
localparam ADDR_CDI_FIRST = 8'h20;
|
||||||
localparam ADDR_CDI_LAST = 8'h27;
|
localparam ADDR_CDI_LAST = 8'h27;
|
||||||
|
|
||||||
@ -107,6 +109,7 @@ module tk1 #(
|
|||||||
localparam FW_RAM_FIRST = 32'hd0000000;
|
localparam FW_RAM_FIRST = 32'hd0000000;
|
||||||
localparam FW_RAM_LAST = 32'hd00007ff;
|
localparam FW_RAM_LAST = 32'hd00007ff;
|
||||||
|
|
||||||
|
localparam FW_ROM_LAST = 32'h000017ff;
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Registers including update variables and write enable.
|
// Registers including update variables and write enable.
|
||||||
@ -115,6 +118,7 @@ module tk1 #(
|
|||||||
reg cdi_mem_we;
|
reg cdi_mem_we;
|
||||||
|
|
||||||
reg system_mode_reg;
|
reg system_mode_reg;
|
||||||
|
reg system_mode_new;
|
||||||
reg system_mode_we;
|
reg system_mode_we;
|
||||||
|
|
||||||
reg [ 2 : 0] led_reg;
|
reg [ 2 : 0] led_reg;
|
||||||
@ -133,9 +137,6 @@ module tk1 #(
|
|||||||
reg [31 : 0] app_size_reg;
|
reg [31 : 0] app_size_reg;
|
||||||
reg app_size_we;
|
reg app_size_we;
|
||||||
|
|
||||||
reg [31 : 0] blake2s_addr_reg;
|
|
||||||
reg blake2s_addr_we;
|
|
||||||
|
|
||||||
reg [23 : 0] cpu_trap_ctr_reg;
|
reg [23 : 0] cpu_trap_ctr_reg;
|
||||||
reg [23 : 0] cpu_trap_ctr_new;
|
reg [23 : 0] cpu_trap_ctr_new;
|
||||||
reg [ 2 : 0] cpu_trap_led_reg;
|
reg [ 2 : 0] cpu_trap_led_reg;
|
||||||
@ -180,6 +181,11 @@ module tk1 #(
|
|||||||
reg spi_tx_data_vld;
|
reg spi_tx_data_vld;
|
||||||
wire spi_ready;
|
wire spi_ready;
|
||||||
wire [ 7 : 0] spi_rx_data;
|
wire [ 7 : 0] spi_rx_data;
|
||||||
|
wire spi_access_en;
|
||||||
|
|
||||||
|
wire rom_exec_en;
|
||||||
|
|
||||||
|
wire system_mode;
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Concurrent connectivity for ports etc.
|
// Concurrent connectivity for ports etc.
|
||||||
@ -187,8 +193,6 @@ module tk1 #(
|
|||||||
assign read_data = tmp_read_data;
|
assign read_data = tmp_read_data;
|
||||||
assign ready = tmp_ready;
|
assign ready = tmp_ready;
|
||||||
|
|
||||||
assign system_mode = system_mode_reg;
|
|
||||||
|
|
||||||
assign force_trap = force_trap_reg;
|
assign force_trap = force_trap_reg;
|
||||||
|
|
||||||
assign gpio3 = gpio3_reg;
|
assign gpio3 = gpio3_reg;
|
||||||
@ -199,6 +203,12 @@ module tk1 #(
|
|||||||
|
|
||||||
assign system_reset = system_reset_reg;
|
assign system_reset = system_reset_reg;
|
||||||
|
|
||||||
|
assign system_mode = system_mode_reg;
|
||||||
|
|
||||||
|
assign rom_exec_en = !system_mode | access_level_hi;
|
||||||
|
assign fw_ram_en = !system_mode | access_level_hi;
|
||||||
|
assign spi_access_en = !system_mode | access_level_hi;
|
||||||
|
assign rw_locked = system_mode;
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Module instance.
|
// Module instance.
|
||||||
@ -258,7 +268,6 @@ module tk1 #(
|
|||||||
gpio4_reg <= 1'h0;
|
gpio4_reg <= 1'h0;
|
||||||
app_start_reg <= 32'h0;
|
app_start_reg <= 32'h0;
|
||||||
app_size_reg <= APP_SIZE;
|
app_size_reg <= APP_SIZE;
|
||||||
blake2s_addr_reg <= 32'h0;
|
|
||||||
cdi_mem[0] <= 32'h0;
|
cdi_mem[0] <= 32'h0;
|
||||||
cdi_mem[1] <= 32'h0;
|
cdi_mem[1] <= 32'h0;
|
||||||
cdi_mem[2] <= 32'h0;
|
cdi_mem[2] <= 32'h0;
|
||||||
@ -290,7 +299,7 @@ module tk1 #(
|
|||||||
gpio2_reg[1] <= gpio2_reg[0];
|
gpio2_reg[1] <= gpio2_reg[0];
|
||||||
|
|
||||||
if (system_mode_we) begin
|
if (system_mode_we) begin
|
||||||
system_mode_reg <= 1'h1;
|
system_mode_reg <= system_mode_new;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (led_we) begin
|
if (led_we) begin
|
||||||
@ -313,10 +322,6 @@ module tk1 #(
|
|||||||
app_size_reg <= write_data;
|
app_size_reg <= write_data;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (blake2s_addr_we) begin
|
|
||||||
blake2s_addr_reg <= write_data;
|
|
||||||
end
|
|
||||||
|
|
||||||
if (cdi_mem_we) begin
|
if (cdi_mem_we) begin
|
||||||
cdi_mem[address[2 : 0]] <= write_data;
|
cdi_mem[address[2 : 0]] <= write_data;
|
||||||
end
|
end
|
||||||
@ -385,6 +390,9 @@ module tk1 #(
|
|||||||
//
|
//
|
||||||
// Trying to execute instructions in FW-RAM.
|
// Trying to execute instructions in FW-RAM.
|
||||||
//
|
//
|
||||||
|
// Executing instructions in ROM, while ROM is marked as not
|
||||||
|
// executable.
|
||||||
|
//
|
||||||
// Trying to execute code in mem area set to be data access only.
|
// Trying to execute code in mem area set to be data access only.
|
||||||
// This requires execution monitor to have been setup and
|
// This requires execution monitor to have been setup and
|
||||||
// enabled.
|
// enabled.
|
||||||
@ -402,6 +410,12 @@ module tk1 #(
|
|||||||
force_trap_set = 1'h1;
|
force_trap_set = 1'h1;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if (!rom_exec_en) begin
|
||||||
|
if (cpu_addr <= FW_ROM_LAST) begin // Only valid as long as ROM starts at address 0x00.
|
||||||
|
force_trap_set = 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if (cpu_mon_en_reg) begin
|
if (cpu_mon_en_reg) begin
|
||||||
if ((cpu_addr >= cpu_mon_first_reg) && (cpu_addr <= cpu_mon_last_reg)) begin
|
if ((cpu_addr >= cpu_mon_first_reg) && (cpu_addr <= cpu_mon_last_reg)) begin
|
||||||
force_trap_set = 1'h1;
|
force_trap_set = 1'h1;
|
||||||
@ -411,18 +425,32 @@ module tk1 #(
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// system_mode_ctrl
|
||||||
|
//
|
||||||
|
// Automatically lower privilege when executing above ROM.
|
||||||
|
// ----------------------------------------------------------------
|
||||||
|
always @* begin : system_mode_ctrl
|
||||||
|
system_mode_new = 1'h0;
|
||||||
|
system_mode_we = 1'h0;
|
||||||
|
|
||||||
|
if (cpu_valid & cpu_instr) begin
|
||||||
|
if (cpu_addr > FW_ROM_LAST) begin
|
||||||
|
system_mode_new = 1'h1;
|
||||||
|
system_mode_we = 1'h1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// api
|
// api
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
always @* begin : api
|
always @* begin : api
|
||||||
system_mode_we = 1'h0;
|
|
||||||
led_we = 1'h0;
|
led_we = 1'h0;
|
||||||
gpio3_we = 1'h0;
|
gpio3_we = 1'h0;
|
||||||
gpio4_we = 1'h0;
|
gpio4_we = 1'h0;
|
||||||
app_start_we = 1'h0;
|
app_start_we = 1'h0;
|
||||||
app_size_we = 1'h0;
|
app_size_we = 1'h0;
|
||||||
blake2s_addr_we = 1'h0;
|
|
||||||
cdi_mem_we = 1'h0;
|
cdi_mem_we = 1'h0;
|
||||||
ram_addr_rand_we = 1'h0;
|
ram_addr_rand_we = 1'h0;
|
||||||
ram_data_rand_we = 1'h0;
|
ram_data_rand_we = 1'h0;
|
||||||
@ -437,16 +465,12 @@ module tk1 #(
|
|||||||
spi_start = 1'h0;
|
spi_start = 1'h0;
|
||||||
spi_tx_data_vld = 1'h0;
|
spi_tx_data_vld = 1'h0;
|
||||||
|
|
||||||
spi_enable = write_data[0];
|
spi_enable = write_data[0] & spi_access_en;
|
||||||
spi_tx_data = write_data[7 : 0];
|
spi_tx_data = write_data[7 : 0] & {8{spi_access_en}};
|
||||||
|
|
||||||
if (cs) begin
|
if (cs) begin
|
||||||
tmp_ready = 1'h1;
|
tmp_ready = 1'h1;
|
||||||
if (we) begin
|
if (we) begin
|
||||||
if (address == ADDR_SYSTEM_MODE_CTRL) begin
|
|
||||||
system_mode_we = 1'h1;
|
|
||||||
end
|
|
||||||
|
|
||||||
if (address == ADDR_LED) begin
|
if (address == ADDR_LED) begin
|
||||||
led_we = 1'h1;
|
led_we = 1'h1;
|
||||||
end
|
end
|
||||||
@ -457,13 +481,13 @@ module tk1 #(
|
|||||||
end
|
end
|
||||||
|
|
||||||
if (address == ADDR_APP_START) begin
|
if (address == ADDR_APP_START) begin
|
||||||
if (!system_mode_reg) begin
|
if (!rw_locked) begin
|
||||||
app_start_we = 1'h1;
|
app_start_we = 1'h1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (address == ADDR_APP_SIZE) begin
|
if (address == ADDR_APP_SIZE) begin
|
||||||
if (!system_mode_reg) begin
|
if (!rw_locked) begin
|
||||||
app_size_we = 1'h1;
|
app_size_we = 1'h1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -472,26 +496,20 @@ module tk1 #(
|
|||||||
system_reset_new = 1'h1;
|
system_reset_new = 1'h1;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (address == ADDR_BLAKE2S) begin
|
|
||||||
if (!system_mode_reg) begin
|
|
||||||
blake2s_addr_we = 1'h1;
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if ((address >= ADDR_CDI_FIRST) && (address <= ADDR_CDI_LAST)) begin
|
if ((address >= ADDR_CDI_FIRST) && (address <= ADDR_CDI_LAST)) begin
|
||||||
if (!system_mode_reg) begin
|
if (!rw_locked) begin
|
||||||
cdi_mem_we = 1'h1;
|
cdi_mem_we = 1'h1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (address == ADDR_RAM_ADDR_RAND) begin
|
if (address == ADDR_RAM_ADDR_RAND) begin
|
||||||
if (!system_mode_reg) begin
|
if (!rw_locked) begin
|
||||||
ram_addr_rand_we = 1'h1;
|
ram_addr_rand_we = 1'h1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (address == ADDR_RAM_DATA_RAND) begin
|
if (address == ADDR_RAM_DATA_RAND) begin
|
||||||
if (!system_mode_reg) begin
|
if (!rw_locked) begin
|
||||||
ram_data_rand_we = 1'h1;
|
ram_data_rand_we = 1'h1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -513,16 +531,22 @@ module tk1 #(
|
|||||||
end
|
end
|
||||||
|
|
||||||
if (address == ADDR_SPI_EN) begin
|
if (address == ADDR_SPI_EN) begin
|
||||||
|
if (spi_access_en) begin
|
||||||
spi_enable_vld = 1'h1;
|
spi_enable_vld = 1'h1;
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if (address == ADDR_SPI_XFER) begin
|
if (address == ADDR_SPI_XFER) begin
|
||||||
|
if (spi_access_en) begin
|
||||||
spi_start = 1'h1;
|
spi_start = 1'h1;
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if (address == ADDR_SPI_DATA) begin
|
if (address == ADDR_SPI_DATA) begin
|
||||||
|
if (spi_access_en) begin
|
||||||
spi_tx_data_vld = 1'h1;
|
spi_tx_data_vld = 1'h1;
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
else begin
|
else begin
|
||||||
@ -558,27 +582,27 @@ module tk1 #(
|
|||||||
tmp_read_data = app_size_reg;
|
tmp_read_data = app_size_reg;
|
||||||
end
|
end
|
||||||
|
|
||||||
if (address == ADDR_BLAKE2S) begin
|
|
||||||
tmp_read_data = blake2s_addr_reg;
|
|
||||||
end
|
|
||||||
|
|
||||||
if ((address >= ADDR_CDI_FIRST) && (address <= ADDR_CDI_LAST)) begin
|
if ((address >= ADDR_CDI_FIRST) && (address <= ADDR_CDI_LAST)) begin
|
||||||
tmp_read_data = cdi_mem[address[2 : 0]];
|
tmp_read_data = cdi_mem[address[2 : 0]];
|
||||||
end
|
end
|
||||||
|
|
||||||
if ((address >= ADDR_UDI_FIRST) && (address <= ADDR_UDI_LAST)) begin
|
if ((address >= ADDR_UDI_FIRST) && (address <= ADDR_UDI_LAST)) begin
|
||||||
if (!system_mode_reg) begin
|
if (!rw_locked) begin
|
||||||
tmp_read_data = udi_rdata;
|
tmp_read_data = udi_rdata;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (address == ADDR_SPI_XFER) begin
|
if (address == ADDR_SPI_XFER) begin
|
||||||
|
if (spi_access_en) begin
|
||||||
tmp_read_data[0] = spi_ready;
|
tmp_read_data[0] = spi_ready;
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if (address == ADDR_SPI_DATA) begin
|
if (address == ADDR_SPI_DATA) begin
|
||||||
|
if (spi_access_en) begin
|
||||||
tmp_read_data[7 : 0] = spi_rx_data;
|
tmp_read_data[7 : 0] = spi_rx_data;
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -18,7 +18,7 @@ module tb_tk1 ();
|
|||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Internal constant and parameter definitions.
|
// Internal constant and parameter definitions.
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
parameter DEBUG = 1;
|
parameter DEBUG = 0;
|
||||||
|
|
||||||
parameter CLK_HALF_PERIOD = 1;
|
parameter CLK_HALF_PERIOD = 1;
|
||||||
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
|
parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD;
|
||||||
@ -62,6 +62,7 @@ module tb_tk1 ();
|
|||||||
localparam ADDR_SPI_XFER = 8'h81;
|
localparam ADDR_SPI_XFER = 8'h81;
|
||||||
localparam ADDR_SPI_DATA = 8'h82;
|
localparam ADDR_SPI_DATA = 8'h82;
|
||||||
|
|
||||||
|
localparam APP_RAM_START = 32'h40000000;
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Register and Wire declarations.
|
// Register and Wire declarations.
|
||||||
@ -76,7 +77,7 @@ module tb_tk1 ();
|
|||||||
reg tb_clk;
|
reg tb_clk;
|
||||||
reg tb_reset_n;
|
reg tb_reset_n;
|
||||||
reg tb_cpu_trap;
|
reg tb_cpu_trap;
|
||||||
wire tb_system_mode;
|
wire tb_rw_locked;
|
||||||
|
|
||||||
reg [31 : 0] tb_cpu_addr;
|
reg [31 : 0] tb_cpu_addr;
|
||||||
reg tb_cpu_instr;
|
reg tb_cpu_instr;
|
||||||
@ -95,6 +96,10 @@ module tb_tk1 ();
|
|||||||
wire tb_gpio3;
|
wire tb_gpio3;
|
||||||
wire tb_gpio4;
|
wire tb_gpio4;
|
||||||
|
|
||||||
|
reg tb_access_level_hi;
|
||||||
|
|
||||||
|
wire tb_fw_ram_en;
|
||||||
|
|
||||||
wire tb_spi_ss;
|
wire tb_spi_ss;
|
||||||
wire tb_spi_sck;
|
wire tb_spi_sck;
|
||||||
wire tb_spi_mosi;
|
wire tb_spi_mosi;
|
||||||
@ -122,7 +127,7 @@ module tb_tk1 ();
|
|||||||
.reset_n(tb_reset_n),
|
.reset_n(tb_reset_n),
|
||||||
|
|
||||||
.cpu_trap(tb_cpu_trap),
|
.cpu_trap(tb_cpu_trap),
|
||||||
.system_mode(tb_system_mode),
|
.rw_locked(tb_rw_locked),
|
||||||
|
|
||||||
.cpu_addr (tb_cpu_addr),
|
.cpu_addr (tb_cpu_addr),
|
||||||
.cpu_instr (tb_cpu_instr),
|
.cpu_instr (tb_cpu_instr),
|
||||||
@ -141,6 +146,10 @@ module tb_tk1 ();
|
|||||||
.gpio3(tb_gpio3),
|
.gpio3(tb_gpio3),
|
||||||
.gpio4(tb_gpio4),
|
.gpio4(tb_gpio4),
|
||||||
|
|
||||||
|
.access_level_hi(tb_access_level_hi),
|
||||||
|
|
||||||
|
.fw_ram_en(tb_fw_ram_en),
|
||||||
|
|
||||||
.spi_ss (tb_spi_ss),
|
.spi_ss (tb_spi_ss),
|
||||||
.spi_sck (tb_spi_sck),
|
.spi_sck (tb_spi_sck),
|
||||||
.spi_mosi(tb_spi_mosi),
|
.spi_mosi(tb_spi_mosi),
|
||||||
@ -192,7 +201,7 @@ module tb_tk1 ();
|
|||||||
$display("------------");
|
$display("------------");
|
||||||
if (tb_main_monitor) begin
|
if (tb_main_monitor) begin
|
||||||
$display("Inputs and outputs:");
|
$display("Inputs and outputs:");
|
||||||
$display("tb_cpu_trap: 0x%1x, system_mode: 0x%1x", tb_cpu_trap, tb_system_mode);
|
$display("tb_cpu_trap: 0x%1x, system_mode: 0x%1x", tb_cpu_trap, dut.system_mode);
|
||||||
$display("cpu_addr: 0x%08x, cpu_instr: 0x%1x, cpu_valid: 0x%1x, force_tap: 0x%1x",
|
$display("cpu_addr: 0x%08x, cpu_instr: 0x%1x, cpu_valid: 0x%1x, force_tap: 0x%1x",
|
||||||
tb_cpu_addr, tb_cpu_instr, tb_cpu_valid, tb_force_trap);
|
tb_cpu_addr, tb_cpu_instr, tb_cpu_valid, tb_force_trap);
|
||||||
$display("ram_addr_rand: 0x%08x, ram_data_rand: 0x%08x", tb_ram_addr_rand,
|
$display("ram_addr_rand: 0x%08x, ram_data_rand: 0x%08x", tb_ram_addr_rand,
|
||||||
@ -277,6 +286,8 @@ module tb_tk1 ();
|
|||||||
tb_gpio1 = 1'h0;
|
tb_gpio1 = 1'h0;
|
||||||
tb_gpio2 = 1'h0;
|
tb_gpio2 = 1'h0;
|
||||||
|
|
||||||
|
tb_access_level_hi = 1'h0;
|
||||||
|
|
||||||
tb_cs = 1'h0;
|
tb_cs = 1'h0;
|
||||||
tb_we = 1'h0;
|
tb_we = 1'h0;
|
||||||
tb_address = 8'h0;
|
tb_address = 8'h0;
|
||||||
@ -285,6 +296,25 @@ module tb_tk1 ();
|
|||||||
endtask // init_sim
|
endtask // init_sim
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// restore_mem_bus()
|
||||||
|
//
|
||||||
|
// Restore memory bus to its initial state
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
task restore_mem_bus();
|
||||||
|
begin : restore_mem_bus
|
||||||
|
tb_cpu_addr = 32'h0;
|
||||||
|
tb_cpu_instr = 1'h0;
|
||||||
|
tb_cpu_valid = 1'h0;
|
||||||
|
|
||||||
|
tb_cs = 1'h0;
|
||||||
|
tb_we = 1'h0;
|
||||||
|
tb_address = 8'h0;
|
||||||
|
tb_write_data = 32'h0;
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// write_word()
|
// write_word()
|
||||||
//
|
//
|
||||||
@ -301,7 +331,7 @@ module tb_tk1 ();
|
|||||||
tb_write_data = word;
|
tb_write_data = word;
|
||||||
tb_cs = 1;
|
tb_cs = 1;
|
||||||
tb_we = 1;
|
tb_we = 1;
|
||||||
#(2 * CLK_PERIOD);
|
#(CLK_PERIOD);
|
||||||
tb_cs = 0;
|
tb_cs = 0;
|
||||||
tb_we = 0;
|
tb_we = 0;
|
||||||
end
|
end
|
||||||
@ -354,21 +384,53 @@ module tb_tk1 ();
|
|||||||
#(CLK_PERIOD);
|
#(CLK_PERIOD);
|
||||||
tb_cs = 1'h0;
|
tb_cs = 1'h0;
|
||||||
|
|
||||||
if (DEBUG) begin
|
|
||||||
if (read_data == expected) begin
|
if (read_data == expected) begin
|
||||||
|
if (DEBUG) begin
|
||||||
$display("--- Reading 0x%08x from 0x%02x.", read_data, address);
|
$display("--- Reading 0x%08x from 0x%02x.", read_data, address);
|
||||||
end
|
end
|
||||||
|
end
|
||||||
else begin
|
else begin
|
||||||
$display("--- Error: Got 0x%08x when reading from 0x%02x, expected 0x%08x", read_data,
|
$display("--- Error: Got 0x%08x when reading from 0x%02x, expected 0x%08x", read_data,
|
||||||
address, expected);
|
address, expected);
|
||||||
error_ctr = error_ctr + 1;
|
error_ctr = error_ctr + 1;
|
||||||
end
|
end
|
||||||
$display("");
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
endtask // read_check_word
|
endtask // read_check_word
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// check_equal()
|
||||||
|
//
|
||||||
|
// Check that two values are equal
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
task check_equal(input [31 : 0] value, input [31 : 0] expected);
|
||||||
|
begin : check_equal
|
||||||
|
if (value != expected) begin
|
||||||
|
$display("--- Error: Got 0x%08x, expected 0x%08x", expected, value);
|
||||||
|
error_ctr = error_ctr + 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endtask // check_equal
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// fetch_instruction()
|
||||||
|
//
|
||||||
|
// Simulate fetch of an instruction at specified address.
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
task fetch_instruction(input [31 : 0] address);
|
||||||
|
begin : fetch_instruction
|
||||||
|
tb_cpu_addr = address;
|
||||||
|
tb_cpu_instr = 1'h1;
|
||||||
|
tb_cpu_valid = 1'h1;
|
||||||
|
#(CLK_PERIOD);
|
||||||
|
tb_cpu_addr = 32'h0;
|
||||||
|
tb_cpu_instr = 1'h0;
|
||||||
|
tb_cpu_valid = 1'h0;
|
||||||
|
end
|
||||||
|
endtask // fetch_instruction
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// test1()
|
// test1()
|
||||||
// Read out name and version.
|
// Read out name and version.
|
||||||
@ -400,10 +462,27 @@ module tb_tk1 ();
|
|||||||
|
|
||||||
$display("");
|
$display("");
|
||||||
$display("--- test2: Read out UDI started.");
|
$display("--- test2: Read out UDI started.");
|
||||||
|
tb_access_level_hi = 0;
|
||||||
|
reset_dut();
|
||||||
|
|
||||||
read_check_word(ADDR_UDI_FIRST, 32'h00010203);
|
read_check_word(ADDR_UDI_FIRST, 32'h00010203);
|
||||||
read_check_word(ADDR_UDI_LAST, 32'h04050607);
|
read_check_word(ADDR_UDI_LAST, 32'h04050607);
|
||||||
|
|
||||||
|
$display("--- test2: Switch to app mode.");
|
||||||
|
fetch_instruction(APP_RAM_START);
|
||||||
|
|
||||||
|
read_check_word(ADDR_UDI_FIRST, 32'h0);
|
||||||
|
read_check_word(ADDR_UDI_LAST, 32'h0);
|
||||||
|
|
||||||
|
$display("--- test2: Enter syscall.");
|
||||||
|
tb_access_level_hi = 1;
|
||||||
|
|
||||||
|
read_check_word(ADDR_UDI_FIRST, 32'h0);
|
||||||
|
read_check_word(ADDR_UDI_LAST, 32'h0);
|
||||||
|
|
||||||
|
$display("--- test2: Leave syscall.");
|
||||||
|
tb_access_level_hi = 0;
|
||||||
|
|
||||||
$display("--- test2: completed.");
|
$display("--- test2: completed.");
|
||||||
$display("");
|
$display("");
|
||||||
end
|
end
|
||||||
@ -418,6 +497,10 @@ module tb_tk1 ();
|
|||||||
begin
|
begin
|
||||||
tc_ctr = tc_ctr + 1;
|
tc_ctr = tc_ctr + 1;
|
||||||
|
|
||||||
|
$display("--- test5: Reset DUT to switch to fw mode.");
|
||||||
|
tb_access_level_hi = 0;
|
||||||
|
reset_dut();
|
||||||
|
|
||||||
$display("");
|
$display("");
|
||||||
$display("--- test3: Write and read CDI started.");
|
$display("--- test3: Write and read CDI started.");
|
||||||
$display("--- test3: Write CDI.");
|
$display("--- test3: Write CDI.");
|
||||||
@ -441,9 +524,9 @@ module tb_tk1 ();
|
|||||||
read_check_word(ADDR_CDI_LAST + 0, 32'h70717273);
|
read_check_word(ADDR_CDI_LAST + 0, 32'h70717273);
|
||||||
|
|
||||||
$display("--- test3: Switch to app mode.");
|
$display("--- test3: Switch to app mode.");
|
||||||
write_word(ADDR_SYSTEM_MODE_CTRL, 32'hdeadbeef);
|
fetch_instruction(APP_RAM_START);
|
||||||
|
|
||||||
$display("--- test3: Try to write CDI again.");
|
$display("--- test3: Try to write CDI from app mode.");
|
||||||
write_word(ADDR_CDI_FIRST + 0, 32'hfffefdfc);
|
write_word(ADDR_CDI_FIRST + 0, 32'hfffefdfc);
|
||||||
write_word(ADDR_CDI_FIRST + 1, 32'hefeeedec);
|
write_word(ADDR_CDI_FIRST + 1, 32'hefeeedec);
|
||||||
write_word(ADDR_CDI_FIRST + 2, 32'hdfdedddc);
|
write_word(ADDR_CDI_FIRST + 2, 32'hdfdedddc);
|
||||||
@ -453,7 +536,7 @@ module tb_tk1 ();
|
|||||||
write_word(ADDR_CDI_FIRST + 6, 32'h8f8e8d8c);
|
write_word(ADDR_CDI_FIRST + 6, 32'h8f8e8d8c);
|
||||||
write_word(ADDR_CDI_FIRST + 7, 32'h7f7e7d7c);
|
write_word(ADDR_CDI_FIRST + 7, 32'h7f7e7d7c);
|
||||||
|
|
||||||
$display("--- test3: Read CDI again.");
|
$display("--- test3: Read CDI from app mode.");
|
||||||
read_check_word(ADDR_CDI_FIRST + 0, 32'hf0f1f2f3);
|
read_check_word(ADDR_CDI_FIRST + 0, 32'hf0f1f2f3);
|
||||||
read_check_word(ADDR_CDI_FIRST + 1, 32'he0e1e2e3);
|
read_check_word(ADDR_CDI_FIRST + 1, 32'he0e1e2e3);
|
||||||
read_check_word(ADDR_CDI_FIRST + 2, 32'hd0d1d2d3);
|
read_check_word(ADDR_CDI_FIRST + 2, 32'hd0d1d2d3);
|
||||||
@ -463,46 +546,38 @@ module tb_tk1 ();
|
|||||||
read_check_word(ADDR_CDI_FIRST + 6, 32'h80818283);
|
read_check_word(ADDR_CDI_FIRST + 6, 32'h80818283);
|
||||||
read_check_word(ADDR_CDI_LAST + 0, 32'h70717273);
|
read_check_word(ADDR_CDI_LAST + 0, 32'h70717273);
|
||||||
|
|
||||||
|
$display("--- test3: Enter syscall.");
|
||||||
|
tb_access_level_hi = 1;
|
||||||
|
|
||||||
|
$display("--- test3: Try to write CDI from syscall.");
|
||||||
|
write_word(ADDR_CDI_FIRST + 0, 32'hfffefdfc);
|
||||||
|
write_word(ADDR_CDI_FIRST + 1, 32'hefeeedec);
|
||||||
|
write_word(ADDR_CDI_FIRST + 2, 32'hdfdedddc);
|
||||||
|
write_word(ADDR_CDI_FIRST + 3, 32'hcfcecdcc);
|
||||||
|
write_word(ADDR_CDI_FIRST + 4, 32'hafaeadac);
|
||||||
|
write_word(ADDR_CDI_FIRST + 5, 32'h9f9e9d9c);
|
||||||
|
write_word(ADDR_CDI_FIRST + 6, 32'h8f8e8d8c);
|
||||||
|
write_word(ADDR_CDI_FIRST + 7, 32'h7f7e7d7c);
|
||||||
|
|
||||||
|
$display("--- test3: Read CDI from syscall.");
|
||||||
|
read_check_word(ADDR_CDI_FIRST + 0, 32'hf0f1f2f3);
|
||||||
|
read_check_word(ADDR_CDI_FIRST + 1, 32'he0e1e2e3);
|
||||||
|
read_check_word(ADDR_CDI_FIRST + 2, 32'hd0d1d2d3);
|
||||||
|
read_check_word(ADDR_CDI_FIRST + 3, 32'hc0c1c2c3);
|
||||||
|
read_check_word(ADDR_CDI_FIRST + 4, 32'ha0a1a2a3);
|
||||||
|
read_check_word(ADDR_CDI_FIRST + 5, 32'h90919293);
|
||||||
|
read_check_word(ADDR_CDI_FIRST + 6, 32'h80818283);
|
||||||
|
read_check_word(ADDR_CDI_LAST + 0, 32'h70717273);
|
||||||
|
|
||||||
|
$display("--- test3: Leave syscall.");
|
||||||
|
tb_access_level_hi = 0;
|
||||||
|
|
||||||
$display("--- test3: completed.");
|
$display("--- test3: completed.");
|
||||||
$display("");
|
$display("");
|
||||||
end
|
end
|
||||||
endtask // test3
|
endtask // test3
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
// test4()
|
|
||||||
// Write and read blake2s entry point.
|
|
||||||
//----------------------------------------------------------------
|
|
||||||
task test4;
|
|
||||||
begin
|
|
||||||
tc_ctr = tc_ctr + 1;
|
|
||||||
|
|
||||||
$display("");
|
|
||||||
$display("--- test4: Write and read blake2s entry point in fw mode started.");
|
|
||||||
$display("--- test4: Reset DUT to switch to fw mode.");
|
|
||||||
reset_dut();
|
|
||||||
|
|
||||||
$display("--- test4: Write Blake2s entry point.");
|
|
||||||
write_word(ADDR_BLAKE2S, 32'hcafebabe);
|
|
||||||
|
|
||||||
$display("--- test4: Read Blake2s entry point.");
|
|
||||||
read_check_word(ADDR_BLAKE2S, 32'hcafebabe);
|
|
||||||
|
|
||||||
$display("--- test4: Switch to app mode.");
|
|
||||||
write_word(ADDR_SYSTEM_MODE_CTRL, 32'hf00ff00f);
|
|
||||||
|
|
||||||
$display("--- test4: Write Blake2s entry point again.");
|
|
||||||
write_word(ADDR_BLAKE2S, 32'hdeadbeef);
|
|
||||||
|
|
||||||
$display("--- test4: Read Blake2s entry point again");
|
|
||||||
read_check_word(ADDR_BLAKE2S, 32'hcafebabe);
|
|
||||||
|
|
||||||
$display("--- test4: completed.");
|
|
||||||
$display("");
|
|
||||||
end
|
|
||||||
endtask // test4
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// test5()
|
// test5()
|
||||||
// Write and read APP start address end size.
|
// Write and read APP start address end size.
|
||||||
@ -525,7 +600,7 @@ module tb_tk1 ();
|
|||||||
read_check_word(ADDR_APP_SIZE, 32'h47114711);
|
read_check_word(ADDR_APP_SIZE, 32'h47114711);
|
||||||
|
|
||||||
$display("--- test5: Switch to app mode.");
|
$display("--- test5: Switch to app mode.");
|
||||||
write_word(ADDR_SYSTEM_MODE_CTRL, 32'hf000000);
|
fetch_instruction(APP_RAM_START);
|
||||||
|
|
||||||
$display("--- test5: Write app start address and size again.");
|
$display("--- test5: Write app start address and size again.");
|
||||||
write_word(ADDR_APP_START, 32'hdeadbeef);
|
write_word(ADDR_APP_START, 32'hdeadbeef);
|
||||||
@ -543,7 +618,7 @@ module tb_tk1 ();
|
|||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// test6()
|
// test6()
|
||||||
// Write RAM address and data randomizatio in fw mode.
|
// Write and read RAM-address and data randomization.
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
task test6;
|
task test6;
|
||||||
begin
|
begin
|
||||||
@ -552,6 +627,7 @@ module tb_tk1 ();
|
|||||||
$display("");
|
$display("");
|
||||||
$display("--- test6: Write RAM addr and data randomization in fw mode.");
|
$display("--- test6: Write RAM addr and data randomization in fw mode.");
|
||||||
$display("--- test6: Reset DUT to switch to fw mode.");
|
$display("--- test6: Reset DUT to switch to fw mode.");
|
||||||
|
tb_access_level_hi = 0;
|
||||||
reset_dut();
|
reset_dut();
|
||||||
|
|
||||||
$display("--- test6: Write to ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND .");
|
$display("--- test6: Write to ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND .");
|
||||||
@ -562,9 +638,14 @@ module tb_tk1 ();
|
|||||||
"--- test6: Check value in dut ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND registers.");
|
"--- test6: Check value in dut ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND registers.");
|
||||||
$display("--- test6: ram_addr_rand_reg: 0x%04x, ram_data_rand_reg: 0x%08x",
|
$display("--- test6: ram_addr_rand_reg: 0x%04x, ram_data_rand_reg: 0x%08x",
|
||||||
dut.ram_addr_rand, dut.ram_data_rand);
|
dut.ram_addr_rand, dut.ram_data_rand);
|
||||||
|
check_equal(dut.ram_addr_rand, 15'h1337);
|
||||||
|
check_equal(dut.ram_data_rand, 32'h47114711);
|
||||||
|
read_check_word(ADDR_RAM_ADDR_RAND, 32'h0);
|
||||||
|
read_check_word(ADDR_RAM_DATA_RAND, 32'h0);
|
||||||
|
|
||||||
|
|
||||||
$display("--- test6: Switch to app mode.");
|
$display("--- test6: Switch to app mode.");
|
||||||
write_word(ADDR_SYSTEM_MODE_CTRL, 32'hf000000);
|
fetch_instruction(APP_RAM_START);
|
||||||
|
|
||||||
$display("--- test6: Write to ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND again.");
|
$display("--- test6: Write to ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND again.");
|
||||||
write_word(ADDR_RAM_ADDR_RAND, 32'hdeadbeef);
|
write_word(ADDR_RAM_ADDR_RAND, 32'hdeadbeef);
|
||||||
@ -574,6 +655,30 @@ module tb_tk1 ();
|
|||||||
"--- test6: Check value in dut ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND registers.");
|
"--- test6: Check value in dut ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND registers.");
|
||||||
$display("--- test6: ram_addr_rand_reg: 0x%04x, ram_data_rand_reg: 0x%08x",
|
$display("--- test6: ram_addr_rand_reg: 0x%04x, ram_data_rand_reg: 0x%08x",
|
||||||
dut.ram_addr_rand, dut.ram_data_rand);
|
dut.ram_addr_rand, dut.ram_data_rand);
|
||||||
|
check_equal(dut.ram_addr_rand, 15'h1337);
|
||||||
|
check_equal(dut.ram_data_rand, 32'h47114711);
|
||||||
|
read_check_word(ADDR_RAM_ADDR_RAND, 32'h0);
|
||||||
|
read_check_word(ADDR_RAM_DATA_RAND, 32'h0);
|
||||||
|
|
||||||
|
|
||||||
|
$display("--- test6: Enter syscall.");
|
||||||
|
tb_access_level_hi = 1;
|
||||||
|
|
||||||
|
$display("--- test6: Write to ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND again.");
|
||||||
|
write_word(ADDR_RAM_ADDR_RAND, 32'hdeadbeef);
|
||||||
|
write_word(ADDR_RAM_DATA_RAND, 32'hf00ff00f);
|
||||||
|
|
||||||
|
$display(
|
||||||
|
"--- test6: Check value in dut ADDR_RAM_ADDR_RAND and ADDR_RAM_DATA_RAND registers.");
|
||||||
|
$display("--- test6: ram_addr_rand_reg: 0x%04x, ram_data_rand_reg: 0x%08x",
|
||||||
|
dut.ram_addr_rand, dut.ram_data_rand);
|
||||||
|
check_equal(dut.ram_addr_rand, 15'h1337);
|
||||||
|
check_equal(dut.ram_data_rand, 32'h47114711);
|
||||||
|
read_check_word(ADDR_RAM_ADDR_RAND, 32'h0);
|
||||||
|
read_check_word(ADDR_RAM_DATA_RAND, 32'h0);
|
||||||
|
|
||||||
|
$display("--- test6: Leave syscall.");
|
||||||
|
tb_access_level_hi = 0;
|
||||||
|
|
||||||
$display("--- test6: completed.");
|
$display("--- test6: completed.");
|
||||||
$display("");
|
$display("");
|
||||||
@ -655,17 +760,20 @@ module tb_tk1 ();
|
|||||||
write_word(ADDR_CPU_MON_LAST, 32'hdeadcafe);
|
write_word(ADDR_CPU_MON_LAST, 32'hdeadcafe);
|
||||||
$display("--- test9: cpu_mon_first_reg: 0x%08x, cpu_mon_last_reg: 0x%08x",
|
$display("--- test9: cpu_mon_first_reg: 0x%08x, cpu_mon_last_reg: 0x%08x",
|
||||||
dut.cpu_mon_first_reg, dut.cpu_mon_last_reg);
|
dut.cpu_mon_first_reg, dut.cpu_mon_last_reg);
|
||||||
|
check_equal(dut.cpu_mon_first_reg, 32'h10000000);
|
||||||
|
check_equal(dut.cpu_mon_last_reg, 32'h20000000);
|
||||||
|
|
||||||
$display("--- test9: force_trap before illegal access: 0x%1x", tb_force_trap);
|
$display("--- test9: force_trap before illegal access: 0x%1x", tb_force_trap);
|
||||||
$display("--- test9: Creating an illegal access.");
|
$display("--- test9: Creating an illegal access.");
|
||||||
|
|
||||||
tb_cpu_addr = 32'h13371337;
|
fetch_instruction(32'h13371337);
|
||||||
tb_cpu_instr = 1'h1;
|
|
||||||
tb_cpu_valid = 1'h1;
|
|
||||||
#(2 * CLK_PERIOD);
|
|
||||||
$display("--- test9: cpu_addr: 0x%08x, cpu_instr: 0x%1x, cpu_valid: 0x%1x", tb_cpu_addr,
|
$display("--- test9: cpu_addr: 0x%08x, cpu_instr: 0x%1x, cpu_valid: 0x%1x", tb_cpu_addr,
|
||||||
tb_cpu_instr, tb_cpu_valid);
|
tb_cpu_instr, tb_cpu_valid);
|
||||||
|
check_equal(dut.cpu_mon_first_reg, 32'h10000000);
|
||||||
|
check_equal(dut.cpu_mon_last_reg, 32'h20000000);
|
||||||
|
|
||||||
$display("--- test9: force_trap: 0x%1x", tb_force_trap);
|
$display("--- test9: force_trap: 0x%1x", tb_force_trap);
|
||||||
|
check_equal(tb_force_trap, 1);
|
||||||
|
|
||||||
$display("--- test9: completed.");
|
$display("--- test9: completed.");
|
||||||
$display("");
|
$display("");
|
||||||
@ -673,6 +781,66 @@ module tb_tk1 ();
|
|||||||
endtask // test9
|
endtask // test9
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// check_inverting_spi_loopback_transfer_succeeds()
|
||||||
|
// Do an SPI tranfer. Check that the received value is the inverse
|
||||||
|
// of the value sent.
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
task check_inverting_spi_loopback_transfer_succeeds(input [32 : 0] data);
|
||||||
|
begin : check_inverting_spi_loopback_transfer
|
||||||
|
$display("--- test10: Sending a byte.");
|
||||||
|
write_word(ADDR_SPI_EN, 32'h1);
|
||||||
|
write_word(ADDR_SPI_DATA, data);
|
||||||
|
write_word(ADDR_SPI_XFER, 32'h1);
|
||||||
|
|
||||||
|
// Ready ready flag in SPI until it is set.
|
||||||
|
read_word(ADDR_SPI_XFER);
|
||||||
|
while (!tb_read_data) begin
|
||||||
|
read_word(ADDR_SPI_XFER);
|
||||||
|
end
|
||||||
|
$display("--- test10: Byte should have been sent.");
|
||||||
|
|
||||||
|
#(2 * CLK_PERIOD);
|
||||||
|
read_check_word(ADDR_SPI_DATA, ~data[7 : 0] & 8'hff);
|
||||||
|
write_word(ADDR_SPI_EN, 32'h0);
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// check_spi_does_not_transfer()
|
||||||
|
// Do an SPI transfer. Check that the SS, SCK and MISO signal are
|
||||||
|
// not active.
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
task check_spi_does_not_transfer;
|
||||||
|
begin : check_spi_does_not_transfer
|
||||||
|
reg [31 : 0] wait_ctr;
|
||||||
|
reg error;
|
||||||
|
localparam CLK_PER_SPI_BIT = 3;
|
||||||
|
localparam WAIT_MARGIN = 10;
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
wait_ctr = CLK_PER_SPI_BIT * 8 * WAIT_MARGIN;
|
||||||
|
|
||||||
|
$display("--- test10: Sending a byte.");
|
||||||
|
write_word(ADDR_SPI_EN, 32'h1);
|
||||||
|
write_word(ADDR_SPI_DATA, 32'haa);
|
||||||
|
write_word(ADDR_SPI_XFER, 32'h1);
|
||||||
|
|
||||||
|
$display("--- test10: Waiting to see if SPI signals change state.");
|
||||||
|
while (!error && (wait_ctr != 0)) begin
|
||||||
|
if (~tb_spi_ss || tb_spi_sck || tb_spi_mosi) begin
|
||||||
|
$display("--- Error: SPI signals changed state");
|
||||||
|
error_ctr = error_ctr + 1;
|
||||||
|
error = 1;
|
||||||
|
end
|
||||||
|
#(CLK_PERIOD);
|
||||||
|
wait_ctr = wait_ctr - 1;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
endtask
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// test10()
|
// test10()
|
||||||
// SPI master loopback test.
|
// SPI master loopback test.
|
||||||
@ -683,28 +851,28 @@ module tb_tk1 ();
|
|||||||
tb_monitor = 0;
|
tb_monitor = 0;
|
||||||
tb_spi_monitor = 0;
|
tb_spi_monitor = 0;
|
||||||
|
|
||||||
|
restore_mem_bus();
|
||||||
|
reset_dut();
|
||||||
|
|
||||||
$display("");
|
$display("");
|
||||||
$display("--- test10: Loopback in SPI Master started.");
|
$display("--- test10: Loopback in SPI Master started.");
|
||||||
|
|
||||||
#(CLK_PERIOD);
|
#(CLK_PERIOD);
|
||||||
|
|
||||||
// Sending 0xa7 trough the inverting loopback.
|
check_inverting_spi_loopback_transfer_succeeds(32'ha7);
|
||||||
$display("--- test10: Sending a byte.");
|
|
||||||
write_word(ADDR_SPI_EN, 32'h1);
|
|
||||||
write_word(ADDR_SPI_DATA, 32'ha7);
|
|
||||||
write_word(ADDR_SPI_XFER, 32'h1);
|
|
||||||
|
|
||||||
// Ready ready flag in SPI until it is set.
|
$display("--- test10: Switch to app mode.");
|
||||||
read_word(ADDR_SPI_XFER);
|
fetch_instruction(APP_RAM_START);
|
||||||
while (!tb_read_data) begin
|
|
||||||
read_word(ADDR_SPI_XFER);
|
|
||||||
end
|
|
||||||
$display("--- test10: Byte should have been sent.");
|
|
||||||
|
|
||||||
// 0x58 is the inverse of 0xa7.
|
check_spi_does_not_transfer();
|
||||||
#(2 * CLK_PERIOD);
|
|
||||||
read_check_word(ADDR_SPI_DATA, 32'h58);
|
$display("--- test10: Enter syscall.");
|
||||||
write_word(ADDR_SPI_EN, 32'h0);
|
tb_access_level_hi = 1;
|
||||||
|
|
||||||
|
check_inverting_spi_loopback_transfer_succeeds(32'hc8);
|
||||||
|
|
||||||
|
$display("--- test10: Leave syscall.");
|
||||||
|
tb_access_level_hi = 0;
|
||||||
|
|
||||||
tb_monitor = 0;
|
tb_monitor = 0;
|
||||||
tb_spi_monitor = 0;
|
tb_spi_monitor = 0;
|
||||||
@ -746,7 +914,6 @@ module tb_tk1 ();
|
|||||||
test1();
|
test1();
|
||||||
test2();
|
test2();
|
||||||
test3();
|
test3();
|
||||||
test4();
|
|
||||||
test5();
|
test5();
|
||||||
test6();
|
test6();
|
||||||
test7();
|
test7();
|
||||||
|
@ -17,8 +17,7 @@ module uds (
|
|||||||
input wire clk,
|
input wire clk,
|
||||||
input wire reset_n,
|
input wire reset_n,
|
||||||
|
|
||||||
input wire system_mode,
|
input wire en,
|
||||||
|
|
||||||
input wire cs,
|
input wire cs,
|
||||||
input wire [ 2 : 0] address,
|
input wire [ 2 : 0] address,
|
||||||
output wire [31 : 0] read_data,
|
output wire [31 : 0] read_data,
|
||||||
@ -89,7 +88,7 @@ module uds (
|
|||||||
if (cs) begin
|
if (cs) begin
|
||||||
tmp_ready = 1'h1;
|
tmp_ready = 1'h1;
|
||||||
|
|
||||||
if (!system_mode) begin
|
if (en) begin
|
||||||
if (uds_rd_reg[address[2 : 0]] == 1'h0) begin
|
if (uds_rd_reg[address[2 : 0]] == 1'h0) begin
|
||||||
uds_rd_we = 1'h1;
|
uds_rd_we = 1'h1;
|
||||||
end
|
end
|
||||||
|
9
hw/application_fpga/fw/irqpoc/Makefile
Normal file
9
hw/application_fpga/fw/irqpoc/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/custom_ops.S
Normal file
102
hw/application_fpga/fw/irqpoc/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/main.c
Normal file
10
hw/application_fpga/fw/irqpoc/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) {
|
||||||
|
}
|
||||||
|
}
|
40
hw/application_fpga/fw/irqpoc/start.S
Normal file
40
hw/application_fpga/fw/irqpoc/start.S
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Example firmware that demonstrates how to raise interrupts
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "custom_ops.S" // PicoRV32 custom instructions
|
||||||
|
|
||||||
|
.section ".text.init"
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
j init
|
||||||
|
|
||||||
|
.=0x10 // IRQ handler at fixed address 0x10
|
||||||
|
irq_handler:
|
||||||
|
// PicoRV32 stores the IRQ bitmask in x4.
|
||||||
|
// If bit 31 is 1: IRQ31 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
|
||||||
|
|
||||||
|
.=0x20 // Setting location of init to 0x20. Makes it easier to find when
|
||||||
|
// simulating.
|
||||||
|
init:
|
||||||
|
li t0, 0x7fffffff // IRQ31 mask
|
||||||
|
picorv32_maskirq_insn(zero, t0) // Enable IRQs
|
||||||
|
|
||||||
|
li t0, 0xe1000000 // IRQ31 trigger address
|
||||||
|
sw zero, 0(t0) // Raise IRQ by writing to interrupt trigger address.
|
||||||
|
// Writing any data triggers an interrupt.
|
||||||
|
loop:
|
||||||
|
j loop
|
||||||
|
|
||||||
|
.align 4 // Padding to please makehex.py which requires even 4-byte file
|
||||||
|
// sizes.
|
||||||
|
|
9
hw/application_fpga/fw/irqpoc_c_example/Makefile
Normal file
9
hw/application_fpga/fw/irqpoc_c_example/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_c_example/custom_ops.S
Normal file
102
hw/application_fpga/fw/irqpoc_c_example/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)
|
||||||
|
|
32
hw/application_fpga/fw/irqpoc_c_example/main.c
Normal file
32
hw/application_fpga/fw/irqpoc_c_example/main.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../tk1/types.h"
|
||||||
|
#include "../tk1/led.h"
|
||||||
|
#include "../tk1/assert.h"
|
||||||
|
|
||||||
|
// Proof-of-concept firmware for handling syscalls.
|
||||||
|
// This is NOT a best-practice example of secure syscall implementation.
|
||||||
|
|
||||||
|
#define SYSCALL_SET_LED 10
|
||||||
|
|
||||||
|
int32_t syscall_handler(uint32_t syscall_nr, uint32_t arg1) {
|
||||||
|
switch (syscall_nr) {
|
||||||
|
case SYSCALL_SET_LED:
|
||||||
|
set_led(arg1);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
assert(1 == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(1 == 2);
|
||||||
|
return -1; // This should never run
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
}
|
||||||
|
}
|
241
hw/application_fpga/fw/irqpoc_c_example/start.S
Normal file
241
hw/application_fpga/fw/irqpoc_c_example/start.S
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
/*
|
||||||
|
* 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 continuosly calls the SET_LED syscall in firmware (main.c).
|
||||||
|
//
|
||||||
|
#include "../tk1_mem.h"
|
||||||
|
#include "custom_ops.S" // PicoRV32 custom instructions
|
||||||
|
|
||||||
|
#define illegal_insn() .word 0
|
||||||
|
|
||||||
|
#define FW_SP_STORAGE (TK1_MMIO_FW_RAM_BASE + TK1_MMIO_FW_RAM_SIZE - 4)
|
||||||
|
#define FW_STACK_TOP (TK1_MMIO_FW_RAM_BASE + TK1_MMIO_FW_RAM_SIZE - 2*4)
|
||||||
|
|
||||||
|
#define LED_RED (1 << TK1_MMIO_TK1_LED_R_BIT)
|
||||||
|
#define LED_GREEN (1 << TK1_MMIO_TK1_LED_G_BIT)
|
||||||
|
#define LED_BLUE (1 << TK1_MMIO_TK1_LED_B_BIT)
|
||||||
|
|
||||||
|
.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.
|
||||||
|
li t4, (1 << 31)
|
||||||
|
beq x4, t4, irq_source_ok
|
||||||
|
unexpected_irq_source:
|
||||||
|
illegal_insn()
|
||||||
|
j unexpected_irq_source
|
||||||
|
irq_source_ok:
|
||||||
|
|
||||||
|
// Save app stack pointer. App is responsible for saving the rest of
|
||||||
|
// the registers.
|
||||||
|
la t0, FW_SP_STORAGE
|
||||||
|
sw sp, 0(t0)
|
||||||
|
|
||||||
|
// Setup firmware stack pointer
|
||||||
|
la sp, FW_STACK_TOP
|
||||||
|
|
||||||
|
// Run syscall handler
|
||||||
|
call syscall_handler
|
||||||
|
|
||||||
|
// Restore app stack pointer
|
||||||
|
la t0, FW_SP_STORAGE
|
||||||
|
lw sp, 0(t0)
|
||||||
|
|
||||||
|
// Verify that interrupt return address (x3) is in app RAM
|
||||||
|
li t0, TK1_RAM_BASE // 0x40000000
|
||||||
|
blt x3, t0, x3_invalid
|
||||||
|
li t0, TK1_RAM_BASE + TK1_RAM_SIZE // 0x40020000
|
||||||
|
bge x3, t0, x3_invalid
|
||||||
|
j x3_valid
|
||||||
|
x3_invalid:
|
||||||
|
illegal_insn()
|
||||||
|
j x3_invalid
|
||||||
|
x3_valid:
|
||||||
|
|
||||||
|
// Remove data left over from the syscall handling
|
||||||
|
mv x0, zero
|
||||||
|
mv x1, zero
|
||||||
|
// x2 (sp) is assumed to be preserved by the interrupt handler
|
||||||
|
// x3 (interrupt return address) assumed preserved
|
||||||
|
mv x4, zero
|
||||||
|
mv x5, zero
|
||||||
|
mv x6, zero
|
||||||
|
mv x7, zero
|
||||||
|
mv x8, zero
|
||||||
|
mv x9, zero
|
||||||
|
// x10 (a0) contains syscall return value. And should not be destroyed.
|
||||||
|
mv x11, zero
|
||||||
|
mv x12, zero
|
||||||
|
mv x13, zero
|
||||||
|
mv x14, zero
|
||||||
|
mv x15, zero
|
||||||
|
mv x16, zero
|
||||||
|
mv x17, zero
|
||||||
|
mv x18, zero
|
||||||
|
mv x19, zero
|
||||||
|
mv x20, zero
|
||||||
|
mv x21, zero
|
||||||
|
mv x22, zero
|
||||||
|
mv x23, zero
|
||||||
|
mv x24, zero
|
||||||
|
mv x25, zero
|
||||||
|
mv x26, zero
|
||||||
|
mv x27, zero
|
||||||
|
mv x28, zero
|
||||||
|
mv x29, zero
|
||||||
|
mv x30, zero
|
||||||
|
mv x31, zero
|
||||||
|
|
||||||
|
picorv32_retirq_insn() // Return from interrupt
|
||||||
|
|
||||||
|
//
|
||||||
|
// Init
|
||||||
|
//
|
||||||
|
.=0x100
|
||||||
|
init:
|
||||||
|
li t0, TK1_MMIO_TK1_LED
|
||||||
|
li t1, LED_RED
|
||||||
|
sw t1, 0(t0)
|
||||||
|
|
||||||
|
// Enable IRQs
|
||||||
|
li t0, 0x7fffffff // IRQ31 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
|
||||||
|
//
|
||||||
|
#define SYSCALL_SET_LED 10
|
||||||
|
|
||||||
|
.=0x1000
|
||||||
|
app_start:
|
||||||
|
// Set stack pointer to end of app RAM
|
||||||
|
li sp, 0x4001fffc
|
||||||
|
|
||||||
|
app_loop:
|
||||||
|
li a0, SYSCALL_SET_LED
|
||||||
|
li a1, LED_GREEN
|
||||||
|
call app_syscall
|
||||||
|
call app_delay
|
||||||
|
|
||||||
|
li a0, SYSCALL_SET_LED
|
||||||
|
li a1, LED_BLUE
|
||||||
|
call app_syscall
|
||||||
|
call app_delay
|
||||||
|
|
||||||
|
j app_loop
|
||||||
|
|
||||||
|
app_syscall:
|
||||||
|
// Save registers to stack
|
||||||
|
addi sp, sp, -32*4
|
||||||
|
sw x0, 0*4(sp)
|
||||||
|
sw x1, 1*4(sp)
|
||||||
|
// x2 (sp) is assumed to be preserved by the interrupt handler.
|
||||||
|
sw x3, 3*4(sp)
|
||||||
|
sw x4, 4*4(sp)
|
||||||
|
sw x5, 5*4(sp)
|
||||||
|
sw x6, 6*4(sp)
|
||||||
|
sw x7, 7*4(sp)
|
||||||
|
sw x8, 8*4(sp)
|
||||||
|
sw x9, 9*4(sp)
|
||||||
|
// x10 (a0) will contain syscall return value. And should not be saved.
|
||||||
|
sw x11, 11*4(sp)
|
||||||
|
sw x12, 12*4(sp)
|
||||||
|
sw x13, 13*4(sp)
|
||||||
|
sw x14, 14*4(sp)
|
||||||
|
sw x15, 15*4(sp)
|
||||||
|
sw x16, 16*4(sp)
|
||||||
|
sw x17, 17*4(sp)
|
||||||
|
sw x18, 18*4(sp)
|
||||||
|
sw x19, 19*4(sp)
|
||||||
|
sw x20, 20*4(sp)
|
||||||
|
sw x21, 21*4(sp)
|
||||||
|
sw x22, 22*4(sp)
|
||||||
|
sw x23, 23*4(sp)
|
||||||
|
sw x24, 24*4(sp)
|
||||||
|
sw x25, 25*4(sp)
|
||||||
|
sw x26, 26*4(sp)
|
||||||
|
sw x27, 27*4(sp)
|
||||||
|
sw x28, 28*4(sp)
|
||||||
|
sw x29, 29*4(sp)
|
||||||
|
sw x30, 30*4(sp)
|
||||||
|
sw x31, 31*4(sp)
|
||||||
|
|
||||||
|
// Trigger syscall interrupt
|
||||||
|
li t0, (1 << 31)
|
||||||
|
and t0, a0, t0
|
||||||
|
li t1, 0xe1000000 // Syscall interrupt trigger address
|
||||||
|
sw zero, 0(t1) // Trigger interrupt
|
||||||
|
|
||||||
|
// Restore registers from stack
|
||||||
|
lw x0, 0*4(sp)
|
||||||
|
lw x1, 1*4(sp)
|
||||||
|
// x2 (sp) is assumed to be preserved by the interrupt handler.
|
||||||
|
lw x3, 3*4(sp)
|
||||||
|
lw x4, 4*4(sp)
|
||||||
|
lw x5, 5*4(sp)
|
||||||
|
lw x6, 6*4(sp)
|
||||||
|
lw x7, 7*4(sp)
|
||||||
|
lw x8, 8*4(sp)
|
||||||
|
lw x9, 9*4(sp)
|
||||||
|
// x10 (a0) contains syscall return value. And should not be destroyed.
|
||||||
|
lw x11, 11*4(sp)
|
||||||
|
lw x12, 12*4(sp)
|
||||||
|
lw x13, 13*4(sp)
|
||||||
|
lw x14, 14*4(sp)
|
||||||
|
lw x15, 15*4(sp)
|
||||||
|
lw x16, 16*4(sp)
|
||||||
|
lw x17, 17*4(sp)
|
||||||
|
lw x18, 18*4(sp)
|
||||||
|
lw x19, 19*4(sp)
|
||||||
|
lw x20, 20*4(sp)
|
||||||
|
lw x21, 21*4(sp)
|
||||||
|
lw x22, 22*4(sp)
|
||||||
|
lw x23, 23*4(sp)
|
||||||
|
lw x24, 24*4(sp)
|
||||||
|
lw x25, 25*4(sp)
|
||||||
|
lw x26, 26*4(sp)
|
||||||
|
lw x27, 27*4(sp)
|
||||||
|
lw x28, 28*4(sp)
|
||||||
|
lw x29, 29*4(sp)
|
||||||
|
lw x30, 30*4(sp)
|
||||||
|
lw x31, 31*4(sp)
|
||||||
|
addi sp, sp, 32*4
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
app_delay:
|
||||||
|
li t5, 0x100000
|
||||||
|
app_delay_dec:
|
||||||
|
addi t5, t5, -1
|
||||||
|
bne t5, zero, app_delay_dec
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
app_end:
|
||||||
|
|
9
hw/application_fpga/fw/irqpoc_led_toggle/Makefile
Normal file
9
hw/application_fpga/fw/irqpoc_led_toggle/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_led_toggle/custom_ops.S
Normal file
102
hw/application_fpga/fw/irqpoc_led_toggle/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_led_toggle/main.c
Normal file
10
hw/application_fpga/fw/irqpoc_led_toggle/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) {
|
||||||
|
}
|
||||||
|
}
|
82
hw/application_fpga/fw/irqpoc_led_toggle/start.S
Normal file
82
hw/application_fpga/fw/irqpoc_led_toggle/start.S
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Example firmware demonstrating setting the LED from the interrupt handler.
|
||||||
|
// The LED color will alterate between blue and green.
|
||||||
|
// The color will be RED if an interrupt is triggered by an unexpected source.
|
||||||
|
//
|
||||||
|
// | Color | Execution context |
|
||||||
|
// |-------|-------------------|
|
||||||
|
// | Blue | Firmware loop |
|
||||||
|
// | Green | IRQ31 |
|
||||||
|
// | Red | Unexpected IRQ |
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "custom_ops.S" // PicoRV32 custom instructions
|
||||||
|
|
||||||
|
.section ".text.init"
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
j init
|
||||||
|
|
||||||
|
|
||||||
|
.=0x10 // IRQ handler at fixed address 0x10
|
||||||
|
irq_handler:
|
||||||
|
// PicoRV32 stores the IRQ bitmask in x4.
|
||||||
|
// If bit 31 is 1: IRQ31 was triggered.
|
||||||
|
li t4, (1 << 31)
|
||||||
|
bne x4, t4, unexpected_irq
|
||||||
|
call led_green
|
||||||
|
call delay
|
||||||
|
j irq_source_check_done
|
||||||
|
unexpected_irq:
|
||||||
|
call led_red
|
||||||
|
call delay
|
||||||
|
irq_source_check_done:
|
||||||
|
picorv32_retirq_insn() // Return from interrupt
|
||||||
|
|
||||||
|
|
||||||
|
init:
|
||||||
|
li t0, 0x7fffffff // IRQ31 mask
|
||||||
|
picorv32_maskirq_insn(zero, t0) // Enable IRQs
|
||||||
|
|
||||||
|
irq_trigger_loop:
|
||||||
|
call led_blue
|
||||||
|
call delay
|
||||||
|
|
||||||
|
li t0, 0xe1000000 // IRQ31 trigger address
|
||||||
|
sw zero, 0(t0) // Raise IRQ by writing to interrupt trigger address.
|
||||||
|
// Writing any data triggers an interrupt.
|
||||||
|
|
||||||
|
j irq_trigger_loop
|
||||||
|
|
||||||
|
led_red:
|
||||||
|
li t2, 0xff000024
|
||||||
|
li t3, (1 << 2)
|
||||||
|
sw t3, 0(t2)
|
||||||
|
ret
|
||||||
|
|
||||||
|
led_green:
|
||||||
|
li t2, 0xff000024
|
||||||
|
li t3, (1 << 1)
|
||||||
|
sw t3, 0(t2)
|
||||||
|
ret
|
||||||
|
|
||||||
|
led_blue:
|
||||||
|
li t2, 0xff000024
|
||||||
|
li t3, (1 << 0)
|
||||||
|
sw t3, 0(t2)
|
||||||
|
ret
|
||||||
|
|
||||||
|
delay:
|
||||||
|
li t5, 0x100000
|
||||||
|
delay_dec:
|
||||||
|
addi t5, t5, -1
|
||||||
|
bne t5, zero, delay_dec
|
||||||
|
ret
|
||||||
|
|
||||||
|
.align 4 // Padding to please makehex.py which requires even 4-byte file
|
||||||
|
// sizes.
|
||||||
|
|
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) {
|
||||||
|
}
|
||||||
|
}
|
110
hw/application_fpga/fw/irqpoc_with_app/start.S
Normal file
110
hw/application_fpga/fw/irqpoc_with_app/start.S
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* 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 IRQ_SYSCALL
|
||||||
|
// Checks are done to make sure that firmware RAM can/cannot be read depending
|
||||||
|
// on wether we're executing from firmware, syscall or app.
|
||||||
|
// Finally the app tries to jump firmware. This should result in a trap since
|
||||||
|
// the app is executing in app mode.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "custom_ops.S" // PicoRV32 custom instructions
|
||||||
|
|
||||||
|
#define illegal_insn() .word 0
|
||||||
|
|
||||||
|
.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.
|
||||||
|
li t4, (1 << 31)
|
||||||
|
bne x4, t4, unexpected_irq
|
||||||
|
// Firmware RAM should be readable from IRQ_SYSCALL
|
||||||
|
call check_can_read_test_val_from_fw_ram
|
||||||
|
j irq_source_check_done
|
||||||
|
unexpected_irq:
|
||||||
|
illegal_insn()
|
||||||
|
irq_source_check_done:
|
||||||
|
picorv32_retirq_insn() // Return from interrupt
|
||||||
|
|
||||||
|
//
|
||||||
|
// Init
|
||||||
|
//
|
||||||
|
.=0x100
|
||||||
|
init:
|
||||||
|
// Save test value in firmware RAM
|
||||||
|
li t0, 0xd0000000
|
||||||
|
li t1, 0x5555aaaa
|
||||||
|
sw t1, 0(t0)
|
||||||
|
|
||||||
|
// Firmware RAM should be readable from firmware mode
|
||||||
|
call check_can_read_test_val_from_fw_ram
|
||||||
|
|
||||||
|
// Enable IRQs
|
||||||
|
li t0, 0x7fffffff // IRQ31
|
||||||
|
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:
|
||||||
|
// Firmware RAM should not be readable from app mode
|
||||||
|
call check_cannot_read_test_val_from_fw_ram
|
||||||
|
|
||||||
|
// Raise IRQ_SYSCALL
|
||||||
|
li t0, 0xe1000000 // IRQ_SYSCALL (IRQ31) 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
|
||||||
|
|
||||||
|
|
||||||
|
check_cannot_read_test_val_from_fw_ram:
|
||||||
|
li t0, 0xd0000000
|
||||||
|
lw t1, 0(t0)
|
||||||
|
li t2, 0
|
||||||
|
bne t1, t2, cannot_read_test_val_from_fw_ram_fail
|
||||||
|
ret
|
||||||
|
cannot_read_test_val_from_fw_ram_fail:
|
||||||
|
illegal_insn()
|
||||||
|
|
||||||
|
check_can_read_test_val_from_fw_ram:
|
||||||
|
// Check that saved test value can not be read while in app mode
|
||||||
|
li t0, 0xd0000000
|
||||||
|
lw t1, 0(t0)
|
||||||
|
li t2, 0x5555aaaa
|
||||||
|
bne t1, t2, can_read_test_val_from_fw_ram_fail
|
||||||
|
ret
|
||||||
|
can_read_test_val_from_fw_ram_fail:
|
||||||
|
illegal_insn()
|
||||||
|
|
||||||
|
.align 4
|
||||||
|
app_end:
|
||||||
|
|
70
hw/application_fpga/fw/testapp/Makefile
Normal file
70
hw/application_fpga/fw/testapp/Makefile
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
P := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
OBJCOPY ?= llvm-objcopy
|
||||||
|
CC = clang
|
||||||
|
CFLAGS = \
|
||||||
|
-target riscv32-unknown-none-elf \
|
||||||
|
-march=rv32iczmmul \
|
||||||
|
-mabi=ilp32 \
|
||||||
|
-mcmodel=medany \
|
||||||
|
-static \
|
||||||
|
-std=gnu99 \
|
||||||
|
-O2 \
|
||||||
|
-ffast-math \
|
||||||
|
-fno-common \
|
||||||
|
-fno-builtin-printf \
|
||||||
|
-fno-builtin-putchar \
|
||||||
|
-fno-builtin-memcpy \
|
||||||
|
-nostdlib \
|
||||||
|
-mno-relax \
|
||||||
|
-Wall \
|
||||||
|
-Wpedantic \
|
||||||
|
-Wno-language-extension-token \
|
||||||
|
-Werror \
|
||||||
|
-flto \
|
||||||
|
-g
|
||||||
|
|
||||||
|
AS = clang
|
||||||
|
|
||||||
|
ASFLAGS = \
|
||||||
|
-target riscv32-unknown-none-elf \
|
||||||
|
-march=rv32iczmmul \
|
||||||
|
-mabi=ilp32 \
|
||||||
|
-mno-relax
|
||||||
|
|
||||||
|
LDFLAGS=-T $(P)/app.lds
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: testapp.bin
|
||||||
|
|
||||||
|
# Turn elf into bin for device
|
||||||
|
%.bin: %.elf
|
||||||
|
$(OBJCOPY) --input-target=elf32-littleriscv --output-target=binary $^ $@
|
||||||
|
chmod a-x $@
|
||||||
|
|
||||||
|
TESTAPP_FMTFILES = \
|
||||||
|
$(P)/main.c \
|
||||||
|
$(P)/syscall.h
|
||||||
|
|
||||||
|
TESTAPP_OBJS = \
|
||||||
|
$(P)/main.o \
|
||||||
|
$(P)/crt0.o \
|
||||||
|
$(P)/syscall.o \
|
||||||
|
$(P)/../tk1/led.o \
|
||||||
|
$(P)/../tk1/lib.o \
|
||||||
|
$(P)/../tk1/proto.o
|
||||||
|
|
||||||
|
testapp.elf: $(TESTAPP_OBJS)
|
||||||
|
$(CC) $(CFLAGS) $(TESTAPP_OBJS) $(LDFLAGS) -o $@
|
||||||
|
|
||||||
|
.PHONY: fmt
|
||||||
|
fmt:
|
||||||
|
clang-format --dry-run --ferror-limit=0 $(TESTAPP_FMTFILES)
|
||||||
|
clang-format --verbose -i $(TESTAPP_FMTFILES)
|
||||||
|
|
||||||
|
.PHONY: checkfmt
|
||||||
|
checkfmt:
|
||||||
|
clang-format --dry-run --ferror-limit=0 --Werror $(TESTAPP_FMTFILES)
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -f testapp.bin testapp.elf $(TESTAPP_OBJS)
|
64
hw/application_fpga/fw/testapp/app.lds
Normal file
64
hw/application_fpga/fw/testapp/app.lds
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
OUTPUT_ARCH( "riscv" )
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
RAM (rwx) : ORIGIN = 0x40000000, LENGTH = 0x20000 /* 128 KB */
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text.init :
|
||||||
|
{
|
||||||
|
*(.text.init)
|
||||||
|
} >RAM
|
||||||
|
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.text) /* .text sections (code) */
|
||||||
|
*(.text*) /* .text* sections (code) */
|
||||||
|
*(.rodata) /* .rodata sections (constants, strings, etc.) */
|
||||||
|
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||||
|
*(.srodata) /* .rodata sections (constants, strings, etc.) */
|
||||||
|
*(.srodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||||
|
. = ALIGN(4);
|
||||||
|
_etext = .;
|
||||||
|
_sidata = _etext;
|
||||||
|
} >RAM
|
||||||
|
|
||||||
|
.data : AT (_etext)
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sdata = .;
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.data) /* .data sections */
|
||||||
|
*(.data*) /* .data* sections */
|
||||||
|
*(.sdata) /* .sdata sections */
|
||||||
|
*(.sdata*) /* .sdata* sections */
|
||||||
|
. = ALIGN(4);
|
||||||
|
_edata = .;
|
||||||
|
} >RAM
|
||||||
|
|
||||||
|
/* Uninitialized data section */
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
_sbss = .;
|
||||||
|
*(.bss)
|
||||||
|
*(.bss*)
|
||||||
|
*(.sbss)
|
||||||
|
*(.sbss*)
|
||||||
|
*(COMMON)
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
_ebss = .;
|
||||||
|
} >RAM
|
||||||
|
|
||||||
|
/* libcrt0/crt0.S inits stack to start just below end of RAM */
|
||||||
|
}
|
53
hw/application_fpga/fw/testapp/crt0.S
Normal file
53
hw/application_fpga/fw/testapp/crt0.S
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2022 Tillitis AB <tillitis.se>
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
.section ".text.init"
|
||||||
|
.global _start
|
||||||
|
_start:
|
||||||
|
li x1, 0
|
||||||
|
li x2, 0
|
||||||
|
li x3, 0
|
||||||
|
li x4, 0
|
||||||
|
li x5, 0
|
||||||
|
li x6, 0
|
||||||
|
li x7, 0
|
||||||
|
li x8, 0
|
||||||
|
li x9, 0
|
||||||
|
li x10,0
|
||||||
|
li x11,0
|
||||||
|
li x12,0
|
||||||
|
li x13,0
|
||||||
|
li x14,0
|
||||||
|
li x15,0
|
||||||
|
li x16,0
|
||||||
|
li x17,0
|
||||||
|
li x18,0
|
||||||
|
li x19,0
|
||||||
|
li x20,0
|
||||||
|
li x21,0
|
||||||
|
li x22,0
|
||||||
|
li x23,0
|
||||||
|
li x24,0
|
||||||
|
li x25,0
|
||||||
|
li x26,0
|
||||||
|
li x27,0
|
||||||
|
li x28,0
|
||||||
|
li x29,0
|
||||||
|
li x30,0
|
||||||
|
li x31,0
|
||||||
|
|
||||||
|
/* init stack below 0x40020000 (TK1_RAM_BASE+TK1_RAM_SIZE) */
|
||||||
|
li sp, 0x4001fff0
|
||||||
|
|
||||||
|
/* zero-init bss section */
|
||||||
|
la a0, _sbss
|
||||||
|
la a1, _ebss
|
||||||
|
bge a0, a1, end_init_bss
|
||||||
|
|
||||||
|
loop_init_bss:
|
||||||
|
sw zero, 0(a0)
|
||||||
|
addi a0, a0, 4
|
||||||
|
blt a0, a1, loop_init_bss
|
||||||
|
|
||||||
|
end_init_bss:
|
||||||
|
call main
|
297
hw/application_fpga/fw/testapp/main.c
Normal file
297
hw/application_fpga/fw/testapp/main.c
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../tk1/led.h"
|
||||||
|
#include "../tk1/lib.h"
|
||||||
|
#include "../tk1/proto.h"
|
||||||
|
#include "../tk1/syscall_nrs.h"
|
||||||
|
#include "../tk1/types.h"
|
||||||
|
#include "../tk1_mem.h"
|
||||||
|
#include "syscall.h"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
volatile uint32_t *tk1name0 = (volatile uint32_t *)TK1_MMIO_TK1_NAME0;
|
||||||
|
volatile uint32_t *tk1name1 = (volatile uint32_t *)TK1_MMIO_TK1_NAME1;
|
||||||
|
volatile uint32_t *uds = (volatile uint32_t *)TK1_MMIO_UDS_FIRST;
|
||||||
|
volatile uint32_t *cdi = (volatile uint32_t *)TK1_MMIO_TK1_CDI_FIRST;
|
||||||
|
volatile uint32_t *udi = (volatile uint32_t *)TK1_MMIO_TK1_UDI_FIRST;
|
||||||
|
volatile uint32_t *system_mode_ctrl = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_MODE_CTRL;
|
||||||
|
volatile uint8_t *fw_ram = (volatile uint8_t *)TK1_MMIO_FW_RAM_BASE;
|
||||||
|
volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER;
|
||||||
|
volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER;
|
||||||
|
volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS;
|
||||||
|
volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
|
||||||
|
volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS;
|
||||||
|
volatile uint32_t *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#define UDS_WORDS 8
|
||||||
|
#define UDI_WORDS 2
|
||||||
|
#define CDI_WORDS 8
|
||||||
|
|
||||||
|
void *memcpy(void *dest, const void *src, size_t n)
|
||||||
|
{
|
||||||
|
uint8_t *src_byte = (uint8_t *)src;
|
||||||
|
uint8_t *dest_byte = (uint8_t *)dest;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
dest_byte[i] = src_byte[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
void puts(char *reason)
|
||||||
|
{
|
||||||
|
for (char *c = reason; *c != '\0'; c++) {
|
||||||
|
writebyte(*c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void putsn(char *p, int n)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
writebyte(p[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void puthex(uint8_t c)
|
||||||
|
{
|
||||||
|
unsigned int upper = (c >> 4) & 0xf;
|
||||||
|
unsigned int lower = c & 0xf;
|
||||||
|
writebyte(upper < 10 ? '0' + upper : 'a' - 10 + upper);
|
||||||
|
writebyte(lower < 10 ? '0' + lower : 'a' - 10 + lower);
|
||||||
|
}
|
||||||
|
|
||||||
|
void puthexn(uint8_t *p, int n)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
puthex(p[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hexdump(void *buf, int len)
|
||||||
|
{
|
||||||
|
uint8_t *byte_buf = (uint8_t *)buf;
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
puthex(byte_buf[i]);
|
||||||
|
if (i % 2 == 1) {
|
||||||
|
writebyte(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i != 1 && i % 16 == 1) {
|
||||||
|
puts("\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void reverseword(uint32_t *wordp)
|
||||||
|
{
|
||||||
|
*wordp = ((*wordp & 0xff000000) >> 24) | ((*wordp & 0x00ff0000) >> 8) |
|
||||||
|
((*wordp & 0x0000ff00) << 8) | ((*wordp & 0x000000ff) << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wait_timer_tick(uint32_t last_timer)
|
||||||
|
{
|
||||||
|
uint32_t newtimer;
|
||||||
|
for (;;) {
|
||||||
|
newtimer = *timer;
|
||||||
|
if (newtimer != last_timer) {
|
||||||
|
return newtimer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero_fwram(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < TK1_MMIO_FW_RAM_SIZE; i++) {
|
||||||
|
fw_ram[i] = 0x00;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int check_fwram_zero_except(unsigned int offset, uint8_t expected_val)
|
||||||
|
{
|
||||||
|
int failed = 0;
|
||||||
|
for (unsigned int i = 0; i < TK1_MMIO_FW_RAM_SIZE; i++) {
|
||||||
|
uint32_t addr = TK1_MMIO_FW_RAM_BASE + i;
|
||||||
|
uint8_t *p = (uint8_t *)addr;
|
||||||
|
uint8_t val = *(volatile uint8_t *)p;
|
||||||
|
int failed_now = 0;
|
||||||
|
if (i == offset) {
|
||||||
|
if (val != expected_val) {
|
||||||
|
failed_now = 1;
|
||||||
|
puts(" wrong value at: ");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (val != 0) {
|
||||||
|
failed_now = 1;
|
||||||
|
puts(" not zero at: ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (failed_now) {
|
||||||
|
failed = 1;
|
||||||
|
reverseword(&addr);
|
||||||
|
puthexn((uint8_t *)&addr, 4);
|
||||||
|
puts("\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void failmsg(char *s)
|
||||||
|
{
|
||||||
|
puts("FAIL: ");
|
||||||
|
puts(s);
|
||||||
|
puts("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
uint8_t in;
|
||||||
|
|
||||||
|
set_led(LED_BLUE);
|
||||||
|
|
||||||
|
// Wait for terminal program and a character to be typed
|
||||||
|
in = readbyte();
|
||||||
|
|
||||||
|
puts("\r\nI'm testapp on:");
|
||||||
|
// Output the TK1 core's NAME0 and NAME1
|
||||||
|
uint32_t name;
|
||||||
|
wordcpy_s(&name, 1, (void *)tk1name0, 1);
|
||||||
|
reverseword(&name);
|
||||||
|
putsn((char *)&name, 4);
|
||||||
|
puts(" ");
|
||||||
|
wordcpy_s(&name, 1, (void *)tk1name1, 1);
|
||||||
|
reverseword(&name);
|
||||||
|
putsn((char *)&name, 4);
|
||||||
|
puts("\r\n");
|
||||||
|
|
||||||
|
uint32_t zeros[8];
|
||||||
|
memset(zeros, 0, 8 * 4);
|
||||||
|
|
||||||
|
int anyfailed = 0;
|
||||||
|
|
||||||
|
uint32_t uds_local[UDS_WORDS];
|
||||||
|
uint32_t udi_local[UDI_WORDS];
|
||||||
|
|
||||||
|
uint32_t sw = *system_mode_ctrl;
|
||||||
|
if (sw != 0xffffffff) {
|
||||||
|
failmsg("system_mode_ctrl is not 0xffffffff");
|
||||||
|
anyfailed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should NOT be able to read from UDS in app-mode.
|
||||||
|
wordcpy_s(uds_local, UDS_WORDS, (void *)uds, UDS_WORDS);
|
||||||
|
if (!memeq(uds_local, zeros, UDS_WORDS * 4)) {
|
||||||
|
failmsg("Read from UDS in app-mode");
|
||||||
|
anyfailed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should NOT be able to read from UDI in app-mode.
|
||||||
|
wordcpy_s(udi_local, UDI_WORDS, (void *)udi, UDI_WORDS);
|
||||||
|
if (!memeq(udi_local, zeros, UDI_WORDS * 4)) {
|
||||||
|
failmsg("Read from UDI in app-mode");
|
||||||
|
anyfailed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t cdi_local[CDI_WORDS];
|
||||||
|
uint32_t cdi_local2[CDI_WORDS];
|
||||||
|
wordcpy_s(cdi_local, CDI_WORDS, (void *)cdi, CDI_WORDS);
|
||||||
|
|
||||||
|
// Write to CDI should NOT have any effect in app mode.
|
||||||
|
wordcpy_s((void *)cdi, CDI_WORDS, zeros, CDI_WORDS);
|
||||||
|
wordcpy_s(cdi_local2, CDI_WORDS, (void *)cdi, CDI_WORDS);
|
||||||
|
if (!memeq(cdi_local, cdi_local2, CDI_WORDS * 4)) {
|
||||||
|
failmsg("Write to CDI in app-mode");
|
||||||
|
anyfailed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
syscall_enable();
|
||||||
|
|
||||||
|
// Syscall should be able to access flash
|
||||||
|
puts("\r\nReading SPI flash capacity using syscall...\r\n");
|
||||||
|
int flash_capacity = syscall(TK1_SYSCALL_GET_FLASH_CAPACITY, 0);
|
||||||
|
if (flash_capacity != 0x14) {
|
||||||
|
failmsg("Expected SPI flash capacity: 0x14 (1 MByte)");
|
||||||
|
anyfailed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test FW_RAM.
|
||||||
|
*fw_ram = 0x21;
|
||||||
|
if (*fw_ram == 0x21) {
|
||||||
|
failmsg("Write and read FW RAM in app-mode");
|
||||||
|
anyfailed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("\r\nTesting timer... 3");
|
||||||
|
// Matching clock at 21 MHz, giving us timer in seconds
|
||||||
|
*timer_prescaler = 21 * 1000000;
|
||||||
|
|
||||||
|
// Test timer expiration after 1s
|
||||||
|
*timer = 1;
|
||||||
|
// Start the timer
|
||||||
|
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
|
||||||
|
while (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) {
|
||||||
|
}
|
||||||
|
// Now timer has expired and is ready to run again
|
||||||
|
puts(" 2");
|
||||||
|
|
||||||
|
// Test to interrupt a timer - and reads from timer register
|
||||||
|
// Starting 10s timer and interrupting it in 3s...
|
||||||
|
*timer = 10;
|
||||||
|
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
|
||||||
|
uint32_t last_timer = 10;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
last_timer = wait_timer_tick(last_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the timer
|
||||||
|
*timer_ctrl = (1 << TK1_MMIO_TIMER_CTRL_STOP_BIT);
|
||||||
|
puts(" 1. done.\r\n");
|
||||||
|
|
||||||
|
if (*timer_status & (1 << TK1_MMIO_TIMER_STATUS_RUNNING_BIT)) {
|
||||||
|
failmsg("Timer didn't stop");
|
||||||
|
anyfailed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*timer != 10) {
|
||||||
|
failmsg("Timer didn't reset to 10");
|
||||||
|
anyfailed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and display test results.
|
||||||
|
puts("\r\n--> ");
|
||||||
|
if (anyfailed) {
|
||||||
|
puts("Some test FAILED!\r\n");
|
||||||
|
} else {
|
||||||
|
puts("All tests passed.\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
puts("\r\nHere are 256 bytes from the TRNG:\r\n");
|
||||||
|
for (int j = 0; j < 8; j++) {
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
while ((*trng_status &
|
||||||
|
(1 << TK1_MMIO_TRNG_STATUS_READY_BIT)) == 0) {
|
||||||
|
}
|
||||||
|
uint32_t rnd = *trng_entropy;
|
||||||
|
puthexn((uint8_t *)&rnd, 4);
|
||||||
|
puts(" ");
|
||||||
|
}
|
||||||
|
puts("\r\n");
|
||||||
|
}
|
||||||
|
puts("\r\n");
|
||||||
|
|
||||||
|
puts("Now echoing what you type...Type + to reset device\r\n");
|
||||||
|
for (;;) {
|
||||||
|
in = readbyte(); // blocks
|
||||||
|
if (in == '+') {
|
||||||
|
syscall(TK1_SYSCALL_RESET, 0);
|
||||||
|
}
|
||||||
|
writebyte(in);
|
||||||
|
}
|
||||||
|
}
|
94
hw/application_fpga/fw/testapp/syscall.S
Normal file
94
hw/application_fpga/fw/testapp/syscall.S
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 Tillitis AB <tillitis.se>
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
#include "../tk1/picorv32/custom_ops.S"
|
||||||
|
|
||||||
|
.section ".text"
|
||||||
|
.globl syscall_enable
|
||||||
|
.globl syscall
|
||||||
|
|
||||||
|
syscall_enable:
|
||||||
|
// Enable IRQs
|
||||||
|
li t0, 0x7fffffff // IRQ31 mask
|
||||||
|
picorv32_maskirq_insn(zero, t0) // Enable IRQs
|
||||||
|
|
||||||
|
ret
|
||||||
|
|
||||||
|
syscall:
|
||||||
|
// Save registers to stack
|
||||||
|
addi sp, sp, -32*4
|
||||||
|
sw x0, 0*4(sp)
|
||||||
|
sw x1, 1*4(sp)
|
||||||
|
// x2 (sp) is assumed to be preserved by the interrupt handler.
|
||||||
|
sw x3, 3*4(sp)
|
||||||
|
sw x4, 4*4(sp)
|
||||||
|
sw x5, 5*4(sp)
|
||||||
|
sw x6, 6*4(sp)
|
||||||
|
sw x7, 7*4(sp)
|
||||||
|
sw x8, 8*4(sp)
|
||||||
|
sw x9, 9*4(sp)
|
||||||
|
// x10 (a0) will contain syscall return value. And should not be saved.
|
||||||
|
sw x11, 11*4(sp)
|
||||||
|
sw x12, 12*4(sp)
|
||||||
|
sw x13, 13*4(sp)
|
||||||
|
sw x14, 14*4(sp)
|
||||||
|
sw x15, 15*4(sp)
|
||||||
|
sw x16, 16*4(sp)
|
||||||
|
sw x17, 17*4(sp)
|
||||||
|
sw x18, 18*4(sp)
|
||||||
|
sw x19, 19*4(sp)
|
||||||
|
sw x20, 20*4(sp)
|
||||||
|
sw x21, 21*4(sp)
|
||||||
|
sw x22, 22*4(sp)
|
||||||
|
sw x23, 23*4(sp)
|
||||||
|
sw x24, 24*4(sp)
|
||||||
|
sw x25, 25*4(sp)
|
||||||
|
sw x26, 26*4(sp)
|
||||||
|
sw x27, 27*4(sp)
|
||||||
|
sw x28, 28*4(sp)
|
||||||
|
sw x29, 29*4(sp)
|
||||||
|
sw x30, 30*4(sp)
|
||||||
|
sw x31, 31*4(sp)
|
||||||
|
|
||||||
|
// Trigger syscall interrupt
|
||||||
|
li t0, (1 << 31)
|
||||||
|
and t0, a0, t0
|
||||||
|
li t1, 0xe1000000 // Syscall interrupt trigger address
|
||||||
|
sw zero, 0(t1) // Trigger interrupt
|
||||||
|
|
||||||
|
// Restore registers from stack
|
||||||
|
lw x0, 0*4(sp)
|
||||||
|
lw x1, 1*4(sp)
|
||||||
|
// x2 (sp) is assumed to be preserved by the interrupt handler.
|
||||||
|
lw x3, 3*4(sp)
|
||||||
|
lw x4, 4*4(sp)
|
||||||
|
lw x5, 5*4(sp)
|
||||||
|
lw x6, 6*4(sp)
|
||||||
|
lw x7, 7*4(sp)
|
||||||
|
lw x8, 8*4(sp)
|
||||||
|
lw x9, 9*4(sp)
|
||||||
|
// x10 (a0) contains syscall return value. And should not be destroyed.
|
||||||
|
lw x11, 11*4(sp)
|
||||||
|
lw x12, 12*4(sp)
|
||||||
|
lw x13, 13*4(sp)
|
||||||
|
lw x14, 14*4(sp)
|
||||||
|
lw x15, 15*4(sp)
|
||||||
|
lw x16, 16*4(sp)
|
||||||
|
lw x17, 17*4(sp)
|
||||||
|
lw x18, 18*4(sp)
|
||||||
|
lw x19, 19*4(sp)
|
||||||
|
lw x20, 20*4(sp)
|
||||||
|
lw x21, 21*4(sp)
|
||||||
|
lw x22, 22*4(sp)
|
||||||
|
lw x23, 23*4(sp)
|
||||||
|
lw x24, 24*4(sp)
|
||||||
|
lw x25, 25*4(sp)
|
||||||
|
lw x26, 26*4(sp)
|
||||||
|
lw x27, 27*4(sp)
|
||||||
|
lw x28, 28*4(sp)
|
||||||
|
lw x29, 29*4(sp)
|
||||||
|
lw x30, 30*4(sp)
|
||||||
|
lw x31, 31*4(sp)
|
||||||
|
addi sp, sp, 32*4
|
||||||
|
|
||||||
|
ret
|
12
hw/application_fpga/fw/testapp/syscall.h
Normal file
12
hw/application_fpga/fw/testapp/syscall.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2024 Tillitis AB <tillitis.se>
|
||||||
|
// SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
|
||||||
|
#include "../tk1/types.h"
|
||||||
|
|
||||||
|
#ifndef TKEY_APP_SYSCALL_H
|
||||||
|
#define TKEY_APP_SYSCALL_H
|
||||||
|
|
||||||
|
void syscall_enable(void);
|
||||||
|
int syscall(uint32_t number, uint32_t arg1);
|
||||||
|
|
||||||
|
#endif
|
@ -3,7 +3,7 @@
|
|||||||
* SPDX-License-Identifier: GPL-2.0-only
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../tk1/blake2s/blake2s.h"
|
#include "../tk1/flash.h"
|
||||||
#include "../tk1/lib.h"
|
#include "../tk1/lib.h"
|
||||||
#include "../tk1/proto.h"
|
#include "../tk1/proto.h"
|
||||||
#include "../tk1/types.h"
|
#include "../tk1/types.h"
|
||||||
@ -23,7 +23,6 @@ volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS
|
|||||||
volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
|
volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
|
||||||
volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS;
|
volatile uint32_t *trng_status = (volatile uint32_t *)TK1_MMIO_TRNG_STATUS;
|
||||||
volatile uint32_t *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY;
|
volatile uint32_t *trng_entropy = (volatile uint32_t *)TK1_MMIO_TRNG_ENTROPY;
|
||||||
volatile uint32_t *fw_blake2s_addr = (volatile uint32_t *)TK1_MMIO_TK1_BLAKE2S;
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
#define UDS_WORDS 8
|
#define UDS_WORDS 8
|
||||||
@ -151,11 +150,6 @@ void failmsg(char *s)
|
|||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
// Function pointer to blake2s()
|
|
||||||
volatile int (*fw_blake2s)(void *, unsigned long, const void *,
|
|
||||||
unsigned long, const void *, unsigned long,
|
|
||||||
blake2s_ctx *);
|
|
||||||
|
|
||||||
uint8_t in;
|
uint8_t in;
|
||||||
// Hard coded test UDS in ../../data/uds.hex
|
// Hard coded test UDS in ../../data/uds.hex
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@ -246,6 +240,16 @@ int main(void)
|
|||||||
anyfailed = 1;
|
anyfailed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t jedec_id[3];
|
||||||
|
puts("\r\nReading SPI flash capacity...\r\n");
|
||||||
|
flash_release_powerdown();
|
||||||
|
flash_read_jedec_id(jedec_id);
|
||||||
|
|
||||||
|
if (jedec_id[2] != 0x14) {
|
||||||
|
failmsg("Expected SPI flash capacity: 0x14 (1 MByte)");
|
||||||
|
anyfailed = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Test FW_RAM.
|
// Test FW_RAM.
|
||||||
puts("\r\nTesting FW_RAM (takes 15s on hw)...\r\n");
|
puts("\r\nTesting FW_RAM (takes 15s on hw)...\r\n");
|
||||||
for (unsigned int i = 0; i < TK1_MMIO_FW_RAM_SIZE; i++) {
|
for (unsigned int i = 0; i < TK1_MMIO_FW_RAM_SIZE; i++) {
|
||||||
@ -263,53 +267,6 @@ int main(void)
|
|||||||
anyfailed = 1;
|
anyfailed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store function pointer to blake2s() so it's reachable from app
|
|
||||||
*fw_blake2s_addr = (uint32_t)blake2s;
|
|
||||||
|
|
||||||
// Turn on application mode.
|
|
||||||
// -------------------------
|
|
||||||
|
|
||||||
*system_mode_ctrl = 1;
|
|
||||||
|
|
||||||
sw = *system_mode_ctrl;
|
|
||||||
if (sw != 0xffffffff) {
|
|
||||||
failmsg("system_mode_ctrl is not 0xffffffff in app mode");
|
|
||||||
anyfailed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should NOT be able to read from UDS in app-mode.
|
|
||||||
wordcpy_s(uds_local, UDS_WORDS, (void *)uds, UDS_WORDS);
|
|
||||||
if (!memeq(uds_local, zeros, UDS_WORDS * 4)) {
|
|
||||||
failmsg("Read from UDS in app-mode");
|
|
||||||
anyfailed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should NOT be able to read from UDI in app-mode.
|
|
||||||
wordcpy_s(udi_local, UDI_WORDS, (void *)udi, UDI_WORDS);
|
|
||||||
if (!memeq(udi_local, zeros, UDI_WORDS * 4)) {
|
|
||||||
failmsg("Read from UDI in app-mode");
|
|
||||||
anyfailed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t cdi_local[CDI_WORDS];
|
|
||||||
uint32_t cdi_local2[CDI_WORDS];
|
|
||||||
wordcpy_s(cdi_local, CDI_WORDS, (void *)cdi, CDI_WORDS);
|
|
||||||
|
|
||||||
// Write to CDI should NOT have any effect in app mode.
|
|
||||||
wordcpy_s((void *)cdi, CDI_WORDS, zeros, CDI_WORDS);
|
|
||||||
wordcpy_s(cdi_local2, CDI_WORDS, (void *)cdi, CDI_WORDS);
|
|
||||||
if (!memeq(cdi_local, cdi_local2, CDI_WORDS * 4)) {
|
|
||||||
failmsg("Write to CDI in app-mode");
|
|
||||||
anyfailed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test FW_RAM.
|
|
||||||
*fw_ram = 0x21;
|
|
||||||
if (*fw_ram == 0x21) {
|
|
||||||
failmsg("Write and read FW RAM in app-mode");
|
|
||||||
anyfailed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
puts("\r\nTesting timer... 3");
|
puts("\r\nTesting timer... 3");
|
||||||
// Matching clock at 18 MHz, giving us timer in seconds
|
// Matching clock at 18 MHz, giving us timer in seconds
|
||||||
*timer_prescaler = 18 * 1000000;
|
*timer_prescaler = 18 * 1000000;
|
||||||
@ -346,32 +303,6 @@ int main(void)
|
|||||||
anyfailed = 1;
|
anyfailed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Testing the blake2s MMIO in app mode
|
|
||||||
|
|
||||||
fw_blake2s = (volatile int (*)(void *, unsigned long, const void *,
|
|
||||||
unsigned long, const void *,
|
|
||||||
unsigned long, blake2s_ctx *)) *
|
|
||||||
fw_blake2s_addr;
|
|
||||||
|
|
||||||
char msg[17] = "dldlkjsdkljdslsdj";
|
|
||||||
uint32_t digest0[8];
|
|
||||||
uint32_t digest1[8];
|
|
||||||
blake2s_ctx b2s_ctx;
|
|
||||||
|
|
||||||
blake2s(&digest0[0], 32, NULL, 0, &msg, 17, &b2s_ctx);
|
|
||||||
fw_blake2s(&digest1[0], 32, NULL, 0, &msg, 17, &b2s_ctx);
|
|
||||||
|
|
||||||
puts("\r\ndigest #0: \r\n");
|
|
||||||
hexdump((uint8_t *)digest0, 32);
|
|
||||||
|
|
||||||
puts("digest #1: \r\n");
|
|
||||||
hexdump((uint8_t *)digest1, 32);
|
|
||||||
|
|
||||||
if (!memeq(digest0, digest1, 32)) {
|
|
||||||
failmsg("Digests not the same");
|
|
||||||
anyfailed = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check and display test results.
|
// Check and display test results.
|
||||||
puts("\r\n--> ");
|
puts("\r\n--> ");
|
||||||
if (anyfailed) {
|
if (anyfailed) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# Uses ../.clang-format
|
# Uses ../.clang-format
|
||||||
FMTFILES=main.c lib.h lib.c proto.h proto.c types.h assert.c assert.h led.c led.h
|
FMTFILES=main.c lib.h lib.c proto.h proto.c types.h assert.c assert.h led.c \
|
||||||
|
led.h syscall.c spi.c spi.h flash.c flash.h
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
fmt:
|
fmt:
|
||||||
clang-format --dry-run --ferror-limit=0 $(FMTFILES)
|
clang-format --dry-run --ferror-limit=0 $(FMTFILES)
|
||||||
|
216
hw/application_fpga/fw/tk1/flash.c
Normal file
216
hw/application_fpga/fw/tk1/flash.c
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
// Copyright (C) 2024 - Tillitis AB
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#include "flash.h"
|
||||||
|
#include "../tk1/types.h"
|
||||||
|
#include "../tk1_mem.h"
|
||||||
|
#include "spi.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
static volatile uint32_t *timer = (volatile uint32_t *)TK1_MMIO_TIMER_TIMER;
|
||||||
|
static volatile uint32_t *timer_prescaler = (volatile uint32_t *)TK1_MMIO_TIMER_PRESCALER;
|
||||||
|
static volatile uint32_t *timer_status = (volatile uint32_t *)TK1_MMIO_TIMER_STATUS;
|
||||||
|
static volatile uint32_t *timer_ctrl = (volatile uint32_t *)TK1_MMIO_TIMER_CTRL;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// CPU clock frequency in Hz
|
||||||
|
#define CPUFREQ 21000000
|
||||||
|
#define PAGE_SIZE 256
|
||||||
|
|
||||||
|
static void delay(int timeout_ms)
|
||||||
|
{
|
||||||
|
// Tick once every centisecond
|
||||||
|
*timer_prescaler = CPUFREQ / 100;
|
||||||
|
*timer = timeout_ms / 10;
|
||||||
|
|
||||||
|
*timer_ctrl |= (1 << TK1_MMIO_TIMER_CTRL_START_BIT);
|
||||||
|
|
||||||
|
while (*timer_status != 0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop timer
|
||||||
|
*timer_ctrl |= (1 << TK1_MMIO_TIMER_CTRL_STOP_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool flash_is_busy(void)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf = READ_STATUS_REG_1;
|
||||||
|
uint8_t rx_buf = {0x00};
|
||||||
|
|
||||||
|
spi_transfer(&tx_buf, sizeof(tx_buf), NULL, 0, &rx_buf, sizeof(rx_buf));
|
||||||
|
|
||||||
|
if (rx_buf & (1 << STATUS_REG_BUSY_BIT)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blocking until !busy
|
||||||
|
void flash_wait_busy(void)
|
||||||
|
{
|
||||||
|
while (flash_is_busy()) {
|
||||||
|
delay(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_write_enable(void)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf = WRITE_ENABLE;
|
||||||
|
|
||||||
|
spi_transfer(&tx_buf, sizeof(tx_buf), NULL, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_write_disable(void)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf = WRITE_DISABLE;
|
||||||
|
|
||||||
|
spi_transfer(&tx_buf, sizeof(tx_buf), NULL, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_sector_erase(uint32_t address)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf[4] = {0x00};
|
||||||
|
tx_buf[0] = SECTOR_ERASE;
|
||||||
|
tx_buf[1] = (address >> ADDR_BYTE_3_BIT) & 0xFF;
|
||||||
|
tx_buf[2] = (address >> ADDR_BYTE_2_BIT) & 0xFF;
|
||||||
|
/* tx_buf[3] is within a sector, and hence does not make a difference */
|
||||||
|
|
||||||
|
flash_write_enable();
|
||||||
|
spi_transfer(tx_buf, sizeof(tx_buf), NULL, 0, NULL, 0);
|
||||||
|
flash_wait_busy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_block_32_erase(uint32_t address)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf[4] = {0x00};
|
||||||
|
tx_buf[0] = BLOCK_ERASE_32K;
|
||||||
|
tx_buf[1] = (address >> ADDR_BYTE_3_BIT) & 0xFF;
|
||||||
|
tx_buf[2] = (address >> ADDR_BYTE_2_BIT) & 0xFF;
|
||||||
|
tx_buf[3] = (address >> ADDR_BYTE_1_BIT) & 0xFF;
|
||||||
|
|
||||||
|
flash_write_enable();
|
||||||
|
spi_transfer(tx_buf, sizeof(tx_buf), NULL, 0, NULL, 0);
|
||||||
|
flash_wait_busy();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 64 KiB block erase, only cares about address bits 16 and above.
|
||||||
|
void flash_block_64_erase(uint32_t address)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf[4] = {0x00};
|
||||||
|
tx_buf[0] = BLOCK_ERASE_64K;
|
||||||
|
tx_buf[1] = (address >> ADDR_BYTE_3_BIT) & 0xFF;
|
||||||
|
/* tx_buf[2] and tx_buf[3] is within a block, and hence does not make a
|
||||||
|
* difference */
|
||||||
|
|
||||||
|
flash_write_enable();
|
||||||
|
spi_transfer(tx_buf, sizeof(tx_buf), NULL, 0, NULL, 0);
|
||||||
|
flash_wait_busy();
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_release_powerdown(void)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf[4] = {0x00};
|
||||||
|
tx_buf[0] = RELEASE_POWER_DOWN;
|
||||||
|
|
||||||
|
spi_transfer(tx_buf, sizeof(tx_buf), NULL, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_powerdown(void)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf = POWER_DOWN;
|
||||||
|
|
||||||
|
spi_transfer(&tx_buf, sizeof(tx_buf), NULL, 0, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_read_manufacturer_device_id(uint8_t *device_id)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf[4] = {0x00};
|
||||||
|
tx_buf[0] = READ_MANUFACTURER_ID;
|
||||||
|
|
||||||
|
spi_transfer(tx_buf, sizeof(tx_buf), NULL, 0, device_id, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_read_jedec_id(uint8_t *jedec_id)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf = READ_JEDEC_ID;
|
||||||
|
|
||||||
|
spi_transfer(&tx_buf, sizeof(tx_buf), NULL, 0, jedec_id, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_read_unique_id(uint8_t *unique_id)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf[5] = {0x00};
|
||||||
|
tx_buf[0] = READ_UNIQUE_ID;
|
||||||
|
|
||||||
|
spi_transfer(tx_buf, sizeof(tx_buf), NULL, 0, unique_id, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void flash_read_status(uint8_t *status_reg)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf = READ_STATUS_REG_1;
|
||||||
|
|
||||||
|
spi_transfer(&tx_buf, sizeof(tx_buf), NULL, 0, status_reg, 1);
|
||||||
|
|
||||||
|
tx_buf = READ_STATUS_REG_2;
|
||||||
|
spi_transfer(&tx_buf, sizeof(tx_buf), NULL, 0, status_reg + 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int flash_read_data(uint32_t address, uint8_t *dest_buf, size_t size)
|
||||||
|
{
|
||||||
|
uint8_t tx_buf[4] = {0x00};
|
||||||
|
tx_buf[0] = READ_DATA;
|
||||||
|
tx_buf[1] = (address >> ADDR_BYTE_3_BIT) & 0xFF;
|
||||||
|
tx_buf[2] = (address >> ADDR_BYTE_2_BIT) & 0xFF;
|
||||||
|
tx_buf[3] = (address >> ADDR_BYTE_1_BIT) & 0xFF;
|
||||||
|
|
||||||
|
return spi_transfer(tx_buf, sizeof(tx_buf), NULL, 0, dest_buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only handles writes where the least significant byte of the start address is
|
||||||
|
// zero.
|
||||||
|
int flash_write_data(uint32_t address, uint8_t *data, size_t size)
|
||||||
|
{
|
||||||
|
if (size <= 0 || size > 4096) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t left = size;
|
||||||
|
uint8_t *p_data = data;
|
||||||
|
size_t n_bytes = 0;
|
||||||
|
|
||||||
|
uint8_t tx_buf[4] = {
|
||||||
|
PAGE_PROGRAM, /* tx_buf[0] */
|
||||||
|
(address >> ADDR_BYTE_3_BIT) & 0xFF, /* tx_buf[1] */
|
||||||
|
(address >> ADDR_BYTE_2_BIT) & 0xFF, /* tx_buf[2] */
|
||||||
|
0x00, /* tx_buf[3] */
|
||||||
|
};
|
||||||
|
|
||||||
|
while (left > 0) {
|
||||||
|
if (left >= PAGE_SIZE) {
|
||||||
|
n_bytes = PAGE_SIZE;
|
||||||
|
} else {
|
||||||
|
n_bytes = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
flash_write_enable();
|
||||||
|
|
||||||
|
if (spi_transfer(tx_buf, sizeof(tx_buf), p_data, n_bytes, NULL,
|
||||||
|
0) != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
left -= n_bytes;
|
||||||
|
p_data += n_bytes;
|
||||||
|
|
||||||
|
address += n_bytes;
|
||||||
|
tx_buf[1] = (address >> ADDR_BYTE_3_BIT) & 0xFF;
|
||||||
|
tx_buf[2] = (address >> ADDR_BYTE_2_BIT) & 0xFF;
|
||||||
|
|
||||||
|
flash_wait_busy();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
57
hw/application_fpga/fw/tk1/flash.h
Normal file
57
hw/application_fpga/fw/tk1/flash.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (C) 2024 - Tillitis AB
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#ifndef TKEY_FLASH_H
|
||||||
|
#define TKEY_FLASH_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define WRITE_ENABLE 0x06
|
||||||
|
#define WRITE_DISABLE 0x04
|
||||||
|
|
||||||
|
#define READ_STATUS_REG_1 0x05
|
||||||
|
#define READ_STATUS_REG_2 0x35
|
||||||
|
#define WRITE_STATUS_REG 0x01
|
||||||
|
|
||||||
|
#define PAGE_PROGRAM 0x02
|
||||||
|
#define SECTOR_ERASE 0x20
|
||||||
|
#define BLOCK_ERASE_32K 0x52
|
||||||
|
#define BLOCK_ERASE_64K 0xD8
|
||||||
|
#define CHIP_ERASE 0xC7
|
||||||
|
|
||||||
|
#define POWER_DOWN 0xB9
|
||||||
|
#define READ_DATA 0x03
|
||||||
|
#define RELEASE_POWER_DOWN 0xAB
|
||||||
|
|
||||||
|
#define READ_MANUFACTURER_ID 0x90
|
||||||
|
#define READ_JEDEC_ID 0x9F
|
||||||
|
#define READ_UNIQUE_ID 0x4B
|
||||||
|
|
||||||
|
#define ENABLE_RESET 0x66
|
||||||
|
#define RESET 0x99
|
||||||
|
|
||||||
|
#define ADDR_BYTE_3_BIT 16
|
||||||
|
#define ADDR_BYTE_2_BIT 8
|
||||||
|
#define ADDR_BYTE_1_BIT 0
|
||||||
|
|
||||||
|
#define STATUS_REG_BUSY_BIT 0
|
||||||
|
#define STATUS_REG_WEL_BIT 1
|
||||||
|
|
||||||
|
bool flash_is_busy(void);
|
||||||
|
void flash_wait_busy(void);
|
||||||
|
void flash_write_enable(void);
|
||||||
|
void flash_write_disable(void);
|
||||||
|
void flash_sector_erase(uint32_t address);
|
||||||
|
void flash_block_32_erase(uint32_t address);
|
||||||
|
void flash_block_64_erase(uint32_t address);
|
||||||
|
void flash_release_powerdown(void);
|
||||||
|
void flash_powerdown(void);
|
||||||
|
void flash_read_manufacturer_device_id(uint8_t *device_id);
|
||||||
|
void flash_read_jedec_id(uint8_t *jedec_id);
|
||||||
|
void flash_read_unique_id(uint8_t *unique_id);
|
||||||
|
void flash_read_status(uint8_t *status_reg);
|
||||||
|
int flash_read_data(uint32_t address, uint8_t *dest_buf, size_t size);
|
||||||
|
int flash_write_data(uint32_t address, uint8_t *data, size_t size);
|
||||||
|
|
||||||
|
#endif
|
7
hw/application_fpga/fw/tk1/picorv32/README.md
Normal file
7
hw/application_fpga/fw/tk1/picorv32/README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# PicoRV32
|
||||||
|
|
||||||
|
## custom_ops.S
|
||||||
|
|
||||||
|
Custom PicoRV32 instructions are located in `custom_ops.S`.
|
||||||
|
`custom_ops.S` is imported from upstream PicoRV32 commit:
|
||||||
|
YosysHQ/picorv32@70f3c33
|
102
hw/application_fpga/fw/tk1/picorv32/custom_ops.S
Normal file
102
hw/application_fpga/fw/tk1/picorv32/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)
|
||||||
|
|
88
hw/application_fpga/fw/tk1/spi.c
Normal file
88
hw/application_fpga/fw/tk1/spi.c
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
// Copyright (C) 2024 - Tillitis AB
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#include "spi.h"
|
||||||
|
#include "../tk1/types.h"
|
||||||
|
#include "../tk1_mem.h"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
static volatile uint32_t *spi_en = (volatile uint32_t *)(TK1_MMIO_TK1_BASE | 0x200);
|
||||||
|
static volatile uint32_t *spi_xfer = (volatile uint32_t *)(TK1_MMIO_TK1_BASE | 0x204);
|
||||||
|
static volatile uint32_t *spi_data = (volatile uint32_t *)(TK1_MMIO_TK1_BASE | 0x208);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// returns non-zero when the SPI-master is ready, and zero if not
|
||||||
|
// ready. This can be used to check if the SPI-master is available
|
||||||
|
// in the hardware.
|
||||||
|
int spi_ready(void)
|
||||||
|
{
|
||||||
|
return *spi_xfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_enable(void)
|
||||||
|
{
|
||||||
|
*spi_en = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_disable(void)
|
||||||
|
{
|
||||||
|
*spi_en = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _spi_write(uint8_t *cmd, size_t size)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
while (!spi_ready()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
*spi_data = cmd[i];
|
||||||
|
*spi_xfer = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!spi_ready()) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _spi_read(uint8_t *buf, size_t size)
|
||||||
|
{
|
||||||
|
|
||||||
|
while (!spi_ready()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
|
||||||
|
*spi_data = 0x00;
|
||||||
|
*spi_xfer = 1;
|
||||||
|
|
||||||
|
// wait until spi master is done
|
||||||
|
while (!spi_ready()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[i] = (*spi_data & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to both read and write data to the connected SPI flash.
|
||||||
|
int spi_transfer(uint8_t *cmd, size_t cmd_size, uint8_t *tx_buf, size_t tx_size,
|
||||||
|
uint8_t *rx_buf, size_t rx_size)
|
||||||
|
{
|
||||||
|
if (cmd == NULL || cmd_size == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_enable();
|
||||||
|
|
||||||
|
_spi_write(cmd, cmd_size);
|
||||||
|
|
||||||
|
if (tx_buf != NULL || tx_size != 0) {
|
||||||
|
_spi_write(tx_buf, tx_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rx_buf != NULL && rx_size != 0) {
|
||||||
|
_spi_read(rx_buf, rx_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
spi_disable();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
13
hw/application_fpga/fw/tk1/spi.h
Normal file
13
hw/application_fpga/fw/tk1/spi.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (C) 2024 - Tillitis AB
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#ifndef TKEY_SPI_H
|
||||||
|
#define TKEY_SPI_H
|
||||||
|
|
||||||
|
#include "../tk1/types.h"
|
||||||
|
|
||||||
|
int spi_ready(void);
|
||||||
|
int spi_transfer(uint8_t *cmd, size_t cmd_size, uint8_t *tx_buf, size_t tx_size,
|
||||||
|
uint8_t *rx_buf, size_t rx_size);
|
||||||
|
|
||||||
|
#endif
|
@ -1,11 +1,102 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2022, 2023 - Tillitis AB
|
* Copyright (C) 2022, 2023, 2024, 2025 - Tillitis AB
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "../tk1_mem.h"
|
||||||
|
#include "picorv32/custom_ops.S" // PicoRV32 custom instructions
|
||||||
|
|
||||||
|
#define illegal_insn() .word 0
|
||||||
|
|
||||||
|
#define FW_SP_STORAGE (TK1_MMIO_FW_RAM_BASE + TK1_MMIO_FW_RAM_SIZE - 4)
|
||||||
|
#define FW_STACK_TOP (TK1_MMIO_FW_RAM_BASE + TK1_MMIO_FW_RAM_SIZE - 2*4)
|
||||||
|
|
||||||
.section ".text.init"
|
.section ".text.init"
|
||||||
.globl _start
|
.globl _start
|
||||||
_start:
|
_start:
|
||||||
|
j init
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IRQ handler
|
||||||
|
*/
|
||||||
|
.=0x10
|
||||||
|
irq_handler:
|
||||||
|
// PicoRV32 stores the IRQ bitmask in x4.
|
||||||
|
// If bit 31 is 1: IRQ31 was triggered.
|
||||||
|
li t4, (1 << 31)
|
||||||
|
beq x4, t4, irq_source_ok
|
||||||
|
unexpected_irq_source:
|
||||||
|
illegal_insn()
|
||||||
|
j unexpected_irq_source
|
||||||
|
irq_source_ok:
|
||||||
|
|
||||||
|
// Save app stack pointer. App is responsible for saving the rest of
|
||||||
|
// the registers.
|
||||||
|
li t0, FW_SP_STORAGE
|
||||||
|
sw sp, 0(t0)
|
||||||
|
|
||||||
|
// Setup firmware stack pointer
|
||||||
|
li sp, FW_STACK_TOP
|
||||||
|
|
||||||
|
// Run syscall handler
|
||||||
|
call syscall_handler
|
||||||
|
|
||||||
|
// Restore app stack pointer
|
||||||
|
li t0, FW_SP_STORAGE
|
||||||
|
lw sp, 0(t0)
|
||||||
|
|
||||||
|
// Verify that interrupt return address (x3) is in app RAM
|
||||||
|
li t0, TK1_RAM_BASE // 0x40000000
|
||||||
|
blt x3, t0, x3_invalid
|
||||||
|
li t0, TK1_RAM_BASE + TK1_RAM_SIZE // 0x40020000
|
||||||
|
bge x3, t0, x3_invalid
|
||||||
|
j x3_valid
|
||||||
|
x3_invalid:
|
||||||
|
illegal_insn()
|
||||||
|
j x3_invalid
|
||||||
|
x3_valid:
|
||||||
|
|
||||||
|
// Remove data left over from the syscall handling
|
||||||
|
mv x0, zero
|
||||||
|
mv x1, zero
|
||||||
|
// x2 (sp) is assumed to be preserved by the interrupt handler
|
||||||
|
// x3 (interrupt return address) assumed preserved
|
||||||
|
mv x4, zero
|
||||||
|
mv x5, zero
|
||||||
|
mv x6, zero
|
||||||
|
mv x7, zero
|
||||||
|
mv x8, zero
|
||||||
|
mv x9, zero
|
||||||
|
// x10 (a0) contains syscall return value. And should not be destroyed.
|
||||||
|
mv x11, zero
|
||||||
|
mv x12, zero
|
||||||
|
mv x13, zero
|
||||||
|
mv x14, zero
|
||||||
|
mv x15, zero
|
||||||
|
mv x16, zero
|
||||||
|
mv x17, zero
|
||||||
|
mv x18, zero
|
||||||
|
mv x19, zero
|
||||||
|
mv x20, zero
|
||||||
|
mv x21, zero
|
||||||
|
mv x22, zero
|
||||||
|
mv x23, zero
|
||||||
|
mv x24, zero
|
||||||
|
mv x25, zero
|
||||||
|
mv x26, zero
|
||||||
|
mv x27, zero
|
||||||
|
mv x28, zero
|
||||||
|
mv x29, zero
|
||||||
|
mv x30, zero
|
||||||
|
mv x31, zero
|
||||||
|
|
||||||
|
picorv32_retirq_insn() // Return from interrupt
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Init
|
||||||
|
*/
|
||||||
|
.=0x100
|
||||||
|
init:
|
||||||
li x1, 0
|
li x1, 0
|
||||||
li x2, 0
|
li x2, 0
|
||||||
li x3, 0
|
li x3, 0
|
||||||
|
41
hw/application_fpga/fw/tk1/syscall.c
Normal file
41
hw/application_fpga/fw/tk1/syscall.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2025 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../tk1/assert.h"
|
||||||
|
#include "../tk1/flash.h"
|
||||||
|
#include "../tk1/led.h"
|
||||||
|
#include "../tk1/syscall_nrs.h"
|
||||||
|
#include "../tk1/types.h"
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
static volatile uint32_t *system_reset = (volatile uint32_t *)TK1_MMIO_TK1_SYSTEM_RESET;
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
// Proof-of-concept firmware for handling syscalls.
|
||||||
|
// This is NOT a best-practice example of secure syscall implementation.
|
||||||
|
|
||||||
|
int32_t syscall_handler(uint32_t syscall_nr, uint32_t arg1)
|
||||||
|
{
|
||||||
|
switch (syscall_nr) {
|
||||||
|
case TK1_SYSCALL_RESET:
|
||||||
|
*system_reset = 1;
|
||||||
|
return 0;
|
||||||
|
case TK1_SYSCALL_SET_LED:
|
||||||
|
set_led(arg1);
|
||||||
|
return 0;
|
||||||
|
case TK1_SYSCALL_GET_FLASH_CAPACITY: {
|
||||||
|
uint8_t jedec_id[3];
|
||||||
|
flash_release_powerdown();
|
||||||
|
flash_read_jedec_id(jedec_id);
|
||||||
|
flash_powerdown();
|
||||||
|
return jedec_id[2];
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
assert(1 == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(1 == 2);
|
||||||
|
return -1; // This should never run
|
||||||
|
}
|
13
hw/application_fpga/fw/tk1/syscall_nrs.h
Normal file
13
hw/application_fpga/fw/tk1/syscall_nrs.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// Copyright (C) 2025 - Tillitis AB
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
#ifndef TKEY_SYSCALL_H
|
||||||
|
#define TKEY_SYSCALL_H
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TK1_SYSCALL_RESET = 1,
|
||||||
|
TK1_SYSCALL_SET_LED = 10,
|
||||||
|
TK1_SYSCALL_GET_FLASH_CAPACITY = 11,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -14,7 +14,7 @@ typedef long long int64_t;
|
|||||||
typedef unsigned char uint8_t;
|
typedef unsigned char uint8_t;
|
||||||
typedef unsigned long size_t;
|
typedef unsigned long size_t;
|
||||||
|
|
||||||
#define NULL ((char *)0)
|
#define NULL ((void *)0)
|
||||||
|
|
||||||
#define FALSE 0
|
#define FALSE 0
|
||||||
#define TRUE !FALSE
|
#define TRUE !FALSE
|
||||||
|
@ -54,11 +54,13 @@ module application_fpga (
|
|||||||
localparam UART_PREFIX = 6'h03;
|
localparam UART_PREFIX = 6'h03;
|
||||||
localparam TOUCH_SENSE_PREFIX = 6'h04;
|
localparam TOUCH_SENSE_PREFIX = 6'h04;
|
||||||
localparam FW_RAM_PREFIX = 6'h10;
|
localparam FW_RAM_PREFIX = 6'h10;
|
||||||
|
localparam IRQ31_PREFIX = 6'h21;
|
||||||
localparam TK1_PREFIX = 6'h3f;
|
localparam TK1_PREFIX = 6'h3f;
|
||||||
|
|
||||||
// Instruction used to cause a trap.
|
// Instruction used to cause a trap.
|
||||||
localparam ILLEGAL_INSTRUCTION = 32'h0;
|
localparam ILLEGAL_INSTRUCTION = 32'h0;
|
||||||
|
|
||||||
|
localparam IRQ31_IRQ_MASK = 2 ** 31;
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Registers, memories with associated wires.
|
// Registers, memories with associated wires.
|
||||||
@ -77,11 +79,13 @@ module application_fpga (
|
|||||||
wire reset_n;
|
wire reset_n;
|
||||||
|
|
||||||
/* verilator lint_off UNOPTFLAT */
|
/* verilator lint_off UNOPTFLAT */
|
||||||
|
reg [31 : 0] cpu_irq;
|
||||||
wire cpu_trap;
|
wire cpu_trap;
|
||||||
wire cpu_valid;
|
wire cpu_valid;
|
||||||
wire cpu_instr;
|
wire cpu_instr;
|
||||||
wire [03 : 0] cpu_wstrb;
|
wire [03 : 0] cpu_wstrb;
|
||||||
/* verilator lint_off UNUSED */
|
/* verilator lint_off UNUSED */
|
||||||
|
wire [31 : 0] cpu_eoi;
|
||||||
wire [31 : 0] cpu_addr;
|
wire [31 : 0] cpu_addr;
|
||||||
wire [31 : 0] cpu_wdata;
|
wire [31 : 0] cpu_wdata;
|
||||||
|
|
||||||
@ -129,6 +133,7 @@ module application_fpga (
|
|||||||
reg [31 : 0] fw_ram_write_data;
|
reg [31 : 0] fw_ram_write_data;
|
||||||
wire [31 : 0] fw_ram_read_data;
|
wire [31 : 0] fw_ram_read_data;
|
||||||
wire fw_ram_ready;
|
wire fw_ram_ready;
|
||||||
|
wire fw_ram_en;
|
||||||
|
|
||||||
reg touch_sense_cs;
|
reg touch_sense_cs;
|
||||||
reg touch_sense_we;
|
reg touch_sense_we;
|
||||||
@ -136,13 +141,17 @@ module application_fpga (
|
|||||||
wire [31 : 0] touch_sense_read_data;
|
wire [31 : 0] touch_sense_read_data;
|
||||||
wire touch_sense_ready;
|
wire touch_sense_ready;
|
||||||
|
|
||||||
|
reg irq31_cs;
|
||||||
|
reg irq31_we;
|
||||||
|
reg irq31_eoi;
|
||||||
|
|
||||||
reg tk1_cs;
|
reg tk1_cs;
|
||||||
reg tk1_we;
|
reg tk1_we;
|
||||||
reg [ 7 : 0] tk1_address;
|
reg [ 7 : 0] tk1_address;
|
||||||
reg [31 : 0] tk1_write_data;
|
reg [31 : 0] tk1_write_data;
|
||||||
wire [31 : 0] tk1_read_data;
|
wire [31 : 0] tk1_read_data;
|
||||||
wire tk1_ready;
|
wire tk1_ready;
|
||||||
wire system_mode;
|
wire rw_locked;
|
||||||
wire force_trap;
|
wire force_trap;
|
||||||
wire [14 : 0] ram_addr_rand;
|
wire [14 : 0] ram_addr_rand;
|
||||||
wire [31 : 0] ram_data_rand;
|
wire [31 : 0] ram_data_rand;
|
||||||
@ -168,7 +177,12 @@ module application_fpga (
|
|||||||
.CATCH_MISALIGN (0),
|
.CATCH_MISALIGN (0),
|
||||||
.COMPRESSED_ISA (1),
|
.COMPRESSED_ISA (1),
|
||||||
.ENABLE_FAST_MUL (1),
|
.ENABLE_FAST_MUL (1),
|
||||||
.BARREL_SHIFTER (1)
|
.BARREL_SHIFTER (1),
|
||||||
|
.ENABLE_IRQ (1),
|
||||||
|
.ENABLE_IRQ_QREGS(0),
|
||||||
|
.ENABLE_IRQ_TIMER(0),
|
||||||
|
.MASKED_IRQ (~IRQ31_IRQ_MASK),
|
||||||
|
.LATCHED_IRQ (IRQ31_IRQ_MASK)
|
||||||
) cpu (
|
) cpu (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.resetn(reset_n),
|
.resetn(reset_n),
|
||||||
@ -182,11 +196,12 @@ module application_fpga (
|
|||||||
.mem_rdata(muxed_rdata_reg),
|
.mem_rdata(muxed_rdata_reg),
|
||||||
.mem_instr(cpu_instr),
|
.mem_instr(cpu_instr),
|
||||||
|
|
||||||
|
.irq(cpu_irq),
|
||||||
|
.eoi(cpu_eoi),
|
||||||
|
|
||||||
// Defined unused ports. Makes lint happy. But
|
// Defined unused ports. Makes lint happy. But
|
||||||
// we still needs to help lint with empty ports.
|
// we still needs to help lint with empty ports.
|
||||||
/* verilator lint_off PINCONNECTEMPTY */
|
/* verilator lint_off PINCONNECTEMPTY */
|
||||||
.irq(32'h0),
|
|
||||||
.eoi(),
|
|
||||||
.trace_valid(),
|
.trace_valid(),
|
||||||
.trace_data(),
|
.trace_data(),
|
||||||
.mem_la_read(),
|
.mem_la_read(),
|
||||||
@ -237,8 +252,7 @@ module application_fpga (
|
|||||||
.clk(clk),
|
.clk(clk),
|
||||||
.reset_n(reset_n),
|
.reset_n(reset_n),
|
||||||
|
|
||||||
.system_mode(system_mode),
|
.en(fw_ram_en),
|
||||||
|
|
||||||
.cs(fw_ram_cs),
|
.cs(fw_ram_cs),
|
||||||
.we(fw_ram_we),
|
.we(fw_ram_we),
|
||||||
.address(fw_ram_address),
|
.address(fw_ram_address),
|
||||||
@ -277,7 +291,7 @@ module application_fpga (
|
|||||||
.clk(clk),
|
.clk(clk),
|
||||||
.reset_n(reset_n),
|
.reset_n(reset_n),
|
||||||
|
|
||||||
.system_mode(system_mode),
|
.en(~rw_locked),
|
||||||
|
|
||||||
.cs(uds_cs),
|
.cs(uds_cs),
|
||||||
.address(uds_address),
|
.address(uds_address),
|
||||||
@ -320,7 +334,7 @@ module application_fpga (
|
|||||||
.clk(clk),
|
.clk(clk),
|
||||||
.reset_n(reset_n),
|
.reset_n(reset_n),
|
||||||
|
|
||||||
.system_mode(system_mode),
|
.rw_locked(rw_locked),
|
||||||
|
|
||||||
.cpu_addr (cpu_addr),
|
.cpu_addr (cpu_addr),
|
||||||
.cpu_instr (cpu_instr),
|
.cpu_instr (cpu_instr),
|
||||||
@ -347,6 +361,10 @@ module application_fpga (
|
|||||||
.gpio3(app_gpio3),
|
.gpio3(app_gpio3),
|
||||||
.gpio4(app_gpio4),
|
.gpio4(app_gpio4),
|
||||||
|
|
||||||
|
.access_level_hi(irq31_eoi),
|
||||||
|
|
||||||
|
.fw_ram_en(fw_ram_en),
|
||||||
|
|
||||||
.cs(tk1_cs),
|
.cs(tk1_cs),
|
||||||
.we(tk1_we),
|
.we(tk1_we),
|
||||||
.address(tk1_address),
|
.address(tk1_address),
|
||||||
@ -373,6 +391,20 @@ module application_fpga (
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// irq_ctrl
|
||||||
|
// Interrupt logic
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
always @* begin : irq_ctrl
|
||||||
|
reg irq31_set;
|
||||||
|
|
||||||
|
irq31_set = irq31_cs & irq31_we;
|
||||||
|
cpu_irq = {irq31_set, 31'h0};
|
||||||
|
|
||||||
|
irq31_eoi = cpu_eoi[31];
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// cpu_mem_ctrl
|
// cpu_mem_ctrl
|
||||||
// CPU memory decode and control logic.
|
// CPU memory decode and control logic.
|
||||||
@ -422,6 +454,9 @@ module application_fpga (
|
|||||||
touch_sense_we = |cpu_wstrb;
|
touch_sense_we = |cpu_wstrb;
|
||||||
touch_sense_address = cpu_addr[9 : 2];
|
touch_sense_address = cpu_addr[9 : 2];
|
||||||
|
|
||||||
|
irq31_cs = 1'h0;
|
||||||
|
irq31_we = |cpu_wstrb;
|
||||||
|
|
||||||
tk1_cs = 1'h0;
|
tk1_cs = 1'h0;
|
||||||
tk1_we = |cpu_wstrb;
|
tk1_we = |cpu_wstrb;
|
||||||
tk1_address = cpu_addr[9 : 2];
|
tk1_address = cpu_addr[9 : 2];
|
||||||
@ -494,6 +529,11 @@ module application_fpga (
|
|||||||
muxed_ready_new = fw_ram_ready;
|
muxed_ready_new = fw_ram_ready;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
IRQ31_PREFIX: begin
|
||||||
|
irq31_cs = 1'h1;
|
||||||
|
muxed_ready_new = 1'h1;
|
||||||
|
end
|
||||||
|
|
||||||
TK1_PREFIX: begin
|
TK1_PREFIX: begin
|
||||||
tk1_cs = 1'h1;
|
tk1_cs = 1'h1;
|
||||||
muxed_rdata_new = tk1_read_data;
|
muxed_rdata_new = tk1_read_data;
|
||||||
|
@ -67,11 +67,13 @@ module application_fpga_sim (
|
|||||||
localparam UART_PREFIX = 6'h03;
|
localparam UART_PREFIX = 6'h03;
|
||||||
localparam TOUCH_SENSE_PREFIX = 6'h04;
|
localparam TOUCH_SENSE_PREFIX = 6'h04;
|
||||||
localparam FW_RAM_PREFIX = 6'h10;
|
localparam FW_RAM_PREFIX = 6'h10;
|
||||||
|
localparam IRQ31_PREFIX = 6'h21;
|
||||||
localparam TK1_PREFIX = 6'h3f;
|
localparam TK1_PREFIX = 6'h3f;
|
||||||
|
|
||||||
// Instruction used to cause a trap.
|
// Instruction used to cause a trap.
|
||||||
localparam ILLEGAL_INSTRUCTION = 32'h0;
|
localparam ILLEGAL_INSTRUCTION = 32'h0;
|
||||||
|
|
||||||
|
localparam IRQ31_IRQ_MASK = 2 ** 31;
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Registers, memories with associated wires.
|
// Registers, memories with associated wires.
|
||||||
@ -89,11 +91,13 @@ module application_fpga_sim (
|
|||||||
wire reset_n;
|
wire reset_n;
|
||||||
|
|
||||||
/* verilator lint_off UNOPTFLAT */
|
/* verilator lint_off UNOPTFLAT */
|
||||||
|
reg [31 : 0] cpu_irq;
|
||||||
wire cpu_trap;
|
wire cpu_trap;
|
||||||
wire cpu_valid;
|
wire cpu_valid;
|
||||||
wire cpu_instr;
|
wire cpu_instr;
|
||||||
wire [ 3 : 0] cpu_wstrb;
|
wire [ 3 : 0] cpu_wstrb;
|
||||||
/* verilator lint_off UNUSED */
|
/* verilator lint_off UNUSED */
|
||||||
|
wire [31 : 0] cpu_eoi;
|
||||||
wire [31 : 0] cpu_addr;
|
wire [31 : 0] cpu_addr;
|
||||||
wire [31 : 0] cpu_wdata;
|
wire [31 : 0] cpu_wdata;
|
||||||
|
|
||||||
@ -141,6 +145,7 @@ module application_fpga_sim (
|
|||||||
reg [31 : 0] fw_ram_write_data;
|
reg [31 : 0] fw_ram_write_data;
|
||||||
wire [31 : 0] fw_ram_read_data;
|
wire [31 : 0] fw_ram_read_data;
|
||||||
wire fw_ram_ready;
|
wire fw_ram_ready;
|
||||||
|
wire fw_ram_en;
|
||||||
|
|
||||||
reg touch_sense_cs;
|
reg touch_sense_cs;
|
||||||
reg touch_sense_we;
|
reg touch_sense_we;
|
||||||
@ -148,13 +153,17 @@ module application_fpga_sim (
|
|||||||
wire [31 : 0] touch_sense_read_data;
|
wire [31 : 0] touch_sense_read_data;
|
||||||
wire touch_sense_ready;
|
wire touch_sense_ready;
|
||||||
|
|
||||||
|
reg irq31_cs;
|
||||||
|
reg irq31_we;
|
||||||
|
reg irq31_eoi;
|
||||||
|
|
||||||
reg tk1_cs;
|
reg tk1_cs;
|
||||||
reg tk1_we;
|
reg tk1_we;
|
||||||
reg [ 7 : 0] tk1_address;
|
reg [ 7 : 0] tk1_address;
|
||||||
reg [31 : 0] tk1_write_data;
|
reg [31 : 0] tk1_write_data;
|
||||||
wire [31 : 0] tk1_read_data;
|
wire [31 : 0] tk1_read_data;
|
||||||
wire tk1_ready;
|
wire tk1_ready;
|
||||||
wire system_mode;
|
wire rw_locked;
|
||||||
wire force_trap;
|
wire force_trap;
|
||||||
wire [14 : 0] ram_addr_rand;
|
wire [14 : 0] ram_addr_rand;
|
||||||
wire [31 : 0] ram_data_rand;
|
wire [31 : 0] ram_data_rand;
|
||||||
@ -179,7 +188,12 @@ module application_fpga_sim (
|
|||||||
.CATCH_MISALIGN (0),
|
.CATCH_MISALIGN (0),
|
||||||
.COMPRESSED_ISA (1),
|
.COMPRESSED_ISA (1),
|
||||||
.ENABLE_FAST_MUL (1),
|
.ENABLE_FAST_MUL (1),
|
||||||
.BARREL_SHIFTER (1)
|
.BARREL_SHIFTER (1),
|
||||||
|
.ENABLE_IRQ (1),
|
||||||
|
.ENABLE_IRQ_QREGS(0),
|
||||||
|
.ENABLE_IRQ_TIMER(0),
|
||||||
|
.MASKED_IRQ (~IRQ31_IRQ_MASK),
|
||||||
|
.LATCHED_IRQ (IRQ31_IRQ_MASK)
|
||||||
) cpu (
|
) cpu (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.resetn(reset_n),
|
.resetn(reset_n),
|
||||||
@ -193,11 +207,12 @@ module application_fpga_sim (
|
|||||||
.mem_rdata(muxed_rdata_reg),
|
.mem_rdata(muxed_rdata_reg),
|
||||||
.mem_instr(cpu_instr),
|
.mem_instr(cpu_instr),
|
||||||
|
|
||||||
|
.irq(cpu_irq),
|
||||||
|
.eoi(cpu_eoi),
|
||||||
|
|
||||||
// Defined unused ports. Makes lint happy. But
|
// Defined unused ports. Makes lint happy. But
|
||||||
// we still needs to help lint with empty ports.
|
// we still needs to help lint with empty ports.
|
||||||
/* verilator lint_off PINCONNECTEMPTY */
|
/* verilator lint_off PINCONNECTEMPTY */
|
||||||
.irq(32'h0),
|
|
||||||
.eoi(),
|
|
||||||
.trace_valid(),
|
.trace_valid(),
|
||||||
.trace_data(),
|
.trace_data(),
|
||||||
.mem_la_read(),
|
.mem_la_read(),
|
||||||
@ -248,8 +263,7 @@ module application_fpga_sim (
|
|||||||
.clk(clk),
|
.clk(clk),
|
||||||
.reset_n(reset_n),
|
.reset_n(reset_n),
|
||||||
|
|
||||||
.system_mode(system_mode),
|
.en(fw_ram_en),
|
||||||
|
|
||||||
.cs(fw_ram_cs),
|
.cs(fw_ram_cs),
|
||||||
.we(fw_ram_we),
|
.we(fw_ram_we),
|
||||||
.address(fw_ram_address),
|
.address(fw_ram_address),
|
||||||
@ -288,7 +302,7 @@ module application_fpga_sim (
|
|||||||
.clk(clk),
|
.clk(clk),
|
||||||
.reset_n(reset_n),
|
.reset_n(reset_n),
|
||||||
|
|
||||||
.system_mode(system_mode),
|
.en(~rw_locked),
|
||||||
|
|
||||||
.cs(uds_cs),
|
.cs(uds_cs),
|
||||||
.address(uds_address),
|
.address(uds_address),
|
||||||
@ -333,7 +347,7 @@ module application_fpga_sim (
|
|||||||
.clk(clk),
|
.clk(clk),
|
||||||
.reset_n(reset_n),
|
.reset_n(reset_n),
|
||||||
|
|
||||||
.system_mode(system_mode),
|
.rw_locked(rw_locked),
|
||||||
|
|
||||||
.cpu_addr (cpu_addr),
|
.cpu_addr (cpu_addr),
|
||||||
.cpu_instr (cpu_instr),
|
.cpu_instr (cpu_instr),
|
||||||
@ -360,6 +374,10 @@ module application_fpga_sim (
|
|||||||
.gpio3(app_gpio3),
|
.gpio3(app_gpio3),
|
||||||
.gpio4(app_gpio4),
|
.gpio4(app_gpio4),
|
||||||
|
|
||||||
|
.access_level_hi(irq31_eoi),
|
||||||
|
|
||||||
|
.fw_ram_en(fw_ram_en),
|
||||||
|
|
||||||
.cs(tk1_cs),
|
.cs(tk1_cs),
|
||||||
.we(tk1_we),
|
.we(tk1_we),
|
||||||
.address(tk1_address),
|
.address(tk1_address),
|
||||||
@ -385,6 +403,20 @@ module application_fpga_sim (
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// irq_ctrl
|
||||||
|
// Interrupt logic
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
always @* begin : irq_ctrl
|
||||||
|
reg irq31_set;
|
||||||
|
|
||||||
|
irq31_set = irq31_cs & irq31_we;
|
||||||
|
cpu_irq = {irq31_set, 31'h0};
|
||||||
|
|
||||||
|
irq31_eoi = cpu_eoi[31];
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// cpu_mem_ctrl
|
// cpu_mem_ctrl
|
||||||
// CPU memory decode and control logic.
|
// CPU memory decode and control logic.
|
||||||
@ -436,6 +468,9 @@ module application_fpga_sim (
|
|||||||
touch_sense_we = |cpu_wstrb;
|
touch_sense_we = |cpu_wstrb;
|
||||||
touch_sense_address = cpu_addr[9 : 2];
|
touch_sense_address = cpu_addr[9 : 2];
|
||||||
|
|
||||||
|
irq31_cs = 1'h0;
|
||||||
|
irq31_we = |cpu_wstrb;
|
||||||
|
|
||||||
tk1_cs = 1'h0;
|
tk1_cs = 1'h0;
|
||||||
tk1_we = |cpu_wstrb;
|
tk1_we = |cpu_wstrb;
|
||||||
tk1_address = cpu_addr[9 : 2];
|
tk1_address = cpu_addr[9 : 2];
|
||||||
@ -528,6 +563,13 @@ module application_fpga_sim (
|
|||||||
muxed_ready_new = fw_ram_ready;
|
muxed_ready_new = fw_ram_ready;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
IRQ31_PREFIX: begin
|
||||||
|
`verbose($display("Access to syscall interrupt trigger");)
|
||||||
|
ascii_state = "Syscall IRQ trigger";
|
||||||
|
irq31_cs = 1'h1;
|
||||||
|
muxed_ready_new = 1'h1;
|
||||||
|
end
|
||||||
|
|
||||||
TK1_PREFIX: begin
|
TK1_PREFIX: begin
|
||||||
`verbose($display("Access to TK1 core");)
|
`verbose($display("Access to TK1 core");)
|
||||||
ascii_state = "TK1 core";
|
ascii_state = "TK1 core";
|
||||||
|
@ -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)
|
||||||
#20000000;
|
#14000;
|
||||||
$display("TIMEOUT");
|
$display("TIMEOUT");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user