OpenCores
URL https://opencores.org/ocsvn/scan_based_serial_communication/scan_based_serial_communication/trunk

Subversion Repositories scan_based_serial_communication

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /scan_based_serial_communication/trunk
    from Rev 3 to Rev 4
    Reverse comparison

Rev 3 → Rev 4

/SCAN_README.txt
9,6 → 9,7
 
VERSION
1.0 - June 27, 2010
1.1 - January 7, 2011
 
SCAN DESCRIPTION
This is a simple scan chain implemented with deperlify. It has been
47,7 → 48,17
the chip data has been loaded into the scan chain, clock out the
data as normal.
 
Due to the buffering latch, complex internal interfaces can be
To create a large number of bits, address and data fields may
be created for a signal. 2^addr_bits*data_bits must be greater
than the size. In this way, only addr_bits+data_bits number of
bits may be generated in the scan chain, which reduces the
length of the scan chain, as well as the area, since latches
are much smaller than the muxing elements needed for the
chain. Since this is a new feature, the size specified by the
address and data bits should most likely match the total size
in order to avoid bugs.
 
Due to the buffering latches, complex internal interfaces can be
emulated using the scan chain. For instance, an SRAM could be
connected to a clock, chip select, write enable, 64-bit data-in,
and 64-bit data-out, all of which are connected to the scan
61,14 → 72,8
 
EXAMPLE DESCRIPTION
To run the example, use deperlify to generate scan.v and
scan_testbench.v:
To run the example, call "make". The example uses Synopsys VCS.
 
perl deperlify.pl scan.perl.v
perl depeflify.pl scan_testbench.perl.v
 
Then use your Verilog simulator of choice.
 
This example takes advantage of the DEPERLIFY_INCLUDE command. The
scan.perl.v file reads in the data structure scan_signal_list.pl
in order to generate the scan chain. The file scan_testbench.perl.v
/scan_signal_list.pl
1,24 → 1,67
 
 
# The list at the beginning defines the scan lists. Defining an input name or output
# name determines what type of scan signal it is.
 
# This must be defined, whether or not it's used
my $scan_reset_name = 'scan_reset';
 
# Values are always readable (the buffering latch is what is read if writable)
my @signal_list = ( # Inputs - outside to chip
{ size => 1, writable => 1, name => $scan_reset_name},
 
my @signal_list = ( # Inputs - outside to chip
{ size => 1, writable => 1, name => 'write_data_1'},
{ size => 2, writable => 1, name => 'write_data_2'},
{ size => 3, writable => 1, name => 'write_data_3'},
 
{ size => 15, writable => 1, name => 'write_data_array', addr_bits => 2, data_bits => 4},
 
# Outputs - chip to outside
{ size => 1, writable => 0, name => 'read_data_1'},
{ size => 2, writable => 0, name => 'read_data_2'},
{ size => 3, writable => 0, name => 'read_data_3'},
 
{ size => 16, writable => 0, name => 'read_data_array', addr_bits => 2, data_bits => 4},
);
 
 
 
# We're going to calculate the total scan chain length.
# We also use this to set some key values and do some error checking, so do not comment out this section.
my $scan_chain_length = 0;
my $reset_exists = 0;
my $scan_reset_bit = -1;
 
for (my $i = 0; $i < scalar @signal_list; $i++) {
$signal_list[$i]{start} = $scan_chain_length;
$scan_chain_length += $signal_list[$i]{size};
# Check to see if we have a reset signal
if ($signal_list[$i]{name} eq $scan_reset_name) {
$scan_reset_exists = 1;
$scan_reset_bit = $scan_chain_length;
}
 
# Here we set the default values for the addr_bits and data_bits fields
$signal_list[$i]{addr_bits} = 0 if (!exists $signal_list[$i]{addr_bits});
$signal_list[$i]{data_bits} = 0 if (!exists $signal_list[$i]{data_bits});
# It's an array if either of these values are set
if ($signal_list[$i]{addr_bits} == 0 && $signal_list[$i]{data_bits} == 0) {
 
# Default case is that nothing is set so we just add the size
$scan_chain_length += $signal_list[$i]{size};
 
} else {
# Let's do some error checking while we're at it: 2^addr_bits * data_bits >= size
if ((1 << $signal_list[$i]{addr_bits}) * $signal_list[$i]{data_bits} < $signal_list[$i]{size}) {
print STDERR "SCAN ERROR: addr_bits ($signal_list[$i]{addr_bits}) and data_bits ( $signal_list[$i]{data_bits})";
print STDERR " are not big enough to fit size ($signal_list[$i]{size}) for $signal_list[$i]{name}\n";
die;
}
# Passed the error checking, we're instead going to have address and data fields
$scan_chain_length += $signal_list[$i]{addr_bits};
$scan_chain_length += $signal_list[$i]{data_bits};
 
}
}
/scan_testbench.perl.v
21,13 → 21,25
 
for (my $i = 0; $i < scalar @signal_list; $i++) {
my $begin = 0;
my $end = $signal_list[$i]{size} - 1;
 
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";
my $name = $signal_list[$i]{name};
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";
}
}
*/
67,10 → 79,17
for (my $i = 0; $i < scalar @signal_list; $i++) {
my $begin = $signal_list[$i]{start};
my $end = $signal_list[$i]{start} + $signal_list[$i]{size} - 1;
print " data_in[$end:$begin] = " . $signal_list[$i]{name} . ";\n";
if ($signal_list[$i]{addr_bits} == 0) {
my $begin = $signal_list[$i]{start};
my $end = $signal_list[$i]{start} + $signal_list[$i]{size} - 1;
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";
}
}
*/
92,10 → 111,17
for (my $i = 0; $i < scalar @signal_list; $i++) {
my $begin = $signal_list[$i]{start};
my $end = $signal_list[$i]{start} + $signal_list[$i]{size} - 1;
print " " . $signal_list[$i]{name} . "_read = data_out[$end:$begin];\n";
if ($signal_list[$i]{addr_bits} == 0) {
my $begin = $signal_list[$i]{start};
my $end = $signal_list[$i]{start} + $signal_list[$i]{size} - 1;
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";
}
}
*/
157,6 → 183,8
initial begin
 
