```//
// 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 [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;
end else if( head_word == ( 3 & (tail_nibble-1)>>1 ) ) begin
empty_out = !empty_out;
end else begin
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        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;
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 ||

inclk = 1;
check <= #1 !check;

begin
if( remove_delay_limit === remove_delay_limit_long ) begin
remove_delay_limit = remove_delay_limit_short;
phasecount = phasecount + 1;
end
end
end

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;

if( shadow_occ <= 8 ) begin
remove_delay_limit = remove_delay_limit_long;
end else begin
end
end
outclk = #(10*clk_fall_delay) 0;
end // block: EMPTY

forever @( out or check ) #1
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

```