| 1 |
2 |
sinclairrf |
//
|
| 2 |
|
|
// PERIPHERAL UART_Rx: @NAME@
|
| 3 |
|
|
//
|
| 4 |
|
|
// Technique:
|
| 5 |
|
|
// - optionally synchronize the incoming signal
|
| 6 |
|
|
// - optionally deglitch the incoming signal
|
| 7 |
|
|
// - identify edges, align with value before the edge
|
| 8 |
|
|
// - generate missing edges, align values
|
| 9 |
|
|
// - assemble received bit sequence
|
| 10 |
|
|
// - run state machine counting number of received bits and waiting for delayed start bits
|
| 11 |
|
|
// - validate bit sequence and output bit sequence at end of last stop bit
|
| 12 |
|
|
// - optional FIFO
|
| 13 |
|
|
//
|
| 14 |
|
|
localparam L__BAUDMETHOD = ((@BAUDMETHOD@)+1)/2;
|
| 15 |
|
|
localparam L__BAUDMETHOD_MINUS = L__BAUDMETHOD - 2;
|
| 16 |
|
|
localparam L__BAUDMETHOD_NBITS = $clog2(L__BAUDMETHOD+1);
|
| 17 |
|
|
localparam L__SYNC_LENGTH = @SYNC@;
|
| 18 |
|
|
localparam L__DEGLITCH_LENGTH = @DEGLITCH@;
|
| 19 |
|
|
localparam L__NSTOP = @NSTOP@;
|
| 20 |
|
|
localparam L__NRX = 1+8+L__NSTOP;
|
| 21 |
|
|
localparam L__EVENT_COUNT = 2*L__NRX-1;
|
| 22 |
|
|
localparam L__EVENT_COUNT_NBITS = $clog2(L__EVENT_COUNT+1);
|
| 23 |
|
|
localparam L__INFIFO = @INFIFO@;
|
| 24 |
|
|
localparam L__INFIFO_NBITS = $clog2((L__INFIFO==0)?1:L__INFIFO);
|
| 25 |
|
|
generate
|
| 26 |
|
|
// Either copy the input, register it, or put it through a synchronizer.
|
| 27 |
|
|
wire s__Rx_sync;
|
| 28 |
|
|
if (L__SYNC_LENGTH == 0) begin : gen__no_sync
|
| 29 |
|
|
assign s__Rx_sync = @INPORT@;
|
| 30 |
|
|
end else if (L__SYNC_LENGTH == 1) begin : gen__short_sync
|
| 31 |
|
|
reg s__Rx_inport_s = 1'b1;
|
| 32 |
|
|
always @ (posedge i_clk)
|
| 33 |
|
|
if (i_rst)
|
| 34 |
|
|
s__Rx_inport_s <= 1'b1;
|
| 35 |
|
|
else
|
| 36 |
|
|
s__Rx_inport_s <= @INPORT@;
|
| 37 |
|
|
assign s__Rx_sync = s__Rx_inport_s;
|
| 38 |
|
|
end else begin : gen__long_sync
|
| 39 |
|
|
reg [L__SYNC_LENGTH-1:0] s__Rx_inport_s = {(L__SYNC_LENGTH){1'b1}};
|
| 40 |
|
|
always @ (posedge i_clk)
|
| 41 |
|
|
if (i_rst)
|
| 42 |
|
|
s__Rx_inport_s <= {(L__SYNC_LENGTH){1'b1}};
|
| 43 |
|
|
else
|
| 44 |
|
|
s__Rx_inport_s <= { s__Rx_inport_s[0+:L__SYNC_LENGTH-1], @INPORT@ };
|
| 45 |
|
|
assign s__Rx_sync = s__Rx_inport_s[L__SYNC_LENGTH-1];
|
| 46 |
|
|
end
|
| 47 |
|
|
// Either pass the received signal with no deglitching or apply deglitch
|
| 48 |
|
|
// hysteresis that consists of not changing the reported state unless all of
|
| 49 |
|
|
// the queued bits have changed state.
|
| 50 |
|
|
reg s__Rx_deglitched;
|
| 51 |
|
|
if (L__DEGLITCH_LENGTH == 0) begin : gen__nodeglitch
|
| 52 |
|
|
always @ (*)
|
| 53 |
|
|
s__Rx_deglitched = s__Rx_sync;
|
| 54 |
|
|
end else begin : gen__deglitch
|
| 55 |
|
|
initial s__Rx_deglitched = 1'b1;
|
| 56 |
|
|
reg [L__DEGLITCH_LENGTH-1:0] s__Rx_deglitch = {(L__DEGLITCH_LENGTH){1'b1}};
|
| 57 |
|
|
always @ (posedge i_clk) begin
|
| 58 |
|
|
s__Rx_deglitched <= (&(s__Rx_deglitch != {(L__DEGLITCH_LENGTH){s__Rx_deglitched}})) ? ~s__Rx_deglitched : s__Rx_deglitched;
|
| 59 |
|
|
s__Rx_deglitch <= { s__Rx_deglitch[0+:L__DEGLITCH_LENGTH-1], @INPORT@ };
|
| 60 |
|
|
end
|
| 61 |
|
|
end
|
| 62 |
|
|
// Identify edges
|
| 63 |
|
|
reg s__Rx_last = 1'b1;
|
| 64 |
|
|
always @ (posedge i_clk)
|
| 65 |
|
|
if (i_rst)
|
| 66 |
|
|
s__Rx_last <= 1'b1;
|
| 67 |
|
|
else
|
| 68 |
|
|
s__Rx_last <= s__Rx_deglitched;
|
| 69 |
|
|
reg s__Rx_edge = 1'b0;
|
| 70 |
|
|
always @ (posedge i_clk)
|
| 71 |
|
|
if (i_rst)
|
| 72 |
|
|
s__Rx_edge <= 1'b0;
|
| 73 |
|
|
else
|
| 74 |
|
|
s__Rx_edge <= (s__Rx_deglitched != s__Rx_last);
|
| 75 |
|
|
// Run a timer at twice the desired edge frequency rate. Synchronize it to the
|
| 76 |
|
|
// incoming edges.
|
| 77 |
|
|
reg [L__BAUDMETHOD_NBITS-1:0] s__Rx_event_time = L__BAUDMETHOD_MINUS[L__BAUDMETHOD_NBITS-1:0];
|
| 78 |
|
|
reg s__Rx_event_time_msb = L__BAUDMETHOD_MINUS[L__BAUDMETHOD_NBITS-1];
|
| 79 |
|
|
wire s__Rx_event_time_expired = ({s__Rx_event_time_msb,s__Rx_event_time[L__BAUDMETHOD_NBITS-1]} == 2'b01);
|
| 80 |
|
|
always @ (posedge i_clk)
|
| 81 |
|
|
if (i_rst) begin
|
| 82 |
|
|
s__Rx_event_time <= L__BAUDMETHOD_MINUS[L__BAUDMETHOD_NBITS-1:0];
|
| 83 |
|
|
s__Rx_event_time_msb <= L__BAUDMETHOD_MINUS[L__BAUDMETHOD_NBITS-1];
|
| 84 |
|
|
end else if (s__Rx_edge || s__Rx_event_time_expired) begin
|
| 85 |
|
|
s__Rx_event_time <= L__BAUDMETHOD_MINUS[L__BAUDMETHOD_NBITS-1:0];
|
| 86 |
|
|
s__Rx_event_time_msb <= L__BAUDMETHOD_MINUS[L__BAUDMETHOD_NBITS-1];
|
| 87 |
|
|
end else begin
|
| 88 |
|
|
s__Rx_event_time <= s__Rx_event_time - { {(L__BAUDMETHOD_NBITS-1){1'b0}}, 1'b1 };
|
| 89 |
|
|
s__Rx_event_time_msb <= s__Rx_event_time[L__BAUDMETHOD_NBITS-1];
|
| 90 |
|
|
end
|
| 91 |
|
|
// Fabricate composite event detection.
|
| 92 |
|
|
reg s__Rx_idle;
|
| 93 |
|
|
wire s__Rx_wait_edge;
|
| 94 |
|
|
reg s__Rx_event = 1'b0;
|
| 95 |
|
|
always @ (posedge i_clk)
|
| 96 |
|
|
if (i_rst)
|
| 97 |
|
|
s__Rx_event <= 1'b0;
|
| 98 |
|
|
else
|
| 99 |
|
|
s__Rx_event <= ~s__Rx_event && ((s__Rx_wait_edge && s__Rx_edge) || (~s__Rx_idle && s__Rx_event_time_expired));
|
| 100 |
|
|
// State machine -- idle state and event (edge/fabricated-edge and midpoint) counter.
|
| 101 |
|
|
initial s__Rx_idle = 1'b1;
|
| 102 |
|
|
reg [L__EVENT_COUNT_NBITS-1:0] s__Rx_event_count = L__EVENT_COUNT[L__EVENT_COUNT_NBITS-1:0];
|
| 103 |
|
|
reg s__Rx_event_count_zero = 1'b1;
|
| 104 |
|
|
always @ (posedge i_clk)
|
| 105 |
|
|
if (i_rst) begin
|
| 106 |
|
|
s__Rx_event_count <= L__EVENT_COUNT[L__EVENT_COUNT_NBITS-1:0];
|
| 107 |
|
|
s__Rx_idle <= 1'b1;
|
| 108 |
|
|
s__Rx_event_count_zero <= 1'b1;
|
| 109 |
|
|
end else begin
|
| 110 |
|
|
if (s__Rx_idle && s__Rx_event)
|
| 111 |
|
|
s__Rx_idle <= 1'b0;
|
| 112 |
|
|
else
|
| 113 |
|
|
s__Rx_idle <= (s__Rx_event_count_zero) ? 1'b1: s__Rx_idle;
|
| 114 |
|
|
if (s__Rx_idle) begin
|
| 115 |
|
|
s__Rx_event_count <= L__EVENT_COUNT[L__EVENT_COUNT_NBITS-1:0];
|
| 116 |
|
|
s__Rx_event_count_zero <= 1'b0;
|
| 117 |
|
|
end else if (s__Rx_event) begin
|
| 118 |
|
|
s__Rx_event_count <= s__Rx_event_count - { {(L__EVENT_COUNT_NBITS-1){1'b0}}, 1'b1 };
|
| 119 |
|
|
s__Rx_event_count_zero <= (s__Rx_event_count == { {(L__EVENT_COUNT_NBITS-1){1'b0}}, 1'b1 });
|
| 120 |
|
|
end else begin
|
| 121 |
|
|
s__Rx_event_count <= s__Rx_event_count;
|
| 122 |
|
|
s__Rx_event_count_zero <= 1'b0;
|
| 123 |
|
|
end
|
| 124 |
|
|
end
|
| 125 |
|
|
assign s__Rx_wait_edge = s__Rx_idle || (L__EVENT_COUNT[0] ^ s__Rx_event_count[0]);
|
| 126 |
|
|
wire s__Rx_wait_sample = ~s__Rx_wait_edge;
|
| 127 |
|
|
// Generate a strobe when a new bit is to be recorded.
|
| 128 |
|
|
reg s__Rx_got_bit = 1'b0;
|
| 129 |
|
|
always @ (posedge i_clk)
|
| 130 |
|
|
if (i_rst)
|
| 131 |
|
|
s__Rx_got_bit <= 1'b0;
|
| 132 |
|
|
else
|
| 133 |
|
|
s__Rx_got_bit <= (~s__Rx_idle && s__Rx_wait_sample && s__Rx_event);
|
| 134 |
|
|
// Record the received bit stream after edges occur (start bit is always discarded)
|
| 135 |
|
|
reg [L__NRX-1:2] s__Rx_s = {(L__NRX-2){1'b1}};
|
| 136 |
|
|
always @ (posedge i_clk)
|
| 137 |
|
|
if (i_rst)
|
| 138 |
|
|
s__Rx_s <= {(L__NRX-2){1'b1}};
|
| 139 |
|
|
else if (s__Rx_got_bit)
|
| 140 |
|
|
s__Rx_s <= { s__Rx_last, s__Rx_s[3+:L__NRX-3] };
|
| 141 |
|
|
else
|
| 142 |
|
|
s__Rx_s <= s__Rx_s;
|
| 143 |
|
|
// Generate strobe to write the received byte to the output buffer.
|
| 144 |
|
|
reg s__Rx_wr = 1'b0;
|
| 145 |
|
|
reg [3:0] s__Rx_count = L__NRX[0+:4] - 4'd1;
|
| 146 |
|
|
always @ (posedge i_clk)
|
| 147 |
|
|
if (i_rst) begin
|
| 148 |
|
|
s__Rx_wr <= 1'b0;
|
| 149 |
|
|
s__Rx_count <= L__NRX[0+:4] - 4'd1;
|
| 150 |
|
|
end else if (s__Rx_idle) begin
|
| 151 |
|
|
s__Rx_wr <= 1'b0;
|
| 152 |
|
|
s__Rx_count <= L__NRX[0+:4] - 4'd1;
|
| 153 |
|
|
end else if (s__Rx_got_bit) begin
|
| 154 |
|
|
s__Rx_wr <= (s__Rx_count == 4'd1);
|
| 155 |
|
|
s__Rx_count <= s__Rx_count - 4'd1;
|
| 156 |
|
|
end else begin
|
| 157 |
|
|
s__Rx_wr <= 1'b0;
|
| 158 |
|
|
s__Rx_count <= s__Rx_count;
|
| 159 |
|
|
end
|
| 160 |
|
|
// Optional FIFO
|
| 161 |
|
|
if (L__INFIFO == 0) begin : gen__nofifo
|
| 162 |
|
|
always @ (posedge i_clk)
|
| 163 |
|
|
if (i_rst) begin
|
| 164 |
|
|
s__Rx_empty <= 1'b1;
|
| 165 |
|
|
s__Rx <= 8'h00;
|
| 166 |
|
|
end else begin
|
| 167 |
|
|
if (s__Rx_wr)
|
| 168 |
|
|
s__Rx <= s__Rx_s[2+:8];
|
| 169 |
|
|
else
|
| 170 |
|
|
s__Rx <= s__Rx;
|
| 171 |
|
|
if (s__Rx_wr) begin
|
| 172 |
|
|
if (s__Rx_rd)
|
| 173 |
|
|
s__Rx_empty <= s__Rx_empty;
|
| 174 |
|
|
else
|
| 175 |
|
|
s__Rx_empty <= 1'b0;
|
| 176 |
|
|
end else begin
|
| 177 |
|
|
if (s__Rx_rd)
|
| 178 |
|
|
s__Rx_empty <= 1'b1;
|
| 179 |
|
|
else
|
| 180 |
|
|
s__Rx_empty <= s__Rx_empty;
|
| 181 |
|
|
end
|
| 182 |
|
|
end
|
| 183 |
|
|
end else begin : gen__fifo
|
| 184 |
|
|
reg [L__INFIFO_NBITS:0] s__Rx_fifo_addr_in;
|
| 185 |
|
|
reg [L__INFIFO_NBITS:0] s__Rx_fifo_addr_out;
|
| 186 |
|
|
wire s__Rx_shift;
|
| 187 |
|
|
reg s__Rx_fifo_has_data = 1'b0;
|
| 188 |
|
|
always @ (posedge i_clk)
|
| 189 |
|
|
if (i_rst)
|
| 190 |
|
|
s__Rx_fifo_has_data <= 1'b0;
|
| 191 |
|
|
else
|
| 192 |
|
|
s__Rx_fifo_has_data <= (s__Rx_fifo_addr_out != s__Rx_fifo_addr_in) && !s__Rx_shift;
|
| 193 |
|
|
always @ (posedge i_clk)
|
| 194 |
|
|
if (i_rst) begin
|
| 195 |
|
|
s__Rx_empty <= 1'b1;
|
| 196 |
|
|
end else begin
|
| 197 |
|
|
case ({ s__Rx_fifo_has_data, s__Rx_empty, s__Rx_rd })
|
| 198 |
|
|
3'b000 : s__Rx_empty <= 1'b0;
|
| 199 |
|
|
3'b001 : s__Rx_empty <= 1'b1; // good read
|
| 200 |
|
|
3'b010 : s__Rx_empty <= 1'b1;
|
| 201 |
|
|
3'b011 : s__Rx_empty <= 1'b1; // bad read
|
| 202 |
|
|
3'b100 : s__Rx_empty <= 1'b0;
|
| 203 |
|
|
3'b101 : s__Rx_empty <= 1'b0; // shift, good read
|
| 204 |
|
|
3'b110 : s__Rx_empty <= 1'b0; // shift
|
| 205 |
|
|
3'b111 : s__Rx_empty <= 1'b1; // shift, bad read
|
| 206 |
|
|
endcase
|
| 207 |
|
|
end
|
| 208 |
|
|
assign s__Rx_shift = s__Rx_fifo_has_data && (s__Rx_empty || s__Rx_rd);
|
| 209 |
|
|
reg s__Rx_full = 1'b0;
|
| 210 |
|
|
always @ (posedge i_clk)
|
| 211 |
|
|
if (i_rst)
|
| 212 |
|
|
s__Rx_full <= 1'b0;
|
| 213 |
|
|
else
|
| 214 |
|
|
s__Rx_full <= (s__Rx_fifo_addr_in == (s__Rx_fifo_addr_out ^ { 1'b1, {(L__INFIFO_NBITS){1'b0}} }));
|
| 215 |
|
|
reg [7:0] s__Rx_fifo_mem[@INFIFO@-1:0];
|
| 216 |
|
|
initial s__Rx_fifo_addr_in = {(L__INFIFO_NBITS+1){1'b0}};
|
| 217 |
|
|
always @ (posedge i_clk)
|
| 218 |
|
|
if (i_rst)
|
| 219 |
|
|
s__Rx_fifo_addr_in <= {(L__INFIFO_NBITS+1){1'b0}};
|
| 220 |
|
|
else if (s__Rx_wr && (!s__Rx_full || s__Rx_shift)) begin
|
| 221 |
|
|
s__Rx_fifo_addr_in <= s__Rx_fifo_addr_in + { {(L__INFIFO_NBITS){1'b0}}, 1'b1 };
|
| 222 |
|
|
s__Rx_fifo_mem[s__Rx_fifo_addr_in[0+:L__INFIFO_NBITS]] <= s__Rx_s[2+:8];
|
| 223 |
|
|
end else
|
| 224 |
|
|
s__Rx_fifo_addr_in <= s__Rx_fifo_addr_in;
|
| 225 |
|
|
initial s__Rx_fifo_addr_out = {(L__INFIFO_NBITS+1){1'b0}};
|
| 226 |
|
|
always @ (posedge i_clk)
|
| 227 |
|
|
if (i_rst) begin
|
| 228 |
|
|
s__Rx_fifo_addr_out <= {(L__INFIFO_NBITS+1){1'b0}};
|
| 229 |
|
|
s__Rx <= 8'h00;
|
| 230 |
|
|
end else if (s__Rx_shift) begin
|
| 231 |
|
|
s__Rx_fifo_addr_out <= s__Rx_fifo_addr_out + { {(L__INFIFO_NBITS){1'b0}}, 1'b1 };
|
| 232 |
|
|
s__Rx <= s__Rx_fifo_mem[s__Rx_fifo_addr_out[0+:L__INFIFO_NBITS]];
|
| 233 |
|
|
end else begin
|
| 234 |
|
|
s__Rx_fifo_addr_out <= s__Rx_fifo_addr_out;
|
| 235 |
|
|
s__Rx <= s__Rx;
|
| 236 |
|
|
end
|
| 237 |
|
|
end
|
| 238 |
|
|
endgenerate
|