/// EE 4702 Spring 2001 Alternate Homework 2 Solution and Test

// Solution to Homework 2 based on student submissions.
// Test code used to test student submissions. (metatest_pe_8)

////////////////////////////////////////////////////////////////////////////////
/// Problem 1
///

 /// Solution to Problem 1 based on student submissions.
//
module priority_encoder_8_b(grant,request);
   input request;
   output grant;

   wire [7:0] request;
   reg [7:0]  grant;

   always @( request ) begin
      grant = 1;
      while( grant && ! ( grant & request ) ) grant = grant << 1;
   end

endmodule

 /// Another solution to Problem 1.
//
// This solution is less desirable since it uses an additional
// variable, i, and more lines.
//
module alternate_priority_encoder_8_b(grant,request);
   input request;
   output grant;

   wire [7:0] request;
   reg [7:0]  grant;

   always @( request ) begin:MAIN
      integer i;

      grant = 0;

      begin:LOOP1
         for(i=0; i<8; i=i+1)
           if( request[i] ) begin
              grant[i] = 1'b1;
              disable LOOP1;
           end
      end
   end

endmodule

////////////////////////////////////////////////////////////////////////////////
/// Problem 2
///

module priority_encoder_1_es(grant,found_out,request,found_in);
   output grant, found_out;
   input  request, found_in;
   wire   grant, found_out;
   wire   request, found_in;

   or #1 o1(found_out, found_in, request);
   and #1 a1(grant, not_found_in, request);
   not #1 n1(not_found_in, found_in);

endmodule

////////////////////////////////////////////////////////////////////////////////
/// Problem 3
///

module priority_encoder_8_es(grant, request);
   input request;
   output grant;
   wire [7:0] request, grant;
   wire       found_out_0, dummy;

   priority_encoder_4_es pe4_0(grant[3:0],found_out_0,    request[3:0],1'b0);
   priority_encoder_4_es pe4_1(grant[7:4],dummy,request[7:4],found_out_0);

endmodule

module priority_encoder_4_es(grant, found_out, request, found_in);
   input request, found_in;
   output grant, found_out;

   wire [2:0] found;
   wire [3:0] grant, request;
   
   priority_encoder_1_es pe1_0(grant[0], found[0],  request[0], found_in);
   priority_encoder_1_es pe1_1(grant[1], found[1],  request[1], found[0]);
   priority_encoder_1_es pe1_2(grant[2], found[2],  request[2], found[1]);
   priority_encoder_1_es pe1_3(grant[3], found_out, request[3], found[2]);

endmodule

////////////////////////////////////////////////////////////////////////////////
/// Problem 4
///

// Solution based on student submissions.

module test_pe_8(done, okay_b, okay_es, start);
   output done, okay_b, okay_es;
   input  start;

   reg    done, okay_b, okay_es;

   integer i;

   wire [7:0] request = i[7:0];

   wire [7:0] grant_b, grant_es;

   priority_encoder_8_b peb(grant_b,request);
   priority_encoder_8_es pees(grant_es,request);

   initial done = 0;

   always begin:MAIN

      integer pos;

      wait( start );  done = 0;  wait( !start );

      okay_b = 1;  okay_es = 1;

      for( pos = 0; pos <= 8; pos = pos + 1 ) begin:POS_LOOP

         reg [7:0] start;
         integer   incr;

         start = 1 << pos;
         incr  = 1 << ( pos + 1 );

         for( i = start; i < 256; i = i + incr ) #25 begin

            if( grant_b !== start )  okay_b = 0; 
            if( grant_es !== start ) okay_es = 0;

         end
         
      end // block: POS_LOOP

      // Use if statement to turn on messages when debugging.
      if( 0 ) begin
         $display("Test over, behavioral model %s",
                  okay_b ? "passed" : "failed");
         $display("Test over, structural model %s",
                  okay_es ? "passed" : "failed");
      end

      done = 1;
      
   end // block: MAIN

endmodule // test_pe_8

////////////////////////////////////////////////////////////////////////////////
/// Grading Modules
///


 /// A priority encoder module that can be set to fail in particular ways.
 //
 //  Used to test testbenches.

module t_priority_encoder_8_b(grant,request);
   input request;
   output grant;

   wire [7:0] request;
   reg [7:0]  grant;

   function [7:0] r_pot;
      input dummy;
      r_pot = 1 << ( $random & 7 );
   endfunction

   always @( request or metatest_pe_8.fault ) begin:MAIN
      integer i;
      reg [7:0] old_grant;

      grant = 8'b0;

      begin:LOOP1
         for(i=0; i<8; i=i+1)
           if( request[i] ) begin
              grant[i] = 1'b1;
              disable LOOP1;
           end
      end

      if( metatest_pe_8.fault_at[request] && metatest_pe_8.fault ) begin
         old_grant = grant;
         while( old_grant === grant )
           case( metatest_pe_8.fault )
             0: $stop;
             1: grant = r_pot(1);
             2: grant = old_grant | r_pot(1);
             3: grant = old_grant | r_pot(1) | r_pot(1);
             4: if( request == 0 ) begin grant = 1; old_grant = 0; end
                else begin grant = 0; old_grant = 1; end
             5: grant = old_grant ^ 8'bx0000000;
             6: $stop;
           endcase
      end
      
   end

endmodule

module t_priority_encoder_8_es(grant, request);
   input request;
   output grant;
   wire [7:0] request, grant;
   wire       found_out_0, dummy;

   t_priority_encoder_8_b pe(grant,request);
   
endmodule

 /// Meta-Testbench
//
//   Runs submitted testbenches multiple times, changing the kinds
//   of faults in the priority encoder modules.
   
module metatest_pe_8();
   wire done, ok_b, ok_es;
   reg  start;
   integer fault;
   integer okays_b[0:4];
   // Bit vector specifying which requests should generate an incorrect output.
   reg [255:0] fault_at;
   integer     fault_density;
   
   test_pe_8 tpe8(done, ok_b, ok_es, start);

   initial begin

      for( fault_density = 0; fault_density < 5;
           fault_density = fault_density + 1 ) begin:A

         case( fault_density )
           0: fault_at = 1;
           1: fault_at = 1<<200;
           2: fault_at = 1<<255;
           // Five faults.
           3: fault_at = 256'h10001000801000000000000000000000000000000000002000;
           // 128 faults
           4: fault_at = 
   256'h131dc062bab2b48e50f5abd4fc1e0a2abd54a5053ed4d181079afcee0a8f78ef;
         endcase // case( fault_density )
         
         for( fault = 0; fault < 6; fault = fault + 1 ) begin

            start = 1;
            wait( done === 0 );
            // Wait from 0 to 3 cycles, randomly chosen.
            #( $random & 3 );  
            start = 0;
            wait( done === 1 );

            if( ( fault == 0 ) !== ok_b ) begin
               $display("GR OUTC: FAIL (den,ty) (%d,%d)",
                        fault_density,fault);
               disable A;
            end
            // Wait from 0 to 3 cycles, randomly chosen.
            #( $random & 3 );  
         end // for ( fault = 0; fault < 6; fault = fault + 1 )

         $display("GR OUTC: PASS (den) %d",fault_density);
         
      end // block: A

      $display("Done with test.");

   end // initial begin
      
endmodule // metatest_pe_8