OpenCores
URL https://opencores.org/ocsvn/potato/potato/trunk

Subversion Repositories potato

[/] [potato/] [trunk/] [soc/] [pp_soc_uart.vhd] - Blame information for rev 14

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 7 skordal
-- The Potato Processor - A simple processor for FPGAs
2
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
3
-- Report bugs and issues on <https://github.com/skordal/potato/issues>
4
 
5
library ieee;
6
use ieee.std_logic_1164.all;
7
 
8
--! @brief Simple UART module.
9
--! The following registers are defined:
10
--! 0 - Transmit data register (write-only)
11
--! 1 - Receive data register (read-only)
12
--! 2 - Status register; (read-only)
13
--!     - Bit 0: data in receive buffer
14
--!     - Bit 1: no data in transmit buffer
15
--!     - Bit 2: receive buffer full
16
--!     - Bit 3: transmit buffer full
17
--! 3 - Control register, currently unused.
18
entity pp_soc_uart is
19
        generic(
20
                FIFO_DEPTH : natural := 64;        --! Depth of the input and output FIFOs.
21
                SAMPLE_CLK_DIVISOR : natural := 54 --! Divisor used to obtain the sample clock, f_clk / (16 * baudrate).
22
        );
23
        port(
24
                clk : in std_logic;
25
                reset : in std_logic;
26
 
27
                -- UART ports:
28
                txd : out std_logic;
29
                rxd : in  std_logic;
30
 
31
                -- Interrupt signals:
32
                irq_send_buffer_empty : out std_logic;
33
                irq_data_received     : out std_logic;
34
 
35
                -- Wishbone ports:
36
                wb_adr_in  : in  std_logic_vector(1 downto 0);
37
                wb_dat_in  : in  std_logic_vector(7 downto 0);
38
                wb_dat_out : out std_logic_vector(7 downto 0);
39
                wb_we_in   : in  std_logic;
40
                wb_cyc_in  : in  std_logic;
41
                wb_stb_in  : in  std_logic;
42
                wb_ack_out : out std_logic
43
        );
44
end entity pp_soc_uart;
45
 
46
architecture behaviour of pp_soc_uart is
47
 
48
        subtype bitnumber is natural range 0 to 7;
49
 
50
        -- UART sample clock signals:
51
        signal sample_clk : std_logic;
52
 
53
        subtype sample_clk_counter_type is natural range 0 to SAMPLE_CLK_DIVISOR - 1;
54
        signal sample_clk_counter : sample_clk_counter_type := 0;
55
 
56
        -- UART receive process signals:
57
        type rx_state_type is (IDLE, RECEIVE, STOPBIT);
58
        signal rx_state : rx_state_type;
59
        signal rx_byte : std_logic_vector(7 downto 0);
60
        signal rx_current_bit : bitnumber;
61
 
62
        subtype rx_sample_counter_type is natural range 0 to 15;
63
        signal rx_sample_counter : rx_sample_counter_type;
64
        signal rx_sample_value   : rx_sample_counter_type;
65
 
66
        -- UART transmit process signals:
67
        type tx_state_type is (IDLE, TRANSMIT, STOPBIT);
68
        signal tx_state : tx_state_type;
69
        signal tx_byte : std_logic_vector(7 downto 0);
70
        signal tx_current_bit : bitnumber;
71
 
72
        -- UART transmit clock:
73
        subtype uart_tx_counter_type is natural range 0 to 15;
74
        signal uart_tx_counter : uart_tx_counter_type := 0;
75
        signal uart_tx_clk : std_logic;
76
 
77
        -- Buffer signals:
78
        signal send_buffer_full, send_buffer_empty   : std_logic;
79
        signal recv_buffer_full, recv_buffer_empty   : std_logic;
80
        signal send_buffer_input, send_buffer_output : std_logic_vector(7 downto 0);
81
        signal recv_buffer_input, recv_buffer_output : std_logic_vector(7 downto 0);
82
        signal send_buffer_push, send_buffer_pop     : std_logic := '0';
83
        signal recv_buffer_push, recv_buffer_pop     : std_logic := '0';
84
 
85
        -- Wishbone signals:
86
        type wb_state_type is (IDLE, WRITE_ACK, READ_ACK);
87
        signal wb_state : wb_state_type;
88
 
89
        signal wb_ack : std_logic; --! Wishbone acknowledge signal
90
 
91
begin
92
 
93
        irq_send_buffer_empty <= send_buffer_empty;
94
        irq_data_received <= not recv_buffer_empty;
