Browse Source

Add uart_aes design, simulation & fpga-flow

main
T. Meissner 2 years ago
parent
commit
1777fbd742
16 changed files with 1437 additions and 0 deletions
  1. +155
    -0
      uart_aes/rtl/uart_aes.vhd
  2. +40
    -0
      uart_aes/rtl/uart_aes_types.vhd
  3. +209
    -0
      uart_aes/rtl/uart_ctrl.vhd
  4. +105
    -0
      uart_aes/rtl/uart_rx.vhd
  5. +102
    -0
      uart_aes/rtl/uart_tx.vhd
  6. +57
    -0
      uart_aes/sim/Makefile
  7. +13
    -0
      uart_aes/sim/tb_uart_aes.tcl
  8. +73
    -0
      uart_aes/sim/tb_uart_aes.vhd
  9. +164
    -0
      uart_aes/sim/uart_aes_ref.c
  10. +46
    -0
      uart_aes/sim/uart_aes_ref.vhd
  11. +125
    -0
      uart_aes/sim/uart_aes_sim.vhd
  12. +72
    -0
      uart_aes/syn/Makefile
  13. +16
    -0
      uart_aes/syn/read_data.txt
  14. +149
    -0
      uart_aes/syn/tb_uart_aes.v
  15. +21
    -0
      uart_aes/syn/uart_aes.ccf
  16. +90
    -0
      uart_aes/syn/write_cmds.txt

+ 155
- 0
uart_aes/rtl/uart_aes.vhd View File

@ -0,0 +1,155 @@
-- 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;
library gatemate;
use gatemate.components.all;
library cryptocores;
use work.uart_aes_types.all;
entity uart_aes is
port (
clk_i : in std_logic; -- 10 MHz clock
rst_n_i : in std_logic; -- SW3 button
uart_rx_i : in std_logic; -- PMODA IO3
uart_tx_o : out std_logic; -- PMODA IO5
led_n_o : out std_logic_vector(3 downto 0)
);
end entity uart_aes;
architecture rtl of uart_aes 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_rx_tdata : std_logic_vector(7 downto 0);
signal s_uart_rx_tvalid : std_logic;
signal s_uart_rx_tready : 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_ctrl_aes_m2s : t_axis_ctrl_aes_m2s;
signal s_ctrl_aes_s2m : t_axis_s2m;
signal s_aes_ctrl_m2s : t_axis_aes_ctrl_m2s;
signal s_aes_ctrl_s2m : t_axis_s2m;
begin
pll : CC_PLL
generic map (
REF_CLK => "10",
OUT_CLK => "10",
PERF_MD => "SPEED"
)
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
);
uart_rx : entity work.uart_rx
generic map (
CLK_DIV => 1040
)
port map (
-- globals
rst_n_i => s_rst_n,
clk_i => s_pll_clk,
-- axis user interface
tdata_o => s_uart_rx_tdata,
tvalid_o => s_uart_rx_tvalid,
tready_i => s_uart_rx_tready,
-- uart interface
rx_i => uart_rx_i
);
uart_ctrl : entity work.uart_ctrl
port map (
-- globals
rst_n_i => s_rst_n,
clk_i => s_pll_clk,
-- uart rx interface
tdata_i => s_uart_rx_tdata,
tvalid_i => s_uart_rx_tvalid,
tready_o => s_uart_rx_tready,
-- uart tx interface
tdata_o => s_uart_tx_tdata,
tvalid_o => s_uart_tx_tvalid,
tready_i => s_uart_tx_tready,
-- aes out
ctrl_aes_o => s_ctrl_aes_m2s,
ctrl_aes_i => s_ctrl_aes_s2m,
-- aes in
aes_ctrl_i => s_aes_ctrl_m2s,
aes_ctrl_o => s_aes_ctrl_s2m
);
aes_inst : entity cryptocores.ctraes
port map (
reset_i => s_rst_n,
clk_i => s_pll_clk,
start_i => s_ctrl_aes_m2s.tuser.start,
nonce_i => s_ctrl_aes_m2s.tuser.nonce,
key_i => s_ctrl_aes_m2s.tuser.key,
data_i => s_ctrl_aes_m2s.tdata,
valid_i => s_ctrl_aes_m2s.tvalid,
accept_o => s_ctrl_aes_s2m.tready,
data_o => s_aes_ctrl_m2s.tdata,
valid_o => s_aes_ctrl_m2s.tvalid,
accept_i => s_aes_ctrl_s2m.tready
);
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;
-- Lets some LEDs blink
led_n_o(0) <= rst_n_i; -- reset button
led_n_o(1) <= s_uart_rx_tready and s_uart_tx_tvalid; -- uart ctrl ready
led_n_o(2) <= not s_uart_rx_tready; -- uart received
led_n_o(3) <= not s_uart_tx_tvalid; -- uart send
end architecture;

