forked from antonblanchard/microwatt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sim_pp_uart.vhdl
135 lines (120 loc) · 4.12 KB
/
sim_pp_uart.vhdl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
-- 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;