1 |
13 |
robfinch |
// ============================================================================
|
2 |
|
|
// __
|
3 |
|
|
// \\__/ o\ (C) 2005-2023 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 |
|
|
// 369 LUTs / 409 FFs
|
36 |
|
|
// ============================================================================
|
37 |
|
|
//
|
38 |
|
|
`define UART_TRB 2'd0 // transmit/receive buffer
|
39 |
|
|
`define UART_STAT 2'd1
|
40 |
|
|
`define UART_CMD 2'd2
|
41 |
|
|
`define UART_CTRL 2'd3
|
42 |
|
|
|
43 |
|
|
import fta_bus_pkg::*;
|
44 |
|
|
|
45 |
|
|
module uart6551pci_fta32(rst_i, clk_i, cs_config_i, cs_io_i, irq_o,
|
46 |
|
|
req, resp,
|
47 |
|
|
cts_ni, rts_no, dsr_ni, dcd_ni, dtr_no, ri_ni,
|
48 |
|
|
rxd_i, txd_o, data_present,
|
49 |
|
|
rxDRQ_o, txDRQ_o,
|
50 |
|
|
xclk_i, RxC_i
|
51 |
|
|
);
|
52 |
|
|
parameter pClkFreq = 100;
|
53 |
|
|
parameter pCounterBits = 24;
|
54 |
|
|
parameter pFifoSize = 1024;
|
55 |
|
|
parameter pClkDiv = 24'd1302; // 9.6k baud, 200.000MHz clock
|
56 |
|
|
parameter HIGH = 1'b1;
|
57 |
|
|
parameter LOW = 1'b0;
|
58 |
|
|
|
59 |
|
|
parameter UART_ADDR = 32'hFED00001;
|
60 |
|
|
parameter UART_ADDR_MASK = 32'h00FF0000;
|
61 |
|
|
|
62 |
|
|
parameter CFG_BUS = 8'd0;
|
63 |
|
|
parameter CFG_DEVICE = 5'd16;
|
64 |
|
|
parameter CFG_FUNC = 3'd0;
|
65 |
|
|
parameter CFG_VENDOR_ID = 16'h0;
|
66 |
|
|
parameter CFG_DEVICE_ID = 16'h0;
|
67 |
|
|
parameter CFG_SUBSYSTEM_VENDOR_ID = 16'h0;
|
68 |
|
|
parameter CFG_SUBSYSTEM_ID = 16'h0;
|
69 |
|
|
parameter CFG_ROM_ADDR = 32'hFFFFFFF0;
|
70 |
|
|
|
71 |
|
|
parameter CFG_REVISION_ID = 8'd0;
|
72 |
|
|
parameter CFG_PROGIF = 8'd1;
|
73 |
|
|
parameter CFG_SUBCLASS = 8'h80; // 80 = Other
|
74 |
|
|
parameter CFG_CLASS = 8'h03; // 03 = display controller
|
75 |
|
|
parameter CFG_CACHE_LINE_SIZE = 8'd8; // 32-bit units
|
76 |
|
|
parameter CFG_MIN_GRANT = 8'h00;
|
77 |
|
|
parameter CFG_MAX_LATENCY = 8'h00;
|
78 |
|
|
parameter CFG_IRQ_LINE = 8'd16;
|
79 |
|
|
|
80 |
|
|
localparam CFG_HEADER_TYPE = 8'h00; // 00 = a general device
|
81 |
|
|
|
82 |
|
|
parameter MSIX = 1'b0;
|
83 |
|
|
input rst_i;
|
84 |
|
|
input clk_i; // fta bus clock eg. 50.000MHz
|
85 |
|
|
input cs_config_i; // config region circuit select
|
86 |
|
|
input cs_io_i; // IO region circuit select
|
87 |
|
|
// FTA -------------------------------
|
88 |
|
|
input fta_cmd_request32_t req;
|
89 |
|
|
output fta_cmd_response32_t resp;
|
90 |
|
|
//------------------------------------------
|
91 |
|
|
output reg [31:0] irq_o; // interrupt request
|
92 |
|
|
input cts_ni; // clear to send - (flow control) active low
|
93 |
|
|
output reg rts_no; // request to send - (flow control) active low
|
94 |
|
|
input dsr_ni; // data set ready - active low
|
95 |
|
|
input dcd_ni; // data carrier detect - active low
|
96 |
|
|
output reg dtr_no; // data terminal ready - active low
|
97 |
|
|
input ri_ni; // ring indicator
|
98 |
|
|
input rxd_i; // serial data in
|
99 |
|
|
output txd_o; // serial data out
|
100 |
|
|
output data_present;
|
101 |
|
|
output rxDRQ_o; // reciever DMA request
|
102 |
|
|
output txDRQ_o; // transmitter DMA request
|
103 |
|
|
input xclk_i; // external clock source
|
104 |
|
|
input RxC_i; // external receiver clock source
|
105 |
|
|
|
106 |
|
|
wire cs_uart;
|
107 |
|
|
reg [31:0] uart_addr;
|
108 |
|
|
reg accessCD; // clock multiplier access flag
|
109 |
|
|
reg llb; // local loopback mode
|
110 |
|
|
reg dmaEnable;
|
111 |
|
|
// baud rate clock control
|
112 |
|
|
reg [4:0] baudRateSel;
|
113 |
|
|
reg selCD; // Use clock multiplier register
|
114 |
|
|
reg [pCounterBits-1:0] c; // current count
|
115 |
|
|
reg [pCounterBits-1:0] ckdiv; // baud rate clock divider
|
116 |
|
|
reg [pCounterBits-1:0] clkdiv; // clock multiplier register
|
117 |
|
|
reg [1:0] xclks; // synchronized external clock
|
118 |
|
|
reg [1:0] RxCs; // synchronized external receiver clock
|
119 |
|
|
reg baud16; // 16x baud rate clock
|
120 |
|
|
wire baud16rx; // reciever clock
|
121 |
|
|
reg xClkSrc; // uart baud clock is external
|
122 |
|
|
reg rxClkSrc; // receiver clock is external
|
123 |
|
|
|
124 |
|
|
// frame format registers
|
125 |
|
|
reg [3:0] wordLength;
|
126 |
|
|
reg stopBit;
|
127 |
|
|
reg [2:0] stopBits;
|
128 |
|
|
reg [2:0] parityCtrl;
|
129 |
|
|
wire [7:0] frameSize;
|
130 |
|
|
|
131 |
|
|
reg txBreak; // transmit a break
|
132 |
|
|
|
133 |
|
|
wire rxFull;
|
134 |
|
|
wire rxEmpty;
|
135 |
|
|
wire txFull;
|
136 |
|
|
wire txEmpty;
|
137 |
|
|
reg hwfc; // hardware flow control enable
|
138 |
|
|
wire [7:0] lineStatusReg;
|
139 |
|
|
wire [7:0] modemStatusReg;
|
140 |
|
|
wire [7:0] irqStatusReg;
|
141 |
|
|
// interrupt
|
142 |
|
|
wire irq_en; // global IRQ enable
|
143 |
|
|
reg irq;
|
144 |
|
|
reg rxIe;
|
145 |
|
|
reg txIe;
|
146 |
|
|
reg modemStatusChangeIe;
|
147 |
|
|
wire modemStatusChange;
|
148 |
|
|
reg lineStatusChangeIe;
|
149 |
|
|
wire lineStatusChange;
|
150 |
|
|
reg rxToutIe; // receiver timeout interrupt enable
|
151 |
|
|
reg [3:0] rxThres; // receiver threshold for interrupt
|
152 |
|
|
reg [3:0] txThres; // transmitter threshold for interrupt
|
153 |
|
|
reg rxTout; // receiver timeout
|
154 |
|
|
wire [9:0] rxCnt; // reciever counter value
|
155 |
|
|
reg [7:0] rxToutMax;
|
156 |
|
|
reg [2:0] irqenc; // encoded irq cause
|
157 |
|
|
wire rxITrig; // receiver interrupt trigger level
|
158 |
|
|
wire txITrig; // transmitter interrupt trigger level
|
159 |
|
|
// reciever errors
|
160 |
|
|
wire parityErr; // reciever detected a parity error
|
161 |
|
|
wire frameErr; // receiver char framing error
|
162 |
|
|
wire overrun; // receiver over run
|
163 |
|
|
wire rxBreak; // reciever detected a break
|
164 |
|
|
wire rxGErr; // global error: there is at least one error in the reciever fifo
|
165 |
|
|
// modem controls
|
166 |
|
|
reg [1:0] ctsx; // cts_n sampling
|
167 |
|
|
reg [1:0] dcdx;
|
168 |
|
|
reg [1:0] dsrx;
|
169 |
|
|
reg [1:0] rix;
|
170 |
|
|
reg deltaCts;
|
171 |
|
|
reg deltaDcd;
|
172 |
|
|
reg deltaDsr;
|
173 |
|
|
reg deltaRi;
|
174 |
|
|
|
175 |
|
|
// fifo
|
176 |
|
|
reg rxFifoClear;
|
177 |
|
|
reg txFifoClear;
|
178 |
|
|
reg txClear;
|
179 |
|
|
reg fifoEnable;
|
180 |
|
|
wire [3:0] rxQued;
|
181 |
|
|
wire [3:0] txQued;
|
182 |
|
|
|
183 |
|
|
fta_cmd_request32_t reqi;
|
184 |
|
|
|
185 |
|
|
// config
|
186 |
|
|
reg [31:0] cfg_out;
|
187 |
|
|
|
188 |
|
|
// test
|
189 |
|
|
wire txd1;
|
190 |
|
|
|
191 |
|
|
assign data_present = ~rxEmpty;
|
192 |
|
|
|
193 |
|
|
assign rxITrig = rxQued >= rxThres;
|
194 |
|
|
assign txITrig = txQued <= txThres;
|
195 |
|
|
wire rxDRQ1 = (fifoEnable ? rxITrig : ~rxEmpty);
|
196 |
|
|
wire txDRQ1 = (fifoEnable ? txITrig : txEmpty);
|
197 |
|
|
assign rxDRQ_o = dmaEnable & rxDRQ1;
|
198 |
|
|
assign txDRQ_o = dmaEnable & txDRQ1;
|
199 |
|
|
wire rxIRQ = rxIe & rxDRQ1;
|
200 |
|
|
wire txIRQ = txIe & txDRQ1;
|
201 |
|
|
|
202 |
|
|
reg [7:0] cmd0, cmd1, cmd2, cmd3;
|
203 |
|
|
reg [7:0] ctrl0, ctrl1, ctrl2, ctrl3;
|
204 |
|
|
|
205 |
|
|
always_ff @(posedge clk_i)
|
206 |
|
|
irq <= (
|
207 |
|
|
rxIRQ
|
208 |
|
|
| txIRQ
|
209 |
|
|
| (rxTout & rxToutIe)
|
210 |
|
|
| (lineStatusChange & lineStatusChangeIe)
|
211 |
|
|
| (modemStatusChange & modemStatusChangeIe)
|
212 |
|
|
) & irq_en;
|
213 |
|
|
;
|
214 |
|
|
|
215 |
|
|
// Hold onto address and data an extra cycle.
|
216 |
|
|
// The extra cycle updates or reads the serial transmit / receive.
|
217 |
|
|
reg we;
|
218 |
|
|
reg [3:0] sel;
|
219 |
|
|
reg [31:0] dati;
|
220 |
|
|
reg [31:0] dat_o;
|
221 |
|
|
reg [31:0] adr_h;
|
222 |
|
|
always_ff @(posedge clk_i)
|
223 |
|
|
reqi <= req;
|
224 |
|
|
always_ff @(posedge clk_i)
|
225 |
|
|
dati <= req.dat;
|
226 |
|
|
always_ff @(posedge clk_i)
|
227 |
|
|
adr_h <= req.padr;
|
228 |
|
|
always_ff @(posedge clk_i)
|
229 |
|
|
we <= req.we;
|
230 |
|
|
always_ff @(posedge clk_i)
|
231 |
|
|
sel <= req.sel;
|
232 |
|
|
|
233 |
|
|
wire [7:0] rx_do;
|
234 |
|
|
reg erc;
|
235 |
|
|
|
236 |
|
|
reg cs_config, cs_io, cs_io_ii;
|
237 |
|
|
always_ff @(posedge clk_i)
|
238 |
|
|
erc <= req.cti==fta_bus_pkg::ERC;
|
239 |
|
|
always_ff @(posedge clk_i)
|
240 |
|
|
cs_config <= req.cyc & req.stb & cs_config_i && req.padr[27:20]==CFG_BUS && req.padr[19:15]==CFG_DEVICE && req.padr[14:12]==CFG_FUNC;
|
241 |
|
|
always_ff @(posedge clk_i)
|
242 |
|
|
cs_io_ii <= cs_io_i;
|
243 |
|
|
always_comb
|
244 |
|
|
cs_io = cs_io_ii & reqi.cyc & reqi.stb && cs_uart;
|
245 |
|
|
|
246 |
|
|
wire rdrx = cs_io && adr_h[3:2]==`UART_TRB && ~we && !accessCD;
|
247 |
|
|
wire txrx = cs_io && we && adr_h[3:2]==`UART_TRB && !accessCD;
|
248 |
|
|
|
249 |
|
|
vtdl #(.WID(1), .DEP(16)) urdyd2 (.clk(clk_i), .ce(1'b1), .a(4'd0), .d((cs_io|cs_config)&(erc|~we)), .q(resp.ack));
|
250 |
|
|
vtdl #(.WID(6), .DEP(16)) urdyd3 (.clk(clk_i), .ce(1'b1), .a(4'd1), .d(req.cid), .q(resp.cid));
|
251 |
|
|
vtdl #(.WID($bits(fta_tranid_t)), .DEP(16)) urdyd4 (.clk(clk_i), .ce(1'b1), .a(4'd1), .d(req.tid), .q(resp.tid));
|
252 |
|
|
vtdl #(.WID($bits(fta_address_t)), .DEP(16)) urdyd5 (.clk(clk_i), .ce(1'b1), .a(4'd1), .d(req.padr), .q(resp.adr));
|
253 |
|
|
assign resp.next = 1'b0;
|
254 |
|
|
assign resp.stall = 1'b0;
|
255 |
|
|
assign resp.err = 1'b0;
|
256 |
|
|
assign resp.rty = 1'b0;
|
257 |
|
|
assign resp.pri = 4'd7;
|
258 |
|
|
assign resp.dat = dat_o;
|
259 |
|
|
|
260 |
|
|
pci32_config #(
|
261 |
|
|
.CFG_BUS(CFG_BUS),
|
262 |
|
|
.CFG_DEVICE(CFG_DEVICE),
|
263 |
|
|
.CFG_FUNC(CFG_FUNC),
|
264 |
|
|
.CFG_VENDOR_ID(CFG_VENDOR_ID),
|
265 |
|
|
.CFG_DEVICE_ID(CFG_DEVICE_ID),
|
266 |
|
|
.CFG_BAR0(UART_ADDR),
|
267 |
|
|
.CFG_BAR0_MASK(UART_ADDR_MASK),
|
268 |
|
|
.CFG_SUBSYSTEM_VENDOR_ID(CFG_SUBSYSTEM_VENDOR_ID),
|
269 |
|
|
.CFG_SUBSYSTEM_ID(CFG_SUBSYSTEM_ID),
|
270 |
|
|
.CFG_ROM_ADDR(CFG_ROM_ADDR),
|
271 |
|
|
.CFG_REVISION_ID(CFG_REVISION_ID),
|
272 |
|
|
.CFG_PROGIF(CFG_PROGIF),
|
273 |
|
|
.CFG_SUBCLASS(CFG_SUBCLASS),
|
274 |
|
|
.CFG_CLASS(CFG_CLASS),
|
275 |
|
|
.CFG_CACHE_LINE_SIZE(CFG_CACHE_LINE_SIZE),
|
276 |
|
|
.CFG_MIN_GRANT(CFG_MIN_GRANT),
|
277 |
|
|
.CFG_MAX_LATENCY(CFG_MAX_LATENCY),
|
278 |
|
|
.CFG_IRQ_LINE(CFG_IRQ_LINE)
|
279 |
|
|
)
|
280 |
|
|
ucfg1
|
281 |
|
|
(
|
282 |
|
|
.rst_i(rst_i),
|
283 |
|
|
.clk_i(clk_i),
|
284 |
|
|
.irq_i(irq),
|
285 |
|
|
.irq_o(irq_o),
|
286 |
|
|
.cs_config_i(cs_config),
|
287 |
|
|
.we_i(we),
|
288 |
|
|
.sel_i(sel),
|
289 |
|
|
.adr_i(adr_h),
|
290 |
|
|
.dat_i(dati),
|
291 |
|
|
.dat_o(cfg_out),
|
292 |
|
|
.cs_bar0_o(cs_uart),
|
293 |
|
|
.cs_bar1_o(),
|
294 |
|
|
.cs_bar2_o(),
|
295 |
|
|
.irq_en_o(irq_en)
|
296 |
|
|
);
|
297 |
|
|
|
298 |
|
|
uart6551Rx uart_rx0
|
299 |
|
|
(
|
300 |
|
|
.rst(rst_i),
|
301 |
|
|
.clk(clk_i),
|
302 |
|
|
.cyc(cs_io),
|
303 |
|
|
.cs(rdrx),
|
304 |
|
|
.wr(we),
|
305 |
|
|
.dout(rx_do),
|
306 |
|
|
.ack(),
|
307 |
|
|
.fifoEnable(fifoEnable),
|
308 |
|
|
.fifoClear(rxFifoClear),
|
309 |
|
|
.clearGErr(1'b0),
|
310 |
|
|
.wordLength(wordLength),
|
311 |
|
|
.parityCtrl(parityCtrl),
|
312 |
|
|
.frameSize(frameSize),
|
313 |
|
|
.stop_bits(stopBits),
|
314 |
|
|
.baud16x_ce(baud16rx),
|
315 |
|
|
.clear(1'b0),
|
316 |
|
|
.rxd(llb ? txd1 : rxd_i),
|
317 |
|
|
.full(),
|
318 |
|
|
.empty(rxEmpty),
|
319 |
|
|
.frameErr(frameErr),
|
320 |
|
|
.overrun(overrun),
|
321 |
|
|
.parityErr(parityErr),
|
322 |
|
|
.break_o(rxBreak),
|
323 |
|
|
.gerr(rxGErr),
|
324 |
|
|
.qcnt(rxQued),
|
325 |
|
|
.cnt(rxCnt)
|
326 |
|
|
);
|
327 |
|
|
|
328 |
|
|
uart6551Tx uart_tx0
|
329 |
|
|
(
|
330 |
|
|
.rst(rst_i),
|
331 |
|
|
.clk(clk_i),
|
332 |
|
|
.cyc(cs_io),
|
333 |
|
|
.cs(txrx),
|
334 |
|
|
.wr(we),
|
335 |
|
|
.din(dati[7:0]),
|
336 |
|
|
.ack(),
|
337 |
|
|
.fifoEnable(fifoEnable),
|
338 |
|
|
.fifoClear(txFifoClear),
|
339 |
|
|
.txBreak(txBreak),
|
340 |
|
|
.frameSize(frameSize), // 16 x 10 bits
|
341 |
|
|
.wordLength(wordLength),// 8 bits
|
342 |
|
|
.parityCtrl(parityCtrl),// no parity
|
343 |
|
|
.baud16x_ce(baud16),
|
344 |
|
|
.cts(ctsx[1]|~hwfc),
|
345 |
|
|
.clear(txClear),
|
346 |
|
|
.txd(txd1),
|
347 |
|
|
.full(txFull),
|
348 |
|
|
.empty(txEmpty),
|
349 |
|
|
.qcnt(txQued)
|
350 |
|
|
);
|
351 |
|
|
|
352 |
|
|
assign txd_o = llb ? 1'b1 : txd1;
|
353 |
|
|
|
354 |
|
|
assign lineStatusReg = {rxGErr,1'b0,txFull,rxBreak,1'b0,1'b0,1'b0,1'b0};
|
355 |
|
|
assign modemStatusChange = deltaDcd|deltaRi|deltaDsr|deltaCts; // modem status delta
|
356 |
|
|
assign modemStatusReg = {1'b0,~rix[1],1'b0,~ctsx[1],deltaDcd, deltaRi, deltaDsr, deltaCts};
|
357 |
|
|
assign irqStatusReg = {irq_o,2'b00,irqenc,2'b00};
|
358 |
|
|
|
359 |
|
|
// mux the reg outputs
|
360 |
|
|
always_ff @(posedge clk_i)
|
361 |
|
|
if (cs_config)
|
362 |
|
|
dat_o <= cfg_out;
|
363 |
|
|
else if (cs_io) begin
|
364 |
|
|
case(adr_h[3:2])
|
365 |
|
|
`UART_TRB: dat_o <= accessCD ? {8'h0,clkdiv} : {24'h0,rx_do}; // receiver holding register
|
366 |
|
|
`UART_STAT: dat_o <= {irqStatusReg,modemStatusReg,lineStatusReg,irq_o,dsrx[1],dcdx[1],fifoEnable ? ~txFull : txEmpty,~rxEmpty,overrun,frameErr,parityErr};
|
367 |
|
|
`UART_CMD: dat_o <= {cmd3,cmd2,cmd1,cmd0};
|
368 |
|
|
`UART_CTRL: dat_o <= {ctrl3,ctrl2,ctrl1,ctrl0};
|
369 |
|
|
endcase
|
370 |
|
|
end
|
371 |
|
|
|
372 |
|
|
|
373 |
|
|
// register updates
|
374 |
|
|
always_ff @(posedge clk_i)
|
375 |
|
|
if (rst_i) begin
|
376 |
|
|
rts_no <= HIGH;
|
377 |
|
|
dtr_no <= HIGH;
|
378 |
|
|
// interrupts
|
379 |
|
|
rxIe <= 1'b0;
|
380 |
|
|
txIe <= 1'b0;
|
381 |
|
|
modemStatusChangeIe <= 1'b0;
|
382 |
|
|
lineStatusChangeIe <= 1'b0;
|
383 |
|
|
hwfc <= 1'b0;
|
384 |
|
|
modemStatusChangeIe <= 1'b0;
|
385 |
|
|
lineStatusChangeIe <= 1'b0;
|
386 |
|
|
dmaEnable <= 1'b0;
|
387 |
|
|
// clock control
|
388 |
|
|
baudRateSel <= 5'h0;
|
389 |
|
|
rxClkSrc <= 1'b0; // ** 6551 defaults to zero (external receiver clock)
|
390 |
|
|
clkdiv <= pClkDiv;
|
391 |
|
|
// frame format
|
392 |
|
|
wordLength <= 4'd8; // 8 bits
|
393 |
|
|
stopBit <= 1'b0; // 1 stop bit
|
394 |
|
|
parityCtrl <= 3'd0; // no parity
|
395 |
|
|
|
396 |
|
|
txBreak <= 1'b0;
|
397 |
|
|
// Fifo control
|
398 |
|
|
txFifoClear <= 1'b1;
|
399 |
|
|
rxFifoClear <= 1'b1;
|
400 |
|
|
txClear <= 1'b1;
|
401 |
|
|
fifoEnable <= 1'b1;
|
402 |
|
|
// Test
|
403 |
|
|
llb <= 1'b0;
|
404 |
|
|
selCD <= 1'b0;
|
405 |
|
|
accessCD <= 1'b0;
|
406 |
|
|
|
407 |
|
|
cmd0 <= 8'h00;
|
408 |
|
|
cmd1 <= 8'h00;
|
409 |
|
|
cmd2 <= 8'h00;
|
410 |
|
|
cmd3 <= 8'h00;
|
411 |
|
|
|
412 |
|
|
ctrl0 <= 8'h00;
|
413 |
|
|
ctrl1 <= 8'h00;
|
414 |
|
|
ctrl2 <= 8'h06;
|
415 |
|
|
ctrl3 <= 8'h20;
|
416 |
|
|
end
|
417 |
|
|
else begin
|
418 |
|
|
|
419 |
|
|
//llb <= 1'b1;
|
420 |
|
|
rxFifoClear <= 1'b0;
|
421 |
|
|
txFifoClear <= 1'b0;
|
422 |
|
|
txClear <= 1'b0;
|
423 |
|
|
ctrl2[1] <= 1'b0;
|
424 |
|
|
ctrl2[2] <= 1'b0;
|
425 |
|
|
|
426 |
|
|
if (cs_io & we) begin
|
427 |
|
|
case (adr_h[3:2]) // synopsys full_case parallel_case
|
428 |
|
|
|
429 |
|
|
`UART_TRB:
|
430 |
|
|
if (accessCD) begin
|
431 |
|
|
clkdiv <= dati;
|
432 |
|
|
accessCD <= 1'b0;
|
433 |
|
|
ctrl3[7] <= 1'b0;
|
434 |
|
|
end
|
435 |
|
|
|
436 |
|
|
// Writing to the status register does a software reset of some bits.
|
437 |
|
|
`UART_STAT:
|
438 |
|
|
begin
|
439 |
|
|
dtr_no <= HIGH;
|
440 |
|
|
rxIe <= 1'b0;
|
441 |
|
|
rts_no <= HIGH;
|
442 |
|
|
txIe <= 1'b0;
|
443 |
|
|
txBreak <= 1'b0;
|
444 |
|
|
llb <= 1'b0;
|
445 |
|
|
end
|
446 |
|
|
`UART_CMD:
|
447 |
|
|
begin
|
448 |
|
|
if (sel[0]) begin
|
449 |
|
|
cmd0 <= dati[7:0];
|
450 |
|
|
dtr_no <= ~dati[0];
|
451 |
|
|
rxIe <= ~dati[1];
|
452 |
|
|
case(dati[3:2])
|
453 |
|
|
2'd0: begin rts_no <= 1'b1; txIe <= 1'b0; txBreak <= 1'b0; end
|
454 |
|
|
2'd1: begin rts_no <= 1'b0; txIe <= 1'b1; txBreak <= 1'b0; end
|
455 |
|
|
2'd2: begin rts_no <= 1'b0; txIe <= 1'b0; txBreak <= 1'b0; end
|
456 |
|
|
2'd3: begin rts_no <= 1'b0; txIe <= 1'b0; txBreak <= 1'b1; end
|
457 |
|
|
endcase
|
458 |
|
|
llb <= dati[4];
|
459 |
|
|
parityCtrl <= dati[7:5]; //000=none,001=odd,011=even,101=force 1,111 = force 0
|
460 |
|
|
end
|
461 |
|
|
if (sel[1]) begin
|
462 |
|
|
cmd1 <= dati[15:8];
|
463 |
|
|
lineStatusChangeIe <= dati[8];
|
464 |
|
|
modemStatusChangeIe <= dati[9];
|
465 |
|
|
rxToutIe <= dati[10];
|
466 |
|
|
end
|
467 |
|
|
if (sel[2])
|
468 |
|
|
cmd2 <= dati[23:16];
|
469 |
|
|
if (sel[3])
|
470 |
|
|
cmd3 <= dati[31:24];
|
471 |
|
|
end
|
472 |
|
|
|
473 |
|
|
`UART_CTRL:
|
474 |
|
|
begin
|
475 |
|
|
if (sel[0]) begin
|
476 |
|
|
ctrl0 <= dati[7:0];
|
477 |
|
|
baudRateSel[3:0] <= dati[3:0];
|
478 |
|
|
rxClkSrc <= dati[4]; // 1 = baud rate generator, 0 = external
|
479 |
|
|
//11=5,10=6,01=7,00=8
|
480 |
|
|
case(dati[6:5])
|
481 |
|
|
2'd0: wordLength <= 6'd8;
|
482 |
|
|
2'd1: wordLength <= 6'd7;
|
483 |
|
|
2'd2: wordLength <= 6'd6;
|
484 |
|
|
2'd3: wordLength <= 6'd5;
|
485 |
|
|
endcase
|
486 |
|
|
stopBit <= dati[7]; //0=1,1=1.5 or 2
|
487 |
|
|
end
|
488 |
|
|
// Extended word length, values beyond 11 not supported.
|
489 |
|
|
if (sel[1]) begin
|
490 |
|
|
ctrl1 <= dati[15:8];
|
491 |
|
|
end
|
492 |
|
|
if (sel[2]) begin
|
493 |
|
|
ctrl2 <= dati[23:16];
|
494 |
|
|
fifoEnable <= dati[16];
|
495 |
|
|
rxFifoClear <= dati[17];
|
496 |
|
|
txFifoClear <= dati[18];
|
497 |
|
|
case (dati[21:20])
|
498 |
|
|
2'd0: txThres <= 4'd1; // one-byte
|
499 |
|
|
2'd1: txThres <= pFifoSize / 4; // one-quarter full
|
500 |
|
|
2'd2: txThres <= pFifoSize / 2; // one-half full
|
501 |
|
|
2'd3: txThres <= pFifoSize * 3 / 4; // three-quarters full
|
502 |
|
|
endcase
|
503 |
|
|
case (dati[23:22])
|
504 |
|
|
2'd0: rxThres <= 4'd1; // one-byte
|
505 |
|
|
2'd1: rxThres <= pFifoSize / 4; // one-quarter full
|
506 |
|
|
2'd2: rxThres <= pFifoSize / 2; // one-half full
|
507 |
|
|
2'd3: rxThres <= pFifoSize * 3 / 4; // three quarters full
|
508 |
|
|
endcase
|
509 |
|
|
end
|
510 |
|
|
if (sel[3]) begin
|
511 |
|
|
ctrl3 <= dati[31:24];
|
512 |
|
|
hwfc <= dati[24];
|
513 |
|
|
dmaEnable <= dati[26];
|
514 |
|
|
baudRateSel[4] <= dati[27];
|
515 |
|
|
txClear <= dati[29];
|
516 |
|
|
selCD <= dati[30];
|
517 |
|
|
accessCD <= dati[31];
|
518 |
|
|
end
|
519 |
|
|
end
|
520 |
|
|
|
521 |
|
|
default:
|
522 |
|
|
;
|
523 |
|
|
endcase
|
524 |
|
|
end
|
525 |
|
|
end
|
526 |
|
|
|
527 |
|
|
// ----------------------------------------------------------------------------
|
528 |
|
|
// Baud rate control.
|
529 |
|
|
// ----------------------------------------------------------------------------
|
530 |
|
|
|
531 |
|
|
always_ff @(posedge clk_i)
|
532 |
|
|
xClkSrc <= baudRateSel==5'd0;
|
533 |
|
|
|
534 |
|
|
wire [pCounterBits-1:0] bclkdiv;
|
535 |
|
|
uart6551BaudLUT #(.pClkFreq(pClkFreq), .pCounterBits(pCounterBits)) ublt1 (.a(baudRateSel), .o(bclkdiv));
|
536 |
|
|
|
537 |
|
|
reg [pCounterBits-1:0] clkdiv2;
|
538 |
|
|
always_ff @(posedge clk_i)
|
539 |
|
|
clkdiv2 <= selCD ? clkdiv : bclkdiv;
|
540 |
|
|
|
541 |
|
|
always_ff @(posedge clk_i)
|
542 |
|
|
if (rst_i)
|
543 |
|
|
c <= 24'd1;
|
544 |
|
|
else begin
|
545 |
|
|
c <= c + 2'd1;
|
546 |
|
|
if (c >= clkdiv2)
|
547 |
|
|
c <= 2'd1;
|
548 |
|
|
end
|
549 |
|
|
|
550 |
|
|
// for detecting an edge on the baud clock
|
551 |
|
|
wire ibaud16 = c == 2'd1;
|
552 |
|
|
|
553 |
|
|
// Detect an edge on the external clock
|
554 |
|
|
wire xclkEdge;
|
555 |
|
|
edge_det ed1(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(xclks[1]), .pe(xclkEdge), .ne() );
|
556 |
|
|
|
557 |
|
|
// Detect an edge on the external clock
|
558 |
|
|
wire rxClkEdge;
|
559 |
|
|
edge_det ed2(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(RxCs[1]), .pe(rxClkEdge), .ne() );
|
560 |
|
|
|
561 |
|
|
always_comb
|
562 |
|
|
if (xClkSrc) // 16x external clock (xclk)
|
563 |
|
|
baud16 <= xclkEdge;
|
564 |
|
|
else
|
565 |
|
|
baud16 <= ibaud16;
|
566 |
|
|
|
567 |
|
|
assign baud16rx = rxClkSrc ? baud16 : rxClkEdge;
|
568 |
|
|
|
569 |
|
|
//------------------------------------------------------------
|
570 |
|
|
// external signal synchronization
|
571 |
|
|
//------------------------------------------------------------
|
572 |
|
|
|
573 |
|
|
// External receiver clock
|
574 |
|
|
always_ff @(posedge clk_i)
|
575 |
|
|
RxCs <= {RxCs[1:0],RxC_i};
|
576 |
|
|
|
577 |
|
|
// External baud clock
|
578 |
|
|
always_ff @(posedge clk_i)
|
579 |
|
|
xclks <= {xclks[1:0],xclk_i};
|
580 |
|
|
|
581 |
|
|
|
582 |
|
|
always_ff @(posedge clk_i)
|
583 |
|
|
ctsx <= {ctsx[0],llb?~rts_no:~cts_ni};
|
584 |
|
|
|
585 |
|
|
always_ff @(posedge clk_i)
|
586 |
|
|
dcdx <= {dcdx[0],~dcd_ni};
|
587 |
|
|
|
588 |
|
|
always_ff @(posedge clk_i)
|
589 |
|
|
dsrx <= {dsrx[0],llb?~dtr_no:~dsr_ni};
|
590 |
|
|
|
591 |
|
|
always_ff @(posedge clk_i)
|
592 |
|
|
rix <= {rix[0],~ri_ni};
|
593 |
|
|
|
594 |
|
|
//------------------------------------------------------------
|
595 |
|
|
// state change detectors
|
596 |
|
|
//------------------------------------------------------------
|
597 |
|
|
|
598 |
|
|
wire ne_stat;
|
599 |
|
|
edge_det ued3 (
|
600 |
|
|
.rst(rst_i),
|
601 |
|
|
.clk(clk_i),
|
602 |
|
|
.ce(1'b1),
|
603 |
|
|
.i(cs_io && adr_h==`UART_STAT && ~we && sel[2]),
|
604 |
|
|
.pe(),
|
605 |
|
|
.ne(ne_stat),
|
606 |
|
|
.ee()
|
607 |
|
|
);
|
608 |
|
|
|
609 |
|
|
// detect a change on the dsr signal
|
610 |
|
|
always_ff @(posedge clk_i)
|
611 |
|
|
if (rst_i)
|
612 |
|
|
deltaDsr <= 1'b0;
|
613 |
|
|
else begin
|
614 |
|
|
if (ne_stat)
|
615 |
|
|
deltaDsr <= 0;
|
616 |
|
|
else if (~deltaDsr)
|
617 |
|
|
deltaDsr <= dsrx[1] ^ dsrx[0];
|
618 |
|
|
end
|
619 |
|
|
|
620 |
|
|
// detect a change on the dcd signal
|
621 |
|
|
always_ff @(posedge clk_i)
|
622 |
|
|
if (rst_i)
|
623 |
|
|
deltaDcd <= 1'b0;
|
624 |
|
|
else begin
|
625 |
|
|
if (ne_stat)
|
626 |
|
|
deltaDcd <= 0;
|
627 |
|
|
else if (~deltaDcd)
|
628 |
|
|
deltaDcd <= dcdx[1] ^ dcdx[0];
|
629 |
|
|
end
|
630 |
|
|
|
631 |
|
|
// detect a change on the cts signal
|
632 |
|
|
always_ff @(posedge clk_i)
|
633 |
|
|
if (rst_i)
|
634 |
|
|
deltaCts <= 1'b0;
|
635 |
|
|
else begin
|
636 |
|
|
if (ne_stat)
|
637 |
|
|
deltaCts <= 0;
|
638 |
|
|
else if (~deltaCts)
|
639 |
|
|
deltaCts <= ctsx[1] ^ ctsx[0];
|
640 |
|
|
end
|
641 |
|
|
|
642 |
|
|
// detect a change on the ri signal
|
643 |
|
|
always_ff @(posedge clk_i)
|
644 |
|
|
if (rst_i)
|
645 |
|
|
deltaRi <= 1'b0;
|
646 |
|
|
else begin
|
647 |
|
|
if (ne_stat)
|
648 |
|
|
deltaRi <= 0;
|
649 |
|
|
else if (~deltaRi)
|
650 |
|
|
deltaRi <= rix[1] ^ rix[0];
|
651 |
|
|
end
|
652 |
|
|
|
653 |
|
|
// detect a change in line status
|
654 |
|
|
reg [7:0] pLineStatusReg;
|
655 |
|
|
always_ff @(posedge clk_i)
|
656 |
|
|
pLineStatusReg <= lineStatusReg;
|
657 |
|
|
|
658 |
|
|
assign lineStatusChange = pLineStatusReg != lineStatusReg;
|
659 |
|
|
|
660 |
|
|
//-----------------------------------------------------
|
661 |
|
|
|
662 |
|
|
// compute recieve timeout
|
663 |
|
|
always_comb
|
664 |
|
|
rxToutMax <= (wordLength << 2) + 6'd12;
|
665 |
|
|
|
666 |
|
|
always_ff @(posedge clk_i)
|
667 |
|
|
if (rst_i)
|
668 |
|
|
rxTout <= 1'b0;
|
669 |
|
|
else begin
|
670 |
|
|
// read of receiver clears timeout counter
|
671 |
|
|
if (rdrx)
|
672 |
|
|
rxTout <= 1'b0;
|
673 |
|
|
// Don't time out if the fifo is empty
|
674 |
|
|
else if (rxCnt[9:4]==rxToutMax && ~rxEmpty)
|
675 |
|
|
rxTout <= 1'b1;
|
676 |
|
|
end
|
677 |
|
|
|
678 |
|
|
|
679 |
|
|
//-----------------------------------------------------
|
680 |
|
|
// compute the 2x number of stop bits
|
681 |
|
|
always_comb
|
682 |
|
|
if (stopBit==1'b0) // one stop bit
|
683 |
|
|
stopBits <= 3'd2;
|
684 |
|
|
else if (wordLength==6'd8 && parityCtrl != 3'd0)
|
685 |
|
|
stopBits <= 3'd2;
|
686 |
|
|
else if (wordLength==6'd5 && parityCtrl == 3'd0) // 5 bits - 1 1/2 stop bit
|
687 |
|
|
stopBits <= 3'd3;
|
688 |
|
|
else
|
689 |
|
|
stopBits <= 3'd4; // two stop bits
|
690 |
|
|
|
691 |
|
|
|
692 |
|
|
// compute frame size
|
693 |
|
|
// frame size is one less
|
694 |
|
|
assign frameSize = {wordLength + 4'd1 + stopBits[2:1] + parityCtrl[0], stopBits[0],3'b0} - 1;
|
695 |
|
|
|
696 |
|
|
//-----------------------------------------------------
|
697 |
|
|
// encode IRQ mailbox
|
698 |
|
|
always_comb
|
699 |
|
|
irqenc <=
|
700 |
|
|
lineStatusChange ? 3'd0 :
|
701 |
|
|
~rxDRQ_o ? 3'd1 :
|
702 |
|
|
rxTout ? 3'd2 :
|
703 |
|
|
~txDRQ_o ? 3'd3 :
|
704 |
|
|
modemStatusChange ? 3'd4 :
|
705 |
|
|
3'd0;
|
706 |
|
|
|
707 |
|
|
endmodule
|