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

 /// Assignment  http://www.ece.lsu.edu/koppel/v/2017/hw04.pdf

 /// 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
  //
  // (3) Log in to a Linux workstation.
  //
  // (4) If you haven't already, follow the account setup instructions here:
  //     http://www.ece.lsu.edu/koppel/v/proc.html
  //
  // (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.


 /// Additional Resources
  //
  // Verilog Documentation
  //    The Verilog Standard
  //      http://standards.ieee.org/getieee/1800/download/1800-2012.pdf
  //    Introductory Treatment (Warning: Does not include SystemVerilog)
  //      Brown & Vranesic, Fundamentals of Digital Logic with Verilog, 3rd Ed.
  //
  // Account Setup and Emacs (Text Editor) Instructions
  //      http://www.ece.lsu.edu/koppel/v/proc.html
  //      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.
 //  See  http://www.ece.lsu.edu/koppel/v/2017/hw04.pdf
//
//     [ ] 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.)


// cadence translate_off

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 [char_wid-1:0] char, shadow_last_char;
   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;
      int shadow_mr_len, shadow_mr_char, shadow_cr_len;
      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 );

         shadow_last_char = char;

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

         if ( !do_reset && char === shadow_last_char )
           shadow_cr_len++;
         else
           shadow_cr_len = 1;

         if ( do_reset )
            shadow_mr_len = 0;

         if ( shadow_cr_len > shadow_mr_len ) begin
            shadow_mr_len = shadow_cr_len;
            shadow_mr_char = char;
         end

         @( posedge clk_reactive );

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

         is_err_cr_len = shadow_cr_len !== cr_len;
         is_err_mr_len = shadow_mr_len !== mr_len;
         is_err_mr_char = shadow_mr_char !== mr_char[0];

         $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

// cadence translate_on