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

Subversion Repositories socgen

[/] [socgen/] [trunk/] [common/] [opencores.org/] [Testbench/] [bfms/] [uart_model/] [rtl/] [verilog/] [serial_xmit] - Rev 133

Go to most recent revision | Compare with Previous | Blame | View Log

/**********************************************************************/
/*                                                                    */
/*             -------                                                */
/*            /   SOC  \                                              */
/*           /    GEN   \                                             */
/*          /     LIB    \                                            */
/*          ==============                                            */
/*          |            |                                            */
/*          |____________|                                            */
/*                                                                    */
/*  Generic model for a serial asynchronous transmitter               */
/*                                                                    */
/*  Author(s):                                                        */
/*      - John Eaton, jt_eaton@opencores.org                          */
/*                                                                    */
/**********************************************************************/
/*                                                                    */
/*    Copyright (C) <2010>  <Ouabache Design Works>                   */
/*                                                                    */
/*  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;      */
/*  either version 2.1 of the License, or (at your option) any        */
/*  later version.                                                    */
/*                                                                    */
/*  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.opencores.org/lgpl.shtml                          */
/*                                                                    */
/**********************************************************************/

module 
uart_model_serial_xmit
#(parameter   WIDTH=8,   // Number of data bits
  parameter   SIZE=4     // binary size of shift_cnt, must be able to hold  WIDTH + 4 states       
 )  


(
input  wire              clk,
input  wire              reset,
input  wire              edge_enable,                 // one pulse per bit time for data rate timing
input  wire              parity_enable,               // 0 = no parity bit sent, 1= parity bit sent
input  wire              two_stop_enable,             // 0 = 1 stop bit, 1 = 2 stop bits
input  wire  [1:0]       parity_type,                 // 00= odd,01=even,10=force a 0,11= force a 1
input  wire              load,                        // start transmiting data
input  wire              start_value,                 // value out at start bit time
input  wire              stop_value,                  // value out for stop bit also used for break
input  wire [WIDTH-1:0]  data,                        // data byte

output  reg              buffer_empty,                // ready for next byte
output  reg              ser_out                      // to pad_ring
                         );
   
reg [SIZE-1:0]           shift_cnt;
reg [WIDTH-1:0]          shift_buffer;
reg                      parity_calc;
reg                      delayed_edge_enable;


//
//   shift_cnt controls the serial bit out
//  
//   0           Start bit  
//   1-> WIDTH   Data bit lsb first
//   WIDTH+1     Parity bit if enabled
//   2^SIZE-2    Second stop bit if enabled
//   2^SIZE-1    Last stop bit and idle
 
always@(posedge clk)
  if(reset || buffer_empty)                                        shift_cnt   <= {SIZE{1'b1}};
  else
  if(!edge_enable)                                                 shift_cnt   <= shift_cnt;
  else
  if(( shift_cnt ==  {SIZE{1'b1}}  ) &&  ! buffer_empty )          shift_cnt   <= {SIZE{1'b0}};
  else
  if ( shift_cnt == WIDTH)               
    case({two_stop_enable,parity_enable})        
      (2'b00):                                                     shift_cnt   <= {SIZE{1'b1}};
      (2'b01):                                                     shift_cnt   <= shift_cnt + 1'b1;
      (2'b10):                                                     shift_cnt   <= {SIZE{1'b1}} - 1'b1;
      (2'b11):                                                     shift_cnt   <= shift_cnt + 1'b1;
    endcase // case ({two_stop_enable,parity_enable})
  else
  if ( shift_cnt == (WIDTH+1))               
    case( two_stop_enable)       
      (1'b0):                                                      shift_cnt   <= {SIZE{1'b1}};
      (1'b1):                                                      shift_cnt   <= {SIZE{1'b1}} - 1'b1;
    endcase
  else                                                             shift_cnt   <= shift_cnt + 1'b1;

//
//    
//   Clear buffer_empty upon load pulse
//   set it back at the start of the final stop pulse
//   if load happens BEFORE the next edge_enable then data transfer will have no pauses 
//   logic ensures that having load happen on a edge_enable will work
//   
   
always@(posedge clk)
   if(reset)                                                       delayed_edge_enable <= 1'b0;
   else                                                            delayed_edge_enable <= edge_enable && ! load;

   
always@(posedge clk)
if(reset)                                                          buffer_empty <= 1'b1;
else
if(load)                                                           buffer_empty <= 1'b0;
else
if((shift_cnt == {SIZE{1'b1}}) && delayed_edge_enable)    
                                                                   buffer_empty <= 1'b1;
else                                                               buffer_empty <= buffer_empty;





//
//
//   load shift_buffer during start_bit
//   shift down every bit
//   
//   
always@(posedge clk)
  if(reset)                                                        shift_buffer <= {WIDTH{1'b0}};
  else
  if(!edge_enable)                                                 shift_buffer <= shift_buffer;
  else
  if(shift_cnt == {SIZE{1'b0}})                                    shift_buffer <= data;
  else                                                             shift_buffer <= {1'b0,shift_buffer[WIDTH-1:1]};






//
//
//   calculate parity on the fly
//   seed reg with 0 for odd and 1 for even
//   force reg to 0 or 1 if needed  
//   
always@(posedge clk)
  if(reset)                                                        parity_calc <= 1'b0;
  else
  if(!edge_enable)                                                 parity_calc <= parity_calc;
  else
  if(parity_type[1] || (shift_cnt == {SIZE{1'b0}}))                parity_calc <= parity_type[0];
  else                                                             parity_calc <= parity_calc ^ shift_buffer[0];


//   send start_bit,data,parity and stop  based on shift_cnt
   

   always@(posedge clk)
     if(reset)                                                     ser_out <= stop_value;
     else
     if( shift_cnt == {SIZE{1'b0}} )                               ser_out <= start_value;
     else
     if( shift_cnt == {SIZE{1'b1}} )                               ser_out <= stop_value;
     else
     if( shift_cnt == ({SIZE{1'b1}}+1'b1) )                        ser_out <= stop_value;
     else
     if( shift_cnt == (WIDTH+1) )                                  ser_out <= parity_calc;
     else                                                          ser_out <= shift_buffer[0];
                
   
endmodule


Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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