+ 40
- 0
uart_aes/rtl/uart_aes_types.vhd View File

@ -0,0 +1,40 @@
library ieee;
use ieee.std_logic_1164.all;
package uart_aes_types is
type t_axis_ctrl_aes_tuser is record
start : std_logic;
key : std_logic_vector(0 to 127);
nonce : std_logic_vector(0 to 95);
end record;
type t_axis_ctrl_aes_m2s is record
tuser : t_axis_ctrl_aes_tuser;
tdata : std_logic_vector(0 to 127);
tvalid : std_logic;
end record;
type t_axis_m2s is record
tdata : std_logic_vector(0 to 127);
tvalid : std_logic;
end record;
alias t_axis_aes_ctrl_m2s is t_axis_m2s;
type t_axis_s2m is record
tready : std_logic;
end record;
-- No dout reg necessary, as we simply use AES tdata output
type t_reg_file is record
ctrl : std_logic_vector(7 downto 0);
key : std_logic_vector(0 to 127);
nonce : std_logic_vector(0 to 95);
din : std_logic_vector(0 to 127);
end record;
constant c_reg_file_init : t_reg_file := (8x"0", 128x"0", 96x"0", 128x"0");
end package;

+ 209
- 0
uart_aes/rtl/uart_ctrl.vhd View File