$dumpvars(0, tbench);
$display("Starting scan chain test");
scan_phi = 0;
164,24 → 192,43
scan_data_in = 0;
scan_load_chip = 0;
scan_load_chain = 0;
 
scan_reset = 1'b1;
rotate_chain();
load_chip();
 
// Write each variable
// Make sure reset worked
if (chip_internal_write_data_array !== 0)
$display("RESET TEST FAILED");
else
$display("RESET TEST PASSED");
// Write each variable
scan_reset = 1'b0;
write_data_1 = 1'd1;
write_data_2 = 2'd2;
write_data_3 = 3'd3;
 
write_data_array_addr = 2'd2;
write_data_array_data = 4'hA;
 
rotate_chain();
load_chip();
// Check that the chip sees the new variables
if (chip_internal_write_data_1 != 1'd1 ||
chip_internal_write_data_2 != 2'd2 ||
chip_internal_write_data_3 != 3'd3 )
$display("TEST 1 FAILED");
else
if (chip_internal_write_data_1 !== 1'd1 ||
chip_internal_write_data_2 !== 2'd2 ||
chip_internal_write_data_3 !== 3'd3 ||
chip_internal_write_data_array !== 15'h0A00) begin
$display("TEST 1 FAILED");
$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");
// Set internal values to read out
189,28 → 236,34
chip_internal_read_data_2 = 2'd3;
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_data_array_addr = 2'd1;
rotate_chain();
load_chain();
rotate_chain();
 
// Check to see that we read out all values properly
if (write_data_1_read != 1'd1 ||
write_data_2_read != 2'd2 ||
write_data_3_read != 3'd3 ||
read_data_1_read != 1'd0 ||
read_data_2_read != 2'd3 ||
read_data_3_read != 3'd5 ) begin
if (write_data_1_read !== 1'd1 ||
write_data_2_read !== 2'd2 ||
write_data_3_read !== 3'd3 ||
read_data_1_read !== 1'd0 ||
read_data_2_read !== 2'd3 ||
read_data_3_read !== 3'd5 ||
read_data_array_data_read !== 4'hC) begin
$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_2_read,
write_data_3_read,
read_data_1_read,
read_data_2_read,
read_data_3_read);
read_data_3_read,
read_data_array_data_read);
end else
$display("TEST 2 PASSED");
 
$finish;
end
/scan.perl.v
45,9 → 45,9
for (my $i = 0; $i < scalar @signal_list; $i++) {
if ($signal_list[$i]{writable} == 1) {
print " output reg ";
print " output reg ";
} else {
print " input ";
print " input ";
}
print "[$signal_list[$i]{size}-1:0] $signal_list[$i]{name};\n";
76,19 → 76,43
print " reg [$scan_chain_length-1:0] scan_slave;\n\n";
 
# Print scan_load and scan_next logic
print " wire [$scan_chain_length-1:0] scan_load;\n";
print " reg [$scan_chain_length-1:0] scan_load;\n";
print " wire [$scan_chain_length-1:0] scan_next;\n\n";
print " always @ (*) begin\n";
for (my $i = 0; $i < scalar @signal_list; $i++) {
 
my $begin = $signal_list[$i]{start};
my $end = $signal_list[$i]{start} + $signal_list[$i]{size} - 1;
my $name = $signal_list[$i]{name};
my $size = $signal_list[$i]{size};
my $addr_bits = $signal_list[$i]{addr_bits};
my $data_bits = $signal_list[$i]{data_bits};
print " assign scan_load[$end:$begin] = " . $signal_list[$i]{name} . ";\n";
my $size_begin = $signal_list[$i]{start};
my $size_end = $size_begin + $size - 1;
my $addr_begin = $signal_list[$i]{start};
my $addr_end = $addr_begin + $addr_bits - 1;
my $data_begin = $addr_end + 1;
my $data_end = $data_begin + $data_bits - 1;
 
if ($signal_list[$i]{addr_bits} == 0) {
print " scan_load[$size_end:$size_begin] = ${name};\n";
} else {
print " scan_load[$addr_end:$addr_begin] = scan_slave[$addr_end:$addr_begin];\n";
print " case (scan_slave[$addr_end:$addr_begin])\n";
for (my $a = 0; ($a+1-1)*$data_bits < $size; $a++) {
print " ${addr_bits}'d${a}: scan_load[$data_end:$data_begin] = ${name}[$a*$data_bits +: $data_bits];\n";
}
print " endcase\n";
}
}
print "\n assign scan_next = scan_load_chain ? scan_load : {scan_data_in, scan_slave[$'$scan_chain_length-1:1]};\n\n";
print " end\n\n";
print " assign scan_next = scan_load_chain ? scan_load : {scan_data_in, scan_slave[$'$scan_chain_length-1:1]};\n\n";
# Print latches
print " //synopsys one_hot \"scan_phi, scan_phi_bar\"\n";
print " always @ (*) begin\n";
99,15 → 123,42
print " end\n\n";
# Print input latches
print " always @ (*) if (scan_load_chip) begin\n";
for (my $i = 0; $i < scalar @signal_list; $i++) {
if ($signal_list[$i]{writable} == 1) {
my $begin = $signal_list[$i]{start};
my $end = $signal_list[$i]{start} + $signal_list[$i]{size} - 1;
my $name = $signal_list[$i]{name};
print " always @ (*) if (scan_load_chip) $name = scan_slave[$end:$begin];\n";
my $name = $signal_list[$i]{name};
my $size = $signal_list[$i]{size};
my $addr_bits = $signal_list[$i]{addr_bits};
my $data_bits = $signal_list[$i]{data_bits};
my $size_begin = $signal_list[$i]{start};
my $size_end = $size_begin + $size - 1;
my $addr_begin = $signal_list[$i]{start};
my $addr_end = $addr_begin + $addr_bits - 1;
my $data_begin = $addr_end + 1;
my $data_end = $data_begin + $data_bits - 1;
if ($signal_list[$i]{addr_bits} == 0) {
print " $name = scan_slave[$size_end:$size_begin];\n";
} else {
if ($scan_reset_exists) {
print " if (scan_slave[$scan_reset_bit]) ${name} = ${size}'d0; else\n";
}
print " case (scan_slave[$addr_end:$addr_begin])\n";
for (my $a = 0; ($a+1-1)*$data_bits < $size; $a++) {
print " ${addr_bits}'d${a}: ${name}[$a*$data_bits +: $data_bits] = scan_slave[$data_end:$data_begin];\n";
}
print " endcase\n";
}
}
}
print " end\n\n";
# Print data_out
print " assign scan_data_out = scan_slave[0];\n";
/deperlify.pl
167,16 → 167,17
 
open (BLOCK_CODE, ">" . $temp_file);
print BLOCK_CODE $text;
# run perl on block
$generated_text = `perl $temp_file`;
`rm $temp_file`;
 
# Check for errors in the eval statement
if ($@) {
print "Error in perl section:\n" . $text . "\n ERRORS: \n" . $@;
# Stop if there's an error
if ($? != 0) {
die;
}
 
`rm $temp_file`;
 
return $generated_text;
}
 
/Makefile
0,0 → 1,17
 
VV = vcs
VVOPTS = -o $@ +v2k +vc -sverilog -timescale=1ns/1ps +vcs+lic+wait +multisource_int_delays +neg_tchk +libext+.v+.vlib+.vh
 
TESTBENCH_SOURCE = scan_testbench.v scan.v
 
all: run_test
 
%.v: %.perl.v deperlify.pl scan_signal_list.pl
perl deperlify.pl $*.perl.v
 
testbench.exe: $(TESTBENCH_SOURCE)
$(VV) $(VVOPTS) $(TESTBENCH_SOURCE) | tee $@.log
 
run_test: testbench.exe
./testbench.exe
 

powered by: WebSVN 2.1.0

© copyright 1999-2021 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.