// ============================================================================
|
// ============================================================================
|
// __
|
// __
|
// \\__/ o\ (C) 2005-2022 Robert Finch, Waterloo
|
// \\__/ o\ (C) 2005-2022 Robert Finch, Waterloo
|
// \ __ / All rights reserved.
|
// \ __ / All rights reserved.
|
// \/_// robfinch@finitron.ca
|
// \/_// robfinch@finitron.ca
|
// ||
|
// ||
|
//
|
//
|
//
|
//
|
// BSD 3-Clause License
|
// BSD 3-Clause License
|
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
// modification, are permitted provided that the following conditions are met:
|
// modification, are permitted provided that the following conditions are met:
|
//
|
//
|
// 1. Redistributions of source code must retain the above copyright notice, this
|
// 1. Redistributions of source code must retain the above copyright notice, this
|
// list of conditions and the following disclaimer.
|
// list of conditions and the following disclaimer.
|
//
|
//
|
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
// this list of conditions and the following disclaimer in the documentation
|
// this list of conditions and the following disclaimer in the documentation
|
// and/or other materials provided with the distribution.
|
// and/or other materials provided with the distribution.
|
//
|
//
|
// 3. Neither the name of the copyright holder nor the names of its
|
// 3. Neither the name of the copyright holder nor the names of its
|
// contributors may be used to endorse or promote products derived from
|
// contributors may be used to endorse or promote products derived from
|
// this software without specific prior written permission.
|
// this software without specific prior written permission.
|
//
|
//
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
// 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
|
// 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.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
//
|
//
|
// ============================================================================
|
// ============================================================================
|
//
|
//
|
`define UART_TRB 2'd0 // transmit/receive buffer
|
`define UART_TRB 2'd0 // transmit/receive buffer
|
`define UART_STAT 2'd1
|
`define UART_STAT 2'd1
|
`define UART_CMD 2'd2
|
`define UART_CMD 2'd2
|
`define UART_CTRL 2'd3
|
`define UART_CTRL 2'd3
|
|
|
module uart6551(rst_i, clk_i, cs_i, irq_o,
|
module uart6551(rst_i, clk_i, cs_i, irq_o,
|
cyc_i, stb_i, ack_o, we_i, sel_i, adr_i, dat_i, dat_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,
|
cts_ni, rts_no, dsr_ni, dcd_ni, dtr_no, ri_ni,
|
rxd_i, txd_o, data_present,
|
rxd_i, txd_o, data_present,
|
rxDRQ_o, txDRQ_o,
|
rxDRQ_o, txDRQ_o,
|
xclk_i, RxC_i
|
xclk_i, RxC_i
|
);
|
);
|
parameter pClkFreq = 40;
|
parameter pClkFreq = 100;
|
parameter pCounterBits = 24;
|
parameter pCounterBits = 24;
|
parameter pFifoSize = 1024;
|
parameter pFifoSize = 1024;
|
parameter pClkDiv = 24'd1302; // 9.6k baud, 200.000MHz clock
|
parameter pClkDiv = 24'd1302; // 9.6k baud, 200.000MHz clock
|
parameter HIGH = 1'b1;
|
parameter HIGH = 1'b1;
|
parameter LOW = 1'b0;
|
parameter LOW = 1'b0;
|
input rst_i;
|
input rst_i;
|
input clk_i; // eg 50.000MHz
|
input clk_i; // eg 50.000MHz
|
input cs_i; // circuit select
|
input cs_i; // circuit select
|
// WISHBONE -------------------------------
|
// WISHBONE -------------------------------
|
input cyc_i; // bus cycle valid
|
input cyc_i; // bus cycle valid
|
input stb_i;
|
input stb_i;
|
output ack_o;
|
output ack_o;
|
input we_i; // 1 = write
|
input we_i; // 1 = write
|
input [3:0] sel_i;
|
input [3:0] sel_i;
|
input [3:2] adr_i; // register address
|
input [3:2] adr_i; // register address
|
input [31:0] dat_i; // data input bus
|
input [31:0] dat_i; // data input bus
|
output reg [31:0] dat_o; // data output bus
|
output reg [31:0] dat_o; // data output bus
|
//------------------------------------------
|
//------------------------------------------
|
output reg irq_o; // interrupt request
|
output reg irq_o; // interrupt request
|
input cts_ni; // clear to send - (flow control) active low
|
input cts_ni; // clear to send - (flow control) active low
|
output reg rts_no; // request 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 dsr_ni; // data set ready - active low
|
input dcd_ni; // data carrier detect - active low
|
input dcd_ni; // data carrier detect - active low
|
output reg dtr_no; // data terminal ready - active low
|
output reg dtr_no; // data terminal ready - active low
|
input ri_ni; // ring indicator
|
input ri_ni; // ring indicator
|
input rxd_i; // serial data in
|
input rxd_i; // serial data in
|
output txd_o; // serial data out
|
output txd_o; // serial data out
|
output data_present;
|
output data_present;
|
output rxDRQ_o; // reciever DMA request
|
output rxDRQ_o; // reciever DMA request
|
output txDRQ_o; // transmitter DMA request
|
output txDRQ_o; // transmitter DMA request
|
input xclk_i; // external clock source
|
input xclk_i; // external clock source
|
input RxC_i; // external receiver clock source
|
input RxC_i; // external receiver clock source
|
|
|
reg accessCD; // clock multiplier access flag
|
reg accessCD; // clock multiplier access flag
|
reg llb; // local loopback mode
|
reg llb; // local loopback mode
|
reg dmaEnable;
|
reg dmaEnable;
|
// baud rate clock control
|
// baud rate clock control
|
reg [4:0] baudRateSel;
|
reg [4:0] baudRateSel;
|
reg selCD; // Use clock multiplier register
|
reg selCD; // Use clock multiplier register
|
reg [pCounterBits-1:0] c; // current count
|
reg [pCounterBits-1:0] c; // current count
|
reg [pCounterBits-1:0] ckdiv; // baud rate clock divider
|
reg [pCounterBits-1:0] ckdiv; // baud rate clock divider
|
reg [pCounterBits-1:0] clkdiv; // clock multiplier register
|
reg [pCounterBits-1:0] clkdiv; // clock multiplier register
|
reg [1:0] xclks; // synchronized external clock
|
reg [1:0] xclks; // synchronized external clock
|
reg [1:0] RxCs; // synchronized external receiver clock
|
reg [1:0] RxCs; // synchronized external receiver clock
|
reg baud16; // 16x baud rate clock
|
reg baud16; // 16x baud rate clock
|
wire baud16rx; // reciever clock
|
wire baud16rx; // reciever clock
|
reg xClkSrc; // uart baud clock is external
|
reg xClkSrc; // uart baud clock is external
|
reg rxClkSrc; // receiver clock is external
|
reg rxClkSrc; // receiver clock is external
|
|
|
// frame format registers
|
// frame format registers
|
reg [3:0] wordLength;
|
reg [3:0] wordLength;
|
reg stopBit;
|
reg stopBit;
|
reg [2:0] stopBits;
|
reg [2:0] stopBits;
|
reg [2:0] parityCtrl;
|
reg [2:0] parityCtrl;
|
wire [7:0] frameSize;
|
wire [7:0] frameSize;
|
|
|
reg txBreak; // transmit a break
|
reg txBreak; // transmit a break
|
|
|
wire rxFull;
|
wire rxFull;
|
wire rxEmpty;
|
wire rxEmpty;
|
wire txFull;
|
wire txFull;
|
wire txEmpty;
|
wire txEmpty;
|
reg hwfc; // hardware flow control enable
|
reg hwfc; // hardware flow control enable
|
wire [7:0] lineStatusReg;
|
wire [7:0] lineStatusReg;
|
wire [7:0] modemStatusReg;
|
wire [7:0] modemStatusReg;
|
wire [7:0] irqStatusReg;
|
wire [7:0] irqStatusReg;
|
// interrupt
|
// interrupt
|
reg rxIe;
|
reg rxIe;
|
reg txIe;
|
reg txIe;
|
reg modemStatusChangeIe;
|
reg modemStatusChangeIe;
|
wire modemStatusChange;
|
wire modemStatusChange;
|
reg lineStatusChangeIe;
|
reg lineStatusChangeIe;
|
wire lineStatusChange;
|
wire lineStatusChange;
|
reg rxToutIe; // receiver timeout interrupt enable
|
reg rxToutIe; // receiver timeout interrupt enable
|
reg [3:0] rxThres; // receiver threshold for interrupt
|
reg [3:0] rxThres; // receiver threshold for interrupt
|
reg [3:0] txThres; // transmitter threshold for interrupt
|
reg [3:0] txThres; // transmitter threshold for interrupt
|
reg rxTout; // receiver timeout
|
reg rxTout; // receiver timeout
|
wire [9:0] rxCnt; // reciever counter value
|
wire [9:0] rxCnt; // reciever counter value
|
reg [7:0] rxToutMax;
|
reg [7:0] rxToutMax;
|
reg [2:0] irqenc; // encoded irq cause
|
reg [2:0] irqenc; // encoded irq cause
|
wire rxITrig; // receiver interrupt trigger level
|
wire rxITrig; // receiver interrupt trigger level
|
wire txITrig; // transmitter interrupt trigger level
|
wire txITrig; // transmitter interrupt trigger level
|
// reciever errors
|
// reciever errors
|
wire parityErr; // reciever detected a parity error
|
wire parityErr; // reciever detected a parity error
|
wire frameErr; // receiver char framing error
|
wire frameErr; // receiver char framing error
|
wire overrun; // receiver over run
|
wire overrun; // receiver over run
|
wire rxBreak; // reciever detected a break
|
wire rxBreak; // reciever detected a break
|
wire rxGErr; // global error: there is at least one error in the reciever fifo
|
wire rxGErr; // global error: there is at least one error in the reciever fifo
|
// modem controls
|
// modem controls
|
reg [1:0] ctsx; // cts_n sampling
|
reg [1:0] ctsx; // cts_n sampling
|
reg [1:0] dcdx;
|
reg [1:0] dcdx;
|
reg [1:0] dsrx;
|
reg [1:0] dsrx;
|
reg [1:0] rix;
|
reg [1:0] rix;
|
reg deltaCts;
|
reg deltaCts;
|
reg deltaDcd;
|
reg deltaDcd;
|
reg deltaDsr;
|
reg deltaDsr;
|
reg deltaRi;
|
reg deltaRi;
|
|
|
// fifo
|
// fifo
|
reg rxFifoClear;
|
reg rxFifoClear;
|
reg txFifoClear;
|
reg txFifoClear;
|
reg txClear;
|
reg txClear;
|
reg fifoEnable;
|
reg fifoEnable;
|
wire [3:0] rxQued;
|
wire [3:0] rxQued;
|
wire [3:0] txQued;
|
wire [3:0] txQued;
|
|
|
// test
|
// test
|
wire txd1;
|
wire txd1;
|
|
|
assign data_present = ~rxEmpty;
|
assign data_present = ~rxEmpty;
|
|
|
assign rxITrig = rxQued >= rxThres;
|
assign rxITrig = rxQued >= rxThres;
|
assign txITrig = txQued <= txThres;
|
assign txITrig = txQued <= txThres;
|
wire rxDRQ1 = (fifoEnable ? rxITrig : ~rxEmpty);
|
wire rxDRQ1 = (fifoEnable ? rxITrig : ~rxEmpty);
|
wire txDRQ1 = (fifoEnable ? txITrig : txEmpty);
|
wire txDRQ1 = (fifoEnable ? txITrig : txEmpty);
|
assign rxDRQ_o = dmaEnable & rxDRQ1;
|
assign rxDRQ_o = dmaEnable & rxDRQ1;
|
assign txDRQ_o = dmaEnable & txDRQ1;
|
assign txDRQ_o = dmaEnable & txDRQ1;
|
wire rxIRQ = rxIe & rxDRQ1;
|
wire rxIRQ = rxIe & rxDRQ1;
|
wire txIRQ = txIe & txDRQ1;
|
wire txIRQ = txIe & txDRQ1;
|
|
|
reg [7:0] cmd0, cmd1, cmd2, cmd3;
|
reg [7:0] cmd0, cmd1, cmd2, cmd3;
|
reg [7:0] ctrl0, ctrl1, ctrl2, ctrl3;
|
reg [7:0] ctrl0, ctrl1, ctrl2, ctrl3;
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
irq_o <=
|
irq_o <=
|
rxIRQ
|
rxIRQ
|
| txIRQ
|
| txIRQ
|
| (rxTout & rxToutIe)
|
| (rxTout & rxToutIe)
|
| (lineStatusChange & lineStatusChangeIe)
|
| (lineStatusChange & lineStatusChangeIe)
|
| (modemStatusChange & modemStatusChangeIe)
|
| (modemStatusChange & modemStatusChangeIe)
|
;
|
;
|
|
|
// Hold onto address and data an extra cycle.
|
// Hold onto address and data an extra cycle.
|
// The extra cycle updates or reads the serial transmit / receive.
|
// The extra cycle updates or reads the serial transmit / receive.
|
reg [31:0] dati;
|
reg [31:0] dati;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
dati <= dat_i;
|
dati <= dat_i;
|
reg [3:2] adr_h;
|
reg [3:2] adr_h;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
adr_h <= adr_i;
|
adr_h <= adr_i;
|
reg we;
|
reg we;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
we <= we_i;
|
we <= we_i;
|
reg [3:0] sel;
|
reg [3:0] sel;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
sel <= sel_i;
|
sel <= sel_i;
|
|
|
wire [7:0] rx_do;
|
wire [7:0] rx_do;
|
wire rdrx = ack_o && adr_h==`UART_TRB && ~we && !accessCD;
|
wire rdrx = ack_o && adr_h==`UART_TRB && ~we && !accessCD;
|
wire txrx = ack_o && adr_h==`UART_TRB && !accessCD;
|
wire txrx = ack_o && adr_h==`UART_TRB && !accessCD;
|
|
|
wire cs = cs_i & cyc_i & stb_i;
|
wire cs = cs_i & cyc_i & stb_i;
|
|
|
ack_gen #(
|
ack_gen #(
|
.READ_STAGES(1),
|
.READ_STAGES(1),
|
.WRITE_STAGES(0),
|
.WRITE_STAGES(0),
|
.REGISTER_OUTPUT(1)
|
.REGISTER_OUTPUT(1)
|
) uag1
|
) uag1
|
(
|
(
|
.clk_i(clk_i),
|
.clk_i(clk_i),
|
.ce_i(1'b1),
|
.ce_i(1'b1),
|
.rid_i('d0),
|
.rid_i('d0),
|
.wid_i('d0),
|
.wid_i('d0),
|
.i(cs & ~we_i),
|
.i(cs & ~we_i),
|
.we_i(cs & we_i),
|
.we_i(cs & we_i),
|
.o(ack_o),
|
.o(ack_o),
|
.rid_o(),
|
.rid_o(),
|
.wid_o()
|
.wid_o()
|
);
|
);
|
|
|
uart6551Rx uart_rx0
|
uart6551Rx uart_rx0
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.cyc(cyc_i),
|
.cyc(cyc_i),
|
.cs(rdrx),
|
.cs(rdrx),
|
.wr(we),
|
.wr(we),
|
.dout(rx_do),
|
.dout(rx_do),
|
.ack(),
|
.ack(),
|
.fifoEnable(fifoEnable),
|
.fifoEnable(fifoEnable),
|
.fifoClear(rxFifoClear),
|
.fifoClear(rxFifoClear),
|
.clearGErr(1'b0),
|
.clearGErr(1'b0),
|
.wordLength(wordLength),
|
.wordLength(wordLength),
|
.parityCtrl(parityCtrl),
|
.parityCtrl(parityCtrl),
|
.frameSize(frameSize),
|
.frameSize(frameSize),
|
.stop_bits(stopBits),
|
.stop_bits(stopBits),
|
.baud16x_ce(baud16rx),
|
.baud16x_ce(baud16rx),
|
.clear(1'b0),
|
.clear(1'b0),
|
.rxd(llb ? txd1 : rxd_i),
|
.rxd(llb ? txd1 : rxd_i),
|
.full(),
|
.full(),
|
.empty(rxEmpty),
|
.empty(rxEmpty),
|
.frameErr(frameErr),
|
.frameErr(frameErr),
|
.overrun(overrun),
|
.overrun(overrun),
|
.parityErr(parityErr),
|
.parityErr(parityErr),
|
.break_o(rxBreak),
|
.break_o(rxBreak),
|
.gerr(rxGErr),
|
.gerr(rxGErr),
|
.qcnt(rxQued),
|
.qcnt(rxQued),
|
.cnt(rxCnt)
|
.cnt(rxCnt)
|
);
|
);
|
|
|
uart6551Tx uart_tx0
|
uart6551Tx uart_tx0
|
(
|
(
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.cyc(cyc_i),
|
.cyc(cyc_i),
|
.cs(txrx),
|
.cs(txrx),
|
.wr(we),
|
.wr(we),
|
.din(dati[7:0]),
|
.din(dati[7:0]),
|
.ack(),
|
.ack(),
|
.fifoEnable(fifoEnable),
|
.fifoEnable(fifoEnable),
|
.fifoClear(txFifoClear),
|
.fifoClear(txFifoClear),
|
.txBreak(txBreak),
|
.txBreak(txBreak),
|
.frameSize(frameSize), // 16 x 10 bits
|
.frameSize(frameSize), // 16 x 10 bits
|
.wordLength(wordLength),// 8 bits
|
.wordLength(wordLength),// 8 bits
|
.parityCtrl(parityCtrl),// no parity
|
.parityCtrl(parityCtrl),// no parity
|
.baud16x_ce(baud16),
|
.baud16x_ce(baud16),
|
.cts(ctsx[1]|~hwfc),
|
.cts(ctsx[1]|~hwfc),
|
.clear(txClear),
|
.clear(txClear),
|
.txd(txd1),
|
.txd(txd1),
|
.full(txFull),
|
.full(txFull),
|
.empty(txEmpty),
|
.empty(txEmpty),
|
.qcnt(txQued)
|
.qcnt(txQued)
|
);
|
);
|
|
|
assign txd_o = llb ? 1'b1 : txd1;
|
assign txd_o = llb ? 1'b1 : txd1;
|
|
|
assign lineStatusReg = {rxGErr,1'b0,txFull,rxBreak,1'b0,1'b0,1'b0,1'b0};
|
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 modemStatusChange = deltaDcd|deltaRi|deltaDsr|deltaCts; // modem status delta
|
assign modemStatusReg = {1'b0,~rix[1],1'b0,~ctsx[1],deltaDcd, deltaRi, deltaDsr, deltaCts};
|
assign modemStatusReg = {1'b0,~rix[1],1'b0,~ctsx[1],deltaDcd, deltaRi, deltaDsr, deltaCts};
|
assign irqStatusReg = {irq_o,2'b00,irqenc,2'b00};
|
assign irqStatusReg = {irq_o,2'b00,irqenc,2'b00};
|
|
|
// mux the reg outputs
|
// mux the reg outputs
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
begin
|
begin
|
case(adr_i)
|
case(adr_i)
|
`UART_TRB: dat_o <= accessCD ? {8'h0,clkdiv} : {24'h0,rx_do}; // receiver holding register
|
`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_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_CMD: dat_o <= {cmd3,cmd2,cmd1,cmd0};
|
`UART_CTRL: dat_o <= {ctrl3,ctrl2,ctrl1,ctrl0};
|
`UART_CTRL: dat_o <= {ctrl3,ctrl2,ctrl1,ctrl0};
|
endcase
|
endcase
|
end
|
end
|
|
|
|
|
// register updates
|
// register updates
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i) begin
|
if (rst_i) begin
|
rts_no <= HIGH;
|
rts_no <= HIGH;
|
dtr_no <= HIGH;
|
dtr_no <= HIGH;
|
// interrupts
|
// interrupts
|
rxIe <= 1'b0;
|
rxIe <= 1'b0;
|
txIe <= 1'b0;
|
txIe <= 1'b0;
|
modemStatusChangeIe <= 1'b0;
|
modemStatusChangeIe <= 1'b0;
|
lineStatusChangeIe <= 1'b0;
|
lineStatusChangeIe <= 1'b0;
|
hwfc <= 1'b0;
|
hwfc <= 1'b0;
|
modemStatusChangeIe <= 1'b0;
|
modemStatusChangeIe <= 1'b0;
|
lineStatusChangeIe <= 1'b0;
|
lineStatusChangeIe <= 1'b0;
|
dmaEnable <= 1'b0;
|
dmaEnable <= 1'b0;
|
// clock control
|
// clock control
|
baudRateSel <= 5'h0;
|
baudRateSel <= 5'h0;
|
rxClkSrc <= 1'b0; // ** 6551 defaults to zero (external receiver clock)
|
rxClkSrc <= 1'b0; // ** 6551 defaults to zero (external receiver clock)
|
clkdiv <= pClkDiv;
|
clkdiv <= pClkDiv;
|
// frame format
|
// frame format
|
wordLength <= 4'd8; // 8 bits
|
wordLength <= 4'd8; // 8 bits
|
stopBit <= 1'b0; // 1 stop bit
|
stopBit <= 1'b0; // 1 stop bit
|
parityCtrl <= 3'd0; // no parity
|
parityCtrl <= 3'd0; // no parity
|
|
|
txBreak <= 1'b0;
|
txBreak <= 1'b0;
|
// Fifo control
|
// Fifo control
|
txFifoClear <= 1'b1;
|
txFifoClear <= 1'b1;
|
rxFifoClear <= 1'b1;
|
rxFifoClear <= 1'b1;
|
txClear <= 1'b1;
|
txClear <= 1'b1;
|
fifoEnable <= 1'b1;
|
fifoEnable <= 1'b1;
|
// Test
|
// Test
|
llb <= 1'b0;
|
llb <= 1'b0;
|
selCD <= 1'b0;
|
selCD <= 1'b0;
|
accessCD <= 1'b0;
|
accessCD <= 1'b0;
|
end
|
end
|
else begin
|
else begin
|
|
|
//llb <= 1'b1;
|
//llb <= 1'b1;
|
rxFifoClear <= 1'b0;
|
rxFifoClear <= 1'b0;
|
txFifoClear <= 1'b0;
|
txFifoClear <= 1'b0;
|
txClear <= 1'b0;
|
txClear <= 1'b0;
|
ctrl2[1] <= 1'b0;
|
ctrl2[1] <= 1'b0;
|
ctrl2[2] <= 1'b0;
|
ctrl2[2] <= 1'b0;
|
|
|
if (ack_o & we) begin
|
if (ack_o & we) begin
|
case (adr_h) // synopsys full_case parallel_case
|
case (adr_h) // synopsys full_case parallel_case
|
|
|
`UART_TRB:
|
`UART_TRB:
|
if (accessCD) begin
|
if (accessCD) begin
|
clkdiv <= dati;
|
clkdiv <= dati;
|
accessCD <= 1'b0;
|
accessCD <= 1'b0;
|
ctrl3[7] <= 1'b0;
|
ctrl3[7] <= 1'b0;
|
end
|
end
|
|
|
// Writing to the status register does a software reset of some bits.
|
// Writing to the status register does a software reset of some bits.
|
`UART_STAT:
|
`UART_STAT:
|
begin
|
begin
|
dtr_no <= HIGH;
|
dtr_no <= HIGH;
|
rxIe <= 1'b0;
|
rxIe <= 1'b0;
|
rts_no <= HIGH;
|
rts_no <= HIGH;
|
txIe <= 1'b0;
|
txIe <= 1'b0;
|
txBreak <= 1'b0;
|
txBreak <= 1'b0;
|
llb <= 1'b0;
|
llb <= 1'b0;
|
end
|
end
|
`UART_CMD:
|
`UART_CMD:
|
begin
|
begin
|
if (sel[0]) begin
|
if (sel[0]) begin
|
cmd0 <= dati[7:0];
|
cmd0 <= dati[7:0];
|
dtr_no <= ~dati[0];
|
dtr_no <= ~dati[0];
|
rxIe <= ~dati[1];
|
rxIe <= ~dati[1];
|
case(dati[3:2])
|
case(dati[3:2])
|
2'd0: begin rts_no <= 1'b1; txIe <= 1'b0; txBreak <= 1'b0; end
|
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'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'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
|
2'd3: begin rts_no <= 1'b0; txIe <= 1'b0; txBreak <= 1'b1; end
|
endcase
|
endcase
|
llb <= dati[4];
|
llb <= dati[4];
|
parityCtrl <= dati[7:5]; //000=none,001=odd,011=even,101=force 1,111 = force 0
|
parityCtrl <= dati[7:5]; //000=none,001=odd,011=even,101=force 1,111 = force 0
|
end
|
end
|
if (sel[1]) begin
|
if (sel[1]) begin
|
cmd1 <= dati[15:8];
|
cmd1 <= dati[15:8];
|
lineStatusChangeIe <= dati[8];
|
lineStatusChangeIe <= dati[8];
|
modemStatusChangeIe <= dati[9];
|
modemStatusChangeIe <= dati[9];
|
rxToutIe <= dati[10];
|
rxToutIe <= dati[10];
|
end
|
end
|
if (sel[2])
|
if (sel[2])
|
cmd2 <= dati[23:16];
|
cmd2 <= dati[23:16];
|
if (sel[3])
|
if (sel[3])
|
cmd3 <= dati[31:24];
|
cmd3 <= dati[31:24];
|
end
|
end
|
|
|
`UART_CTRL:
|
`UART_CTRL:
|
begin
|
begin
|
if (sel[0]) begin
|
if (sel[0]) begin
|
ctrl0 <= dati[7:0];
|
ctrl0 <= dati[7:0];
|
baudRateSel[3:0] <= dati[3:0];
|
baudRateSel[3:0] <= dati[3:0];
|
rxClkSrc <= dati[4]; // 1 = baud rate generator, 0 = external
|
rxClkSrc <= dati[4]; // 1 = baud rate generator, 0 = external
|
//11=5,10=6,01=7,00=8
|
//11=5,10=6,01=7,00=8
|
case(dati[6:5])
|
case(dati[6:5])
|
2'd0: wordLength <= 6'd8;
|
2'd0: wordLength <= 6'd8;
|
2'd1: wordLength <= 6'd7;
|
2'd1: wordLength <= 6'd7;
|
2'd2: wordLength <= 6'd6;
|
2'd2: wordLength <= 6'd6;
|
2'd3: wordLength <= 6'd5;
|
2'd3: wordLength <= 6'd5;
|
endcase
|
endcase
|
stopBit <= dati[7]; //0=1,1=1.5 or 2
|
stopBit <= dati[7]; //0=1,1=1.5 or 2
|
end
|
end
|
// Extended word length, values beyond 11 not supported.
|
// Extended word length, values beyond 11 not supported.
|
if (sel[1]) begin
|
if (sel[1]) begin
|
ctrl1 <= dati[15:8];
|
ctrl1 <= dati[15:8];
|
end
|
end
|
if (sel[2]) begin
|
if (sel[2]) begin
|
ctrl2 <= dati[23:16];
|
ctrl2 <= dati[23:16];
|
fifoEnable <= dati[16];
|
fifoEnable <= dati[16];
|
rxFifoClear <= dati[17];
|
rxFifoClear <= dati[17];
|
txFifoClear <= dati[18];
|
txFifoClear <= dati[18];
|
case (dati[21:20])
|
case (dati[21:20])
|
2'd0: txThres <= 4'd1; // one-byte
|
2'd0: txThres <= 4'd1; // one-byte
|
2'd1: txThres <= pFifoSize / 4; // one-quarter full
|
2'd1: txThres <= pFifoSize / 4; // one-quarter full
|
2'd2: txThres <= pFifoSize / 2; // one-half full
|
2'd2: txThres <= pFifoSize / 2; // one-half full
|
2'd3: txThres <= pFifoSize * 3 / 4; // three-quarters full
|
2'd3: txThres <= pFifoSize * 3 / 4; // three-quarters full
|
endcase
|
endcase
|
case (dati[23:22])
|
case (dati[23:22])
|
2'd0: rxThres <= 4'd1; // one-byte
|
2'd0: rxThres <= 4'd1; // one-byte
|
2'd1: rxThres <= pFifoSize / 4; // one-quarter full
|
2'd1: rxThres <= pFifoSize / 4; // one-quarter full
|
2'd2: rxThres <= pFifoSize / 2; // one-half full
|
2'd2: rxThres <= pFifoSize / 2; // one-half full
|
2'd3: rxThres <= pFifoSize * 3 / 4; // three quarters full
|
2'd3: rxThres <= pFifoSize * 3 / 4; // three quarters full
|
endcase
|
endcase
|
end
|
end
|
if (sel[3]) begin
|
if (sel[3]) begin
|
ctrl3 <= dati[31:24];
|
ctrl3 <= dati[31:24];
|
hwfc <= dati[24];
|
hwfc <= dati[24];
|
dmaEnable <= dati[26];
|
dmaEnable <= dati[26];
|
baudRateSel[4] <= dati[27];
|
baudRateSel[4] <= dati[27];
|
txClear <= dati[29];
|
txClear <= dati[29];
|
selCD <= dati[30];
|
selCD <= dati[30];
|
accessCD <= dati[31];
|
accessCD <= dati[31];
|
end
|
end
|
end
|
end
|
|
|
default:
|
default:
|
;
|
;
|
endcase
|
endcase
|
end
|
end
|
end
|
end
|
|
|
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
// Baud rate control.
|
// Baud rate control.
|
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
xClkSrc <= baudRateSel==5'd0;
|
xClkSrc <= baudRateSel==5'd0;
|
|
|
wire [pCounterBits-1:0] bclkdiv;
|
wire [pCounterBits-1:0] bclkdiv;
|
uart6551BaudLUT #(.pClkFreq(pClkFreq), .pCounterBits(pCounterBits)) ublt1 (.a(baudRateSel), .o(bclkdiv));
|
uart6551BaudLUT #(.pClkFreq(pClkFreq), .pCounterBits(pCounterBits)) ublt1 (.a(baudRateSel), .o(bclkdiv));
|
|
|
reg [pCounterBits-1:0] clkdiv2;
|
reg [pCounterBits-1:0] clkdiv2;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
clkdiv2 <= selCD ? clkdiv : bclkdiv;
|
clkdiv2 <= selCD ? clkdiv : bclkdiv;
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i)
|
if (rst_i)
|
c <= 1'd1;
|
c <= 24'd1;
|
else begin
|
else begin
|
c <= c + 2'd1;
|
c <= c + 2'd1;
|
if (c >= clkdiv2)
|
if (c >= clkdiv2)
|
c <= 2'd1;
|
c <= 2'd1;
|
end
|
end
|
|
|
// for detecting an edge on the baud clock
|
// for detecting an edge on the baud clock
|
wire ibaud16 = c == 2'd1;
|
wire ibaud16 = c == 2'd1;
|
|
|
// Detect an edge on the external clock
|
// Detect an edge on the external clock
|
wire xclkEdge;
|
wire xclkEdge;
|
edge_det ed1(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(xclks[1]), .pe(xclkEdge), .ne() );
|
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
|
// Detect an edge on the external clock
|
wire rxClkEdge;
|
wire rxClkEdge;
|
edge_det ed2(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(RxCs[1]), .pe(rxClkEdge), .ne() );
|
edge_det ed2(.rst(rst_i), .clk(clk_i), .ce(1'b1), .i(RxCs[1]), .pe(rxClkEdge), .ne() );
|
|
|
always @(xClkSrc or xclkEdge or ibaud16)
|
always_comb
|
if (xClkSrc) // 16x external clock (xclk)
|
if (xClkSrc) // 16x external clock (xclk)
|
baud16 <= xclkEdge;
|
baud16 <= xclkEdge;
|
else
|
else
|
baud16 <= ibaud16;
|
baud16 <= ibaud16;
|
|
|
assign baud16rx = rxClkSrc ? baud16 : rxClkEdge;
|
assign baud16rx = rxClkSrc ? baud16 : rxClkEdge;
|
|
|
//------------------------------------------------------------
|
//------------------------------------------------------------
|
// external signal synchronization
|
// external signal synchronization
|
//------------------------------------------------------------
|
//------------------------------------------------------------
|
|
|
// External receiver clock
|
// External receiver clock
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
RxCs <= {RxCs[1:0],RxC_i};
|
RxCs <= {RxCs[1:0],RxC_i};
|
|
|
// External baud clock
|
// External baud clock
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
xclks <= {xclks[1:0],xclk_i};
|
xclks <= {xclks[1:0],xclk_i};
|
|
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
ctsx <= {ctsx[0],llb?~rts_no:~cts_ni};
|
ctsx <= {ctsx[0],llb?~rts_no:~cts_ni};
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
dcdx <= {dcdx[0],~dcd_ni};
|
dcdx <= {dcdx[0],~dcd_ni};
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
dsrx <= {dsrx[0],llb?~dtr_no:~dsr_ni};
|
dsrx <= {dsrx[0],llb?~dtr_no:~dsr_ni};
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
rix <= {rix[0],~ri_ni};
|
rix <= {rix[0],~ri_ni};
|
|
|
//------------------------------------------------------------
|
//------------------------------------------------------------
|
// state change detectors
|
// state change detectors
|
//------------------------------------------------------------
|
//------------------------------------------------------------
|
|
|
wire ne_stat;
|
wire ne_stat;
|
edge_det ued3 (
|
edge_det ued3 (
|
.rst(rst_i),
|
.rst(rst_i),
|
.clk(clk_i),
|
.clk(clk_i),
|
.ce(1'b1),
|
.ce(1'b1),
|
.i(ack_o && adr_i==`UART_STAT && ~we_i && sel_i[2]),
|
.i(ack_o && adr_i==`UART_STAT && ~we_i && sel_i[2]),
|
.pe(),
|
.pe(),
|
.ne(ne_stat),
|
.ne(ne_stat),
|
.ee()
|
.ee()
|
);
|
);
|
|
|
// detect a change on the dsr signal
|
// detect a change on the dsr signal
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i)
|
if (rst_i)
|
deltaDsr <= 1'b0;
|
deltaDsr <= 1'b0;
|
else begin
|
else begin
|
if (ne_stat)
|
if (ne_stat)
|
deltaDsr <= 0;
|
deltaDsr <= 0;
|
else if (~deltaDsr)
|
else if (~deltaDsr)
|
deltaDsr <= dsrx[1] ^ dsrx[0];
|
deltaDsr <= dsrx[1] ^ dsrx[0];
|
end
|
end
|
|
|
// detect a change on the dcd signal
|
// detect a change on the dcd signal
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i)
|
if (rst_i)
|
deltaDcd <= 1'b0;
|
deltaDcd <= 1'b0;
|
else begin
|
else begin
|
if (ne_stat)
|
if (ne_stat)
|
deltaDcd <= 0;
|
deltaDcd <= 0;
|
else if (~deltaDcd)
|
else if (~deltaDcd)
|
deltaDcd <= dcdx[1] ^ dcdx[0];
|
deltaDcd <= dcdx[1] ^ dcdx[0];
|
end
|
end
|
|
|
// detect a change on the cts signal
|
// detect a change on the cts signal
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i)
|
if (rst_i)
|
deltaCts <= 1'b0;
|
deltaCts <= 1'b0;
|
else begin
|
else begin
|
if (ne_stat)
|
if (ne_stat)
|
deltaCts <= 0;
|
deltaCts <= 0;
|
else if (~deltaCts)
|
else if (~deltaCts)
|
deltaCts <= ctsx[1] ^ ctsx[0];
|
deltaCts <= ctsx[1] ^ ctsx[0];
|
end
|
end
|
|
|
// detect a change on the ri signal
|
// detect a change on the ri signal
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i)
|
if (rst_i)
|
deltaRi <= 1'b0;
|
deltaRi <= 1'b0;
|
else begin
|
else begin
|
if (ne_stat)
|
if (ne_stat)
|
deltaRi <= 0;
|
deltaRi <= 0;
|
else if (~deltaRi)
|
else if (~deltaRi)
|
deltaRi <= rix[1] ^ rix[0];
|
deltaRi <= rix[1] ^ rix[0];
|
end
|
end
|
|
|
// detect a change in line status
|
// detect a change in line status
|
reg [7:0] pLineStatusReg;
|
reg [7:0] pLineStatusReg;
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
pLineStatusReg <= lineStatusReg;
|
pLineStatusReg <= lineStatusReg;
|
|
|
assign lineStatusChange = pLineStatusReg != lineStatusReg;
|
assign lineStatusChange = pLineStatusReg != lineStatusReg;
|
|
|
//-----------------------------------------------------
|
//-----------------------------------------------------
|
|
|
// compute recieve timeout
|
// compute recieve timeout
|
always @(wordLength)
|
always @(wordLength)
|
rxToutMax <= (wordLength << 2) + 6'd12;
|
rxToutMax <= (wordLength << 2) + 6'd12;
|
|
|
always @(posedge clk_i)
|
always @(posedge clk_i)
|
if (rst_i)
|
if (rst_i)
|
rxTout <= 1'b0;
|
rxTout <= 1'b0;
|
else begin
|
else begin
|
// read of receiver clears timeout counter
|
// read of receiver clears timeout counter
|
if (rdrx)
|
if (rdrx)
|
rxTout <= 1'b0;
|
rxTout <= 1'b0;
|
// Don't time out if the fifo is empty
|
// Don't time out if the fifo is empty
|
else if (rxCnt[9:4]==rxToutMax && ~rxEmpty)
|
else if (rxCnt[9:4]==rxToutMax && ~rxEmpty)
|
rxTout <= 1'b1;
|
rxTout <= 1'b1;
|
end
|
end
|
|
|
|
|
//-----------------------------------------------------
|
//-----------------------------------------------------
|
// compute the 2x number of stop bits
|
// compute the 2x number of stop bits
|
always @*
|
always @*
|
if (stopBit==1'b0) // one stop bit
|
if (stopBit==1'b0) // one stop bit
|
stopBits <= 3'd2;
|
stopBits <= 3'd2;
|
else if (wordLength==6'd8 && parityCtrl != 3'd0)
|
else if (wordLength==6'd8 && parityCtrl != 3'd0)
|
stopBits <= 3'd2;
|
stopBits <= 3'd2;
|
else if (wordLength==6'd5 && parityCtrl == 3'd0) // 5 bits - 1 1/2 stop bit
|
else if (wordLength==6'd5 && parityCtrl == 3'd0) // 5 bits - 1 1/2 stop bit
|
stopBits <= 3'd3;
|
stopBits <= 3'd3;
|
else
|
else
|
stopBits <= 3'd4; // two stop bits
|
stopBits <= 3'd4; // two stop bits
|
|
|
|
|
// compute frame size
|
// compute frame size
|
// frame size is one less
|
// frame size is one less
|
assign frameSize = {wordLength + 4'd1 + stopBits[2:1] + parityCtrl[0], stopBits[0],3'b0} - 1;
|
assign frameSize = {wordLength + 4'd1 + stopBits[2:1] + parityCtrl[0], stopBits[0],3'b0} - 1;
|
|
|
//-----------------------------------------------------
|
//-----------------------------------------------------
|
// encode IRQ mailbox
|
// encode IRQ mailbox
|
always @(rxDRQ_o or rxTout or txDRQ_o or lineStatusChange or modemStatusChange)
|
always @(rxDRQ_o or rxTout or txDRQ_o or lineStatusChange or modemStatusChange)
|
irqenc <=
|
irqenc <=
|
lineStatusChange ? 3'd0 :
|
lineStatusChange ? 3'd0 :
|
~rxDRQ_o ? 3'd1 :
|
~rxDRQ_o ? 3'd1 :
|
rxTout ? 3'd2 :
|
rxTout ? 3'd2 :
|
~txDRQ_o ? 3'd3 :
|
~txDRQ_o ? 3'd3 :
|
modemStatusChange ? 3'd4 :
|
modemStatusChange ? 3'd4 :
|
3'd0;
|
3'd0;
|
|
|
endmodule
|
endmodule
|
|
|