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

Subversion Repositories forwardcom

[/] [forwardcom/] [trunk/] [uart_and_fifo.sv] - Blame information for rev 91

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

Line No. Rev Author Line
1 11 Agner
//////////////////////////////////////////////////////////////////////////////////
2
// Engineer: Agner Fog
3
//
4
// Create date:    2020-11-01
5
// Last modified:  2021-07-02
6
// Module name:    uart_and_fifo
7
// Project name:   ForwardCom soft core
8
// Tool versions:  Vivado 2020.1
9
// License:        CERN-OHL-W v. 2 or later
10
// Description:    UART: RS232 serial interface
11
// 8 data bits, 1 stop bit, no parity
12
// Description:    fifo_buffer: First-in-first-out byte queue.
13
//
14
//////////////////////////////////////////////////////////////////////////////////
15
 
16
// CLOCK_FREQUENCY and BAUD_RATE defined in defines.vh:
17
`include "defines.vh"
18
 
19
// UART receiver
20
module UART_RX (
21
    input            reset,                      // clear buffer, reset everything
22
    input            clock,                      // clock at `CLOCK_RATE
23
    input            rx_in,                      // RX input
24
    output reg       receive_complete_out,       // byte received. Will be high for 1 clock cycle after the middle of the stop bit
25
    output reg       error_out,                  // transmission error. Remains high until reset in case of error
26
    output reg [7:0] byte_out                    // byte output
27
);
28
 
29
// clock count per bit
30
localparam CLKS_PER_BIT = `CLOCK_FREQUENCY / `BAUD_RATE;
31
 
32
// state names
33
localparam STATE_IDLE      = 4'b0000;            // wait for start bit
34
localparam STATE_START_BIT = 4'b0001;            // start bit detected
35
localparam STATE_DATA_0    = 4'b1000;            // read first data bit
36
localparam STATE_DATA_7    = 4'b1111;            // read last data bit
37
localparam STATE_STOP_BIT  = 4'b0010;            // read stop bit
38
 
39
reg [$clog2(CLKS_PER_BIT)-1:0] clock_counter;    // clock counter for length of one bit
40
reg [3:0] state;  // state
41
 
42
 
43
// state machine for UART receiver
44
always_ff @(posedge clock) begin
45
 
46
    if (reset) begin
47
        // reset everything
48
        state <= STATE_IDLE;
49
        receive_complete_out <= 0;
50
        error_out <= 0;
51
        clock_counter <= 0;
52
        byte_out <= 0;
53
 
54
    end else if (state == STATE_IDLE) begin
55
        // wait for start bit
56
        receive_complete_out <= 0;
57
        clock_counter <= 0;
58
        if (rx_in == 0) begin                    // Start bit detected
59
            state <= STATE_START_BIT;
60
        end
61
 
62
    end else if (state == STATE_START_BIT) begin
63
        // start bit detected. wait until middle of start bit
64
        if (clock_counter == CLKS_PER_BIT / 2) begin // middle of start bit
65
            if (rx_in == 0) begin
66
                clock_counter <= 0;              // reset counter to the middle of the start bit
67
                state     <= STATE_DATA_0;
68
            end else begin
69
                error_out <= 1;                  // error. start bit shorter than a half period. possibly wrong BAUD rate
70
                state <= STATE_IDLE;
71
            end
72
        end else begin
73
            clock_counter <= clock_counter + 1;  // count time until next bit
74
        end
75
 
76
    end else if (state[3]) begin                 // this covers STATE_DATA_0 ... STATE_DATA_7
77
        // read eight data bits
78
 
79
        if (clock_counter < CLKS_PER_BIT-1) begin
80
            clock_counter <= clock_counter + 1;  // count time until next bit
81
        end else begin                           // middle of data bit. sample bit and go to next state
82
            clock_counter        <= 0;
83
            byte_out[state[2:0]] <= rx_in;       // save data bit
84
            if (state == STATE_DATA_7) state <= STATE_STOP_BIT; // next state is stop bit
85
            else state <= state + 1;                            // next data bit
86
        end
87
 
88
    end else if (state == STATE_STOP_BIT) begin
89
        // expecting stop bit
90
        if (clock_counter < CLKS_PER_BIT-1) begin
91
            clock_counter <= clock_counter + 1;  // count time until stop bit
92
        end else begin                           // middle of stop bit
93
            if (rx_in == 0) begin                // error: stop bit missing
94
                error_out <= 1;