95
 
96
        ---------- UART receive ----------
97
 
98
        recv_buffer_input <= rx_byte;
99
 
100
        uart_receive: process(clk)
101
        begin
102
                if rising_edge(clk) then
103
                        if reset = '1' then
104
                                rx_state <= IDLE;
105
                        else
106
                                case rx_state is
107
                                        when IDLE =>
108
                                                if sample_clk = '1' and rxd = '0' then
109
                                                        rx_sample_value <= rx_sample_counter;
110
                                                        rx_current_bit <= 0;
111
                                                        rx_state <= RECEIVE;
112
                                                end if;
113
                                        when RECEIVE =>
114
                                                if sample_clk = '1' and rx_sample_counter = rx_sample_value then
115
                                                        if rx_current_bit /= 7 then
116
                                                                rx_byte(rx_current_bit) <= rxd;
117
                                                                rx_current_bit <= rx_current_bit + 1;
118
                                                        else
119
                                                                rx_byte(rx_current_bit) <= rxd;
120
                                                                rx_state <= STOPBIT;
121
 
122
                                                                if recv_buffer_full = '0' then
123
                                                                        recv_buffer_push <= '1';
124
                                                                end if;
125
                                                        end if;
126
                                                end if;
127
                                        when STOPBIT =>
128
                                                recv_buffer_push <= '0';
129
 
130
                                                if sample_clk = '1' and rx_sample_counter = rx_sample_value then
131
                                                        rx_state <= IDLE;
132
                                                end if;
133
                                end case;
134
                        end if;
135
                end if;
136
        end process uart_receive;
137
 
138
        sample_counter: process(clk)
139
        begin
140
                if rising_edge(clk) then
141
                        if reset = '1' then
142
                                rx_sample_counter <= 0;
143
                        elsif sample_clk = '1' then
144
                                if rx_sample_counter = 15 then
145
                                        rx_sample_counter <= 0;
146
                                else
147
                                        rx_sample_counter <= rx_sample_counter + 1;
148
                                end if;
149
                        end if;
150
                end if;
151
        end process sample_counter;
152
 
153
        ---------- UART transmit ----------
154
 
155
        tx_byte <= send_buffer_output;
156
 
157
        uart_transmit: process(clk)
158
        begin
159
                if rising_edge(clk) then
160
                        if reset = '1' then
161
                                txd <= '1';
162
                                tx_state <= IDLE;
163
                                send_buffer_pop <= '0';
164
                                tx_current_bit <= 0;
165
                        else
166
                                case tx_state is
167
                                        when IDLE =>
168
                                                if send_buffer_empty = '0' and uart_tx_clk = '1' then
169
                                                        txd <= '0';
170
                                                        send_buffer_pop <= '1';
171
                                                        tx_current_bit <= 0;
172
                                                        tx_state <= TRANSMIT;
173
                                                elsif uart_tx_clk = '1' then
174
                                                        txd <= '1';
175
                                                end if;
176
                                        when TRANSMIT =>
177
                                                if send_buffer_pop = '1' then
178
                                                        send_buffer_pop <= '0';
179
                                                elsif uart_tx_clk = '1' and tx_current_bit = 7 then
180
                                                        txd <= tx_byte(tx_current_bit);
181
                                                        tx_state <= STOPBIT;
182
                                                elsif uart_tx_clk = '1' then
183
                                                        txd <= tx_byte(tx_current_bit);
184
                                                        tx_current_bit <= tx_current_bit + 1;
185
                                                end if;
186
                                        when STOPBIT =>
187
                                                if uart_tx_clk = '1' then
188
                                                        txd <= '1';
189
                                                        tx_state <= IDLE;
190
                                                end if;
191
                                end case;
192
                        end if;
193
                end if;
194
        end process uart_transmit;
195
 
196
        uart_tx_clock_generator: process(clk)
197
        begin
198
                if rising_edge(clk) then
199
                        if reset = '1' then
200
                                uart_tx_counter <= 0;
201
                                uart_tx_clk <= '0';
202
                        else
203
                                if sample_clk = '1' then
204
                                        if uart_tx_counter = 15 then
205
                                                uart_tx_counter <= 0;
206
                                                uart_tx_clk <= '1';
207
                                        else
208
                                                uart_tx_counter <= uart_tx_counter + 1;
209
                                                uart_tx_clk <= '0';
210
                                        end if;
211
                                else
212
                                        uart_tx_clk <= '0';
213
                                end if;
214
                        end if;
215
                end if;
