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