////////////////////////////////////////////////////////////////////////////////
//
/// LSU EE 4755 Fall 2017 Homework 4
//

///

/// Instructions:
//
// (1) Find the undergraduate workstation laboratory, room 126 EE
//     Building.
//
// (2) Locate your account.  If you did not get an account please
//     E-mail: koppel@ece.lsu.edu
//
//
// (4) If you haven't already, follow the account setup instructions here:
//       //
// (5) Copy this assignment, local path name
//     /home/faculty/koppel/pub/ee4755/hw/2017/hw04
//     to a directory ~/hw04 in your class account. (~ is your home
//     directory.) Use this file for your solution.
///      BE SURE THAT YOUR FILE IS CORRECTLY NAMED AND IN THE RIGHT PLACE.
//
// (6) Find the problems in this file and solve them.
//
//     Your entire solution should be in this file.
//
//     Do not change module names.
//
// (7) Your solution will automatically be copied from your account by
//     the TA-bot.

//
// Verilog Documentation
//    The Verilog Standard
//        //    Introductory Treatment (Warning: Does not include SystemVerilog)
//      Brown & Vranesic, Fundamentals of Digital Logic with Verilog, 3rd Ed.
//
// Account Setup and Emacs (Text Editor) Instructions
//        //      To learn Emacs look for Emacs tutorial.

`default_nettype none

//////////////////////////////////////////////////////////////////////////////
///  Problem 1
//
/// Modify maxrun so that it keeps track of the current and maximum runs.
//  //
//     [ ] Make sure that the testbench does not report errors.
//     [ ] Module must be synthesizable.
//     [ ] Code must be reasonably efficient.

module maxrun
#( int w = 2,
int c = 4 )
( output uwire [w-1:0] len,
output logic [c-1:0] mr_char,
input uwire clk, reset, mr,
input uwire [c-1:0] in_char );

endmodule

//////////////////////////////////////////////////////////////////////////////
/// Testbench Code
//
//  The code below instantiates some of the modules above,
//  provides test inputs, and verifies the outputs.
//
//  The testbench may be modified to facilitate your solution. Of
//  course, the removal of tests which your module fails is not a
//  method of fixing a broken module. (One might modify the testbench
//  so that the first tests it performs are those which make it easier
//  to determine what the problem is, for example, test inputs that
//  are all 0's or all 1's.)

program reactivate
(output uwire clk_reactive, output int cycle_reactive,
input uwire clk, input var int cycle);
assign clk_reactive = clk;
assign cycle_reactive = cycle;
endprogram

module testbench;

localparam int char_wid = 8;
localparam int count_wid = 10;

localparam int test_num_chars = 100;
localparam int cycle_limit = test_num_chars + 20;

localparam int nmuts = 1;

localparam int char_mask = ( 1 << char_wid ) - 1;

uwire [count_wid-1:0] len[nmuts];
uwire [char_wid-1:0] mr_char[nmuts];
logic mr;

logic clock, reset;
bit done;
int cycle;

logic clk_reactive;
int cycle_reactive;
reactivate ra(clk_reactive,cycle_reactive,clock,cycle);

initial begin
clock = 0;
cycle = 0;

fork
forever #10 cycle += clock++;
wait( done );
wait( cycle >= cycle_limit )
\$write("*** Cycle limit exceeded, ending.\n");
join_any;

\$finish();
end

maxrun #(count_wid,char_wid) mr1 (len[0],mr_char[0],clock,reset,mr,char);

initial begin

automatic int n_err_cr_len = 0, n_err_mr_len = 0, n_err_mr_char = 0;
bit is_err_cr_len, is_err_mr_len, is_err_mr_char;

done = 0;
reset = 0;
char = 0;
mr = 0;

@( posedge clk_reactive );

for ( int i=0; i<test_num_chars; i++ ) begin

automatic bit do_reset = i == 0 || {\$random} % 10 == 0;
automatic bit do_new_char = {\$random} % 3 == 0;
logic [count_wid-1:0] mr_len, cr_len;

@( negedge clock );

if ( do_new_char ) char = {\$random} & char_mask;
reset = do_reset;

if ( !do_reset && char === shadow_last_char )
else

if ( do_reset )

end

@( posedge clk_reactive );

repeat ( 2 ) begin
if ( mr ) mr_len = len[0]; else cr_len = len[0];
mr = !mr;
#0; #0;
end

\$write
("%5d %1s c=%2x    cr_len %3d %s    mr_len %3d %s    mr_c %2x %s\n",
i, do_reset ? "r" : " ", char,
cr_len,
is_err_cr_len ? \$sformatf("!= %3d", shadow_cr_len) : "ok    ",
mr_len,
is_err_mr_len ? \$sformatf("!= %3d", shadow_mr_len) : "ok    ",
mr_char[0],
is_err_mr_char ? \$sformatf("!= %2x", shadow_mr_char) : "ok   " );

if ( shadow_cr_len !== cr_len ) n_err_cr_len++;
if ( shadow_mr_len !== mr_len ) n_err_mr_len++;
if ( shadow_mr_char !== mr_char[0] ) n_err_mr_char++;

end

\$write("Done with %0d tests, %0d %0d %0d errors found.\n",
test_num_chars,
n_err_cr_len,
n_err_mr_len,
n_err_mr_char);

done = 1;

end

endmodule