//
// LSU EE 4702-1 Spring 2000 Homework 6 Solution
//
module width_change(out,full,complete,empty,outclk,in,inclk,reset);
input outclk, in, inclk, reset;
output out, full, complete, empty;
parameter storage = 32;
wire [7:0] out;
wire [3:0] in;
wire inclk, outclk, full, empty, complete;
reg [storage-1:0] sto;
reg [1:0] head_word;
reg [2:0] tail_nibble;
reg empty_in, empty_out, full_in, full_out;
assign out = empty ? 0 : sto >> { head_word, 3'b0 };
assign empty = empty_in ^ empty_out;
assign full = full_in ^ full_out;
assign complete = !empty &&
( full || head_word != tail_nibble[2:1] );
always @( posedge inclk or posedge reset )
if( reset ) begin
sto[7:0] = 0; tail_nibble = 0; empty_in = 1; full_in = 0;
end else if( !full ) begin
if( empty ) begin empty_in = !empty_in; tail_nibble = 0; end
case ( tail_nibble )
0: sto[7:0] = {4'b0,in};
1: sto[7:4] = in;
2: sto[15:8] = {4'b0,in};
3: sto[15:12] = in;
4: sto[23:16] = {4'b0,in};
5: sto[23:20] = in;
6: sto[31:24] = {4'b0,in};
7: sto[31:28] = in;
endcase
tail_nibble = tail_nibble + 1;
if( tail_nibble[0]==0 && tail_nibble>>1 == head_word )
full_in = !full_in;
end
always @( posedge outclk or posedge reset )
if( reset ) begin
head_word = 0; empty_out = 0; full_out = 0;
end else
if( !empty ) begin
if( full ) begin
full_out = !full_out;
head_word = head_word + 1;
end else if( head_word == ( 3 & (tail_nibble-1)>>1 ) ) begin
empty_out = !empty_out;
head_word = 0;
end else begin
head_word = head_word + 1;
end
end
endmodule // width_change
// exemplar translate_off
module wc_test();
// If non-zero, stop simulation when an error is encountered.
// If zero, when an error is encountered simulation will proceed
// and a count of errors will be displayed.
parameter stop_on_err = 1;
wire [7:0] out;
wire full, empty, comp;
reg outclk, inclk, reset;
reg [3:0] indata;
reg [31:0] shadow;
reg shadow_full, shadow_comp, shadow_empty;
reg [7:0] shadow_head;
integer shadow_occ;
reg check;
integer phasecount;
time remove_delay_limit_short, remove_delay_limit_long;
time remove_delay_limit;
time fill_delay_limit;
time next_empty;
integer allow_simultaneous_clocks;
integer allow_overlapping_clocks;
integer error_out_t, error_out;
integer error_empty_t, error_empty;
integer error_comp_t, error_comp;
integer error_full_t, error_full;
integer error_test, error_test_t;
width_change wc(out,full,comp,empty,outclk,indata,inclk,reset);
function [31:0] randi;
input [31:0] limit;
randi = ( $random >> 1 ) % limit;
endfunction // randi
initial begin
indata = 0; outclk = 0; inclk = 0; reset = 0;
shadow_empty = 1; shadow_comp = 0; shadow_full = 0; shadow_head = 0;
check = 0; shadow = 0; shadow_occ = 0; phasecount = 0;
fill_delay_limit = 20;
remove_delay_limit_short = 0.5 * fill_delay_limit * 2;
remove_delay_limit_long = 2 * fill_delay_limit * 2;
// Start filling.
remove_delay_limit = remove_delay_limit_long;
allow_overlapping_clocks = 0;
allow_simultaneous_clocks = 0;
error_out = 0; error_out_t = 0;
error_empty = 0; error_empty_t = 0;
error_comp = 0; error_comp_t = 0;
error_full = 0; error_full_t = 0;
error_test = 0; error_test_t = 0;
reset = 1; #10 reset = 0; #10;
fork:TESTLOOP
forever begin:FILL
integer clk_fall_delay;
integer clk_rise_delay;
clk_fall_delay = allow_overlapping_clocks ?
randi(fill_delay_limit)+1 : 1;
clk_rise_delay = randi(fill_delay_limit)+1;
indata <= #(10*randi(clk_rise_delay)) $random;
#(10*clk_rise_delay);
// Special case: if FIFO is full or empty and data is
// simultaneously clocked in and out there's no way to
// tell if FIFO rejected the data begin clocked in.
while( next_empty == $time &&
( !allow_simultaneous_clocks ||
shadow_occ >= 20 || shadow_occ < 12 )) #10;
inclk = 1;
check <= #1 !check;
shadow_empty = 0;
if( !shadow_full ) begin
shadow_occ = shadow_occ + 4;
shadow = { indata, shadow[31:4] };
if( shadow_occ > 28 )
begin
shadow_full = 1;
if( remove_delay_limit === remove_delay_limit_long ) begin
remove_delay_limit = remove_delay_limit_short;
phasecount = phasecount + 1;
end
end
if( shadow_occ > 7 ) shadow_comp = 1;
end
shadow_head = shadow >> ( 32 - shadow_occ );
indata <= #(10*randi(clk_fall_delay)) $random;
inclk = #(10*clk_fall_delay) 0;
end
forever begin:EMPTY
integer clk_fall_delay;
integer clk_rise_delay;
clk_fall_delay = allow_overlapping_clocks ?
randi(remove_delay_limit)+1 : 1;
clk_rise_delay = randi(remove_delay_limit)+1;
next_empty = $time + 10 * clk_rise_delay;
outclk = #(10*clk_rise_delay) 1;
check <= #1 !check;
shadow_full = 0;
if( !shadow_empty ) begin
if( shadow_occ <= 8 ) begin
shadow_occ = 0; shadow_empty = 1;
remove_delay_limit = remove_delay_limit_long;
end else begin
shadow_occ = shadow_occ - 8;
end
shadow_head = shadow >> ( 32 - shadow_occ );
if( shadow_occ < 8 ) shadow_comp = 0;
end
outclk = #(10*clk_fall_delay) 0;
end // block: EMPTY
forever @( out or check ) #1
if( out !== shadow_head ) begin
if( stop_on_err ) begin
$display("Wrong output.");
#2 $stop;
end
error_out = error_out + 1;
end
forever @( empty or check ) #1
if( empty !== shadow_empty ) begin
if( stop_on_err ) begin
$display("Wrong empty.");
#2 $stop;
end
error_empty = error_empty + 1;
end
forever @( comp or check ) #1
if( comp !== shadow_comp ) begin
if( stop_on_err ) begin
$display("Wrong complete.");
#2 $stop;
end
error_comp = error_comp + 1;
end
forever @( full or check ) #1
if( full !== shadow_full ) begin
if( stop_on_err ) begin
$display("Wrong full.");
#2 $stop;
end
error_full = error_full + 1;
end
forever @( phasecount ) begin:P
reg [84:0] test_name;
if( phasecount == 200 || phasecount == 400 || phasecount == 600 )
begin
error_test = error_out + error_empty + error_comp + error_full;
error_test_t = error_test_t + error_test;
error_out_t = error_out_t + error_out;
error_empty_t = error_empty_t + error_empty;
error_comp_t = error_comp_t + error_comp;
error_full_t = error_full_t + error_full;
case( phasecount )
200:test_name = "No Overlap";
400:test_name = "Not Simult";
600:test_name = "Full Test";
endcase // case( phasecount )
$display("Test %s. Total Errors %d. Errors by type:",
test_name, error_test);
$display(" Output %d, empty %d, compl %d, full %d",
error_out, error_empty, error_comp, error_full);
if( phasecount == 200 ) begin
allow_overlapping_clocks = 1;
if( error_test === 0 )
$display("Passed all non-overlapping tests!!");
end else if ( phasecount == 400 ) begin
allow_simultaneous_clocks = 1;
if( error_test === 0 )
$display("Passed all overlapping-but-not-simultaneous tests!!!!!");
end else if ( phasecount == 600 ) begin
if( error_test === 0 )
$display("Passed all simultaneous clock tests!!!!!!!");
if( error_test_t === 0 )
$display("Passed EVERY test! PERFECT!!!!!!!!!!!!!!!");
else
$display("Failed %d tests. :-(",error_test_t);
disable TESTLOOP;
end
error_out = 0; error_empty = 0; error_comp = 0; error_full = 0;
error_test = 0;
end // if ( phasecount == 200 || phasecount == 400 || phasecount == 600 )
end
join
end // initial begin
endmodule // wc_test
// exemplar translate_on