OpenCores
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

powered by: WebSVN 2.1.0

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