Merge pull request #134 from paulusmack/master
[microwatt.git] / sim_uart.vhdl
1 -- Sim console UART, provides the same interface as potato UART by
2 -- Kristian Klomsten Skordal.
3
4 library ieee;
5 use ieee.std_logic_1164.all;
6 use ieee.numeric_std.all;
7
8 library work;
9 use work.wishbone_types.all;
10 use work.sim_console.all;
11
12 --! @brief Simple UART module.
13 --! The following registers are defined:
14 --! |--------------------|--------------------------------------------|
15 --! | Address | Description |
16 --! |--------------------|--------------------------------------------|
17 --! | 0x00 | Transmit register (write-only) |
18 --! | 0x08 | Receive register (read-only) |
19 --! | 0x10 | Status register (read-only) |
20 --! | 0x18 | Sample clock divisor register (dummy) |
21 --! | 0x20 | Interrupt enable register (read/write) |
22 --! |--------------------|--------------------------------------------|
23 --!
24 --! The status register contains the following bits:
25 --! - Bit 0: receive buffer empty
26 --! - Bit 1: transmit buffer empty
27 --! - Bit 2: receive buffer full
28 --! - Bit 3: transmit buffer full
29 --!
30 --! Interrupts are enabled by setting the corresponding bit in the interrupt
31 --! enable register. The following bits are available:
32 --! - Bit 0: data received (receive buffer not empty)
33 --! - Bit 1: ready to send data (transmit buffer empty)
34 entity pp_soc_uart is
35 generic(
36 FIFO_DEPTH : natural := 64 --Unused
37 );
38 port(
39 clk : in std_logic;
40 reset : in std_logic;
41
42 -- UART ports:
43 txd : out std_logic;
44 rxd : in std_logic;
45
46 -- Wishbone ports:
47 wb_adr_in : in std_logic_vector(11 downto 0);
48 wb_dat_in : in std_logic_vector( 7 downto 0);
49 wb_dat_out : out std_logic_vector( 7 downto 0);
50 wb_we_in : in std_logic;
51 wb_cyc_in : in std_logic;
52 wb_stb_in : in std_logic;
53 wb_ack_out : out std_logic
54 );
55 end entity pp_soc_uart;
56
57 architecture behaviour of pp_soc_uart is
58
59 signal sample_clk_divisor : std_logic_vector(7 downto 0);
60
61 -- IRQ enable signals:
62 signal irq_recv_enable, irq_tx_ready_enable : std_logic := '0';
63
64 -- Wishbone signals:
65 type wb_state_type is (IDLE, WRITE_ACK, READ_ACK);
66 signal wb_state : wb_state_type;
67 signal wb_ack : std_logic; --! Wishbone acknowledge signal
68
69 begin
70
71 wb_ack_out <= wb_ack and wb_cyc_in and wb_stb_in;
72
73 wishbone: process(clk)
74 variable sim_tmp : std_logic_vector(63 downto 0);
75 begin
76 if rising_edge(clk) then
77 if reset = '1' then
78 wb_ack <= '0';
79 wb_state <= IDLE;
80 sample_clk_divisor <= (others => '0');
81 irq_recv_enable <= '0';
82 irq_tx_ready_enable <= '0';
83 else
84 case wb_state is
85 when IDLE =>
86 if wb_cyc_in = '1' and wb_stb_in = '1' then
87 if wb_we_in = '1' then -- Write to register
88 if wb_adr_in(11 downto 0) = x"000" then
89 sim_console_write(x"00000000000000" & wb_dat_in);
90 elsif wb_adr_in(11 downto 0) = x"018" then
91 sample_clk_divisor <= wb_dat_in;
92 elsif wb_adr_in(11 downto 0) = x"020" then
93 irq_recv_enable <= wb_dat_in(0);
94 irq_tx_ready_enable <= wb_dat_in(1);
95 end if;
96 wb_ack <= '1';
97 wb_state <= WRITE_ACK;
98 else -- Read from register
99 if wb_adr_in(11 downto 0) = x"008" then
100 sim_console_read(sim_tmp);
101 wb_dat_out <= sim_tmp(7 downto 0);
102 elsif wb_adr_in(11 downto 0) = x"010" then
103 sim_console_poll(sim_tmp);
104 wb_dat_out <= "00000" & sim_tmp(0) & '1' & not sim_tmp(0);
105 elsif wb_adr_in(11 downto 0) = x"018" then
106 wb_dat_out <= sample_clk_divisor;
107 elsif wb_adr_in(11 downto 0) = x"020" then
108 wb_dat_out <= (0 => irq_recv_enable,
109 1 => irq_tx_ready_enable,
110 others => '0');
111 else
112 wb_dat_out <= (others => '0');
113 end if;
114 wb_ack <= '1';
115 wb_state <= READ_ACK;
116 end if;
117 end if;
118 when WRITE_ACK|READ_ACK =>
119 if wb_stb_in = '0' then
120 wb_ack <= '0';
121 wb_state <= IDLE;
122 end if;
123 end case;
124 end if;
125 end if;
126 end process wishbone;
127
128 end architecture behaviour;