URL
https://opencores.org/ocsvn/uart6551/uart6551/trunk
Subversion Repositories uart6551
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 10 to Rev 11
- ↔ Reverse comparison
Rev 10 → Rev 11
/uart6551/trunk/trunk/doc/uart6551pci.docx
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
uart6551/trunk/trunk/doc/uart6551pci.docx
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: uart6551/trunk/trunk/doc/uart6551pci.pdf
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: uart6551/trunk/trunk/doc/uart6551pci.pdf
===================================================================
--- uart6551/trunk/trunk/doc/uart6551pci.pdf (nonexistent)
+++ uart6551/trunk/trunk/doc/uart6551pci.pdf (revision 11)
uart6551/trunk/trunk/doc/uart6551pci.pdf
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: uart6551/trunk/trunk/rtl/pci32_config.sv
===================================================================
--- uart6551/trunk/trunk/rtl/pci32_config.sv (nonexistent)
+++ uart6551/trunk/trunk/rtl/pci32_config.sv (revision 11)
@@ -0,0 +1,226 @@
+// ============================================================================
+// __
+// \\__/ o\ (C) 2023 Robert Finch, Waterloo
+// \ __ / All rights reserved.
+// \/_// robfinch@finitron.ca
+// ||
+//
+//
+// BSD 3-Clause License
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// ============================================================================
+//
+
+module pci32_config(rst_i, clk_i, irq_i, irq_o, cs_config_i,
+ we_i, sel_i, adr_i, dat_i, dat_o, bar0_o, bar1_o, bar2_o, irq_en_o);
+input rst_i;
+input clk_i;
+input irq_i;
+output reg [31:0] irq_o;
+input cs_config_i;
+input we_i;
+input [3:0] sel_i;
+input [31:0] adr_i;
+input [31:0] dat_i;
+output [31:0] dat_o;
+output reg [31:0] bar0_o;
+output reg [31:0] bar1_o;
+output reg [31:0] bar2_o;
+output reg irq_en_o;
+
+parameter CFG_BUS = 8'd0;
+parameter CFG_DEVICE = 5'd0;
+parameter CFG_FUNC = 3'd0;
+parameter CFG_VENDOR_ID = 16'h0;
+parameter CFG_DEVICE_ID = 16'h0;
+parameter CFG_SUBSYSTEM_VENDOR_ID = 16'h0;
+parameter CFG_SUBSYSTEM_ID = 16'h0;
+parameter CFG_BAR0 = 32'h1;
+parameter CFG_BAR1 = 32'h1;
+parameter CFG_BAR2 = 32'h1;
+parameter CFG_BAR0_ALLOC = 32'h0;
+parameter CFG_BAR1_ALLOC = 32'h0;
+parameter CFG_BAR2_ALLOC = 32'h0;
+parameter CFG_ROM_ADDR = 32'hFFFFFFF0;
+
+parameter CFG_REVISION_ID = 8'd0;
+parameter CFG_PROGIF = 8'd1;
+parameter CFG_SUBCLASS = 8'h80; // 80 = Other
+parameter CFG_CLASS = 8'h03; // 03 = display controller
+parameter CFG_CACHE_LINE_SIZE = 8'd8; // 32-bit units
+parameter CFG_MIN_GRANT = 8'h00;
+parameter CFG_MAX_LATENCY = 8'h00;
+parameter CFG_IRQ_LINE = 8'd16;
+
+localparam CFG_HEADER_TYPE = 8'h00; // 00 = a general device
+
+parameter MSIX = 1'b0;
+
+integer n1;
+reg [15:0] cmd_reg;
+reg [15:0] cmdo_reg;
+reg memory_space, io_space;
+reg bus_master;
+reg parity_err_resp;
+reg serr_enable;
+reg int_disable;
+reg [7:0] latency_timer = 8'h00;
+
+always_comb
+begin
+ cmdo_reg = cmd_reg;
+ cmdo_reg[3] = 1'b0; // no special cycles
+ cmdo_reg[4] = 1'b0; // memory write and invalidate supported
+ cmdo_reg[5] = 1'b0; // VGA palette snoop
+ cmdo_reg[7] = 1'b0; // reserved bit
+ cmdo_reg[9] = 1'b1; // fast back-to-back enable
+ cmdo_reg[15:11] = 5'd0; // reserved
+end
+
+reg [15:0] stat_reg;
+reg [15:0] stato_reg;
+always_comb
+begin
+ stato_reg = stat_reg;
+ stato_reg[2:0] = 3'b0; // reserved
+ stato_reg[3] = 1'b0; // interrupt status
+ stato_reg[4] = 1'b0; // capabilities list
+ stato_reg[5] = 1'b1; // 66 MHz enable (N/A)
+ stato_reg[6] = 1'b0; // reserved
+ stato_reg[7] = 1'b1; // fast back-to-back capable
+ stato_reg[10:9] = 2'b01; // medium DEVSEL timing
+end
+
+reg [31:0] cfg_dat [0:63];
+reg [31:0] cfg_out;
+reg [7:0] irq_line;
+
+initial begin
+ for (n1 = 0; n1 < 32; n1 = n1 + 1)
+ cfg_dat[n1] = 'd0;
+end
+
+wire cs = cs_config_i &&
+ adr_i[27:20]==CFG_BUS &&
+ adr_i[19:15]==CFG_DEVICE &&
+ adr_i[14:12]==CFG_FUNC;
+
+always_ff @(posedge clk_i)
+if (rst_i) begin
+ bar0_o <= CFG_BAR0;
+ bar1_o <= CFG_BAR1;
+ bar2_o <= CFG_BAR2;
+ cmd_reg <= 16'h4003;
+ stat_reg <= 16'h0000;
+ irq_line <= CFG_IRQ_LINE;
+end
+else begin
+ io_space <= cmdo_reg[0];
+ memory_space <= cmdo_reg[1];
+ bus_master <= cmdo_reg[2];
+ parity_err_resp <= cmdo_reg[6];
+ serr_enable <= cmdo_reg[8];
+ int_disable <= cmdo_reg[10];
+ irq_en_o <= ~cmdo_reg[10];
+
+ if (cs) begin
+ if (we_i)
+ case(adr_i[7:2])
+ 5'h02:
+ begin
+ if (sel_i[0]) cmd_reg[7:0] <= dat_i[7:0];
+ if (sel_i[1]) cmd_reg[15:8] <= dat_i[15:8];
+ if (sel_i[3]) begin
+ if (dat_i[8]) stat_reg[8] <= 1'b0;
+ if (dat_i[11]) stat_reg[11] <= 1'b0;
+ if (dat_i[12]) stat_reg[12] <= 1'b0;
+ if (dat_i[13]) stat_reg[13] <= 1'b0;
+ if (dat_i[14]) stat_reg[14] <= 1'b0;
+ if (dat_i[15]) stat_reg[15] <= 1'b0;
+ end
+ end
+ 5'h04:
+ if (&sel_i[3:0] && dat_i[31:0]==32'hFFFFFFFF)
+ bar0_o <= CFG_BAR0_ALLOC;
+ else begin
+ if (sel_i[0]) bar0_o[7:0] <= dat_i[7:0];
+ if (sel_i[1]) bar0_o[15:8] <= dat_i[15:8];
+ if (sel_i[2]) bar0_o[23:16] <= dat_i[23:16];
+ if (sel_i[3]) bar0_o[31:24] <= dat_i[31:24];
+ end
+ 5'h05:
+ if (&sel_i[3:0] && dat_i[31:0]==32'hFFFFFFFF)
+ bar1_o <= CFG_BAR1_ALLOC;
+ else begin
+ if (sel_i[0]) bar1_o[7:0] <= dat_i[7:0];
+ if (sel_i[1]) bar1_o[15:8] <= dat_i[15:8];
+ if (sel_i[2]) bar1_o[23:16] <= dat_i[23:16];
+ if (sel_i[3]) bar1_o[31:24] <= dat_i[31:24];
+ end
+ 5'h06:
+ if (&sel_i[3:0] && dat_i[31:0]==32'hFFFFFFFF)
+ bar2_o <= CFG_BAR2_ALLOC;
+ else begin
+ if (sel_i[0]) bar2_o[7:0] <= dat_i[7:0];
+ if (sel_i[1]) bar2_o[15:8] <= dat_i[15:8];
+ if (sel_i[2]) bar2_o[23:16] <= dat_i[23:16];
+ if (sel_i[3]) bar2_o[31:24] <= dat_i[31:24];
+ end
+ 5'h0F:
+ if (sel_i[0]) irq_line <= dat_i[7:0];
+ default:
+ cfg_dat[adr_i[7:2]] <= dat_i;
+ endcase
+ else
+ case(adr_i[7:3])
+ 5'h00: cfg_out <= {CFG_DEVICE_ID,CFG_VENDOR_ID};
+ 5'h01: cfg_out <= {stato_reg,cmdo_reg};
+ 5'h02: cfg_out <= {
+ CFG_CLASS,CFG_SUBCLASS,CFG_PROGIF,CFG_REVISION_ID};
+ 5'h03: cfg_out <= {8'h00,
+ CFG_HEADER_TYPE,latency_timer,CFG_CACHE_LINE_SIZE};
+ 5'h04: cfg_out <= bar0_o;
+ 5'h05: cfg_out <= bar1_o;
+ 5'h06: cfg_out <= bar2_o;
+ 5'h07: cfg_out <= 32'hFFFFFFFF;
+ 5'h08: cfg_out <= 32'hFFFFFFFF;
+ 5'h09: cfg_out <= 32'hFFFFFFFF;
+ 5'h0A: cfg_out <= 32'h0;
+ 5'h0B: cfg_out <= {CFG_SUBSYSTEM_ID,CFG_SUBSYSTEM_VENDOR_ID};
+ 5'h0C: cfg_out <= CFG_ROM_ADDR;
+ 5'h0D: cfg_out <= 32'h0;
+ 5'h0E: cfg_out <= 32'h0;
+ 5'h0F: cfg_out <= {8'd8,8'd0,8'd0,irq_line};
+ default: cfg_out <= cfg_dat[adr_i[7:2]];
+ endcase
+ end
+end
+
+always_comb
+ irq_o = {31'd0,irq_i & ~int_disable} << irq_line;
+
+endmodule
Index: uart6551/trunk/trunk/rtl/uart6551pci.sv
===================================================================
--- uart6551/trunk/trunk/rtl/uart6551pci.sv (nonexistent)
+++ uart6551/trunk/trunk/rtl/uart6551pci.sv (revision 11)
@@ -0,0 +1,695 @@
+// ============================================================================
+// __
+// \\__/ o\ (C) 2005-2023 Robert Finch, Waterloo
+// \ __ / All rights reserved.
+// \/_// robfinch@finitron.ca
+// ||
+//
+//
+// BSD 3-Clause License
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// 369 LUTs / 409 FFs
+// ============================================================================
+//
+`define UART_ADDR 32'hFE000001
+`define UART_TRB 2'd0 // transmit/receive buffer
+`define UART_STAT 2'd1
+`define UART_CMD 2'd2
+`define UART_CTRL 2'd3
+
+module uart6551pci(rst_i, clk_i, cs_config_i, cs_io_i, irq_o,
+ cyc_i, stb_i, ack_o, we_i, sel_i, adr_i, dat_i, dat_o,
+ cts_ni, rts_no, dsr_ni, dcd_ni, dtr_no, ri_ni,
+ rxd_i, txd_o, data_present,
+ rxDRQ_o, txDRQ_o,
+ xclk_i, RxC_i
+);
+parameter pClkFreq = 100;
+parameter pCounterBits = 24;
+parameter pFifoSize = 1024;
+parameter pClkDiv = 24'd1302; // 9.6k baud, 200.000MHz clock
+parameter HIGH = 1'b1;
+parameter LOW = 1'b0;
+
+parameter CFG_BUS = 8'd0;
+parameter CFG_DEVICE = 5'd16;
+parameter CFG_FUNC = 3'd0;
+parameter CFG_VENDOR_ID = 16'h0;
+parameter CFG_DEVICE_ID = 16'h0;
+parameter CFG_SUBSYSTEM_VENDOR_ID = 16'h0;
+parameter CFG_SUBSYSTEM_ID = 16'h0;
+parameter CFG_ROM_ADDR = 32'hFFFFFFF0;
+
+parameter CFG_REVISION_ID = 8'd0;
+parameter CFG_PROGIF = 8'd1;
+parameter CFG_SUBCLASS = 8'h80; // 80 = Other
+parameter CFG_CLASS = 8'h03; // 03 = display controller
+parameter CFG_CACHE_LINE_SIZE = 8'd8; // 32-bit units
+parameter CFG_MIN_GRANT = 8'h00;
+parameter CFG_MAX_LATENCY = 8'h00;
+parameter CFG_IRQ_LINE = 8'd16;
+
+localparam CFG_HEADER_TYPE = 8'h00; // 00 = a general device
+
+parameter MSIX = 1'b0;
+input rst_i;
+input clk_i; // eg 50.000MHz
+input cs_config_i; // config region circuit select
+input cs_io_i; // IO region circuit select
+// WISHBONE -------------------------------
+input cyc_i; // bus cycle valid
+input stb_i;
+output ack_o;
+input we_i; // 1 = write
+input [3:0] sel_i;
+input [31:0] adr_i; // register address
+input [31:0] dat_i; // data input bus
+output reg [31:0] dat_o; // data output bus
+//------------------------------------------
+output reg [31:0] irq_o; // interrupt request
+input cts_ni; // clear to send - (flow control) active low
+output reg rts_no; // request to send - (flow control) active low
+input dsr_ni; // data set ready - active low
+input dcd_ni; // data carrier detect - active low
+output reg dtr_no; // data terminal ready - active low
+input ri_ni; // ring indicator
+input rxd_i; // serial data in
+output txd_o; // serial data out
+output data_present;
+output rxDRQ_o; // reciever DMA request
+output txDRQ_o; // transmitter DMA request
+input xclk_i; // external clock source
+input RxC_i; // external receiver clock source
+
+reg [31:0] uart_addr;
+reg accessCD; // clock multiplier access flag
+reg llb; // local loopback mode
+reg dmaEnable;
+// baud rate clock control
+reg [4:0] baudRateSel;
+reg selCD; // Use clock multiplier register
+reg [pCounterBits-1:0] c; // current count
+reg [pCounterBits-1:0] ckdiv; // baud rate clock divider
+reg [pCounterBits-1:0] clkdiv; // clock multiplier register
+reg [1:0] xclks; // synchronized external clock
+reg [1:0] RxCs; // synchronized external receiver clock
+reg baud16; // 16x baud rate clock
+wire baud16rx; // reciever clock
+reg xClkSrc; // uart baud clock is external
+reg rxClkSrc; // receiver clock is external
+
+// frame format registers
+reg [3:0] wordLength;
+reg stopBit;
+reg [2:0] stopBits;
+reg [2:0] parityCtrl;
+wire [7:0] frameSize;
+
+reg txBreak; // transmit a break
+
+wire rxFull;
+wire rxEmpty;
+wire txFull;
+wire txEmpty;
+reg hwfc; // hardware flow control enable
+wire [7:0] lineStatusReg;
+wire [7:0] modemStatusReg;
+wire [7:0] irqStatusReg;
+// interrupt
+wire irq_en; // global IRQ enable
+reg irq;
+reg rxIe;
+reg txIe;
+reg modemStatusChangeIe;
+wire modemStatusChange;
+reg lineStatusChangeIe;
+wire lineStatusChange;
+reg rxToutIe; // receiver timeout interrupt enable
+reg [3:0] rxThres; // receiver threshold for interrupt
+reg [3:0] txThres; // transmitter threshold for interrupt
+reg rxTout; // receiver timeout
+wire [9:0] rxCnt; // reciever counter value
+reg [7:0] rxToutMax;
+reg [2:0] irqenc; // encoded irq cause
+wire rxITrig; // receiver interrupt trigger level
+wire txITrig; // transmitter interrupt trigger level
+// reciever errors
+wire parityErr; // reciever detected a parity error
+wire frameErr; // receiver char framing error
+wire overrun; // receiver over run
+wire rxBreak; // reciever detected a break
+wire rxGErr; // global error: there is at least one error in the reciever fifo
+// modem controls
+reg [1:0] ctsx; // cts_n sampling
+reg [1:0] dcdx;
+reg [1:0] dsrx;
+reg [1:0] rix;
+reg deltaCts;
+reg deltaDcd;
+reg deltaDsr;
+reg deltaRi;
+
+// fifo
+reg rxFifoClear;
+reg txFifoClear;
+reg txClear;
+reg fifoEnable;
+wire [3:0] rxQued;
+wire [3:0] txQued;
+
+// config
+reg [31:0] cfg_out;
+
+// test
+wire txd1;
+
+assign data_present = ~rxEmpty;
+
+assign rxITrig = rxQued >= rxThres;
+assign txITrig = txQued <= txThres;
+wire rxDRQ1 = (fifoEnable ? rxITrig : ~rxEmpty);
+wire txDRQ1 = (fifoEnable ? txITrig : txEmpty);
+assign rxDRQ_o = dmaEnable & rxDRQ1;
+assign txDRQ_o = dmaEnable & txDRQ1;
+wire rxIRQ = rxIe & rxDRQ1;
+wire txIRQ = txIe & txDRQ1;
+
+reg [7:0] cmd0, cmd1, cmd2, cmd3;
+reg [7:0] ctrl0, ctrl1, ctrl2, ctrl3;
+
+always_ff @(posedge clk_i)
+ irq <= (
+ rxIRQ
+ | txIRQ
+ | (rxTout & rxToutIe)
+ | (lineStatusChange & lineStatusChangeIe)
+ | (modemStatusChange & modemStatusChangeIe)
+ ) & irq_en;
+ ;
+
+// Hold onto address and data an extra cycle.
+// The extra cycle updates or reads the serial transmit / receive.
+reg [31:0] dati;
+always @(posedge clk_i)
+ dati <= dat_i;
+reg [31:0] adr_h;
+always @(posedge clk_i)
+ adr_h <= adr_i;
+reg we;
+always @(posedge clk_i)
+ we <= we_i;
+reg [3:0] sel;
+always @(posedge clk_i)
+ sel <= sel_i;
+
+wire [7:0] rx_do;
+wire rdrx = cs_io && ack_o && adr_h==`UART_TRB && ~we && !accessCD;
+wire txrx = cs_io && ack_o && adr_h==`UART_TRB && !accessCD;
+
+wire cs_config = cs_config_i & cyc_i & stb_i &&
+ adr_i[27:20]==CFG_BUS &&
+ adr_i[19:15]==CFG_DEVICE &&
+ adr_i[14:12]==CFG_FUNC;
+wire cs_io = cs_io_i & cyc_i & stb_i && adr_i[27:4]==uart_addr[27:4];
+
+ack_gen #(
+ .READ_STAGES(1),
+ .WRITE_STAGES(0),
+ .REGISTER_OUTPUT(1)
+) uag1
+(
+ .rst_i(rst_i),
+ .clk_i(clk_i),
+ .ce_i(1'b1),
+ .rid_i('d0),
+ .wid_i('d0),
+ .i((cs_config|cs_io) & ~we_i),
+ .we_i((cs_config|cs_io) & we_i),
+ .o(ack_o),
+ .rid_o(),
+ .wid_o()
+);
+
+pci32_config #(
+ .CFG_BUS(CFG_BUS),
+ .CFG_DEVICE(CFG_DEVICE),
+ .CFG_FUNC(CFG_FUNC),
+ .CFG_VENDOR_ID(CFG_VENDOR_ID),
+ .CFG_DEVICE_ID(CFG_DEVICE_ID),
+ .CFG_BAR0(`UART_ADDR),
+ .CFG_SUBSYSTEM_VENDOR_ID(CFG_SUBSYSTEM_VENDOR_ID),
+ .CFG_SUBSYSTEM_ID(CFG_SUBSYSTEM_ID),
+ .CFG_ROM_ADDR(CFG_ROM_ADDR),
+ .CFG_REVISION_ID(CFG_REVISION_ID),
+ .CFG_PROGIF(CFG_PROGIF),
+ .CFG_SUBCLASS(CFG_SUBCLASS),
+ .CFG_CLASS(CFG_CLASS),
+ .CFG_CACHE_LINE_SIZE(CFG_CACHE_LINE_SIZE),
+ .CFG_MIN_GRANT(CFG_MIN_GRANT),
+ .CFG_MAX_LATENCY(CFG_MAX_LATENCY),
+ .CFG_IRQ_LINE(CFG_IRQ_LINE)
+)
+ucfg1
+(
+ .rst_i(rst_i),
+ .clk_i(clk_i),
+ .irq_i(irq),
+ .irq_o(irq_o),
+ .cs_config_i(cs_config),
+ .we_i(we),
+ .sel_i(sel),
+ .adr_i(adr_h),
+ .dat_i(dati),
+ .dat_o(cfg_out),
+ .bar0_o(uart_addr),
+ .bar1_o(),
+ .bar2_o(),
+ .irq_en_o(irq_en)
+);
+
+uart6551Rx uart_rx0
+(
+ .rst(rst_i),
+ .clk(clk_i),
+ .cyc(cyc_i),
+ .cs(rdrx),
+ .wr(we),
+ .dout(rx_do),
+ .ack(),
+ .fifoEnable(fifoEnable),
+ .fifoClear(rxFifoClear),
+ .clearGErr(1'b0),
+ .wordLength(wordLength),
+ .parityCtrl(parityCtrl),
+ .frameSize(frameSize),
+ .stop_bits(stopBits),
+ .baud16x_ce(baud16rx),
+ .clear(1'b0),
+ .rxd(llb ? txd1 : rxd_i),
+ .full(),
+ .empty(rxEmpty),
+ .frameErr(frameErr),
+ .overrun(overrun),
+ .parityErr(parityErr),
+ .break_o(rxBreak),
+ .gerr(rxGErr),
+ .qcnt(rxQued),
+ .cnt(rxCnt)
+);
+
+uart6551Tx uart_tx0
+(
+ .rst(rst_i),
+ .clk(clk_i),
+ .cyc(cyc_i),
+ .cs(txrx),
+ .wr(we),
+ .din(dati[7:0]),
+ .ack(),
+ .fifoEnable(fifoEnable),
+ .fifoClear(txFifoClear),
+ .txBreak(txBreak),
+ .frameSize(frameSize), // 16 x 10 bits
+ .wordLength(wordLength),// 8 bits
+ .parityCtrl(parityCtrl),// no parity
+ .baud16x_ce(baud16),
+ .cts(ctsx[1]|~hwfc),
+ .clear(txClear),
+ .txd(txd1),
+ .full(txFull),
+ .empty(txEmpty),
+ .qcnt(txQued)
+);
+
+assign txd_o = llb ? 1'b1 : txd1;
+
+assign lineStatusReg = {rxGErr,1'b0,txFull,rxBreak,1'b0,1'b0,1'b0,1'b0};
+assign modemStatusChange = deltaDcd|deltaRi|deltaDsr|deltaCts; // modem status delta
+assign modemStatusReg = {1'b0,~rix[1],1'b0,~ctsx[1],deltaDcd, deltaRi, deltaDsr, deltaCts};
+assign irqStatusReg = {irq_o,2'b00,irqenc,2'b00};
+
+// mux the reg outputs
+always @(posedge clk_i)
+if (cs_config)
+ dat_o <= cfg_out;
+else if (cs_io) begin
+ case(adr_i)
+ `UART_TRB: dat_o <= accessCD ? {8'h0,clkdiv} : {24'h0,rx_do}; // receiver holding register
+ `UART_STAT: dat_o <= {irqStatusReg,modemStatusReg,lineStatusReg,irq_o,dsrx[1],dcdx[1],fifoEnable ? ~txFull : txEmpty,~rxEmpty,overrun,frameErr,parityErr};
+ `UART_CMD: dat_o <= {cmd3,cmd2,cmd1,cmd0};
+ `UART_CTRL: dat_o <= {ctrl3,ctrl2,ctrl1,ctrl0};
+ endcase
+end
+else
+ dat_o <= 'd0;
+
+
+// register updates
+always @(posedge clk_i)
+if (rst_i) begin
+ rts_no <= HIGH;
+ dtr_no <= HIGH;
+ // interrupts
+ rxIe <= 1'b0;
+ txIe <= 1'b0;
+ modemStatusChangeIe <= 1'b0;
+ lineStatusChangeIe <= 1'b0;
+ hwfc <= 1'b0;
+ modemStatusChangeIe <= 1'b0;
+ lineStatusChangeIe <= 1'b0;
+ dmaEnable <= 1'b0;
+ // clock control
+ baudRateSel <= 5'h0;
+ rxClkSrc <= 1'b0; // ** 6551 defaults to zero (external receiver clock)
+ clkdiv <= pClkDiv;
+ // frame format
+ wordLength <= 4'd8; // 8 bits
+ stopBit <= 1'b0; // 1 stop bit
+ parityCtrl <= 3'd0; // no parity
+
+ txBreak <= 1'b0;
+ // Fifo control
+ txFifoClear <= 1'b1;
+ rxFifoClear <= 1'b1;
+ txClear <= 1'b1;
+ fifoEnable <= 1'b1;
+ // Test
+ llb <= 1'b0;
+ selCD <= 1'b0;
+ accessCD <= 1'b0;
+end
+else begin
+
+ //llb <= 1'b1;
+ rxFifoClear <= 1'b0;
+ txFifoClear <= 1'b0;
+ txClear <= 1'b0;
+ ctrl2[1] <= 1'b0;
+ ctrl2[2] <= 1'b0;
+
+ if (cs_io & ack_o & we) begin
+ case (adr_h) // synopsys full_case parallel_case
+
+ `UART_TRB:
+ if (accessCD) begin
+ clkdiv <= dati;
+ accessCD <= 1'b0;
+ ctrl3[7] <= 1'b0;
+ end
+
+ // Writing to the status register does a software reset of some bits.
+ `UART_STAT:
+ begin
+ dtr_no <= HIGH;
+ rxIe <= 1'b0;
+ rts_no <= HIGH;
+ txIe <= 1'b0;
+ txBreak <= 1'b0;
+ llb <= 1'b0;
+ end
+ `UART_CMD:
+ begin
+ if (sel[0]) begin
+ cmd0 <= dati[7:0];
+ dtr_no <= ~dati[0];
+ rxIe <= ~dati[1];
+ case(dati[3:2])
+ 2'd0: begin rts_no <= 1'b1; txIe <= 1'b0; txBreak <= 1'b0; end
+ 2'd1: begin rts_no <= 1'b0; txIe <= 1'b1; txBreak <= 1'b0; end
+ 2'd2: begin rts_no <= 1'b0; txIe <= 1'b0; txBreak <= 1'b0; end
+ 2'd3: begin rts_no <= 1'b0; txIe <= 1'b0; txBreak <= 1'b1; end
+ endcase
+ llb <= dati[4];
+ parityCtrl <= dati[7:5]; //000=none,001=odd,011=even,101=force 1,111 = force 0
+ end
+ if (sel[1]) begin
+ cmd1 <= dati[15:8];
+ lineStatusChangeIe <= dati[8];
+ modemStatusChangeIe <= dati[9];
+ rxToutIe <= dati[10];
+ end
+ if (sel[2])
+ cmd2 <= dati[23:16];
+ if (sel[3])
+ cmd3 <= dati[31:24];
+ end
+
+ `UART_CTRL:
+ begin
+ if (sel[0]) begin
+ ctrl0 <= dati[7:0];
+ baudRateSel[3:0] <= dati[3:0];
+ rxClkSrc <= dati[4]; // 1 = baud rate generator, 0 = external
+ //11=5,10=6,01=7,00=8
+ case(dati[6:5])
+ 2'd0: wordLength <= 6'd8;
+ 2'd1: wordLength <= 6'd7;
+ 2'd2: wordLength <= 6'd6;
+ 2'd3: wordLength <= 6'd5;
+ endcase
+ stopBit <= dati[7]; //0=1,1=1.5 or 2
+ end
+ // Extended word length, values beyond 11 not supported.
+ if (sel[1]) begin
+ ctrl1 <= dati[15:8];
+ end
+ if (sel[2]) begin
+ ctrl2 <= dati[23:16];
+ fifoEnable <= dati[16];
+ rxFifoClear <= dati[17];
+ txFifoClear <= dati[18];
+ case (dati[21:20])
+ 2'd0: txThres <= 4'd1; // one-byte
+ 2'd1: txThres <= pFifoSize / 4; // one-quarter full
+ 2'd2: txThres <= pFifoSize / 2; // one-half full
+ 2'd3: txThres <= pFifoSize * 3 / 4; // three-quarters full
+ endcase
+ case (dati[23:22])
+ 2'd0: rxThres <= 4'd1; // one-byte
+ 2'd1: rxThres <= pFifoSize / 4; // one-quarter full
+ 2'd2: rxThres <= pFifoSize / 2; // one-half full
+ 2'd3: rxThres <= pFifoSize * 3 / 4; // three quarters full
+ endcase
+ end
+ if (sel[3]) begin
+ ctrl3 <= dati[31:24];
+ hwfc <= dati[24];
+ dmaEnable <= dati[26];
+ baudRateSel[4] <= dati[27];
+ txClear <= dati[29];
+ selCD <= dati[30];
+ accessCD <= dati[31];
+ end
+ end
+
+ default:
+ ;
+ endcase
+ end
+end
+
+// ----------------------------------------------------------------------------
+// Baud rate control.
+// ----------------------------------------------------------------------------
+
+always @(posedge clk_i)
+ xClkSrc <= baudRateSel==5'd0;
+
+wire [pCounterBits-1:0] bclkdiv;
+uart6551BaudLUT #(.pClkFreq(pClkFreq), .pCounterBits(pCounterBits)) ublt1 (.a(baudRateSel), .o(bclkdiv));
+
+reg [pCounterBits-1:0] clkdiv2;
+always @(posedge clk_i)
+ clkdiv2 <= selCD ? clkdiv : bclkdiv;
+
+always @(posedge clk_i)
+if (rst_i)
+ c <= 24'd1;
+else begin
+ c <= c + 2'd1;
+ if (c >= clkdiv2)
+ c <= 2'd1;
+end
+
+// for detecting an edge on the baud clock
+wire ibaud16 = c == 2'd1;
+
+// Detect an edge on the external clock
+wire xclkEdge;
+edge_det ed1(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(xclks[1]), .pe(xclkEdge), .ne() );
+
+// Detect an edge on the external clock
+wire rxClkEdge;
+edge_det ed2(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(RxCs[1]), .pe(rxClkEdge), .ne() );
+
+always_comb
+if (xClkSrc) // 16x external clock (xclk)
+ baud16 <= xclkEdge;
+else
+ baud16 <= ibaud16;
+
+assign baud16rx = rxClkSrc ? baud16 : rxClkEdge;
+
+//------------------------------------------------------------
+// external signal synchronization
+//------------------------------------------------------------
+
+// External receiver clock
+always @(posedge clk_i)
+ RxCs <= {RxCs[1:0],RxC_i};
+
+// External baud clock
+always @(posedge clk_i)
+ xclks <= {xclks[1:0],xclk_i};
+
+
+always @(posedge clk_i)
+ ctsx <= {ctsx[0],llb?~rts_no:~cts_ni};
+
+always @(posedge clk_i)
+ dcdx <= {dcdx[0],~dcd_ni};
+
+always @(posedge clk_i)
+ dsrx <= {dsrx[0],llb?~dtr_no:~dsr_ni};
+
+always @(posedge clk_i)
+ rix <= {rix[0],~ri_ni};
+
+//------------------------------------------------------------
+// state change detectors
+//------------------------------------------------------------
+
+wire ne_stat;
+edge_det ued3 (
+ .rst(rst_i),
+ .clk(clk_i),
+ .ce(1'b1),
+ .i(ack_o && adr_i==`UART_STAT && ~we_i && sel_i[2]),
+ .pe(),
+ .ne(ne_stat),
+ .ee()
+);
+
+// detect a change on the dsr signal
+always @(posedge clk_i)
+if (rst_i)
+ deltaDsr <= 1'b0;
+else begin
+ if (ne_stat)
+ deltaDsr <= 0;
+ else if (~deltaDsr)
+ deltaDsr <= dsrx[1] ^ dsrx[0];
+end
+
+// detect a change on the dcd signal
+always @(posedge clk_i)
+if (rst_i)
+ deltaDcd <= 1'b0;
+else begin
+ if (ne_stat)
+ deltaDcd <= 0;
+ else if (~deltaDcd)
+ deltaDcd <= dcdx[1] ^ dcdx[0];
+end
+
+// detect a change on the cts signal
+always @(posedge clk_i)
+if (rst_i)
+ deltaCts <= 1'b0;
+else begin
+ if (ne_stat)
+ deltaCts <= 0;
+ else if (~deltaCts)
+ deltaCts <= ctsx[1] ^ ctsx[0];
+end
+
+// detect a change on the ri signal
+always @(posedge clk_i)
+if (rst_i)
+ deltaRi <= 1'b0;
+else begin
+ if (ne_stat)
+ deltaRi <= 0;
+ else if (~deltaRi)
+ deltaRi <= rix[1] ^ rix[0];
+end
+
+// detect a change in line status
+reg [7:0] pLineStatusReg;
+always @(posedge clk_i)
+ pLineStatusReg <= lineStatusReg;
+
+assign lineStatusChange = pLineStatusReg != lineStatusReg;
+
+//-----------------------------------------------------
+
+// compute recieve timeout
+always @(wordLength)
+ rxToutMax <= (wordLength << 2) + 6'd12;
+
+always @(posedge clk_i)
+if (rst_i)
+ rxTout <= 1'b0;
+else begin
+ // read of receiver clears timeout counter
+ if (rdrx)
+ rxTout <= 1'b0;
+ // Don't time out if the fifo is empty
+ else if (rxCnt[9:4]==rxToutMax && ~rxEmpty)
+ rxTout <= 1'b1;
+end
+
+
+//-----------------------------------------------------
+// compute the 2x number of stop bits
+always @*
+if (stopBit==1'b0) // one stop bit
+ stopBits <= 3'd2;
+else if (wordLength==6'd8 && parityCtrl != 3'd0)
+ stopBits <= 3'd2;
+else if (wordLength==6'd5 && parityCtrl == 3'd0) // 5 bits - 1 1/2 stop bit
+ stopBits <= 3'd3;
+else
+ stopBits <= 3'd4; // two stop bits
+
+
+// compute frame size
+// frame size is one less
+assign frameSize = {wordLength + 4'd1 + stopBits[2:1] + parityCtrl[0], stopBits[0],3'b0} - 1;
+
+//-----------------------------------------------------
+// encode IRQ mailbox
+always @(rxDRQ_o or rxTout or txDRQ_o or lineStatusChange or modemStatusChange)
+ irqenc <=
+ lineStatusChange ? 3'd0 :
+ ~rxDRQ_o ? 3'd1 :
+ rxTout ? 3'd2 :
+ ~txDRQ_o ? 3'd3 :
+ modemStatusChange ? 3'd4 :
+ 3'd0;
+
+endmodule