URL
https://opencores.org/ocsvn/uart16550/uart16550/trunk
Subversion Repositories uart16550
[/] [uart16550/] [tags/] [rel_4/] [bench/] [verilog/] [uart_device.v] - Rev 106
Compare with Previous | Blame | View Log
////////////////////////////////////////////////////////////////////// //// //// //// uart_device.v //// //// //// //// This file is part of the "uart16550" project //// //// http://www.opencores.org/projects/uart16550/ //// //// //// //// Author(s): //// //// - tadej@opencores.org (Tadej Markovic) //// //// - igorm@opencores.org (Igor Mohor) //// //// //// //// All additional information is avaliable in the README.txt //// //// file. //// //// //// //// //// ////////////////////////////////////////////////////////////////////// //// //// //// Copyright (C) 2000 - 2004 authors //// //// //// //// 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 //// //// //// ////////////////////////////////////////////////////////////////////// // // CVS Revision History // // $Log: not supported by cvs2svn $ // // `include "uart_testbench_defines.v" `include "timescale.v" module uart_device ( // UART signals stx_i, srx_o, // Modem signals rts_i, cts_o, dtr_i, dsr_o, ri_o, dcd_o ); // IN/OUT signals //############### // UART signals input stx_i; output srx_o; // Modem signals input rts_i; output cts_o; input dtr_i; output dsr_o; output ri_o; output dcd_o; // INTERNAL signals //################# // Clock generation signals //######################### // Operational and transmission clock signals reg rx_clk; // RX device clock with period T_clk_period (should be equal to wb_clk_period) reg tx_clk; // TX device clock with period (T_clk_period + T_clk_delay) reg tx_clk_divided; // divided TX device clock with period ((T_clk_period + T_clk_delay) * T_divisor * 16) // Clock enable signals reg rx_clk_en = 1'b1; reg tx_clk_en = 1'b1; reg tx_clk_divided_en = 1'b1; // Clock period variables real T_clk_period = 20; real T_clk_delay = 0; integer T_divisor = 5; // IN/OUT assignment signals //########################## // Modem signals wire rts; wire dtr; // UART receiver signals //###################### // RX packet control signals wire rx; reg [3:0] rx_length; reg rx_odd_parity; reg rx_even_parity; reg rx_stick1_parity; reg rx_stick0_parity; reg rx_parity_enabled; reg rx_stop_bit_1; reg rx_stop_bit_1_5; reg rx_stop_bit_2; // RX logic signals wire [3:0] rx_total_length; wire [5:0] rx_break_detection_length; reg rx_packet_end; reg rx_packet_end_q; reg rx_clk_cnt_en; reg [31:0] rx_clk_cnt; reg rx_sample_clock; integer rx_bit_index; integer rx_stop_bit_index; reg [7:0] rx_data; reg [1:0] rx_stop; reg rx_framing_error; reg rx_parity; reg rx_parity_error; reg rx_break_detected; reg rx_break_detected_q; reg [31:0] rx_break_cnt; // RX events event device_received_packet; event device_received_last_bit; event device_received_stop_bit; event device_detected_rx_break; // UART transmitter signals //######################### // TX packet control signals reg tx; reg [3:0] tx_length; reg tx_odd_parity; reg tx_even_parity; reg tx_stick1_parity; reg tx_stick0_parity; reg tx_parity_enabled; reg tx_parity_wrong; reg tx_framing_wrong; // TX logic signals reg [23:0] tx_glitch_num; reg start_tx_glitch_cnt; reg [31:0] tx_glitch_cnt; reg tx_glitch; reg tx_break_enable; reg [15:0] tx_break_num; reg start_tx_break_cnt; reg [31:0] tx_break_cnt; reg tx_break; // TX test signals reg [7:0] sent_data; reg tx_accept_next_framing_err; reg tx_framing_err; reg tx_framing_glitch_err; // TX events event device_sent_packet; event sent_packet_received; // Clock generation //################# // Example of TESTBENCH's task for setting UART clock period: // ---------------- // task set_uart_clk_period; // input [31:0] clk_period; // begin // //@(posedge testbench.uart_device.clk); // testbench.uart_device.T_clk_period = clk_period; // end // endtask // set_uart_clk_period // ---------------- // Example of TESTBENCH's task for setting UART clock rising edge // delayed for time_delay_i after WB clock rising edge: // ---------------- // task uart_clk_follows_wb_clk; // input [31:0] time_delay_i; // integer time_delay; // begin // time_delay = time_delay_i; // @(posedge testbench.uart_device.clk); // testbench.uart_device.clk_en = 1'b0; // @(posedge wb_clk); // #time_delay testbench.uart_device.clk = 1'b1; // testbench.uart_device.clk_en = 1'b1; // end // endtask // uart_clk_follows_wb_clk // ---------------- // rx_clk rising edge always@(posedge rx_clk) if (rx_clk_en) #(T_clk_period / 2) rx_clk = 1'b0; // rx_clk falling edge always@(negedge rx_clk) if (rx_clk_en) #(T_clk_period / 2) rx_clk = 1'b1; // tx_clk rising edge always@(posedge tx_clk) if (tx_clk_en) #((T_clk_period + T_clk_delay) / 2) tx_clk = 1'b0; // tx_clk falling edge always@(negedge tx_clk) if (tx_clk_en) #((T_clk_period + T_clk_delay) / 2) tx_clk = 1'b1; // tx_clk_divided rising edge always@(posedge tx_clk_divided) if (tx_clk_divided_en) #(((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor) tx_clk_divided = 1'b0; // tx_clk_divided falling edge always@(negedge tx_clk_divided) if (tx_clk_divided_en) #(((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor) tx_clk_divided = 1'b1; // Inital CLK values initial begin:device rx_clk = 1'b0; tx_clk = 1'b0; tx_clk_divided = 1'b0; end // IN/OUT assignments //################### // UART output assign srx_o = (tx ^ tx_glitch) & ~tx_break; // Modem output assign cts_o = 0; assign dsr_o = 0; assign ri_o = 0; assign dcd_o = 0; // UART input assign rx = stx_i; // Modem input assign rts = rts_i; assign dtr = dtr_i; // UART receiver //############## // Initial values for RX initial begin // Default LENGTH rx_length = 8; // Default PARITY rx_odd_parity = 1'b0; rx_even_parity = 1'b0; rx_stick1_parity = 1'b0; rx_stick0_parity = 1'b0; rx_parity_enabled = 1'b0; // Default STOP rx_stop_bit_1 = 1'b1; rx_stop_bit_1_5 = 1'b0; rx_stop_bit_2 = 1'b0; end // Total length of RX packet (for proper generation of the rx_packet_end signal): // data length + parity + 1 stop bit + second stop bit (when enabled) assign rx_total_length = rx_length + rx_parity_enabled + 1 + rx_stop_bit_2; // +1 is used because start bit was not included in rx_total_length. assign rx_break_detection_length = rx_total_length + 1; // Generating rx_clk_cnt_en signal. always@(posedge rx_clk) begin if (~rx_clk_cnt_en) begin wait (~rx); end rx_clk_cnt_en = 1; rx_packet_end = 0; wait (rx_packet_end); rx_clk_cnt_en = 0; wait (rx); // Must be high to continue, because of break condition end // Counter used in data reception always@(posedge rx_clk) begin if (rx_clk_cnt_en) begin if (rx_clk_cnt == (8 * T_divisor - 1) & rx) // False start bit detection rx_packet_end = 1; if (rx_clk_cnt_en) // Checking is still enabled after devisor clocks rx_clk_cnt <= #1 rx_clk_cnt + 1; else rx_clk_cnt <= #1 0; end else rx_clk_cnt <= #1 0; end // Delayed rx_packet_end signal always@(posedge rx_clk) rx_packet_end_q = rx_packet_end; // Generating sample clock and end of the frame (Received data is sampled with this clock) always@(posedge rx_clk) begin if (rx_clk_cnt == 8 * T_divisor - 1) rx_bit_index = 0; else if (rx_clk_cnt == (8 * T_divisor + 16 * T_divisor * (rx_bit_index + 1) - 1)) begin rx_sample_clock = 1; rx_bit_index = rx_bit_index + 1; if (rx_bit_index == rx_total_length) rx_packet_end = 1; end else rx_sample_clock = 0; end // Sampling data (received data) always@(posedge rx_clk) begin if (rx_sample_clock) begin if (rx_bit_index <= rx_length) // Sampling data begin rx_stop_bit_index <= 0; // Stop bit index reset at the beginning of the data stage // $display("\t\t\t\t\t\t\t(rx_bit_index = %0d) Reading data bits = %0x", rx_bit_index, rx); rx_data[rx_bit_index - 1] = rx; if (rx_bit_index == rx_length) -> device_received_last_bit; end else begin if (rx_bit_index == (rx_length + 1)) begin if (rx_parity_enabled) begin // $display("\t\t\t\t\t\t\t(rx_bit_index = %0d) Reading parity bits = %0x", rx_bit_index, rx); end else begin -> device_received_stop_bit; rx_stop[rx_stop_bit_index] = rx; rx_stop_bit_index <= rx_stop_bit_index + 1; end rx_parity = rx & rx_parity_enabled; end if (rx_bit_index >= (rx_length + 1 + rx_parity_enabled)) begin // $display("\t\t\t\t\t\t\t(rx_bit_index = %0d) Reading stop bits = %0x", rx_bit_index, rx); rx_stop[rx_stop_bit_index] = rx; rx_stop_bit_index <= rx_stop_bit_index + 1; end end end // Filling the rest of the data with 0 if (rx_length == 5) rx_data[7:5] = 0; if (rx_length == 6) rx_data[7:6] = 0; if (rx_length == 7) rx_data[7] = 0; // Framing error generation // When 1 or 1.5 stop bits are used, only first stop bit is checked rx_framing_error = (rx_stop_bit_1 | rx_stop_bit_1_5) ? ~rx_stop[0] : ~(&rx_stop[1:0]); // Parity error generation if (rx_odd_parity) rx_parity_error = ~(^{rx_data, rx_parity}); else if (rx_even_parity) rx_parity_error = ^{rx_data, rx_parity}; else if (rx_stick0_parity) rx_parity_error = rx_parity; else if (rx_stick1_parity) rx_parity_error = ~rx_parity; else rx_parity_error = 0; end // Break detection always@(posedge rx_clk) begin rx_break_detected_q <= rx_break_detected; if (rx) begin rx_break_cnt = 0; // Reseting counter rx_break_detected = 0; // Clearing break detected signal end else rx_break_cnt = rx_break_cnt + 1; if (rx_break_cnt == rx_break_detection_length * 16 * T_divisor) begin // $display("\n(%0t) Break_detected.", $time); rx_break_detected <= 1; -> device_detected_rx_break; end end // Writing received data always@(posedge rx_clk) begin if ((rx_packet_end & ~rx_packet_end_q) | (rx_break_detected & ~rx_break_detected_q)) begin wait (rx | rx_break_detected); // Waiting for "end of cycle detected" or "break to be activated" // rx_break_detected // rx_length // rx_parity_enabled // rx_odd_parity | rx_even_parity | rx_stick1_parity | rx_stick0_parity // rx_stop_bit_1 | rx_stop_bit_1_5 | rx_stop_bit_2 -> device_received_packet; end end // UART transmitter //################# // Initial values for TX initial begin // Default LENGTH tx_length = 8; // Default PARITY tx_odd_parity = 1'b0; tx_even_parity = 1'b0; tx_stick1_parity = 1'b0; tx_stick0_parity = 1'b0; tx_parity_enabled = 1'b0; // Default CORRECT PARITY tx_parity_wrong = 1'b0; // Default CORRECT FRAME tx_framing_wrong = 1'b0; tx_framing_err = 0; tx_framing_glitch_err = 0; // Default NO GLITCH tx_glitch_num = 24'h0; // Default NO BREAK tx_break_enable = 1'b0; tx_break_num = 16'h0; end // Counter for TX glitch generation always@(posedge tx_clk or posedge start_tx_glitch_cnt) begin if (start_tx_glitch_cnt) begin tx_glitch_cnt <= tx_glitch_cnt + 1; if (tx_glitch_cnt == ((tx_glitch_num - 1) * T_divisor)) tx_glitch = 1'b1; else if (tx_glitch_cnt == (tx_glitch_num * T_divisor)) begin tx_glitch = 1'b0; start_tx_glitch_cnt = 1'b0; end end else tx_glitch_cnt <= 0; end // Break setting & break counter always@(posedge tx_clk) begin if (tx_break_enable && (tx_break_cnt == (tx_break_num * T_divisor))) begin start_tx_break_cnt = 0; end else if (start_tx_break_cnt) begin tx_break_cnt = tx_break_cnt + 1; tx_break = 1; end else begin tx_break_cnt = 0; tx_break = 0; end end // Sending packets task send_packet; input tx_random_i; input [7:0] tx_data_i; input num_of_tx_data_i; reg [7:0] tx_data; reg tx_parity_xor; integer tx_bit_index; integer num_of_tx_data; reg last_tx_data; begin // SEVERE ERROR if (// WRONG combinations of parameters for testing ((T_clk_delay != 0) && (tx_parity_wrong || tx_framing_wrong)) || ((T_clk_delay != 0) && (tx_glitch_num != 0)) || ((T_clk_delay != 0) && (tx_break_enable)) || ((tx_parity_wrong || tx_framing_wrong) && (tx_glitch_num != 0)) || ((tx_parity_wrong || tx_framing_wrong) && (tx_break_enable)) || ((tx_glitch_num != 0) && (tx_break_enable)) || (tx_glitch_num > ((tx_length + 2'h2 + tx_parity_enabled) * 16 * T_divisor)) || // with STOP bit // (tx_glitch_num > ((tx_length + 2'h1 + tx_parity_enabled) * 16 * T_divisor)) || // without STOP bit // WRONG input parameters (num_of_tx_data_i == 0) || ((num_of_tx_data_i > 1) && tx_break_enable) ) begin `SEVERE_ERROR("WRONG combination of parameters for testing UART receiver"); end for (num_of_tx_data = 0; num_of_tx_data < num_of_tx_data_i; num_of_tx_data = (num_of_tx_data + 1'b1)) begin if (num_of_tx_data == (num_of_tx_data_i - 1'b1)) last_tx_data = 1'b1; else last_tx_data = 0; // TX data if (~tx_random_i) tx_data = tx_data_i; else tx_data = {$random}%256; // 0..255 // Sending start bit @(posedge tx_clk_divided); tx = 0; if (tx_glitch_num > 0) start_tx_glitch_cnt = 1; // enabling tx_glitch generation if (tx_break_enable) start_tx_break_cnt = 1; // Start counter that counts break tx_length // Wait for almost 1 bit #(((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor); // wait half period #((((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor) - 2); // wait 2 less than half period // Sending tx_data bits for (tx_bit_index = 0; tx_bit_index < tx_length; tx_bit_index = tx_bit_index + 1) begin @(posedge tx_clk_divided); tx = tx_data[tx_bit_index]; end // Wait for almost 1 bit #(((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor); // wait half period #((((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor) - 2); // wait 2 less than half period sent_data = tx_data; // Calculating parity if(tx_length == 5) begin tx_parity_xor = ^tx_data[4:0]; end else if(tx_length == 6) begin tx_parity_xor = ^tx_data[5:0]; end else if(tx_length == 7) begin tx_parity_xor = ^tx_data[6:0]; end else if(tx_length == 8) begin tx_parity_xor = ^tx_data[7:0]; end else $display("WRONG length of TX data packet"); // Sending parity bit if (tx_parity_enabled) begin @(posedge tx_clk_divided); if (tx_odd_parity) tx = tx_parity_wrong ^ (~tx_parity_xor); else if (tx_even_parity) tx = tx_parity_wrong ^ tx_parity_xor; else if (tx_stick1_parity) tx = tx_parity_wrong ^ 1; else if (tx_stick0_parity) tx = tx_parity_wrong ^ 0; // Wait for almost 1 bit #(((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor); // wait half period #((((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor) - 2); // wait 2 less than half period end // Sending stop bit if (~tx_framing_wrong || (tx_glitch_num != ((((tx_length + 2'h2 + tx_parity_enabled) * 2) - 1'b1) * 8 * T_divisor))) begin @(posedge tx_clk_divided); tx = 1; // Wait for almost 1 bit #(((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor); // wait half period #((((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor) - 2); // wait 2 less than half period -> device_sent_packet; @(sent_packet_received); end else if (~tx_framing_wrong || (tx_glitch_num == ((((tx_length + 2'h2 + tx_parity_enabled) * 2) - 1'b1) * 8 * T_divisor))) begin @(posedge tx_clk_divided); tx = 1; // Wait for 1 bit @(posedge tx_clk_divided); // this will be like 2. stop bit -> device_sent_packet; @(sent_packet_received); end else if (tx_framing_wrong && last_tx_data) begin @(posedge tx_clk_divided); // Wrong stop | start bit tx = 0; @(posedge tx_clk_divided); -> device_sent_packet; @(sent_packet_received); tx_framing_wrong = 0; // TX data tx = 1; tx_data = 8'hFF; // Sending tx_data bits for (tx_bit_index = 0; tx_bit_index < tx_length; tx_bit_index = tx_bit_index + 1) begin @(posedge tx_clk_divided); tx = tx_data[tx_bit_index]; end // Wait for almost 1 bit #(((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor); // wait half period #((((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor) - 2); // wait 2 less than half period sent_data = tx_data; // Calculating parity if(tx_length == 5) begin tx_parity_xor = ^tx_data[4:0]; end else if(tx_length == 6) begin tx_parity_xor = ^tx_data[5:0]; end else if(tx_length == 7) begin tx_parity_xor = ^tx_data[6:0]; end else if(tx_length == 8) begin tx_parity_xor = ^tx_data[7:0]; end else $display("WRONG length of TX data packet"); // Sending parity bit if (tx_parity_enabled) begin @(posedge tx_clk_divided); if (tx_odd_parity) tx = tx_parity_wrong ^ (~tx_parity_xor); else if (tx_even_parity) tx = tx_parity_wrong ^ tx_parity_xor; else if (tx_stick1_parity) tx = tx_parity_wrong ^ 1; else if (tx_stick0_parity) tx = tx_parity_wrong ^ 0; // Wait for almost 1 bit #(((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor); // wait half period #((((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor) - 2); // wait 2 less than half period end // Stop bit @(posedge tx_clk_divided); tx = 1; // Wait for almost 1 bit #(((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor); // wait half period #((((T_clk_period + T_clk_delay) / 2) * 16 * T_divisor) - 2); // wait 2 less than half period -> device_sent_packet; @(sent_packet_received); tx_framing_wrong = 1'b1; end else if (last_tx_data) begin @(posedge tx_clk_divided); -> device_sent_packet; @(sent_packet_received); end end end endtask // send_packet endmodule