URL
https://opencores.org/ocsvn/uart6551/uart6551/trunk
Subversion Repositories uart6551
[/] [uart6551/] [trunk/] [trunk/] [rtl/] [uart6551Rx_x12.sv] - Rev 6
Compare with Previous | Blame | View Log
// ============================================================================
// __
// \\__/ o\ (C) 2005-2022 Robert Finch, Waterloo
// \ __ / All rights reserved.
// \/_// robfinch<remove>@finitron.ca
// ||
//
//
// BSD 3-Clause License
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ============================================================================
//
`define IDLE 0
`define CNT 1
module uart6551Rx_x12(rst, clk,
cyc, cs, wr, dout, ack,
fifoEnable, fifoClear, clearGErr,
parityCtrl, frameSize, stop_bits, wordLength, baud16x_ce, clear, rxd,
full, empty, frameErr, overrun, parityErr, break_o, gerr, qcnt, cnt, bitStream);
input rst;
input clk;
input cyc; // valid bus cycle
input cs; // core select
input wr; // read reciever
output [11:0] dout; // fifo data out
output ack;
input fifoEnable; // enable the fifo
input fifoClear;
input clearGErr; // clear global error
input [2:0] parityCtrl;
input [8:0] frameSize; // frame count
input [2:0] stop_bits;
input [3:0] wordLength;
input baud16x_ce; // baud rate clock enable
input clear; // clear reciever
input rxd; // external serial input
output full; // receive fifo full
output empty; // receiver fifo is empty
output frameErr; // framing error
output overrun; // receiver overrun
output parityErr; // parity error
output break_o; // break detected
output gerr; // global error indicator
output [5:0] qcnt; // count of number of words queued
output [10:0] cnt; // receiver counter
output bitStream; // received bit stream
//0 - simple sampling at middle of symbol period
//>0 - sampling of 3 middle ticks of sumbol perion and results as majority
parameter SamplerStyle = 0;
reg overrun;
reg [10:0] cnt; // sample bit rate counter / timeout counter
reg [14:0] rx_data; // working receive data register
reg [13:0] t4; // data minus stop bit(s)
reg [11:0] t3; // data minus parity bit and start bit
reg [11:0] t5;
reg [3:0] shft_amt;
reg p1;
reg gerr; // global error status
reg perr; // parity error
reg ferr = 1'b0; // framing error
wire bz; // break detected
reg state; // state machine
reg wf; // fifo write
wire empty;
reg didRd;
wire [11:0] dout1;
reg full1;
wire fifoFull, fifoEmpty;
ack_gen #(
.READ_STAGES(1),
.WRITE_STAGES(0),
.REGISTER_OUTPUT(1)
) uag1
(
.rst_i(rst),
.clk_i(clk),
.ce_i(1'b1),
.i(cs & cyc & ~wr),
.we_i(cs & cyc & wr),
.o(ack),
.rid_i(0),
.wid_i(0),
.rid_o(),
.wid_o()
);
wire pe_rd, pe_wf;
edge_det ued1 (.rst(rst), .clk(clk), .ce(1'b1), .i(cs & cyc & ~wr), .pe(pe_rd), .ne(), .ee());
edge_det ued2 (.rst(rst), .clk(clk), .ce(1'b1), .i(wf), .pe(pe_wf), .ne(), .ee());
assign bitStream = rx_data[14];
assign bz = t3==12'd0;
wire rdf = fifoEnable ? pe_rd : pe_wf;
// Distributed RAM fifo (vendor supplied):
// First word fall-through
// 64 entries deep
// 15 bits wide
uart6551RxFifo uf1
(
.clk(clk),
.srst(rst|clear|fifoClear),
.wr_en(wf),
.rd_en(rdf),
.din({bz,perr,ferr,t3}),
.dout({break_o,parityErr,frameErr,dout1}),
.data_count(qcnt),
.full(fifoFull),
.empty(fifoEmpty)
);
assign dout = fifoEnable ? dout1 : t5;
assign empty = fifoEnable ? fifoEmpty : ~full1;
assign full = fifoEnable ? fifoFull : full1;
// compute 1/2 the length of the last bit
// needed for framing error detection
reg [8:0] halfLastBit;
always_ff @(posedge clk)
if (stop_bits==3'd3) // 1.5 stop bits ?
halfLastBit <= 9'd8;
else
halfLastBit <= 9'd16;
reg [8:0] fhb;
always_ff @(posedge clk)
fhb <= frameSize-halfLastBit;
// record a global error status
always_ff @(posedge clk)
if (rst)
gerr <= 0;
else begin
if (clearGErr)
gerr <= perr | ferr | bz;
else
gerr <= gerr | perr | ferr | bz;
end
// right align data for word length, strip start bit
// depending on the word length, the first few bits in the
// recieve shift register will be invalid because the shift
// register shifts from MSB to LSB and shorter frames
// won't shift as far towards the LSB.
always_ff @(posedge clk)
shft_amt <= (5'd16 - (wordLength + ({stop_bits[3],~stop_bits[3]}) + parityCtrl[0]));
always_comb
t4 <= rx_data >> shft_amt;
// grab the parity bit
// Note the data is right aligned
always_comb
p1 <= t4[wordLength];
// strip off parity, stop
integer n2;
always_comb
for (n2 = 0; n2 < 12; n2 = n2 + 1)
if (n2 < wordLength)
t3[n2] <= t4[n2];
else
t3[n2] <= 1'b0;
// detect a parity err
always_comb begin
case (parityCtrl)
3'b001: perr <= p1 != ~^t3; // odd parity
3'b011: perr <= p1 != ^t3; // even parity
default: perr <= 0;
endcase
end
// Three stage synchronizer to synchronize incoming data to
// the local clock (avoids metastability).
reg [5:0] rxdd /* synthesis ramstyle = "logic" */; // synchronizer flops
reg rxdsmp; // majority samples
reg rdxstart; // for majority style sample solid 3tik-wide sample
reg [1:0] rxdsum [0:1];
always_ff @(posedge clk)
if (baud16x_ce) begin
rxdd <= {rxdd[4:0],rxd};
if (SamplerStyle == 0) begin
rxdsmp <= rxdd[3];
rdxstart <= rxdd[4]&~rxdd[3];
end
else begin
rxdsum[1] <= rxdsum[0];
rxdsum[0] <= {1'b0,rxdd[3]} + {1'b0,rxdd[4]} + {1'b0,rxdd[5]};
rxdsmp <= rxdsum[1] > 2'd1;
rdxstart <= (rxdsum[0] == 2'b00) & (rxdsum[1] == 2'b11);
end
end
always_ff @(posedge clk)
if (rst)
state <= `IDLE;
else begin
if (clear)
state <= `IDLE;
else if (baud16x_ce) begin
case (state)
// Sit in the idle state until a start bit is
// detected.
`IDLE:
if (rdxstart)
state <= `CNT;
`CNT:
begin
// Switch back to the idle state a little
// bit too soon.
if (cnt[8:2]==frameSize[8:2])
state <= `IDLE;
// On start bit check make sure the start
// bit is low, otherwise go back to the
// idle state because it's a false start.
if (cnt[8:0]==8'h07) begin
if (rxdsmp)
state <= `IDLE;
end
end
endcase
end
end
always_ff @(posedge clk)
if (rst)
cnt <= 9'h00;
else begin
if (clear)
cnt <= 9'h00;
else if (baud16x_ce) begin
cnt <= cnt + 2'h1;
case (state)
`IDLE:
begin
// reset counter on read of reciever
// (resets timeout count).
if (didRd)
cnt <= 9'h0;
if (rdxstart)
cnt <= 9'h0;
end
default: ;
endcase
end
end
always_ff @(posedge clk)
if (rst)
wf <= 1'b0;
else begin
// Clear write flag
wf <= 1'b0;
if (baud16x_ce) begin
case (state)
`CNT:
// End of the frame ?
// - write data to fifo
if (cnt[8:0]==fhb) begin
if (!full)
wf <= 1'b1;
end
default: ;
endcase
end
end
always_ff @(posedge clk)
if (rst)
t5 <= 1'b0;
else begin
if (pe_wf)
t5 <= t3;
end
always_ff @(posedge clk)
if (rst)
full1 <= 1'b0;
else begin
if (pe_wf)
full1 <= 1'b1;
else if (pe_rd)
full1 <= 1'b0;
end
always_ff @(posedge clk)
if (rst)
didRd <= 1'b0;
else begin
// set a read flag for later reference
if (pe_rd)
didRd <= 1'b1;
if (clear)
didRd <= 1'b0;
else if (baud16x_ce) begin
case (state)
`IDLE:
begin
if (didRd)
didRd <= 1'b0;
if (rdxstart)
didRd <= 1'b0;
end
default: ;
endcase
end
end
always_ff @(posedge clk)
if (rst)
rx_data <= 15'h0;
else begin
if (clear)
rx_data <= 15'h0;
else if (baud16x_ce) begin
case (state)
`CNT:
begin
//if (cnt[7:2]==frameSize[7:2])
// rx_data <= 11'h0;
if (cnt[3:0]==4'h7)
rx_data <= {rxdsmp,rx_data[14:1]};
end
default: ;
endcase
end
end
// Overrun: trying to recieve data when recieve buffer is already full.
always_ff @(posedge clk)
if (rst)
overrun <= 1'b0;
else begin
if (!full)
overrun <= 1'b0;
if (clear)
overrun <= 1'b0;
else if (baud16x_ce) begin
case (state)
`CNT:
if (cnt[8:0]==fhb) begin
if (full)
overrun <= 1'b1;
end
default: ;
endcase
end
end
always_ff @(posedge clk)
if (rst)
ferr <= 1'b0;
else begin
if (clear)
ferr <= 1'b0;
else if (baud16x_ce) begin
case (state)
`CNT:
if (cnt[8:0]==fhb)
ferr <= ~rxdsmp;
default: ;
endcase
end
end
endmodule