95
                state <= STATE_IDLE;
96
            end else begin
97
                receive_complete_out <= 1;       // byte received successfully
98
                clock_counter <= 0;
99
                // We are in the middle of the stop bit.
100
                // Go to state IDLE while waiting for a possible next start bit.
101
                // This is expected to last a half period
102
                state <= STATE_IDLE;
103
            end
104
        end
105
    end else begin
106
        // Error. undefined state
107
        error_out <= 1;
108
        state <= STATE_IDLE;
109
    end
110
end
111
endmodule // UART_RX
112
 
113
 
114
// UART transmitter
115
module UART_TX (
116
   input       reset,                            // reset
117
   input       clock,                            // clock at `CLOCK_RATE
118
   input       start_in,                         // command to send one byte
119
   input [7:0] byte_in,                          // byte input
120
   output reg  active_out,                       // is busy
121
   output reg  tx_out,                           // TX output
122
   output reg  done_out                          // will be high for one clock cycle shortly before the end of the stop bit
123
   );                                            // You may use done_out as a signal to prepare the next byte
124
 
125
// clock count per bit
126
localparam CLKS_PER_BIT = `CLOCK_FREQUENCY / `BAUD_RATE;
127
 
128
// state names
129
localparam STATE_IDLE      = 4'b0000;            // wait for start bit
130
localparam STATE_START_BIT = 4'b0001;            // start bit detected
131
localparam STATE_DATA_0    = 4'b1000;            // read first data bit
132
localparam STATE_DATA_7    = 4'b1111;            // read last data bit
133
localparam STATE_STOP_BIT  = 4'b0010;            // read stop bit
134
 
135
reg [3:0] state;                                 // state
136
reg [$clog2(CLKS_PER_BIT)-1:0] clock_counter;    // clock counter for length of one bit
137
reg [7:0] byte_data;                             // copy of byte to transmit
138
 
139
 
140
// state machine
141
always_ff @(posedge clock) begin
142
    if (reset) begin
143
        // reset everything
144
        state <= STATE_IDLE;
145
        clock_counter <= 0;
146
        active_out    <= 0;
147
        done_out      <= 0;
148
        tx_out        <= 1;                      // output must be high when idle
149
 
150
    end else if (state == STATE_IDLE) begin
151
        clock_counter <= 0;
152
        done_out      <= 0;
153
        tx_out        <= 1;                      // output must be high when idle
154
        if (start_in) begin                      // start sending a byte
155
            active_out <= 1;
156
            byte_data  <= byte_in;               // copy input byte
157
            state <= STATE_START_BIT;
158
        end
159
 
160
    end else if (state == STATE_START_BIT) begin
161
        // start bit must be 0
162
        tx_out <= 0;
163
 
164
        // Wait for start bit to finish
165
        if (clock_counter < CLKS_PER_BIT-1) begin
166
            clock_counter <= clock_counter + 1;
167
        end else begin
168
            clock_counter <= 0;
169
            state <= STATE_DATA_0;               // go to first data bit
170
        end
171
 
172
    end else if (state[3]) begin                 // this covers STATE_DATA_0 ... STATE_DATA_7
173
        // write eight data bits
174
        tx_out <= byte_data[state[2:0]];         // send one data bit
175
 
176
        // Wait for data bit to finish
177
        if (clock_counter < CLKS_PER_BIT-1) begin
178
            clock_counter <= clock_counter + 1;
179
        end else begin
180
            clock_counter <= 0;
181
            if (state == STATE_DATA_7) state <= STATE_STOP_BIT; // next bit is stop bit
182
            else state <= state + 1;                            // next bit is data bit
183
        end
184
 
185
    end else if (state == STATE_STOP_BIT) begin
186
        // send stop bit
187
        tx_out <= 1;                             // stop bit must be 1
188
 
189
        // send request for next byte shortly before finished with this byte
190
        if (clock_counter == CLKS_PER_BIT-4) begin
191
            done_out <= 1;                       // set done_out high for one clock cycle to request next byte from buffer
192
        end else begin
193
            done_out <= 0;
194
        end
195
 
196
        // Wait for stop bit to finish
197
        if (clock_counter < CLKS_PER_BIT-1) begin
198
            clock_counter <= clock_counter + 1;
199
        end else begin
200
            clock_counter <= 0;
201
            begin
202
                active_out <= 0;
203
                state      <= STATE_IDLE;        // wait at least one clock for next start_in signal
204
            end