@ -0,0 +1,209 @@
-- UART register
-- Register file with 8 registers storing values of one byte each.
--
-- The first received byte on the axis in port contains command & address:
--
-- 7 reserved
-- 6:4 register address
-- 3:0 command
-- 0x0 read
-- 0x1 write
--
-- 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.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.uart_aes_types.all;
entity uart_ctrl is
port (
-- globals
rst_n_i : in std_logic;
clk_i : in std_logic;
-- axis in
tdata_i : in std_logic_vector(7 downto 0);
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;
-- aes out
ctrl_aes_o : out t_axis_ctrl_aes_m2s;
ctrl_aes_i : in t_axis_s2m;
-- aes in
aes_ctrl_i : in t_axis_aes_ctrl_m2s;
aes_ctrl_o : out t_axis_s2m
);
end entity uart_ctrl;
architecture rtl of uart_ctrl is
type t_state is (IDLE, GET_CMD, RECV_DATA, SEND_DATA);
signal s_state : t_state;
signal s_reg_file : t_reg_file;
signal s_reg_addr : natural range 0 to 7;
signal s_reg_data : std_logic_vector(7 downto 0);
subtype t_cmd is std_ulogic_vector(3 downto 0);
constant c_read : t_cmd := x"0";
constant c_write : t_cmd := x"1";
alias a_tdata_cmd is tdata_i(3 downto 0);
alias a_tdata_addr is tdata_i(6 downto 4);
constant c_ctrl_addr : natural := 0;
constant c_key_addr : natural := 1;
constant c_nonce_addr : natural := 2;
constant c_din_addr : natural := 3;
constant c_out_addr : natural := 4;
constant AES_RESET : natural := 0; -- Reset key & din registers
constant CTR_START : natural := 1; -- 1st round of counter mode
constant AES_START : natural := 2; -- start AES engine (cleared with AES_END)
constant AES_END : natural := 3; -- AES engine finished
type reg_acc_cnt_t is array (natural range <>) of unsigned(3 downto 0);
signal read_acc_cnt : reg_acc_cnt_t(0 to 3);
signal write_acc_cnt : reg_acc_cnt_t(0 to 2);
begin
-- Register memory
process (clk_i, rst_n_i) is
begin
if (not rst_n_i) then
s_reg_data <= (others => '0');
s_reg_file <= c_reg_file_init;
read_acc_cnt <= (others => x"0");
write_acc_cnt <= (others => x"0");
elsif (rising_edge(clk_i)) then
-- Register write
if (s_state = RECV_DATA and tvalid_i = '1') then
case s_reg_addr is
when 0 => s_reg_file.ctrl <= tdata_i;
-- Clear all regs when AES_RESET bit set
if (tdata_i(AES_RESET)) then
s_reg_file.ctrl <= (others => '0');
s_reg_file.key <= (others => '0');
s_reg_file.nonce <= (others => '0');
s_reg_file.din <= (others => '0');
write_acc_cnt <= (others => x"0");
read_acc_cnt <= (others => x"0");
end if;
when 1 => write_acc_cnt(0) <= write_acc_cnt(0) + 1;
s_reg_file.key(to_integer(write_acc_cnt(0))*8 to to_integer(write_acc_cnt(0))*8+7) <= tdata_i;
when 2 => if (write_acc_cnt(1) = 11) then
write_acc_cnt(1) <= x"0";
else
write_acc_cnt(1) <= write_acc_cnt(1) + 1;
end if;
s_reg_file.nonce(to_integer(write_acc_cnt(1))*8 to to_integer(write_acc_cnt(1))*8+7) <= tdata_i;
when 3 => write_acc_cnt(2) <= write_acc_cnt(2) + 1;
s_reg_file.din(to_integer(write_acc_cnt(2))*8 to to_integer(write_acc_cnt(2))*8+7) <= tdata_i;
when others => null;
end case;
end if;
-- Register read
aes_ctrl_o.tready <= '0';
if (s_state = GET_CMD and a_tdata_cmd = c_read) then
case s_reg_addr is
when 0 => s_reg_data <= s_reg_file.ctrl;
when 1 => read_acc_cnt(0) <= read_acc_cnt(0) + 1;
s_reg_data <= s_reg_file.key(to_integer(read_acc_cnt(0))*8 to to_integer(read_acc_cnt(0))*8+7);
when 2 => if (read_acc_cnt(1) = 11) then
read_acc_cnt(1) <= x"0";
else
read_acc_cnt(1) <= read_acc_cnt(1) + 1;
end if;
s_reg_data <= s_reg_file.nonce(to_integer(read_acc_cnt(1))*8 to to_integer(read_acc_cnt(1))*8+7);
when 3 => read_acc_cnt(2) <= read_acc_cnt(2) + 1;
s_reg_data <= s_reg_file.din(to_integer(read_acc_cnt(2))*8 to to_integer(read_acc_cnt(2))*8+7);
when 4 => read_acc_cnt(3) <= read_acc_cnt(3) + 1;
s_reg_data <= aes_ctrl_i.tdata(to_integer(read_acc_cnt(3))*8 to to_integer(read_acc_cnt(3))*8+7);
if (read_acc_cnt(3) = 15) then
aes_ctrl_o.tready <= aes_ctrl_i.tvalid;
end if;
when others => s_reg_data <= (others => '0');
end case;
end if;
-- Set AES_END when AES out data is valid
-- Reset when AES out data was accepted (all 16 bytes of AES output data were read)
if (aes_ctrl_o.tready) then
s_reg_file.ctrl(AES_END) <= '0';
elsif (aes_ctrl_i.tvalid) then
s_reg_file.ctrl(AES_END) <= '1';
end if;
-- Reset AES_START & CTR_START when AES engine accepts in data
if (ctrl_aes_i.tready and s_reg_file.ctrl(AES_START)) then
s_reg_file.ctrl(AES_START) <= '0';
s_reg_file.ctrl(CTR_START) <= '0';
end if;
end if;
end process;
-- Control state machine
process (clk_i, rst_n_i) is
begin
if (not rst_n_i) then
s_state <= IDLE;
s_reg_addr <= 0;
elsif (rising_edge(clk_i)) then
case s_state is
when IDLE =>
if (tvalid_i) then
s_state <= GET_CMD;
s_reg_addr <= to_integer(unsigned(a_tdata_addr));
end if;
when GET_CMD =>
if (a_tdata_cmd = c_read) then
s_state <= SEND_DATA;
elsif (a_tdata_cmd = c_write) then
s_state <= RECV_DATA;
else
s_state <= IDLE;
end if;
when RECV_DATA =>
if (tvalid_i) then
s_state <= IDLE;
end if;
when SEND_DATA =>
if (tready_i) then
s_state <= IDLE;
end if;
when others =>
null;
end case;
end if;
end process;
tready_o <= '1' when s_state = GET_CMD or s_state = RECV_DATA else '0';
tdata_o <= s_reg_data;
tvalid_o <= '1' when s_state = SEND_DATA else '0';
ctrl_aes_o.tuser.start <= s_reg_file.ctrl(CTR_START);
ctrl_aes_o.tuser.key <= s_reg_file.key;
ctrl_aes_o.tuser.nonce <= s_reg_file.nonce;
ctrl_aes_o.tdata <= s_reg_file.din;
ctrl_aes_o.tvalid <= s_reg_file.ctrl(AES_START);
end architecture;

