URL
https://opencores.org/ocsvn/forwardcom/forwardcom/trunk
Subversion Repositories forwardcom
[/] [forwardcom/] [trunk/] [uart_and_fifo.sv] - Rev 167
Go to most recent revision | Compare with Previous | Blame | View Log
//////////////////////////////////////////////////////////////////////////////////// Engineer: Agner Fog//// Create date: 2020-11-01// Last modified: 2021-07-02// Module name: uart_and_fifo// Project name: ForwardCom soft core// Tool versions: Vivado 2020.1// License: CERN-OHL-W v. 2 or later// Description: UART: RS232 serial interface// 8 data bits, 1 stop bit, no parity// Description: fifo_buffer: First-in-first-out byte queue.////////////////////////////////////////////////////////////////////////////////////// CLOCK_FREQUENCY and BAUD_RATE defined in defines.vh:`include "defines.vh"// UART receivermodule UART_RX (input reset, // clear buffer, reset everythinginput clock, // clock at `CLOCK_RATEinput rx_in, // RX inputoutput reg receive_complete_out, // byte received. Will be high for 1 clock cycle after the middle of the stop bitoutput reg error_out, // transmission error. Remains high until reset in case of erroroutput reg [7:0] byte_out // byte output);// clock count per bitlocalparam CLKS_PER_BIT = `CLOCK_FREQUENCY / `BAUD_RATE;// state nameslocalparam STATE_IDLE = 4'b0000; // wait for start bitlocalparam STATE_START_BIT = 4'b0001; // start bit detectedlocalparam STATE_DATA_0 = 4'b1000; // read first data bitlocalparam STATE_DATA_7 = 4'b1111; // read last data bitlocalparam STATE_STOP_BIT = 4'b0010; // read stop bitreg [$clog2(CLKS_PER_BIT)-1:0] clock_counter; // clock counter for length of one bitreg [3:0] state; // state// state machine for UART receiveralways_ff @(posedge clock) beginif (reset) begin// reset everythingstate <= STATE_IDLE;receive_complete_out <= 0;error_out <= 0;clock_counter <= 0;byte_out <= 0;end else if (state == STATE_IDLE) begin// wait for start bitreceive_complete_out <= 0;clock_counter <= 0;if (rx_in == 0) begin // Start bit detectedstate <= STATE_START_BIT;endend else if (state == STATE_START_BIT) begin// start bit detected. wait until middle of start bitif (clock_counter == CLKS_PER_BIT / 2) begin // middle of start bitif (rx_in == 0) beginclock_counter <= 0; // reset counter to the middle of the start bitstate <= STATE_DATA_0;end else beginerror_out <= 1; // error. start bit shorter than a half period. possibly wrong BAUD ratestate <= STATE_IDLE;endend else beginclock_counter <= clock_counter + 1; // count time until next bitendend else if (state[3]) begin // this covers STATE_DATA_0 ... STATE_DATA_7// read eight data bitsif (clock_counter < CLKS_PER_BIT-1) beginclock_counter <= clock_counter + 1; // count time until next bitend else begin // middle of data bit. sample bit and go to next stateclock_counter <= 0;byte_out[state[2:0]] <= rx_in; // save data bitif (state == STATE_DATA_7) state <= STATE_STOP_BIT; // next state is stop bitelse state <= state + 1; // next data bitendend else if (state == STATE_STOP_BIT) begin// expecting stop bitif (clock_counter < CLKS_PER_BIT-1) beginclock_counter <= clock_counter + 1; // count time until stop bitend else begin // middle of stop bitif (rx_in == 0) begin // error: stop bit missingerror_out <= 1;state <= STATE_IDLE;end else beginreceive_complete_out <= 1; // byte received successfullyclock_counter <= 0;// We are in the middle of the stop bit.// Go to state IDLE while waiting for a possible next start bit.// This is expected to last a half periodstate <= STATE_IDLE;endendend else begin// Error. undefined stateerror_out <= 1;state <= STATE_IDLE;endendendmodule // UART_RX// UART transmittermodule UART_TX (input reset, // resetinput clock, // clock at `CLOCK_RATEinput start_in, // command to send one byteinput [7:0] byte_in, // byte inputoutput reg active_out, // is busyoutput reg tx_out, // TX outputoutput reg done_out // will be high for one clock cycle shortly before the end of the stop bit); // You may use done_out as a signal to prepare the next byte// clock count per bitlocalparam CLKS_PER_BIT = `CLOCK_FREQUENCY / `BAUD_RATE;// state nameslocalparam STATE_IDLE = 4'b0000; // wait for start bitlocalparam STATE_START_BIT = 4'b0001; // start bit detectedlocalparam STATE_DATA_0 = 4'b1000; // read first data bitlocalparam STATE_DATA_7 = 4'b1111; // read last data bitlocalparam STATE_STOP_BIT = 4'b0010; // read stop bitreg [3:0] state; // statereg [$clog2(CLKS_PER_BIT)-1:0] clock_counter; // clock counter for length of one bitreg [7:0] byte_data; // copy of byte to transmit// state machinealways_ff @(posedge clock) beginif (reset) begin// reset everythingstate <= STATE_IDLE;clock_counter <= 0;active_out <= 0;done_out <= 0;tx_out <= 1; // output must be high when idleend else if (state == STATE_IDLE) beginclock_counter <= 0;done_out <= 0;tx_out <= 1; // output must be high when idleif (start_in) begin // start sending a byteactive_out <= 1;byte_data <= byte_in; // copy input bytestate <= STATE_START_BIT;endend else if (state == STATE_START_BIT) begin// start bit must be 0tx_out <= 0;// Wait for start bit to finishif (clock_counter < CLKS_PER_BIT-1) beginclock_counter <= clock_counter + 1;end else beginclock_counter <= 0;state <= STATE_DATA_0; // go to first data bitendend else if (state[3]) begin // this covers STATE_DATA_0 ... STATE_DATA_7// write eight data bitstx_out <= byte_data[state[2:0]]; // send one data bit// Wait for data bit to finishif (clock_counter < CLKS_PER_BIT-1) beginclock_counter <= clock_counter + 1;end else beginclock_counter <= 0;if (state == STATE_DATA_7) state <= STATE_STOP_BIT; // next bit is stop bitelse state <= state + 1; // next bit is data bitendend else if (state == STATE_STOP_BIT) begin// send stop bittx_out <= 1; // stop bit must be 1// send request for next byte shortly before finished with this byteif (clock_counter == CLKS_PER_BIT-4) begindone_out <= 1; // set done_out high for one clock cycle to request next byte from bufferend else begindone_out <= 0;end// Wait for stop bit to finishif (clock_counter < CLKS_PER_BIT-1) beginclock_counter <= clock_counter + 1;end else beginclock_counter <= 0;beginactive_out <= 0;state <= STATE_IDLE; // wait at least one clock for next start_in signalendendend else begin// illegal state. resetstate <= STATE_IDLE;clock_counter <= 0;active_out <= 0;done_out <= 0;tx_out <= 1;endendendmodule/******************************************************************************* First-in-first-out byte queue.** This queue is implemented as a circular buffer.* The size can be any power of 2.* It may be implemented as distributed RAM or block RAM if the size is large.* (Vivado does this automatically)* It is possible to read and write simultaneously as long as the queue is not* empty. It is not possible to pass a byte directly from input to output without* a delay of two clocks if the buffer is empty.* The input, byte_in, is placed at the tail of the queue at the rising edge of clock.* The output, byte_out, is prefetched so that it is ready to read before the* clock edge. The read_next input signal will remove one byte from the head of* the queue and put the next byte into byte_out.* The data_ready_out output tells if it is possible to read a byte******************************************************************************/module fifo_buffer#(parameter size_log2 = 10) // buffer size = 2**size_log2 bytes(input reset, // clear buffer and reset error conditioninput reset_error, // reset error conditioninput clock, // clock at `CLOCK_RATEinput read_next, // read next byte from bufferinput write, // write one byte to bufferinput [7:0] byte_in, // serial byte inputoutput reg [7:0] byte_out, // serial byte output prefetchedoutput reg data_ready_out, // the buffer contains at least one byteoutput reg overflow, // attempt to write to full bufferoutput reg underflow, // attempt to read from empty bufferoutput reg [size_log2-1:0] num // number of bytes currently in buffer);reg [7:0] buffer[0 : (2**size_log2)-1]; // circular bufferreg [size_log2-1:0] head; // pointer to head position where bytes are extractedreg [size_log2-1:0] tail; // pointer to tail position where bytes are insertedlogic [size_log2-1:0] head_plus_1; // (head + 1) modulo 2**(size_log2)always_ff @(posedge clock) beginif (reset) begin// clear buffer, reset everythinghead <= 0;tail <= 0;byte_out <= 0;num <= 0;data_ready_out <= 0;overflow <= 0;underflow <= 0;end else if (reset_error) begin// reset error flagsoverflow <= 0;underflow <= 0;end else beginif (write) begin// insert a byte in bufferif (&num) begin// buffer is fulloverflow <= 1;end else begin// buffer is not fullbuffer[tail] <= byte_in; // insert at tail position// advance tailtail <= tail + 1; // this will wrap around because size is a power of 2// count bytes in bufferif (!read_next) beginnum <= num + 1;endendend// make output readyif (num == 0 || read_next && num == 1) beginbyte_out <= 0;data_ready_out <= 0;end else if (read_next) beginbyte_out <= buffer[head_plus_1]; // read byte and make next byte ready from head positiondata_ready_out <= 1;end else beginbyte_out <= buffer[head]; // make byte read ready from head positiondata_ready_out <= 1;endif (read_next) begin// read a byte from bufferif (~data_ready_out) begin // reading from empty bufferunderflow <= 1;end else begin// advance headhead <= head_plus_1; // this will wrap around because size is a power of 2// count bytes in bufferif (!write) beginnum <= num - 1;endendendendendalways_comb beginhead_plus_1 = head + 1; // (head + 1) with size_log2 bitsendendmodule
Go to most recent revision | Compare with Previous | Blame | View Log
