| @ -0,0 +1,53 @@ | |||
| library ieee; | |||
| use ieee.std_logic_1164.all; | |||
| use ieee.numeric_std.all; | |||
| entity firo is | |||
| generic ( | |||
| TOGGLE : boolean := true | |||
| ); | |||
| port ( | |||
| frun_i : in std_logic; | |||
| fdata_o : out std_logic | |||
| ); | |||
| end entity firo; | |||
| architecture rtl of firo is | |||
| -- signal for inverter loop | |||
| signal s_ring : std_logic_vector(15 downto 0); | |||
| signal s_tff : std_logic; | |||
| -- attributes for synplify synthesis tool to preserve inverter loop | |||
| attribute syn_keep : boolean; | |||
| attribute syn_hier : string; | |||
| attribute syn_hier of rtl : architecture is "hard"; | |||
| attribute syn_keep of s_ring : signal is true; | |||
| attribute syn_keep of s_tff : signal is true; | |||
| begin | |||
| firoring : for index in 1 to 15 generate | |||
| s_ring(index) <= not(s_ring(index - 1)); | |||
| end generate; | |||
| s_ring(0) <= (s_ring(15) xor s_ring(14) xor s_ring(7) xor s_ring(6) xor s_ring(5) xor s_ring(4) xor s_ring(2)) and frun_i; | |||
| with_toggle : if TOGGLE generate | |||
| tffP : process(frun_i, s_ring(15)) is | |||
| begin | |||
| if (not frun_i) then | |||
| s_tff <= '0'; | |||
| elsif (rising_edge(s_ring(15))) then | |||
| s_tff <= not s_tff; | |||
| end if; | |||
| end process tffP; | |||
| fdata_o <= s_ring(15) xor s_tff; | |||
| else generate | |||
| fdata_o <= s_ring(15); | |||
| end generate; | |||
| end architecture rtl; | |||
| @ -0,0 +1,189 @@ | |||
| library ieee; | |||
| use ieee.std_logic_1164.all; | |||
| use ieee.numeric_std.all; | |||
| entity firo_ctrl is | |||
| generic ( | |||
| EXTRACT : boolean := true | |||
| ); | |||
| port ( | |||
| -- system | |||
| clk_i : in std_logic; | |||
| rst_n_i : in std_logic; | |||
| -- axis in | |||
| tvalid_i : in std_logic; | |||
| tready_o : out std_logic; | |||
| -- axis out | |||
| tdata_o : out std_logic_vector(7 downto 0); | |||
| tvalid_o : out std_logic; | |||
| tready_i : in std_logic; | |||
| -- firo | |||
| frun_o : out std_logic; | |||
| fdata_i : in std_logic | |||
| ); | |||
| end entity firo_ctrl; | |||
| architecture rtl of firo_ctrl is | |||
| signal s_clk_counter : unsigned(4 downto 0); | |||
| signal s_run : std_logic; | |||
| signal s_firo_valid : std_logic; | |||
| type t_neumann_state is (BIT1, BIT2, BIT3, BIT4); | |||
| signal s_neumann_state : t_neumann_state; | |||
| signal s_neumann_buffer : std_logic_vector(2 downto 0); | |||
| type t_register_state is (SLEEP, COLLECT, VALID); | |||
| signal s_register_state : t_register_state; | |||
| signal s_register_enable : std_logic; | |||
| signal s_register_din : std_logic_vector(1 downto 0); | |||
| signal s_register_data : std_logic_vector(8 downto 0); | |||
| signal s_register_counter : unsigned(2 downto 0); | |||
| signal s_register_length : natural range 1 to 2; | |||
| signal s_data : std_logic_vector(3 downto 0); | |||
| begin | |||
| frun_o <= s_run when s_register_state = COLLECT else '0'; | |||
| s_data <= s_neumann_buffer & fdata_i; | |||
| ControllerP : process (clk_i) is | |||
| begin | |||
| if (rising_edge(clk_i)) then | |||
| if (s_register_state = SLEEP) then | |||
| s_clk_counter <= (others => '1'); | |||
| s_run <= '0'; | |||
| s_firo_valid <= '0'; | |||
| else | |||
| s_clk_counter <= s_clk_counter - 1; | |||
| s_firo_valid <= '0'; | |||
| if (s_clk_counter = 23 and s_run = '0') then | |||
| s_run <= '1'; | |||
| s_clk_counter <= (others => '1'); | |||
| end if; | |||
| if (s_clk_counter = 12 and s_run = '1') then | |||
| s_run <= '0'; | |||
| s_clk_counter <= (others => '1'); | |||
| end if; | |||
| if (s_clk_counter = 13 and s_run = '1') then | |||
| s_firo_valid <= '1'; | |||
| end if; | |||
| end if; | |||
| end if; | |||
| end process ControllerP; | |||
| VON_NEUMANN : if EXTRACT generate | |||
| process (clk_i, rst_n_i) is | |||
| begin | |||
| if (not rst_n_i) then | |||
| s_neumann_state <= BIT1; | |||
| s_register_enable <= '0'; | |||
| s_register_din <= "00"; | |||
| elsif (rising_edge(clk_i)) then | |||
| case s_neumann_state is | |||
| when BIT1 => | |||
| s_register_enable <= '0'; | |||
| if (s_firo_valid) then | |||
| s_neumann_buffer(2) <= fdata_i; | |||
| s_neumann_state <= BIT2; | |||
| end if; | |||
| when BIT2 => | |||
| if (s_firo_valid) then | |||
| s_neumann_buffer(1) <= fdata_i; | |||
| s_neumann_state <= BIT3; | |||
| end if; | |||
| when BIT3 => | |||
| if (s_firo_valid) then | |||
| s_neumann_buffer(0) <= fdata_i; | |||
| s_neumann_state <= BIT4; | |||
| end if; | |||
| when BIT4 => | |||
| if (s_firo_valid) then | |||
| s_register_enable <= '1'; | |||
| s_register_length <= 1; | |||
| s_register_din <= "00"; | |||
| s_neumann_state <= BIT1; | |||
| case (s_data) is | |||
| when x"5" => | |||
| s_register_din <= "01"; | |||
| when x"1" | x"6" | x"7" => | |||
| s_register_length <= 2; | |||
| when x"2" | x"9" | x"b" => | |||
| s_register_din <= "01"; | |||
| s_register_length <= 2; | |||
| when x"4" | x"a" | x"d" => | |||
| s_register_din <= "10"; | |||
| s_register_length <= 2; | |||
| when x"8" | x"c" | x"e" => | |||
| s_register_din <= "11"; | |||
| s_register_length <= 2; | |||
| when x"0" | x"f" => | |||
| s_register_enable <= '0'; | |||
| when others => -- incl. x"3" | |||
| null; | |||
| end case; | |||
| end if; | |||
| when others => | |||
| null; | |||
| end case; | |||
| end if; | |||
| end process; | |||
| else generate | |||
| s_register_enable <= s_firo_valid; | |||
| s_register_din(0) <= fdata_i; | |||
| s_register_length <= 1; | |||
| end generate; | |||
| ShiftRegisterP : process (clk_i, rst_n_i) is | |||
| begin | |||
| if (not rst_n_i) then | |||
| s_register_counter <= (others => '1'); | |||
| s_register_state <= SLEEP; | |||
| elsif (rising_edge(clk_i)) then | |||
| case s_register_state is | |||
| when SLEEP => | |||
| if (tvalid_i) then | |||
| s_register_state <= COLLECT; | |||
| s_register_data(0) <= s_register_data(8); | |||
| end if; | |||
| when COLLECT => | |||
| if (s_register_enable) then | |||
| if (s_register_counter = 0) then | |||
| s_register_data <= s_register_din(1) & s_register_data(6 downto 0) & s_register_din(0); | |||
| s_register_state <= VALID; | |||
| elsif (s_register_counter = 1) then | |||
| if (s_register_length = 1) then | |||
| s_register_data(7 downto 0) <= s_register_data(6 downto 0) & s_register_din(0); | |||
| end if; | |||
| if (s_register_length = 2) then | |||
| s_register_data(7 downto 0) <= s_register_data(5 downto 0) & s_register_din; | |||
| s_register_state <= VALID; | |||
| end if; | |||
| else | |||
| if (s_register_length = 1) then | |||
| s_register_data(7 downto 0) <= s_register_data(6 downto 0) & s_register_din(0); | |||
| else | |||
| s_register_data(7 downto 0) <= s_register_data(5 downto 0) & s_register_din; | |||
| end if; | |||
| end if; | |||
| s_register_counter <= s_register_counter - s_register_length; | |||
| end if; | |||
| when VALID => | |||
| if (tready_i) then | |||
| s_register_state <= SLEEP; | |||
| end if; | |||
| when others => | |||
| null; | |||
| end case; | |||
| end if; | |||
| end process ShiftRegisterP; | |||
| tready_o <= '1' when s_register_state = SLEEP else '0'; | |||
| tvalid_o <= '1' when s_register_state = VALID else '0'; | |||
| tdata_o <= s_register_data(7 downto 0); | |||
| end architecture rtl; | |||
| @ -0,0 +1,137 @@ | |||
| -- This design implements a register file which can | |||
| -- be accessed by an UART with 9600 baud | |||
| -- | |||
| -- See into uart_ctrl.vhd for documentation of the protocol | |||
| -- used to read / write the register file. | |||
| library ieee ; | |||
| use ieee.std_logic_1164.all; | |||
| use ieee.numeric_std.all; | |||
| use ieee.math_real.all; | |||
| library gatemate; | |||
| use gatemate.components.all; | |||
| entity uart_trng is | |||
| generic ( | |||
| SIM : natural := 0 | |||
| ); | |||
| port ( | |||
| clk_i : in std_logic; -- 10 MHz clock | |||
| rst_n_i : in std_logic; -- SW3 button | |||
| uart_tx_o : out std_logic -- PMODA IO5 | |||
| ); | |||
| end entity uart_trng; | |||
| architecture rtl of uart_trng is | |||
| signal s_pll_clk : std_logic; | |||
| signal s_pll_lock : std_logic; | |||
| signal s_rst_n : std_logic; | |||
| signal s_cfg_end : std_logic; | |||
| signal s_uart_tx_tdata : std_logic_vector(7 downto 0); | |||
| signal s_uart_tx_tvalid : std_logic; | |||
| signal s_uart_tx_tready : std_logic; | |||
| signal s_firo_run : std_logic; | |||
| signal s_firo_data : std_logic; | |||
| begin | |||
| pll : CC_PLL | |||
| generic map ( | |||
| REF_CLK => "10", | |||
| OUT_CLK => "10", | |||
| PERF_MD => "ECONOMY" | |||
| ) | |||
| port map ( | |||
| CLK_REF => clk_i, | |||
| CLK_FEEDBACK => '0', | |||
| USR_CLK_REF => '0', | |||
| USR_LOCKED_STDY_RST => '0', | |||
| USR_PLL_LOCKED_STDY => open, | |||
| USR_PLL_LOCKED => s_pll_lock, | |||
| CLK270 => open, | |||
| CLK180 => open, | |||
| CLK0 => s_pll_clk, | |||
| CLK90 => open, | |||
| CLK_REF_OUT => open | |||
| ); | |||
| cfg_end_inst : CC_CFG_END | |||
| port map ( | |||
| CFG_END => s_cfg_end | |||
| ); | |||
| firo_ctrl : entity work.firo_ctrl | |||
| generic map ( | |||
| EXTRACT => true | |||
| ) | |||
| port map ( | |||
| -- system | |||
| rst_n_i => s_rst_n, | |||
| clk_i => s_pll_clk, | |||
| -- axis in | |||
| tvalid_i => '1', | |||
| tready_o => open, | |||
| -- axis out | |||
| tdata_o => s_uart_tx_tdata, | |||
| tvalid_o => s_uart_tx_tvalid, | |||
| tready_i => s_uart_tx_tready, | |||
| -- firo | |||
| frun_o => s_firo_run, | |||
| fdata_i => s_firo_data | |||
| ); | |||
| SIMULATION : if (SIM /= 0) generate | |||
| -- simple random bit generator | |||
| RandomGenP : process (s_pll_clk, s_firo_run) is | |||
| variable v_seed1, v_seed2 : positive := 1; | |||
| variable v_real_rand : real; | |||
| begin | |||
| if (not s_firo_run) then | |||
| s_firo_data <= '0'; | |||
| elsif (s_pll_clk'event) then | |||
| uniform(v_seed1, v_seed2, v_real_rand); | |||
| if (v_real_rand < 0.5) then | |||
| s_firo_data <= '0'; | |||
| else | |||
| s_firo_data <= '1'; | |||
| end if; | |||
| end if; | |||
| end process RandomGenP; | |||
| else generate | |||
| firo : entity work.firo | |||
| generic map ( | |||
| TOGGLE => true | |||
| ) | |||
| port map ( | |||
| frun_i => s_firo_run, | |||
| fdata_o => s_firo_data | |||
| ); | |||
| end generate; | |||
| uart_tx : entity work.uart_tx | |||
| generic map ( | |||
| CLK_DIV => 1040 | |||
| ) | |||
| port map ( | |||
| -- globals | |||
| rst_n_i => s_rst_n, | |||
| clk_i => s_pll_clk, | |||
| -- axis user interface | |||
| tdata_i => s_uart_tx_tdata, | |||
| tvalid_i => s_uart_tx_tvalid, | |||
| tready_o => s_uart_tx_tready, | |||
| -- uart interface | |||
| tx_o => uart_tx_o | |||
| ); | |||
| s_rst_n <= rst_n_i and s_pll_lock and s_cfg_end; | |||
| end architecture; | |||
| @ -0,0 +1,102 @@ | |||
| -- Copyright (c) 2022 by Torsten Meissner | |||
| -- | |||
| -- Licensed under the Apache License, Version 2.0 (the "License"); | |||
| -- you may not use this file except in compliance with the License. | |||
| -- You may obtain a copy of the License at | |||
| -- | |||
| -- https://www.apache.org/licenses/LICENSE-2.0 | |||
| -- | |||
| -- Unless required by applicable law or agreed to in writing, software | |||
| -- distributed under the License is distributed on an "AS IS" BASIS, | |||
| -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| -- See the License for the specific language governing permissions and | |||
| -- limitations under the License. | |||
| library ieee; | |||
| use ieee.std_logic_1164.all; | |||
| use ieee.numeric_std.all; | |||
| entity uart_tx is | |||
| generic ( | |||
| CLK_DIV : natural := 10 | |||
| ); | |||
| port ( | |||
| -- globals | |||
| rst_n_i : in std_logic; | |||
| clk_i : in std_logic; | |||
| -- axis user interface | |||
| tdata_i : in std_logic_vector(7 downto 0); | |||
| tvalid_i : in std_logic; | |||
| tready_o : out std_logic; | |||
| -- uart interface | |||
| tx_o : out std_logic | |||
| ); | |||
| end entity uart_tx; | |||
| architecture rtl of uart_tx is | |||
| type t_uart_state is (IDLE, SEND); | |||
| signal s_uart_state : t_uart_state; | |||
| signal s_data : std_logic_vector(tdata_i'length+1 downto 0); | |||
| signal s_clk_cnt : natural range 0 to CLK_DIV-1; | |||
| signal s_clk_en : std_logic; | |||
| signal s_bit_cnt : natural range 0 to s_data'length-1; | |||
| begin | |||
| ClkDivP : process (clk_i, rst_n_i) is | |||
| begin | |||
| if (not rst_n_i) then | |||
| s_clk_cnt <= CLK_DIV-1; | |||
| elsif (rising_edge(clk_i)) then | |||
| if (s_uart_state = IDLE) then | |||
| s_clk_cnt <= CLK_DIV-2; | |||
| elsif (s_uart_state = SEND) then | |||
| if (s_clk_cnt = 0) then | |||
| s_clk_cnt <= CLK_DIV-1; | |||
| else | |||
| s_clk_cnt <= s_clk_cnt - 1; | |||
| end if; | |||
| end if; | |||
| end if; | |||
| end process ClkDivP; | |||
| s_clk_en <= '1' when s_uart_state = SEND and s_clk_cnt = 0 else '0'; | |||
| TxP : process (clk_i, rst_n_i) is | |||
| begin | |||
| if (not rst_n_i) then | |||
| s_uart_state <= IDLE; | |||
| s_data <= (0 => '1', others => '0'); | |||
| s_bit_cnt <= 0; | |||
| elsif (rising_edge(clk_i)) then | |||
| FsmL : case s_uart_state is | |||
| when IDLE => | |||
| s_bit_cnt <= s_data'length-1; | |||
| if (tvalid_i) then | |||
| s_data <= '1' & tdata_i & '0'; | |||
| s_uart_state <= SEND; | |||
| end if; | |||
| when SEND => | |||
| if (s_clk_en) then | |||
| s_data <= '1' & s_data(s_data'length-1 downto 1); | |||
| if (s_bit_cnt = 0) then | |||
| s_uart_state <= IDLE; | |||
| else | |||
| s_bit_cnt <= s_bit_cnt - 1; | |||
| end if; | |||
| end if; | |||
| end case; | |||
| end if; | |||
| end process TxP; | |||
| tready_o <= '1' when s_uart_state = IDLE else '0'; | |||
| tx_o <= s_data(0); | |||
| end architecture rtl; | |||
| @ -0,0 +1,30 @@ | |||
| DESIGN_NAME := uart_trng | |||
| LIB_SRC := ../../lib/rtl_components.vhd ../../lib/sim_components.vhd | |||
| RTL_SRC := ../rtl/uart_tx.vhd ../rtl/firo.vhd ../rtl/firo_ctrl.vhd ../rtl/${DESIGN_NAME}.vhd | |||
| SIM_SRC := tb_${DESIGN_NAME}.vhd | |||
| SIM_FLAGS := --std=08 -fpsl --workdir=work | |||
| .PHONY: all compile sim clean | |||
| all: sim | |||
| compile: tb_${DESIGN_NAME} | |||
| tb_${DESIGN_NAME}: ${LIB_SRC} ${RTL_SRC} ${SIM_SRC} | |||
| mkdir -p work | |||
| @echo "Analyze gatemate library ..." | |||
| ghdl -a ${SIM_FLAGS} --work=gatemate ${LIB_SRC} | |||
| @echo "Analyze testbench & design ..." | |||
| ghdl -a ${SIM_FLAGS} -Pwork ${RTL_SRC} ${SIM_SRC} | |||
| @echo "Elaborate testbench & design ..." | |||
| ghdl -e ${SIM_FLAGS} -Pwork $@ | |||
| sim: tb_${DESIGN_NAME} | |||
| @echo "Run testbench ..." | |||
| ghdl -r ${SIM_FLAGS} -Pwork tb_${DESIGN_NAME} --assert-level=error --wave=tb_${DESIGN_NAME}.ghw | |||
| work: | |||
| mkdir $@ | |||
| clean: | |||
| @echo "Cleaning simulation files ..." | |||
| rm -rf tb_${DESIGN_NAME} tb_${DESIGN_NAME}.ghw *.o work/ | |||
| @ -0,0 +1,80 @@ | |||
| library ieee ; | |||
| use ieee.std_logic_1164.all; | |||
| use ieee.numeric_std.all; | |||
| use std.env.all; | |||
| entity tb_uart_trng is | |||
| end entity tb_uart_trng; | |||
| architecture sim of tb_uart_trng is | |||
| signal s_clk : std_logic := '1'; | |||
| signal s_rst_n : std_logic := '0'; | |||
| signal s_uart_tx : std_logic; | |||
| constant c_baudrate : natural := 9600; | |||
| constant c_period_ns : time := 1000000000 / c_baudrate * ns; | |||
| procedure uart_send ( data : in std_logic_vector(7 downto 0); | |||
| signal tx : out std_logic) is | |||
| begin | |||
| report "UART send: 0x" & to_hstring(data); | |||
| tx <= '0'; | |||
| wait for c_period_ns; | |||
| for i in 0 to 7 loop | |||
| tx <= data(i); | |||
| wait for c_period_ns; | |||
| end loop; | |||
| tx <= '1'; | |||
| wait for c_period_ns; | |||
| end procedure; | |||
| procedure uart_recv ( data : out std_logic_vector(7 downto 0); | |||
| signal rx : in std_logic) is | |||
| begin | |||
| wait until not rx; | |||
| wait for c_period_ns; -- Skip start bit | |||
| wait for c_period_ns/2; | |||
| for i in 0 to 7 loop | |||
| data(i) := rx; | |||
| wait for c_period_ns; | |||
| end loop; | |||
| report "UART recv: 0x" & to_hstring(data); | |||
| end procedure; | |||
| begin | |||
| dut : entity work.uart_trng | |||
| generic map ( | |||
| SIM => 1 | |||
| ) | |||
| port map ( | |||
| clk_i => s_clk, | |||
| rst_n_i => s_rst_n, | |||
| uart_tx_o => s_uart_tx | |||
| ); | |||
| s_rst_n <= '1' after 120 ns; | |||
| s_clk <= not s_clk after 50 ns; | |||
| ReceiveP : process is | |||
| type t_exp is array (0 to 7) of std_logic_vector(7 downto 0); | |||
| variable v_exp : t_exp; | |||
| variable v_data : std_logic_vector(7 downto 0); | |||
| begin | |||
| wait until s_rst_n; | |||
| wait until rising_edge(s_clk); | |||
| -- First read all registers | |||
| for i in 0 to 7 loop | |||
| uart_recv(v_data, s_uart_tx); | |||
| end loop; | |||
| wait for 200 us; | |||
| report "Simulation finished :-)"; | |||
| stop(0); | |||
| end process; | |||
| end architecture; | |||
| @ -0,0 +1,7 @@ | |||
| all: uart_trng | |||
| uart_trng: uart_trng.c | |||
| gcc -Wall uart_trng.c -o uart_trng | |||
| clean: | |||
| rm -rf uart_trng | |||
| @ -0,0 +1,252 @@ | |||
| #include <stdio.h> /* Standard input/output definitions */ | |||
| #include <stdlib.h> | |||
| #include <stdint.h> /* Standard types */ | |||
| #include <string.h> /* String function definitions */ | |||
| #include <unistd.h> /* UNIX standard function definitions */ | |||
| #include <fcntl.h> /* File control definitions */ | |||
| #include <errno.h> /* Error number definitions */ | |||
| #include <termios.h> /* POSIX terminal control definitions */ | |||
| #include <sys/ioctl.h> | |||
| #ifdef __APPLE__ | |||
| // define 460k baud rate, seems not to be available in headers on osx | |||
| #define B460800 460800 | |||
| #endif | |||
| void help(void); | |||
| int serialport_init(const char* serialport, unsigned int baud); | |||
| int serialport_read_until(int fd, unsigned int until); | |||
| // Checks for an argument (characters with a leading '-') | |||
| // Returns 0 if argument does not exist or the index of argument | |||
| // type in the argv[] array | |||
| int parArgTypExists (int argc, char *argv[], char argType) | |||
| { | |||
| char tmp[3]; | |||
| tmp[0] = '-'; | |||
| tmp[1] = argType; | |||
| tmp[2] = 0; | |||
| if (argc > 1) { | |||
| for (int i = 1; i < argc; i++) { | |||
| if (!strcmp (argv[i], tmp)) | |||
| return i; | |||
| } | |||
| } | |||
| return 0; | |||
| } | |||
| // Get string argument value | |||
| // Returns 0 in error case, returns 1 if OK | |||
| // (string is limited to max. 4096 characters) | |||
| int parGetString (int argc, char *argv[], char argType, char *value) | |||
| { | |||
| int a = parArgTypExists(argc, argv, argType); | |||
| // Check for errors | |||
| if (a == 0) return 0; | |||
| if (a >= (argc -1)) return 0; | |||
| if (strlen(argv[a+1]) > 256) return 0; | |||
| strcpy(value, argv[a+1]); | |||
| return 1; | |||
| } | |||
| // Get unsigned int argument value | |||
| // Returns 0 in error case, 1 if OK | |||
| int parGetUnsignedInt (int argc, char *argv[], char argType, | |||
| unsigned int *value) | |||
| { | |||
| int a = parArgTypExists (argc, argv, argType); | |||
| /* error checking */ | |||
| if (a == 0) return 0; | |||
| if (a >= (argc -1)) return 0; | |||
| a = sscanf(argv[a+1], "%iu", value); | |||
| return a; | |||
| } | |||
| void help(void) { | |||
| printf("Usage: uart_trng -p <serialport> [OPTIONS]\n" | |||
| "\n" | |||
| "Options:\n" | |||
| " -h, --help Print this help message\n" | |||
| " -p, --port=serialport Serial port where the uart_trng device is plugged on\n" | |||
| " -b, --baud=baudrate Baudrate (bps) of uart_trng device, default = 9600\n" | |||
| " -s, --size number of bytes to receive from uart_trng device,\n" | |||
| " 0 for reading until break with Ctrl-c, default = 1024\n" | |||
| "\n"); | |||
| } | |||
| int main(int argc, char *argv[]) | |||
| { | |||
| int fd = 0; | |||
| int r = 0; | |||
| char serialport[256]; | |||
| unsigned int baudrate = 9600; | |||
| unsigned int size = 1024; | |||
| // check for command line arguments | |||
| if (argc == 1) { | |||
| help(); | |||
| return 1; | |||
| } | |||
| else { | |||
| if (parArgTypExists (argc, argv, 'h')) { | |||
| help(); | |||
| return 1; | |||
| } | |||
| // get serial port | |||
| if (parArgTypExists (argc, argv, 'p')) { | |||
| r = parGetString (argc, argv, 'p', serialport); | |||
| if (r == 0) { | |||
| return (1); | |||
| } | |||
| } else { | |||
| help(); | |||
| return (1); | |||
| } | |||
| // get baud rate | |||
| if (parArgTypExists (argc, argv, 'b')) { | |||
| r = parGetUnsignedInt (argc, argv, 'b', &baudrate); | |||
| if (r == 0) { | |||
| return (1); | |||
| } | |||
| } | |||
| // get read size in bytes | |||
| if (parArgTypExists (argc, argv, 's')) { | |||
| r = parGetUnsignedInt (argc, argv, 's', &size); | |||
| if (r == 0) { | |||
| return (1); | |||
| } | |||
| } | |||
| } | |||
| fd = serialport_init(serialport, baudrate); | |||
| if (fd == -1) | |||
| return -1; | |||
| serialport_read_until(fd, size); | |||
| exit(EXIT_SUCCESS); | |||
| } | |||
| int serialport_read_until(int fd, unsigned int until) | |||
| { | |||
| char b[1]; | |||
| int index = 0; | |||
| int n; | |||
| while (1) { | |||
| while (1) { | |||
| // read one char | |||
| n = read(fd, b, 1); | |||
| // we had a read error | |||
| // check if there were no bytes to read or if it was a real error | |||
| if (n == -1) { | |||
| if (errno != EAGAIN) { | |||
| fprintf(stderr,"serial read error at byte %d", index); | |||
| return -1; | |||
| } | |||
| } else { | |||
| break; | |||
| } | |||
| } | |||
| // we got no byte, so wait 10 ms for the next try | |||
| if (n == 0) { | |||
| usleep (10 * 1000); | |||
| continue; | |||
| } | |||
| printf("%c",b[0]); | |||
| if (until == 0) { | |||
| continue; | |||
| } else { | |||
| index++; | |||
| if (index == until) { | |||
| break; | |||
| } | |||
| } | |||
| }; | |||
| fprintf(stderr,"uart_trng: read %d random bytes from device\n", until); | |||
| return 0; | |||
| } | |||
| // takes the string name of the serial port (e.g. "/dev/tty.usbserial","COM1") | |||
| // and a baud rate (bps) and connects to that port at that speed and 8N1. | |||
| // opens the port in fully raw mode so you can send binary data. | |||
| // returns valid fd, or -1 on error | |||
| int serialport_init(const char* serialport, unsigned int baud) | |||
| { | |||
| struct termios toptions; | |||
| int fd; | |||
| fprintf(stderr,"init_serialport: opening port %s @ %u bps\n", | |||
| serialport, baud); | |||
| fd = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY); | |||
| if (fd == -1) { | |||
| perror("init_serialport: Unable to open port "); | |||
| return -1; | |||
| } | |||
| if (tcgetattr(fd, &toptions) < 0) { | |||
| perror("init_serialport: Couldn't get term attributes"); | |||
| return -1; | |||
| } | |||
| speed_t brate = baud; // let you override switch below if needed | |||
| switch(baud) { | |||
| case 4800: brate=B4800; break; | |||
| case 9600: brate=B9600; break; | |||
| #ifdef B14400 | |||
| case 14400: brate=B14400; break; | |||
| #endif | |||
| case 19200: brate=B19200; break; | |||
| #ifdef B28800 | |||
| case 28800: brate=B28800; break; | |||
| #endif | |||
| case 38400: brate=B38400; break; | |||
| case 57600: brate=B57600; break; | |||
| case 115200: brate=B115200; break; | |||
| case 230400: brate=B230400; break; | |||
| case 460800: brate=B460800; break; | |||
| } | |||
| cfsetispeed(&toptions, brate); | |||
| cfsetospeed(&toptions, brate); | |||
| // 8N1 | |||
| toptions.c_cflag &= ~PARENB; | |||
| toptions.c_cflag &= ~CSTOPB; | |||
| toptions.c_cflag &= ~CSIZE; | |||
| toptions.c_cflag |= CS8; | |||
| // no flow control | |||
| toptions.c_cflag &= ~CRTSCTS; | |||
| toptions.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines | |||
| toptions.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl | |||
| toptions.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw | |||
| toptions.c_oflag &= ~OPOST; // make raw | |||
| // see: http://unixwiz.net/techtips/termios-vmin-vtime.html | |||
| toptions.c_cc[VMIN] = 0; | |||
| toptions.c_cc[VTIME] = 20; | |||
| if( tcsetattr(fd, TCSANOW, &toptions) < 0) { | |||
| perror("init_serialport: Couldn't set term attributes"); | |||
| return -1; | |||
| } | |||
| return fd; | |||
| } | |||
| @ -0,0 +1,51 @@ | |||
| DESIGN_NAME := uart_trng | |||
| WORK_FILES := ../rtl/uart_tx.vhd ../rtl/firo.vhd ../rtl/firo_ctrl.vhd ../rtl/${DESIGN_NAME}.vhd | |||
| GM_FILES := ../../lib/rtl_components.vhd | |||
| GHDL_FLAGS := --std=08 --workdir=build -Pbuild | |||
| YOSYSPIPE := -nomx8 -retime | |||
| # ATTENTION: -luttree option seems to mis-synthesize the design, broken with synth_gatemate? | |||
| PNRFLAGS := -om 2 | |||
| PNRTOOL := $(shell which p_r) | |||
| .PHONY: all syn imp prog syn_sim imp_sim | |||
| all: imp | |||
| syn: ${DESIGN_NAME}.v | |||
| imp: ${DESIGN_NAME}.bit | |||
| build/work-obj08.cf: ${WORK_FILES} build/gatemate-obj08.cf | |||
| ghdl -a ${GHDL_FLAGS} --work=work ${WORK_FILES} | |||
| build/gatemate-obj08.cf: ${GM_FILES} | |||
| mkdir -p build | |||
| ghdl -a ${GHDL_FLAGS} --work=gatemate ${GM_FILES} | |||
| # Synthesis target for implementation | |||
| ${DESIGN_NAME}.v: build/work-obj08.cf | |||
| yosys -m ghdl -p 'ghdl ${GHDL_FLAGS} --warn-no-binding --no-formal ${DESIGN_NAME}; synth_gatemate -top $(DESIGN_NAME) ${YOSYSPIPE} -vlog $@' \ | |||
| 2>&1 | tee build/yosys-report.txt | |||
| # Implementation target for FPGA | |||
| ${DESIGN_NAME}.bit: ${DESIGN_NAME}.v ${DESIGN_NAME}.ccf | |||
| cd build && \ | |||
| ${PNRTOOL} -i ../${DESIGN_NAME}.v -o $@ --ccf ../${DESIGN_NAME}.ccf $(PNRFLAGS) \ | |||
| 2>&1 | tee p_r-report.txt && \ | |||
| mv ${DESIGN_NAME}*.bit ../$@ | |||
| # Post-synthesis simulation target | |||
| syn_sim: ${DESIGN_NAME}.v | |||
| iverilog -g2012 -o tb_${DESIGN_NAME}_syn.vvp ${DESIGN_NAME}.v tb_${DESIGN_NAME}.v /usr/local/share/yosys/gatemate/cells_sim.v | |||
| vvp -N tb_${DESIGN_NAME}_syn.vvp -fst | |||
| # Post-implementation simulation target | |||
| imp_sim: ${DESIGN_NAME}.bit | |||
| iverilog -g2012 -o tb_${DESIGN_NAME}_imp.vvp build/${DESIGN_NAME}_00.v tb_${DESIGN_NAME}.v /opt/cc-toolchain-linux/bin/p_r/cpelib.v | |||
| vvp -N tb_${DESIGN_NAME}_imp.vvp -fst | |||
| # FPGA FW load per JTAG | |||
| prog: ${DESIGN_NAME}.bit | |||
| openFPGALoader -b gatemate_evb_jtag $< | |||
| clean : | |||
| echo "# Cleaning files" | |||
| rm -rf build ${DESIGN_NAME}.v ${DESIGN_NAME}_sim.v ${DESIGN_NAME}.vhd ${DESIGN_NAME}.bit *.vvp *.fst | |||
| @ -0,0 +1,125 @@ | |||
| `timescale 1 ns/10 ps // time-unit = 1 ns, precision = 10 ps | |||
| // simplified CC_PLL model | |||
| module CC_PLL #( | |||
| parameter REF_CLK = "", // e.g. "10.0" | |||
| parameter OUT_CLK = "", // e.g. "50.0" | |||
| parameter PERF_MD = "", // LOWPOWER, ECONOMY, SPEED | |||
| parameter LOW_JITTER = 1, | |||
| parameter CI_FILTER_CONST = 2, | |||
| parameter CP_FILTER_CONST = 4 | |||
| )( | |||
| input CLK_REF, CLK_FEEDBACK, USR_CLK_REF, | |||
| input USR_LOCKED_STDY_RST, USR_SET_SEL, | |||
| output USR_PLL_LOCKED_STDY, USR_PLL_LOCKED, | |||
| output CLK270, CLK180, CLK90, CLK0, CLK_REF_OUT | |||
| ); | |||
| reg r_pll_clk; | |||
| reg r_user_pll_locked; | |||
| // OUT_FREQ = 1 MHz | |||
| integer clk_half_period = 50; | |||
| initial begin | |||
| r_pll_clk = 1'b0; | |||
| r_user_pll_locked = 1'b1; | |||
| end | |||
| always #clk_half_period r_pll_clk = ~r_pll_clk; | |||
| assign CLK0 = r_pll_clk; | |||
| assign USR_PLL_LOCKED = r_user_pll_locked; | |||
| endmodule | |||
| // simplified CC_CFG_END model | |||
| module CC_CFG_END ( | |||
| output CFG_END | |||
| ); | |||
| assign CFG_END = 1'b1; | |||
| endmodule | |||
| module tb_uart_reg; | |||
| // DUT in/out | |||
| reg clk = 1'b0; | |||
| reg rst_n = 1'b1; | |||
| reg uart_rx; | |||
| wire uart_tx; | |||
| // Testbench variables | |||
| reg [7:0] tx_data = 8'h0; | |||
| reg [7:0] rx_data = 8'h0; | |||
| // Testbench 1/2 clock period | |||
| localparam clk_half_period = 50; | |||
| // UART period calculation (9600 baud) | |||
| localparam uart_bit_period = 1000000000 / 9600; | |||
| localparam uart_bit_half_period = uart_bit_period/2; | |||
| uart_reg UUT (.clk_i(clk), .rst_n_i(rst_n), .uart_rx_i(uart_rx), .uart_tx_o(uart_tx)); | |||
| // set dumpfile | |||
| initial begin | |||
| $dumpfile ("tb_uart_reg.fst"); | |||
| $dumpvars (0, tb_uart_reg); | |||
| end | |||
| // Setup simulation | |||
| initial begin | |||
| uart_rx = 1'b1; | |||
| #1 rst_n = 1'b0; | |||
| #120 rst_n = 1'b1; | |||
| end | |||
| // Generate 10 mhz clock | |||
| always #clk_half_period clk = !clk; | |||
| // Stimuli generator | |||
| initial | |||
| forever @(posedge rst_n) begin | |||
| uart_rx = 1'b1; | |||
| #uart_bit_period; | |||
| for (integer tx = 0; tx < 32; tx = tx + 1) begin | |||
| tx_data = tx; | |||
| $display ("UART send: 0x%h", tx_data); | |||
| uart_rx = 1'b0; | |||
| #uart_bit_period; | |||
| for (integer i = 0; i < 7; i = i + 1) begin | |||
| uart_rx = tx_data[i]; | |||
| #uart_bit_period; | |||
| end | |||
| uart_rx = 1'b1; | |||
| #uart_bit_period; | |||
| #uart_bit_period | |||
| #uart_bit_period; | |||
| end | |||
| end | |||
| // Checker | |||
| initial begin | |||
| @(posedge rst_n) | |||
| for (reg [7:0] rx = 0; rx < 32; rx = rx + 1) begin | |||
| @(negedge uart_tx) | |||
| #uart_bit_period; | |||
| #uart_bit_half_period; | |||
| for (integer i = 0; i < 7; i = i + 1) begin | |||
| rx_data[i] = uart_tx; | |||
| #uart_bit_period; | |||
| end | |||
| assert (rx_data == rx) | |||
| $display("UART recv: 0x%h", rx_data); | |||
| else | |||
| $warning("UART receive error, got 0x%h, expected 0x%h", rx_data, rx); | |||
| end | |||
| $display ("UART tests finished"); | |||
| $finish; | |||
| end | |||
| endmodule | |||
| @ -0,0 +1,15 @@ | |||
| # Configuration for the Gatemate eval board | |||
| Pin_in "clk_i" Loc = "IO_SB_A8" | SCHMITT_TRIGGER=true; | |||
| Pin_in "rst_n_i" Loc = "IO_EB_B0"; # SW3 | |||
| Pin_out "uart_tx_o" Loc = "IO_NB_A0"; # PMODA IO1 | |||
| Pin_out "debug_o[0]" Loc = "IO_NB_A4"; | |||
| Pin_out "debug_o[1]" Loc = "IO_NB_A5"; | |||
| Pin_out "debug_o[2]" Loc = "IO_NB_A6"; | |||
| Pin_out "debug_o[3]" Loc = "IO_NB_A7"; | |||
| Pin_out "debug_o[4]" Loc = "IO_NB_B4"; | |||
| Pin_out "debug_o[5]" Loc = "IO_NB_B5"; | |||
| Pin_out "debug_o[6]" Loc = "IO_NB_B6"; | |||
| Pin_out "debug_o[7]" Loc = "IO_NB_B7"; | |||