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 *//* *//**********************************************************************/moduleuart_model_serial_xmit#(parameter WIDTH=8, // Number of data bitsparameter 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 timinginput wire parity_enable, // 0 = no parity bit sent, 1= parity bit sentinput wire two_stop_enable, // 0 = 1 stop bit, 1 = 2 stop bitsinput wire [1:0] parity_type, // 00= odd,01=even,10=force a 0,11= force a 1input wire load, // start transmiting datainput wire start_value, // value out at start bit timeinput wire stop_value, // value out for stop bit also used for breakinput wire [WIDTH-1:0] data, // data byteoutput reg buffer_empty, // ready for next byteoutput 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 idlealways@(posedge clk)if(reset || buffer_empty) shift_cnt <= {SIZE{1'b1}};elseif(!edge_enable) shift_cnt <= shift_cnt;elseif(( shift_cnt == {SIZE{1'b1}} ) && ! buffer_empty ) shift_cnt <= {SIZE{1'b0}};elseif ( 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})elseif ( shift_cnt == (WIDTH+1))case( two_stop_enable)(1'b0): shift_cnt <= {SIZE{1'b1}};(1'b1): shift_cnt <= {SIZE{1'b1}} - 1'b1;endcaseelse 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;elseif(load) buffer_empty <= 1'b0;elseif((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}};elseif(!edge_enable) shift_buffer <= shift_buffer;elseif(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;elseif(!edge_enable) parity_calc <= parity_calc;elseif(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_cntalways@(posedge clk)if(reset) ser_out <= stop_value;elseif( shift_cnt == {SIZE{1'b0}} ) ser_out <= start_value;elseif( shift_cnt == {SIZE{1'b1}} ) ser_out <= stop_value;elseif( shift_cnt == ({SIZE{1'b1}}+1'b1) ) ser_out <= stop_value;elseif( shift_cnt == (WIDTH+1) ) ser_out <= parity_calc;else ser_out <= shift_buffer[0];endmodule
