OpenCores
URL https://opencores.org/ocsvn/uart6551/uart6551/trunk

Subversion Repositories uart6551

[/] [uart6551/] [trunk/] [trunk/] [rtl/] [uart6551.sv] - Blame information for rev 6

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.