From aea1865b7b55ae58c371188eba867f7f93a51476 Mon Sep 17 00:00:00 2001 From: Romain Dolbeau Date: Tue, 20 Jul 2021 07:45:51 -0400 Subject: [PATCH] commit the neorv32trgn-based trng --- .../9.0/usr/src/sys/dev/sbus/sbusfpga_sdram.c | 39 ++ .../9.0/usr/src/sys/dev/sbus/sbusfpga_trng.c | 207 ++++++++++ .../9.0/usr/src/sys/dev/sbus/sbusfpga_trng.h | 43 ++ .../neorv32_trng_patched.vhd | 382 ++++++++++++++++++ sbus-to-ztex-gateware-migen/netbsd_csr.h | 104 +++-- sbus-to-ztex-gateware-migen/prom_csr.fth | 1 + sbus-to-ztex-gateware-migen/prom_migen.fth | 41 ++ .../sbus_to_fpga_export.py | 12 +- .../sbus_to_fpga_soc.py | 3 + .../sbus_to_fpga_trng.py | 94 +++++ 10 files changed, 877 insertions(+), 49 deletions(-) create mode 100644 NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.c create mode 100644 NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.h create mode 100644 sbus-to-ztex-gateware-migen/neorv32_trng_patched.vhd create mode 100644 sbus-to-ztex-gateware-migen/sbus_to_fpga_trng.py diff --git a/NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_sdram.c b/NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_sdram.c index 92b351f..d91d394 100644 --- a/NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_sdram.c +++ b/NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_sdram.c @@ -55,6 +55,8 @@ __KERNEL_RCSID(0, "$NetBSD$"); #include + #include + int sbusfpga_sdram_match(device_t, cfdata_t, void *); void sbusfpga_sdram_attach(device_t, device_t, void *); @@ -446,6 +448,30 @@ sbusfpga_sdram_diskstart(device_t self, struct buf *bp) goto done; } + /* + { + paddr_t pap; + pmap_t pk = pmap_kernel(); + if (pmap_extract(pk, (vaddr_t)bp->b_data, &pap)) { + aprint_normal_dev(sc->dk.sc_dev, "KVA %p mapped to PA 0x%08lx\n", bp->b_data, pap); + if (bp->b_bcount > 4096) { + u_int32_t np = (bp->b_bcount + 4095) / 4096; + u_int32_t pn; + for (pn = 1 ; pn < np ; pn ++) { + paddr_t papn; + if (pmap_extract(pk, (vaddr_t)bp->b_data + pn * 4096, &papn)) { + if (papn != (pap + pn * 4096)) + break; + } else break; + } + aprint_normal_dev(sc->dk.sc_dev, "And we have %u out %u consecutive PA pages\n", pn, np); + } + } else { + aprint_normal_dev(sc->dk.sc_dev, "KVA %p not mapped\n", bp->b_data); + } + } + */ + if (bp->b_flags & B_READ) { unsigned char* data = bp->b_data; daddr_t blk = bp->b_rawblkno; @@ -527,18 +553,31 @@ sbusfpga_sdram_diskstart(device_t self, struct buf *bp) #define CONFIG_CSR_DATA_WIDTH 32 // define CSR_LEDS_BASE & others to avoid defining the CSRs of HW we don't handle #define CSR_LEDS_BASE +//#define CSR_DDRPHY_BASE +//#define CSR_SDRAM_BASE +//#define CSR_EXCHANGE_WITH_MEM_BASE #define CSR_SDBLOCK2MEM_BASE #define CSR_SDCORE_BASE #define CSR_SDIRQ_BASE #define CSR_SDMEM2BLOCK_BASE #define CSR_SDPHY_BASE +#define CSR_TRNG_BASE + +/* grrr */ +#define sbusfpga_exchange_with_mem_softc sbusfpga_sdram_softc +#define sbusfpga_ddrphy_softc sbusfpga_sdram_softc + #include "dev/sbus/litex_csr.h" #undef CSR_LEDS_BASE +//#undef CSR_DDRPHY_BASE +//#undef CSR_SDRAM_BASE +//#undef CSR_EXCHANGE_WITH_MEM_BASE #undef CSR_SDBLOCK2MEM_BASE #undef CSR_SDCORE_BASE #undef CSR_SDIRQ_BASE #undef CSR_SDMEM2BLOCK_BASE #undef CSR_SDPHY_BASE +#undef CSR_TRNG_BASE int dma_init(struct sbusfpga_sdram_softc *sc) { diff --git a/NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.c b/NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.c new file mode 100644 index 0000000..d67fde8 --- /dev/null +++ b/NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.c @@ -0,0 +1,207 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2020 Romain Dolbeau + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include + +#include + +int sbusfpga_trng_print(void *, const char *); +int sbusfpga_trng_match(device_t, cfdata_t, void *); +void sbusfpga_trng_attach(device_t, device_t, void *); + +CFATTACH_DECL_NEW(sbusfpga_trng, sizeof(struct sbusfpga_trng_softc), + sbusfpga_trng_match, sbusfpga_trng_attach, NULL, NULL); + +dev_type_open(sbusfpga_trng_open); +dev_type_close(sbusfpga_trng_close); +dev_type_ioctl(sbusfpga_trng_ioctl); + + + +const struct cdevsw sbusfpga_trng_cdevsw = { + .d_open = sbusfpga_trng_open, + .d_close = sbusfpga_trng_close, + .d_read = noread, + .d_write = nowrite, + .d_ioctl = noioctl, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_discard = nodiscard, + .d_flag = 0 +}; + +extern struct cfdriver sbusfpga_trng_cd; +int +sbusfpga_trng_open(dev_t dev, int flags, int mode, struct lwp *l) +{ + return (0); +} + +int +sbusfpga_trng_close(dev_t dev, int flags, int mode, struct lwp *l) +{ + return (0); +} + +int +sbusfpga_trng_print(void *aux, const char *busname) +{ + + sbus_print(aux, busname); + return (UNCONF); +} + +int +sbusfpga_trng_match(device_t parent, cfdata_t cf, void *aux) +{ + struct sbus_attach_args *sa = (struct sbus_attach_args *)aux; + + return (strcmp("RDOL,neorv32trng", sa->sa_name) == 0); +} + +#define CONFIG_CSR_DATA_WIDTH 32 +// define CSR_LEDS_BASE & others to avoid defining the CSRs of HW we don't handle +#define CSR_LEDS_BASE +#define CSR_DDRPHY_BASE +#define CSR_EXCHANGE_WITH_MEM_BASE +#define CSR_SDRAM_BASE +#define CSR_SDBLOCK2MEM_BASE +#define CSR_SDCORE_BASE +#define CSR_SDIRQ_BASE +#define CSR_SDMEM2BLOCK_BASE +#define CSR_SDPHY_BASE +//#define CSR_TRNG_BASE +#include "dev/sbus/litex_csr.h" +#undef CSR_LEDS_BASE +#undef CSR_DDRPHY_BASE +#undef CSR_EXCHANGE_WITH_MEM_BASE +#undef CSR_SDRAM_BASE +#undef CSR_SDBLOCK2MEM_BASE +#undef CSR_SDCORE_BASE +#undef CSR_SDIRQ_BASE +#undef CSR_SDMEM2BLOCK_BASE +#undef CSR_SDPHY_BASE +//#undef CSR_TRNG_BASE + +static void +sbusfpga_trng_getentropy(size_t nbytes, void *cookie) { + struct sbusfpga_trng_softc *sc = cookie; + size_t dbytes = 0; + int failure = 0; + while ((nbytes - dbytes) > 0) { + u_int32_t data = trng_data_read(sc); + if (data) { + rnd_add_data_sync(&sc->sc_rndsource, &data, 4, 32); // 32 is perhaps optimistic + dbytes += 4; + } else { + failure ++; + if (failure > (1+(dbytes/4))) { // something going on + aprint_normal_dev(sc->sc_dev, "out of entropy after %zd / %zd bytes\n", dbytes, nbytes); + return; + } + delay(1); + } + } + aprint_normal_dev(sc->sc_dev, "gathered %zd bytes\n", dbytes); +} + +/* + * Attach all the sub-devices we can find + */ +void +sbusfpga_trng_attach(device_t parent, device_t self, void *aux) +{ + struct sbus_attach_args *sa = aux; + struct sbusfpga_trng_softc *sc = device_private(self); + struct sbus_softc *sbsc = device_private(parent); + int node; + int sbusburst; + + sc->sc_bustag = sa->sa_bustag; + sc->sc_dev = self; + + if (sbus_bus_map(sc->sc_bustag, sa->sa_slot, sa->sa_offset, sa->sa_size, + BUS_SPACE_MAP_LINEAR, &sc->sc_bhregs_trng) != 0) { + aprint_error(": cannot map registers\n"); + return; + } + + //sc->sc_buffer = bus_space_vaddr(sc->sc_bustag, sc->sc_bhregs_trng); + sc->sc_bufsiz = sa->sa_size; + + node = sc->sc_node = sa->sa_node; + + /* + * Get transfer burst size from PROM + */ + sbusburst = sbsc->sc_burst; + if (sbusburst == 0) + sbusburst = SBUS_BURST_32 - 1; /* 1->16 */ + + sc->sc_burst = prom_getpropint(node, "burst-sizes", -1); + if (sc->sc_burst == -1) + /* take SBus burst sizes */ + sc->sc_burst = sbusburst; + + /* Clamp at parent's burst sizes */ + sc->sc_burst &= sbusburst; + + aprint_normal("\n"); + aprint_normal_dev(self, "nid 0x%x, bustag %p, burst 0x%x (parent 0x%0x)\n", + sc->sc_node, + sc->sc_bustag, + sc->sc_burst, + sbsc->sc_burst); + + trng_ctrl_write(sc, 0x02); // start the TRNG + + rndsource_setcb(&sc->sc_rndsource, sbusfpga_trng_getentropy, sc); + rnd_attach_source(&sc->sc_rndsource, device_xname(self), RND_TYPE_RNG, RND_FLAG_HASCB | RND_FLAG_COLLECT_VALUE); +} diff --git a/NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.h b/NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.h new file mode 100644 index 0000000..365b367 --- /dev/null +++ b/NetBSD/9.0/usr/src/sys/dev/sbus/sbusfpga_trng.h @@ -0,0 +1,43 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2020 Romain Dolbeau + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _RDFPGA_TRNG_H_ +#define _RDFPGA_TRNG_H_ + +struct sbusfpga_trng_softc { + device_t sc_dev; /* us as a device */ + u_int sc_rev; /* revision */ + int sc_node; /* PROM node ID */ + int sc_burst; /* DVMA burst size in effect */ + bus_space_tag_t sc_bustag; /* bus tag */ + bus_space_handle_t sc_bhregs_trng; /* bus handle */ + int sc_bufsiz; /* Size of buffer */ + struct krndsource sc_rndsource; +}; + +#endif /* _RDFPGA_TRNG_H_ */ diff --git a/sbus-to-ztex-gateware-migen/neorv32_trng_patched.vhd b/sbus-to-ztex-gateware-migen/neorv32_trng_patched.vhd new file mode 100644 index 0000000..5934a41 --- /dev/null +++ b/sbus-to-ztex-gateware-migen/neorv32_trng_patched.vhd @@ -0,0 +1,382 @@ +-- # THIS IS NOT THE ORIGINAL FILE +-- # THIS WAS MODIFIED TO EXPOSE THE TRNG IN LITEX +-- # See the link in the copyright header to find the original file +-- +-- +-- ################################################################################################# +-- # << NEORV32 - True Random Number Generator (TRNG) >> # +-- # ********************************************************************************************* # +-- # This unit implements a *true* random number generator which uses several ring oscillators as # +-- # entropy source. The outputs of all chains are XORed and de-biased using a John von Neumann # +-- # randomness extractor. The de-biased signal is further processed by a simple LFSR for improved # +-- # whitening. # +-- # ********************************************************************************************* # +-- # BSD 3-Clause License # +-- # # +-- # Copyright (c) 2021, Stephan Nolting. All rights reserved. # +-- # # +-- # Redistribution and use in source and binary forms, with or without modification, are # +-- # permitted provided that the following conditions are met: # +-- # # +-- # 1. Redistributions of source code must retain the above copyright notice, this list of # +-- # conditions and the following disclaimer. # +-- # # +-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # +-- # conditions and the following disclaimer in the documentation and/or other materials # +-- # provided with the distribution. # +-- # # +-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # +-- # endorse or promote products derived from this software without specific prior written # +-- # permission. # +-- # # +-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # +-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # +-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # +-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # +-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # +-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # +-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # +-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # +-- # OF THE POSSIBILITY OF SUCH DAMAGE. # +-- # ********************************************************************************************* # +-- # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # +-- ################################################################################################# + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library neorv32; +-- use neorv32.neorv32_package.all; + +entity neorv32_trng is + port ( + -- host access -- + clk_i : in std_ulogic; -- global clock line +-- addr_i : in std_ulogic_vector(31 downto 0); -- address + rden_i : in std_ulogic; -- read enable + wren_i : in std_ulogic; -- write enable + data_i : in std_ulogic_vector(31 downto 0); -- data in + data_o : out std_ulogic_vector(31 downto 0)--; -- data out +-- ack_o : out std_ulogic -- transfer acknowledge + ); +end neorv32_trng; + +architecture neorv32_trng_rtl of neorv32_trng is + + -- Advanced Configuration -------------------------------------------------------------------------------- + constant num_roscs_c : natural := 4; -- total number of ring oscillators + constant num_inv_start_c : natural := 5; -- number of inverters in FIRST ring oscillator (has to be odd) + constant num_inv_inc_c : natural := 2; -- number of inverters increment for each next ring oscillator (has to be even) + constant lfsr_en_c : boolean := true; -- use LFSR-based post-processing + constant lfsr_taps_c : std_ulogic_vector(7 downto 0) := "10111000"; -- Fibonacci post-processing LFSR feedback taps + -- ------------------------------------------------------------------------------------------------------- + + -- 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_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 +-- constant lo_abb_c : natural := index_size_f(trng_size_c); -- low address boundary bit + +-- copy/pasted from the rtl/core/neorv32_package.vhd file + function xor_reduce_f(a : std_ulogic_vector) return std_ulogic is + variable tmp_v : std_ulogic; + begin + tmp_v := '0'; + if (a'low < a'high) then -- not null range? + for i in a'low to a'high loop + tmp_v := tmp_v xor a(i); + end loop; -- i + end if; + return tmp_v; + end function xor_reduce_f; + + + -- Component: Ring-Oscillator -- + component neorv32_trng_ring_osc + generic ( + NUM_INV : natural := 16 -- number of inverters in chain + ); + port ( + clk_i : in std_ulogic; + enable_i : in std_ulogic; -- enable chain input + enable_o : out std_ulogic; -- enable chain output + data_o : out std_ulogic -- sync random bit + ); + end component; + + -- access control -- + signal acc_en : std_ulogic; -- module access enable +-- signal wren : std_ulogic; -- full word write enable +-- signal rden : std_ulogic; -- read enable + + -- ring-oscillator array -- + signal osc_array_en_in : std_ulogic_vector(num_roscs_c-1 downto 0); + signal osc_array_en_out : std_ulogic_vector(num_roscs_c-1 downto 0); + signal osc_array_data : std_ulogic_vector(num_roscs_c-1 downto 0); + + -- von-Neumann de-biasing -- + type debiasing_t is record + sreg : std_ulogic_vector(1 downto 0); + state : std_ulogic; -- process de-biasing every second cycle + valid : std_ulogic; -- de-biased data + data : std_ulogic; -- de-biased data valid + end record; + signal debiasing : debiasing_t; + + -- (post-)processing core -- + type processing_t is record + enable : std_ulogic; -- TRNG enable flag + cnt : std_ulogic_vector(3 downto 0); -- bit counter + sreg : std_ulogic_vector(7 downto 0); -- data shift register + output : std_ulogic_vector(7 downto 0); -- output register + valid : std_ulogic; -- data output valid flag + end record; + signal processing : processing_t; + +begin + + -- Sanity Checks -------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + assert not (num_roscs_c = 0) report "NEORV32 PROCESSOR CONFIG ERROR: TRNG - Total number of ring-oscillators has to be >0." severity error; + assert not ((num_inv_start_c mod 2) = 0) report "NEORV32 PROCESSOR CONFIG ERROR: TRNG - Number of inverters in fisrt ring has to be odd." severity error; + assert not ((num_inv_inc_c mod 2) /= 0) report "NEORV32 PROCESSOR CONFIG ERROR: TRNG - Number of inverters increment for each next ring has to be even." severity error; + + + -- Access Control ------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- +-- acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = trng_base_c(hi_abb_c downto lo_abb_c)) else '0'; +-- wren <= acc_en and wren_i; +-- rden <= acc_en and rden_i; + + -- Read/Write Access ---------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + rw_access: process(clk_i) + begin + if rising_edge(clk_i) then +-- ack_o <= wren_i or rden_i; + -- write access -- + if (wren_i = '1') then + processing.enable <= data_i(ctrl_en_c); + end if; + -- read access -- +-- data_o <= (others => '0'); + if (rden_i = '1') then + data_o(ctrl_data_msb_c downto ctrl_data_lsb_c) <= processing.output; + data_o(ctrl_en_c) <= processing.enable; + data_o(ctrl_valid_c) <= processing.valid; + end if; + end if; + end process rw_access; + + + -- Entropy Source ------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + neorv32_trng_ring_osc_inst: + for i in 0 to num_roscs_c-1 generate + neorv32_trng_ring_osc_inst_i: neorv32_trng_ring_osc + generic map ( + NUM_INV => num_inv_start_c + (i*num_inv_inc_c) -- number of inverters in chain + ) + port map ( + clk_i => clk_i, + enable_i => osc_array_en_in(i), + enable_o => osc_array_en_out(i), + data_o => osc_array_data(i) + ); + end generate; + + -- RO enable chain -- + array_intercon: process(processing.enable, osc_array_en_out) + begin + for i in 0 to num_roscs_c-1 loop + if (i = 0) then -- start of enable chain + osc_array_en_in(i) <= processing.enable; + else + osc_array_en_in(i) <= osc_array_en_out(i-1); + end if; + end loop; -- i + end process array_intercon; + + + -- John von Neumann De-Biasing ------------------------------------------------------------ + -- ------------------------------------------------------------------------------------------- + neumann_debiasing_sync: process(clk_i) + begin + if rising_edge(clk_i) then + debiasing.sreg <= debiasing.sreg(debiasing.sreg'left-1 downto 0) & xor_reduce_f(osc_array_data); + debiasing.state <= (not debiasing.state) and osc_array_en_out(num_roscs_c-1); -- start toggling when last RO is enabled -> process in every second cycle + end if; + end process neumann_debiasing_sync; + + -- Edge detector -- + neumann_debiasing_comb: process(debiasing) + variable tmp_v : std_ulogic_vector(2 downto 0); + begin + -- check groups of two non-overlapping bits from the input stream + tmp_v := debiasing.state & debiasing.sreg; + case tmp_v is + when "101" => debiasing.valid <= '1'; debiasing.data <= '1'; -- rising edge -> '1' + when "110" => debiasing.valid <= '1'; debiasing.data <= '0'; -- falling edge -> '0' + when others => debiasing.valid <= '0'; debiasing.data <= '0'; -- no valid data + end case; + end process neumann_debiasing_comb; + + + -- Processing Core ------------------------------------------------------------------------ + -- ------------------------------------------------------------------------------------------- + processing_core: process(clk_i) + begin + if rising_edge(clk_i) then + -- sample random data bit and apply post-processing -- + if (processing.enable = '0') then + processing.cnt <= (others => '0'); + processing.sreg <= (others => '0'); + elsif (debiasing.valid = '1') then -- valid random sample? + if (processing.cnt = "1000") then + processing.cnt <= (others => '0'); + else + processing.cnt <= std_ulogic_vector(unsigned(processing.cnt) + 1); + end if; + if (lfsr_en_c = true) then -- LFSR post-processing + processing.sreg <= processing.sreg(processing.sreg'left-1 downto 0) & ((not xor_reduce_f(processing.sreg and lfsr_taps_c)) xnor debiasing.data); + else -- NO post-processing + processing.sreg <= processing.sreg(processing.sreg'left-1 downto 0) & debiasing.data; + end if; + end if; + + -- data output register -- + if (processing.cnt = "1000") then + processing.output <= processing.sreg; + end if; + + -- data ready/valid flag -- + if (processing.cnt = "1000") then -- new sample ready? + processing.valid <= '1'; + elsif (processing.enable = '0') or (rden_i = '1') then -- clear when deactivated or on data read + processing.valid <= '0'; + end if; + end if; + end process processing_core; + + +end neorv32_trng_rtl; + + +-- ############################################################################################################################ +-- ############################################################################################################################ + + +-- ################################################################################################# +-- # << NEORV32 - True Random Number Generator (TRNG) - Ring-Oscillator-Based Entropy Source >> # +-- # ********************************************************************************************* # +-- # An inverter chain (ring oscillator) is used as entropy source. # +-- # The inverter chain is constructed as an "asynchronous" LFSR. The single inverters are # +-- # connected via latches that are used to enable/disable the TRNG. Also, these latches are used # +-- # as additional delay element. By using unique enable signals for each latch, the synthesis # +-- # tool cannot "optimize" (=remove) any of the inverters out of the design. Furthermore, the # +-- # latches prevent the synthesis tool from detecting combinatorial loops. # +-- # ********************************************************************************************* # +-- # BSD 3-Clause License # +-- # # +-- # Copyright (c) 2021, Stephan Nolting. All rights reserved. # +-- # # +-- # Redistribution and use in source and binary forms, with or without modification, are # +-- # permitted provided that the following conditions are met: # +-- # # +-- # 1. Redistributions of source code must retain the above copyright notice, this list of # +-- # conditions and the following disclaimer. # +-- # # +-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # +-- # conditions and the following disclaimer in the documentation and/or other materials # +-- # provided with the distribution. # +-- # # +-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # +-- # endorse or promote products derived from this software without specific prior written # +-- # permission. # +-- # # +-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # +-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # +-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # +-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # +-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # +-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # +-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # +-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # +-- # OF THE POSSIBILITY OF SUCH DAMAGE. # +-- # ********************************************************************************************* # +-- # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # +-- ################################################################################################# + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library neorv32; +-- use neorv32.neorv32_package.all; + +entity neorv32_trng_ring_osc is + generic ( + NUM_INV : natural := 15 -- number of inverters in chain + ); + port ( + clk_i : in std_ulogic; + enable_i : in std_ulogic; -- enable chain input + enable_o : out std_ulogic; -- enable chain output + data_o : out std_ulogic -- sync random bit + ); +end neorv32_trng_ring_osc; + +architecture neorv32_trng_ring_osc_rtl of neorv32_trng_ring_osc is + + signal inv_chain : std_ulogic_vector(NUM_INV-1 downto 0); -- oscillator chain + signal enable_sreg : std_ulogic_vector(NUM_INV-1 downto 0); -- enable shift register + signal sync_ff : std_ulogic_vector(1 downto 0); -- output signal synchronizer + +begin + + -- Ring Oscillator ------------------------------------------------------------------------ + -- ------------------------------------------------------------------------------------------- + ring_osc: process(enable_i, enable_sreg, inv_chain) + begin + -- Using individual enable signals for each inverter - derived from a shift register - to prevent the synthesis tool + -- from removing all but one inverter (since they implement "logical identical functions"). + -- This also allows to make the TRNG platform independent. + for i in 0 to NUM_INV-1 loop -- inverters in chain + if (enable_i = '0') then -- start with a defined state (latch reset) + inv_chain(i) <= '0'; + elsif (enable_sreg(i) = '1') then + -- here we have the inverter chain -- + if (i = NUM_INV-1) then -- left-most inverter? + inv_chain(i) <= not inv_chain(0); + else + inv_chain(i) <= not inv_chain(i+1); + end if; + end if; + end loop; -- i + end process ring_osc; + + + -- Control -------------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + ctrl_unit: process(clk_i) + begin + if rising_edge(clk_i) then + enable_sreg <= enable_sreg(enable_sreg'left-1 downto 0) & enable_i; -- activate right-most inverter first + sync_ff <= sync_ff(0) & inv_chain(0); -- synchronize to prevent metastability + end if; + end process ctrl_unit; + + -- output for "enable chain" -- + enable_o <= enable_sreg(enable_sreg'left); + + -- rnd output -- + data_o <= sync_ff(1); + + +end neorv32_trng_ring_osc_rtl; diff --git a/sbus-to-ztex-gateware-migen/netbsd_csr.h b/sbus-to-ztex-gateware-migen/netbsd_csr.h index 534c79e..cf7ec66 100644 --- a/sbus-to-ztex-gateware-migen/netbsd_csr.h +++ b/sbus-to-ztex-gateware-migen/netbsd_csr.h @@ -1,5 +1,5 @@ //-------------------------------------------------------------------------------- -// Auto-generated by Migen (3ffd64c) & LiteX (8a644c90) on 2021-07-18 12:35:05 +// Auto-generated by Migen (3ffd64c) & LiteX (8a644c90) on 2021-07-20 07:32:43 //-------------------------------------------------------------------------------- #ifndef __GENERATED_CSR_H #define __GENERATED_CSR_H @@ -12,10 +12,10 @@ #define CSR_LEDS_BASE (CSR_BASE + 0x0L) #define CSR_LEDS_OUT_ADDR (CSR_LEDS_BASE + 0x0L) #define CSR_LEDS_OUT_SIZE 1 -static inline uint32_t leds_out_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t leds_out_read(struct sbusfpga_leds_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_leds, 0x0L); } -static inline void leds_out_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void leds_out_write(struct sbusfpga_leds_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_leds, 0x0L, v); } #endif // CSR_LEDS_BASE @@ -25,106 +25,106 @@ static inline void leds_out_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { #define CSR_DDRPHY_BASE (CSR_BASE + 0x1000L) #define CSR_DDRPHY_RST_ADDR (CSR_DDRPHY_BASE + 0x0L) #define CSR_DDRPHY_RST_SIZE 1 -static inline uint32_t ddrphy_rst_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_rst_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x0L); } -static inline void ddrphy_rst_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_rst_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x0L, v); } #define CSR_DDRPHY_HALF_SYS8X_TAPS_ADDR (CSR_DDRPHY_BASE + 0x4L) #define CSR_DDRPHY_HALF_SYS8X_TAPS_SIZE 1 -static inline uint32_t ddrphy_half_sys8x_taps_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_half_sys8x_taps_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x4L); } -static inline void ddrphy_half_sys8x_taps_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_half_sys8x_taps_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x4L, v); } #define CSR_DDRPHY_WLEVEL_EN_ADDR (CSR_DDRPHY_BASE + 0x8L) #define CSR_DDRPHY_WLEVEL_EN_SIZE 1 -static inline uint32_t ddrphy_wlevel_en_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_wlevel_en_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x8L); } -static inline void ddrphy_wlevel_en_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_wlevel_en_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x8L, v); } #define CSR_DDRPHY_WLEVEL_STROBE_ADDR (CSR_DDRPHY_BASE + 0xcL) #define CSR_DDRPHY_WLEVEL_STROBE_SIZE 1 -static inline uint32_t ddrphy_wlevel_strobe_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_wlevel_strobe_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0xcL); } -static inline void ddrphy_wlevel_strobe_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_wlevel_strobe_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0xcL, v); } #define CSR_DDRPHY_DLY_SEL_ADDR (CSR_DDRPHY_BASE + 0x10L) #define CSR_DDRPHY_DLY_SEL_SIZE 1 -static inline uint32_t ddrphy_dly_sel_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_dly_sel_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x10L); } -static inline void ddrphy_dly_sel_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_dly_sel_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x10L, v); } #define CSR_DDRPHY_RDLY_DQ_RST_ADDR (CSR_DDRPHY_BASE + 0x14L) #define CSR_DDRPHY_RDLY_DQ_RST_SIZE 1 -static inline uint32_t ddrphy_rdly_dq_rst_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_rdly_dq_rst_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x14L); } -static inline void ddrphy_rdly_dq_rst_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_rdly_dq_rst_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x14L, v); } #define CSR_DDRPHY_RDLY_DQ_INC_ADDR (CSR_DDRPHY_BASE + 0x18L) #define CSR_DDRPHY_RDLY_DQ_INC_SIZE 1 -static inline uint32_t ddrphy_rdly_dq_inc_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_rdly_dq_inc_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x18L); } -static inline void ddrphy_rdly_dq_inc_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_rdly_dq_inc_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x18L, v); } #define CSR_DDRPHY_RDLY_DQ_BITSLIP_RST_ADDR (CSR_DDRPHY_BASE + 0x1cL) #define CSR_DDRPHY_RDLY_DQ_BITSLIP_RST_SIZE 1 -static inline uint32_t ddrphy_rdly_dq_bitslip_rst_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_rdly_dq_bitslip_rst_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x1cL); } -static inline void ddrphy_rdly_dq_bitslip_rst_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_rdly_dq_bitslip_rst_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x1cL, v); } #define CSR_DDRPHY_RDLY_DQ_BITSLIP_ADDR (CSR_DDRPHY_BASE + 0x20L) #define CSR_DDRPHY_RDLY_DQ_BITSLIP_SIZE 1 -static inline uint32_t ddrphy_rdly_dq_bitslip_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_rdly_dq_bitslip_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x20L); } -static inline void ddrphy_rdly_dq_bitslip_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_rdly_dq_bitslip_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x20L, v); } #define CSR_DDRPHY_WDLY_DQ_BITSLIP_RST_ADDR (CSR_DDRPHY_BASE + 0x24L) #define CSR_DDRPHY_WDLY_DQ_BITSLIP_RST_SIZE 1 -static inline uint32_t ddrphy_wdly_dq_bitslip_rst_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_wdly_dq_bitslip_rst_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x24L); } -static inline void ddrphy_wdly_dq_bitslip_rst_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_wdly_dq_bitslip_rst_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x24L, v); } #define CSR_DDRPHY_WDLY_DQ_BITSLIP_ADDR (CSR_DDRPHY_BASE + 0x28L) #define CSR_DDRPHY_WDLY_DQ_BITSLIP_SIZE 1 -static inline uint32_t ddrphy_wdly_dq_bitslip_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_wdly_dq_bitslip_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x28L); } -static inline void ddrphy_wdly_dq_bitslip_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_wdly_dq_bitslip_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x28L, v); } #define CSR_DDRPHY_RDPHASE_ADDR (CSR_DDRPHY_BASE + 0x2cL) #define CSR_DDRPHY_RDPHASE_SIZE 1 -static inline uint32_t ddrphy_rdphase_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_rdphase_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x2cL); } -static inline void ddrphy_rdphase_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_rdphase_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x2cL, v); } #define CSR_DDRPHY_WRPHASE_ADDR (CSR_DDRPHY_BASE + 0x30L) #define CSR_DDRPHY_WRPHASE_SIZE 1 -static inline uint32_t ddrphy_wrphase_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t ddrphy_wrphase_read(struct sbusfpga_ddrphy_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x30L); } -static inline void ddrphy_wrphase_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void ddrphy_wrphase_write(struct sbusfpga_ddrphy_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_ddrphy, 0x30L, v); } #endif // CSR_DDRPHY_BASE @@ -134,66 +134,66 @@ static inline void ddrphy_wrphase_write(struct sbusfpga_sdram_softc *sc, uint32_ #define CSR_EXCHANGE_WITH_MEM_BASE (CSR_BASE + 0x2000L) #define CSR_EXCHANGE_WITH_MEM_BLK_SIZE_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0x0L) #define CSR_EXCHANGE_WITH_MEM_BLK_SIZE_SIZE 1 -static inline uint32_t exchange_with_mem_blk_size_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_blk_size_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x0L); } #define CSR_EXCHANGE_WITH_MEM_BLK_BASE_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0x4L) #define CSR_EXCHANGE_WITH_MEM_BLK_BASE_SIZE 1 -static inline uint32_t exchange_with_mem_blk_base_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_blk_base_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x4L); } #define CSR_EXCHANGE_WITH_MEM_MEM_SIZE_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0x8L) #define CSR_EXCHANGE_WITH_MEM_MEM_SIZE_SIZE 1 -static inline uint32_t exchange_with_mem_mem_size_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_mem_size_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x8L); } #define CSR_EXCHANGE_WITH_MEM_BLK_ADDR_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0xcL) #define CSR_EXCHANGE_WITH_MEM_BLK_ADDR_SIZE 1 -static inline uint32_t exchange_with_mem_blk_addr_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_blk_addr_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0xcL); } -static inline void exchange_with_mem_blk_addr_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void exchange_with_mem_blk_addr_write(struct sbusfpga_exchange_with_mem_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0xcL, v); } #define CSR_EXCHANGE_WITH_MEM_DMA_ADDR_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0x10L) #define CSR_EXCHANGE_WITH_MEM_DMA_ADDR_SIZE 1 -static inline uint32_t exchange_with_mem_dma_addr_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_dma_addr_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x10L); } -static inline void exchange_with_mem_dma_addr_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void exchange_with_mem_dma_addr_write(struct sbusfpga_exchange_with_mem_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x10L, v); } #define CSR_EXCHANGE_WITH_MEM_BLK_CNT_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0x14L) #define CSR_EXCHANGE_WITH_MEM_BLK_CNT_SIZE 1 -static inline uint32_t exchange_with_mem_blk_cnt_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_blk_cnt_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x14L); } -static inline void exchange_with_mem_blk_cnt_write(struct sbusfpga_sdram_softc *sc, uint32_t v) { +static inline void exchange_with_mem_blk_cnt_write(struct sbusfpga_exchange_with_mem_softc *sc, uint32_t v) { bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x14L, v); } #define CSR_EXCHANGE_WITH_MEM_LAST_BLK_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0x18L) #define CSR_EXCHANGE_WITH_MEM_LAST_BLK_SIZE 1 -static inline uint32_t exchange_with_mem_last_blk_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_last_blk_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x18L); } #define CSR_EXCHANGE_WITH_MEM_LAST_DMA_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0x1cL) #define CSR_EXCHANGE_WITH_MEM_LAST_DMA_SIZE 1 -static inline uint32_t exchange_with_mem_last_dma_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_last_dma_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x1cL); } #define CSR_EXCHANGE_WITH_MEM_BLK_REM_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0x20L) #define CSR_EXCHANGE_WITH_MEM_BLK_REM_SIZE 1 -static inline uint32_t exchange_with_mem_blk_rem_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_blk_rem_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x20L); } #define CSR_EXCHANGE_WITH_MEM_DMA_STATUS_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0x24L) #define CSR_EXCHANGE_WITH_MEM_DMA_STATUS_SIZE 1 -static inline uint32_t exchange_with_mem_dma_status_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_dma_status_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x24L); } #define CSR_EXCHANGE_WITH_MEM_WR_TOSDRAM_ADDR (CSR_EXCHANGE_WITH_MEM_BASE + 0x28L) #define CSR_EXCHANGE_WITH_MEM_WR_TOSDRAM_SIZE 1 -static inline uint32_t exchange_with_mem_wr_tosdram_read(struct sbusfpga_sdram_softc *sc) { +static inline uint32_t exchange_with_mem_wr_tosdram_read(struct sbusfpga_exchange_with_mem_softc *sc) { return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_exchange_with_mem, 0x28L); } #endif // CSR_EXCHANGE_WITH_MEM_BASE @@ -467,4 +467,22 @@ static inline uint32_t sdram_dfii_pi3_rddata_read(struct sbusfpga_sdram_softc *s } #endif // CSR_SDRAM_BASE +/* trng */ +#ifndef CSR_TRNG_BASE +#define CSR_TRNG_BASE (CSR_BASE + 0x4000L) +#define CSR_TRNG_CTRL_ADDR (CSR_TRNG_BASE + 0x0L) +#define CSR_TRNG_CTRL_SIZE 1 +static inline uint32_t trng_ctrl_read(struct sbusfpga_trng_softc *sc) { + return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_trng, 0x0L); +} +static inline void trng_ctrl_write(struct sbusfpga_trng_softc *sc, uint32_t v) { + bus_space_write_4(sc->sc_bustag, sc->sc_bhregs_trng, 0x0L, v); +} +#define CSR_TRNG_DATA_ADDR (CSR_TRNG_BASE + 0x4L) +#define CSR_TRNG_DATA_SIZE 1 +static inline uint32_t trng_data_read(struct sbusfpga_trng_softc *sc) { + return bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_trng, 0x4L); +} +#endif // CSR_TRNG_BASE + #endif diff --git a/sbus-to-ztex-gateware-migen/prom_csr.fth b/sbus-to-ztex-gateware-migen/prom_csr.fth index d0b8e76..44c9655 100644 --- a/sbus-to-ztex-gateware-migen/prom_csr.fth +++ b/sbus-to-ztex-gateware-migen/prom_csr.fth @@ -3,6 +3,7 @@ h# 40000 constant sbusfpga_csraddr_leds h# 41000 constant sbusfpga_csraddr_ddrphy h# 42000 constant sbusfpga_csraddr_exchange_with_mem h# 43000 constant sbusfpga_csraddr_sdram +h# 44000 constant sbusfpga_csraddr_trng h# 80000 constant sbusfpga_regionaddr_usb_host_ctrl h# 0 constant sbusfpga_regionaddr_prom h# 80000000 constant sbusfpga_regionaddr_main_ram diff --git a/sbus-to-ztex-gateware-migen/prom_migen.fth b/sbus-to-ztex-gateware-migen/prom_migen.fth index 6b0821d..1170c1a 100644 --- a/sbus-to-ztex-gateware-migen/prom_migen.fth +++ b/sbus-to-ztex-gateware-migen/prom_migen.fth @@ -5,6 +5,7 @@ fload prom_csr.fth \ fload v2compat.fth +\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ LEDs \ Absolute minimal stuff; name & registers def. " RDOL,led" device-name my-address sbusfpga_csraddr_leds + my-space h# 4 reg @@ -38,6 +39,7 @@ my-space constant my-sbus-space \ tokenizer[ 01 emit-byte h# 27 emit-byte h# 01 emit-byte h# 1f emit-byte ]tokenizer \ The OpenFirmware tokenizer does accept the 'clean' syntax finish-device +\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ USB OHCI new-device \ Absolute minimal stuff; name & registers def. @@ -86,6 +88,7 @@ my-reset! \ tokenizer[ 01 emit-byte h# 27 emit-byte h# 01 emit-byte h# 1f emit-byte ]tokenizer \ The OpenFirmware tokenizer does accept the 'clean' syntax finish-device +\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ SDRAM new-device \ Absolute minimal stuff; name & registers def. @@ -129,4 +132,42 @@ my-space constant my-sbus-space \ init! + +\ OpenBIOS tokenizer won't accept finish-device without new-device +\ Cheat by using the tokenizer so we can do OpenBoot 2.x siblings +\ tokenizer[ 01 emit-byte h# 27 emit-byte h# 01 emit-byte h# 1f emit-byte ]tokenizer +\ The OpenFirmware tokenizer does accept the 'clean' syntax +finish-device +\ \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ TRNG +new-device + +\ Absolute minimal stuff; name & registers def. +" RDOL,neorv32trng" device-name + +my-address sbusfpga_csraddr_trng + my-space h# 8 reg +\ we don't support ET or HWORD +h# 7d xdrint " slave-burst-sizes" attribute +h# 7d xdrint " burst-sizes" attribute + +headers +-1 instance value trng-virt +my-address constant my-sbus-address +my-space constant my-sbus-space + +: map-in ( adr space size -- virt ) " map-in" $call-parent ; +: map-out ( virt size -- ) " map-out" $call-parent ; + +: map-in-trng ( -- ) my-sbus-address sbusfpga_csraddr_trng + my-sbus-space h# 8 map-in is trng-virt ; +: map-out-trng ( -- ) trng-virt h# 8 map-out ; + +\ external + +: disabletrng! ( -- ) + map-in-trng + 1 trng-virt l! ( pattern virt -- ) + map-out-trng +; + +disabletrng! + end0 diff --git a/sbus-to-ztex-gateware-migen/sbus_to_fpga_export.py b/sbus-to-ztex-gateware-migen/sbus_to_fpga_export.py index 3859bb6..e6a2f1a 100644 --- a/sbus-to-ztex-gateware-migen/sbus_to_fpga_export.py +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_export.py @@ -43,7 +43,7 @@ def _get_rw_functions_c(name, csr_name, reg_base, area_base, nwords, busword, al stride = alignment//8; if with_access_functions: - r += "static inline {} {}_read(struct sbusfpga_sdram_softc *sc) {{\n".format(ctype, reg_name) + r += "static inline {} {}_read(struct sbusfpga_{}_softc *sc) {{\n".format(ctype, reg_name, name) if nwords > 1: r += "\t{} r = bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_{}, {}L);\n".format(ctype, name, hex(reg_base - area_base)) for sub in range(1, nwords): @@ -54,7 +54,7 @@ def _get_rw_functions_c(name, csr_name, reg_base, area_base, nwords, busword, al r += "\treturn bus_space_read_4(sc->sc_bustag, sc->sc_bhregs_{}, {}L);\n}}\n".format(name, hex(reg_base - area_base)) if not read_only: - r += "static inline void {}_write(struct sbusfpga_sdram_softc *sc, {} v) {{\n".format(reg_name, ctype) + r += "static inline void {}_write(struct sbusfpga_{}_softc *sc, {} v) {{\n".format(reg_name, name, ctype) for sub in range(nwords): shift = (nwords-sub-1)*busword if shift: @@ -102,18 +102,18 @@ def get_csr_header(regions, constants, csr_base=None, with_access_functions=True if with_access_functions and csr.size <= 32: # FIXME: Implement extract/read functions for csr.size > 32-bit. reg_name = name + "_" + csr.name.lower() field_name = reg_name + "_" + field.name.lower() - r += "static inline uint32_t " + field_name + "_extract(struct sbusfpga_sdram_softc *sc, uint32_t oldword) {\n" + r += "static inline uint32_t " + field_name + "_extract(struct sbusfpga_" + name + "_softc *sc, uint32_t oldword) {\n" r += "\tuint32_t mask = ((1 << " + size + ")-1);\n" r += "\treturn ( (oldword >> " + offset + ") & mask );\n}\n" - r += "static inline uint32_t " + field_name + "_read(struct sbusfpga_sdram_softc *sc) {\n" + r += "static inline uint32_t " + field_name + "_read(struct sbusfpga_" + name + "_softc *sc) {\n" r += "\tuint32_t word = " + reg_name + "_read(sc);\n" r += "\treturn " + field_name + "_extract(sc, word);\n" r += "}\n" if not getattr(csr, "read_only", False): - r += "static inline uint32_t " + field_name + "_replace(struct sbusfpga_sdram_softc *sc, uint32_t oldword, uint32_t plain_value) {\n" + r += "static inline uint32_t " + field_name + "_replace(struct sbusfpga_" + name + "_softc *sc, uint32_t oldword, uint32_t plain_value) {\n" r += "\tuint32_t mask = ((1 << " + size + ")-1);\n" r += "\treturn (oldword & (~(mask << " + offset + "))) | (mask & plain_value)<< " + offset + " ;\n}\n" - r += "static inline void " + field_name + "_write(struct sbusfpga_sdram_softc *sc, uint32_t plain_value) {\n" + r += "static inline void " + field_name + "_write(struct sbusfpga_" + name + "_softc *sc, uint32_t plain_value) {\n" r += "\tuint32_t oldword = " + reg_name + "_read(sc);\n" r += "\tuint32_t newword = " + field_name + "_replace(sc, oldword, plain_value);\n" r += "\t" + reg_name + "_write(sc, newword);\n" diff --git a/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py b/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py index 78f4152..e8faeb7 100644 --- a/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_soc.py @@ -18,6 +18,7 @@ from litedram.phy import s7ddrphy from sbus_to_fpga_fsm import * from sbus_to_fpga_blk_dma import * +from sbus_to_fpga_trng import * from litedram.frontend.dma import * @@ -226,6 +227,8 @@ class SBusFPGA(SoCCore): #self.add_sdcard() + self.submodules.trng = NeoRV32TrngWrapper(platform=platform) + def main(): parser = argparse.ArgumentParser(description="SbusFPGA") parser.add_argument("--build", action="store_true", help="Build bitstream") diff --git a/sbus-to-ztex-gateware-migen/sbus_to_fpga_trng.py b/sbus-to-ztex-gateware-migen/sbus_to_fpga_trng.py new file mode 100644 index 0000000..5db0f8e --- /dev/null +++ b/sbus-to-ztex-gateware-migen/sbus_to_fpga_trng.py @@ -0,0 +1,94 @@ +from migen import * +from migen.genlib.fifo import * +from litex.soc.interconnect.csr import * + +class NeoRV32TrngWrapper(Module, AutoCSR): + def __init__(self, platform): + self.add_sources(platform) + + rden_i = Signal() + wren_i = Signal() + data_i = Signal(32) + data_o = Signal(32) + + self.ctrl = CSRStorage(32, description = "CTRL register; bit 0 : disable ; bit 1 : enable") + self.data = CSRStatus(32, description = "Rnd Data or 0") + + self.submodules.ctrl_fsm = ctrl_fsm = FSM(reset_state = "Reset") + ctrl_fsm.act("Reset", + NextState("Idle") + ) + ctrl_fsm.act("Idle", + If(self.ctrl.re, # someone has written control + If(self.ctrl.storage[0], + data_i.eq(0), + wren_i.eq(1), + ).Elif(self.ctrl.storage[1], + data_i.eq(0xffffffff), + wren_i.eq(1), + ) + ), + If(self.data.we, # someone has read the data, reset so that the same value is never read twice + NextValue(self.data.status, 0), + ) + ) + + # fill out an intermediate buffer, one byte every 11 cycles + # then copy the 4 bytes to data CST and do it all over again + buf = Array(Signal(8) for a in range(4)) + idx = Signal(2) + cnt = Signal(4) + self.submodules.upd_fsm = upd_fsm = FSM(reset_state = "Reset") + upd_fsm.act("Reset", + NextValue(cnt, 11), + NextValue(idx, 0), + NextState("ByteWait") + ) + upd_fsm.act("ByteWait", + If(cnt == 0, + rden_i.eq(1), + NextState("ByteWrite"), + ).Else( + NextValue(cnt, cnt - 1) + ) + ) + upd_fsm.act("ByteWrite", + If (data_o[31] & data_o[30], + NextValue(buf[idx], data_o[0:8]), + NextValue(cnt, 11), + NextValue(idx, idx + 1), + If(idx == 3, + NextState("Copy"), + ).Else( + NextState("ByteWait"), + ) + ).Else( # try again + NextValue(cnt, 11), + NextState("ByteWait"), + ) + ) + upd_fsm.act("Copy", + NextValue(self.data.status, Cat(buf[0], buf[1], buf[2], buf[3])), + NextValue(buf[0], 0), + NextValue(buf[1], 0), + NextValue(buf[2], 0), + NextValue(buf[3], 0), + NextState("ByteWait") + ) + + + + + self.specials += Instance(self.get_netlist_name(), + i_clk_i = ClockSignal("sys"), + i_rden_i = rden_i, + i_wren_i = wren_i, + i_data_i = data_i, + o_data_o = data_o) + + def get_netlist_name(self): + return "neorv32_trng" + + def add_sources(self, platform): + platform.add_source("neorv32_trng_patched.vhd", "vhdl") +