//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//// ////
|
//// ////
|
//// can_testbench.v ////
|
//// can_testbench.v ////
|
//// ////
|
//// ////
|
//// ////
|
//// ////
|
//// This file is part of the CAN Protocol Controller ////
|
//// This file is part of the CAN Protocol Controller ////
|
//// http://www.opencores.org/projects/can/ ////
|
//// http://www.opencores.org/projects/can/ ////
|
//// ////
|
//// ////
|
//// ////
|
//// ////
|
//// Author(s): ////
|
//// Author(s): ////
|
//// Igor Mohor ////
|
//// Igor Mohor ////
|
//// igorm@opencores.org ////
|
//// igorm@opencores.org ////
|
//// ////
|
//// ////
|
//// ////
|
//// ////
|
//// All additional information is available in the README.txt ////
|
//// All additional information is available in the README.txt ////
|
//// file. ////
|
//// file. ////
|
//// ////
|
//// ////
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//// ////
|
//// ////
|
//// Copyright (C) 2002, 2003 Authors ////
|
//// Copyright (C) 2002, 2003 Authors ////
|
//// ////
|
//// ////
|
//// This source file may be used and distributed without ////
|
//// This source file may be used and distributed without ////
|
//// restriction provided that this copyright statement is not ////
|
//// restriction provided that this copyright statement is not ////
|
//// removed from the file and that any derivative work contains ////
|
//// removed from the file and that any derivative work contains ////
|
//// the original copyright notice and the associated disclaimer. ////
|
//// the original copyright notice and the associated disclaimer. ////
|
//// ////
|
//// ////
|
//// This source file is free software; you can redistribute it ////
|
//// This source file is free software; you can redistribute it ////
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
//// and/or modify it under the terms of the GNU Lesser General ////
|
//// Public License as published by the Free Software Foundation; ////
|
//// Public License as published by the Free Software Foundation; ////
|
//// either version 2.1 of the License, or (at your option) any ////
|
//// either version 2.1 of the License, or (at your option) any ////
|
//// later version. ////
|
//// later version. ////
|
//// ////
|
//// ////
|
//// This source is distributed in the hope that it will be ////
|
//// This source is distributed in the hope that it will be ////
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
//// useful, but WITHOUT ANY WARRANTY; without even the implied ////
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
//// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ////
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
//// PURPOSE. See the GNU Lesser General Public License for more ////
|
//// details. ////
|
//// details. ////
|
//// ////
|
//// ////
|
//// You should have received a copy of the GNU Lesser General ////
|
//// You should have received a copy of the GNU Lesser General ////
|
//// Public License along with this source; if not, download it ////
|
//// Public License along with this source; if not, download it ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// from http://www.opencores.org/lgpl.shtml ////
|
//// ////
|
//// ////
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
//
|
//
|
// CVS Revision History
|
// CVS Revision History
|
//
|
//
|
// $Log: not supported by cvs2svn $
|
// $Log: not supported by cvs2svn $
|
|
// Revision 1.6 2002/12/27 00:12:48 mohor
|
|
// Header changed, testbench improved to send a frame (crc still missing).
|
|
//
|
// Revision 1.5 2002/12/26 16:00:29 mohor
|
// Revision 1.5 2002/12/26 16:00:29 mohor
|
// Testbench define file added. Clock divider register added.
|
// Testbench define file added. Clock divider register added.
|
//
|
//
|
// Revision 1.4 2002/12/26 01:33:01 mohor
|
// Revision 1.4 2002/12/26 01:33:01 mohor
|
// Tripple sampling supported.
|
// Tripple sampling supported.
|
//
|
//
|
// Revision 1.3 2002/12/25 23:44:12 mohor
|
// Revision 1.3 2002/12/25 23:44:12 mohor
|
// Commented lines removed.
|
// Commented lines removed.
|
//
|
//
|
// Revision 1.2 2002/12/25 14:16:54 mohor
|
// Revision 1.2 2002/12/25 14:16:54 mohor
|
// Synchronization working.
|
// Synchronization working.
|
//
|
//
|
// Revision 1.1.1.1 2002/12/20 16:39:21 mohor
|
// Revision 1.1.1.1 2002/12/20 16:39:21 mohor
|
// Initial
|
// Initial
|
//
|
//
|
//
|
//
|
//
|
//
|
|
|
// synopsys translate_off
|
// synopsys translate_off
|
`include "timescale.v"
|
`include "timescale.v"
|
// synopsys translate_on
|
// synopsys translate_on
|
`include "can_defines.v"
|
`include "can_defines.v"
|
`include "can_testbench_defines.v"
|
`include "can_testbench_defines.v"
|
|
|
module can_testbench();
|
module can_testbench();
|
|
|
|
|
|
|
parameter Tp = 1;
|
parameter Tp = 1;
|
parameter BRP = 2*(`CAN_TIMING0_BRP + 1);
|
parameter BRP = 2*(`CAN_TIMING0_BRP + 1);
|
|
|
|
|
|
|
reg clk;
|
reg clk;
|
reg rst;
|
reg rst;
|
reg [7:0] data_in;
|
reg [7:0] data_in;
|
wire [7:0] data_out;
|
wire [7:0] data_out;
|
reg cs, rw;
|
reg cs, rw;
|
reg [7:0] addr;
|
reg [7:0] addr;
|
reg rx;
|
reg rx;
|
reg idle;
|
|
integer start_tb;
|
integer start_tb;
|
|
|
/* Instantiate can_top module */
|
/* Instantiate can_top module */
|
can_top i_can_top
|
can_top i_can_top
|
(
|
(
|
.clk(clk),
|
.clk(clk),
|
.rst(rst),
|
.rst(rst),
|
.data_in(data_in),
|
.data_in(data_in),
|
.data_out(data_out),
|
.data_out(data_out),
|
.cs(cs),
|
.cs(cs),
|
.rw(rw),
|
.rw(rw),
|
.addr(addr),
|
.addr(addr),
|
.rx(rx),
|
.rx(rx)
|
.idle(idle)
|
|
);
|
);
|
|
|
|
|
// Generate clock signal 24 MHz
|
// Generate clock signal 24 MHz
|
initial
|
initial
|
begin
|
begin
|
clk=0;
|
clk=0;
|
forever #20 clk = ~clk;
|
forever #20 clk = ~clk;
|
end
|
end
|
|
|
initial
|
initial
|
begin
|
begin
|
start_tb = 0;
|
start_tb = 0;
|
data_in = 'hz;
|
data_in = 'hz;
|
cs = 0;
|
cs = 0;
|
rw = 'hz;
|
rw = 'hz;
|
addr = 'hz;
|
addr = 'hz;
|
rx = 1;
|
rx = 1;
|
rst = 1;
|
rst = 1;
|
idle = 1;
|
|
#200 rst = 0;
|
#200 rst = 0;
|
#200 start_tb = 1;
|
#200 start_tb = 1;
|
end
|
end
|
|
|
|
|
// Main testbench
|
// Main testbench
|
initial
|
initial
|
begin
|
begin
|
wait(start_tb);
|
wait(start_tb);
|
|
|
/* Set bus timing register 0 */
|
/* Set bus timing register 0 */
|
write_register(8'h6, {`CAN_TIMING0_SJW, `CAN_TIMING0_BRP});
|
write_register(8'h6, {`CAN_TIMING0_SJW, `CAN_TIMING0_BRP});
|
|
|
/* Set bus timing register 1 */
|
/* Set bus timing register 1 */
|
write_register(8'h7, {`CAN_TIMING1_SAM, `CAN_TIMING1_TSEG2, `CAN_TIMING1_TSEG1});
|
write_register(8'h7, {`CAN_TIMING1_SAM, `CAN_TIMING1_TSEG2, `CAN_TIMING1_TSEG1});
|
|
|
#10;
|
#10;
|
repeat (1000) @ (posedge clk);
|
repeat (1000) @ (posedge clk);
|
|
|
|
/* Switch-off reset mode */
|
|
write_register(8'h0, {7'h0, ~(`CAN_MODE_RESET)});
|
|
|
|
repeat (BRP) @ (posedge clk); // At least BRP clocks needed before bus goes to dominant level. Otherwise 1 quant difference is possible
|
|
// This difference is resynchronized later.
|
|
|
// test_synchronization;
|
// test_synchronization;
|
repeat (2) @ (posedge clk); // So we are not synchronized to anything
|
|
send_frame(1, 29'h12345678, 1); // mode, id, length
|
repeat (7) send_bit(1); // Sending EOF
|
|
|
|
|
|
send_frame(1, 29'h00075678, 1); // mode, id, length
|
|
|
|
|
repeat (50000) @ (posedge clk);
|
repeat (50000) @ (posedge clk);
|
$display("CAN Testbench finished.");
|
$display("CAN Testbench finished.");
|
$stop;
|
$stop;
|
end
|
end
|
|
|
|
|
|
|
|
|
task write_register;
|
task write_register;
|
input [7:0] reg_addr;
|
input [7:0] reg_addr;
|
input [7:0] reg_data;
|
input [7:0] reg_data;
|
|
|
begin
|
begin
|
@ (posedge clk);
|
@ (posedge clk);
|
#1;
|
#1;
|
addr = reg_addr;
|
addr = reg_addr;
|
data_in = reg_data;
|
data_in = reg_data;
|
cs = 1;
|
cs = 1;
|
rw = 0;
|
rw = 0;
|
@ (posedge clk);
|
@ (posedge clk);
|
#1;
|
#1;
|
addr = 'hz;
|
addr = 'hz;
|
data_in = 'hz;
|
data_in = 'hz;
|
cs = 0;
|
cs = 0;
|
rw = 'hz;
|
rw = 'hz;
|
end
|
end
|
endtask
|
endtask
|
|
|
|
|
task test_synchronization;
|
task test_synchronization;
|
begin
|
begin
|
// Hard synchronization
|
// Hard synchronization
|
repeat (2) @ (posedge clk); // So we are not synchronized to anything
|
|
#1 rx=0;
|
#1 rx=0;
|
repeat (2*BRP) @ (posedge clk);
|
repeat (2*BRP) @ (posedge clk);
|
#1 idle = 0;
|
// #1 idle = 0;
|
repeat (8*BRP) @ (posedge clk);
|
repeat (8*BRP) @ (posedge clk);
|
#1 rx=1;
|
#1 rx=1;
|
repeat (10*BRP) @ (posedge clk);
|
repeat (10*BRP) @ (posedge clk);
|
|
|
// Resynchronization on time
|
// Resynchronization on time
|
#1 rx=0;
|
#1 rx=0;
|
repeat (10*BRP) @ (posedge clk);
|
repeat (10*BRP) @ (posedge clk);
|
#1 rx=1;
|
#1 rx=1;
|
idle = 0;
|
// idle = 0;
|
repeat (10*BRP) @ (posedge clk);
|
repeat (10*BRP) @ (posedge clk);
|
|
|
// Resynchronization late
|
// Resynchronization late
|
repeat (BRP) @ (posedge clk);
|
repeat (BRP) @ (posedge clk);
|
repeat (BRP) @ (posedge clk);
|
repeat (BRP) @ (posedge clk);
|
#1 rx=0;
|
#1 rx=0;
|
repeat (10*BRP) @ (posedge clk);
|
repeat (10*BRP) @ (posedge clk);
|
#1 rx=1;
|
#1 rx=1;
|
idle = 0;
|
// idle = 0;
|
|
|
// Resynchronization early
|
// Resynchronization early
|
repeat (8*BRP) @ (posedge clk); // two frames too early
|
repeat (8*BRP) @ (posedge clk); // two frames too early
|
#1 rx=0;
|
#1 rx=0;
|
repeat (10*BRP) @ (posedge clk);
|
repeat (10*BRP) @ (posedge clk);
|
#1 rx=1;
|
#1 rx=1;
|
idle = 0;
|
// idle = 0;
|
repeat (10*BRP) @ (posedge clk);
|
repeat (10*BRP) @ (posedge clk);
|
end
|
end
|
endtask
|
endtask
|
|
|
|
|
task send_bit;
|
task send_bit;
|
input bit;
|
input bit;
|
integer cnt;
|
integer cnt;
|
begin
|
begin
|
#1 rx=bit;
|
#1 rx=bit;
|
repeat ((`CAN_TIMING1_TSEG1 + `CAN_TIMING1_TSEG2 + 3)*BRP) @ (posedge clk);
|
repeat ((`CAN_TIMING1_TSEG1 + `CAN_TIMING1_TSEG2 + 3)*BRP) @ (posedge clk);
|
idle=0;
|
// idle=0;
|
end
|
end
|
endtask
|
endtask
|
|
|
|
|
task send_frame;
|
task send_frame;
|
input mode;
|
input mode;
|
input [28:0] id;
|
input [28:0] id;
|
input [3:0] length;
|
input [3:0] length;
|
integer cnt;
|
integer cnt;
|
|
|
reg [28:0] data;
|
reg [28:0] data;
|
reg [3:0] len;
|
reg [3:0] len;
|
begin
|
begin
|
|
|
data = id;
|
data = id;
|
len = length;
|
len = length;
|
|
|
send_bit(0); // SOF
|
send_bit(0); // SOF
|
|
|
if(mode) // Extended format
|
if(mode) // Extended format
|
begin
|
begin
|
for (cnt=0; cnt<11; cnt=cnt+1) // 11 bit ID
|
for (cnt=0; cnt<11; cnt=cnt+1) // 11 bit ID
|
begin
|
begin
|
send_bit(data[28]);
|
send_bit(data[28]);
|
data=data<<1;
|
data=data<<1;
|
end
|
end
|
send_bit(1); // SRR
|
send_bit(1); // SRR
|
send_bit(1); // IDE
|
send_bit(1); // IDE
|
|
|
for (cnt=11; cnt<29; cnt=cnt+1) // 18 bit ID
|
for (cnt=11; cnt<29; cnt=cnt+1) // 18 bit ID
|
begin
|
begin
|
send_bit(data[28]);
|
send_bit(data[28]);
|
data=data<<1;
|
data=data<<1;
|
end
|
end
|
|
|
send_bit(0); // RTR
|
send_bit(0); // RTR
|
send_bit(0); // r1 (reserved 1)
|
send_bit(0); // r1 (reserved 1)
|
send_bit(0); // r0 (reserved 0)
|
send_bit(0); // r0 (reserved 0)
|
|
|
for (cnt=0; cnt<4; cnt=cnt+1) // DLC (length)
|
for (cnt=0; cnt<4; cnt=cnt+1) // DLC (length)
|
begin
|
begin
|
send_bit(len[3]);
|
send_bit(len[3]);
|
len=len<<1;
|
len=len<<1;
|
end
|
end
|
end
|
end
|
else // Standard format
|
else // Standard format
|
begin
|
begin
|
for (cnt=0; cnt<11; cnt=cnt+1) // 11 bit ID
|
for (cnt=0; cnt<11; cnt=cnt+1) // 11 bit ID
|
begin
|
begin
|
send_bit(data[10]);
|
send_bit(data[10]);
|
data=data<<1;
|
data=data<<1;
|
end
|
end
|
send_bit(0); // RTR
|
send_bit(0); // RTR
|
send_bit(0); // IDE
|
send_bit(0); // IDE
|
send_bit(0); // r0 (reserved 0)
|
send_bit(0); // r0 (reserved 0)
|
|
|
for (cnt=0; cnt<4; cnt=cnt+1) // DLC (length)
|
for (cnt=0; cnt<4; cnt=cnt+1) // DLC (length)
|
begin
|
begin
|
send_bit(len[3]);
|
send_bit(len[3]);
|
len=len<<1;
|
len=len<<1;
|
end
|
end
|
end // End header
|
end // End header
|
|
|
|
|
for (cnt=0; cnt<(8*length); cnt=cnt+4) // data
|
for (cnt=0; cnt<(8*length); cnt=cnt+4) // data
|
begin
|
begin
|
send_bit(cnt[3]);
|
send_bit(cnt[3]);
|
send_bit(cnt[2]);
|
send_bit(cnt[2]);
|
send_bit(cnt[1]);
|
send_bit(cnt[1]);
|
send_bit(cnt[0]);
|
send_bit(cnt[0]);
|
end
|
end
|
|
|
|
|
// Nothing send after the data (just recessive bit)
|
// Nothing send after the data (just recessive bit)
|
send_bit(1);
|
send_bit(1);
|
|
|
|
|
|
|
end
|
end
|
endtask
|
endtask
|
|
|
|
|
/* State machine monitor (btl) */
|
/* State machine monitor (btl) */
|
always @ (posedge clk)
|
always @ (posedge clk)
|
begin
|
begin
|
if(can_testbench.i_can_top.i_can_btl.go_sync & can_testbench.i_can_top.i_can_btl.go_seg1 | can_testbench.i_can_top.i_can_btl.go_sync & can_testbench.i_can_top.i_can_btl.go_seg2 |
|
if(can_testbench.i_can_top.i_can_btl.go_sync & can_testbench.i_can_top.i_can_btl.go_seg1 | can_testbench.i_can_top.i_can_btl.go_sync & can_testbench.i_can_top.i_can_btl.go_seg2 |
|
can_testbench.i_can_top.i_can_btl.go_seg1 & can_testbench.i_can_top.i_can_btl.go_seg2)
|
can_testbench.i_can_top.i_can_btl.go_seg1 & can_testbench.i_can_top.i_can_btl.go_seg2)
|
$display("(%0t) ERROR multiple go_sync, go_seg1 or go_seg2 occurance", $time);
|
begin
|
|
$display("(%0t) ERROR multiple go_sync, go_seg1 or go_seg2 occurance\n\n", $time);
|
|
#1000;
|
|
$stop;
|
|
end
|
|
|
if(can_testbench.i_can_top.i_can_btl.sync & can_testbench.i_can_top.i_can_btl.seg1 | can_testbench.i_can_top.i_can_btl.sync & can_testbench.i_can_top.i_can_btl.seg2 |
|
if(can_testbench.i_can_top.i_can_btl.sync & can_testbench.i_can_top.i_can_btl.seg1 | can_testbench.i_can_top.i_can_btl.sync & can_testbench.i_can_top.i_can_btl.seg2 |
|
can_testbench.i_can_top.i_can_btl.seg1 & can_testbench.i_can_top.i_can_btl.seg2)
|
can_testbench.i_can_top.i_can_btl.seg1 & can_testbench.i_can_top.i_can_btl.seg2)
|
$display("(%0t) ERROR multiple sync, seg1 or seg2 occurance", $time);
|
begin
|
|
$display("(%0t) ERROR multiple sync, seg1 or seg2 occurance\n\n", $time);
|
|
#1000;
|
|
$stop;
|
end
|
end
|
|
end
|
|
|
|
/* stuff_error monitor (bsp)
|
|
always @ (posedge clk)
|
|
begin
|
|
if(can_testbench.i_can_top.i_can_bsp.stuff_error)
|
|
begin
|
|
$display("\n\n(%0t) Stuff error occured in can_bsp.v file\n\n", $time);
|
|
$stop; After everything is finished add another condition (something like & (~idle)) and enable stop
|
|
end
|
|
end
|
|
*/
|
|
|
|
|
endmodule
|
endmodule
|
|
|