1
0
mirror of https://github.com/pConst/basic_verilog.git synced 2025-01-14 06:42:54 +08:00
basic_verilog/uart_rx_shifter.sv

106 lines
2.8 KiB
Systemverilog

//------------------------------------------------------------------------------
// uart_rx_shifter.sv
// Konstantin Pavlov, pavlovconst@gmail.com
//------------------------------------------------------------------------------
// INFO ------------------------------------------------------------------------
// UART-like shifter for simple synchronous messaging inside the FPGA or between FPGAs
// See also `uart_tx_shifter.sv` for TX part
//
// TX and RX parts should share one clock source
// Capable of continious stream transfer when tx_start is held constant 1'b1
// Any reasonable start bit count,data bit count, stop bit count
//
/* --- INSTANTIATION TEMPLATE BEGIN ---
uart_rx_shifter #(
.START_BITS( 1 ),
.DATA_BITS( 8 ),
.STOP_BITS( 2 ),
.SYNCHRONIZE_RXD( 0 ) // 0 - disabled; 1 - enabled
) rx1 (
.clk( clk ),
.nrst( 1'b1 ),
.rx_data( ),
.rx_valid( ),
.rxd( )
);
--- INSTANTIATION TEMPLATE END ---*/
module uart_rx_shifter #(
bit [7:0] START_BITS = 1, // must be >=1
bit [7:0] DATA_BITS = 4, // must be >=1
bit [7:0] STOP_BITS = 2, // must be >=1
bit SYNCHRONIZE_RXD = 0 // its better to synchronize when rxd input
// is actually an FPGA pin
)(
input clk, // transmitter and receiver should use
input nrst, // the same clock
output logic [DATA_BITS-1:0] rx_data = '0, // output data
output logic rx_valid = '0, // read strobe
input rxd
);
localparam TOTAL_BITS = START_BITS + DATA_BITS + STOP_BITS;
logic [TOTAL_BITS-1:0] rx_data_buf = '1;
logic rxd_sync;
delay #(
.LENGTH( 2 ),
.WIDTH( 1 )
) rxd_SYNC_ATTR (
.clk( clk ),
.nrst( 1'b1 ),
.ena( 1'b1 ),
.in( rxd ),
.out( rxd_sync )
);
logic start_detected;
assign start_detected = ~|rx_data_buf[DATA_BITS+STOP_BITS+:START_BITS];
logic stop_detected;
assign stop_detected = &rx_data_buf[0+:STOP_BITS];
logic data_valid;
assign data_valid = start_detected && stop_detected;
always_ff @(posedge clk) begin
if( ~nrst ) begin
rx_data_buf[TOTAL_BITS-1:0] <= '1;
rx_data[DATA_BITS-1:0] <= '0;
rx_valid <= 1'b0;
end else begin
if( data_valid ) begin
// clear rx_data_buf if valid message is already detected
rx_data_buf[TOTAL_BITS-1:0] <= { {(TOTAL_BITS-1){1'b1}},
(SYNCHRONIZE_RXD ? rxd_sync : rxd) };
end else begin
// simple shifter, MSB first
rx_data_buf[TOTAL_BITS-1:0] <= { rx_data_buf[TOTAL_BITS-2:0],
(SYNCHRONIZE_RXD ? rxd_sync : rxd) };
end
// buffering valid messages
if( data_valid ) begin
rx_data[DATA_BITS-1:0] <= rx_data_buf[STOP_BITS+:DATA_BITS];
rx_valid <= 1'b1;
end else begin
rx_valid <= 1'b0;
end
end
end
endmodule