+ 105
- 0
uart_aes/rtl/uart_rx.vhd View File

@ -0,0 +1,105 @@
-- 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_rx is
generic (
CLK_DIV : natural := 10
);
port (
-- globals
rst_n_i : in std_logic;
clk_i : in std_logic;
-- axis user interface
tdata_o : out std_logic_vector(7 downto 0);
tvalid_o : out std_logic;
tready_i : in std_logic;
-- uart interface
rx_i : in std_logic
);
end entity uart_rx;
architecture rtl of uart_rx is
type t_uart_state is (IDLE, RECEIVE, VALID);
signal s_uart_state : t_uart_state;
signal s_clk_en : std_logic;
signal s_clk_cnt : natural range 0 to CLK_DIV-1;
signal s_bit_cnt : natural range 0 to tdata_o'length+1;
signal s_rx_d : std_logic_vector(3 downto 0);
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 = RECEIVE) 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 = RECEIVE and s_clk_cnt = CLK_DIV/2-1 else '0';
RxP : process (clk_i, rst_n_i) is
begin
if (not rst_n_i) then
s_uart_state <= IDLE;
tdata_o <= (others => '0');
s_rx_d <= x"1";
s_bit_cnt <= 0;
elsif (rising_edge(clk_i)) then
s_rx_d <= s_rx_d(2 downto 0) & rx_i;
FsmL : case s_uart_state is
when IDLE =>
s_bit_cnt <= tdata_o'length+1;
if (s_rx_d = "1000") then
s_uart_state <= RECEIVE;
end if;
when RECEIVE =>
if (s_clk_en) then
if (s_bit_cnt = 0) then
s_uart_state <= VALID;
else
tdata_o <= s_rx_d(3) & tdata_o(tdata_o'length-1 downto 1);
s_bit_cnt <= s_bit_cnt - 1;
end if;
end if;
when VALID =>
if (tready_i) then
s_uart_state <= IDLE;
end if;
end case;
end if;
end process RxP;
tvalid_o <= '1' when s_uart_state = VALID else '0';
end architecture rtl;

+ 102
- 0
uart_aes/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;

+ 57
- 0
uart_aes/sim/Makefile View File

@ -0,0 +1,57 @@
DESIGN_NAME := uart_aes
AES_DIR := ../../cryptocores/aes/rtl/vhdl
CRYPTO_SRC := \
$(AES_DIR)/aes_pkg.vhd \
$(AES_DIR)/aes_enc.vhd \
$(AES_DIR)/aes_dec.vhd \
$(AES_DIR)/aes.vhd \
$(AES_DIR)/../../../ctraes/rtl/vhdl/ctraes.vhd
WORK_FILES := \
../rtl/uart_aes_types.vhd \
../rtl/uart_tx.vhd \
../rtl/uart_rx.vhd \
../rtl/uart_ctrl.vhd \
../rtl/${DESIGN_NAME}.vhd \
uart_aes_sim.vhd \
uart_aes_ref.vhd \
tb_${DESIGN_NAME}.vhd
GM_FILES := ../../lib/rtl_components.vhd ../../lib/sim_components.vhd
SIM_SRC := tb_${DESIGN_NAME}.vhd
SIM_FLAGS := --std=08 -fpsl --workdir=work -Pwork
.PHONY: all compile sim clean
all: sim
compile: tb_${DESIGN_NAME}
work/work-obj08.cf: ${WORK_FILES} work/gatemate-obj08.cf work/cryptocores-obj08.cf
mkdir -p work
ghdl -a ${SIM_FLAGS} --work=work ${WORK_FILES}
work/cryptocores-obj08.cf: ${CRYPTO_SRC}
mkdir -p work
ghdl -a $(SIM_FLAGS) --work=cryptocores ${CRYPTO_SRC}
work/gatemate-obj08.cf: ${GM_FILES}
mkdir -p work
ghdl -a ${SIM_FLAGS} --work=gatemate ${GM_FILES}
tb_${DESIGN_NAME}: work/work-obj08.cf uart_aes_ref.c
@echo "Elaborate testbench & design ..."
ghdl -e ${SIM_FLAGS} -Wl,uart_aes_ref.c -Wl,-lcrypto -Wl,-lssl $@
sim: tb_${DESIGN_NAME}
@echo "Run testbench ..."
ghdl -r ${SIM_FLAGS} tb_${DESIGN_NAME} --assert-level=error --ieee-asserts=disable --wave=tb_${DESIGN_NAME}.ghw
work:
mkdir $@
clean:
@echo "Cleaning simulation files ..."
rm -rf tb_${DESIGN_NAME} tb_${DESIGN_NAME}.ghw *.o work/

+ 13
- 0
uart_aes/sim/tb_uart_aes.tcl View File

@ -0,0 +1,13 @@
set signals [list]
lappend signals "top.tb_uart_aes.dut.aes_inst.reset_i"
lappend signals "top.tb_uart_aes.dut.aes_inst.clk_i"
lappend signals "top.tb_uart_aes.dut.aes_inst.valid_i"
lappend signals "top.tb_uart_aes.dut.aes_inst.accept_o"
lappend signals "top.tb_uart_aes.dut.aes_inst.start_i"
lappend signals "top.tb_uart_aes.dut.aes_inst.key_i"
lappend signals "top.tb_uart_aes.dut.aes_inst.nonce_i"
lappend signals "top.tb_uart_aes.dut.aes_inst.data_i"
lappend signals "top.tb_uart_aes.dut.aes_inst.valid_o"
lappend signals "top.tb_uart_aes.dut.aes_inst.accept_i"
lappend signals "top.tb_uart_aes.dut.aes_inst.data_o"
set num_added [ gtkwave::addSignalsFromList $signals ]

+ 73
- 0
uart_aes/sim/tb_uart_aes.vhd View File

@ -0,0 +1,73 @@
library ieee ;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use std.env.all;
use work.uart_aes_ref.all;
entity tb_uart_aes is
end entity tb_uart_aes;
architecture sim of tb_uart_aes is
signal s_clk : std_logic := '1';
signal s_rst_n : std_logic := '0';
signal s_uart_rx : std_logic := '1';
signal s_uart_tx : std_logic;
constant c_baudrate : natural := 9600;
constant c_period_ns : time := 1_000_000_000 / c_baudrate * ns;
package uart_aes_sim_inst is new work.uart_aes_sim
generic map (period_ns => c_period_ns);
use uart_aes_sim_inst.all;
begin
dut : entity work.uart_aes
port map (
clk_i => s_clk,
rst_n_i => s_rst_n,
uart_rx_i => s_uart_rx,
uart_tx_o => s_uart_tx
);
s_rst_n <= '1' after 120 ns;
s_clk <= not s_clk after 50 ns;
TestP : process is
variable v_data : std_logic_vector(7 downto 0);
variable v_uart_data : std_logic_vector(0 to 127);
variable v_key : std_logic_vector(0 to 127);
variable v_nonce : std_logic_vector(0 to 95);
variable v_in_data : std_logic_vector(0 to 127);
variable v_ref_data : std_logic_vector(0 to 127);
begin
wait until s_rst_n;
wait until rising_edge(s_clk);
wait for 200 us;
v_key := x"0123456789ABCDEF0123456789ABCDEF";
v_nonce := x"0123456789ABCDEF01234567";
aes_setup(v_key, v_nonce, s_uart_rx);
for i in 0 to 7 loop
report "Test round " & to_string(i);
v_in_data := x"0123456789ABCDEF0123456789ABCDEF";
aes_write(v_in_data, s_uart_rx);
aes_crypt(s_uart_rx, s_uart_tx);
aes_read(v_uart_data, s_uart_rx, s_uart_tx);
-- Calc reference data
cryptData(swap(v_in_data), swap(v_key), swap(v_nonce & 32x"0"), i=0, i=7, v_ref_data, v_in_data'length/8);
assert v_uart_data = swap(v_ref_data)
report "Encryption error: Expected 0x" & to_hstring(swap(v_ref_data)) & ", got 0x" & to_hstring(v_uart_data)
severity failure;
end loop;
wait for 100 us;
report "Simulation finished without errors";
stop(0);
end process;
end architecture;

+ 164
- 0
uart_aes/sim/uart_aes_ref.c View File

@ -0,0 +1,164 @@
#include <stdio.h>
#include <string.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
static const char HDL_LOGIC_CHAR[] = { 'U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'};
enum HDL_LOGIC_STATES {
HDL_U = 0,
HDL_X = 1,
HDL_0 = 2,
HDL_1 = 3,
HDL_Z = 4,
HDL_W = 5,
HDL_L = 6,
HDL_H = 7,
HDL_D = 8,
};
EVP_CIPHER_CTX *ctx;
void slv_to_uchar(char* datain, unsigned char* dataout, int bytelen) {
for (int i = 0; i < bytelen; i++) {
for (int y = 0; y < 8; y++) {
if (*datain == HDL_1) {
*dataout |= 1 << y;
} else if (*datain == HDL_0) {
*dataout &= ~(1 << y);
}
datain++;
}
dataout++;
}
return;
}
void slv_to_string(char* datain, char* dataout, int bytelen) {
for (int i = 0; i < bytelen; i++) {
*dataout = HDL_LOGIC_CHAR[*datain];
datain++;
dataout++;
}
return;
}
void uchar_to_slv(unsigned char* datain, char* dataout, int bytelen) {
for (int i = 0; i < bytelen; i++) {
for (int y = 0; y < 8; y++) {
if ((*datain >> y) & 1 == 1) {
*dataout = HDL_1 ;
} else {
*dataout = HDL_0;
}
dataout++;
}
datain++;
}
return;
}
void handleErrors(void) {
ERR_print_errors_fp(stderr);
abort();
}
void init(unsigned char *key, unsigned char *iv) {
// Create and initialise the context
if(!(ctx = EVP_CIPHER_CTX_new()))
handleErrors();
// Initialise the encryption operation, no IV needed in CTR mode
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, key, iv))
handleErrors();
// We don't want padding
if(1 != EVP_CIPHER_CTX_set_padding(ctx, 0))
handleErrors();
}
int encrypt(unsigned char *plaintext,
int plaintext_len,
unsigned char *ciphertext) {
int len = 0;
// Provide the message to be encrypted, and obtain the encrypted output
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
handleErrors();
return len;
}
int finalize(void) {
int len = 0;
unsigned char data[16];
// Finalise the encryption. No further bytes are written as padding is switched off
if (1 != EVP_EncryptFinal_ex(ctx, data, &len))
handleErrors();
// Clean up
EVP_CIPHER_CTX_free(ctx);
return len;
}
void cryptData(char* datain, char* key, char* iv, char start, char final, char* dataout, int bytelen) {
int crypt_len;
unsigned char c_din[bytelen];
unsigned char c_key[bytelen];
unsigned char c_iv[bytelen];
unsigned char c_dout[bytelen];
slv_to_uchar(datain, c_din, bytelen);
slv_to_uchar(key, c_key, bytelen);
slv_to_uchar(iv, c_iv, bytelen);
if (start) {
init(c_key, c_iv);
}
crypt_len = encrypt(c_din, bytelen, c_dout);
if (crypt_len != bytelen) {
printf("Warning: encrypt() returned with unexpected length %d\n", crypt_len);
}
if (final) {
crypt_len = finalize();
if (crypt_len != 0) {
printf("Warning: finalize() returned with unexpected length %d\n", crypt_len);
}
}
uchar_to_slv(c_dout, dataout, bytelen);
return;
}

