-- TODO: WARN: SEL bits ignored. -- TODO: Multiple ports is broken (address mapping * 4), plus some ACK error maybe? library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use ieee.std_logic_misc.OR_REDUCE; library ip; use ip.wishbone_package.all; entity uart_wb is generic( portcount : integer := 1 ); port( clk : in std_logic; rst : in std_logic; -- Wishbone slave_i : in wishbone_v3_slave_in; slave_o : out wishbone_v3_slave_out; irq_o : out std_logic_vector(portcount - 1 downto 0); -- UART rx : in std_logic_vector(portcount - 1 downto 0); tx : out std_logic_vector(portcount - 1 downto 0) ); end entity uart_wb; architecture RTL of uart_wb is constant addressQuantum : integer := 4; constant registersPerCore : integer := 5; type uart_data is array (portcount - 1 downto 0) of std_logic_vector(7 downto 0); type uart_ckDiv is array (portcount - 1 downto 0) of std_logic_vector(15 downto 0); type uart_register is array (portcount - 1 downto 0) of std_logic_vector(31 downto 0); signal rx_data : uart_data; signal rx_byte_ready : std_logic_vector(portcount - 1 downto 0); signal rx_error : std_logic_vector(portcount - 1 downto 0); signal ckDiv : uart_ckDiv; signal parityEnable : std_logic_vector(portcount - 1 downto 0); signal parityOdd : std_logic_vector(portcount - 1 downto 0); signal twoStopBits : std_logic_vector(portcount - 1 downto 0); signal tx_data : uart_data; signal tx_strobe : std_logic_vector(portcount - 1 downto 0); signal tx_busy : std_logic_vector(portcount - 1 downto 0); signal CR : uart_register; signal SR : uart_register; signal IMR : uart_register; signal MASKEDSR : uart_register; signal data_in_buffered : uart_data; begin generate_label : for i in 0 to portcount - 1 generate uart_rx_inst : entity work.uart_rx port map( clk => clk, rst => rst, data => rx_data(i), byte_ready => rx_byte_ready(i), error => rx_error(i), ckDiv => ckDiv(i), parityEnable => parityEnable(i), parityOdd => parityOdd(i), twoStopBits => twoStopBits(i), rx => rx(i) ); uart_tx_inst : entity work.uart_tx port map( clk => clk, rst => rst, data => tx_data(i), byte_ready => tx_strobe(i), busy => tx_busy(i), ckDiv => ckDiv(i), parityEnable => parityEnable(i), parityOdd => parityOdd(i), twoStopBits => twoStopBits(i), tx => tx(i) ); end generate generate_label; wb : process(rst, clk) is begin if rst = '1' then slave_o.DAT <= (others => '0'); for i in 0 to portcount - 1 loop SR(i) <= (others => '0'); CR(i) <= (others => '0'); IMR(i) <= (others => '0'); tx_strobe(i) <= '0'; tx_data(i) <= (others => '0'); end loop; elsif rising_edge(clk) then for i in 0 to portcount - 1 loop slave_o.ACK <= '0'; tx_strobe(i) <= '0'; --SR update if (rx_error(i) = '1') then SR(i)(17) <= '1'; -- Set RXEI end if; if (rx_byte_ready(i) = '1') then SR(i)(18) <= '1'; -- Set RXI SR(i)(16) <= '1'; -- Set RXNE (no FIFO yet) data_in_buffered(i) <= rx_data(i); end if; SR(i)(0) <= tx_busy(i); -- TXBF; no FIFO SR(i)(1) <= tx_busy(i); -- TXActive -- WB if slave_i.CYC = '1' and slave_i.STB = '1' then if unsigned(slave_i.ADR) = to_unsigned((registersPerCore * i), slave_i.ADR'length) then -- CRx slave_o.DAT <= CR(i); if slave_i.we = '1' then CR(i) <= slave_i.DAT; end if; elsif unsigned(slave_i.ADR) = to_unsigned((registersPerCore * i) + 1 * addressQuantum, slave_i.ADR'length) then --SRx slave_o.DAT <= SR(i); if slave_i.we = '1' then SR(i) <= slave_i.DAT and (x"00" & "00000110" & x"0000"); -- mask RO bits end if; elsif unsigned(slave_i.ADR) = to_unsigned((registersPerCore * i) + 2 * addressQuantum, slave_i.ADR'length) then --IMRx slave_o.DAT <= IMR(i); if slave_i.we = '1' then IMR(i) <= slave_i.DAT; end if; elsif unsigned(slave_i.ADR) = to_unsigned((registersPerCore * i) + 3 * addressQuantum, slave_i.ADR'length) then --ODRx slave_o.DAT <= x"000000" & tx_data(i); --(others => '0'); if slave_i.we = '1' then tx_data(i) <= slave_i.DAT(7 downto 0); tx_strobe(i) <= '1'; end if; elsif unsigned(slave_i.ADR) = to_unsigned((registersPerCore * i) + 4 * addressQuantum, slave_i.ADR'length) then --IDRx slave_o.DAT <= x"000000" & data_in_buffered(i); SR(i)(18) <= '0'; -- RXI Clear interrupt SR(i)(16) <= '0'; -- RXNE No FIFO -> buffer is immediately empty again end if; slave_o.ACK <= '1'; end if; end loop; end if; end process wb; slave_o.RTY <= '0'; slave_o.ERR <= '0'; applyCR : for i in 0 to portcount - 1 generate ckDiv(i) <= CR(i)(31 downto 16); parityEnable(i) <= CR(i)(1); parityOdd(i) <= CR(i)(0); twoStopBits(i) <= CR(i)(2); end generate applyCR; masking : for i in 0 to portcount - 1 generate MASKEDSR(i) <= SR(i) and IMR(i); irq_o(i) <= OR_REDUCE(MASKEDSR(i)); end generate masking; end architecture RTL;