mirror of
https://github.com/tillitis/tillitis-key1.git
synced 2025-11-29 11:46:57 -05:00
PoC: PicoRV32 interrupts
A proof-of-concept of enabling PicoRV32 interrupts. Two interrupt
sources, which can be triggered by writes to memory addresses, are
added. The design has only been simulated, not run on hardware.
Synthesis:
Ice40 LC utilization is 93% (4934/5280) when built using tkey-builder:4
Simulation:
A `tb_application_fpga_irqpoc` target is added. Running `make
tb_application_fpga_irqpoc` creates `tb_application_fpga_sim.fst` which
can be inspected in GTKWave or Surfer.
Firmware:
A simple firmware is added in `fw/irqpoc`. It enables both interrupts
and triggers each interrupt once.
Custom PicoRV32 instructions are located in `custom_ops.S`. It is
imported from upstream PicoRV32 commit:
70f3c33ac8
This commit is contained in:
parent
d2c7fb0ba9
commit
5e15b40a86
10 changed files with 363 additions and 31 deletions
|
|
@ -145,6 +145,10 @@ TESTFW_OBJS = \
|
||||||
$(P)/fw/tk1/assert.o \
|
$(P)/fw/tk1/assert.o \
|
||||||
$(P)/fw/tk1/blake2s/blake2s.o
|
$(P)/fw/tk1/blake2s/blake2s.o
|
||||||
|
|
||||||
|
IRQPOC_OBJS = \
|
||||||
|
$(P)/fw/irqpoc/main.o \
|
||||||
|
$(P)/fw/irqpoc/start.o
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
# All: Complete build of HW and FW.
|
# All: Complete build of HW and FW.
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
|
|
@ -181,6 +185,7 @@ 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)
|
||||||
|
|
||||||
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 $@
|
||||||
|
|
@ -223,6 +228,9 @@ 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 $@
|
||||||
|
|
||||||
# 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) > $@
|
||||||
|
|
@ -233,6 +241,8 @@ 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) > $@
|
||||||
|
|
||||||
.PHONY: check-binary-hashes
|
.PHONY: check-binary-hashes
|
||||||
check-binary-hashes:
|
check-binary-hashes:
|
||||||
|
|
@ -406,11 +416,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 \
|
||||||
|
|
@ -434,7 +446,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, $^)
|
||||||
|
|
@ -442,6 +454,15 @@ 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
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
# FPGA device programming.
|
# FPGA device programming.
|
||||||
#-------------------------------------------------------------------
|
#-------------------------------------------------------------------
|
||||||
|
|
@ -488,6 +509,7 @@ 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 qemu_firmware.elf
|
rm -f qemu_firmware.elf
|
||||||
.PHONY: clean_fw
|
.PHONY: clean_fw
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,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 +34,8 @@ Rough memory map:
|
||||||
| UART | 0xc3 |
|
| UART | 0xc3 |
|
||||||
| Touch | 0xc4 |
|
| Touch | 0xc4 |
|
||||||
| FW\_RAM | 0xd0 |
|
| FW\_RAM | 0xd0 |
|
||||||
|
| IRQ30\_SET | 0xe0 |
|
||||||
|
| IRQ31\_SET | 0xe1 |
|
||||||
| TK1 | 0xff |
|
| TK1 | 0xff |
|
||||||
|
|
||||||
## `clk_reset_gen`
|
## `clk_reset_gen`
|
||||||
|
|
@ -96,6 +98,41 @@ 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.
|
||||||
|
|
||||||
|
## `irq30_set`
|
||||||
|
|
||||||
|
Interrupt 30 trigger area. A 32-bit write to the IRQ30\_SET memory
|
||||||
|
area will trigger interrupt 30.
|
||||||
|
|
||||||
|
## `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 IRQ30 and IRQ31. 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 source* | *x4 bit* |
|
||||||
|
|--------------------|----------|
|
||||||
|
| IRQ30\_SET | 30 |
|
||||||
|
| 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.
|
||||||
|
|
||||||
## `tk1`
|
## `tk1`
|
||||||
|
|
||||||
See [tk1 README](core/tk1/README.md) for details.
|
See [tk1 README](core/tk1/README.md) for details.
|
||||||
|
|
@ -107,7 +144,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.
|
||||||
|
|
|
||||||
|
|
@ -181,6 +181,7 @@ module tk1 #(
|
||||||
wire spi_ready;
|
wire spi_ready;
|
||||||
wire [ 7 : 0] spi_rx_data;
|
wire [ 7 : 0] spi_rx_data;
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Concurrent connectivity for ports etc.
|
// Concurrent connectivity for ports etc.
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
|
||||||
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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
42
hw/application_fpga/fw/irqpoc/start.S
Normal file
42
hw/application_fpga/fw/irqpoc/start.S
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2022, 2023 - Tillitis AB
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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.
|
||||||
|
// If bit 30 is 1: IRQ30 was triggered.
|
||||||
|
|
||||||
|
nop // NOPs are not necessary. Only added to make it easier to find
|
||||||
|
nop // when simulating.
|
||||||
|
nop
|
||||||
|
picorv32_retirq_insn() // Return from interrupt
|
||||||
|
|
||||||
|
.=0x20 // Setting location of init to 0x20. Makes it easier to find when
|
||||||
|
// simulating.
|
||||||
|
init:
|
||||||
|
li t0, 0x3fffffff // IRQ31 & IRQ30 mask
|
||||||
|
picorv32_maskirq_insn(zero, t0) // Enable IRQs
|
||||||
|
|
||||||
|
li t0, 0xe1000000 // IRQ31 trigger address
|
||||||
|
sw zero, 0(t0) // Raise IRQ by writing to interrupt trigger address.
|
||||||
|
// Writing any data triggers an interrupt.
|
||||||
|
|
||||||
|
li t0, 0xe0000000 // IRQ30 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.
|
||||||
|
|
||||||
|
|
@ -57,11 +57,15 @@ 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 IRQ30_PREFIX = 6'h20;
|
||||||
|
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 IRQ30_IRQ_MASK = 2 ** 30;
|
||||||
|
localparam IRQ31_IRQ_MASK = 2 ** 31;
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Registers, memories with associated wires.
|
// Registers, memories with associated wires.
|
||||||
|
|
@ -80,11 +84,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;
|
||||||
|
|
||||||
|
|
@ -139,6 +145,14 @@ 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 irq30_cs;
|
||||||
|
reg irq30_we;
|
||||||
|
(* keep *)reg irq30_eoi;
|
||||||
|
|
||||||
|
reg irq31_cs;
|
||||||
|
reg irq31_we;
|
||||||
|
(* keep *)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;
|
||||||
|
|
@ -171,7 +185,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 | IRQ30_IRQ_MASK)),
|
||||||
|
.LATCHED_IRQ (IRQ31_IRQ_MASK | IRQ30_IRQ_MASK)
|
||||||
) cpu (
|
) cpu (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.resetn(reset_n),
|
.resetn(reset_n),
|
||||||
|
|
@ -185,11 +204,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(),
|
||||||
|
|
@ -379,6 +399,23 @@ module application_fpga (
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// irq_ctrl
|
||||||
|
// Interrupt logic
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
always @* begin : irq_ctrl
|
||||||
|
reg irq31_set;
|
||||||
|
reg irq30_set;
|
||||||
|
|
||||||
|
irq31_set = irq31_cs & irq31_we;
|
||||||
|
irq30_set = irq30_cs & irq30_we;
|
||||||
|
cpu_irq = {irq31_set, irq30_set, 30'h0};
|
||||||
|
|
||||||
|
irq31_eoi = cpu_eoi[31];
|
||||||
|
irq30_eoi = cpu_eoi[30];
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// cpu_mem_ctrl
|
// cpu_mem_ctrl
|
||||||
// CPU memory decode and control logic.
|
// CPU memory decode and control logic.
|
||||||
|
|
@ -428,6 +465,12 @@ 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];
|
||||||
|
|
||||||
|
irq30_cs = 1'h0;
|
||||||
|
irq30_we = |cpu_wstrb;
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
@ -500,6 +543,16 @@ module application_fpga (
|
||||||
muxed_ready_new = fw_ram_ready;
|
muxed_ready_new = fw_ram_ready;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
IRQ30_PREFIX: begin
|
||||||
|
irq30_cs = 1'h1;
|
||||||
|
muxed_ready_new = 1'h1;
|
||||||
|
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;
|
||||||
|
|
|
||||||
|
|
@ -70,11 +70,15 @@ 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 IRQ30_PREFIX = 6'h20;
|
||||||
|
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 IRQ30_IRQ_MASK = 2 ** 30;
|
||||||
|
localparam IRQ31_IRQ_MASK = 2 ** 31;
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Registers, memories with associated wires.
|
// Registers, memories with associated wires.
|
||||||
|
|
@ -92,11 +96,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;
|
||||||
|
|
||||||
|
|
@ -151,6 +157,14 @@ 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 irq30_cs;
|
||||||
|
reg irq30_we;
|
||||||
|
(* keep *)reg irq30_eoi;
|
||||||
|
|
||||||
|
reg irq31_cs;
|
||||||
|
reg irq31_we;
|
||||||
|
(* keep *)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;
|
||||||
|
|
@ -182,7 +196,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 | IRQ30_IRQ_MASK)),
|
||||||
|
.LATCHED_IRQ (IRQ31_IRQ_MASK | IRQ30_IRQ_MASK)
|
||||||
) cpu (
|
) cpu (
|
||||||
.clk(clk),
|
.clk(clk),
|
||||||
.resetn(reset_n),
|
.resetn(reset_n),
|
||||||
|
|
@ -196,11 +215,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(),
|
||||||
|
|
@ -391,6 +411,23 @@ module application_fpga_sim (
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// irq_ctrl
|
||||||
|
// Interrupt logic
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
always @* begin : irq_ctrl
|
||||||
|
reg irq31_set;
|
||||||
|
reg irq30_set;
|
||||||
|
|
||||||
|
irq31_set = irq31_cs & irq31_we;
|
||||||
|
irq30_set = irq30_cs & irq30_we;
|
||||||
|
cpu_irq = {irq31_set, irq30_set, 30'h0};
|
||||||
|
|
||||||
|
irq31_eoi = cpu_eoi[31];
|
||||||
|
irq30_eoi = cpu_eoi[30];
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// cpu_mem_ctrl
|
// cpu_mem_ctrl
|
||||||
// CPU memory decode and control logic.
|
// CPU memory decode and control logic.
|
||||||
|
|
@ -442,6 +479,12 @@ 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];
|
||||||
|
|
||||||
|
irq30_cs = 1'h0;
|
||||||
|
irq30_we = |cpu_wstrb;
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
@ -534,6 +577,20 @@ module application_fpga_sim (
|
||||||
muxed_ready_new = fw_ram_ready;
|
muxed_ready_new = fw_ram_ready;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
IRQ30_PREFIX: begin
|
||||||
|
`verbose($display("Access to blake2s interrupt trigger");)
|
||||||
|
ascii_state = "Blake2s IRQ trigger";
|
||||||
|
irq30_cs = 1'h1;
|
||||||
|
muxed_ready_new = 1'h1;
|
||||||
|
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";
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,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;
|
#700;
|
||||||
$display("TIMEOUT");
|
$display("TIMEOUT");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue