aboutsummaryrefslogblamecommitdiff
path: root/src/rtl/uart.v
blob: 40a3f69c32f0aee617ddf1eee5cd6064283d67c9 (plain) (tree)



















                                                                        
                            
















































                                                                        
                                         












                                                                    



                                      
 



                                      





                                                   
                                                            

                                                      
                            
                                    
                                         
                                     
                                     




                                                                    


                            
 







                             






                                                                    

                         
  


                              
 


                              
 

                              































                                                                    


                                           



























                                                                    


                                             


             













                                              













                                                                    





                               








                                   
















                                                      






























                                                 














                                                                 













                                                                        
//======================================================================
//
// uart.v
// ------
// Top level wrapper for the uart core.
//
// A simple universal asynchronous receiver/transmitter (UART)
// interface. The interface contains 16 byte wide transmit and 
// receivea buffers and can handle start and stop bits. But in 
// general is rather simple. The primary purpose is as host 
// interface for the coretest design. The core also has a
// loopback mode to allow testing of a serial link.
//
// Note that the UART has a separate API interface to allow
// a control core to change settings such as speed. But the core
// has default values to allow it to start operating directly
// after reset. No config should be needed.
//
//
// Author: Joachim Strombergson
// Copyright (c) 2014, SUNET
// 
// Redistribution and use in source and binary forms, with or 
// without modification, are permitted provided that the following 
// conditions are met: 
// 
// 1. Redistributions of source code must retain the above copyright 
//    notice, this list of conditions and the following disclaimer. 
// 
// 2. Redistributions in binary form must reproduce the above copyright 
//    notice, this list of conditions and the following disclaimer in 
//    the documentation and/or other materials provided with the 
//    distribution. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
// 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 OF THIS SOFTWARE, EVEN IF 
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//======================================================================

