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

Subversion Repositories wbuart32

[/] [wbuart32/] [trunk/] [rtl/] [txuart.v] - Diff between revs 5 and 6

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 5 Rev 6
Line 114... Line 114...
        output  reg             o_uart_tx;
        output  reg             o_uart_tx;
        output  wire            o_busy;
        output  wire            o_busy;
 
 
        wire    [27:0]   clocks_per_baud, break_condition;
        wire    [27:0]   clocks_per_baud, break_condition;
        wire    [1:0]    data_bits;
        wire    [1:0]    data_bits;
        wire            use_parity, parity_even, dblstop, fixd_parity;
        wire            use_parity, parity_even, dblstop, fixd_parity,
 
                        fixdp_value;
        reg     [29:0]   r_setup;
        reg     [29:0]   r_setup;
        assign  clocks_per_baud = { 4'h0, r_setup[23:0] };
        assign  clocks_per_baud = { 4'h0, r_setup[23:0] };
        assign  break_condition = { r_setup[23:0], 4'h0 };
        assign  break_condition = { r_setup[23:0], 4'h0 };
        assign  data_bits   = r_setup[29:28];
        assign  data_bits   = r_setup[29:28];
        assign  dblstop     = r_setup[27];
        assign  dblstop     = r_setup[27];
        assign  use_parity  = r_setup[26];
        assign  use_parity  = r_setup[26];
        assign  fixd_parity = r_setup[25];
        assign  fixd_parity = r_setup[25];
        assign  parity_even = r_setup[24];
        assign  parity_even = r_setup[24];
 
        assign  fixdp_value = r_setup[24];
 
 
        reg     [27:0]   baud_counter;
        reg     [27:0]   baud_counter;
        reg     [3:0]    state;
        reg     [3:0]    state;
        reg     [7:0]    lcl_data;
        reg     [7:0]    lcl_data;
        reg             calc_parity, r_busy, zero_baud_counter;
        reg             calc_parity, r_busy, zero_baud_counter;
 
 
        initial r_setup = INITIAL_SETUP;
 
        initial o_uart_tx = 1'b1;
        initial o_uart_tx = 1'b1;
        initial r_busy = 1'b1;
        initial r_busy = 1'b1;
        initial state  = `TXU_IDLE;
        initial state  = `TXU_IDLE;
        initial lcl_data= 8'h0;
        initial lcl_data= 8'h0;
        initial calc_parity = 1'b0;
        initial calc_parity = 1'b0;
        // initial      baud_counter = clocks_per_baud;//ILLEGAL--not constant
        // initial      baud_counter = clocks_per_baud;//ILLEGAL--not constant
        always @(posedge i_clk)
        always @(posedge i_clk)
        begin
        begin
                if (i_reset)
                if (i_reset)
                begin
                begin
                        o_uart_tx <= 1'b1;
 
                        r_busy <= 1'b1;
                        r_busy <= 1'b1;
                        state <= `TXU_IDLE;
                        state <= `TXU_IDLE;
                        lcl_data <= 8'h0;
 
                        calc_parity <= 1'b0;
 
                end else if (i_break)
                end else if (i_break)
                begin
                begin
                        o_uart_tx <= 1'b0;
 
                        state <= `TXU_BREAK;
                        state <= `TXU_BREAK;
                        calc_parity <= 1'b0;
 
                        r_busy <= 1'b1;
                        r_busy <= 1'b1;
                end else if (~zero_baud_counter)
                end else if (!zero_baud_counter)
                begin // r_busy needs to be set coming into here
                begin // r_busy needs to be set coming into here
                        r_busy <= 1'b1;
                        r_busy <= 1'b1;
                end else if (state == `TXU_BREAK)
                end else if (state == `TXU_BREAK)
                begin
                begin
                        state <= `TXU_IDLE;
                        state <= `TXU_IDLE;
                        r_busy <= 1'b1;
                        r_busy <= 1'b1;
                        o_uart_tx <= 1'b1;
 
                        calc_parity <= 1'b0;
 
                end else if (state == `TXU_IDLE)        // STATE_IDLE
                end else if (state == `TXU_IDLE)        // STATE_IDLE
                begin
                begin
                        // baud_counter <= 0;
                        if ((i_wr)&&(!r_busy))
                        r_setup <= i_setup;
 
                        calc_parity <= 1'b0;
 
                        if ((i_wr)&&(~r_busy))
 
                        begin   // Immediately start us off with a start bit
                        begin   // Immediately start us off with a start bit
                                o_uart_tx <= 1'b0;
 
                                r_busy <= 1'b1;
                                r_busy <= 1'b1;
                                case(data_bits)
                                case(data_bits)
                                2'b00: state <= `TXU_BIT_ZERO;
                                2'b00: state <= `TXU_BIT_ZERO;
                                2'b01: state <= `TXU_BIT_ONE;
                                2'b01: state <= `TXU_BIT_ONE;
                                2'b10: state <= `TXU_BIT_TWO;
                                2'b10: state <= `TXU_BIT_TWO;
                                2'b11: state <= `TXU_BIT_THREE;
                                2'b11: state <= `TXU_BIT_THREE;
                                endcase
                                endcase
                                lcl_data <= i_data;
 
                                // baud_counter <= clocks_per_baud-28'h01;
 
                        end else begin // Stay in idle
                        end else begin // Stay in idle
                                o_uart_tx <= 1'b1;
 
                                r_busy <= 0;
                                r_busy <= 0;
                                // lcl_data is irrelevant
 
                                // state <= state;
 
                        end
                        end
                end else begin
                end else begin
                        // One clock tick in each of these states ...
                        // One clock tick in each of these states ...
                        // baud_counter <= clocks_per_baud - 28'h01;
                        // baud_counter <= clocks_per_baud - 28'h01;
                        r_busy <= 1'b1;
                        r_busy <= 1'b1;
                        if (state[3] == 0) // First 8 bits
                        if (state[3] == 0) // First 8 bits
                        begin
                        begin
                                o_uart_tx <= lcl_data[0];
 
                                calc_parity <= calc_parity ^ lcl_data[0];
 
                                if (state == `TXU_BIT_SEVEN)
                                if (state == `TXU_BIT_SEVEN)
                                        state <= (use_parity)?`TXU_PARITY:`TXU_STOP;
                                        state <= (use_parity)?`TXU_PARITY:`TXU_STOP;
                                else
                                else
                                        state <= state + 1;
                                        state <= state + 1;
                                lcl_data <= { 1'b0, lcl_data[7:1] };
 
                        end else if (state == `TXU_PARITY)
                        end else if (state == `TXU_PARITY)
                        begin
                        begin
                                state <= `TXU_STOP;
                                state <= `TXU_STOP;
                                if (fixd_parity)
 
                                        o_uart_tx <= parity_even;
 
                                else
 
                                        o_uart_tx <= calc_parity^((parity_even)? 1'b1:1'b0);
 
                        end else if (state == `TXU_STOP)
                        end else if (state == `TXU_STOP)
                        begin // two stop bit(s)
                        begin // two stop bit(s)
                                o_uart_tx <= 1'b1;
 
                                if (dblstop)
                                if (dblstop)
                                        state <= `TXU_SECOND_STOP;
                                        state <= `TXU_SECOND_STOP;
                                else
                                else
                                        state <= `TXU_IDLE;
                                        state <= `TXU_IDLE;
                                calc_parity <= 1'b0;
 
                        end else // `TXU_SECOND_STOP and default:
                        end else // `TXU_SECOND_STOP and default:
                        begin
                        begin
                                state <= `TXU_IDLE; // Go back to idle
                                state <= `TXU_IDLE; // Go back to idle
                                o_uart_tx <= 1'b1;
 
                                // Still r_busy, since we need to wait
                                // Still r_busy, since we need to wait
                                // for the baud clock to finish counting
                                // for the baud clock to finish counting
                                // out this last bit.
                                // out this last bit.
                        end
                        end
                end
                end
        end
        end
 
 
 
        // o_busy
 
        //
 
        // This is a wire, designed to be true is we are ever busy above.
 
        // originally, this was going to be true if we were ever not in the
 
        // idle state.  The logic has since become more complex, hence we have
 
        // a register dedicated to this and just copy out that registers value.
        assign  o_busy = (r_busy);
        assign  o_busy = (r_busy);
 
 
 
 
 
        // r_setup
 
        //
 
        // Our setup register.  Accept changes between any pair of transmitted
 
        // words.  The register itself has many fields to it.  These are
 
        // broken out up top, and indicate what 1) our baud rate is, 2) our
 
        // number of stop bits, 3) what type of parity we are using, and 4)
 
        // the size of our data word.
 
        initial r_setup = INITIAL_SETUP;
 
        always @(posedge i_clk)
 
                if (state == `TXU_IDLE)
 
                        r_setup <= i_setup;
 
 
 
        // lcl_data
 
        //
 
        // This is our working copy of the i_data register which we use
 
        // when transmitting.  It is only of interest during transmit, and is
 
        // allowed to be whatever at any other time.  Hence, if r_busy isn't
 
        // true, we can always set it.  On the one clock where r_busy isn't
 
        // true and i_wr is, we set it and r_busy is true thereafter.
 
        // Then, on any zero_baud_counter (i.e. change between baud intervals)
 
        // we simple logically shift the register right to grab the next bit.
 
        always @(posedge i_clk)
 
                if (!r_busy)
 
                        lcl_data <= i_data;
 
                else if (zero_baud_counter)
 
                        lcl_data <= { 1'b0, lcl_data[7:1] };
 
 
 
        // o_uart_tx
 
        //
 
        // This is the final result/output desired of this core.  It's all
 
        // centered about o_uart_tx.  This is what finally needs to follow
 
        // the UART protocol.
 
        //
 
        // Ok, that said, our rules are:
 
        //      1'b0 on any break condition
 
        //      1'b0 on a start bit (IDLE, write, and not busy)
 
        //      lcl_data[0] during any data transfer, but only at the baud
 
        //              change
 
        //      PARITY -- During the parity bit.  This depends upon whether or
 
        //              not the parity bit is fixed, then what it's fixed to,
 
        //              or changing, and hence what it's calculated value is.
 
        //      1'b1 at all other times (stop bits, idle, etc)
 
        always @(posedge i_clk)
 
                if (i_reset)
 
                        o_uart_tx <= 1'b1;
 
                else if ((i_break)||((i_wr)&&(!r_busy)))
 
                        o_uart_tx <= 1'b0;
 
                else if (zero_baud_counter)
 
                        casez(state)
 
                        4'b0???:        o_uart_tx <= lcl_data[0];
 
                        `TXU_PARITY:    o_uart_tx <= calc_parity;
 
                        default:        o_uart_tx <= 1'b1;
 
                        endcase
 
 
 
 
 
        // calc_parity
 
        //
 
        // Calculate the parity to be placed into the parity bit.  If the
 
        // parity is fixed, then the parity bit is given by the fixed parity
 
        // value (r_setup[24]).  Otherwise the parity is given by the GF2
 
        // sum of all the data bits (plus one for even parity).
 
        always @(posedge i_clk)
 
                if (fixd_parity)
 
                        calc_parity <= fixdp_value;
 
                else if (zero_baud_counter)
 
                begin
 
                        if (state[3] == 0) // First 8 bits of msg
 
                                calc_parity <= calc_parity ^ lcl_data[0];
 
                        else
 
                                calc_parity <= parity_even;
 
                end else if (!r_busy)
 
                        calc_parity <= parity_even;
 
 
 
 
 
        // All of the above logic is driven by the baud counter.  Bits must last
 
        // clocks_per_baud in length, and this baud counter is what we use to
 
        // make certain of that.
 
        //
 
        // The basic logic is this: at the beginning of a bit interval, start
 
        // the baud counter and set it to count clocks_per_baud.  When it gets
 
        // to zero, restart it.
 
        //
 
        // However, comparing a 28'bit number to zero can be rather complex--
 
        // especially if we wish to do anything else on that same clock.  For
 
        // that reason, we create "zero_baud_counter".  zero_baud_counter is
 
        // nothing more than a flag that is true anytime baud_counter is zero.
 
        // It's true when the logic (above) needs to step to the next bit.
 
        // Simple enough?
 
        //
 
        // I wish we could stop there, but there are some other (ugly)
 
        // conditions to deal with that offer exceptions to this basic logic.
 
        //
 
        // 1. When the user has commanded a BREAK across the line, we need to
 
        // wait several baud intervals following the break before we start
 
        // transmitting, to give any receiver a chance to recognize that we are
 
        // out of the break condition, and to know that the next bit will be
 
        // a stop bit.
 
        //
 
        // 2. A reset is similar to a break condition--on both we wait several
 
        // baud intervals before allowing a start bit.
 
        //
 
        // 3. In the idle state, we stop our counter--so that upon a request
 
        // to transmit when idle we can start transmitting immediately, rather
 
        // than waiting for the end of the next (fictitious and arbitrary) baud
 
        // interval.
 
        //
 
        // When (i_wr)&&(!r_busy)&&(state == `TXU_IDLE) then we're not only in
 
        // the idle state, but we also just accepted a command to start writing
 
        // the next word.  At this point, the baud counter needs to be reset
 
        // to the number of clocks per baud, and zero_baud_counter set to zero.
 
        //
 
        // The logic is a bit twisted here, in that it will only check for the
 
        // above condition when zero_baud_counter is false--so as to make
 
        // certain the STOP bit is complete.
        initial zero_baud_counter = 1'b0;
        initial zero_baud_counter = 1'b0;
        initial baud_counter = 28'h05;
        initial baud_counter = 28'h05;
        always @(posedge i_clk)
        always @(posedge i_clk)
        begin
        begin
                zero_baud_counter <= (baud_counter == 28'h01);
                zero_baud_counter <= (baud_counter == 28'h01);
                if ((i_reset)||(i_break))
                if ((i_reset)||(i_break))
                begin
                begin
                        // Give ourselves 16 bauds before being ready
                        // Give ourselves 16 bauds before being ready
                        baud_counter <= break_condition;
                        baud_counter <= break_condition;
                        zero_baud_counter <= 1'b0;
                        zero_baud_counter <= 1'b0;
                end else if (~zero_baud_counter)
                end else if (!zero_baud_counter)
                        baud_counter <= baud_counter - 28'h01;
                        baud_counter <= baud_counter - 28'h01;
                else if (state == `TXU_BREAK)
                else if (state == `TXU_BREAK)
                        // Give us two stop bits before becoming available
                        // Give us four idle baud intervals before becoming
 
                        // available
                        baud_counter <= clocks_per_baud<<2;
                        baud_counter <= clocks_per_baud<<2;
                else if (state == `TXU_IDLE)
                else if (state == `TXU_IDLE)
                begin
                begin
                        if((i_wr)&&(~r_busy))
                        baud_counter <= 28'h0;
                                baud_counter <= clocks_per_baud - 28'h01;
 
                        else
 
                                zero_baud_counter <= 1'b1;
                                zero_baud_counter <= 1'b1;
 
                        if ((i_wr)&&(!r_busy))
 
                        begin
 
                                baud_counter <= clocks_per_baud - 28'h01;
 
                                zero_baud_counter <= 1'b0;
 
                        end
                end else
                end else
                        baud_counter <= clocks_per_baud - 28'h01;
                        baud_counter <= clocks_per_baud - 28'h01;
        end
        end
endmodule
endmodule
 
 

powered by: WebSVN 2.1.0

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