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

[rtl] TRNG: add data-available interrupt #922

Merged
merged 6 commits into from
Jun 8, 2024
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 @@ -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