+ 46
- 0
uart_aes/sim/uart_aes_ref.vhd View File

@ -0,0 +1,46 @@
library ieee ;
use ieee.std_logic_1164.all;
package uart_aes_ref is
procedure cryptData(datain : in std_logic_vector(0 to 127);
key : in std_logic_vector(0 to 127);
iv : in std_logic_vector(0 to 127);
start : in boolean;
final : in boolean;
dataout : out std_logic_vector(0 to 127);
bytelen : in integer);
attribute foreign of cryptData: procedure is "VHPIDIRECT cryptData";
function swap (datain : std_logic_vector(0 to 127)) return std_logic_vector;
end package;
package body uart_aes_ref is
procedure cryptData(datain : in std_logic_vector(0 to 127);
key : in std_logic_vector(0 to 127);
iv : in std_logic_vector(0 to 127);
start : in boolean;
final : in boolean;
dataout : out std_logic_vector(0 to 127);
bytelen : in integer) is
begin
report "VHPIDIRECT cryptData" severity failure;
end procedure;
function swap (datain : std_logic_vector(0 to 127)) return std_logic_vector is
variable v_data : std_logic_vector(0 to 127);
begin
for i in 0 to 15 loop
for y in 0 to 7 loop
v_data((i*8)+y) := datain((i*8)+7-y);
end loop;
end loop;
return v_data;
end function;
end package body;

