// // 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