1 |
7 |
robfinch |
// ============================================================================
|
2 |
|
|
// __
|
3 |
|
|
// \\__/ o\ (C) 2005-2022 Robert Finch, Waterloo
|
4 |
|
|
// \ __ / All rights reserved.
|
5 |
|
|
// \/_// robfinch@finitron.ca
|
6 |
|
|
// ||
|
7 |
|
|
//
|
8 |
|
|
//
|
9 |
|
|
// BSD 3-Clause License
|
10 |
|
|
// Redistribution and use in source and binary forms, with or without
|
11 |
|
|
// modification, are permitted provided that the following conditions are met:
|
12 |
|
|
//
|
13 |
|
|
// 1. Redistributions of source code must retain the above copyright notice, this
|
14 |
|
|
// list of conditions and the following disclaimer.
|
15 |
|
|
//
|
16 |
|
|
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
17 |
|
|
// this list of conditions and the following disclaimer in the documentation
|
18 |
|
|
// and/or other materials provided with the distribution.
|
19 |
|
|
//
|
20 |
|
|
// 3. Neither the name of the copyright holder nor the names of its
|
21 |
|
|
// contributors may be used to endorse or promote products derived from
|
22 |
|
|
// this software without specific prior written permission.
|
23 |
|
|
//
|
24 |
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
25 |
|
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
26 |
|
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
27 |
|
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
28 |
|
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
29 |
|
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
30 |
|
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
31 |
|
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
32 |
|
|
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
33 |
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34 |
|
|
//
|
35 |
|
|
// ============================================================================
|
36 |
|
|
//
|
37 |
|
|
`define UART_TRB 5'd0 // transmit/receive buffer
|
38 |
|
|
`define UART_STAT 5'd1
|
39 |
|
|
`define UART_CMD 5'd2
|
40 |
|
|
`define UART_CTRL 5'd3
|
41 |
|
|
`define UART_CLKD0 5'd4
|
42 |
|
|
`define UART_CLKD1 5'd5
|
43 |
|
|
`define UART_CLKD2 5'd6
|
44 |
|
|
`define UART_TMP 5'd7
|
45 |
|
|
`define UART_CMD1 5'd8
|
46 |
|
|
`define UART_CMD2 5'd9
|
47 |
|
|
`define UART_CMD3 5'd10
|
48 |
|
|
`define UART_LS 5'd11
|
49 |
|
|
`define UART_MS 5'd12
|
50 |
|
|
`define UART_IRQS 5'd13
|
51 |
|
|
`define UART_CTRL1 5'd14
|
52 |
|
|
`define UART_CTRL2 5'd15
|
53 |
|
|
`define UART_CTRL3 5'd16
|
54 |
|
|
|
55 |
|
|
|
56 |
|
|
module uart6551sbi(rst_i, refclk_i, ph2_i, cs_i, irq_o,
|
57 |
|
|
rw_i, adr_i, dat_i, dat_o,
|
58 |
|
|
cts_ni, rts_no, dsr_ni, dcd_ni, dtr_no, ri_ni,
|
59 |
|
|
rxd_i, txd_o, data_present,
|
60 |
|
|
rxDRQ_o, txDRQ_o,
|
61 |
|
|
xph2_i, RxC_i
|
62 |
|
|
);
|
63 |
|
|
parameter pCounterBits = 24;
|
64 |
|
|
parameter pFifoSize = 1024;
|
65 |
|
|
parameter pClkDiv = 24'd1302; // 9.6k baud, 200.000MHz clock
|
66 |
|
|
parameter HIGH = 1'b1;
|
67 |
|
|
parameter LOW = 1'b0;
|
68 |
|
|
input rst_i;
|
69 |
|
|
input refclk_i; // reference clock eg 50.000 MHz
|
70 |
|
|
input ph2_i; // bus clock
|
71 |
|
|
input cs_i; // circuit select
|
72 |
|
|
// Synchronous Bus Interface ---------------
|
73 |
|
|
input rw_i; // 0 = write
|
74 |
|
|
input [4:0] adr_i; // register address
|
75 |
|
|
input [7:0] dat_i; // data input bus
|
76 |
|
|
output reg [7:0] dat_o; // data output bus
|
77 |
|
|
//------------------------------------------
|
78 |
|
|
output reg irq_o; // interrupt request
|
79 |
|
|
input cts_ni; // clear to send - (flow control) active low
|
80 |
|
|
output reg rts_no; // request to send - (flow control) active low
|
81 |
|
|
input dsr_ni; // data set ready - active low
|
82 |
|
|
input dcd_ni; // data carrier detect - active low
|
83 |
|
|
output reg dtr_no; // data terminal ready - active low
|
84 |
|
|
input ri_ni; // ring indicator
|
85 |
|
|
input rxd_i; // serial data in
|
86 |
|
|
output txd_o; // serial data out
|
87 |
|
|
output data_present;
|
88 |
|
|
output rxDRQ_o; // reciever DMA request
|
89 |
|
|
output txDRQ_o; // transmitter DMA request
|
90 |
|
|
input xph2_i; // external clock source
|
91 |
|
|
input RxC_i; // external receiver clock source
|
92 |
|
|
|
93 |
|
|
reg [7:0] tmpreg;
|
94 |
|
|
reg accessCD; // clock multiplier access flag
|
95 |
|
|
reg llb; // local loopback mode
|
96 |
|
|
reg dmaEnable;
|
97 |
|
|
// baud rate clock control
|
98 |
|
|
reg [4:0] baudRateSel;
|
99 |
|
|
reg selCD; // Use clock multiplier register
|
100 |
|
|
reg [pCounterBits-1:0] c; // current count
|
101 |
|
|
reg [pCounterBits-1:0] ckdiv; // baud rate clock divider
|
102 |
|
|
reg [pCounterBits-1:0] clkdiv; // clock multiplier register
|
103 |
|
|
reg [1:0] xclks; // synchronized external clock
|
104 |
|
|
reg [1:0] RxCs; // synchronized external receiver clock
|
105 |
|
|
reg baud16; // 16x baud rate clock
|
106 |
|
|
wire baud16rx; // reciever clock
|
107 |
|
|
reg xClkSrc; // uart baud clock is external
|
108 |
|
|
reg rxClkSrc; // receiver clock is external
|
109 |
|
|
|
110 |
|
|
// frame format registers
|
111 |
|
|
reg [3:0] wordLength;
|
112 |
|
|
reg stopBit;
|
113 |
|
|
reg [2:0] stopBits;
|
114 |
|
|
reg [2:0] parityCtrl;
|
115 |
|
|
wire [7:0] frameSize;
|
116 |
|
|
|
117 |
|
|
reg txBreak; // transmit a break
|
118 |
|
|
|
119 |
|
|
wire rxFull;
|
120 |
|
|
wire rxEmpty;
|
121 |
|
|
wire txFull;
|
122 |
|
|
wire txEmpty;
|
123 |
|
|
reg hwfc; // hardware flow control enable
|
124 |
|
|
wire [7:0] lineStatusReg;
|
125 |
|
|
wire [7:0] modemStatusReg;
|
126 |
|
|
wire [7:0] irqStatusReg;
|
127 |
|
|
// interrupt
|
128 |
|
|
reg rxIe;
|
129 |
|
|
reg txIe;
|
130 |
|
|
reg modemStatusChangeIe;
|
131 |
|
|
wire modemStatusChange;
|
132 |
|
|
reg lineStatusChangeIe;
|
133 |
|
|
wire lineStatusChange;
|
134 |
|
|
reg rxToutIe; // receiver timeout interrupt enable
|
135 |
|
|
reg [3:0] rxThres; // receiver threshold for interrupt
|
136 |
|
|
reg [3:0] txThres; // transmitter threshold for interrupt
|
137 |
|
|
reg rxTout; // receiver timeout
|
138 |
|
|
wire [9:0] rxCnt; // reciever counter value
|
139 |
|
|
reg [7:0] rxToutMax;
|
140 |
|
|
reg [2:0] irqenc; // encoded irq cause
|
141 |
|
|
wire rxITrig; // receiver interrupt trigger level
|
142 |
|
|
wire txITrig; // transmitter interrupt trigger level
|
143 |
|
|
// reciever errors
|
144 |
|
|
wire parityErr; // reciever detected a parity error
|
145 |
|
|
wire frameErr; // receiver char framing error
|
146 |
|
|
wire overrun; // receiver over run
|
147 |
|
|
wire rxBreak; // reciever detected a break
|
148 |
|
|
wire rxGErr; // global error: there is at least one error in the reciever fifo
|
149 |
|
|
// modem controls
|
150 |
|
|
reg [1:0] ctsx; // cts_n sampling
|
151 |
|
|
reg [1:0] dcdx;
|
152 |
|
|
reg [1:0] dsrx;
|
153 |
|
|
reg [1:0] rix;
|
154 |
|
|
reg deltaCts;
|
155 |
|
|
reg deltaDcd;
|
156 |
|
|
reg deltaDsr;
|
157 |
|
|
reg deltaRi;
|
158 |
|
|
|
159 |
|
|
// fifo
|
160 |
|
|
reg rxFifoClear;
|
161 |
|
|
reg txFifoClear;
|
162 |
|
|
reg fifoEnable;
|
163 |
|
|
wire [3:0] rxQued;
|
164 |
|
|
wire [3:0] txQued;
|
165 |
|
|
|
166 |
|
|
// test
|
167 |
|
|
wire txd1;
|
168 |
|
|
|
169 |
|
|
assign data_present = ~rxEmpty;
|
170 |
|
|
|
171 |
|
|
assign rxITrig = rxQued >= rxThres;
|
172 |
|
|
assign txITrig = txQued <= txThres;
|
173 |
|
|
wire rxDRQ1 = (fifoEnable ? rxITrig : ~rxEmpty);
|
174 |
|
|
wire txDRQ1 = (fifoEnable ? txITrig : txEmpty);
|
175 |
|
|
assign rxDRQ_o = dmaEnable & rxDRQ1;
|
176 |
|
|
assign txDRQ_o = dmaEnable & txDRQ1;
|
177 |
|
|
wire rxIRQ = rxIe & rxDRQ1;
|
178 |
|
|
wire txIRQ = txIe & txDRQ1;
|
179 |
|
|
|
180 |
|
|
reg [7:0] cmd0, cmd1, cmd2, cmd3;
|
181 |
|
|
reg [7:0] ctrl0, ctrl1, ctrl2, ctrl3;
|
182 |
|
|
|
183 |
|
|
always_ff @(negedge ph2_i)
|
184 |
|
|
irq_o <=
|
185 |
|
|
rxIRQ
|
186 |
|
|
| txIRQ
|
187 |
|
|
| (rxTout & rxToutIe)
|
188 |
|
|
| (lineStatusChange & lineStatusChangeIe)
|
189 |
|
|
| (modemStatusChange & modemStatusChangeIe)
|
190 |
|
|
;
|
191 |
|
|
|
192 |
|
|
// Hold onto address and data an extra cycle.
|
193 |
|
|
// The extra cycle updates or reads the serial transmit / receive.
|
194 |
|
|
reg [7:0] dati;
|
195 |
|
|
always_ff @(negedge ph2_i)
|
196 |
|
|
dati <= dat_i;
|
197 |
|
|
reg [4:0] adr_h;
|
198 |
|
|
always_ff @(posedge ph2_i)
|
199 |
|
|
adr_h <= adr_i;
|
200 |
|
|
reg we;
|
201 |
|
|
always_ff @(posedge ph2_i)
|
202 |
|
|
we <= ~rw_i;
|
203 |
|
|
reg csh;
|
204 |
|
|
always_ff @(posedge ph2_i)
|
205 |
|
|
csh <= cs;
|
206 |
|
|
|
207 |
|
|
wire [7:0] rx_do;
|
208 |
|
|
wire cs = cs_i;
|
209 |
|
|
wire rdrx = csh && adr_h==`UART_TRB && ~we;
|
210 |
|
|
wire txrx = csh && adr_h==`UART_TRB;
|
211 |
|
|
|
212 |
|
|
wire ne_ph2, pe_ph2;
|
213 |
|
|
edge_det ued4 (.rst(rst_i), .clk(refclk_i), .ce(1'b1), .i(ph2_i), .pe(pe_ph2), .ne(ne_ph2), .ee());
|
214 |
|
|
reg ne_ph2d, pe_ph2d;
|
215 |
|
|
always_ff @(posedge refclk_i)
|
216 |
|
|
ne_ph2d <= ne_ph2;
|
217 |
|
|
always_ff @(posedge refclk_i)
|
218 |
|
|
pe_ph2d <= pe_ph2;
|
219 |
|
|
|
220 |
|
|
uart6551Rx uart_rx0
|
221 |
|
|
(
|
222 |
|
|
.rst(rst_i),
|
223 |
|
|
.clk(refclk_i),
|
224 |
|
|
.cyc(cs & pe_ph2d),
|
225 |
|
|
.cs(rdrx),
|
226 |
|
|
.wr(we),
|
227 |
|
|
.dout(rx_do),
|
228 |
|
|
.ack(),
|
229 |
|
|
.fifoEnable(fifoEnable),
|
230 |
|
|
.fifoClear(rxFifoClear),
|
231 |
|
|
.clearGErr(1'b0),
|
232 |
|
|
.wordLength(wordLength),
|
233 |
|
|
.parityCtrl(parityCtrl),
|
234 |
|
|
.frameSize(frameSize),
|
235 |
|
|
.stop_bits(stopBits),
|
236 |
|
|
.baud16x_ce(baud16rx),
|
237 |
|
|
.clear(1'b0),
|
238 |
|
|
.rxd(llb ? txd1 : rxd_i),
|
239 |
|
|
.full(),
|
240 |
|
|
.empty(rxEmpty),
|
241 |
|
|
.frameErr(frameErr),
|
242 |
|
|
.overrun(overrun),
|
243 |
|
|
.parityErr(parityErr),
|
244 |
|
|
.break_o(rxBreak),
|
245 |
|
|
.gerr(rxGErr),
|
246 |
|
|
.qcnt(rxQued),
|
247 |
|
|
.cnt(rxCnt)
|
248 |
|
|
);
|
249 |
|
|
|
250 |
|
|
uart6551Tx uart_tx0
|
251 |
|
|
(
|
252 |
|
|
.rst(rst_i),
|
253 |
|
|
.clk(refclk_i),
|
254 |
|
|
.cyc(cs & ne_ph2d),
|
255 |
|
|
.cs(txrx),
|
256 |
|
|
.wr(we),
|
257 |
|
|
.din(dati[7:0]),
|
258 |
|
|
.ack(),
|
259 |
|
|
.fifoEnable(fifoEnable),
|
260 |
|
|
.fifoClear(txFifoClear),
|
261 |
|
|
.txBreak(txBreak),
|
262 |
|
|
.frameSize(frameSize), // 16 x 10 bits
|
263 |
|
|
.wordLength(wordLength),// 8 bits
|
264 |
|
|
.parityCtrl(parityCtrl),// no parity
|
265 |
|
|
.baud16x_ce(baud16),
|
266 |
|
|
.cts(ctsx[1]|~hwfc),
|
267 |
|
|
.clear(clear),
|
268 |
|
|
.txd(txd1),
|
269 |
|
|
.full(txFull),
|
270 |
|
|
.empty(txEmpty),
|
271 |
|
|
.qcnt(txQued)
|
272 |
|
|
);
|
273 |
|
|
|
274 |
|
|
assign txd_o = llb ? 1'b1 : txd1;
|
275 |
|
|
|
276 |
|
|
assign lineStatusReg = {rxGErr,1'b0,txFull,rxBreak,1'b0,1'b0,1'b0,1'b0};
|
277 |
|
|
assign modemStatusChange = deltaDcd|deltaRi|deltaDsr|deltaCts; // modem status delta
|
278 |
|
|
assign modemStatusReg = {1'b0,~rix[1],1'b0,~ctsx[1],deltaDcd, deltaRi, deltaDsr, deltaCts};
|
279 |
|
|
assign irqStatusReg = {irq_o,2'b00,irqenc,2'b00};
|
280 |
|
|
|
281 |
|
|
// mux the reg outputs
|
282 |
|
|
always_ff @(posedge ph2_i)
|
283 |
|
|
begin
|
284 |
|
|
case(adr_i)
|
285 |
|
|
`UART_TRB: dat_o <= rx_do; // receiver holding register
|
286 |
|
|
`UART_STAT: dat_o <= {irq_o,dsrx[1],dcdx[1],fifoEnable ? ~txFull : txEmpty,~rxEmpty,overrun,frameErr,parityErr};
|
287 |
|
|
`UART_CMD: dat_o <= cmd0;
|
288 |
|
|
`UART_CTRL: dat_o <= ctrl0;
|
289 |
|
|
3'd4: dat_o <= clkdiv[7:0];
|
290 |
|
|
3'd5: dat_o <= clkdiv[15:8];
|
291 |
|
|
3'd6: dat_o <= clkdiv[23:16];
|
292 |
|
|
3'd7: dat_o <= tmpreg;
|
293 |
|
|
`UART_CMD1: dat_o <= cmd1;
|
294 |
|
|
`UART_CMD2: dat_o <= cmd2;
|
295 |
|
|
`UART_CMD3: dat_o <= cmd3;
|
296 |
|
|
`UART_LS: dat_o <= lineStatusReg;
|
297 |
|
|
`UART_MS: dat_o <= modemStatusReg;
|
298 |
|
|
`UART_IRQS: dat_o <= irqStatusReg;
|
299 |
|
|
`UART_CTRL1: dat_o <= ctrl1;
|
300 |
|
|
`UART_CTRL2: dat_o <= ctrl2;
|
301 |
|
|
`UART_CTRL3: dat_o <= ctrl3;
|
302 |
|
|
default: dat_o <= 8'hFF;
|
303 |
|
|
endcase
|
304 |
|
|
end
|
305 |
|
|
|
306 |
|
|
|
307 |
|
|
// register updates
|
308 |
|
|
always_ff @(negedge ph2_i)
|
309 |
|
|
if (rst_i) begin
|
310 |
|
|
tmpreg <= 8'hFF;
|
311 |
|
|
rts_no <= HIGH;
|
312 |
|
|
dtr_no <= HIGH;
|
313 |
|
|
// interrupts
|
314 |
|
|
rxIe <= 1'b0;
|
315 |
|
|
txIe <= 1'b0;
|
316 |
|
|
modemStatusChangeIe <= 1'b0;
|
317 |
|
|
lineStatusChangeIe <= 1'b0;
|
318 |
|
|
hwfc <= 1'b0;
|
319 |
|
|
modemStatusChangeIe <= 1'b0;
|
320 |
|
|
lineStatusChangeIe <= 1'b0;
|
321 |
|
|
dmaEnable <= 1'b0;
|
322 |
|
|
// clock control
|
323 |
|
|
baudRateSel <= 5'h0;
|
324 |
|
|
rxClkSrc <= 1'b0; // ** 6551 defaults to zero (external receiver clock)
|
325 |
|
|
clkdiv <= pClkDiv;
|
326 |
|
|
// frame format
|
327 |
|
|
wordLength <= 4'd8; // 8 bits
|
328 |
|
|
stopBit <= 1'b0; // 1 stop bit
|
329 |
|
|
parityCtrl <= 3'd0; // no parity
|
330 |
|
|
|
331 |
|
|
txBreak <= 1'b0;
|
332 |
|
|
// Fifo control
|
333 |
|
|
txFifoClear <= 1'b1;
|
334 |
|
|
rxFifoClear <= 1'b1;
|
335 |
|
|
fifoEnable <= 1'b1;
|
336 |
|
|
// Test
|
337 |
|
|
llb <= 1'b0;
|
338 |
|
|
selCD <= 1'b0;
|
339 |
|
|
accessCD <= 1'b0;
|
340 |
|
|
end
|
341 |
|
|
else begin
|
342 |
|
|
|
343 |
|
|
//llb <= 1'b1;
|
344 |
|
|
rxFifoClear <= 1'b0;
|
345 |
|
|
txFifoClear <= 1'b0;
|
346 |
|
|
ctrl2[1] <= 1'b0;
|
347 |
|
|
ctrl2[2] <= 1'b0;
|
348 |
|
|
|
349 |
|
|
if (rw_i==1'b0) begin
|
350 |
|
|
case (adr_h) // synopsys full_case parallel_case
|
351 |
|
|
|
352 |
|
|
`UART_TRB:
|
353 |
|
|
;
|
354 |
|
|
|
355 |
|
|
// Writing to the status register does a software reset of some bits.
|
356 |
|
|
`UART_STAT:
|
357 |
|
|
begin
|
358 |
|
|
dtr_no <= HIGH;
|
359 |
|
|
rxIe <= 1'b0;
|
360 |
|
|
rts_no <= HIGH;
|
361 |
|
|
txIe <= 1'b0;
|
362 |
|
|
txBreak <= 1'b0;
|
363 |
|
|
llb <= 1'b0;
|
364 |
|
|
end
|
365 |
|
|
`UART_CMD:
|
366 |
|
|
begin
|
367 |
|
|
cmd0 <= dati[7:0];
|
368 |
|
|
dtr_no <= ~dati[0];
|
369 |
|
|
rxIe <= ~dati[1];
|
370 |
|
|
case(dati[3:2])
|
371 |
|
|
2'd0: begin rts_no <= 1'b1; txIe <= 1'b0; txBreak <= 1'b0; end
|
372 |
|
|
2'd1: begin rts_no <= 1'b0; txIe <= 1'b1; txBreak <= 1'b0; end
|
373 |
|
|
2'd2: begin rts_no <= 1'b0; txIe <= 1'b0; txBreak <= 1'b0; end
|
374 |
|
|
2'd3: begin rts_no <= 1'b0; txIe <= 1'b0; txBreak <= 1'b1; end
|
375 |
|
|
endcase
|
376 |
|
|
llb <= dati[4];
|
377 |
|
|
parityCtrl <= dati[7:5]; //000=none,001=odd,011=even,101=force 1,111 = force 0
|
378 |
|
|
end
|
379 |
|
|
`UART_CMD1:
|
380 |
|
|
begin
|
381 |
|
|
cmd1 <= dati;
|
382 |
|
|
lineStatusChangeIe <= dati[0];
|
383 |
|
|
modemStatusChangeIe <= dati[1];
|
384 |
|
|
rxToutIe <= dati[2];
|
385 |
|
|
end
|
386 |
|
|
`UART_CMD2:
|
387 |
|
|
cmd2 <= dati;
|
388 |
|
|
`UART_CMD3:
|
389 |
|
|
cmd3 <= dati;
|
390 |
|
|
|
391 |
|
|
`UART_CTRL:
|
392 |
|
|
begin
|
393 |
|
|
ctrl0 <= dati[7:0];
|
394 |
|
|
baudRateSel[3:0] <= dati[3:0];
|
395 |
|
|
rxClkSrc <= dati[4]; // 1 = baud rate generator, 0 = external
|
396 |
|
|
//11=5,10=6,01=7,00=8
|
397 |
|
|
case(dati[6:5])
|
398 |
|
|
2'd0: wordLength <= 6'd8;
|
399 |
|
|
2'd1: wordLength <= 6'd7;
|
400 |
|
|
2'd2: wordLength <= 6'd6;
|
401 |
|
|
2'd3: wordLength <= 6'd5;
|
402 |
|
|
endcase
|
403 |
|
|
stopBit <= dati[7]; //0=1,1=1.5 or 2
|
404 |
|
|
end
|
405 |
|
|
`UART_CTRL1:
|
406 |
|
|
// Extended word length, values beyond 11 not supported.
|
407 |
|
|
ctrl1 <= dati;
|
408 |
|
|
`UART_CTRL2:
|
409 |
|
|
begin
|
410 |
|
|
ctrl2 <= dati;
|
411 |
|
|
fifoEnable <= dati[0];
|
412 |
|
|
rxFifoClear <= dati[1];
|
413 |
|
|
txFifoClear <= dati[2];
|
414 |
|
|
case (dati[5:4])
|
415 |
|
|
2'd0: txThres <= 4'd1; // one-byte
|
416 |
|
|
2'd1: txThres <= pFifoSize / 4; // one-quarter full
|
417 |
|
|
2'd2: txThres <= pFifoSize / 2; // one-half full
|
418 |
|
|
2'd3: txThres <= pFifoSize * 3 / 4; // three-quarters full
|
419 |
|
|
endcase
|
420 |
|
|
case (dati[7:6])
|
421 |
|
|
2'd0: rxThres <= 4'd1; // one-byte
|
422 |
|
|
2'd1: rxThres <= pFifoSize / 4; // one-quarter full
|
423 |
|
|
2'd2: rxThres <= pFifoSize / 2; // one-half full
|
424 |
|
|
2'd3: rxThres <= pFifoSize * 3 / 4; // three quarters full
|
425 |
|
|
endcase
|
426 |
|
|
end
|
427 |
|
|
`UART_CTRL3:
|
428 |
|
|
begin
|
429 |
|
|
ctrl3 <= dati;
|
430 |
|
|
hwfc <= dati[0];
|
431 |
|
|
dmaEnable <= dati[2];
|
432 |
|
|
baudRateSel[4] <= dati[3];
|
433 |
|
|
selCD <= dati[6];
|
434 |
|
|
accessCD <= dati[7];
|
435 |
|
|
end
|
436 |
|
|
|
437 |
|
|
default:
|
438 |
|
|
;
|
439 |
|
|
endcase
|
440 |
|
|
end
|
441 |
|
|
end
|
442 |
|
|
|
443 |
|
|
// ----------------------------------------------------------------------------
|
444 |
|
|
// Baud rate control.
|
445 |
|
|
// ----------------------------------------------------------------------------
|
446 |
|
|
|
447 |
|
|
always_ff @(posedge refclk_i)
|
448 |
|
|
xClkSrc <= baudRateSel==5'd0;
|
449 |
|
|
|
450 |
|
|
wire [pCounterBits-1:0] bclkdiv;
|
451 |
|
|
uart6551BaudLUT #(pCounterBits) ublt1 (.a(baudRateSel), .o(bclkdiv));
|
452 |
|
|
|
453 |
|
|
reg [pCounterBits-1:0] clkdiv2;
|
454 |
|
|
always_ff @(posedge refclk_i)
|
455 |
|
|
clkdiv2 <= selCD ? clkdiv : bclkdiv;
|
456 |
|
|
|
457 |
|
|
always_ff @(posedge refclk_i)
|
458 |
|
|
if (rst_i)
|
459 |
|
|
c <= 1'd1;
|
460 |
|
|
else begin
|
461 |
|
|
c <= c + 2'd1;
|
462 |
|
|
if (c >= clkdiv2)
|
463 |
|
|
c <= 2'd1;
|
464 |
|
|
end
|
465 |
|
|
|
466 |
|
|
// for detecting an edge on the baud clock
|
467 |
|
|
wire ibaud16 = c == 2'd1;
|
468 |
|
|
|
469 |
|
|
// Detect an edge on the external clock
|
470 |
|
|
wire xclkEdge;
|
471 |
|
|
edge_det ed1(.rst(rst_i), .clk(refclk_i), .ce(1'b1), .i(xclks[1]), .pe(xclkEdge), .ne() );
|
472 |
|
|
|
473 |
|
|
// Detect an edge on the external clock
|
474 |
|
|
wire rxClkEdge;
|
475 |
|
|
edge_det ed2(.rst(rst_i), .clk(refclk_i), .ce(1'b1), .i(RxCs[1]), .pe(rxClkEdge), .ne() );
|
476 |
|
|
|
477 |
|
|
always_comb
|
478 |
|
|
if (xClkSrc) // 16x external clock (xclk)
|
479 |
|
|
baud16 <= xclkEdge;
|
480 |
|
|
else
|
481 |
|
|
baud16 <= ibaud16;
|
482 |
|
|
|
483 |
|
|
assign baud16rx = rxClkSrc ? baud16 : rxClkEdge;
|
484 |
|
|
|
485 |
|
|
//------------------------------------------------------------
|
486 |
|
|
// external signal synchronization
|
487 |
|
|
//------------------------------------------------------------
|
488 |
|
|
|
489 |
|
|
// External receiver clock
|
490 |
|
|
always_ff @(posedge refclk_i)
|
491 |
|
|
RxCs <= {RxCs[1:0],RxC_i};
|
492 |
|
|
|
493 |
|
|
// External baud clock
|
494 |
|
|
always_ff @(posedge refclk_i)
|
495 |
|
|
xclks <= {xclks[1:0],xph2_i};
|
496 |
|
|
|
497 |
|
|
|
498 |
|
|
always_ff @(posedge ph2_i)
|
499 |
|
|
ctsx <= {ctsx[0],llb?~rts_no:~cts_ni};
|
500 |
|
|
|
501 |
|
|
always_ff @(posedge ph2_i)
|
502 |
|
|
dcdx <= {dcdx[0],~dcd_ni};
|
503 |
|
|
|
504 |
|
|
always_ff @(posedge ph2_i)
|
505 |
|
|
dsrx <= {dsrx[0],llb?~dtr_no:~dsr_ni};
|
506 |
|
|
|
507 |
|
|
always_ff @(posedge ph2_i)
|
508 |
|
|
rix <= {rix[0],~ri_ni};
|
509 |
|
|
|
510 |
|
|
//------------------------------------------------------------
|
511 |
|
|
// state change detectors
|
512 |
|
|
//------------------------------------------------------------
|
513 |
|
|
|
514 |
|
|
wire ne_stat;
|
515 |
|
|
edge_det ued3 (
|
516 |
|
|
.rst(rst_i),
|
517 |
|
|
.clk(~ph2_i),
|
518 |
|
|
.ce(1'b1),
|
519 |
|
|
.i(adr_i==`UART_MS && rw_i),
|
520 |
|
|
.pe(),
|
521 |
|
|
.ne(ne_stat),
|
522 |
|
|
.ee()
|
523 |
|
|
);
|
524 |
|
|
|
525 |
|
|
// detect a change on the dsr signal
|
526 |
|
|
always_ff @(posedge ph2_i)
|
527 |
|
|
if (rst_i)
|
528 |
|
|
deltaDsr <= 1'b0;
|
529 |
|
|
else begin
|
530 |
|
|
if (ne_stat)
|
531 |
|
|
deltaDsr <= 0;
|
532 |
|
|
else if (~deltaDsr)
|
533 |
|
|
deltaDsr <= dsrx[1] ^ dsrx[0];
|
534 |
|
|
end
|
535 |
|
|
|
536 |
|
|
// detect a change on the dcd signal
|
537 |
|
|
always_ff @(posedge ph2_i)
|
538 |
|
|
if (rst_i)
|
539 |
|
|
deltaDcd <= 1'b0;
|
540 |
|
|
else begin
|
541 |
|
|
if (ne_stat)
|
542 |
|
|
deltaDcd <= 0;
|
543 |
|
|
else if (~deltaDcd)
|
544 |
|
|
deltaDcd <= dcdx[1] ^ dcdx[0];
|
545 |
|
|
end
|
546 |
|
|
|
547 |
|
|
// detect a change on the cts signal
|
548 |
|
|
always_ff @(posedge ph2_i)
|
549 |
|
|
if (rst_i)
|
550 |
|
|
deltaCts <= 1'b0;
|
551 |
|
|
else begin
|
552 |
|
|
if (ne_stat)
|
553 |
|
|
deltaCts <= 0;
|
554 |
|
|
else if (~deltaCts)
|
555 |
|
|
deltaCts <= ctsx[1] ^ ctsx[0];
|
556 |
|
|
end
|
557 |
|
|
|
558 |
|
|
// detect a change on the ri signal
|
559 |
|
|
always_ff @(posedge ph2_i)
|
560 |
|
|
if (rst_i)
|
561 |
|
|
deltaRi <= 1'b0;
|
562 |
|
|
else begin
|
563 |
|
|
if (ne_stat)
|
564 |
|
|
deltaRi <= 0;
|
565 |
|
|
else if (~deltaRi)
|
566 |
|
|
deltaRi <= rix[1] ^ rix[0];
|
567 |
|
|
end
|
568 |
|
|
|
569 |
|
|
// detect a change in line status
|
570 |
|
|
reg [7:0] pLineStatusReg;
|
571 |
|
|
always_ff @(posedge ph2_i)
|
572 |
|
|
pLineStatusReg <= lineStatusReg;
|
573 |
|
|
|
574 |
|
|
assign lineStatusChange = pLineStatusReg != lineStatusReg;
|
575 |
|
|
|
576 |
|
|
//-----------------------------------------------------
|
577 |
|
|
|
578 |
|
|
// compute recieve timeout
|
579 |
|
|
always_comb
|
580 |
|
|
rxToutMax <= (wordLength << 2) + 6'd12;
|
581 |
|
|
|
582 |
|
|
always_ff @(posedge refclk_i)
|
583 |
|
|
if (rst_i)
|
584 |
|
|
rxTout <= 1'b0;
|
585 |
|
|
else begin
|
586 |
|
|
// read of receiver clears timeout counter
|
587 |
|
|
if (rdrx)
|
588 |
|
|
rxTout <= 1'b0;
|
589 |
|
|
// Don't time out if the fifo is empty
|
590 |
|
|
else if (rxCnt[9:4]==rxToutMax && ~rxEmpty)
|
591 |
|
|
rxTout <= 1'b1;
|
592 |
|
|
end
|
593 |
|
|
|
594 |
|
|
|
595 |
|
|
//-----------------------------------------------------
|
596 |
|
|
// compute the 2x number of stop bits
|
597 |
|
|
always_comb
|
598 |
|
|
if (stopBit==1'b0) // one stop bit
|
599 |
|
|
stopBits <= 3'd2;
|
600 |
|
|
else if (wordLength==6'd8 && parityCtrl != 3'd0)
|
601 |
|
|
stopBits <= 3'd2;
|
602 |
|
|
else if (wordLength==6'd5 && parityCtrl == 3'd0) // 5 bits - 1 1/2 stop bit
|
603 |
|
|
stopBits <= 3'd3;
|
604 |
|
|
else
|
605 |
|
|
stopBits <= 3'd4; // two stop bits
|
606 |
|
|
|
607 |
|
|
|
608 |
|
|
// compute frame size
|
609 |
|
|
// frame size is one less
|
610 |
|
|
assign frameSize = {wordLength + 4'd1 + stopBits[2:1] + parityCtrl[0], stopBits[0],3'b0} - 1;
|
611 |
|
|
|
612 |
|
|
//-----------------------------------------------------
|
613 |
|
|
// encode IRQ mailbox
|
614 |
|
|
always_comb
|
615 |
|
|
irqenc <=
|
616 |
|
|
lineStatusChange ? 3'd0 :
|
617 |
|
|
~rxDRQ_o ? 3'd1 :
|
618 |
|
|
rxTout ? 3'd2 :
|
619 |
|
|
~txDRQ_o ? 3'd3 :
|
620 |
|
|
modemStatusChange ? 3'd4 :
|
621 |
|
|
3'd0;
|
622 |
|
|
|
623 |
|
|
endmodule
|