+ 125
- 0
uart_aes/sim/uart_aes_sim.vhd View File

@ -0,0 +1,125 @@
library ieee ;
use ieee.std_logic_1164.all;
package uart_aes_sim is
generic (
period_ns : time
);
procedure uart_send ( data : in std_logic_vector(7 downto 0);
signal tx : out std_logic);
procedure uart_recv ( data : out std_logic_vector(7 downto 0);
signal rx : in std_logic);
procedure aes_setup ( key : in std_logic_vector(0 to 127);
nonce : in std_logic_vector(0 to 95);
signal tx : out std_logic);
procedure aes_write ( data : in std_logic_vector(0 to 127);
signal tx : out std_logic);
procedure aes_read ( data : out std_logic_vector(0 to 127);
signal tx : out std_logic;
signal rx : in std_logic);
procedure aes_crypt (signal tx : out std_logic;
signal rx : in std_logic);
end package;
package body uart_aes_sim is
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);
wait for period_ns;
tx <= '0';
wait for period_ns;
for i in 0 to 7 loop
tx <= data(i);
wait for period_ns;
end loop;
tx <= '1';
wait for 0 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 period_ns; -- Skip start bit
wait for period_ns/2;
for i in 0 to 7 loop
data(i) := rx;
wait for period_ns;
end loop;
report "UART recv: 0x" & to_hstring(data);
end procedure;
procedure aes_setup ( key : in std_logic_vector(0 to 127);
nonce : in std_logic_vector(0 to 95);
signal tx : out std_logic) is
begin
-- Reset control register
uart_send(x"01", tx);
uart_send(x"01", tx);
-- Write key register
for i in 0 to 15 loop
uart_send(x"11", tx);
uart_send(key(i*8 to i*8+7), tx);
end loop;
-- Write nonce register
for i in 0 to 11 loop
uart_send(x"21", tx);
uart_send(nonce(i*8 to i*8+7), tx);
end loop;
-- Set control registers CTR_START bit
uart_send(x"01", tx);
uart_send(x"02", tx);
end procedure;
procedure aes_write ( data : in std_logic_vector(0 to 127);
signal tx : out std_logic) is
begin
-- Write din register
for i in 0 to 15 loop
uart_send(x"31", tx);
uart_send(data(i*8 to i*8+7), tx);
end loop;
end procedure;
procedure aes_read ( data : out std_logic_vector(0 to 127);
signal tx : out std_logic;
signal rx : in std_logic) is
variable v_data : std_logic_vector(7 downto 0);
begin
-- Check for valid AES output data
loop
uart_send(x"00", tx);
uart_recv(v_data, rx);
exit when v_data(3);
end loop;
-- Read dout register
for i in 0 to 15 loop
uart_send(x"40", tx);
uart_recv(data(i*8 to i*8+7), rx);
end loop;
end procedure;
procedure aes_crypt (signal tx : out std_logic;
signal rx : in std_logic) is
variable v_data : std_logic_vector(7 downto 0);
begin
uart_send(x"00", tx);
uart_recv(v_data, rx);
v_data(2) := '1';
-- Set control registers CTR_START bit
uart_send(x"01", tx);
uart_send(v_data, tx);
end procedure;
end package body;

