Add random number generator and implement the darn instruction
authorPaul Mackerras <paulus@ozlabs.org>
Wed, 5 Aug 2020 05:28:45 +0000 (15:28 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Thu, 6 Aug 2020 01:31:13 +0000 (11:31 +1000)
This adds a true random number generator for the Xilinx FPGAs which
uses a set of chaotic ring oscillators to generate random bits and
then passes them through a Linear Hybrid Cellular Automaton (LHCA) to
remove bias, as described in "High Speed True Random Number Generators
in Xilinx FPGAs" by Catalin Baetoniu of Xilinx Inc., in:

https://pdfs.semanticscholar.org/83ac/9e9c1bb3dad5180654984604c8d5d8137412.pdf

This requires adding a .xdc file to tell vivado that the combinatorial
loops that form the ring oscillators are intentional.  The same
code should work on other FPGAs as well if their tools can be told to
accept the combinatorial loops.

For simulation, the random.vhdl module gets compiled in, which uses
the pseudorand() function to generate random numbers.

Synthesis using yosys uses nonrandom.vhdl, which always signals an
error, causing darn to return 0xffff_ffff_ffff_ffff.

This adds an implementation of the darn instruction.  Darn can return
either raw or conditioned random numbers.  On Xilinx FPGAs, reading a
raw random number gives the output of the ring oscillators, and
reading a conditioned random number gives the output of the LHCA.

Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Makefile
decode1.vhdl
execute1.vhdl
fpga/fpga-random.vhdl [new file with mode: 0644]
fpga/fpga-random.xdc [new file with mode: 0644]
microwatt.core
nonrandom.vhdl [new file with mode: 0644]
random.vhdl [new file with mode: 0644]

index 096be56007230826c3bfa645c8a2309cb661cc2f..b584895b66ddece8b26cc087f5b3bd8ff7be8bd9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -58,7 +58,8 @@ uart_files = $(wildcard uart16550/*.v)
 
 soc_sim_files = $(soc_files) sim_console.vhdl sim_pp_uart.vhdl sim_bram_helpers.vhdl \
        sim_bram.vhdl sim_jtag_socket.vhdl sim_jtag.vhdl dmi_dtm_xilinx.vhdl \
-       sim_16550_uart.vhdl
+       sim_16550_uart.vhdl \
+       random.vhdl glibc_random.vhdl glibc_random_helpers.vhdl
 
 soc_sim_c_files = sim_vhpi_c.c sim_bram_helpers_c.c sim_console_c.c \
        sim_jtag_socket_c.c
@@ -177,7 +178,8 @@ toplevel=fpga/top-generic.vhdl
 dmi_dtm=dmi_dtm_dummy.vhdl
 
 fpga_files = $(core_files) $(soc_files) fpga/soc_reset.vhdl \
-       fpga/pp_fifo.vhd fpga/pp_soc_uart.vhd fpga/main_bram.vhdl
+       fpga/pp_fifo.vhd fpga/pp_soc_uart.vhd fpga/main_bram.vhdl \
+       nonrandom.vhdl
 
 synth_files = $(core_files) $(soc_files) $(fpga_files) $(clkgen) $(toplevel) $(dmi_dtm)
 
index eceee40b3a086742e388560c89417a817a05d35a..a58525e9a8c6671021693137c06ac6ebe5400ef3 100644 (file)
@@ -188,7 +188,7 @@ architecture behaviour of decode1 is
         2#0000011010#  =>       (ALU,    OP_CNTZ,      NONE,       NONE,        RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0'), -- cntlzw
         2#1000111010#  =>       (ALU,    OP_CNTZ,      NONE,       NONE,        RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC,   '0', '0'), -- cnttzd
         2#1000011010#  =>       (ALU,    OP_CNTZ,      NONE,       NONE,        RS,   RA,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC,   '0', '0'), -- cnttzw
-        -- 2#1011110011# darn
+        2#1011110011#  =>       (ALU,    OP_DARN,      NONE,       NONE,        NONE, RT,   '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0'), -- darn
         2#0001010110#  =>       (ALU,    OP_NOP,       NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbf
         2#0000110110#  =>       (ALU,    OP_NOP,       NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbst
         2#0100010110#  =>       (ALU,    OP_NOP,       NONE,       NONE,        NONE, NONE, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '1'), -- dcbt
index a620a509c06f382c822d2126c745570649537383..a53024fc8e26577f08bc4dc8d448577e6e3b2b16 100644 (file)
@@ -97,6 +97,11 @@ architecture behaviour of execute1 is
     signal x_to_divider: Execute1ToDividerType;
     signal divider_to_x: DividerToExecute1Type;
 
+    -- random number generator signals
+    signal random_raw  : std_ulogic_vector(63 downto 0);
+    signal random_cond : std_ulogic_vector(63 downto 0);
+    signal random_err  : std_ulogic;
+
     -- signals for logging
     signal exception_log : std_ulogic;
     signal irq_valid_log : std_ulogic;
@@ -185,6 +190,11 @@ architecture behaviour of execute1 is
        return msr_out;
     end;
 
+    -- Tell vivado to keep the hierarchy for the random module so that the
+    -- net names in the xdc file match.
+    attribute keep_hierarchy : string;
+    attribute keep_hierarchy of random_0 : label is "yes";
+
 begin
 
     rotator_0: entity work.rotator
@@ -238,6 +248,14 @@ begin
             d_out => divider_to_x
             );
 
+    random_0: entity work.random
+        port map (
+            clk => clk,
+            data => random_cond,
+            raw => random_raw,
+            err => random_err
+            );
+
     dbg_msr_out <= ctrl.msr;
     log_rd_addr <= r.log_addr_spr;
 
@@ -776,6 +794,20 @@ begin
                 v.e.write_cr_mask := num_to_fxm(crnum);
                 v.e.write_cr_data := newcrf & newcrf & newcrf & newcrf &
                                      newcrf & newcrf & newcrf & newcrf;
+            when OP_DARN =>
+                if random_err = '0' then
+                    case e_in.insn(17 downto 16) is
+                        when "00" =>
+                            result := x"00000000" & random_cond(31 downto 0);
+                        when "10" =>
+                            result := random_raw;
+                        when others =>
+                            result := random_cond;
+                    end case;
+                else
+                    result := (others => '1');
+                end if;
+                result_en := '1';
            when OP_MFMSR =>
                result := ctrl.msr;
                result_en := '1';
diff --git a/fpga/fpga-random.vhdl b/fpga/fpga-random.vhdl
new file mode 100644 (file)
index 0000000..7897c05
--- /dev/null
@@ -0,0 +1,53 @@
+-- Random number generator for Microwatt
+-- Based on https://pdfs.semanticscholar.org/83ac/9e9c1bb3dad5180654984604c8d5d8137412.pdf
+-- "High Speed True Random Number Generators in Xilinx FPGAs"
+-- by Catalin Baetoniu, Xilinx Inc.
+
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+
+entity random is
+    port (
+        clk  : in std_ulogic;
+        data : out std_ulogic_vector(63 downto 0);
+        raw  : out std_ulogic_vector(63 downto 0);
+        err  : out std_ulogic
+        );
+end entity random;
+
+architecture behaviour of random is
+    signal ringosc : std_ulogic_vector(63 downto 0);
+    signal ro_reg  : std_ulogic_vector(63 downto 0);
+    signal lhca    : std_ulogic_vector(63 downto 0);
+
+    constant lhca_diag : std_ulogic_vector(63 downto 0) := x"fffffffffffffffb";
+
+begin
+    random_osc : process(all)
+    begin
+        -- chaotic set of ring oscillators
+        ringosc(0) <= ringosc(63) xor ringosc(0) xor ringosc(1);
+        for i in 1 to 62 loop
+            ringosc(i) <= ringosc(i-1) xor ringosc(i) xor ringosc(i+1);
+        end loop;
+        ringosc(63) <= not (ringosc(62) xor ringosc(63) xor ringosc(0));
+    end process;
+
+    lhca_update : process(clk)
+    begin
+        if rising_edge(clk) then
+            ro_reg <= ringosc;
+            raw <= ro_reg;
+            -- linear hybrid cellular automaton
+            -- used to even out the statistics of the ring oscillators
+            lhca <= ('0' & lhca(63 downto 1)) xor (lhca and lhca_diag) xor
+                    (lhca(62 downto 0) & '0') xor ro_reg;
+        end if;
+    end process;
+
+    data <= lhca;
+    err <= '0';
+end behaviour;
diff --git a/fpga/fpga-random.xdc b/fpga/fpga-random.xdc
new file mode 100644 (file)
index 0000000..ba69f87
--- /dev/null
@@ -0,0 +1,3 @@
+set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets soc0/processor/execute1_0/random_0/ro_reg*]
+set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets soc0/processor/execute1_0/random_0/p_*]
+set_property ALLOW_COMBINATORIAL_LOOPS TRUE [get_nets soc0/processor/execute1_0/random_0/D*]
index 15786fe800d9593b683f822591db42565945f9b4..9c9162024e4a4ca1ae129d6f8e7687968c265aa3 100644 (file)
@@ -64,6 +64,8 @@ filesets:
   xilinx_specific:
     files:
       - xilinx-mult.vhdl : {file_type : vhdlSource-2008}
+      - fpga/fpga-random.vhdl : {file_type : vhdlSource-2008}
+      - fpga/fpga-random.xdc : {file_type : xdc}
 
   debug_xilinx:
     files:
diff --git a/nonrandom.vhdl b/nonrandom.vhdl
new file mode 100644 (file)
index 0000000..16f81da
--- /dev/null
@@ -0,0 +1,22 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+
+entity random is
+    port (
+        clk  : in std_ulogic;
+        data : out std_ulogic_vector(63 downto 0);
+        raw  : out std_ulogic_vector(63 downto 0);
+        err  : out std_ulogic
+        );
+end entity random;
+
+architecture behaviour of random is
+
+begin
+    data <= (others => '1');
+    raw <= (others => '1');
+    err <= '1';
+end behaviour;
diff --git a/random.vhdl b/random.vhdl
new file mode 100644 (file)
index 0000000..063c30e
--- /dev/null
@@ -0,0 +1,30 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+library work;
+use work.glibc_random.all;
+
+entity random is
+    port (
+        clk  : in std_ulogic;
+        data : out std_ulogic_vector(63 downto 0);
+        raw  : out std_ulogic_vector(63 downto 0);
+        err  : out std_ulogic
+        );
+end entity random;
+
+architecture behaviour of random is
+begin
+    err <= '0';
+
+    process(clk)
+        variable rand : std_ulogic_vector(63 downto 0);
+    begin
+        if rising_edge(clk) then
+            rand := pseudorand(64);
+            data <= rand;
+            raw <= rand;
+        end if;
+    end process;
+end behaviour;