Browse Source

Add uart_trng design

main
T. Meissner 1 year ago
parent
commit
0df7a047be
13 changed files with 1046 additions and 1 deletions
  1. +4
    -0
      README.md
  2. +1
    -1
      uart_loop/syn/tb_uart_loop.v
  3. +53
    -0
      uart_trng/rtl/firo.vhd
  4. +189
    -0
      uart_trng/rtl/firo_ctrl.vhd
  5. +137
    -0
      uart_trng/rtl/uart_trng.vhd
  6. +102
    -0
      uart_trng/rtl/uart_tx.vhd
  7. +30
    -0
      uart_trng/sim/Makefile
  8. +80
    -0
      uart_trng/sim/tb_uart_trng.vhd
  9. +7
    -0
      uart_trng/sw/Makefile
  10. +252
    -0
      uart_trng/sw/uart_trng.c
  11. +51
    -0
      uart_trng/syn/Makefile
  12. +125
    -0
      uart_trng/syn/tb_uart_trng.v
  13. +15
    -0
      uart_trng/syn/uart_trng.ccf

+ 4
- 0
README.md View File

@ -24,6 +24,10 @@ Register file which can be accessed through UART. It uses *CC_PLL* & *CC_CFG_END
In case of a write command, the payload has to follow with the next byte. In case of a read command, the value of the addressed register is returned on the axis out port. Register at address 0 is special. It contains the version and is read-only. Writes to that register are ignored.
### uart_trng
An implementation of a TRNG which allows to read random data from the FPGA via UART. Inclusive a software tool for easy access. Random generation is based on a fibonacci ring oscillator (FiRo) with toggle flip-flop and von Neumann post-processing.
## Further Ressources
* [GateMate FPGA](https://www.colognechip.com/programmable-logic/gatemate)


+ 1
- 1
uart_loop/syn/tb_uart_loop.v View File

@ -96,7 +96,7 @@ module tb_uart_loop;
end
uart_rx = 1'b1;
#uart_bit_period;
#uart_bit_period
#uart_bit_period;
#uart_bit_period;
end
end


+ 53
- 0
uart_trng/rtl/firo.vhd View File

@ -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;

+ 189
- 0
uart_trng/rtl/firo_ctrl.vhd View File

@ -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;

+ 137
- 0
uart_trng/rtl/uart_trng.vhd View File

@ -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;

+ 102
- 0
uart_trng/rtl/uart_tx.vhd View File

@ -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;

+ 30
- 0
uart_trng/sim/Makefile View File

@ -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/

+ 80
- 0
uart_trng/sim/tb_uart_trng.vhd View File

@ -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;

+ 7
- 0
uart_trng/sw/Makefile View File

@ -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

+ 252
- 0
uart_trng/sw/uart_trng.c View File

@ -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;
}

+ 51
- 0
uart_trng/syn/Makefile View File

@ -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

+ 125
- 0
uart_trng/syn/tb_uart_trng.v View File

@ -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

+ 15
- 0
uart_trng/syn/uart_trng.ccf View File

@ -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";

Loading…
Cancel
Save