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