216
        end process uart_tx_clock_generator;
217
 
218
        ---------- Sample clock generator ----------
219
 
220
        sample_clock_generator: process(clk)
221
        begin
222
                if rising_edge(clk) then
223
                        if reset = '1' then
224
                                sample_clk_counter <= 0;
225
                                sample_clk <= '0';
226
                        else
227
                                if sample_clk_counter = SAMPLE_CLK_DIVISOR - 1 then
228
                                        sample_clk_counter <= 0;
229
                                        sample_clk <= '1';
230
                                else
231
                                        sample_clk_counter <= sample_clk_counter + 1;
232
                                        sample_clk <= '0';
233
                                end if;
234
                        end if;
235
                end if;
236
        end process sample_clock_generator;
237
 
238
        ---------- Data Buffers ----------
239
 
240
        send_buffer: entity work.pp_fifo
241
                generic map(
242
                        DEPTH => FIFO_DEPTH,
243
                        WIDTH => 8
244
                ) port map(
245
                        clk => clk,
246
                        reset => reset,
247
                        full => send_buffer_full,
248
                        empty => send_buffer_empty,
249
                        data_in => send_buffer_input,
250
                        data_out => send_buffer_output,
251
                        push => send_buffer_push,
252
                        pop => send_buffer_pop
253
                );
254
 
255
        recv_buffer: entity work.pp_fifo
256
                generic map(
257
                        DEPTH => FIFO_DEPTH,
258
                        WIDTH => 8
259
                ) port map(
260
                        clk => clk,
261
                        reset => reset,
262
                        full => recv_buffer_full,
263
                        empty => recv_buffer_empty,
264
                        data_in => recv_buffer_input,
265
                        data_out => recv_buffer_output,
266
                        push => recv_buffer_push,
267
                        pop => recv_buffer_pop
268
                );
269
 
270
        ---------- Wishbone Interface ---------- 
271
 
272
        wb_ack_out <= wb_ack and wb_cyc_in and wb_stb_in;
273
 
274
        wishbone: process(clk)
275
        begin
276
                if rising_edge(clk) then
277
                        if reset = '1' then
278
                                wb_ack <= '0';
279
                                wb_state <= IDLE;
280
                                send_buffer_push <= '0';
281
                        else
282
                                case wb_state is
283
                                        when IDLE =>
284
                                                if wb_cyc_in = '1' and wb_stb_in = '1' then
285
                                                        if wb_we_in = '1' then -- Write to register
286
                                                                if wb_adr_in = b"00" then
287
                                                                        send_buffer_input <= wb_dat_in;
288
                                                                        send_buffer_push <= '1';
289
                                                                        wb_ack <= '1';
290
                                                                        wb_state <= WRITE_ACK;
291
                                                                else -- Invalid write, just ack and ignore
292
                                                                        wb_ack <= '1';
293
                                                                        wb_state <= WRITE_ACK;
294
                                                                end if;
295
                                                        else -- Read from register
296
                                                                if wb_adr_in = b"01" then
297
                                                                        recv_buffer_pop <= '1';
298
                                                                        wb_state <= READ_ACK;
299
                                                                elsif wb_adr_in = b"10" then
300
                                                                        wb_dat_out <= x"0" & send_buffer_full & recv_buffer_full & send_buffer_empty & not recv_buffer_empty;
301
                                                                        wb_ack <= '1';
302
                                                                        wb_state <= READ_ACK;
303
                                                                else
304
                                                                        wb_dat_out <= (others => '0');
305
                                                                        wb_ack <= '1';
306
                                                                        wb_state <= READ_ACK;
307
                                                                end if;
308
                                                        end if;
309
                                                end if;
310
                                        when WRITE_ACK =>
311
                                                send_buffer_push <= '0';
312
 
313
                                                if wb_stb_in = '0' then
314
                                                        wb_ack <= '0';
315
                                                        wb_state <= IDLE;
316
                                                end if;
317
                                        when READ_ACK =>
318
                                                if recv_buffer_pop = '1' then
319
                                                        wb_ack <= '1';
320
                                                        recv_buffer_pop <= '0';
321
                                                        wb_dat_out <= recv_buffer_output;
322
                                                end if;
323
 
324
                                                if wb_stb_in = '0' then
325
                                                        wb_ack <= '0';
326
                                                        wb_state <= IDLE;
327
                                                end if;
328
                                end case;
329
                        end if;
330
                end if;
331
        end process wishbone;
332
 
333
end architecture behaviour;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.