///////////////////////////////////////////////////////////////////////////////
//
/// Integer Compression
//
 // See LSU EE 4755 Fall 2014 Homework 4 for a description.
 // https://www.ece.lsu.edu/koppel/v/2014f/hw04.pdf
 //
 // Follow-up problems in 2015 Homework 6
 // https://www.ece.lsu.edu/koppel/v/2015/hw06.pdf
 // https://www.ece.lsu.edu/koppel/v/2015/hw06_sol.pdf


/// Summary of Modules
//
 /// icomp_none
 //
 //  Buffers characters but does not perform any compression.
 //
 //
 /// icomp_1cyc
 //
 //  Performs compression.
 //  Has a 1-cycle minimum delay.
 //
 //
 /// icomp_2cyc
 //
 //  Performs compression.
 //  Has a 2-cycle minimum delay.


`default_nettype none

typedef enum
  { Char_escape = 1, Char_EOS = 255, Char_0 = 48, Char_9 = 57 } Chars_Special;

module icomp_none
  #( int size_lg = 4,
     int n_bytes_binary = 4,
     int size = 1 << size_lg )
  ( output uwire [7:0] char_out,
    output uwire can_insert, can_remove,
    input uwire [7:0] char_in,
    input uwire insert_req, remove_req,
    input uwire reset, clk);

   logic [7:0] storage [size];

   logic [size_lg:1] head, tail;

   uwire   empty = head == tail;
   uwire   full = tail + 1 == head;

   assign can_insert = !full;
   assign can_remove = !empty;

   assign char_out = storage[head];

   always_ff @( posedge clk ) if ( reset ) begin

      tail <= 0;

   end else begin

      if ( insert_req ) begin

         storage[tail] = char_in;
         tail <= tail + 1;

      end

   end

   always_ff @( posedge clk ) if ( reset ) begin

      head <= 0;

   end else if ( remove_req ) begin

      head <= head + 1;

   end

   ///
   /// Objects for use by testbench only.
   //
   //  The objects below serve no purpose in this module, but objects
   //  with the same names are used in the modules that compress, such
   //  as icomp_1cyc. The testbench looks for these objects and so they
   //  cannot be omitted.
   //
   // cadence translate_off
   logic [n_bytes_binary-1:0][7:0] incoming_val_binary, outgoing_val_binary;
   logic start_encoding, now_encoding, end_encoding, use_encoding;
   logic start_draining, end_draining, have_outgoing_val_binary;
   uwire [size_lg:1] write_idx;
   logic [size_lg:1] tail_at_enc_start;
   logic [7:0] incoming_n_bytes_ascii;
   // cadence translate_on

endmodule


module icomp_1cyc
  #( int size_lg = 4,
     int n_bytes_binary = 4,
     int size = 1 << size_lg )
  ( output uwire [7:0] char_out,
    output uwire can_insert, can_remove,
    input uwire [7:0] char_in,
    input uwire insert_req, remove_req,
    input uwire reset, clk);

   // Storage for characters.
   logic [7:0] storage [size];

   // Location at which encoded number should start.  That is,
   // if esc_here[x] is 1, then storage[x] is the first character of
   // an ASCII string that should be replaced with an escape character
   // and a binary encoded value;
   logic esc_here [size];

   // Register used for encoding integer into binary.
   logic [n_bytes_binary-1:0][7:0] incoming_val_binary;

   // Register for holding binary integer until all characters removed.
   logic [n_bytes_binary-1:0][7:0] outgoing_val_binary;

   // True if outgoing_val_binary holds a value that has not yet been read.
   logic have_outgoing_val_binary;

   // Pointers into storage.
   logic [size_lg:1] head;       // Location being read (sent to module output).
   uwire [size_lg:1] write_idx;  // Next location to write.
   logic [size_lg:1] tail;       // Possible next location to write.
   logic [size_lg:1] tail_at_enc_start;


   // Current length of ASCII integer being encoded.
   logic [7:0] incoming_n_bytes_ascii;

   // Note: draining refers to sending the bytes in
   // outgoing_val_binary to the module outputs.
   logic draining;
   logic [$clog2(n_bytes_binary)-1:0] drain_idx;
   uwire   start_draining, end_draining;

   uwire   empty, full;

   ///
   /// Hardware For Encoding ASCII Digits into Binary
   ///

   // Check whether a digit is present.
   //
   uwire is_digit =    char_in >= Char_0 && char_in <= Char_9;
   uwire is_nz_digit = char_in >  Char_0 && char_in <= Char_9;  // Non-Zero

   // Convert ASCII digit to an integer.
   //
   uwire [3:0] char_bin = char_in - Char_0;

   // Combine digit at char_in with current value of incoming_val_binary.
   //
   uwire [n_bytes_binary:0] [7:0] next_incoming_val_binary =
                            incoming_val_binary * 10 + char_bin;
   uwire overflow = next_incoming_val_binary[n_bytes_binary] != 0;

   ///
   /// Hardware to Detect the Start, End, and Suitability of a String of Digits
   //

   // Note: encoding refers to the process of converting a string of
   // ASCII characters to an integer.
   logic was_encoding;

   logic was_digit;
   always_ff @( posedge clk )
     if ( reset )           was_digit <= 0;
     else if ( insert_req ) was_digit <= is_digit;

   // True if we should start encoding a string of digits.
   uwire start_encoding =
        insert_req && is_nz_digit && ( !was_digit || overflow );

   // True if encoding should end, whether or not the encoding will be used.
   uwire end_encoding =
          insert_req && was_encoding && ( !is_digit || overflow );

   uwire now_encoding = start_encoding || was_encoding && !end_encoding;
   always_ff @( posedge clk )
     if ( reset )           was_encoding <= 0;
     else if ( insert_req ) was_encoding <= now_encoding;

   // True if encoded integer should be used.
   // We don't want to do this if the ASCII string is too short,
   // or if outgoing_val_binary is still occupied.
   uwire use_encoding = end_encoding
        && ( incoming_n_bytes_ascii > n_bytes_binary )
        && ( !have_outgoing_val_binary || end_draining );

   // Update registers holding encoded integer, and those keeping
   // track of locations.
   //
   always_ff @( posedge clk ) if ( insert_req ) begin

      if ( start_encoding ) begin

         // Initialize incoming_val_binary with first character.
         incoming_val_binary <= char_bin;

         // Remember where ASCII digits started.
         tail_at_enc_start <= write_idx;

         // Keep track of how many digits there are.
         incoming_n_bytes_ascii <= 1;

      end else begin

         // Update registers assuming that we are continuing to
         // encode. (It doesn't hurt if we are not currently encoding.)
         incoming_val_binary <= next_incoming_val_binary;
         incoming_n_bytes_ascii <= incoming_n_bytes_ascii + 1;

      end

      // Move incoming_val_binary to a second register so that the
      // next string of ASCII digits can be encoded without having to
      // wait for this value to be removed.
      if ( use_encoding ) outgoing_val_binary <= incoming_val_binary;

   end


   ///
   /// Hardware for Writing Characters into Storage
   ///

   // If the encoded integer is used we need to move the tail back by
   // the number of characters saved. That's easier to compute using
   // the location at which the encoded number started.
   uwire [size_lg:1] tail_adj = tail_at_enc_start + n_bytes_binary + 1;

   // Location at which to write current character.
   assign write_idx = use_encoding ? tail_adj : tail;


   /// Write the Storage and the Tail Pointer
   //
   always_ff @( posedge clk ) if ( reset ) begin

      tail <= 0;

   end else begin

      if ( insert_req ) begin

         esc_here[write_idx] <= 0;

         storage[write_idx] <= char_in;

         tail <= write_idx + 1;

      end

      // If we've decided to use an encoded number remember
      // where. When head reaches tail_at_enc_start we will start
      // sending the encoded number to the output.
      if ( use_encoding ) esc_here[tail_at_enc_start] <= 1;

   end


   ///
   /// Hardware For Removing Characters From Storage
   ///

   /// Character Out Mux
   //
   //  The char_out port can be connected to three things:
   //
   //    - A memory holding stored characters: storage[].
   //    - The escape character (a constant, Char_escape).
   //    - A register holding a number encoded in binary, outgoing_val_binary.
   //
   assign char_out =
          start_draining  ?  Char_escape :
          draining        ?  outgoing_val_binary[drain_idx] :
                             storage[head];

   assign start_draining = !empty && esc_here[head];
   assign end_draining = remove_req && draining && drain_idx == 0;

   // Update the register that indicates whether outgoing_val_binary is holding
   // something.
   always_ff @( posedge clk )

     if ( reset )             have_outgoing_val_binary <= 0;
     else if ( use_encoding ) have_outgoing_val_binary <= 1;
     else if ( end_draining ) have_outgoing_val_binary <= 0;

   always_ff @( posedge clk ) if ( reset ) begin

      draining <= 0;
      drain_idx <= 0;
      head <= 0;

   end else begin
      if ( remove_req ) begin

         head <= head + 1;

         drain_idx <= start_draining  ?  n_bytes_binary-1 :
                      drain_idx > 0   ?  drain_idx - 1 :
                                         0;

         draining <= start_draining  ?  1 :
                     remove_req && drain_idx == 0  ?  0 :
                     draining;

      end


   end


   ///
   /// Hardware to Related to Storage Full and Empty Status
   ///

   assign empty = head == tail;
   assign full = tail + 1 == head;

   assign can_remove = !empty && ( !was_encoding || head != tail_at_enc_start );
   assign can_insert = !full;

endmodule



module icomp_2cyc
  #( int size_lg = 4,
     int n_bytes_binary = 4,
     bit separate_port = 1 )
  ( output uwire [7:0] char_out,
    output uwire can_insert, can_remove,
    input uwire [7:0] char_in,
    input uwire insert_req, remove_req,
    input uwire reset, clk);

   localparam int size = 1 << size_lg;

   // Storage for characters.
   logic [7:0] storage [size];

   // Location at which encoded number should start.  That is,
   // if esc_here[x] is 1, then storage[x] is the first character of
   // an ASCII string that should be replaced with an escape character
   // and a binary encoded value;
   logic esc_here [size];

   // Registers used for preparing encoded integer.
   logic [n_bytes_binary:0][7:0] incoming_val_binary_1, incoming_val_binary_2;

   // Register for holding encoded integer until all characters removed.
   logic [n_bytes_binary-1:0][7:0] outgoing_val_binary;

   // True if outgoing_val_binary holds a value that has not yet been read.
   logic have_outgoing_val_binary;

   // Pointers into storage.
   logic [size_lg:1] head;      // Location being read (sent to module output).
   uwire [size_lg:1] write_idx_1;  // Next location to write.
   logic [size_lg:1] tail_1;      // Possible next location to write.
   logic [size_lg:1] tail_at_enc_start_1;

   logic [7:0] incoming_n_bytes_ascii;

   // Note: draining refers to sending the bytes in outgoing_val_binary to the
   // module outputs.
   logic draining;
   logic [$clog2(n_bytes_binary)-1:0] drain_idx;
   uwire   start_draining, end_draining;

   uwire   empty, full;

   ///
   /// Hardware For Encoding ASCII Digits into Binary
   ///

   // Check whether a digit is present.
   //

   logic [7:0] char_in_1;

   uwire is_digit =    char_in >= Char_0 && char_in <= Char_9;
   uwire is_nz_digit = char_in >  Char_0 && char_in <= Char_9;  // Non-Zero
   logic is_digit_1, is_digit_2, is_nz_digit_1, is_nz_digit_2;

   always_ff @( posedge clk )
     if ( reset ) begin
        is_digit_1 <= 0;
        is_digit_2 <= 0;
        is_nz_digit_1 <= 0;
        is_nz_digit_2 <= 0;
     end else if ( insert_req ) begin
        is_digit_1 <= is_digit;
        is_nz_digit_1 <= is_nz_digit;
        is_digit_2 <= is_digit_1;
        is_nz_digit_2 <= is_nz_digit_1;
      end

   // Convert ASCII digit to an integer.
   //
   uwire [3:0] char_bin = char_in[3:0];
   uwire [3:0] char_bin_1 = char_in_1[3:0];

   // Combine digit at char_in with current value of incoming_val_binary.
   //
   uwire [n_bytes_binary:0] [7:0] incoming_val_binary_0 =
                            incoming_val_binary_1 * 10 + char_bin;

   always_ff @( posedge clk )
     if ( insert_req ) incoming_val_binary_2 <= incoming_val_binary_1;

   uwire overflow_1 = incoming_val_binary_1[n_bytes_binary] != 0;


   ///
   /// Hardware to Detect the Start, End, and Suitability of a String of Digits
   //

   // Update registers holding encoded integer, and those keeping
   // track of locations.
   //

   logic encoding_2;

   uwire start_encoding = encoding_2 && overflow_1 && is_digit_1 && is_digit
                       || !is_digit_2 && is_nz_digit_1 && is_digit;
   uwire end_encoding = encoding_2 && ( overflow_1 || insert_req && !is_digit );

   uwire use_encoding = end_encoding
        && ( incoming_n_bytes_ascii > n_bytes_binary )
        && ( !have_outgoing_val_binary || end_draining );

   // If true, stage 1 is currently converting an integer to binary.
   //
   uwire encoding_1 = start_encoding || encoding_2 && !end_encoding;

   always_ff @( posedge clk )
     if ( reset )           encoding_2 <= 0;
     else if ( insert_req ) encoding_2 <= encoding_1;


   always_ff @( posedge clk )
     if ( reset ) begin

        incoming_val_binary_1 <= 0;
        tail_at_enc_start_1 <= 0;

     end else if ( insert_req ) begin

        incoming_val_binary_1 <= start_encoding
                        ? char_bin + char_bin_1 * 10
                        : incoming_val_binary_0;

        incoming_n_bytes_ascii <=
          start_encoding ? 2 : incoming_n_bytes_ascii + 1;

        if ( start_encoding ) tail_at_enc_start_1 <= write_idx_1;

        if ( use_encoding )
          outgoing_val_binary <=
            overflow_1 ? incoming_val_binary_2 : incoming_val_binary_1;

        char_in_1 <= char_in;

   end


   ///
   /// Hardware for Writing Characters into Storage
   ///

   // If the encoded integer is used we need to move the tail back by
   // the number of characters saved. That's easier to compute using
   // the location at which the encoded number started.
   //
   uwire [size_lg:1] tail_adj =
     tail_at_enc_start_1 + n_bytes_binary + overflow_1;

   // Location at which to write current character.
   assign write_idx_1 = use_encoding ? tail_adj : tail_1;

   logic  reset_1;
   always_ff @( posedge clk )
     if ( reset ) reset_1 <= 1; else if ( insert_req ) reset_1 <= 0;

   /// Write the Storage and the Tail Pointer
   //
   always_ff @( posedge clk ) if ( reset ) begin

      tail_1 <= 0;

   end else begin

      if ( insert_req && !reset_1 ) begin

         if ( separate_port ) begin

            // Higher-Performance Design Option: Two write ports for storage.

            if ( use_encoding ) begin

               esc_here[tail_adj] <= 0;
               storage[tail_adj] <= char_in_1;

            end else begin

               esc_here[tail_1] <= 0;
               storage[tail_1] <= char_in_1;

            end

         end else begin

            // Lower-Cost Design Option: Single write port for storage.

            esc_here[write_idx_1] <= 0;
            storage[write_idx_1] <= char_in_1;

         end

         tail_1 <= write_idx_1 + 1;

      end

      // If we've decided to use an encoded number remember
      // where. When head reaches tail_at_enc_start we will start
      // sending the encoded number to the output.
      if ( use_encoding ) esc_here[tail_at_enc_start_1] <= 1;

   end


   ///
   /// Hardware For Removing Characters From Storage
   ///

   /// Character Out Mux
   //
   //  The char_out port can be connected to three things:
   //
   //    - A memory holding stored characters: storage[].
   //    - The escape character (a constant, Char_escape).
   //    - A register holding a number encoded in binary, outgoing_val_binary.
   //
   assign char_out =
          start_draining  ?  Char_escape :
          draining        ?  outgoing_val_binary[drain_idx] :
                             storage[head];

   assign start_draining = !empty && esc_here[head];
   assign end_draining = remove_req && draining && drain_idx == 0;

   // Update the register that indicates whether outgoing_val_binary is holding
   // something.
   //
   always_ff @( posedge clk )
     if ( reset )                           have_outgoing_val_binary <= 0;
     else if ( use_encoding && insert_req ) have_outgoing_val_binary <= 1;
     else if ( end_draining )               have_outgoing_val_binary <= 0;

   always_ff @( posedge clk ) if ( reset ) begin

      draining <= 0;
      drain_idx <= 0;
      head <= 0;

   end else if ( remove_req ) begin

      head <= head + 1;

      drain_idx <= start_draining  ?  n_bytes_binary-1 :
                   drain_idx > 0   ?  drain_idx - 1 :
                                      0;

      draining <= start_draining  ?  1 :
                  remove_req && drain_idx == 0  ?  0 :
                  draining;
   end


   ///
   /// Hardware to Related to Storage Full and Empty Status
   ///

   assign empty = head == tail_1;
   assign full = tail_1 + 1 == head;

   assign can_remove = !empty && ( !encoding_2 || head != tail_at_enc_start_1 );
   assign can_insert = !full;


   ///
   /// Wires for use by testbench only.
   ///
   // cadence translate_off
   uwire [n_bytes_binary:0] [7:0] incoming_val_binary = incoming_val_binary_1;
   uwire [size_lg:1] write_idx = write_idx_1;
   uwire [size_lg:1] tail = tail_1;
   uwire [size_lg:1] tail_at_enc_start = tail_at_enc_start_1;
   uwire             now_encoding = encoding_1;
   // cadence translate_on

endmodule





// cadence translate_off

program reac(output uwire clock_reactive, input uwire clock);

   assign clock_reactive = clock;

endprogram

module testbench();

   localparam int elts_lg = 4;
   localparam int elts = 1 << elts_lg;
   localparam int n_bytes_binary = 2;

   uwire [7:0] char_out;
   uwire       can_insert, can_remove;
   logic [7:0] char_in;
   logic insert_req, remove_req, reset, clk;
   icomp_1cyc #(elts_lg,n_bytes_binary) b1
     (char_out,can_insert,can_remove,char_in,insert_req,remove_req,reset,clk);

   int cycle_num;

   uwire  clk_reactive;

   reac reactivator(clk_reactive, clk);

   initial begin
      clk = 0;
      cycle_num = 0;
      fork
         forever #1 clk = !clk;
         forever @( posedge clk ) cycle_num++;
      join
   end

   string in_str = "One 1 two 12 three 317 four 1029 six 123456 ten 1234567890.  There are 60 seconds in a minute and 31536123 - 123 in a year.";
   string out_str = "";

   initial begin

      automatic string in_str_w_suffix = {in_str, Char_EOS, Char_EOS };
      automatic int insert_finished_cyc = 0;
      automatic int out_size = 0;
      automatic bit tb_insert_done = 0;
      automatic bit tb_remove_done = 0;
      automatic bit trace_this_cycle = 0;
      automatic bit key_printed = 0;
      // Encoded integer is longer than allowed.
      automatic int err_oversize = 0;
      // Number of remaining encoded bytes expected from char_out.
      automatic int bytes_remaining = 0;
      automatic bit enc_start = 0; // If true, char_out is an escape char.
      automatic bit enc_middle = 0;

      /// Reset the module.
      //
      reset = 0;
      insert_req = 0;
      remove_req = 0;
      @( negedge clk ) reset = 1;
      @( negedge clk ) reset = 0;
      @( negedge clk );

      /// Check for one possible error.
      //
      if ( can_insert !== 1 ) begin

         $display("Module did not reset, can_insert: %h\n", can_insert);
         $fatal(1);

      end

      /// Start Main Testing Loops
      //
      fork

         /// Watchdog -- Stop simulation if it's taking too long.
         //
         fork begin

            automatic int cyc_limit = in_str.len() * 100;

            fork
               wait ( cycle_num == cyc_limit );
               wait ( tb_insert_done && tb_remove_done );
            join_any

            if ( cycle_num >= cyc_limit ) begin
               $write("Exceeded cycle limit, exiting.\n");
               $fatal(1);
            end

         end join_none

         /// Trace Execution -- Print Signal Values After Interesting Changes
         //

         while ( !tb_insert_done || !tb_remove_done )
            @( insert_req or remove_req or can_insert or can_remove
               or b1.tail or b1.head or tb_insert_done or tb_remove_done )
              trace_this_cycle = 1;

         while ( !tb_insert_done || !tb_remove_done ) begin

            @( negedge clk_reactive ) if ( !trace_this_cycle ) continue;
            trace_this_cycle = 0;

            if ( !key_printed ) begin
               localparam string space = "                                           ";
               key_printed = 1;
               $write("%sTrace Key:\n",space);
               $write("%ss___ ___ : Start encoding.\n",space);
               $write("%s_n__ ___ : Now encoding.\n",space);
               $write("%s__e_ ___ : End encoding.\n",space);
               $write("%s___u ___ : Use encoding.\n",space);
               $write("%s____ f__ : Have outgoing binary value.\n",space);
               $write("%s____ _s_ : Start draining.\n",space);
               $write("%s____ __e : End draining.\n",space);
            end

            /// Trace execution by showing removed character and
            /// related information.
            //
            $write( "In %s  Out %d %3s = %3s   tail %d/%d head %d %s%s%s%s %s%s%s es %d  in_sz %2d  in x%h  out x%h\n",
                    insert_req ? ( char_in == Char_EOS ? "E" : char_in ) : "-",
                    can_remove,
                    remove_req ? $sformatf("%3d",char_out) : "   ",
                    !remove_req ? "   " :
                    enc_start ?
                    ( char_out == Char_escape ? "ESC" :
                      $sformatf("E-%1d",char_out-Char_escape) ) :
                    enc_middle ? $sformatf("x%02h",char_out) :
                    char_out >= 32 && char_out < 128 ? char_out
                    : $sformatf("x%02h",char_out),
                    b1.tail, b1.write_idx,
                    b1.head,
                    b1.start_encoding ? "s" : "_",
                    b1.now_encoding ? "n" : "_",
                    b1.end_encoding ? "e" : "_",
                    b1.use_encoding ? "u" : "_",
                    b1.have_outgoing_val_binary ? "f" : "_",
                    b1.start_draining ? "s" : "_",
                    b1.end_draining ? "e" : "_",
                    b1.tail_at_enc_start,
                    b1.incoming_n_bytes_ascii,
                    b1.incoming_val_binary, b1.outgoing_val_binary);

         end

         /// Insert Characters
         //
         begin

            automatic int in_pos = 0;

            while ( in_pos < in_str_w_suffix.len() ) begin

               @( negedge clk );

               // Flip a coin, and if it comes up tails send a character
               // in if module is ready for one.
               //
               if ( {$random} & 'h1 && can_insert ) begin

                  char_in = in_str_w_suffix[in_pos++];
                  insert_req = 1;

               end else begin

                  insert_req = 0;

               end

            end

            @( negedge clk );

            insert_req = 0;
            insert_finished_cyc = cycle_num;

            $write("Done feeding inputs.\n");
            tb_insert_done = 1;

         end

         /// Remove Characters
         //
         begin

            bit [n_bytes_binary-1:0][7:0] buffer;
            bytes_remaining = 0;

            while ( insert_finished_cyc == 0
                    || cycle_num < insert_finished_cyc + elts * 10 ) begin

               @( negedge clk );

               if ( can_remove
                    && bytes_remaining == 0 && char_out == Char_EOS ) break;

               if ( {$random} & 1 && can_remove ) begin

                  remove_req = 1;
                  out_size++;
                  enc_start = 0;
                  enc_middle = bytes_remaining > 0;

                  if ( bytes_remaining > 0 ) begin

                     buffer = ( buffer << 8 ) + char_out;
                     bytes_remaining--;

                     if ( bytes_remaining == 0 ) begin

                        // Convert binary number back to ASCII.
                        out_str = {out_str,$sformatf("%0d",buffer)};

                     end

                  end else if ( char_out == Char_escape )
                    begin

                       enc_start = 1;
                       bytes_remaining =
                           char_out == Char_escape
                         ? n_bytes_binary
                         : char_out - Char_escape ;
                       buffer = 0;
                       if ( bytes_remaining > n_bytes_binary ) err_oversize++;

                    end else begin

                       out_str = {out_str,char_out};

                    end

               end else begin

                  remove_req = 0;

               end

            end

            $write("Done gathering outputs.\n");
            tb_remove_done = 1;

         end

      join

      if ( err_oversize )
        $write("** Error: %d encoded integers too long.\n", err_oversize);

      if ( in_str != out_str )
        $write("** Error: strings don't match.\n");
      else
        $write("Correct output, strings match. %s\n",
                 ( in_str.len() == out_size ) ? "But no compression!" : "");

      $write("In size %d bytes, out size %d bytes.\n",
               in_str.len(), out_size);
      $write("In - \"%s\"\nOut- \"%s\"\n",
               in_str, out_str);

      $finish(2);

   end

endmodule

// cadence translate_on

`ifdef XXX
Module Name                               Area   Clock
                                                Period
icomp_1cyc  4 4                         272268    3378    Old overflow -> 108
icomp_1cyc  4 4                         259632    2318    New ov. 117->109
icomp_2cyc 4 4 0                        319452    2480
icomp_2cyc 4 4 1                        361448    2250
`endif