|
|
`define SCAN_DELAY #1
|
`define SCAN_DELAY #1
|
|
|
module tbench();
|
module tbench();
|
|
|
// Scan
|
// Scan
|
reg scan_phi, scan_phi_bar, scan_data_in, scan_load_chip, scan_load_chain;
|
reg scan_phi, scan_phi_bar, scan_data_in, scan_load_chip, scan_load_chain;
|
wire scan_data_out;
|
wire scan_data_out;
|
|
|
//-----------------------------------------
|
//-----------------------------------------
|
// Scan Chain Registers and Tasks
|
// Scan Chain Registers and Tasks
|
//-----------------------------------------
|
//-----------------------------------------
|
|
|
// Scan Registers and Initializations
|
// Scan Registers and Initializations
|
|
|
PERL begin
|
PERL begin
|
/*
|
/*
|
DEPERLIFY_INCLUDE(scan_signal_list.pl);
|
DEPERLIFY_INCLUDE(scan_signal_list.pl);
|
|
|
print "`define SCAN_CHAIN_LENGTH $scan_chain_length\n\n";
|
print "`define SCAN_CHAIN_LENGTH $scan_chain_length\n\n";
|
|
|
for (my $i = 0; $i < scalar @signal_list; $i++) {
|
for (my $i = 0; $i < scalar @signal_list; $i++) {
|
|
|
my $begin = 0;
|
my $name = $signal_list[$i]{name};
|
my $end = $signal_list[$i]{size} - 1;
|
my $size = $signal_list[$i]{size};
|
|
my $addr_bits = $signal_list[$i]{addr_bits};
|
|
my $data_bits = $signal_list[$i]{data_bits};
|
|
|
|
if ($signal_list[$i]{addr_bits} == 0) {
|
|
print " reg [$size-1:0] ${name};\n";
|
|
print " reg [$size-1:0] ${name}_read;\n";
|
|
print " initial ${name} = ${size}'d0;\n";
|
|
print " initial ${name}_read = ${size}'d0;\n";
|
|
} else {
|
|
print " reg [$addr_bits-1:0] ${name}_addr;\n";
|
|
print " reg [$data_bits-1:0] ${name}_data;\n";
|
|
print " reg [$data_bits-1:0] ${name}_data_read;\n";
|
|
print " initial ${name}_addr = ${addr_bits}'d0;\n";
|
|
print " initial ${name}_data = ${data_bits}'d0;\n";
|
|
print " initial ${name}_data_read = ${data_bits}'d0;\n";
|
|
}
|
|
|
print " reg [$end:$begin] " . $signal_list[$i]{name} . ";\n";
|
|
print " reg [$end:$begin] " . $signal_list[$i]{name} . "_read;\n";
|
|
print " initial " . $signal_list[$i]{name} . " = " .$signal_list[$i]{size} . "'d0;\n";
|
|
print " initial " . $signal_list[$i]{name} . "_read = " .$signal_list[$i]{size} . "'d0;\n";
|
|
}
|
}
|
|
|
*/
|
*/
|
end
|
end
|
|
|
// Scan chain tasks
|
// Scan chain tasks
|
|
|
task load_chip;
|
task load_chip;
|
begin
|
begin
|
`SCAN_DELAY scan_load_chip = 1;
|
`SCAN_DELAY scan_load_chip = 1;
|
`SCAN_DELAY scan_load_chip = 0;
|
`SCAN_DELAY scan_load_chip = 0;
|
end
|
end
|
endtask
|
endtask
|
|
|
task load_chain;
|
task load_chain;
|
begin
|
begin
|
`SCAN_DELAY scan_load_chain = 1;
|
`SCAN_DELAY scan_load_chain = 1;
|
`SCAN_DELAY scan_phi = 1;
|
`SCAN_DELAY scan_phi = 1;
|
`SCAN_DELAY scan_phi = 0;
|
`SCAN_DELAY scan_phi = 0;
|
`SCAN_DELAY scan_phi_bar = 1;
|
`SCAN_DELAY scan_phi_bar = 1;
|
`SCAN_DELAY scan_phi_bar = 0;
|
`SCAN_DELAY scan_phi_bar = 0;
|
`SCAN_DELAY scan_load_chain = 0;
|
`SCAN_DELAY scan_load_chain = 0;
|
end
|
end
|
endtask
|
endtask
|
|
|
task rotate_chain;
|
task rotate_chain;
|
|
|
integer i;
|
integer i;
|
|
|
reg [`SCAN_CHAIN_LENGTH-1:0] data_in;
|
reg [`SCAN_CHAIN_LENGTH-1:0] data_in;
|
reg [`SCAN_CHAIN_LENGTH-1:0] data_out;
|
reg [`SCAN_CHAIN_LENGTH-1:0] data_out;
|
|
|
begin
|
begin
|
PERL begin
|
PERL begin
|
/*
|
/*
|
DEPERLIFY_INCLUDE(scan_signal_list.pl);
|
DEPERLIFY_INCLUDE(scan_signal_list.pl);
|
|
|
for (my $i = 0; $i < scalar @signal_list; $i++) {
|
for (my $i = 0; $i < scalar @signal_list; $i++) {
|
|
|
|
if ($signal_list[$i]{addr_bits} == 0) {
|
my $begin = $signal_list[$i]{start};
|
my $begin = $signal_list[$i]{start};
|
my $end = $signal_list[$i]{start} + $signal_list[$i]{size} - 1;
|
my $end = $signal_list[$i]{start} + $signal_list[$i]{size} - 1;
|
|
|
print " data_in[$end:$begin] = " . $signal_list[$i]{name} . ";\n";
|
print " data_in[$end:$begin] = " . $signal_list[$i]{name} . ";\n";
|
|
} else {
|
|
my $begin = $signal_list[$i]{start};
|
|
my $end = $signal_list[$i]{start} + $signal_list[$i]{addr_bits} + $signal_list[$i]{data_bits} - 1;
|
|
|
|
print " data_in[$end:$begin] = {" . $signal_list[$i]{name} . "_data, " . $signal_list[$i]{name} . "_addr};\n";
|
|
}
|
}
|
}
|
|
|
*/
|
*/
|
end
|
end
|
|
|
for (i = 0; i < `SCAN_CHAIN_LENGTH; i=i+1) begin
|
for (i = 0; i < `SCAN_CHAIN_LENGTH; i=i+1) begin
|
scan_data_in = data_in[0];
|
scan_data_in = data_in[0];
|
data_out = {scan_data_out, data_out[`SCAN_CHAIN_LENGTH-1:1]};
|
data_out = {scan_data_out, data_out[`SCAN_CHAIN_LENGTH-1:1]};
|
`SCAN_DELAY scan_phi = 1;
|
`SCAN_DELAY scan_phi = 1;
|
`SCAN_DELAY scan_phi = 0;
|
`SCAN_DELAY scan_phi = 0;
|
`SCAN_DELAY scan_phi_bar = 1;
|
`SCAN_DELAY scan_phi_bar = 1;
|
`SCAN_DELAY scan_phi_bar = 0;
|
`SCAN_DELAY scan_phi_bar = 0;
|
`SCAN_DELAY data_in = data_in >> 1;
|
`SCAN_DELAY data_in = data_in >> 1;
|
end
|
end
|
|
|
PERL begin
|
PERL begin
|
/*
|
/*
|
DEPERLIFY_INCLUDE(scan_signal_list.pl);
|
DEPERLIFY_INCLUDE(scan_signal_list.pl);
|
|
|
for (my $i = 0; $i < scalar @signal_list; $i++) {
|
for (my $i = 0; $i < scalar @signal_list; $i++) {
|
|
|
|
if ($signal_list[$i]{addr_bits} == 0) {
|
my $begin = $signal_list[$i]{start};
|
my $begin = $signal_list[$i]{start};
|
my $end = $signal_list[$i]{start} + $signal_list[$i]{size} - 1;
|
my $end = $signal_list[$i]{start} + $signal_list[$i]{size} - 1;
|
|
|
print " " . $signal_list[$i]{name} . "_read = data_out[$end:$begin];\n";
|
print " " . $signal_list[$i]{name} . "_read = data_out[$end:$begin];\n";
|
|
} else {
|
|
my $begin = $signal_list[$i]{start} + $signal_list[$i]{addr_bits};
|
|
my $end = $signal_list[$i]{start} + $signal_list[$i]{addr_bits} + $signal_list[$i]{data_bits} - 1;
|
|
|
|
print " " . $signal_list[$i]{name} . "_data_read = data_out[$end:$begin];\n";
|
|
}
|
}
|
}
|
|
|
*/
|
*/
|
end
|
end
|
end
|
end
|
|
|
endtask
|
endtask
|
|
|
//-----------------------------------------
|
//-----------------------------------------
|
// Scan chain DUT
|
// Scan chain DUT
|
//-----------------------------------------
|
//-----------------------------------------
|
|
|
// We're going to use the name chip_iternal_<NAME> for the signals that would
|
// We're going to use the name chip_iternal_<NAME> for the signals that would
|
// normally be inside the chip that we're interacting with. We'll generate them
|
// normally be inside the chip that we're interacting with. We'll generate them
|
// here
|
// here
|
|
|
PERL begin
|
PERL begin
|
/*
|
/*
|
DEPERLIFY_INCLUDE(scan_signal_list.pl);
|
DEPERLIFY_INCLUDE(scan_signal_list.pl);
|
|
|
for (my $i = 0; $i < scalar @signal_list; $i++) {
|
for (my $i = 0; $i < scalar @signal_list; $i++) {
|
if ($signal_list[$i]{writable} == 1) {
|
if ($signal_list[$i]{writable} == 1) {
|
print " wire ";
|
print " wire ";
|
} else {
|
} else {
|
print " reg ";
|
print " reg ";
|
}
|
}
|
|
|
print "[$signal_list[$i]{size}-1:0] chip_internal_$signal_list[$i]{name};\n";
|
print "[$signal_list[$i]{size}-1:0] chip_internal_$signal_list[$i]{name};\n";
|
}
|
}
|
|
|
*/
|
*/
|
end
|
end
|
|
|
scan scan_dut ( // Inputs & outputs to the chip
|
scan scan_dut ( // Inputs & outputs to the chip
|
PERL begin
|
PERL begin
|
/*
|
/*
|
DEPERLIFY_INCLUDE(scan_signal_list.pl);
|
DEPERLIFY_INCLUDE(scan_signal_list.pl);
|
|
|
for (my $i = 0; $i < scalar @signal_list; $i++) {
|
for (my $i = 0; $i < scalar @signal_list; $i++) {
|
print " .$signal_list[$i]{name}(chip_internal_$signal_list[$i]{name}),\n";
|
print " .$signal_list[$i]{name}(chip_internal_$signal_list[$i]{name}),\n";
|
}
|
}
|
|
|
*/
|
*/
|
end
|
end
|
|
|
// To the pads
|
// To the pads
|
.scan_phi (scan_phi),
|
.scan_phi (scan_phi),
|
.scan_phi_bar (scan_phi_bar),
|
.scan_phi_bar (scan_phi_bar),
|
.scan_data_in (scan_data_in),
|
.scan_data_in (scan_data_in),
|
.scan_data_out (scan_data_out),
|
.scan_data_out (scan_data_out),
|
.scan_load_chip (scan_load_chip),
|
.scan_load_chip (scan_load_chip),
|
.scan_load_chain (scan_load_chain)
|
.scan_load_chain (scan_load_chain)
|
);
|
);
|
|
|
|
|
//-----------------------------------------
|
//-----------------------------------------
|
// Testbench
|
// Testbench
|
//-----------------------------------------
|
//-----------------------------------------
|
|
|
initial begin
|
initial begin
|
|
|
|
$dumpvars(0, tbench);
|
|
|
$display("Starting scan chain test");
|
$display("Starting scan chain test");
|
|
|
scan_phi = 0;
|
scan_phi = 0;
|
scan_phi_bar = 0;
|
scan_phi_bar = 0;
|
scan_data_in = 0;
|
scan_data_in = 0;
|
scan_load_chip = 0;
|
scan_load_chip = 0;
|
scan_load_chain = 0;
|
scan_load_chain = 0;
|
|
|
|
scan_reset = 1'b1;
|
|
|
rotate_chain();
|
rotate_chain();
|
load_chip();
|
load_chip();
|
|
|
|
// Make sure reset worked
|
|
if (chip_internal_write_data_array !== 0)
|
|
$display("RESET TEST FAILED");
|
|
else
|
|
$display("RESET TEST PASSED");
|
|
|
// Write each variable
|
// Write each variable
|
|
scan_reset = 1'b0;
|
|
|
write_data_1 = 1'd1;
|
write_data_1 = 1'd1;
|
write_data_2 = 2'd2;
|
write_data_2 = 2'd2;
|
write_data_3 = 3'd3;
|
write_data_3 = 3'd3;
|
|
|
|
write_data_array_addr = 2'd2;
|
|
write_data_array_data = 4'hA;
|
|
|
rotate_chain();
|
rotate_chain();
|
load_chip();
|
load_chip();
|
|
|
// Check that the chip sees the new variables
|
// Check that the chip sees the new variables
|
if (chip_internal_write_data_1 != 1'd1 ||
|
if (chip_internal_write_data_1 !== 1'd1 ||
|
chip_internal_write_data_2 != 2'd2 ||
|
chip_internal_write_data_2 !== 2'd2 ||
|
chip_internal_write_data_3 != 3'd3 )
|
chip_internal_write_data_3 !== 3'd3 ||
|
|
chip_internal_write_data_array !== 15'h0A00) begin
|
$display("TEST 1 FAILED");
|
$display("TEST 1 FAILED");
|
else
|
$display("%d %d %d %h",
|
|
chip_internal_write_data_1,
|
|
chip_internal_write_data_2,
|
|
chip_internal_write_data_3,
|
|
chip_internal_write_data_array);
|
|
end else
|
$display("TEST 1 PASSED");
|
$display("TEST 1 PASSED");
|
|
|
// Set internal values to read out
|
// Set internal values to read out
|
chip_internal_read_data_1 = 1'd0; // As if the chip had this value internally
|
chip_internal_read_data_1 = 1'd0; // As if the chip had this value internally
|
chip_internal_read_data_2 = 2'd3;
|
chip_internal_read_data_2 = 2'd3;
|
chip_internal_read_data_3 = 3'd5;
|
chip_internal_read_data_3 = 3'd5;
|
|
|
|
chip_internal_read_data_array = 16'hABCD;
|
|
|
// Read all of the values for both writable and non-writable variables
|
// Read all of the values for both writable and non-writable variables
|
|
read_data_array_addr = 2'd1;
|
|
|
|
rotate_chain();
|
load_chain();
|
load_chain();
|
rotate_chain();
|
rotate_chain();
|
|
|
// Check to see that we read out all values properly
|
// Check to see that we read out all values properly
|
if (write_data_1_read != 1'd1 ||
|
if (write_data_1_read !== 1'd1 ||
|
write_data_2_read != 2'd2 ||
|
write_data_2_read !== 2'd2 ||
|
write_data_3_read != 3'd3 ||
|
write_data_3_read !== 3'd3 ||
|
read_data_1_read != 1'd0 ||
|
read_data_1_read !== 1'd0 ||
|
read_data_2_read != 2'd3 ||
|
read_data_2_read !== 2'd3 ||
|
read_data_3_read != 3'd5 ) begin
|
read_data_3_read !== 3'd5 ||
|
|
read_data_array_data_read !== 4'hC) begin
|
$display("TEST 2 FAILED");
|
$display("TEST 2 FAILED");
|
$display("%d %d %d %d %d %d",
|
$display("%d %d %d %d %d %d %h",
|
write_data_1_read,
|
write_data_1_read,
|
write_data_2_read,
|
write_data_2_read,
|
write_data_3_read,
|
write_data_3_read,
|
read_data_1_read,
|
read_data_1_read,
|
read_data_2_read,
|
read_data_2_read,
|
read_data_3_read);
|
read_data_3_read,
|
|
read_data_array_data_read);
|
end else
|
end else
|
$display("TEST 2 PASSED");
|
$display("TEST 2 PASSED");
|
|
|
|
|
$finish;
|
$finish;
|
end
|
end
|
|
|
//////////
|
//////////
|
|
|
endmodule // tbench
|
endmodule // tbench
|
|
|
|
|