You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
4.1 KiB
VHDL
136 lines
4.1 KiB
VHDL
-- Sim console UART, provides the same interface as potato UART by
|
|
-- Kristian Klomsten Skordal.
|
|
|
|
library ieee;
|
|
use ieee.std_logic_1164.all;
|
|
use ieee.numeric_std.all;
|
|
|
|
library work;
|
|
use work.wishbone_types.all;
|
|
use work.sim_console.all;
|
|
|
|
--! @brief Simple UART module.
|
|
--! The following registers are defined:
|
|
--! |--------------------|--------------------------------------------|
|
|
--! | Address | Description |
|
|
--! |--------------------|--------------------------------------------|
|
|
--! | 0x00 | Transmit register (write-only) |
|
|
--! | 0x08 | Receive register (read-only) |
|
|
--! | 0x10 | Status register (read-only) |
|
|
--! | 0x18 | Sample clock divisor register (dummy) |
|
|
--! | 0x20 | Interrupt enable register (read/write) |
|
|
--! |--------------------|--------------------------------------------|
|
|
--!
|
|
--! The status register contains the following bits:
|
|
--! - Bit 0: receive buffer empty
|
|
--! - Bit 1: transmit buffer empty
|
|
--! - Bit 2: receive buffer full
|
|
--! - Bit 3: transmit buffer full
|
|
--!
|
|
--! Interrupts are enabled by setting the corresponding bit in the interrupt
|
|
--! enable register. The following bits are available:
|
|
--! - Bit 0: data received (receive buffer not empty)
|
|
--! - Bit 1: ready to send data (transmit buffer empty)
|
|
entity pp_soc_uart is
|
|
generic(
|
|
FIFO_DEPTH : natural := 64 --Unused
|
|
);
|
|
port(
|
|
clk : in std_logic;
|
|
reset : in std_logic;
|
|
|
|
-- UART ports:
|
|
txd : out std_logic;
|
|
rxd : in std_logic;
|
|
|
|
-- Interrupt signal:
|
|
irq : out std_logic;
|
|
|
|
-- Wishbone ports:
|
|
wb_adr_in : in std_logic_vector(11 downto 0);
|
|
wb_dat_in : in std_logic_vector( 7 downto 0);
|
|
wb_dat_out : out std_logic_vector( 7 downto 0);
|
|
wb_we_in : in std_logic;
|
|
wb_cyc_in : in std_logic;
|
|
wb_stb_in : in std_logic;
|
|
wb_ack_out : out std_logic
|
|
);
|
|
end entity pp_soc_uart;
|
|
|
|
architecture behaviour of pp_soc_uart is
|
|
|
|
signal sample_clk_divisor : std_logic_vector(7 downto 0);
|
|
|
|
-- IRQ enable signals:
|
|
signal irq_recv_enable, irq_tx_ready_enable : std_logic := '0';
|
|
|
|
-- Wishbone signals:
|
|
type wb_state_type is (IDLE, WRITE_ACK, READ_ACK);
|
|
signal wb_state : wb_state_type;
|
|
signal wb_ack : std_logic; --! Wishbone acknowledge signal
|
|
|
|
begin
|
|
|
|
wb_ack_out <= wb_ack and wb_cyc_in and wb_stb_in;
|
|
|
|
-- For the sim console, the transmit buffer is always empty, so always
|
|
-- interrupt if enabled. No recieve interrupt.
|
|
irq <= irq_tx_ready_enable;
|
|
|
|
wishbone: process(clk)
|
|
variable sim_tmp : std_logic_vector(63 downto 0);
|
|
begin
|
|
if rising_edge(clk) then
|
|
if reset = '1' then
|
|
wb_ack <= '0';
|
|
wb_state <= IDLE;
|
|
sample_clk_divisor <= (others => '0');
|
|
irq_recv_enable <= '0';
|
|
irq_tx_ready_enable <= '0';
|
|
else
|
|
case wb_state is
|
|
when IDLE =>
|
|
if wb_cyc_in = '1' and wb_stb_in = '1' then
|
|
if wb_we_in = '1' then -- Write to register
|
|
if wb_adr_in(11 downto 0) = x"000" then
|
|
sim_console_write(x"00000000000000" & wb_dat_in);
|
|
elsif wb_adr_in(11 downto 0) = x"018" then
|
|
sample_clk_divisor <= wb_dat_in;
|
|
elsif wb_adr_in(11 downto 0) = x"020" then
|
|
irq_recv_enable <= wb_dat_in(0);
|
|
irq_tx_ready_enable <= wb_dat_in(1);
|
|
end if;
|
|
wb_ack <= '1';
|
|
wb_state <= WRITE_ACK;
|
|
else -- Read from register
|
|
if wb_adr_in(11 downto 0) = x"008" then
|
|
sim_console_read(sim_tmp);
|
|
wb_dat_out <= sim_tmp(7 downto 0);
|
|
elsif wb_adr_in(11 downto 0) = x"010" then
|
|
sim_console_poll(sim_tmp);
|
|
wb_dat_out <= "00000" & sim_tmp(0) & '1' & not sim_tmp(0);
|
|
elsif wb_adr_in(11 downto 0) = x"018" then
|
|
wb_dat_out <= sample_clk_divisor;
|
|
elsif wb_adr_in(11 downto 0) = x"020" then
|
|
wb_dat_out <= (0 => irq_recv_enable,
|
|
1 => irq_tx_ready_enable,
|
|
others => '0');
|
|
else
|
|
wb_dat_out <= (others => '0');
|
|
end if;
|
|
wb_ack <= '1';
|
|
wb_state <= READ_ACK;
|
|
end if;
|
|
end if;
|
|
when WRITE_ACK|READ_ACK =>
|
|
if wb_stb_in = '0' then
|
|
wb_ack <= '0';
|
|
wb_state <= IDLE;
|
|
end if;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
end process wishbone;
|
|
|
|
end architecture behaviour;
|