Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add programmable TRNG interrupt #615

Merged
merged 8 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ mimpid = 0x01080200 => Version 01.08.02.00 => v1.8.2

| Date (*dd.mm.yyyy*) | Version | Comment |
|:-------------------:|:-------:|:--------|
| 18.05.2023 | 1.8.4.9 | remove `is_simulation` flag from SYSINFO; add programmable interrupt to **TRNG** module; [#615](https://github.com/stnolting/neorv32/pull/615) |
| 12.05.2023 | 1.8.4.8 | `mtval` CSR now provides the address of `ebreak` exceptions (re-added temporarily to pass RISC-V ISA tests); [#611](https://github.com/stnolting/neorv32/pull/611) |
| 03.05.2023 | 1.8.4.7 | :bug: fix bug in FPU (terminate FPU sub-module operations if an exception has been raised); [#609](https://github.com/stnolting/neorv32/pull/609) |
| 02.05.2023 | 1.8.4.6 | make SDI FIFO access entirely synchronous; upgrade processor memory modules; update test setup wrappers; [#608]((https://github.com/stnolting/neorv32/pull/608) |
Expand Down
2 changes: 1 addition & 1 deletion docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ table (the channel number also corresponds to the according FIRQ priority: 0 = h
| 12 | <<_general_purpose_timer_gptmr,GPTMR>> | General purpose timer interrupt
| 13 | <<_one_wire_serial_interface_controller_onewire,ONEWIRE>> | 1-wire operation done interrupt
| 14 | - | _reserved_
| 15 | - | _reserved_
| 15 | <<_true_random_number_generator_trng,TRNG>> | TRNG FIFO level interrupt
|=======================

.Trigger Type
Expand Down
3 changes: 1 addition & 2 deletions docs/datasheet/soc_sysinfo.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ will signal a "DEVICE ERROR" in this case.
| `4` | `SYSINFO_SOC_MEM_EXT_ENDIAN` | set if external bus interface uses BIG-endian byte-order (via top's `MEM_EXT_BIG_ENDIAN` generic)
| `5` | `SYSINFO_SOC_ICACHE` | set if processor-internal instruction cache is implemented (via top's `ICACHE_EN` generic)
| `6` | `SYSINFO_SOC_DCACHE` | set if processor-internal data cache is implemented (via top's `DCACHE_EN` generic)
| `12:7` | - | _reserved_, read as zero
| `13` | `SYSINFO_SOC_IS_SIM` | set if processor is being **simulated** (⚠️ not guaranteed)
| `13:7` | - | _reserved_, read as zero
| `14` | `SYSINFO_SOC_OCD` | set if on-chip debugger is implemented (via top's `ON_CHIP_DEBUGGER_EN` generic)
| `15` | `SYSINFO_SOC_IO_DMA` | set if direct memory access controller is implemented (via top's `IO_DMA_EN` generic)
| `16` | `SYSINFO_SOC_IO_GPIO` | set if the GPIO is implemented (via top's `IO_GPIO_EN` generic)
Expand Down
33 changes: 22 additions & 11 deletions docs/datasheet/soc_trng.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
| Top entity port: | none |
| Configuration generics: | `IO_TRNG_EN` | implement TRNG when `true`
| | `IO_TRNG_FIFO` | data FIFO depth, min 1, has to be a power of two
| CPU interrupts: | none |
| CPU interrupts: | fast IRQ channel 15 | TRNG FIFO level interrupt (see <<_processor_interrupts>>)
|=======================


Expand Down Expand Up @@ -48,13 +48,20 @@ valid data available and the lowest 8 bit of the `CTRL` register are set to all-

An internal entropy FIFO can be configured using the `IO_TRNG_FIFO` generic. This FIFO automatically samples
new random data from the TRNG to provide some kind of _random data pool_ for applications, which require a large number
of RND data in a short time. The random data FIFO can be cleared at any time either by disabling the TRNG or by
of random data in a short time. The random data FIFO can be cleared at any time either by disabling the TRNG or by
setting the `TRNG_CTRL_FIFO_CLR` flag.

.Data Gating
[NOTE]
The TRNG data bits `TRNG_CTRL_DATA_MSB : TRNG_CTRL_DATA_MSB` are set to zero if `TRNG_CTRL_VALID` is low.
This prevents a random byte being read twice.

**TRNG Interrupt**

The TRNG provides a single interrupt channel that can be programmed to trigger on certain FIFO fill-level conditions.
This feature can be used to inform the CPU that a dertain amount of entropy is available for further processing. Using
the control register's `TRNG_CTRL_IRQ_*` bits the IRQ can be configured to trigger if the data FIFO is empty
(TRNG_CTRL_IRQ_FIFO_NEMPTY`), if the data FIFO is at least half full (`TRNG_CTRL_IRQ_FIFO_HALF`) or if the data FIFO is
entirely full (`TRNG_CTRL_IRQ_FIFO_NEMPTY`). Note that all enabled interrupt conditions are logically OR-ed.

Once the TRNG interrupt has fired it remains pending until the actual cause of the interrupt is resolved. Furthermore,
an active TRNG interrupt has to be explicitly cleared again by writing zero to the according <<_mip>> CSR bit.


**Register Map**
Expand All @@ -64,9 +71,13 @@ This prevents a random byte being read twice.
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.5+<| `0xffffffb8` .5+<| `CTRL` <|`7:0` `TRNG_CTRL_DATA_MSB : TRNG_CTRL_DATA_MSB` ^| r/- <| 8-bit random data
<|`28` `TRNG_CTRL_FIFO_CLR` ^| -/w <| flush random data FIFO when set (auto-clears)
<|`29` `TRNG_CTRL_SIM_MODE` ^| r/- <| simulation mode (PRNG!)
<|`30` `TRNG_CTRL_EN` ^| r/w <| TRNG enable
<|`31` `TRNG_CTRL_VALID` ^| r/- <| random data is valid when set
.9+<| `0xffffffb8` .9+<| `CTRL` <|`7:0` `TRNG_CTRL_DATA_MSB : TRNG_CTRL_DATA_MSB` ^| r/- <| 8-bit random data
<|`25:8` - ^| r/- <| reserved, read as zero
<|`26` `TRNG_CTRL_IRQ_FIFO_NEMPTY` ^| r/w <| IRQ if data FIFO is not empty
<|`26` `TRNG_CTRL_IRQ_FIFO_HALF` ^| r/w <| IRQ if data FIFO is at least half full
<|`27` `TRNG_CTRL_IRQ_FIFO_FULL` ^| r/w <| IRQ if data FIFO is full
<|`28` `TRNG_CTRL_FIFO_CLR` ^| -/w <| flush random data FIFO when set; auto-clears
<|`29` `TRNG_CTRL_SIM_MODE` ^| r/- <| simulation mode (PRNG!)
<|`30` `TRNG_CTRL_EN` ^| r/w <| TRNG enable
<|`31` `TRNG_CTRL_VALID` ^| r/- <| random data is valid when set
|=======================
Binary file modified docs/figures/neorv32_processor.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 6 additions & 5 deletions rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ package neorv32_package is

-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080408"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080409"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width, do not change!

Expand Down Expand Up @@ -1109,14 +1109,14 @@ package neorv32_package is
IO_UART1_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two, min 1
IO_UART1_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two, min 1
IO_SPI_EN : boolean := false; -- implement serial peripheral interface (SPI)?
IO_SPI_FIFO : natural := 1; -- SPI RTX fifo depth, has to be a power of two, min 1
IO_SPI_FIFO : natural := 1; -- RTX fifo depth, has to be a power of two, min 1
IO_SDI_EN : boolean := false; -- implement serial data interface (SDI)?
IO_SDI_FIFO : natural := 0; -- SDI RTX fifo depth, has to be zero or a power of two
IO_SDI_FIFO : natural := 0; -- RTX fifo depth, has to be zero or a power of two
IO_TWI_EN : boolean := false; -- implement two-wire interface (TWI)?
IO_PWM_NUM_CH : natural := 0; -- number of PWM channels to implement (0..12); 0 = disabled
IO_WDT_EN : boolean := false; -- implement watch dog timer (WDT)?
IO_TRNG_EN : boolean := false; -- implement true random number generator (TRNG)?
IO_TRNG_FIFO : natural := 1; -- TRNG fifo depth, has to be a power of two, min 1
IO_TRNG_FIFO : natural := 1; -- data fifo depth, has to be a power of two, min 1
IO_CFS_EN : boolean := false; -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG : std_ulogic_vector(31 downto 0) := x"00000000"; -- custom CFS configuration generic
IO_CFS_IN_SIZE : natural := 32; -- size of CFS input conduit in bits
Expand Down Expand Up @@ -1838,7 +1838,8 @@ package neorv32_package is
clk_i : in std_ulogic; -- global clock line
rstn_i : in std_ulogic; -- global reset line, low-active, async
bus_req_i : in bus_req_t; -- bus request
bus_rsp_o : out bus_rsp_t -- bus response
bus_rsp_o : out bus_rsp_t; -- bus response
irq_o : out std_ulogic -- CPU interrupt
);
end component;

Expand Down
6 changes: 2 additions & 4 deletions rtl/core/neorv32_sysinfo.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,9 @@ begin
sysinfo(2)(05) <= bool_to_ulogic_f(ICACHE_EN); -- processor-internal instruction cache implemented?
sysinfo(2)(06) <= bool_to_ulogic_f(DCACHE_EN); -- processor-internal data cache implemented?
--
sysinfo(2)(12 downto 07) <= (others => '0'); -- reserved
-- Misc --
sysinfo(2)(13) <= bool_to_ulogic_f(is_simulation_c); -- is this a simulation?
sysinfo(2)(13 downto 07) <= (others => '0'); -- reserved
-- Peripherals --
sysinfo(2)(14) <= bool_to_ulogic_f(ON_CHIP_DEBUGGER_EN); -- on-chip debugger implemented?
--
sysinfo(2)(15) <= bool_to_ulogic_f(IO_DMA_EN); -- direct memory access controller (DMA) implemented?
sysinfo(2)(16) <= bool_to_ulogic_f(IO_GPIO_NUM > 0); -- general purpose input/output port unit (GPIO) implemented?
sysinfo(2)(17) <= bool_to_ulogic_f(IO_MTIME_EN); -- machine system timer (MTIME) implemented?
Expand Down
13 changes: 8 additions & 5 deletions rtl/core/neorv32_top.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,14 @@ entity neorv32_top is
IO_UART1_RX_FIFO : natural := 1; -- RX fifo depth, has to be a power of two, min 1
IO_UART1_TX_FIFO : natural := 1; -- TX fifo depth, has to be a power of two, min 1
IO_SPI_EN : boolean := false; -- implement serial peripheral interface (SPI)?
IO_SPI_FIFO : natural := 1; -- SPI RTX fifo depth, has to be a power of two, min 1
IO_SPI_FIFO : natural := 1; -- RTX fifo depth, has to be a power of two, min 1
IO_SDI_EN : boolean := false; -- implement serial data interface (SDI)?
IO_SDI_FIFO : natural := 0; -- SDI RTX fifo depth, has to be zero or a power of two
IO_SDI_FIFO : natural := 0; -- RTX fifo depth, has to be zero or a power of two
IO_TWI_EN : boolean := false; -- implement two-wire interface (TWI)?
IO_PWM_NUM_CH : natural := 0; -- number of PWM channels to implement (0..12); 0 = disabled
IO_WDT_EN : boolean := false; -- implement watch dog timer (WDT)?
IO_TRNG_EN : boolean := false; -- implement true random number generator (TRNG)?
IO_TRNG_FIFO : natural := 1; -- TRNG fifo depth, has to be a power of two, min 1
IO_TRNG_FIFO : natural := 1; -- data fifo depth, has to be a power of two, min 1
IO_CFS_EN : boolean := false; -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG : std_ulogic_vector(31 downto 0) := x"00000000"; -- custom CFS configuration generic
IO_CFS_IN_SIZE : natural := 32; -- size of CFS input conduit in bits
Expand Down Expand Up @@ -330,6 +330,7 @@ architecture neorv32_top_rtl of neorv32_top is
signal gptmr_irq : std_ulogic;
signal onewire_irq : std_ulogic;
signal dma_irq : std_ulogic;
signal trng_irq : std_ulogic;

-- misc --
signal io_acc : std_ulogic;
Expand Down Expand Up @@ -550,7 +551,7 @@ begin
fast_irq(12) <= gptmr_irq;
fast_irq(13) <= onewire_irq;
fast_irq(14) <= '0';
fast_irq(15) <= '0'; -- lowest priority
fast_irq(15) <= trng_irq; -- lowest priority


-- CPU Instruction Cache ------------------------------------------------------------------
Expand Down Expand Up @@ -1215,13 +1216,15 @@ begin
clk_i => clk_i,
rstn_i => rstn_int,
bus_req_i => io_req,
bus_rsp_o => rsp_bus(DEV_TRNG)
bus_rsp_o => rsp_bus(DEV_TRNG),
irq_o => trng_irq
);
end generate;

neorv32_trng_inst_false:
if (IO_TRNG_EN = false) generate
rsp_bus(DEV_TRNG) <= rsp_terminate_c;
trng_irq <= '0';
end generate;


Expand Down
74 changes: 51 additions & 23 deletions rtl/core/neorv32_trng.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ entity neorv32_trng is
clk_i : in std_ulogic; -- global clock line
rstn_i : in std_ulogic; -- global reset line, low-active, async
bus_req_i : in bus_req_t; -- bus request
bus_rsp_o : out bus_rsp_t -- bus response
bus_rsp_o : out bus_rsp_t; -- bus response
irq_o : out std_ulogic -- CPU interrupt
);
end neorv32_trng;

Expand All @@ -68,13 +69,16 @@ architecture neorv32_trng_rtl of neorv32_trng is
constant sim_mode_c : boolean := is_simulation_c;

-- control register bits --
constant ctrl_data_lsb_c : natural := 0; -- r/-: Random data byte LSB
constant ctrl_data_msb_c : natural := 7; -- r/-: Random data byte MSB
constant ctrl_data_lsb_c : natural := 0; -- r/-: Random data byte LSB
constant ctrl_data_msb_c : natural := 7; -- r/-: Random data byte MSB
--
constant ctrl_fifo_clr_c : natural := 28; -- -/w: Clear data FIFO (auto clears)
constant ctrl_sim_mode_c : natural := 29; -- r/-: TRNG implemented in PRNG simulation mode
constant ctrl_en_c : natural := 30; -- r/w: TRNG enable
constant ctrl_valid_c : natural := 31; -- r/-: Output data valid
constant ctrl_irq_fifo_nempty : natural := 25; -- r/w: IRQ if fifo is not empty
constant ctrl_irq_fifo_half : natural := 26; -- r/w: IRQ if fifo is at least half-full
constant ctrl_irq_fifo_full : natural := 27; -- r/w: IRQ if fifo is full
constant ctrl_fifo_clr_c : natural := 28; -- -/w: Clear data FIFO (auto clears)
constant ctrl_sim_mode_c : natural := 29; -- r/-: TRNG implemented in PRNG simulation mode
constant ctrl_en_c : natural := 30; -- r/w: TRNG enable
constant ctrl_valid_c : natural := 31; -- r/-: Output data valid

-- IO space: module base address --
constant hi_abb_c : natural := index_size_f(io_size_c)-1; -- high address boundary bit
Expand Down Expand Up @@ -104,9 +108,12 @@ architecture neorv32_trng_rtl of neorv32_trng is
);
end component;

-- arbiter --
signal enable : std_ulogic;
signal fifo_clr : std_ulogic;
-- control --
signal enable : std_ulogic;
signal fifo_clr : std_ulogic;
signal irq_fifo_nempty : std_ulogic;
signal irq_fifo_half : std_ulogic;
signal irq_fifo_full : std_ulogic;

-- data FIFO --
type fifo_t is record
Expand All @@ -116,6 +123,8 @@ architecture neorv32_trng_rtl of neorv32_trng is
wdata : std_ulogic_vector(7 downto 0); -- write data
rdata : std_ulogic_vector(7 downto 0); -- read data
avail : std_ulogic; -- data available?
half : std_ulogic; -- at least half full?
free : std_ulogic; -- space left?
end record;
signal fifo : fifo_t;

Expand All @@ -140,13 +149,19 @@ begin
write_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
enable <= '0';
fifo_clr <= '0';
enable <= '0';
fifo_clr <= '0';
irq_fifo_nempty <= '0';
irq_fifo_half <= '0';
irq_fifo_full <= '0';
elsif rising_edge(clk_i) then
fifo_clr <= '0'; -- default
fifo_clr <= '0'; -- auto-clear
if (wren = '1') then
enable <= bus_req_i.data(ctrl_en_c);
fifo_clr <= bus_req_i.data(ctrl_fifo_clr_c);
enable <= bus_req_i.data(ctrl_en_c);
fifo_clr <= bus_req_i.data(ctrl_fifo_clr_c);
irq_fifo_nempty <= bus_req_i.data(ctrl_irq_fifo_nempty);
irq_fifo_half <= bus_req_i.data(ctrl_irq_fifo_half);
irq_fifo_full <= bus_req_i.data(ctrl_irq_fifo_full);
end if;
end if;
end process write_access;
Expand All @@ -158,12 +173,14 @@ begin
bus_rsp_o.ack <= wren or rden; -- host bus acknowledge
bus_rsp_o.data <= (others => '0');
if (rden = '1') then
if (fifo.avail = '1') then -- make sure data byte is zero if no valid data available to prevent it is read twice
bus_rsp_o.data(ctrl_data_msb_c downto ctrl_data_lsb_c) <= fifo.rdata;
end if;
bus_rsp_o.data(ctrl_sim_mode_c) <= bool_to_ulogic_f(sim_mode_c);
bus_rsp_o.data(ctrl_en_c) <= enable;
bus_rsp_o.data(ctrl_valid_c) <= fifo.avail;
bus_rsp_o.data(ctrl_data_msb_c downto ctrl_data_lsb_c) <= fifo.rdata;
--
bus_rsp_o.data(ctrl_irq_fifo_nempty) <= irq_fifo_nempty;
bus_rsp_o.data(ctrl_irq_fifo_half) <= irq_fifo_half;
bus_rsp_o.data(ctrl_irq_fifo_full) <= irq_fifo_full;
bus_rsp_o.data(ctrl_sim_mode_c) <= bool_to_ulogic_f(sim_mode_c);
bus_rsp_o.data(ctrl_en_c) <= enable;
bus_rsp_o.data(ctrl_valid_c) <= fifo.avail;
end if;
end if;
end process read_access;
Expand Down Expand Up @@ -206,11 +223,11 @@ begin
clk_i => clk_i, -- clock, rising edge
rstn_i => rstn_i, -- async reset, low-active
clear_i => fifo.clear, -- sync reset, high-active
half_o => open,
half_o => fifo.half, -- at least half full
-- write port --
wdata_i => fifo.wdata, -- write data
we_i => fifo.we, -- write enable
free_o => open, -- at least one entry is free when set
free_o => fifo.free, -- at least one entry is free when set
-- read port --
re_i => fifo.re, -- read enable
rdata_o => fifo.rdata, -- read data
Expand All @@ -220,6 +237,17 @@ begin
fifo.clear <= '1' when (enable = '0') or (fifo_clr = '1') else '0';
fifo.re <= '1' when (rden = '1') else '0';

-- FIFO-level interrupt generator --
irq_generator: process(clk_i)
begin
if rising_edge(clk_i) then
irq_o <= enable and (
(irq_fifo_nempty and fifo.avail) or -- IRQ if FIFO not empty
(irq_fifo_half and fifo.half) or -- IRQ if FIFO at least half full
(irq_fifo_full and (not fifo.free))); -- IRQ if FIFO full
end if;
end process irq_generator;


end neorv32_trng_rtl;

Expand Down
2 changes: 1 addition & 1 deletion sim/neorv32_tb.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ begin
if ci_mode then
-- No need to send the full expectation in one big chunk
check_uart(net, uart1_rx_handle, nul & nul);
check_uart(net, uart1_rx_handle, "0/50" & cr & lf);
check_uart(net, uart1_rx_handle, "0/51" & cr & lf);
end if;

-- Wait until all expected data has been received
Expand Down
2 changes: 1 addition & 1 deletion sw/example/demo_newlib/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ int main() {
char_buffer = (char *) malloc(4 * sizeof(char)); // 4 bytes

// do not test read & write in simulation as there would be no UART RX input
if (NEORV32_SYSINFO->SOC & (1<<SYSINFO_SOC_IS_SIM)) {
if (neorv32_cpu_csr_read(CSR_MXISA) & (1 << CSR_MXISA_IS_SIM)) {
neorv32_uart0_printf("Skipping <read> & <write> tests as this seems to be a simulation.\n");
}
else {
Expand Down
2 changes: 1 addition & 1 deletion sw/example/demo_trng/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ int main(void) {
}

// enable TRNG
neorv32_trng_enable();
neorv32_trng_enable(0); // no interrupts
neorv32_cpu_delay_ms(100); // TRNG "warm up"

while(1) {
Expand Down
4 changes: 2 additions & 2 deletions sw/example/game_of_life/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ int main(void) {
// check if TRNG was synthesized
if (neorv32_trng_available()) {
neorv32_uart0_printf("\nTRNG detected. Using TRNG for universe initialization.\n");
neorv32_trng_enable();
neorv32_trng_enable(0);
trng_available = 1;
}

Expand Down Expand Up @@ -226,7 +226,7 @@ void print_universe(int u){

for (y=0; y<NUM_CELLS_Y; y++) {
neorv32_uart0_putc('|');

for (x=0; x<NUM_CELLS_X; x++) {
if (get_cell(u, x, y))
neorv32_uart0_putc((char)CELL_ALIVE);
Expand Down
Loading