+ 72
- 0
uart_aes/syn/Makefile View File

@ -0,0 +1,72 @@
DESIGN_NAME := uart_aes
AES_DIR := ../../cryptocores/aes/rtl/vhdl
CRYPTO_SRC := \
$(AES_DIR)/aes_pkg.vhd \
$(AES_DIR)/aes_enc.vhd \
$(AES_DIR)/aes_dec.vhd \
$(AES_DIR)/aes.vhd \
$(AES_DIR)/../../../ctraes/rtl/vhdl/ctraes.vhd
WORK_FILES := \
../rtl/uart_aes_types.vhd \
../rtl/uart_tx.vhd \
../rtl/uart_rx.vhd \
../rtl/uart_ctrl.vhd \
../rtl/${DESIGN_NAME}.vhd
GM_FILES := ../../lib/rtl_components.vhd
GHDL_FLAGS := --std=08 --workdir=build -Pbuild
ICARUSFLAGS := -Wall -Winfloop -g2012 -gspecify -Ttyp
YOSYSPIPE := -nomx8
PNRFLAGS := -om 3 -cCP on
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 build/cryptocores-obj08.cf
ghdl -a ${GHDL_FLAGS} --work=work ${WORK_FILES}
build/cryptocores-obj08.cf: ${CRYPTO_SRC}
ghdl -a $(GHDL_FLAGS) --work=cryptocores ${CRYPTO_SRC}
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 ${ICARUSFLAGS} -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 ${ICARUSFLAGS} -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