module uart(
            input wire           clk,
            input wire           reset_n,

            // External interface.
            input wire           rxd,
            output wire          txd,

            // Internal receive interface.
            output wire          rxd_syn,
            output [7 : 0]       rxd_data,
            input wire           rxd_ack,

            // Internal transmit interface.
            input wire           txd_syn,
            input wire [7 : 0]   txd_data,
            output wire          txd_ack,
            
            // API interface.
            input wire           cs,
            input wire           we,
            input wire [7 : 0]   address,
            input wire [31 : 0]  write_data,
            output wire [31 : 0] read_data,
            output wire          error,

            // Debug output.
            output wire [7 : 0]  debug
           );

  
  //----------------------------------------------------------------
  // Internal constant and parameter definitions.
  //----------------------------------------------------------------
  // API addresses.
  parameter ADDR_CORE_NAME0   = 8'h00;
  parameter ADDR_CORE_NAME1   = 8'h01;
  parameter ADDR_CORE_TYPE    = 8'h02;
  parameter ADDR_CORE_VERSION = 8'h03;

  parameter ADDR_BIT_RATE     = 8'h10;
  parameter ADDR_DATA_BITS    = 8'h11;
  parameter ADDR_STOP_BITS    = 8'h12;
  
  // Core ID constants.
  parameter CORE_NAME0   = 32'h75617274;  // "uart"
  parameter CORE_NAME1   = 32'h20202020;  // "    "
  parameter CORE_TYPE    = 32'h20202031;  // "   1"
  parameter CORE_VERSION = 32'h302e3031;  // "0.01"

  // The default bit rate is based on target clock frequency
  // divided by the bit rate times in order to hit the
  // center of the bits. I.e.
  // Clock: 50 MHz, 9600 bps
  // Divisor = 50*10E6 / 9600 = 5208
  parameter DEFAULT_BIT_RATE  = 16'd5208;
  parameter DEFAULT_DATA_BITS = 4'h8;
  parameter DEFAULT_STOP_BITS = 2'h1;
 
  
  //----------------------------------------------------------------
  // Registers including update variables and write enable.
  //----------------------------------------------------------------
  reg [15 : 0] bit_rate_reg;
  reg [15 : 0] bit_rate_new;
  reg          bit_rate_we;

  reg [3 : 0]  data_bits_reg;
  reg [3 : 0]  data_bits_new;
  reg          data_bits_we;

  reg [1 : 0]  stop_bits_reg;
  reg [1 : 0]  stop_bits_new;
  reg          stop_bits_we;
  
  
  //----------------------------------------------------------------
  // Wires.
  //----------------------------------------------------------------
  wire [15 : 0] bit_rate;
  wire [1 : 0]  stop_bits;

  wire          core_rxd;
  wire          core_txd;
  
  wire          core_rxd_syn;
  wire [7 : 0]  core_rxd_data;
  wire          core_rxd_ack;

  wire          core_txd_syn;
  wire [7 : 0]  core_txd_data;
  wire          core_txd_ack;

  reg [31 : 0]  tmp_read_data;
  reg           tmp_error;

  
  //----------------------------------------------------------------
  // Concurrent connectivity for ports etc.
  //----------------------------------------------------------------
  assign txd           = core_txd;
  assign core_rxd      = rxd;

  assign rxd_syn       = core_rxd_syn;
  assign rxd_data      = core_rxd_data;
  assign core_rxd_ack  = rxd_ack;
  
  assign core_txd_syn  = txd_syn;
  assign core_txd_data = txd_data;
  assign txd_ack       = core_txd_ack;
  
  assign read_data     = tmp_read_data;
  assign error         = tmp_error;

  assign debug         = core_rxd_data;
  

  //----------------------------------------------------------------
  // core
  //
  // Instantiation of the uart core.
  //----------------------------------------------------------------
  uart_core core(
                 .clk(clk),
                 .reset_n(reset_n),

                 // Configuration parameters
                 .bit_rate(bit_rate_reg),
                 .data_bits(data_bits_reg),
                 .stop_bits(stop_bits_reg),
                 
                 // External data interface
                 .rxd(core_rxd),
                 .txd(core_txd),

                 // Internal receive interface.
                 .rxd_syn(core_rxd_syn),
                 .rxd_data(core_rxd_data),
                 .rxd_ack(core_rxd_ack),
                 
                 // Internal transmit interface.
                 .txd_syn(core_txd_syn),
                 .txd_data(core_txd_data),
                 .txd_ack(core_txd_ack)
                );

  
  //----------------------------------------------------------------
  // reg_update
  //
  // Update functionality for all registers in the core.
  // All registers are positive edge triggered with synchronous
  // active low reset. All registers have write enable.
  //----------------------------------------------------------------
  always @ (posedge clk)
    begin: reg_update
      if (!reset_n)
        begin
          bit_rate_reg  <= DEFAULT_BIT_RATE;
          data_bits_reg <= DEFAULT_DATA_BITS;
          stop_bits_reg <= DEFAULT_STOP_BITS;
        end
      else
        begin
          if (bit_rate_we)
            begin
              bit_rate_reg  <= bit_rate_new;
            end
          
          if (data_bits_we)
            begin
              data_bits_reg  <= data_bits_new;
            end
          
          if (stop_bits_we)
            begin
              stop_bits_reg  <= stop_bits_new;
            end

        end
    end // reg_update

  
  //----------------------------------------------------------------
  // api
  //
  // The core API that allows an internal host to control the
  // core functionality.
  //----------------------------------------------------------------
  always @*
    begin: api
      // Default assignments.
      bit_rate_new  = 16'h0000;
      bit_rate_we   = 0;
      data_bits_new = 4'h0;
      data_bits_we  = 0;
      stop_bits_new = 2'b00;
      stop_bits_we  = 0;
      tmp_read_data = 32'h00000000;
      tmp_error     = 0;
      
      if (cs)
        begin
          if (we)
            begin
              // Write operations.
              case (address)
                ADDR_BIT_RATE:
                  begin
                    bit_rate_new = write_data[15 : 0];
                    bit_rate_we  = 1;
                  end

                ADDR_DATA_BITS:
                  begin
                    data_bits_new = write_data[3 : 0];
                    data_bits_we  = 1;
                  end

                ADDR_STOP_BITS:
                  begin
                    stop_bits_new = write_data[1 : 0];
                    stop_bits_we  = 1;
                  end
                
                default:
                  begin
                    tmp_error = 1;
                  end
              endcase // case (address)
            end
          else
            begin
              // Read operations.
              case (address)
                ADDR_CORE_NAME0:
                  begin
                    tmp_read_data = CORE_NAME0;
                  end

                ADDR_CORE_NAME1:
                  begin
                    tmp_read_data = CORE_NAME1;
                  end

                ADDR_CORE_TYPE:
                  begin
                    tmp_read_data = CORE_TYPE;
                  end

                ADDR_CORE_VERSION:
                  begin
                    tmp_read_data = CORE_VERSION;
                  end
                
                ADDR_BIT_RATE:
                  begin
                    tmp_read_data = {16'h0000, bit_rate_reg};
                  end

                ADDR_DATA_BITS:
                  begin
                    tmp_read_data = {28'h0000000, data_bits_reg};
                  end

                ADDR_STOP_BITS:
                  begin
                    tmp_read_data = {30'h0000000, stop_bits_reg};
                  end
                
                default:
                  begin
                    tmp_error = 1;
                  end
              endcase // case (address)
            end
        end
    end
  
endmodule // uart

//======================================================================
// EOF uart.v
//======================================================================