|
|
@ -0,0 +1,135 @@ |
|
|
|
-- 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; |
|
|
|
|
|
|
|
|
|
|
|
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 |
|
|
|
); |
|
|
|
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; |
|
|
|
|
|
|
|
subtype t_reg is std_logic_vector(7 downto 0); |
|
|
|
|
|
|
|
type t_reg_file is array (1 to 7) of t_reg; |
|
|
|
signal s_reg_file : t_reg_file; |
|
|
|
|
|
|
|
constant c_version : t_reg := x"01"; |
|
|
|
|
|
|
|
signal s_reg_addr : natural range 0 to 7; |
|
|
|
signal s_reg_data : t_reg; |
|
|
|
|
|
|
|
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); |
|
|
|
|
|
|
|
begin |
|
|
|
|
|
|
|
-- Register memory, omitted reset of memory during synthesis |
|
|
|
-- for better RAM detection |
|
|
|
process (clk_i, rst_n_i) is |
|
|
|
begin |
|
|
|
if (not rst_n_i) then |
|
|
|
-- synthesis translate_off |
|
|
|
s_reg_file <= (others => (others => '0')); |
|
|
|
-- synthesis translate_on |
|
|
|
s_reg_data <= (others => '0'); |
|
|
|
elsif (rising_edge(clk_i)) then |
|
|
|
-- Write |
|
|
|
if (s_state = RECV_DATA and tvalid_i = '1') then |
|
|
|
-- Ignore writes to version register |
|
|
|
if (s_reg_addr /= 0) then |
|
|
|
s_reg_file(s_reg_addr) <= tdata_i; |
|
|
|
end if; |
|
|
|
end if; |
|
|
|
-- Always read, regardless of write or read command |
|
|
|
if (s_state = GET_CMD) then |
|
|
|
if (s_reg_addr /= 0) then |
|
|
|
s_reg_data <= s_reg_file(s_reg_addr); |
|
|
|
end if; |
|
|
|
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 <= c_version when s_reg_addr = 0 else s_reg_data; |
|
|
|
tvalid_o <= '1' when s_state = SEND_DATA else '0'; |
|
|
|
|
|
|
|
end architecture; |