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 131
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