URL
https://opencores.org/ocsvn/uart16550/uart16550/trunk
Subversion Repositories uart16550
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 71 to Rev 72
- ↔ Reverse comparison
Rev 71 → Rev 72
/trunk/bench/verilog/vapi.log
0,0 → 1,114
////////////////////////////////////////////////////////////////////// |
//// //// |
//// vapi.log //// |
//// //// |
//// //// |
//// This file is part of the "UART 16550 compatible" project //// |
//// http://www.opencores.org/projects/uart16550/ //// |
//// //// |
//// Documentation related to this project: //// |
//// http://www.opencores.org/projects/uart16550/ //// |
//// //// |
//// Projects compatibility: //// |
//// - WISHBONE //// |
//// RS232 Protocol //// |
//// 16550D uart (mostly supported) //// |
//// //// |
//// Overview (main Features): //// |
//// Device interface for testing purposes //// |
//// //// |
//// Known problems (limits): //// |
//// //// |
//// To Do: //// |
//// Nothing. //// |
//// //// |
//// Author(s): //// |
//// - Igor Mohor (igorm@opencores.org) //// |
//// //// |
//// Created and updated: (See log for the revision history) //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2001 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 $ |
// |
// |
// |
// |
|
|
001000020 // devisor 0x32 |
002000300 // rx lcr 8n1 |
|
// Receive |
10000034a // Receive J |
100000361 // Receive a |
100000363 // Receive c |
10000030a // Receive \n |
|
// Send |
000000371 // Transmit q - switching to interrupt mode |
100000353 // Receive S |
100000377 // Receive w |
10000030a // Receive \n |
006000020 // wait 32 tx cycles |
000000331 // Transmit 1 |
000000332 // Transmit 2 |
000000333 // Transmit 3 |
000000334 // Transmit 4 |
000000335 // Transmit 5 |
000000336 // Transmit 6 |
000000337 // Transmit 7 |
000000338 // Transmit 8 |
000000339 // Transmit 9 |
000000361 // Transmit a |
000000362 // Transmit b |
000000363 // Transmit c |
000000364 // Transmit d |
000000365 // Transmit e |
000000366 // Transmit f |
006000040 // wait 64 tx cycles |
100000331 // Receive 1 |
100000332 // Receive 2 |
100000333 // Receive 3 |
100000334 // Receive 4 |
100000335 // Receive 5 |
100000336 // Receive 6 |
100000337 // Receive 7 |
100000338 // Receive 8 |
100000339 // Receive 9 |
100000341 // Receive A |
100000342 // Receive B |
100000343 // Receive C |
100000344 // Receive D |
100000345 // Receive E |
100000346 // Receive F |
|
200000000 // Exit simulation |
/trunk/bench/verilog/uart_device_if_memory.v
0,0 → 1,90
////////////////////////////////////////////////////////////////////// |
//// //// |
//// uart_device_if_memory.v //// |
//// //// |
//// //// |
//// This file is part of the "UART 16550 compatible" project //// |
//// http://www.opencores.org/projects/uart16550/ //// |
//// //// |
//// Documentation related to this project: //// |
//// http://www.opencores.org/projects/uart16550/ //// |
//// //// |
//// Projects compatibility: //// |
//// - WISHBONE //// |
//// RS232 Protocol //// |
//// 16550D uart (mostly supported) //// |
//// //// |
//// Overview (main Features): //// |
//// Device interface for testing purposes //// |
//// //// |
//// Known problems (limits): //// |
//// //// |
//// To Do: //// |
//// Nothing. //// |
//// //// |
//// Author(s): //// |
//// - Igor Mohor (igorm@opencores.org) //// |
//// //// |
//// Created and updated: (See log for the revision history) //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2001 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_device_if_defines.v" |
|
module uart_device_if_memory (adr, data_in, data_out, read, write); |
|
parameter DATA_WIDTH = 36; |
|
input [31:0] adr; |
input read, write; |
input [DATA_WIDTH-1:0] data_in; |
|
output [DATA_WIDTH-1:0] data_out; |
reg [DATA_WIDTH-1:0] data_out; |
|
reg [35:0] mem [0:`MEM_DEPTH-1]; |
|
always @ (adr) |
begin |
data_out = mem[adr]; // Reading instructions from internal memory |
end |
|
initial |
begin |
$readmemh("vapi.log", mem); // Copying instruction from file to internal memory. |
end |
|
endmodule |
/trunk/bench/verilog/uart_device_if_defines.v
0,0 → 1,72
////////////////////////////////////////////////////////////////////// |
//// //// |
//// uart_device_if_defines.v //// |
//// //// |
//// //// |
//// This file is part of the "UART 16550 compatible" project //// |
//// http://www.opencores.org/projects/uart16550/ //// |
//// //// |
//// Documentation related to this project: //// |
//// http://www.opencores.org/projects/uart16550/ //// |
//// //// |
//// Projects compatibility: //// |
//// - WISHBONE //// |
//// RS232 Protocol //// |
//// 16550D uart (mostly supported) //// |
//// //// |
//// Overview (main Features): //// |
//// Device interface for testing purposes //// |
//// //// |
//// Known problems (limits): //// |
//// //// |
//// To Do: //// |
//// Nothing. //// |
//// //// |
//// Author(s): //// |
//// - Igor Mohor (igorm@opencores.org) //// |
//// //// |
//// Created and updated: (See log for the revision history) //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2001 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 $ |
// |
// |
// |
// |
|
|
`define MEM_DEPTH 1000 // Number of commands in the file.txt |
|
//`define SHOW_RX_LCR // Show RX lcr configuration |
//`define SHOW_TX_LCR // Show TX lcr configuration |
//`define SHOW_RECEIVED_BITS // Show received bits |
//`define SHOW_FIFO_ACTIVITY // Shows data being written to FIFO |
/trunk/bench/verilog/readme.txt
0,0 → 1,111
////////////////////////////////////////////////////////////////////// |
//// //// |
//// readme.txt //// |
//// //// |
//// //// |
//// This file is part of the "UART 16550 compatible" project //// |
//// http://www.opencores.org/projects/uart16550/ //// |
//// //// |
//// Documentation related to this project: //// |
//// http://www.opencores.org/projects/uart16550/ //// |
//// //// |
//// Projects compatibility: //// |
//// - WISHBONE //// |
//// RS232 Protocol //// |
//// 16550D uart (mostly supported) //// |
//// //// |
//// Overview (main Features): //// |
//// Device interface for testing purposes //// |
//// //// |
//// Known problems (limits): //// |
//// //// |
//// To Do: //// |
//// Nothing. //// |
//// //// |
//// Author(s): //// |
//// - Igor Mohor (igorm@opencores.org) //// |
//// //// |
//// Created and updated: (See log for the revision history) //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2001 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 $ |
// |
// |
// |
// |
|
|
Following files are making an UART16550 PHY and are used for testing: |
|
uart_device_if_defines.v - defines related to PHY |
uart_device_if_memory.v - Module for initializing PHY (reading commands from vapi.log file) |
uart_device_if.v - Uart PHY with additional feature for testing |
vapi.log - File with commands (expected data, data to be send, etc.) |
readme.txt - This file |
|
|
|
|
OPERATION: |
uart_device_if.v is a uart PHY and connects to the uart_top.v. PHY takes commands from vapi.log |
file. Depending on command it can: |
- set a mode (5, 6, 7, 8-bit, parity, stop bits, etc.) |
- set a frequency divider (dll) |
- send a character |
- receive a character and compare it to the expected one |
- send a glitch (after a certain period of time) |
- send a break |
- detect a break |
- Check if fifo is empty/not empty (and generate an error if expected value differs from actual) |
- delay (does nothing for certain number of characters) |
|
On the other side of uart some kind of host must be connected that controls the phy. |
|
This is the structure: |
|
|
|||||||||||||| |||||||||||||||| |||||||||||||||| |
| | | | | | |
| Host | <----------> | UART | <----------> | PHY | |
| | | | | | |
|||||||||||||| |||||||||||||||| |||||||||||||||| |
|
|
PHY must know how host sets th UART and work in the same mode. Besides that it must know what |
host is sending or expecting to receive. Operation of the PHY must be written in the vapi.log |
file. |
|
When I was using this testing environment, I used OpenRISC1200 as a host. Everything is fully |
operational. UART was also tested in hardware (on two different boards), running uCLinux in |
both, interrupt and polling mode. |
|
|
/trunk/bench/verilog/uart_device_if.v
0,0 → 1,908
////////////////////////////////////////////////////////////////////// |
//// //// |
//// uart_device_if.v //// |
//// //// |
//// //// |
//// This file is part of the "UART 16550 compatible" project //// |
//// http://www.opencores.org/projects/uart16550/ //// |
//// //// |
//// Documentation related to this project: //// |
//// http://www.opencores.org/projects/uart16550/ //// |
//// //// |
//// Projects compatibility: //// |
//// - WISHBONE //// |
//// RS232 Protocol //// |
//// 16550D uart (mostly supported) //// |
//// //// |
//// Overview (main Features): //// |
//// Device interface for testing purposes //// |
//// //// |
//// Known problems (limits): When 1.5 stop bits are used, only //// |
//// first stop bit is checked //// |
//// //// |
//// To Do: //// |
//// Nothing. //// |
//// //// |
//// Author(s): //// |
//// - Igor Mohor (igorm@opencores.org) //// |
//// //// |
//// Created and updated: (See log for the revision history) //// |
//// //// |
//// //// |
////////////////////////////////////////////////////////////////////// |
//// //// |
//// Copyright (C) 2001 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_device_if_defines.v" |
|
module uart_device_if (stx_i, rts_i, dtr_i, srx_o, cts_o, dsr_o, ri_o, dcd_o); |
|
parameter DATA_WIDTH = 36; |
parameter clk_half_period = 25; // clock |
|
parameter FIFO_DEPTH = 16; |
parameter FIFO_ADR_WIDTH = 4; |
|
|
input stx_i; |
input rts_i; |
input dtr_i; |
output srx_o; |
output cts_o; |
output dsr_o; |
output ri_o; |
output dcd_o; |
|
reg [159:0] test_progress; // Information about the test progress (20 characters in ASCII) |
reg [DATA_WIDTH-1:0] packet, mem_data_out; |
reg [31:0] adr; |
reg read, write, clk; |
reg tx_clk; // tx_clk = clk / (divider * 16). |
|
reg rx_cnt_rst; |
reg [3:0] rx_cnt; |
reg reset; |
reg [15:8] rx_lcr; |
|
reg [FIFO_ADR_WIDTH-1:0] fifo_read_adr, fifo_write_adr; |
reg [FIFO_ADR_WIDTH:0] fifo_cnt; |
|
reg [23:0] fifo [0:FIFO_DEPTH-1]; |
reg [23:0] data_from_fifo, data_for_fifo; |
reg write_fifo, read_fifo; |
|
reg [31:0] cnt; |
reg cnt_enable; |
reg receive_packet_end, receive_packet_end_q, sample; |
|
reg [15:0] clock_divider; |
reg [3:0] rx_length; // Data length |
|
reg rx_sample_clock; |
reg [7:0] rx_data; // After data |
reg rx_parity; // received parity |
reg [1:0] rx_stop; // received stop bits |
reg framing_error, parity_error; |
|
reg tx_break_enable; // This bit identifies the break bit (instead the one in the LCR) |
reg [15:0] tx_break_delay; // break is transmitted global_break_delay cycles after start |
// (in 16 * clk units) |
reg start_tx_break_cnt; |
reg srx_break; |
reg srx_serial; |
reg [31:0] tx_break_cnt; |
reg break_detected, break_detected_q; |
|
reg [23:0] glitch_num; |
reg enable_glitch; |
reg glitch; |
|
wire [5:0] rx_break_detection_length; |
wire [DATA_WIDTH-1:0] mem_data_in; |
wire fifo_full, fifo_empty; |
|
wire [3:0] total_rx_length; // Data length + 1 parity + 1 stop bits |
wire rx_length5, rx_length6, rx_length7, rx_length8; // data length = 5, 6,7 or 8 bits |
wire rx_parity_enabled, rx_odd_parity, rx_even_parity, rx_stick1_parity; |
wire rx_stick0_parity, rx_stop_bit_1, rx_stop_bit15, rx_stop_bit2; |
wire rx_break; // not used |
|
integer delay, ii, kk, ll; |
integer mcd; // file handle |
|
//assign srx_o = srx_serial & ~srx_break; |
assign srx_o = (srx_serial ^ glitch) & ~srx_break; |
|
assign cts_o = 0; |
assign dsr_o = 0; |
assign ri_o = 0; |
assign dcd_o = 0; |
|
|
|
|
|
// wire my_stx_i = srx_o; |
wire my_stx_i = stx_i; |
|
|
// Initializing variables at startup |
initial |
begin |
read = 0; |
write = 0; |
ii = 0; |
delay = 5; |
srx_serial = 1; |
srx_break = 0; |
ll = 0; |
write_fifo = 0; |
read_fifo = 0; |
cnt_enable = 0; |
receive_packet_end = 0; |
tx_break_enable = 0; |
tx_break_delay = 0; |
start_tx_break_cnt = 0; |
tx_break_cnt = 0; |
break_detected = 0; |
break_detected_q = 0; |
glitch_num = 0; |
enable_glitch = 0; |
glitch = 0; |
reset = 0; |
#1 reset = 1; |
#1 reset = 0; |
end |
|
|
// Generating clock signal |
always |
begin |
clk = 1; |
forever #clk_half_period clk = ~clk; |
end |
|
|
// Generating divided clock signal that is used for data transmission. |
always |
begin |
tx_clk = 1; |
forever #delay tx_clk = ~tx_clk; |
end |
|
|
// Connecting memory with simulation data to the interface |
uart_device_if_memory #(36) i_memory(.adr(adr), .data_in(mem_data_out), .data_out(mem_data_in), .read(read), .write(write)); |
|
|
////////////////////////////////////////////////////////////////////////////////////// |
// // |
// Start: Main loop for communication (reading instructions from file) // |
// // |
////////////////////////////////////////////////////////////////////////////////////// |
initial |
begin |
mcd = $fopen("uart_device_if.log"); |
#1000; |
while(packet !== 36'h200000000) |
begin |
test_progress = "Read pckt from mem"; |
read_packet(ii, packet); |
if(packet[35:24]==12'h0_00) // send packet |
begin |
$fdisplay(mcd,"(%0t) send_packet 0x%0x", $time, packet[23:0]); |
test_progress = "send_packet"; |
send_packet(packet[23:0]); |
end |
else |
if(packet[35:24]==12'h0_01) // set dll |
begin |
$fdisplay(mcd,"(%0t) set_dll 0x%0x", $time, packet[15:0]); |
test_progress = "set_dll"; |
set_dll(packet[15:0]); |
end |
else |
if(packet[35:24]==12'h0_02) // set rx lcr |
begin |
$fdisplay(mcd,"(%0t) set_rx_lcr 0x%0x", $time, packet[23:0]); |
test_progress = "set_rx_lcr"; |
rx_lcr[15:8] = packet[15:8]; |
end |
else |
if(packet[35:24]==12'h0_03) // glitch generation |
begin |
$fdisplay(mcd,"(%0t) generate_glitch 0x%0x", $time, packet[23:0]); |
test_progress = "generate_glitch"; |
generate_glitch(packet[23:0]); |
end |
else |
if(packet[35:24]==12'h0_04) // set break |
begin |
if(packet[16]) |
$fdisplay(mcd,"(%0t) set_break to activate after 0x%0x cycles (in 1/16th of cycle)", $time, packet[15:0]); |
else |
$fdisplay(mcd,"(%0t) disabling break", $time); |
test_progress = "set_break"; |
set_break(packet[23:0]); |
end |
else |
if(packet[35:24]==12'h0_05) // check fifo empty |
begin |
$fdisplay(mcd,"(%0t) check_fifo_empty 0x%0x", $time, packet[23:0]); |
test_progress = "check_fifo_empty"; |
check_fifo_empty(packet[23:0]); |
end |
else |
if(packet[35:24]==12'h0_06) // Delay number of clk cycles |
begin |
$fdisplay(mcd,"\n(%0t) Delay 0x%0x clk cycles (do nothing in the meantime)", $time, packet[23:0]); |
test_progress = "Wait_clock_cycles"; |
wait_clock_cycles(packet[23:0]); |
end |
else |
if(packet[35:24]==12'h1_00) // read packet from fifo and compare |
begin |
$fwrite(mcd,"\n(%0t) read_fifo_&_compare", $time); |
test_progress = "read_fifo_&_compare"; |
read_fifo_and_compare(packet[23:0]); |
end |
else |
if(packet == 36'h200000000) // end of simulation |
begin |
$fdisplay(mcd,"\n(%0t) Exit simulation (uart_device_if.v)", $time); |
test_progress = "Exit simulation"; |
end |
else |
begin |
$fdisplay(mcd,"\n(%0t) ERROR: Unknown instruction in the vapi.log (%0d).", $time, ii); |
$stop; |
end |
|
ii=ii+1; |
end |
$fdisplay(mcd,"\n\n(%0t) END OF UART SIMULATION DETECTED", $time); |
#1000; |
$fclose(mcd); |
$stop; |
end |
////////////////////////////////////////////////////////////////////////////////////// |
// // |
// End: Main loop for communication (reading instructions from file) // |
// // |
////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////// |
// // |
// Start: Receiving data // |
// // |
////////////////////////////////////////////////////////////////////////////////////// |
assign rx_length5 = ~rx_lcr[9] & ~rx_lcr[8]; // data length = 5 bits |
assign rx_length6 = ~rx_lcr[9] & rx_lcr[8]; // data length = 6 bits |
assign rx_length7 = rx_lcr[9] & ~rx_lcr[8]; // data length = 7 bits |
assign rx_length8 = rx_lcr[9] & rx_lcr[8]; // data length = 8 bits |
|
assign rx_parity_enabled = rx_lcr[11]; |
assign rx_odd_parity = ~rx_lcr[13] & ~rx_lcr[12] & rx_parity_enabled; |
assign rx_even_parity = ~rx_lcr[13] & rx_lcr[12] & rx_parity_enabled; |
assign rx_stick1_parity = rx_lcr[13] & ~rx_lcr[12] & rx_parity_enabled; |
assign rx_stick0_parity = rx_lcr[13] & rx_lcr[12] & rx_parity_enabled; |
|
assign rx_break = rx_lcr[14]; // not used |
|
assign rx_stop_bit_1 = ~rx_lcr[10]; |
assign rx_stop_bit15 = rx_lcr[10] & rx_length5; |
assign rx_stop_bit2 = rx_lcr[10] & ~rx_length5; // (length6 | length7 | length8); |
|
always @ (rx_length5, rx_length6, rx_length7, rx_length8) |
begin |
if(rx_length5) |
rx_length = 5; |
if(rx_length6) |
rx_length = 6; |
if(rx_length7) |
rx_length = 7; |
if(rx_length8) |
rx_length = 8; |
end |
|
|
// Total length of the received packet. Needed for proper generation of the receive_packet_end signal. |
assign total_rx_length = rx_length + rx_parity_enabled + 1 + rx_stop_bit2; // data length + parity + 1 stop bit + second stop bit (when enabled) |
assign rx_break_detection_length = total_rx_length + 1; // +1 is used because start bit was not included in total_rx_length. |
|
// Generating cnt_enable signal. |
always @ (posedge clk) |
begin |
if(~cnt_enable) |
wait(~my_stx_i); |
cnt_enable = 1; |
receive_packet_end = 0; |
wait(receive_packet_end); |
cnt_enable = 0; |
wait(my_stx_i); // Must be high to continue. This is needed because of the break condition |
end |
|
|
// Counter used in data reception |
always @ (posedge clk) |
begin |
if(cnt_enable) |
begin |
if(cnt==(8*clock_divider - 1) & my_stx_i) // False start bit detection |
receive_packet_end = 1; |
if(cnt_enable) // Checking is still enabled after rx_devider clocks |
cnt <=#1 cnt + 1; |
else |
cnt <=#1 0; |
end |
else |
cnt <=#1 0; |
end |
|
|
// Delayed receive_packet_end signal |
always @ (posedge clk) |
begin |
receive_packet_end_q = receive_packet_end; |
end |
|
|
|
// Generating sample clock and end of the frame (Received data is sampled with this clock) |
always @ (posedge clk) |
begin |
if(cnt==8*clock_divider-1) |
kk=0; |
else |
if(cnt==(8*clock_divider + 16*clock_divider*(kk+1) - 1)) |
begin |
rx_sample_clock = 1; |
kk=kk+1; |
if(kk==total_rx_length) |
receive_packet_end = 1; |
end |
else |
rx_sample_clock = 0; |
end |
|
|
|
// Sampling data (received data). When finished, this data is written to fifo. |
always @ (posedge clk) |
begin |
if(rx_sample_clock) |
begin |
if(kk<=rx_length) // Sampling data |
begin |
ll<=0; // Stop bit index reset at the beginning of the data stage |
`ifdef SHOW_RECEIVED_BITS |
$fdisplay(mcd,"\t\t\t\t\t\t\t(kk=%0d) Reading data bits = %0x", kk, my_stx_i); |
`endif |
rx_data[kk-1] = my_stx_i; |
end |
else |
begin |
if(kk==(rx_length+1)) |
begin |
if(rx_parity_enabled) |
begin |
`ifdef SHOW_RECEIVED_BITS |
$fdisplay(mcd,"\t\t\t\t\t\t\t(kk=%0d) Reading parity bits = %0x", kk, my_stx_i); |
`endif |
end |
else |
begin |
rx_stop[ll] = my_stx_i; |
ll<=ll+1; |
end |
rx_parity = my_stx_i & rx_parity_enabled; |
end |
|
if(kk>=(rx_length+1+rx_parity_enabled)) |
begin |
`ifdef SHOW_RECEIVED_BITS |
$fdisplay(mcd,"\t\t\t\t\t\t\t(kk=%0d) Reading stop bits = %0x", kk, my_stx_i); |
`endif |
rx_stop[ll] = my_stx_i; |
ll<=ll+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 |
framing_error = (rx_stop_bit_1 | rx_stop_bit15)? ~rx_stop[0] : ~(&rx_stop[1:0]); // When 1 or 1.5 stop bits are used, |
// only first stop bit is checked |
// Parity error generation |
if(rx_odd_parity) |
parity_error = ~(^{rx_data, rx_parity}); |
else if(rx_even_parity) |
parity_error = ^{rx_data, rx_parity}; |
else if(rx_stick0_parity) |
parity_error = rx_parity; |
else if(rx_stick1_parity) |
parity_error = ~rx_parity; |
else |
parity_error = 0; |
end |
|
//wire write_condition = my_stx_i | (break_detected & ~break_detected_q); |
wire write_condition = my_stx_i | break_detected; |
// Writing received data to FIFO |
always @ (posedge clk) |
begin |
if(receive_packet_end & ~receive_packet_end_q | break_detected & ~break_detected_q) |
wait(write_condition) // Waiting for "end of cycle detected" or "break to be activated" |
begin |
|
`ifdef SHOW_RX_LCR |
if(rx_length5 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_length5"); |
if(rx_length6 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_length6"); |
if(rx_length7 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_length7"); |
if(rx_length8 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_length8"); |
if(rx_parity_enabled) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_parity_enabled"); |
if(rx_odd_parity ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_odd_parity"); |
if(rx_even_parity ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_even_parity"); |
if(rx_stick1_parity ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_stick1_parity"); |
if(rx_stick0_parity ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_stick0_parity"); |
if(rx_break ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_break"); |
if(rx_stop_bit_1 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_stop_bit_1"); |
if(rx_stop_bit15 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_stop_bit15"); |
if(rx_stop_bit2 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\trx_stop_bit2"); |
`endif |
|
write_rx_data_to_fifo({6'h0, framing_error, parity_error, rx_lcr[15:8], rx_data}); |
end |
end |
|
|
// Break detection |
reg [31:0] rx_break_cnt; |
|
|
always @ (posedge clk) |
begin |
break_detected_q <= break_detected; |
if(my_stx_i) |
begin |
rx_break_cnt = 0; // Reseting counter |
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 * clock_divider) |
begin |
$fdisplay(mcd, "\n(%0t) Break_detected.", $time); |
break_detected <= 1; |
test_progress = "Break_detected"; |
end |
end |
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////// |
// // |
// End: Receiving data // |
// // |
////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Reading packet back from the memory |
task read_packet; |
input [31:0] address; |
output [DATA_WIDTH-1:0] data; |
|
begin |
adr = address; |
#1; |
data = mem_data_in; |
end |
endtask |
|
|
// Seting DLL (clock divider) |
task set_dll; |
input [15:0] divider; |
|
begin |
assign clock_divider = divider; // rx clock divider |
|
@ (posedge clk); |
#(2*clk_half_period) delay = (clock_divider*16*clk_half_period); // tx clock divider |
end |
endtask |
|
|
// Sending packets |
task send_packet; |
input [23:0] packet; |
|
reg [7:0] data; |
reg length5, length6, length7, length8; |
reg parity_enabled; |
reg odd_parity, even_parity, stick1_parity, stick0_parity; |
// reg break; // tx_break_enable is used |
reg stop_bit_1, stop_bit15, stop_bit2; |
reg parity_xor; |
|
integer length, jj; |
|
begin |
data[7:0] = packet[7:0]; |
length5 = ~packet[9] & ~packet[8]; // data length = 5 bits |
length6 = ~packet[9] & packet[8]; // data length = 6 bits |
length7 = packet[9] & ~packet[8]; // data length = 7 bits |
length8 = packet[9] & packet[8]; // data length = 8 bits |
|
parity_enabled = packet[11]; |
odd_parity = ~packet[13] & ~packet[12] & parity_enabled; |
even_parity = ~packet[13] & packet[12] & parity_enabled; |
stick1_parity = packet[13] & ~packet[12] & parity_enabled; |
stick0_parity = packet[13] & packet[12] & parity_enabled; |
|
// break = packet[14]; // tx_break_enable is used |
|
stop_bit_1 = ~packet[10]; |
stop_bit15 = packet[10] & length5; |
stop_bit2 = packet[10] & ~length5; // (length6 | length7 | length8); |
|
`ifdef SHOW_TX_LCR |
if(length5 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_length5"); |
if(length6 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_length6"); |
if(length7 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_length7"); |
if(length8 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_length8"); |
if(parity_enabled) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_parity_enabled"); |
if(odd_parity ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_odd_parity"); |
if(even_parity ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_even_parity"); |
if(stick1_parity ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_stick1_parity"); |
if(stick0_parity ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_stick0_parity"); |
if(tx_break_enable) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_break"); |
if(stop_bit_1 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_stop_bit_1"); |
if(stop_bit15 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_stop_bit15"); |
if(stop_bit2 ) |
$fdisplay(mcd,"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttx_stop_bit2"); |
`endif |
|
|
if(length5) |
begin |
length=5; |
parity_xor = ^data[4:0]; |
end |
else if(length6) |
begin |
length=6; |
parity_xor = ^data[5:0]; |
end |
else if(length7) |
begin |
length=7; |
parity_xor = ^data[6:0]; |
end |
else if(length8) |
begin |
length=8; |
parity_xor = ^data[7:0]; |
end |
|
// Sending start bit |
@ (posedge tx_clk); |
srx_serial = 0; |
if(glitch_num > 0) |
enable_glitch = 1; // enabling glitch generation |
if(tx_break_enable) |
start_tx_break_cnt = 1; // Start counter that counts break length |
@ (posedge tx_clk); |
|
// Sending data bits |
for(jj=0; jj<length; jj=jj+1) |
begin |
srx_serial = data[jj]; |
@ (posedge tx_clk); |
end |
|
// Sending parity bit |
if(parity_enabled) |
begin |
if(odd_parity) |
srx_serial = ~parity_xor; |
else if(even_parity) |
srx_serial = parity_xor; |
else if(stick1_parity) |
srx_serial = 1; |
else if(stick0_parity) |
srx_serial = 0; |
@ (posedge tx_clk); |
end |
|
// Sending stop bits |
srx_serial = 1; |
@ (posedge tx_clk); // 1 stop bit |
if(stop_bit15 | stop_bit2) |
@ (posedge tx_clk); // Since only 1st stop bit is detected, there is no need to generate 1.5 stop bits. |
// 2 stop bits are generated instead. |
enable_glitch = 0; |
test_progress = "end send packet"; |
end |
endtask |
|
|
|
// Received data is written to fifo so it can be compared with the "expected" data later. |
task write_rx_data_to_fifo; |
input [23:0] task_data_for_fifo; |
|
begin |
data_for_fifo = task_data_for_fifo; |
if(framing_error | parity_error) |
begin |
if(break_detected) |
begin |
data_for_fifo = 24'h004000; |
// data_for_fifo = (task_data_for_fifo & 24'hffff00) | 24'h004000; |
$fdisplay(mcd, "(%0t) Break packet written to fifo (0x%0x).", $time, data_for_fifo); |
end |
else |
begin |
$fdisplay(mcd,"(%0t) \t\tERROR: Framing error or parity error occured when receiving data (fe=%0x, pe=%0x)", $time, |
framing_error, parity_error); |
end |
end |
`ifdef SHOW_FIFO_ACTIVITY |
else |
$fdisplay(mcd,"(%0t) Writing received packet to fifo: data=0x%0x, parity_error=%0x, framing_error=%0x, lcr=0x%0x", |
$time, data_for_fifo[7:0], data_for_fifo[16], data_for_fifo[17], data_for_fifo[15:8]); |
`endif |
|
@ (posedge clk); |
#1 write_fifo = 1; |
@ (posedge clk); |
#1 write_fifo = 0; |
|
end |
endtask |
|
|
|
// Read data form fifo (received packets were stored to fifo) and compare them with expected data |
task read_fifo_and_compare; |
|
input [23:0] reference_packet; |
|
begin |
if(fifo_empty) |
$fdisplay(mcd,"\n(%0t) \t\tWARNING: Fifo still empty. Waiting for data reception.", $time); |
wait(~fifo_empty); |
@ (posedge clk); |
#1 read_fifo = 1; |
@ (posedge clk); // data is read from fifo |
#1 read_fifo = 0; |
#1; // delay needed for data from fifo to propagate |
if(reference_packet != data_from_fifo) |
begin |
$fdisplay(mcd,"(%0t) \t\tERROR: Reference packet differs from received packet (reference_packet=%0x, data_from_fifo=%0x)", $time, |
reference_packet, data_from_fifo); |
$stop; |
end |
else |
$fdisplay(mcd,"\t\t(%0t) Reference packet equals to received packet (reference_packet=%0x, data_from_fifo=%0x)", $time, |
reference_packet, data_from_fifo); |
`ifdef SHOW_FIFO_ACTIVITY |
$fwrite(mcd," (data_from_fifo = 0x%0x, fifo_adr = 0x%0x)", data_from_fifo, fifo_read_adr-1); // -1 because pointer is already incremented |
`endif |
end |
endtask |
|
|
// Set break (or clear it) |
task set_break; |
input [23:0] break_data; |
|
begin |
tx_break_enable = break_data[16]; |
tx_break_delay = break_data[15:0]; |
end |
endtask |
|
task wait_clock_cycles; |
input [23:0] number_of_clocks; |
|
begin |
repeat(number_of_clocks) |
@ (posedge tx_clk); |
end |
endtask |
|
|
// Checking if receive fifo is full or empty |
assign fifo_full = fifo_cnt == FIFO_DEPTH; |
assign fifo_empty = fifo_cnt == 0; |
|
// Writing and reading data to/from fifo |
always @ (posedge clk or posedge reset) |
begin |
if(reset) |
begin |
fifo_write_adr = 0; |
fifo_read_adr = 0; |
fifo_cnt = 0; |
end |
else |
begin |
case({read_fifo, write_fifo}) |
2'b01: // write |
begin |
if(fifo_full) |
begin |
$fdisplay(mcd,"(%0t) \t\tERROR: Fifo full.", $time); |
$stop; |
end |
fifo[fifo_write_adr] <=#1 data_for_fifo; |
fifo_write_adr <=#1 fifo_write_adr + 1; |
fifo_cnt <=#1 fifo_cnt + 1; |
end |
2'b10: // read |
begin |
data_from_fifo <=#1 fifo[fifo_read_adr]; |
fifo_read_adr <=#1 fifo_read_adr + 1; |
fifo_cnt <=#1 fifo_cnt - 1; |
end |
2'b11: // read and write |
begin |
data_from_fifo <=#1 fifo[fifo_read_adr]; |
fifo[fifo_write_adr] <=#1 data_for_fifo; |
fifo_read_adr <=#1 fifo_read_adr + 1; |
fifo_write_adr <=#1 fifo_write_adr + 1; |
fifo_cnt <=#1 fifo_cnt; |
end |
default: |
; |
endcase |
end |
end |
|
|
// Checking if fifo is empty or full |
task check_fifo_empty; |
input [23:0] fifo_empty_in; |
|
begin |
if(fifo_empty_in[0] !== fifo_empty) |
begin |
if(fifo_empty) |
$fdisplay(mcd,"(%0t) \t\tERROR: Fifo is empty but shouldn't be.", $time); |
else |
$fdisplay(mcd,"(%0t) \t\tERROR: Fifo is not empty but should be.", $time); |
$stop; |
end |
end |
|
endtask |
|
|
task generate_glitch; |
input [23:0] generate_glitch_data; |
|
begin |
glitch_num = generate_glitch_data; |
end |
endtask |
|
|
reg [31:0] glitch_cnt; |
always @ (posedge clk or posedge enable_glitch) |
begin |
if(enable_glitch) |
begin |
glitch_cnt <= glitch_cnt + 1; |
if(glitch_cnt == ((glitch_num-1) * clock_divider)) |
glitch = 1; |
else |
if(glitch_cnt == (glitch_num * clock_divider)) |
glitch = 0; |
end |
else |
glitch_cnt <= 0; |
end |
|
|
// Logic for setting/clearing break condition |
always @ (posedge clk) |
begin |
if(tx_break_enable && (tx_break_cnt == (tx_break_delay*clock_divider))) |
begin |
start_tx_break_cnt = 0; |
srx_break = 1; |
end |
else |
if(start_tx_break_cnt) // Start counter that counts break length |
tx_break_cnt = tx_break_cnt + 1; |
else |
begin |
tx_break_cnt = 0; |
srx_break = 0; |
end |
end |
|
|
|
|
|
endmodule |