| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
89730f767a | Use random stimuli in uart_loop testbench | 3 years ago |
|
|
1777fbd742 | Add uart_aes design, simulation & fpga-flow | 3 years ago |
| @ -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; | |||
| @ -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; | |||
| @ -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; | |||
| @ -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; | |||
| @ -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,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/ | |||
| @ -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 ] | |||
| @ -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; | |||
| @ -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; | |||
| } | |||
| @ -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; | |||
| @ -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; | |||
| @ -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 | |||
| @ -0,0 +1,16 @@ | |||
| A0 | |||
| 55 | |||
| A0 | |||
| 62 | |||
| BC | |||
| DD | |||
| C3 | |||
| 4C | |||
| 33 | |||
| FE | |||
| 9F | |||
| A6 | |||
| 0C | |||
| FB | |||
| 6F | |||
| 2D | |||
| @ -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 | |||
| @ -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"; | |||
| @ -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 | |||