OpenCores
URL https://opencores.org/ocsvn/wbuart32/wbuart32/trunk

Subversion Repositories wbuart32

[/] [wbuart32/] [trunk/] [rtl/] [wbuart.v] - Diff between revs 6 and 9

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 6 Rev 9
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Filename:    wbuart.v
// Filename:    wbuart.v
//
//
// Project:     wbuart32, a full featured UART with simulator
// Project:     wbuart32, a full featured UART with simulator
//
//
// Purpose:     Unlilke wbuart-insert.v, this is a full blown wishbone core
// Purpose:     Unlilke wbuart-insert.v, this is a full blown wishbone core
//              with integrated FIFO support to support the UART transmitter
//              with integrated FIFO support to support the UART transmitter
//      and receiver found within here.  As a result, it's usage may be
//      and receiver found within here.  As a result, it's usage may be
//      heavier on the bus than the insert, but it may also be more useful.
//      heavier on the bus than the insert, but it may also be more useful.
//
//
// Creator:     Dan Gisselquist, Ph.D.
// Creator:     Dan Gisselquist, Ph.D.
//              Gisselquist Technology, LLC
//              Gisselquist Technology, LLC
//
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
//
//
// This program is free software (firmware): you can redistribute it and/or
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of  the GNU General Public License as published
// modify it under the terms of  the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
// your option) any later version.
//
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
// for more details.
//
//
// You should have received a copy of the GNU General Public License along
// You should have received a copy of the GNU General Public License along
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
// target there if the PDF file isn't present.)  If not, see
// target there if the PDF file isn't present.)  If not, see
// <http://www.gnu.org/licenses/> for a copy.
// <http://www.gnu.org/licenses/> for a copy.
//
//
// License:     GPL, v3, as defined and found on www.gnu.org,
// License:     GPL, v3, as defined and found on www.gnu.org,
//              http://www.gnu.org/licenses/gpl.html
//              http://www.gnu.org/licenses/gpl.html
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
`define UART_SETUP      2'b00
`define UART_SETUP      2'b00
`define UART_FIFO       2'b01
`define UART_FIFO       2'b01
`define UART_RXREG      2'b10
`define UART_RXREG      2'b10
`define UART_TXREG      2'b11
`define UART_TXREG      2'b11
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_stall, o_wb_ack, o_wb_data,
                        o_wb_ack, o_wb_stall, o_wb_data,
                //
                //
                i_uart_rx, o_uart_tx,
                i_uart_rx, o_uart_tx, i_rts, o_cts,
                // i_uart_rts, o_uart_cts, i_uart_dtr, o_uart_dts
                // 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       INITIAL_SETUP = 30'd25, // 4MB 8N1, when using 100MHz clock
        parameter [30:0] INITIAL_SETUP = 31'd25; // 4MB 8N1, when using 100MHz clock
                        LGFLEN = 4;
        parameter [3:0]  LGFLEN = 4;
 
        parameter [0:0]   HARDWARE_FLOW_CONTROL_PRESENT = 1'b1;
 
        // Perform a simple/quick bounds check on the log FIFO length, to make
 
        // sure its within the bounds we can support with our current
 
        // interface.
 
        localparam [3:0] LCLLGFLEN = (LGFLEN > 4'ha)? 4'ha
 
                                        : ((LGFLEN < 4'h2) ? 4'h2 : LGFLEN);
        //
        //
        input   i_clk, i_rst;
        input   i_clk, i_rst;
        // Wishbone inputs
        // Wishbone inputs
        input                   i_wb_cyc, i_wb_stb, i_wb_we;
        input                   i_wb_cyc, i_wb_stb, i_wb_we;
        input           [1:0]    i_wb_addr;
        input           [1:0]    i_wb_addr;
        input           [31:0]   i_wb_data;
        input           [31:0]   i_wb_data;
        output  wire            o_wb_stall;
 
        output  reg             o_wb_ack;
        output  reg             o_wb_ack;
 
        output  wire            o_wb_stall;
        output  reg     [31:0]   o_wb_data;
        output  reg     [31:0]   o_wb_data;
        //
        //
        input                   i_uart_rx;
        input                   i_uart_rx;
        output  wire            o_uart_tx;
        output  wire            o_uart_tx;
 
        // RTS is used for hardware flow control.  According to Wikipedia, it
 
        // should probably be renamed RTR for "ready to receive".  It tell us
 
        // whether or not the receiving hardware is ready to accept another
 
        // byte.  If low, the transmitter will pause.
 
        //
 
        // If you don't wish to use hardware flow control, just set i_rts to
 
        // 1'b1 and let the optimizer simply remove this logic.
 
        input                   i_rts;
 
        // 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
 
        // use flow control.
 
        output  reg             o_cts;
        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;
 
 
        //
        //
        // The UART setup parameters: bits per byte, stop bits, parity, and
        // The UART setup parameters: bits per byte, stop bits, parity, and
        // baud rate are all captured within this uart_setup register.
        // baud rate are all captured within this uart_setup register.
        //
        //
        reg     [29:0]   uart_setup;
        reg     [30:0]   uart_setup;
        initial uart_setup = INITIAL_SETUP;
        initial uart_setup = INITIAL_SETUP;
        always @(posedge i_clk)
        always @(posedge i_clk)
                // Under wishbone rules, a write takes place any time i_wb_stb
                // Under wishbone rules, a write takes place any time i_wb_stb
                // is high.  If that's the case, and if the write was to the
                // is high.  If that's the case, and if the write was to the
                // setup address, then set us up for the new parameters.
                // setup address, then set us up for the new parameters.
                if ((i_wb_stb)&&(i_wb_addr == `UART_SETUP)&&(i_wb_we))
                if ((i_wb_stb)&&(i_wb_addr == `UART_SETUP)&&(i_wb_we))
                        uart_setup[29:0] <= i_wb_data[29:0];
                        uart_setup <= {
 
                                (i_wb_data[30])
 
                                        ||(!HARDWARE_FLOW_CONTROL_PRESENT),
 
                                i_wb_data[29:0] };
 
 
 
        /////////////////////////////////////////
 
        //
 
        //
 
        // First, the UART receiver
        //
        //
        // First the UART receiver
 
        //
        //
 
        /////////////////////////////////////////
 
 
        // First the wires/registers this receiver depends upon
        // First the wires/registers this receiver depends upon
        wire            rx_stb, rx_break, rx_perr, rx_ferr, ck_uart;
        wire            rx_stb, rx_break, rx_perr, rx_ferr, ck_uart;
        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), an 8-bit data out value
        // valid when stb is high, a break value (true during a break cond.),
        // valid when stb is high, a break value (true during a break cond.),
        // and parity/framing error flags--also valid when stb is true.
        // 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 data, what do we do
        // with it?
        // with it?
 
 
 
 
        // 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.
        wire            rx_empty_n, rx_fifo_err;
        wire            rx_empty_n, rx_fifo_err;
        wire    [7:0]    rxf_wb_data;
        wire    [7:0]    rxf_wb_data;
        wire    [15:0]   rxf_status;
        wire    [15:0]   rxf_status;
        reg             rxf_wb_read;
        reg             rxf_wb_read;
        //
        //
        // And here's the FIFO proper.
        // And here's the FIFO proper.
        //
        //
        // Note that the FIFO will be cleared upon any reset: either if there's
        // Note that the FIFO will be cleared upon any reset: either if there's
        // a UART break condition on the line, the receiver is in reset, or an
        // a UART break condition on the line, the receiver is in reset, or an
        // external reset is issued.
        // external reset is issued.
        //
        //
        // The FIFO accepts strobe and data from the receiver.
        // The FIFO accepts strobe and data from the receiver.
        // We issue another wire to it (rxf_wb_read), true when we wish to read
        // We issue another wire to it (rxf_wb_read), true when we wish to read
        // from the FIFO, and we get our data in rxf_wb_data.  The FIFO outputs
        // from the FIFO, and we get our data in rxf_wb_data.  The FIFO outputs
        // four status-type values: 1) is it non-empty, 2) is the FIFO over half
        // four status-type values: 1) is it non-empty, 2) is the FIFO over half
        // full, 3) a 16-bit status register, containing info regarding how full
        // full, 3) a 16-bit status register, containing info regarding how full
        // the FIFO truly is, and 4) an error indicator.
        // the FIFO truly is, and 4) an error indicator.
        ufifo   #(.LGFLEN(LGFLEN))
        ufifo   #(.LGFLEN(LCLLGFLEN), .RXFIFO(1))
                rxfifo(i_clk, (i_rst)||(rx_break)||(rx_uart_reset),
                rxfifo(i_clk, (i_rst)||(rx_break)||(rx_uart_reset),
                        rx_stb, rx_uart_data,
                        rx_stb, rx_uart_data,
 
                        rx_empty_n,
                        rxf_wb_read, rxf_wb_data,
                        rxf_wb_read, rxf_wb_data,
                        (rx_empty_n), (o_uart_rxfifo_int),
 
                        rxf_status, rx_fifo_err);
                        rxf_status, rx_fifo_err);
 
        assign  o_uart_rxfifo_int = rxf_status[1];
 
 
        // We produce four interrupts.  One of the receive interrupts indicates
        // We produce four interrupts.  One of the receive interrupts indicates
        // whether or not the receive FIFO is non-empty.  This should wake up
        // whether or not the receive FIFO is non-empty.  This should wake up
        // the CPU.
        // the CPU.
        assign  o_uart_rx_int = !rx_empty_n;
        assign  o_uart_rx_int = rxf_status[0];
 
 
 
        // The clear to send line, which may be ignored, but which we set here
 
        // 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
 
        // 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
 
        // 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)
 
                o_cts = (!HARDWARE_FLOW_CONTROL_PRESENT)
 
                        ||(rxf_status[(LCLLGFLEN+1):2] > check_cutoff);
 
 
        // 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.
        initial rxf_wb_read = 1'b0;
        initial rxf_wb_read = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                rxf_wb_read <= (i_wb_stb)&&(i_wb_addr[1:0]==`UART_RXREG)
                rxf_wb_read <= (i_wb_stb)&&(i_wb_addr[1:0]==`UART_RXREG)
                                &&(!i_wb_we);
                                &&(!i_wb_we);
 
 
        // Now, let's deal with those RX UART errors: both the parity and frame
        // Now, let's deal with those RX UART errors: both the parity and frame
        // errors.  As you may recall, these are valid only when rx_stb is
        // errors.  As you may recall, these are valid only when rx_stb is
        // valid, so we need to hold on to them until the user reads them via
        // valid, so we need to hold on to them until the user reads them via
        // a UART read request..
        // a UART read request..
        reg     r_rx_perr, r_rx_ferr;
        reg     r_rx_perr, r_rx_ferr;
        initial r_rx_perr = 1'b0;
        initial r_rx_perr = 1'b0;
        initial r_rx_ferr = 1'b0;
        initial r_rx_ferr = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if ((rx_uart_reset)||(rx_break))
                if ((rx_uart_reset)||(rx_break))
                begin
                begin
                        // Clear the error
                        // Clear the error
                        r_rx_perr <= 1'b0;
                        r_rx_perr <= 1'b0;
                        r_rx_ferr <= 1'b0;
                        r_rx_ferr <= 1'b0;
                end else if ((i_wb_stb)
                end else if ((i_wb_stb)
                                &&(i_wb_addr[1:0]==`UART_RXREG)&&(i_wb_we))
                                &&(i_wb_addr[1:0]==`UART_RXREG)&&(i_wb_we))
                begin
                begin
                        // Reset the error lines if a '1' is ever written to
                        // Reset the error lines if a '1' is ever written to
                        // them, otherwise leave them alone.
                        // them, otherwise leave them alone.
                        //
                        //
                        r_rx_perr <= (r_rx_perr)&&(~i_wb_data[9]);
                        r_rx_perr <= (r_rx_perr)&&(~i_wb_data[9]);
                        r_rx_ferr <= (r_rx_ferr)&&(~i_wb_data[10]);
                        r_rx_ferr <= (r_rx_ferr)&&(~i_wb_data[10]);
                end else if (rx_stb)
                end else if (rx_stb)
                begin
                begin
                        // On an rx_stb, capture any parity or framing error
                        // On an rx_stb, capture any parity or framing error
                        // indications.  These aren't kept with the data rcvd,
                        // indications.  These aren't kept with the data rcvd,
                        // but rather kept external to the FIFO.  As a result,
                        // but rather kept external to the FIFO.  As a result,
                        // if you get a parity or framing error, you will never
                        // if you get a parity or framing error, you will never
                        // know which data byte it was associated with.
                        // know which data byte it was associated with.
                        // For now ... that'll work.
                        // For now ... that'll work.
                        r_rx_perr <= (r_rx_perr)||(rx_perr);
                        r_rx_perr <= (r_rx_perr)||(rx_perr);
                        r_rx_ferr <= (r_rx_ferr)||(rx_ferr);
                        r_rx_ferr <= (r_rx_ferr)||(rx_ferr);
                end
                end
 
 
        initial rx_uart_reset = 1'b1;
        initial rx_uart_reset = 1'b1;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if ((i_rst)||((i_wb_stb)&&(i_wb_addr[1:0]==`UART_SETUP)&&(i_wb_we)))
                if ((i_rst)||((i_wb_stb)&&(i_wb_addr[1:0]==`UART_SETUP)&&(i_wb_we)))
                        // The receiver reset, always set on a master reset
                        // The receiver reset, always set on a master reset
                        // request.
                        // request.
                        rx_uart_reset <= 1'b1;
                        rx_uart_reset <= 1'b1;
                else if ((i_wb_stb)&&(i_wb_addr[1:0]==`UART_RXREG)&&(i_wb_we))
                else if ((i_wb_stb)&&(i_wb_addr[1:0]==`UART_RXREG)&&(i_wb_we))
                        // Writes to the receive register will command a receive
                        // Writes to the receive register will command a receive
                        // reset anytime bit[12] is set.
                        // reset anytime bit[12] is set.
                        rx_uart_reset <= i_wb_data[12];
                        rx_uart_reset <= i_wb_data[12];
                else
                else
                        rx_uart_reset <= 1'b0;
                        rx_uart_reset <= 1'b0;
 
 
        // Finally, we'll construct a 32-bit value from these various wires,
        // Finally, we'll construct a 32-bit value from these various wires,
        // to be returned over the bus on any read.  These include the data
        // to be returned over the bus on any read.  These include the data
        // that would be read from the FIFO, an error indicator set upon
        // that would be read from the FIFO, an error indicator set upon
        // reading from an empty FIFO, a break indicator, and the frame and
        // reading from an empty FIFO, a break indicator, and the frame and
        // parity error signals.
        // parity error signals.
        wire    [31:0]   wb_rx_data;
        wire    [31:0]   wb_rx_data;
        assign  wb_rx_data = { 16'h00,
        assign  wb_rx_data = { 16'h00,
                                3'h0, rx_fifo_err,
                                3'h0, rx_fifo_err,
                                rx_break, rx_ferr, r_rx_perr, !rx_empty_n,
                                rx_break, rx_ferr, r_rx_perr, !rx_empty_n,
                                rxf_wb_data};
                                rxf_wb_data};
 
 
 
        /////////////////////////////////////////
 
        //
        //
        //
        // Then the UART transmitter
        // Then the UART transmitter
        //
        //
        wire            tx_empty_n, txf_half_full, txf_err;
        //
 
        /////////////////////////////////////////
 
        wire            tx_empty_n, txf_err;
        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             r_tx_break, 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
        // into the FIFO.  In this case, we use the act of writing to the 
        // into the FIFO.  In this case, we use the act of writing to the 
        // UART_TXREG address as our indication that we wish to write to the 
        // UART_TXREG address as our indication that we wish to write to the 
        // FIFO.  Here, we create a write command line, and latch the data for
        // FIFO.  Here, we create a write command line, and latch the data for
        // the extra clock that it'll take so that the command and data can be
        // the extra clock that it'll take so that the command and data can be
        // both true on the same clock.
        // both true on the same clock.
        initial txf_wb_write = 1'b0;
        initial txf_wb_write = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
        begin
        begin
                txf_wb_write <= (i_wb_stb)&&(i_wb_addr == `UART_TXREG)
                txf_wb_write <= (i_wb_stb)&&(i_wb_addr == `UART_TXREG)
                                        &&(i_wb_we);
                                        &&(i_wb_we);
                txf_wb_data  <= i_wb_data[7:0];
                txf_wb_data  <= i_wb_data[7:0];
        end
        end
 
 
        // Transmit FIFO
        // Transmit FIFO
        //
        //
        // Most of this is just wire management.  The TX FIFO is identical in
        // Most of this is just wire management.  The TX FIFO is identical in
        // implementation to the RX FIFO (theyre both UFIFOs), but the TX
        // implementation to the RX FIFO (theyre both UFIFOs), but the TX
        // FIFO is fed from the WB and read by the transmitter.  Some key
        // FIFO is fed from the WB and read by the transmitter.  Some key
        // 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))
        ufifo   #(.LGFLEN(LGFLEN), .RXFIFO(0))
                txfifo(i_clk, (r_tx_break)||(tx_uart_reset),
                txfifo(i_clk, (r_tx_break)||(tx_uart_reset),
                        txf_wb_write, txf_wb_data,
                        txf_wb_write, txf_wb_data,
                                (~tx_busy)&&(tx_empty_n), tx_data,
                        tx_empty_n,
                        tx_empty_n, txf_half_full, txf_status, txf_err);
                        (!tx_busy)&&(tx_empty_n), tx_data,
 
                        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.
        //      The first will be true any time the FIFO is empty.
        //      The first will be true any time the FIFO has at least one open
        assign  o_uart_tx_int = !tx_empty_n;
        //      position within it.
 
        assign  o_uart_tx_int = txf_status[0];
        //      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_half_full;
        assign  o_uart_txfifo_int = txf_status[1];
 
 
        // 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.
        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];
 
 
        // 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
        // a reset cycle.  Keep bit [12] low, and everything will proceed as
        // a reset cycle.  Keep bit [12] low, and everything will proceed as
        // normal.
        // normal.
        initial tx_uart_reset = 1'b1;
        initial tx_uart_reset = 1'b1;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if((i_rst)||((i_wb_stb)&&(i_wb_addr == `UART_SETUP)&&(i_wb_we)))
                if((i_rst)||((i_wb_stb)&&(i_wb_addr == `UART_SETUP)&&(i_wb_we)))
                        tx_uart_reset <= 1'b1;
                        tx_uart_reset <= 1'b1;
                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;
 
        assign  rts = (!HARDWARE_FLOW_CONTROL_PRESENT)||(i_rts);
        // 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
        // here is that tx_empty_n wire--thus, if there's anything in the FIFO,
        // here is that tx_empty_n wire--thus, if there's anything in the FIFO,
        // 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,
                        o_uart_tx, tx_busy);
                        i_rts, o_uart_tx, tx_busy);
 
 
        // 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
        // there are no side effects.  (Reading from the receive port advances
        // there are no side effects.  (Reading from the receive port advances
        // the receive FIFO, here only writing to the transmit port advances the
        // the receive FIFO, here only writing to the transmit port advances the
        // transmit FIFO--hence the read values are free for ... whatever.)  
        // transmit FIFO--hence the read values are free for ... whatever.)  
        // We choose here to provide information about the transmit FIFO
        // We choose here to provide information about the transmit FIFO
        // (txf_err, txf_half_full, tx_empty_n), information about the current
        // (txf_err, txf_half_full, txf_full_n), information about the current
        // 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,
                                1'h0, txf_half_full, tx_empty_n, txf_err,
                                i_rts, txf_status[1:0], txf_err,
                                ck_uart, o_uart_tx, r_tx_break, tx_busy,
                                ck_uart, o_uart_tx, r_tx_break, (tx_busy|txf_status[0]),
                                txf_wb_data};
                                (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
        // can use when reading about the FIFO.
        // can use when reading about the FIFO.
        wire    [31:0]   wb_fifo_data;
        wire    [31:0]   wb_fifo_data;
        assign  wb_fifo_data = { txf_status, rxf_status };
        assign  wb_fifo_data = { txf_status, rxf_status };
 
 
        // You may recall from above that reads take two clocks.  Hence, we
        // You may recall from above that reads take two clocks.  Hence, we
        // need to delay the address decoding for a clock until the data is 
        // need to delay the address decoding for a clock until the data is 
        // ready.  We do that here.
        // ready.  We do that here.
        reg     [1:0]    r_wb_addr;
        reg     [1:0]    r_wb_addr;
        always @(posedge i_clk)
        always @(posedge i_clk)
                r_wb_addr <= i_wb_addr;
                r_wb_addr <= i_wb_addr;
 
 
        // Likewise, the acknowledgement is delayed by one clock.
        // Likewise, the acknowledgement is delayed by one clock.
        reg     r_wb_ack;
        reg     r_wb_ack;
        always @(posedge i_clk) // We'll ACK in two clocks
        always @(posedge i_clk) // We'll ACK in two clocks
                r_wb_ack <= i_wb_stb;
                r_wb_ack <= i_wb_stb;
        always @(posedge i_clk) // Okay, time to set the ACK
        always @(posedge i_clk) // Okay, time to set the ACK
                o_wb_ack <= r_wb_ack;
                o_wb_ack <= r_wb_ack;
 
 
        // Finally, set the return data.  This data must be valid on the same
        // Finally, set the return data.  This data must be valid on the same
        // clock o_wb_ack is high.  On all other clocks, it is irrelelant--since
        // clock o_wb_ack is high.  On all other clocks, it is irrelelant--since
        // no one cares, no one is reading it, it gets lost in the mux in the
        // no one cares, no one is reading it, it gets lost in the mux in the
        // interconnect, etc.  For this reason, we can just simplify our logic.
        // interconnect, etc.  For this reason, we can just simplify our logic.
        always @(posedge i_clk)
        always @(posedge i_clk)
                casez(r_wb_addr)
                casez(r_wb_addr)
                `UART_SETUP: o_wb_data <= { 2'b00, uart_setup };
                `UART_SETUP: o_wb_data <= { 1'b0, uart_setup };
                `UART_FIFO:  o_wb_data <= wb_fifo_data;
                `UART_FIFO:  o_wb_data <= wb_fifo_data;
                `UART_RXREG: o_wb_data <= wb_rx_data;
                `UART_RXREG: o_wb_data <= wb_rx_data;
                `UART_TXREG: o_wb_data <= wb_tx_data;
                `UART_TXREG: o_wb_data <= wb_tx_data;
                endcase
                endcase
 
 
        // This device never stalls.  Sure, it takes two clocks, but they are
        // This device never stalls.  Sure, it takes two clocks, but they are
        // pipelined, and nothing stalls that pipeline.  (Creates FIFO errors,
        // pipelined, and nothing stalls that pipeline.  (Creates FIFO errors,
        // perhaps, but doesn't stall the pipeline.)  Hence, we can just
        // perhaps, but doesn't stall the pipeline.)  Hence, we can just
        // set this value to zero.
        // set this value to zero.
        assign  o_wb_stall = 1'b0;
        assign  o_wb_stall = 1'b0;
 
 
endmodule
endmodule
 
 

powered by: WebSVN 2.1.0

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