Line 45... |
Line 45... |
module wbuart(i_clk, i_rst,
|
module wbuart(i_clk, i_rst,
|
//
|
//
|
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
|
i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data,
|
o_wb_ack, o_wb_stall, o_wb_data,
|
o_wb_ack, o_wb_stall, o_wb_data,
|
//
|
//
|
i_uart_rx, o_uart_tx, i_rts, o_cts,
|
i_uart_rx, o_uart_tx, i_cts_n, o_rts_n,
|
// i_uart_rts, o_uart_cts, i_uart_dtr, o_uart_dts
|
|
//
|
//
|
o_uart_rx_int, o_uart_tx_int,
|
o_uart_rx_int, o_uart_tx_int,
|
o_uart_rxfifo_int, o_uart_txfifo_int);
|
o_uart_rxfifo_int, o_uart_txfifo_int);
|
parameter [30:0] INITIAL_SETUP = 31'd25; // 4MB 8N1, when using 100MHz clock
|
parameter [30:0] INITIAL_SETUP = 31'd25; // 4MB 8N1, when using 100MHz clock
|
parameter [3:0] LGFLEN = 4;
|
parameter [3:0] LGFLEN = 4;
|
Line 75... |
Line 74... |
// RTS is used for hardware flow control. According to Wikipedia, it
|
// RTS is used for hardware flow control. According to Wikipedia, it
|
// should probably be renamed RTR for "ready to receive". It tell us
|
// should probably be renamed RTR for "ready to receive". It tell us
|
// whether or not the receiving hardware is ready to accept another
|
// whether or not the receiving hardware is ready to accept another
|
// byte. If low, the transmitter will pause.
|
// byte. If low, the transmitter will pause.
|
//
|
//
|
// If you don't wish to use hardware flow control, just set i_rts to
|
// If you don't wish to use hardware flow control, just set i_cts_n to
|
// 1'b1 and let the optimizer simply remove this logic.
|
// 1'b0 and let the optimizer simply remove this logic.
|
input i_rts;
|
input i_cts_n;
|
// CTS is the "Clear-to-send" signal. We set it anytime our FIFO
|
// CTS is the "Clear-to-send" signal. We set it anytime our FIFO
|
// isn't full. Feel free to ignore this output if you do not wish to
|
// isn't full. Feel free to ignore this output if you do not wish to
|
// use flow control.
|
// use flow control.
|
output reg o_cts;
|
output reg o_rts_n;
|
output wire o_uart_rx_int, o_uart_tx_int,
|
output wire o_uart_rx_int, o_uart_tx_int,
|
o_uart_rxfifo_int, o_uart_txfifo_int;
|
o_uart_rxfifo_int, o_uart_txfifo_int;
|
|
|
wire tx_busy;
|
wire tx_busy;
|
|
|
Line 118... |
Line 117... |
wire [7:0] rx_uart_data;
|
wire [7:0] rx_uart_data;
|
reg rx_uart_reset;
|
reg rx_uart_reset;
|
|
|
// Here's our UART receiver. Basically, it accepts our setup wires,
|
// Here's our UART receiver. Basically, it accepts our setup wires,
|
// the UART input, a clock, and a reset line, and produces outputs:
|
// the UART input, a clock, and a reset line, and produces outputs:
|
// a stb (true when new data is ready), an 8-bit data out value
|
// a stb (true when new data is ready), and an 8-bit data out value
|
// valid when stb is high, a break value (true during a break cond.),
|
// valid when stb is high.
|
// and parity/framing error flags--also valid when stb is true.
|
`ifdef USE_LITE_UART
|
|
rxuartlite #(INITIAL_SETUP[23:0])
|
|
rx(i_clk, (i_rst), i_uart_rx, rx_stb, rx_uart_data);
|
|
assign rx_break = 1'b0;
|
|
assign rx_perr = 1'b0;
|
|
assign rx_ferr = 1'b0;
|
|
assign ck_uart = 1'b0;
|
|
`else
|
|
// The full receiver also produces a break value (true during a break
|
|
// cond.), and parity/framing error flags--also valid when stb is true.
|
rxuart #(INITIAL_SETUP) rx(i_clk, (i_rst)||(rx_uart_reset),
|
rxuart #(INITIAL_SETUP) rx(i_clk, (i_rst)||(rx_uart_reset),
|
uart_setup, i_uart_rx,
|
uart_setup, i_uart_rx,
|
rx_stb, rx_uart_data, rx_break,
|
rx_stb, rx_uart_data, rx_break,
|
rx_perr, rx_ferr, ck_uart);
|
rx_perr, rx_ferr, ck_uart);
|
// The real trick is ... now that we have this data, what do we do
|
// The real trick is ... now that we have this extra data, what do we do
|
// with it?
|
// with it?
|
|
`endif
|
|
|
|
|
// We place it into a receiver FIFO.
|
// We place it into a receiver FIFO.
|
//
|
//
|
// Here's the declarations for the wires it needs.
|
// Here's the declarations for the wires it needs.
|
Line 168... |
Line 177... |
// to be true any time the FIFO has fewer than N-2 items in it.
|
// to be true any time the FIFO has fewer than N-2 items in it.
|
// Why N-1? Because at N-1 we are totally full, but already so full
|
// Why N-1? Because at N-1 we are totally full, but already so full
|
// that if the transmit end starts sending we won't have a location to
|
// that if the transmit end starts sending we won't have a location to
|
// receive it. (Transmit might've started on the next character by the
|
// receive it. (Transmit might've started on the next character by the
|
// time we set this--need to set it to one character before necessary
|
// time we set this--need to set it to one character before necessary
|
// thus.)
|
|
wire [(LCLLGFLEN-1):0] check_cutoff;
|
|
assign check_cutoff = -3;
|
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
o_cts = (!HARDWARE_FLOW_CONTROL_PRESENT)
|
o_rts_n = ((HARDWARE_FLOW_CONTROL_PRESENT)
|
||(rxf_status[(LCLLGFLEN+1):2] > check_cutoff);
|
&&(!uart_setup[30])
|
|
&&(rxf_status[(LCLLGFLEN+1):4]=={(LCLLGFLEN-2){1'b1}}));
|
|
|
// If the bus requests that we read from the receive FIFO, we need to
|
// If the bus requests that we read from the receive FIFO, we need to
|
// tell this to the receive FIFO. Note that because we are using a
|
// tell this to the receive FIFO. Note that because we are using a
|
// clock here, the output from the receive FIFO will necessarily be
|
// clock here, the output from the receive FIFO will necessarily be
|
// delayed by an extra clock.
|
// delayed by an extra clock.
|
Line 248... |
Line 255... |
//
|
//
|
// Then the UART transmitter
|
// Then the UART transmitter
|
//
|
//
|
//
|
//
|
/////////////////////////////////////////
|
/////////////////////////////////////////
|
wire tx_empty_n, txf_err;
|
wire tx_empty_n, txf_err, tx_break;
|
wire [7:0] tx_data;
|
wire [7:0] tx_data;
|
wire [15:0] txf_status;
|
wire [15:0] txf_status;
|
reg r_tx_break, txf_wb_write, tx_uart_reset;
|
reg txf_wb_write, tx_uart_reset;
|
reg [7:0] txf_wb_data;
|
reg [7:0] txf_wb_data;
|
|
|
// Unlike the receiver which goes from RXUART -> UFIFO -> WB, the
|
// Unlike the receiver which goes from RXUART -> UFIFO -> WB, the
|
// transmitter basically goes WB -> UFIFO -> TXUART. Hence, to build
|
// transmitter basically goes WB -> UFIFO -> TXUART. Hence, to build
|
// support for the transmitter, we start with the command to write data
|
// support for the transmitter, we start with the command to write data
|
Line 280... |
Line 287... |
// differences to note: we reset the transmitter on any request for a
|
// differences to note: we reset the transmitter on any request for a
|
// break. We read from the FIFO any time the UART transmitter is idle.
|
// break. We read from the FIFO any time the UART transmitter is idle.
|
// and ... we just set the values (above) for controlling writing into
|
// and ... we just set the values (above) for controlling writing into
|
// this.
|
// this.
|
ufifo #(.LGFLEN(LGFLEN), .RXFIFO(0))
|
ufifo #(.LGFLEN(LGFLEN), .RXFIFO(0))
|
txfifo(i_clk, (r_tx_break)||(tx_uart_reset),
|
txfifo(i_clk, (tx_break)||(tx_uart_reset),
|
txf_wb_write, txf_wb_data,
|
txf_wb_write, txf_wb_data,
|
tx_empty_n,
|
tx_empty_n,
|
(!tx_busy)&&(tx_empty_n), tx_data,
|
(!tx_busy)&&(tx_empty_n), tx_data,
|
txf_status, txf_err);
|
txf_status, txf_err);
|
// Let's create two transmit based interrupts from the FIFO for the CPU.
|
// Let's create two transmit based interrupts from the FIFO for the CPU.
|
Line 294... |
Line 301... |
// The second will be true any time the FIFO is less than half
|
// The second will be true any time the FIFO is less than half
|
// full, allowing us a change to always keep it (near) fully
|
// full, allowing us a change to always keep it (near) fully
|
// charged.
|
// charged.
|
assign o_uart_txfifo_int = txf_status[1];
|
assign o_uart_txfifo_int = txf_status[1];
|
|
|
|
`ifndef USE_LITE_UART
|
// Break logic
|
// Break logic
|
//
|
//
|
// A break in a UART controller is any time the UART holds the line
|
// A break in a UART controller is any time the UART holds the line
|
// low for an extended period of time. Here, we capture the wb_data[9]
|
// low for an extended period of time. Here, we capture the wb_data[9]
|
// wire, on writes, as an indication we wish to break. As long as you
|
// wire, on writes, as an indication we wish to break. As long as you
|
// write unsigned characters to the interface, this will never be true
|
// write unsigned characters to the interface, this will never be true
|
// unless you wish it to be true. Be aware, though, writing a valid
|
// unless you wish it to be true. Be aware, though, writing a valid
|
// value to the interface will bring it out of the break condition.
|
// value to the interface will bring it out of the break condition.
|
|
reg r_tx_break;
|
initial r_tx_break = 1'b0;
|
initial r_tx_break = 1'b0;
|
always @(posedge i_clk)
|
always @(posedge i_clk)
|
if (i_rst)
|
if (i_rst)
|
r_tx_break <= 1'b0;
|
r_tx_break <= 1'b0;
|
else if ((i_wb_stb)&&(i_wb_addr[1:0]==`UART_TXREG)&&(i_wb_we))
|
else if ((i_wb_stb)&&(i_wb_addr[1:0]==`UART_TXREG)&&(i_wb_we))
|
r_tx_break <= i_wb_data[9];
|
r_tx_break <= i_wb_data[9];
|
|
assign tx_break = r_tx_break;
|
|
`else
|
|
assign tx_break = 1'b0;
|
|
`endif
|
|
|
// TX-Reset logic
|
// TX-Reset logic
|
//
|
//
|
// This is nearly identical to the RX reset logic above. Basically,
|
// This is nearly identical to the RX reset logic above. Basically,
|
// any time someone writes to bit [12] the transmitter will go through
|
// any time someone writes to bit [12] the transmitter will go through
|
Line 324... |
Line 337... |
else if ((i_wb_stb)&&(i_wb_addr[1:0]==`UART_TXREG)&&(i_wb_we))
|
else if ((i_wb_stb)&&(i_wb_addr[1:0]==`UART_TXREG)&&(i_wb_we))
|
tx_uart_reset <= i_wb_data[12];
|
tx_uart_reset <= i_wb_data[12];
|
else
|
else
|
tx_uart_reset <= 1'b0;
|
tx_uart_reset <= 1'b0;
|
|
|
wire rts;
|
`ifdef USE_LITE_UART
|
assign rts = (!HARDWARE_FLOW_CONTROL_PRESENT)||(i_rts);
|
txuart #(INITIAL_SETUP[23:0]) tx(i_clk, (tx_empty_n), tx_data,
|
|
o_uart_tx, tx_busy);
|
|
`else
|
|
wire cts_n;
|
|
assign cts_n = (HARDWARE_FLOW_CONTROL_PRESENT)&&(i_cts_n);
|
// Finally, the UART transmitter module itself. Note that we haven't
|
// Finally, the UART transmitter module itself. Note that we haven't
|
// connected the reset wire. Transmitting is as simple as setting
|
// connected the reset wire. Transmitting is as simple as setting
|
// the stb value (here set to tx_empty_n) and the data. When these
|
// the stb value (here set to tx_empty_n) and the data. When these
|
// are both set on the same clock that tx_busy is low, the transmitter
|
// are both set on the same clock that tx_busy is low, the transmitter
|
// will move on to the next data byte. Really, the only thing magical
|
// will move on to the next data byte. Really, the only thing magical
|
Line 337... |
Line 354... |
// we read it here. (You might notice above, we register a read any
|
// we read it here. (You might notice above, we register a read any
|
// time (tx_empty_n) and (!tx_busy) are both true---the condition for
|
// time (tx_empty_n) and (!tx_busy) are both true---the condition for
|
// starting to transmit a new byte.)
|
// starting to transmit a new byte.)
|
txuart #(INITIAL_SETUP) tx(i_clk, 1'b0, uart_setup,
|
txuart #(INITIAL_SETUP) tx(i_clk, 1'b0, uart_setup,
|
r_tx_break, (tx_empty_n), tx_data,
|
r_tx_break, (tx_empty_n), tx_data,
|
i_rts, o_uart_tx, tx_busy);
|
cts_n, o_uart_tx, tx_busy);
|
|
`endif
|
|
|
// Now that we are done with the chain, pick some wires for the user
|
// Now that we are done with the chain, pick some wires for the user
|
// to read on any read of the transmit port.
|
// to read on any read of the transmit port.
|
//
|
//
|
// This port is different from reading from the receive port, since
|
// This port is different from reading from the receive port, since
|
Line 353... |
Line 371... |
// voltage on the line (o_uart_tx)--and even the voltage on the receive
|
// voltage on the line (o_uart_tx)--and even the voltage on the receive
|
// line (ck_uart), as well as our current setting of the break and
|
// line (ck_uart), as well as our current setting of the break and
|
// whether or not we are actively transmitting.
|
// whether or not we are actively transmitting.
|
wire [31:0] wb_tx_data;
|
wire [31:0] wb_tx_data;
|
assign wb_tx_data = { 16'h00,
|
assign wb_tx_data = { 16'h00,
|
i_rts, txf_status[1:0], txf_err,
|
i_cts_n, txf_status[1:0], txf_err,
|
ck_uart, o_uart_tx, r_tx_break, (tx_busy|txf_status[0]),
|
ck_uart, o_uart_tx, tx_break, (tx_busy|txf_status[0]),
|
(tx_busy|txf_status[0])?txf_wb_data:8'b00};
|
(tx_busy|txf_status[0])?txf_wb_data:8'b00};
|
|
|
// Each of the FIFO's returns a 16 bit status value. This value tells
|
// Each of the FIFO's returns a 16 bit status value. This value tells
|
// us both how big the FIFO is, as well as how much of the FIFO is in
|
// us both how big the FIFO is, as well as how much of the FIFO is in
|
// use. Let's merge those two status words together into a word we
|
// use. Let's merge those two status words together into a word we
|