////////////////////////////////////////////////////////////////////
//
// KS-10 Processor
//
// Brief
//   Double Buffered UART Transmitter
//
// Details
//
// Note
//
// File
//   uart_buftx.vhd
//
// Author
//   Rob Doyle - doyle (at) cox (dot) net
//
////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2009-2013 Rob Doyle
//
// This source file may be used and distributed without
// restriction provided that this copyright statement is not
// removed from the file and that any derivative work contains
// the original copyright notice and the associated disclaimer.
//
// This source file is free software; you can redistribute it
// and/or modify it under the terms of the GNU Lesser General
// Public License as published by the Free Software Foundation;
// version 2.1 of the License.
//
// This source is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU Lesser General Public License for more
// details.
//
// You should have received a copy of the GNU Lesser General
// Public License along with this source; if not, download it
// from http://www.gnu.org/licenses/lgpl.txt
//
////////////////////////////////////////////////////////////////////

module UART_BUFTX(clk, rst, clkBR, load, data, empty, txd);

   input        clk;                    // Clock
   input        rst;                    // Reset
   input        clkBR;                  // Clock Enable from BRG
   input  [7:0] data;                   // Transmitter Data
   input        load;                   // Load Transmitter
   output       empty;                  // Buffer is empty
   output       txd;                    // Transmitter Serial Data

   //
   // State machine states
   //

   parameter [0:1] stateEMPTY = 0,      // Empty
                   stateUART  = 1,      // Character in UART
                   stateBUF   = 2;      // Character buffered and in UART

   //
   // State machine
   //

   wire      txintr;
   reg [0:1] state;
   reg [0:7] txbuf;
   reg [0:7] txdata;

   always @(posedge clk or posedge rst)
     begin
        if (rst)
          begin
             txbuf  <= 0;
             txdata <= 0;
             state  <= stateEMPTY;
          end
        else
          case (state)
            stateEMPTY:
              begin
                 if (load)
                   begin
                      txdata <= data;
                      state  <= stateUART;
                   end
              end
            stateUART:
              begin
                 if (load & ~txintr)
                   begin
                      txbuf <= data;
                      state <= stateBUF;
                   end
                 if (txintr & ~load)
                   begin
                      txdata <= txbuf;
                      state  <= stateEMPTY;
                   end
                 if (txintr & load)
                   begin
                      txbuf  <= data;
                      txdata <= txbuf;
                      state  <= stateUART;
                   end
              end
            stateBUF:
              begin
                 if (txintr & ~load)
                   begin
                      state <= stateUART;
                   end
                 else if (txintr & load)
                   begin
                      txbuf  <= data;
                      txdata <= txbuf;
                      state  <= stateBUF;
                   end
              end
          endcase
     end

   //
   // Generate load signal
   //
   // Details
   //  The txload is delayed by a clock cycle so that the
   //  data can be buffered into txdata or txbuf.
   //

   reg txload;

   always @(posedge clk or posedge rst)
     begin
        if (rst)
          txload <= 0;
        else
          txload <= load;
     end

   //
   // Unbuffered Transmitter
   //

   UART_TX uUART_TX
     (.clk      (clk),
      .rst      (rst),
      .clkBR    (clkBR),
      .data     (txdata),
      .load     (txload),
      .intr     (txintr),
      .txd      (txd)
      );

   //
   // Status
   //

   assign empty = (state == stateEMPTY);

endmodule