+ 16
- 0
uart_aes/syn/read_data.txt View File

@ -0,0 +1,16 @@
A0
55
A0
62
BC
DD
C3
4C
33
FE
9F
A6
0C
FB
6F
2D

+ 149
- 0
uart_aes/syn/tb_uart_aes.v View File

@ -0,0 +1,149 @@
`timescale 1 ns/100 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 = 10 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_aes;
// DUT in/out
reg clk = 1'b0;
reg rst_n = 1'b1;
reg uart_rx;
wire uart_tx;
wire [3:0] led_n;
// 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_aes UUT (.clk_i(clk), .rst_n_i(rst_n), .uart_rx_i(uart_rx), .uart_tx_o(uart_tx), .led_n_o(led_n));
// set dumpfile
initial begin
$dumpfile ("tb_uart_aes.fst");
$dumpvars (0, tb_uart_aes);
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;
reg [7:0] write_cmds [0:89];
reg [7:0] read_data [0:15];
// read in test data files
initial begin
$readmemh("write_cmds.txt", write_cmds);
$readmemh("read_data.txt", read_data);
end
// Stimuli generator
initial
forever @(posedge rst_n) begin
uart_rx = 1'b1;
#uart_bit_period;
// start crypto
for (integer i = 0; i < $size(write_cmds); i = i + 1) begin
tx_data = write_cmds[i];
$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;
end
// Request read of data out register
for (integer i = 0; i <= 15; i = i + 1) begin
tx_data = 8'h40;
$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;
end
end
// Checker
initial begin
@(posedge rst_n)
for (integer i = 0; i <= 15; i = i + 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 == read_data[i])
$display("UART recv: 0x%h", rx_data);
else
$error("UART receive error, got 0x%h, expected 0x%h", rx_data, read_data[i]);
end
$display ("UART tests finished");
$finish;
end
endmodule

+ 21
- 0
uart_aes/syn/uart_aes.ccf View File

@ -0,0 +1,21 @@
# 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_in "uart_rx_i" Loc = "IO_NB_A1"; # PMODA IO3
Pin_out "uart_tx_o" Loc = "IO_NB_A0"; # PMODA IO1
Pin_out "led_n_o[0]" Loc = "IO_EB_B1"; # LED D1
Pin_out "led_n_o[1]" Loc = "IO_EB_B2"; # LED D2
Pin_out "led_n_o[2]" Loc = "IO_EB_B3"; # LED D3
Pin_out "led_n_o[3]" Loc = "IO_EB_B4"; # LED D4
#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";

+ 90
- 0
uart_aes/syn/write_cmds.txt View File

@ -0,0 +1,90 @@
11
01
11
23
11
45
11
67
11
89
11
AB
11
CD
11
EF
11
01
11
23
11
45
11
67
11
89
11
AB
11
CD
11
EF
21
01
21
23
21
45
21
67
21
89
21
AB
21
CD
21
EF
21
01
21
23
21
45
21
67
31
01
31
23
31
45
31
67
31
89
31
AB
31
CD
31
EF
31
01
31
23
31
45
31
67
31
89
31
AB
31
CD
31
EF
01
06

Loading…
Cancel
Save