Line 161... |
Line 161... |
constant data_rx_avail_c : natural := 31; -- r/-: RX data available
|
constant data_rx_avail_c : natural := 31; -- r/-: RX data available
|
|
|
-- access control --
|
-- access control --
|
signal acc_en : std_ulogic; -- module access enable
|
signal acc_en : std_ulogic; -- module access enable
|
signal addr : std_ulogic_vector(31 downto 0); -- access address
|
signal addr : std_ulogic_vector(31 downto 0); -- access address
|
signal wr_en : std_ulogic; -- word write enable
|
signal wren : std_ulogic; -- word write enable
|
signal rd_en : std_ulogic; -- read enable
|
signal rden : std_ulogic; -- read enable
|
|
|
-- clock generator --
|
-- clock generator --
|
signal uart_clk : std_ulogic;
|
signal uart_clk : std_ulogic;
|
|
|
-- numbers of bits in transmission frame --
|
-- numbers of bits in transmission frame --
|
Line 179... |
Line 179... |
-- UART transmitter --
|
-- UART transmitter --
|
type tx_state_t is (S_TX_IDLE, S_TX_GET, S_TX_CHECK, S_TX_TRANSMIT, S_TX_SIM);
|
type tx_state_t is (S_TX_IDLE, S_TX_GET, S_TX_CHECK, S_TX_TRANSMIT, S_TX_SIM);
|
type tx_engine_t is record
|
type tx_engine_t is record
|
state : tx_state_t;
|
state : tx_state_t;
|
busy : std_ulogic;
|
busy : std_ulogic;
|
|
done : std_ulogic;
|
bitcnt : std_ulogic_vector(03 downto 0);
|
bitcnt : std_ulogic_vector(03 downto 0);
|
sreg : std_ulogic_vector(10 downto 0);
|
sreg : std_ulogic_vector(10 downto 0);
|
baud_cnt : std_ulogic_vector(11 downto 0);
|
baud_cnt : std_ulogic_vector(11 downto 0);
|
cts : std_ulogic; -- allow new transmission when 1
|
cts : std_ulogic; -- allow new transmission when 1
|
end record;
|
end record;
|
Line 190... |
Line 191... |
|
|
-- UART receiver --
|
-- UART receiver --
|
type rx_state_t is (S_RX_IDLE, S_RX_RECEIVE);
|
type rx_state_t is (S_RX_IDLE, S_RX_RECEIVE);
|
type rx_engine_t is record
|
type rx_engine_t is record
|
state : rx_state_t;
|
state : rx_state_t;
|
|
done : std_ulogic;
|
sync : std_ulogic_vector(04 downto 0);
|
sync : std_ulogic_vector(04 downto 0);
|
bitcnt : std_ulogic_vector(03 downto 0);
|
bitcnt : std_ulogic_vector(03 downto 0);
|
sreg : std_ulogic_vector(09 downto 0);
|
sreg : std_ulogic_vector(09 downto 0);
|
baud_cnt : std_ulogic_vector(11 downto 0);
|
baud_cnt : std_ulogic_vector(11 downto 0);
|
overr : std_ulogic;
|
overr : std_ulogic;
|
Line 225... |
Line 227... |
free : std_ulogic; -- free entry available?
|
free : std_ulogic; -- free entry available?
|
half : std_ulogic; -- half full
|
half : std_ulogic; -- half full
|
end record;
|
end record;
|
signal rx_buffer : rx_buffer_t;
|
signal rx_buffer : rx_buffer_t;
|
|
|
|
-- interrupt generator --
|
|
type irq_t is record
|
|
pending : std_ulogic; -- pending interrupt request
|
|
set : std_ulogic;
|
|
clr : std_ulogic;
|
|
end record;
|
|
signal rx_irq, tx_irq : irq_t;
|
|
|
begin
|
begin
|
|
|
-- Sanity Checks --------------------------------------------------------------------------
|
-- Sanity Checks --------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
assert not (is_power_of_two_f(UART_RX_FIFO) = false) report "NEORV32 PROCESSOR CONFIG ERROR: UART" &
|
assert not (is_power_of_two_f(UART_RX_FIFO) = false) report "NEORV32 PROCESSOR CONFIG ERROR: UART" &
|
Line 239... |
Line 249... |
|
|
-- Access Control -------------------------------------------------------------------------
|
-- Access Control -------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = uart_id_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = uart_id_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
addr <= uart_id_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
|
addr <= uart_id_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
|
wr_en <= acc_en and wren_i;
|
wren <= acc_en and wren_i;
|
rd_en <= acc_en and rden_i;
|
rden <= acc_en and rden_i;
|
|
|
|
|
-- Read/Write Access ----------------------------------------------------------------------
|
-- Read/Write Access ----------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
rw_access: process(clk_i)
|
rw_access: process(clk_i)
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
-- bus access acknowledge --
|
-- bus access acknowledge --
|
ack_o <= wr_en or rd_en;
|
ack_o <= wren or rden;
|
|
|
-- write access --
|
-- write access --
|
if (wr_en = '1') then
|
if (wren = '1') then
|
if (addr = uart_id_ctrl_addr_c) then
|
if (addr = uart_id_ctrl_addr_c) then
|
ctrl <= (others => '0');
|
ctrl <= (others => '0');
|
ctrl(ctrl_baud11_c downto ctrl_baud00_c) <= data_i(ctrl_baud11_c downto ctrl_baud00_c);
|
ctrl(ctrl_baud11_c downto ctrl_baud00_c) <= data_i(ctrl_baud11_c downto ctrl_baud00_c);
|
ctrl(ctrl_sim_en_c) <= data_i(ctrl_sim_en_c);
|
ctrl(ctrl_sim_en_c) <= data_i(ctrl_sim_en_c);
|
ctrl(ctrl_pmode1_c downto ctrl_pmode0_c) <= data_i(ctrl_pmode1_c downto ctrl_pmode0_c);
|
ctrl(ctrl_pmode1_c downto ctrl_pmode0_c) <= data_i(ctrl_pmode1_c downto ctrl_pmode0_c);
|
Line 269... |
Line 279... |
end if;
|
end if;
|
end if;
|
end if;
|
|
|
-- read access --
|
-- read access --
|
data_o <= (others => '0');
|
data_o <= (others => '0');
|
if (rd_en = '1') then
|
if (rden = '1') then
|
if (addr = uart_id_ctrl_addr_c) then
|
if (addr = uart_id_ctrl_addr_c) then
|
data_o(ctrl_baud11_c downto ctrl_baud00_c) <= ctrl(ctrl_baud11_c downto ctrl_baud00_c);
|
data_o(ctrl_baud11_c downto ctrl_baud00_c) <= ctrl(ctrl_baud11_c downto ctrl_baud00_c);
|
data_o(ctrl_sim_en_c) <= ctrl(ctrl_sim_en_c);
|
data_o(ctrl_sim_en_c) <= ctrl(ctrl_sim_en_c);
|
data_o(ctrl_pmode1_c downto ctrl_pmode0_c) <= ctrl(ctrl_pmode1_c downto ctrl_pmode0_c);
|
data_o(ctrl_pmode1_c downto ctrl_pmode0_c) <= ctrl(ctrl_pmode1_c downto ctrl_pmode0_c);
|
data_o(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl(ctrl_prsc2_c downto ctrl_prsc0_c);
|
data_o(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl(ctrl_prsc2_c downto ctrl_prsc0_c);
|
Line 344... |
Line 354... |
|
|
-- control --
|
-- control --
|
tx_buffer.clear <= not ctrl(ctrl_en_c);
|
tx_buffer.clear <= not ctrl(ctrl_en_c);
|
|
|
-- write access --
|
-- write access --
|
tx_buffer.we <= '1' when (wr_en = '1') and (addr = uart_id_rtx_addr_c) else '0';
|
tx_buffer.we <= '1' when (wren = '1') and (addr = uart_id_rtx_addr_c) else '0';
|
tx_buffer.wdata <= data_i;
|
tx_buffer.wdata <= data_i;
|
|
|
|
|
-- UART Transmitter Engine ----------------------------------------------------------------
|
-- UART Transmitter Engine ----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
Line 356... |
Line 366... |
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
-- defaults --
|
-- defaults --
|
uart_txd_o <= '1'; -- keep TX line idle (=high) if waiting for permission to start sending (->CTS)
|
uart_txd_o <= '1'; -- keep TX line idle (=high) if waiting for permission to start sending (->CTS)
|
tx_buffer.re <= '0';
|
tx_buffer.re <= '0';
|
|
tx_engine.done <= '0';
|
|
|
-- FSM --
|
-- FSM --
|
if (ctrl(ctrl_en_c) = '0') then -- disabled
|
if (ctrl(ctrl_en_c) = '0') then -- disabled
|
tx_engine.state <= S_TX_IDLE;
|
tx_engine.state <= S_TX_IDLE;
|
else
|
else
|
Line 406... |
Line 417... |
tx_engine.baud_cnt <= std_ulogic_vector(unsigned(tx_engine.baud_cnt) - 1);
|
tx_engine.baud_cnt <= std_ulogic_vector(unsigned(tx_engine.baud_cnt) - 1);
|
end if;
|
end if;
|
end if;
|
end if;
|
uart_txd_o <= tx_engine.sreg(0);
|
uart_txd_o <= tx_engine.sreg(0);
|
if (or_reduce_f(tx_engine.bitcnt) = '0') then -- all bits send?
|
if (or_reduce_f(tx_engine.bitcnt) = '0') then -- all bits send?
|
|
tx_engine.done <= '1'; -- sending done
|
tx_engine.state <= S_TX_IDLE;
|
tx_engine.state <= S_TX_IDLE;
|
end if;
|
end if;
|
|
|
when S_TX_SIM => -- simulation mode output
|
when S_TX_SIM => -- simulation mode output
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
Line 434... |
Line 446... |
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
-- input synchronizer --
|
-- input synchronizer --
|
rx_engine.sync <= uart_rxd_i & rx_engine.sync(rx_engine.sync'left downto 1);
|
rx_engine.sync <= uart_rxd_i & rx_engine.sync(rx_engine.sync'left downto 1);
|
|
|
|
-- default --
|
|
rx_engine.done <= '0';
|
|
|
-- FSM --
|
-- FSM --
|
if (ctrl(ctrl_en_c) = '0') then -- disabled
|
if (ctrl(ctrl_en_c) = '0') then -- disabled
|
rx_engine.overr <= '0';
|
rx_engine.overr <= '0';
|
rx_engine.state <= S_RX_IDLE;
|
rx_engine.state <= S_RX_IDLE;
|
else
|
else
|
Line 461... |
Line 476... |
else
|
else
|
rx_engine.baud_cnt <= std_ulogic_vector(unsigned(rx_engine.baud_cnt) - 1);
|
rx_engine.baud_cnt <= std_ulogic_vector(unsigned(rx_engine.baud_cnt) - 1);
|
end if;
|
end if;
|
end if;
|
end if;
|
if (or_reduce_f(rx_engine.bitcnt) = '0') then -- all bits received?
|
if (or_reduce_f(rx_engine.bitcnt) = '0') then -- all bits received?
|
|
rx_engine.done <= '1'; -- receiving done
|
rx_engine.state <= S_RX_IDLE;
|
rx_engine.state <= S_RX_IDLE;
|
end if;
|
end if;
|
|
|
when others => -- undefined
|
when others => -- undefined
|
-- ------------------------------------------------------------
|
-- ------------------------------------------------------------
|
rx_engine.state <= S_RX_IDLE;
|
rx_engine.state <= S_RX_IDLE;
|
|
|
end case;
|
end case;
|
|
|
-- overrun flag --
|
-- overrun flag --
|
if (rd_en = '1') and (addr = uart_id_rtx_addr_c) then -- clear when reading data register
|
if (rden = '1') and (addr = uart_id_rtx_addr_c) then -- clear when reading data register
|
rx_engine.overr <= '1';
|
rx_engine.overr <= '1';
|
elsif (rx_buffer.we = '1') and (rx_buffer.free = '0') then -- write to full FIFO
|
elsif (rx_buffer.we = '1') and (rx_buffer.free = '0') then -- write to full FIFO
|
rx_engine.overr <= '0';
|
rx_engine.overr <= '0';
|
end if;
|
end if;
|
end if;
|
end if;
|
Line 518... |
Line 534... |
-- read/write access --
|
-- read/write access --
|
rx_buffer.wdata(7 downto 0) <= rx_engine.sreg(7 downto 0) when (ctrl(ctrl_pmode1_c) = '1') else rx_engine.sreg(8 downto 1); -- RX data
|
rx_buffer.wdata(7 downto 0) <= rx_engine.sreg(7 downto 0) when (ctrl(ctrl_pmode1_c) = '1') else rx_engine.sreg(8 downto 1); -- RX data
|
rx_buffer.wdata(8) <= ctrl(ctrl_pmode1_c) and (xor_reduce_f(rx_engine.sreg(8 downto 0)) xor ctrl(ctrl_pmode0_c)); -- parity error flag
|
rx_buffer.wdata(8) <= ctrl(ctrl_pmode1_c) and (xor_reduce_f(rx_engine.sreg(8 downto 0)) xor ctrl(ctrl_pmode0_c)); -- parity error flag
|
rx_buffer.wdata(9) <= not rx_engine.sreg(9); -- frame error flag: check stop bit (error if not set)
|
rx_buffer.wdata(9) <= not rx_engine.sreg(9); -- frame error flag: check stop bit (error if not set)
|
rx_buffer.we <= '1' when (rx_engine.bitcnt = "0000") and (rx_engine.state = S_RX_RECEIVE) else '0'; -- RX complete
|
rx_buffer.we <= '1' when (rx_engine.bitcnt = "0000") and (rx_engine.state = S_RX_RECEIVE) else '0'; -- RX complete
|
rx_buffer.re <= '1' when (rd_en = '1') and (addr = uart_id_rtx_addr_c) else '0';
|
rx_buffer.re <= '1' when (rden = '1') and (addr = uart_id_rtx_addr_c) else '0';
|
|
|
|
|
-- Hardware Flow Control ------------------------------------------------------------------
|
-- Hardware Flow Control ------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
tx_engine.cts <= (not uart_cts_ff(1)) when (ctrl(ctrl_cts_en_c) = '1') else '1'; -- input is low-active, internal signal is high-active
|
tx_engine.cts <= (not uart_cts_ff(1)) when (ctrl(ctrl_cts_en_c) = '1') else '1'; -- input is low-active, internal signal is high-active
|
Line 536... |
Line 552... |
uart_rts_o <= uart_rts;
|
uart_rts_o <= uart_rts;
|
end if;
|
end if;
|
end process flow_control_buffer;
|
end process flow_control_buffer;
|
|
|
|
|
-- Interrupts -----------------------------------------------------------------------------
|
-- Interrupt Generator --------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
irq_generator: process(clk_i)
|
irq_type: process(ctrl, tx_buffer, rx_buffer)
|
begin
|
begin
|
if rising_edge(clk_i) then
|
|
if (ctrl(ctrl_en_c) = '0') then -- no interrupts when disabled
|
|
irq_txd_o <= '0';
|
|
irq_rxd_o <= '0';
|
|
else
|
|
-- TX interrupt --
|
-- TX interrupt --
|
if (UART_TX_FIFO = 1) then
|
if (UART_TX_FIFO = 1) then
|
irq_txd_o <= tx_buffer.free; -- fire IRQ if FIFO is not full
|
tx_irq.set <= tx_buffer.free; -- fire IRQ if FIFO is not full
|
else
|
else
|
if (ctrl(ctrl_tx_irq_c) = '1') then
|
if (ctrl(ctrl_tx_irq_c) = '1') then
|
irq_txd_o <= not tx_buffer.half; -- fire IRQ if FIFO is less than half-full
|
tx_irq.set <= not tx_buffer.half; -- fire IRQ if FIFO is less than half-full
|
else
|
else
|
irq_txd_o <= tx_buffer.free; -- fire IRQ if FIFO is not full
|
tx_irq.set <= tx_buffer.free; -- fire IRQ if FIFO is not full
|
end if;
|
end if;
|
end if;
|
end if;
|
|
|
-- RX interrupt --
|
-- RX interrupt --
|
if (UART_RX_FIFO = 1) then
|
if (UART_RX_FIFO = 1) then
|
irq_rxd_o <= rx_buffer.avail; -- fire IRQ if FIFO is not empty
|
rx_irq.set <= rx_buffer.avail; -- fire IRQ if FIFO is not empty
|
else
|
else
|
if (ctrl(ctrl_rx_irq_c) = '1') then
|
if (ctrl(ctrl_rx_irq_c) = '1') then
|
irq_rxd_o <= rx_buffer.half; -- fire IRQ if FIFO is at least half-full
|
rx_irq.set <= rx_buffer.half; -- fire IRQ if FIFO is at least half-full
|
else
|
else
|
irq_rxd_o <= rx_buffer.avail; -- fire IRQ is FIFO is not empty
|
rx_irq.set <= rx_buffer.avail; -- fire IRQ is FIFO is not empty
|
end if;
|
end if;
|
end if;
|
end if;
|
|
end process irq_type;
|
|
|
|
-- interrupt arbiter --
|
|
irq_generator: process(clk_i)
|
|
begin
|
|
if rising_edge(clk_i) then
|
|
if (ctrl(ctrl_en_c) = '0') then
|
|
rx_irq.pending <= '0';
|
|
tx_irq.pending <= '0';
|
|
else
|
|
-- TX --
|
|
if (tx_irq.set = '1') and (tx_engine.done = '1') then -- evaluate IRQ condition when TX is done with current sending
|
|
tx_irq.pending <= '1';
|
|
elsif (tx_irq.clr = '1') then
|
|
tx_irq.pending <= '0';
|
|
end if;
|
|
-- RX --
|
|
if (rx_irq.set = '1') and (rx_engine.done = '1') then -- evaluate IRQ condition when RX is done with current receiving
|
|
rx_irq.pending <= '1';
|
|
elsif (rx_irq.clr = '1') then
|
|
rx_irq.pending <= '0';
|
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process irq_generator;
|
end process irq_generator;
|
|
|
|
-- IRQ requests to CPU --
|
|
irq_txd_o <= tx_irq.pending;
|
|
irq_rxd_o <= rx_irq.pending;
|
|
|
|
-- IRQ acknowledge --
|
|
tx_irq.clr <= '1' when (tx_buffer.we = '1') or ((wren = '1') and (addr = uart_id_ctrl_addr_c)) else '0'; -- write to data reg OR write to control reg
|
|
rx_irq.clr <= '1' when (rx_buffer.re = '1') or ((wren = '1') and (addr = uart_id_ctrl_addr_c)) else '0'; -- read from data reg OR write to control reg
|
|
|
|
|
-- SIMULATION Transmitter -----------------------------------------------------------------
|
-- SIMULATION Transmitter -----------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- pragma translate_off
|
-- pragma translate_off
|
-- synthesis translate_off
|
-- synthesis translate_off
|