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