Skip to content

Commit

Permalink
[rtl] TRNG: add data-available interrupt (#922)
Browse files Browse the repository at this point in the history
  • Loading branch information
stnolting committed Jun 8, 2024
2 parents d6d31fc + e211d5b commit 1da82dc
Show file tree
Hide file tree
Showing 15 changed files with 110 additions and 39 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12

| Date | Version | Comment | Ticket |
|:----:|:-------:|:--------|:------:|
| 07.06.2024 | 1.9.9.7 | :sparkles: re-add TRNG "data available" interrupt | [#922](https://github.com/stnolting/neorv32/pull/922) |
| 31.05.2024 | 1.9.9.6 | add "tag" signal to XBUS to provide additional access information (compatible to the AXI4 _ARPROT_ and _AWPROT_ signals) | [#917](https://github.com/stnolting/neorv32/pull/917) |
| 30.05.2024 | 1.9.9.5 | :bug: fix uncached-vs-cached memory accesses (do not interrupt cache bursts by direct/uncached memory accesses) | [#915](https://github.com/stnolting/neorv32/pull/915) |
| 29.05.2024 | 1.9.9.4 | Vivado IP block: add resizing ports for GPIOs, XIRQs and PWM; split size configuration for GPIO inputs and outputs | [#913](https://github.com/stnolting/neorv32/pull/913) |
Expand Down
4 changes: 2 additions & 2 deletions docs/datasheet/soc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,8 @@ table (the channel number also corresponds to the according FIRQ priority: 0 = h
[options="header",grid="rows"]
|=======================
| Channel | Source | Description
| 0 | - | _reserved_
| 1 | <<_custom_functions_subsystem_cfs,CFS>> | custom functions subsystem (CFS) interrupt (user-defined)
| 0 | <<_true_random_number_generator_trng,TRNG>> | TRNG data available interrupt
| 1 | <<_custom_functions_subsystem_cfs,CFS>> | Custom functions subsystem (CFS) interrupt (user-defined)
| 2 | <<_primary_universal_asynchronous_receiver_and_transmitter_uart0,UART0>> | UART0 RX FIFO level interrupt
| 3 | <<_primary_universal_asynchronous_receiver_and_transmitter_uart0,UART0>> | UART0 TX FIFO level interrupt
| 4 | <<_secondary_universal_asynchronous_receiver_and_transmitter_uart1,UART1>> | UART1 RX FIFO level interrupt
Expand Down
16 changes: 13 additions & 3 deletions docs/datasheet/soc_trng.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
| Top entity ports: | 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 0 | TRNG data available interrupt (see <<_processor_interrupts>>)
|=======================


Expand Down Expand Up @@ -53,18 +53,28 @@ of random data in a short time. The random data FIFO can be cleared at any time
setting the `TRNG_CTRL_FIFO_CLR` flag. The FIFO depth can be retrieved by software via the `TRNG_CTRL_FIFO_*` bits.


**TRNG Interrupt**

As the neoTRNG is a rather slow entropy source, a "data available" interrupt is provided to inform the application
software that new random data is available. This interrupt can be trigger by either of two conditions: trigger the
interrupt if _any_ random data is available (i.e. the data FIFO is not empty; `TRNG_CTRL_IRQ_SEL = 0`) or trigger
the interrupt if the random pool is full (i.e. the data FIFO is full; `TRNG_CTRL_IRQ_SEL = 1`).
Once the TRNG interrupt has fired it remains pending until the actual cause of the interrupt is resolved.


**Register Map**

.TRNG register map (`struct NEORV32_TRNG`)
[cols="<2,<1,<4,^1,<7"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.8+<| `0xfffffa00` .8+<| `CTRL` <|`7:0` `TRNG_CTRL_DATA_MSB : TRNG_CTRL_DATA_MSB` ^| r/- <| 8-bit random data
.9+<| `0xfffffa00` .9+<| `CTRL` <|`7:0` `TRNG_CTRL_DATA_MSB : TRNG_CTRL_DATA_MSB` ^| r/- <| 8-bit random data
<|`15:8` - ^| r/- <| reserved, read as zero
<|`19:16` `TRNG_CTRL_FIFO_MSB : TRNG_CTRL_FIFO_MSB` ^| r/- <| FIFO depth, log2(`IO_TRNG_FIFO`)
<|`27:20` - ^| r/- <| reserved, read as zero
<|`28` `TRNG_CTRL_FIFO_CLR` ^| -/w <| flush random data FIFO when set; auto-clears
<|`27` `TRNG_CTRL_IRQ_SEL` ^| r/w <| interrupt trigger select (0 = data available, 1 = FIFO full)
<|`28` `TRNG_CTRL_FIFO_CLR` ^| -/w <| flush random data FIFO when set; flag 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
Expand Down
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.
2 changes: 1 addition & 1 deletion rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ package neorv32_package is

-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090906"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090907"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width

Expand Down
7 changes: 4 additions & 3 deletions rtl/core/neorv32_top.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ architecture neorv32_top_rtl of neorv32_top is

-- IRQs --
type firq_enum_t is (
FIRQ_UART0_RX, FIRQ_UART0_TX, FIRQ_UART1_RX, FIRQ_UART1_TX, FIRQ_SPI, FIRQ_SDI, FIRQ_TWI,
FIRQ_TRNG, FIRQ_UART0_RX, FIRQ_UART0_TX, FIRQ_UART1_RX, FIRQ_UART1_TX, FIRQ_SPI, FIRQ_SDI, FIRQ_TWI,
FIRQ_CFS, FIRQ_NEOLED, FIRQ_XIRQ, FIRQ_GPTMR, FIRQ_ONEWIRE, FIRQ_DMA, FIRQ_SLINK_RX, FIRQ_SLINK_TX
);
type firq_t is array (firq_enum_t) of std_ulogic;
Expand Down Expand Up @@ -558,7 +558,7 @@ begin
);

-- fast interrupt requests (FIRQs) --
cpu_firq(0) <= '0'; -- reserved
cpu_firq(0) <= firq(FIRQ_TRNG);
cpu_firq(1) <= firq(FIRQ_CFS);
cpu_firq(2) <= firq(FIRQ_UART0_RX);
cpu_firq(3) <= firq(FIRQ_UART0_TX);
Expand Down Expand Up @@ -1391,7 +1391,8 @@ begin
clk_i => clk_i,
rstn_i => rstn_sys,
bus_req_i => iodev_req(IODEV_TRNG),
bus_rsp_o => iodev_rsp(IODEV_TRNG)
bus_rsp_o => iodev_rsp(IODEV_TRNG),
irq_o => firq(FIRQ_TRNG)
);
end generate;

Expand Down
31 changes: 27 additions & 4 deletions rtl/core/neorv32_trng.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,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 -- data-available interrupt
);
end neorv32_trng;

Expand All @@ -46,6 +47,7 @@ architecture neorv32_trng_rtl of neorv32_trng is
constant ctrl_fifo_size2_c : natural := 18; -- r/-: log2(FIFO size) bit 2
constant ctrl_fifo_size3_c : natural := 19; -- r/-: log2(FIFO size) bit 3
--
constant ctrl_irq_sel_c : natural := 27; -- r/w: interrupt select (0 = data available, 1 = FIFO 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 pseudo-RNG simulation mode
constant ctrl_en_c : natural := 30; -- r/w: TRNG enable
Expand All @@ -68,7 +70,7 @@ architecture neorv32_trng_rtl of neorv32_trng is
end component;

-- control --
signal enable, fifo_clr : std_ulogic;
signal enable, irq_sel, fifo_clr : std_ulogic;

-- data FIFO --
type fifo_t is record
Expand All @@ -93,8 +95,9 @@ begin
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
enable <= '0';
fifo_clr <= '0';
irq_sel <= '0';
enable <= '0';
elsif rising_edge(clk_i) then
-- defaults --
bus_rsp_o.ack <= bus_req_i.stb;
Expand All @@ -104,13 +107,15 @@ begin
-- host access --
if (bus_req_i.stb = '1') then
if (bus_req_i.rw = '1') then -- write access
enable <= bus_req_i.data(ctrl_en_c);
irq_sel <= bus_req_i.data(ctrl_irq_sel_c);
fifo_clr <= bus_req_i.data(ctrl_fifo_clr_c);
enable <= bus_req_i.data(ctrl_en_c);
else -- read access
bus_rsp_o.data(ctrl_data_msb_c downto ctrl_data_lsb_c) <= fifo.rdata;
--
bus_rsp_o.data(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(IO_TRNG_FIFO), 4));
--
bus_rsp_o.data(ctrl_irq_sel_c) <= irq_sel;
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;
Expand Down Expand Up @@ -166,6 +171,24 @@ begin
fifo.clear <= '1' when (enable = '0') or (fifo_clr = '1') else '0';
fifo.re <= '1' when (bus_req_i.stb = '1') and (bus_req_i.rw = '0') else '0';

-- IRQ generator --
irq_generator: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
irq_o <= '0';
elsif rising_edge(clk_i) then
if (enable = '1') then
if (irq_sel = '0') then -- fire IRQ if any data is available
irq_o <= fifo.avail;
else -- fire IRQ if data FIFO is full
irq_o <= not fifo.free;
end if;
else
irq_o <= '0';
end if;
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 @@ -157,7 +157,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/55" & cr & lf);
check_uart(net, uart1_rx_handle, "0/56" & cr & lf);
end if;

-- Wait until all expected data has been received
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_uart0_printf("\nTRNG FIFO depth: %i\n", neorv32_trng_get_fifo_depth());
neorv32_uart0_printf("Starting TRNG...\n");
neorv32_trng_enable();
neorv32_trng_enable(0);
neorv32_cpu_delay_ms(100); // TRNG "warm up"

while(1) {
Expand Down
2 changes: 1 addition & 1 deletion sw/example/game_of_life/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,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
44 changes: 35 additions & 9 deletions sw/example/processor_check/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1041,8 +1041,34 @@ int main() {
// ----------------------------------------------------------
// Fast interrupt channel 0
// ----------------------------------------------------------
PRINT_STANDARD("[%i] FIRQ0 ", cnt_test);
PRINT_STANDARD("[n.a.]\n");
neorv32_cpu_csr_write(CSR_MCAUSE, mcause_never_c);
PRINT_STANDARD("[%i] FIRQ (TRNG) ", cnt_test);

if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_IO_TRNG)) {
cnt_test++;

// enable TRNG, trigger IRQ when FIFO is full
neorv32_trng_enable(1);

// enable fast interrupt
neorv32_cpu_csr_write(CSR_MIE, 1 << TRNG_FIRQ_ENABLE);

// sleep until interrupt
neorv32_cpu_sleep();

// no more interrupts
neorv32_cpu_csr_write(CSR_MIE, 0);

if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRNG_TRAP_CODE) {
test_ok();
}
else {
test_fail();
}
}
else {
PRINT_STANDARD("[n.a.]\n");
}


// ----------------------------------------------------------
Expand Down Expand Up @@ -1249,8 +1275,8 @@ int main() {
// enable fast interrupt
neorv32_cpu_csr_write(CSR_MIE, 1 << SPI_FIRQ_ENABLE);

// wait for interrupt
asm volatile ("wfi");
// sleep until interrupt
neorv32_cpu_sleep();

neorv32_cpu_csr_write(CSR_MIE, 0);

Expand Down Expand Up @@ -1287,8 +1313,8 @@ int main() {
// enable TWI FIRQ
neorv32_cpu_csr_write(CSR_MIE, 1 << TWI_FIRQ_ENABLE);

// wait for interrupt
asm volatile ("wfi");
// sleep until interrupt
neorv32_cpu_sleep();

neorv32_cpu_csr_write(CSR_MIE, 0);

Expand Down Expand Up @@ -1419,7 +1445,7 @@ int main() {
neorv32_dma_transfer((uint32_t)(&dma_src), (uint32_t)(&NEORV32_CRC->DATA), 4, tmp_a);

// sleep until interrupt
asm volatile ("wfi");
neorv32_cpu_sleep();

neorv32_cpu_csr_write(CSR_MIE, 0);

Expand Down Expand Up @@ -1756,9 +1782,9 @@ int main() {
// enable mtime interrupt
neorv32_cpu_csr_write(CSR_MIE, 1 << CSR_MIE_MTIE);

// put CPU into sleep mode -the CPU has to wakeup again if any enabled interrupt source
// put CPU into sleep mode - the CPU has to wakeup again if any enabled interrupt source
// becomes pending - even if we are in m-mode and mstatus.mie is cleared
asm volatile ("wfi");
neorv32_cpu_sleep();

neorv32_cpu_csr_write(CSR_MIE, 0);
neorv32_cpu_csr_set(CSR_MSTATUS, 1 << CSR_MSTATUS_MIE);
Expand Down
7 changes: 7 additions & 0 deletions sw/lib/include/neorv32.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ enum NEORV32_CLOCK_PRSC_enum {
* @name Fast Interrupt Requests (FIRQ) device aliases
**************************************************************************/
/**@{*/
/** @name True-Random Number Generator (TRNG) */
/**@{*/
#define TRNG_FIRQ_ENABLE CSR_MIE_FIRQ0E /**< MIE CSR bit (#NEORV32_CSR_MIE_enum) */
#define TRNG_FIRQ_PENDING CSR_MIP_FIRQ0P /**< MIP CSR bit (#NEORV32_CSR_MIP_enum) */
#define TRNG_RTE_ID RTE_TRAP_FIRQ_0 /**< RTE entry code (#NEORV32_RTE_TRAP_enum) */
#define TRNG_TRAP_CODE TRAP_CODE_FIRQ_0 /**< MCAUSE CSR trap code (#NEORV32_EXCEPTION_CODES_enum) */
/**@}*/
/** @name Custom Functions Subsystem (CFS) */
/**@{*/
#define CFS_FIRQ_ENABLE CSR_MIE_FIRQ1E /**< MIE CSR bit (#NEORV32_CSR_MIE_enum) */
Expand Down
3 changes: 2 additions & 1 deletion sw/lib/include/neorv32_trng.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ enum NEORV32_TRNG_CTRL_enum {
TRNG_CTRL_FIFO_LSB = 16, /**< TRNG data/control register(16) (r/-): log2(FIFO size), LSB */
TRNG_CTRL_FIFO_MSB = 19, /**< TRNG data/control register(19) (r/-): log2(FIFO size), MSB */

TRNG_CTRL_IRQ_SEL = 27, /**< TRNG data/control register(27) (r/w): Interrupt trigger select (0 = data available, 1 = FIFO full) */
TRNG_CTRL_FIFO_CLR = 28, /**< TRNG data/control register(28) (-/w): Clear data FIFO (auto clears) */
TRNG_CTRL_SIM_MODE = 29, /**< TRNG data/control register(29) (r/-): PRNG mode (simulation mode) */
TRNG_CTRL_EN = 30, /**< TRNG data/control register(30) (r/w): TRNG enable */
Expand All @@ -51,7 +52,7 @@ enum NEORV32_TRNG_CTRL_enum {
**************************************************************************/
/**@{*/
int neorv32_trng_available(void);
void neorv32_trng_enable(void);
void neorv32_trng_enable(int irq_sel);
void neorv32_trng_disable(void);
void neorv32_trng_fifo_clear(void);
int neorv32_trng_get_fifo_depth(void);
Expand Down
23 changes: 10 additions & 13 deletions sw/lib/source/neorv32_trng.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,24 @@ int neorv32_trng_available(void) {

/**********************************************************************//**
* Reset, configure and enable TRNG.
*
* @param[in] irq_sel Interrupt trigger select (0 = data available, 1 = FIFO full).
**************************************************************************/
void neorv32_trng_enable(void) {

int i;
void neorv32_trng_enable(int irq_sel) {

NEORV32_TRNG->CTRL = 0; // reset
NEORV32_TRNG->CTRL = 0; // disable and reset

// wait for all internal components to reset
int i;
for (i=0; i<256; i++) {
asm volatile ("nop");
}

NEORV32_TRNG->CTRL = 1 << TRNG_CTRL_EN; // activate

// "warm-up"
for (i=0; i<256; i++) {
asm volatile ("nop");
}

// flush random data "pool"
neorv32_trng_fifo_clear();
uint32_t tmp = 0;
tmp |= (1 << TRNG_CTRL_EN); // enable
tmp |= (((uint32_t)(irq_sel & 1)) << TRNG_CTRL_IRQ_SEL); // interrupt trigger select
tmp |= (1 << TRNG_CTRL_FIFO_CLR); // clear data FIFO
NEORV32_TRNG->CTRL = tmp;
}


Expand Down
5 changes: 5 additions & 0 deletions sw/svd/neorv32.svd
Original file line number Diff line number Diff line change
Expand Up @@ -1341,6 +1341,11 @@
<access>read-only</access>
<description>Log2(FIFO size)</description>
</field>
<field>
<name>TRNG_CTRL_IRQ_SEL</name>
<bitRange>[27:27]</bitRange>
<description>Interrupt trigger select (0 = data available, 1 = FIFO full)</description>
</field>
<field>
<name>TRNG_CTRL_FIFO_CLR</name>
<bitRange>[28:28]</bitRange>
Expand Down

0 comments on commit 1da82dc

Please sign in to comment.