205
        end
206
 
207
    end else begin
208
        // illegal state. reset
209
        state <= STATE_IDLE;
210
        clock_counter <= 0;
211
        active_out <= 0;
212
        done_out <= 0;
213
        tx_out   <= 1;
214
    end
215
end
216
 
217
 
218
endmodule
219
 
220
 
221
/******************************************************************************
222
* First-in-first-out byte queue.
223
*
224
* This queue is implemented as a circular buffer.
225
* The size can be any power of 2.
226
* It may be implemented as distributed RAM or block RAM if the size is large.
227
* (Vivado does this automatically)
228
* It is possible to read and write simultaneously as long as the queue is not
229
* empty. It is not possible to pass a byte directly from input to output without
230
* a delay of two clocks if the buffer is empty.
231
* The input, byte_in, is placed at the tail of the queue at the rising edge of clock.
232
* The output, byte_out, is prefetched so that it is ready to read before the
233
* clock edge. The read_next input signal will remove one byte from the head of
234
* the queue and put the next byte into byte_out.
235
* The data_ready_out output tells if it is possible to read a byte
236
******************************************************************************/
237
 
238
module fifo_buffer
239
#(parameter size_log2 = 10)                      // buffer size = 2**size_log2 bytes
240
(
241
    input            reset,                      // clear buffer and reset error condition
242
    input            reset_error,                // reset error condition
243
    input            clock,                      // clock at `CLOCK_RATE
244
    input            read_next,                  // read next byte from buffer
245
    input            write,                      // write one byte to buffer
246
    input  [7:0]     byte_in,                    // serial byte input
247
    output reg [7:0] byte_out,                   // serial byte output prefetched
248
    output reg       data_ready_out,             // the buffer contains at least one byte
249
    output reg       overflow,                   // attempt to write to full buffer
250
    output reg       underflow,                  // attempt to read from empty buffer
251
    output reg [size_log2-1:0] num               // number of bytes currently in buffer
252
);
253
 
254
reg [7:0] buffer[0 : (2**size_log2)-1];          // circular buffer
255
reg [size_log2-1:0] head;                        // pointer to head position where bytes are extracted
256
reg [size_log2-1:0] tail;                        // pointer to tail position where bytes are inserted
257
 
258
logic [size_log2-1:0] head_plus_1;               // (head + 1) modulo 2**(size_log2)
259
 
260
 
261
always_ff @(posedge clock) begin
262
 
263
    if (reset) begin
264
        // clear buffer, reset everything
265
        head <= 0;
266
        tail <= 0;
267
        byte_out <= 0;
268
        num <= 0;
269
        data_ready_out <= 0;
270
        overflow <= 0;
271
        underflow <= 0;
272
    end else if (reset_error) begin
273
        // reset error flags
274
        overflow <= 0;
275
        underflow <= 0;
276
    end else begin
277
        if (write) begin
278
            // insert a byte in buffer
279
            if (&num) begin
280
                // buffer is full
281
                overflow <= 1;
282
            end else begin
283
                // buffer is not full
284
                buffer[tail] <= byte_in;         // insert at tail position
285
 
286
                // advance tail
287
                tail <= tail + 1;                // this will wrap around because size is a power of 2
288
                // count bytes in buffer
289
                if (!read_next) begin
290
                    num <= num + 1;
291
                end
292
            end
293
        end
294
 
295
        // make output ready
296
        if (num == 0 || read_next && num == 1) begin
297
            byte_out <= 0;
298
            data_ready_out <= 0;
299
        end else if (read_next) begin
300
            byte_out <= buffer[head_plus_1];     // read byte and make next byte ready from head position
301
            data_ready_out <= 1;
302
        end else begin
303
            byte_out <= buffer[head];            // make byte read ready from head position
304
            data_ready_out <= 1;
305
        end
306
 
307
        if (read_next) begin
308
            // read a byte from buffer
309
            if (~data_ready_out) begin           // reading from empty buffer
310
                underflow <= 1;
311
            end else begin
312
                // advance head
313
                head <= head_plus_1;             // this will wrap around because size is a power of 2
314
                // count bytes in buffer
315
                if (!write) begin
316
                    num <= num - 1;
317
                end
318
            end
319
        end
320
    end
321
end
322
 
323
 
324
always_comb begin
325
    head_plus_1 = head + 1;                      // (head + 1) with size_log2 bits
326
end
327
 
328
endmodule

powered by: WebSVN 2.1.0

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