/// LSU EE 4702-1 Spring 2001 Final Exam Verilog Code

// Exam:     http://www.ee.lsu.edu/v/2001/fe.pdf
// Solution: http://www.ee.lsu.edu/v/2001/fe_sol.pdf

///
/// Problem 1
///

 
 /// Unmodified Code From Exam

module expl_str(x,y,a,b,c);
   input a, b, c;
   output x, y;
   wire   a, b, c, x, y;
   wire   na, nb, nc, t3, t5, t6;

   not n1(na,a);
   not n2(nb,b);
   not n3(nc,c);
   and #1 a1(t3,na,b,c);
   and a2(t5,a,nb,c);
   and a3(t6,a,b,nc);
   or o1(x,t3,t6);
   or #3 o2(y,a,t5);

endmodule


 /// Solution

module behav(x,y,a,b,c);
   input  a, b, c;
   output x, y;
   wire   a, b, c;
   reg    x, y;
   reg    t3;

   // The delays in expl_str are inertial delays, the delays here
   // are pipeline delays.
   
   // Note that t3 is delayed but t6 is not.

   always @( a or b or c ) t3 <= #1 !a & b & c;
   
   always @( a or b or c or t3 ) x = t3 | a & b & !c;

   // Code below can be simplified to y <= #3 a;
   
   always @( a or b or c ) y <= #3 a | a & !b & c;

endmodule


///
/// Problem 2
///

 /// Code from exam.  Whitespace added for readability.

`define ROTS_ORIG
`ifdef ROTS_ORIG
module rots(ready, rot, start, a, b, clk);
   input a, b, start, clk;        
   output ready, rot;
   
   reg         ready;             
   wire [31:0] a, b;
   reg [5:0]   rot;               
   wire        start, clk;
   
   reg [31:0]  acpy;

   initial rot = 0;

   always @( posedge clk ) begin
      ready = 1;   while( !start ) @( posedge clk );
      ready = 0;   while(  start ) @( posedge clk );
      rot = 0;  acpy = a;
      while(  acpy != b  &&  rot < 32  ) @( posedge clk ) begin
         acpy = { acpy[30:0], acpy[31] };
         if( acpy == a ) rot = 32; else rot = rot + 1;
      end
   end
endmodule
`endif

 /// Solution
module testrot();

   parameter a = 32'd0;
   reg [31:0] b;
   integer    i;

   wire       rdy;
   wire [5:0] r;
   reg        start, clk;

   initial clk = 0;
   always #1 clk = !clk;

   rots myrots(rdy, r, start, a, b, clk);

   integer    err;

   initial begin

      err = 0; start = 0;

      wait(rdy);
      
      for(i=0; i<10; i=i+1) begin
         b = i; 
         start = 1; wait(!rdy);
         start = 0; wait( rdy);#1;
         if( !b && r ) err = err + 1;
         if(  b && r != 32 ) err = err + 1;
      end

      $display("Error count: %d",err);
      $stop;

   end // initial begin

endmodule // testrot


///
/// Problem 3
///

 /// Solution 1, using named states and assuming little about start.

`define xFORM2a
`ifdef FORM2a
module rots(ready, rot, start, a, b, clk);
   input a, b, start, clk;        
   output ready, rot;
   
   wire [31:0] a, b;
   reg [5:0]   rot;               
   wire        start, clk;
   reg [31:0]  acpy;
   reg [1:0]   state;

   parameter   st_ready = 2'b01;
   parameter   st_wait  = 2'b00;
   parameter   st_go    = 2'b10;

   wire        ready = state[0];
   
   initial begin rot = 0; state = st_ready; end

   always @( posedge clk ) 
     case( state )
       st_ready: 
         if( start ) state = st_wait;
       st_wait:  
         if( !start ) begin  rot = 0;  acpy = a;  state = st_go;  end
       st_go: 
         if(  acpy != b  &&  rot < 32  ) begin
            acpy = { acpy[30:0], acpy[31] };
            if( acpy == a ) begin rot = 32; state = st_ready; end
            else rot = rot + 1;
         end else begin
            state = st_ready;
         end
     endcase
endmodule 
`endif

 /// Solution 2, basing state on ready and assumed behavior of start.

`define xFORM2b
`ifdef FORM2b
module rots(ready, rot, start, a, b, clk);
   input a, b, start, clk;        
   output ready, rot;

   reg         ready;
   wire [31:0] a, b;
   reg [5:0]   rot;               
   wire        start, clk;
   reg [31:0]  acpy;

   initial begin rot = 0; ready = 1; end

   always @( posedge clk )
     case( {ready,start} )
       {2'b10}:; // Wait for start to go to one.
       // Unlike original module, gets value of "a" when start goes
       // to 1, not when start goes to zero. (This is where behavior assumed.)
       {2'b11}: begin ready = 0; acpy = a; rot = 0; end
       {2'b01}:; // Wait for start to go to zero.
       {2'b00}: 
         if(  acpy != b  &&  rot < 32  ) begin
            acpy = { acpy[30:0], acpy[31] };
            if( acpy == a ) begin rot = 32;  ready = 1; end
            else rot = rot + 1;
         end else begin
            ready = 1;
         end
     endcase
endmodule 
`endif

///
/// Problem 4
///

 /// Unmodified code from exam.

module whatsyna(x, y, z, a, b, op);
   input a, b, op;
   output x, y, z;
   wire [1:0] op;
   wire [7:0] a, b;
   reg [7:0]  x, y, z;

   always @( op or a or b ) begin

      if( a == 0 ) y = b;

      if( a < b ) z = a; else z = b;

      case( op )
        0: x = a + b;
        1: x = a;
        2: x = b;
      endcase

   end
   
endmodule


 /// Unmodified code from exam.

module whatsyn2(sum, nibbles, a, b, c);
   input nibbles, a, b, c;
   output sum;
   wire [15:0] nibbles;
   wire        a, b;
   reg [6:0]   sum;

   reg [15:0]  n2;
   reg         last_c;
   integer     i;

   always @( posedge a or negedge b ) 
     if( !b ) begin

        sum = 0;

     end else begin

        if( c != last_c ) begin
           n2 = nibbles;
           for( i=0; i < 4; i = i + 1 ) begin
              sum = sum + n2[3:0];
              n2 = n2 >> 4;
           end
        end
        last_c = c;
        
     end

endmodule

 /// The original version of Problem 4c,d. (Was not on test.)

module whatsyn2orig(len, nibbles, a, b);
   input nibbles, a, b;
   output len;
   wire [15:0] nibbles;
   wire        a, b;
   reg [2:0]   len;

   reg [15:0]  n2;
   integer     i;
   reg         done;        

   always @( posedge a or negedge b ) 
     if( !b ) begin

        len = 0;

     end else begin

        done = 0;
        n2 = nibbles;

        for(i=0; i < 24; i = i + 4) begin
           if( !done && !n2[3:0] ) begin
              done = 1;
              len = i[3:2];
           end
           n2 = n2 >> 4;
        end
        
     end

endmodule // whatsyn2


///
/// Problem 5
///


 /// Code from exam plus code to generate waveforms.
 //  Waveform image or link follows code.

module clocks();
   reg a, b, c, d;
   reg clk1, clk2, clk3, clk4, clk5, clk6, clk7, clk8;

   initial begin
      clk1 = 0; clk2 = 0; clk3 = 0; clk4 = 0; clk5 = 0; clk6 = 0; 
      clk7 = 0; clk8 = 0; a = 0;    b = 0;    c = 0;    d = 0;

      a <= #6 1;
      a <= #16 0;
      a <= #34 1;
      a <= #44 0;

      b <= #11 1;
      b <= #21 0;
      b <= #31 1;
      b <= #41 0;

      # 50 $stop;

   end

   always @( posedge a ) clk1 = !clk1;
   always @( a ) @( b ) clk2 = !clk2;
   always @( a or b ) clk3 = !clk3;
   always @( a | b ) clk4 = !clk4;
   always @( posedge ( a | b ) ) clk5 = !clk5;
   always @( a ) c <= a;
   always @( a ) d <= #1 c;
   always @( a or c ) clk6 = !clk6;
   always @( a or c ) #0 clk7 = !clk7;
   always @( a or c ) #2 clk8 = !clk8;

endmodule

 // Solution:  


///
/// Problem 6
///

 /// Problem 6a

module beepprob(beep, clk);
   input clk;
   output beep;
   reg [9:0] beep_timer;

   //  assign beep = | beep_timer;
   // Solution: Set beep on negative edge, after beep_timer computed.
   reg       beep;
   always @( negedge clk )  beep = | beep_timer;
   
   always @( posedge clk ) begin
      // Lots of stuff;

      if( beep_timer ) beep_timer = beep_timer - 1;

   end

endmodule 

 /// Problem 6d

module cond();
   reg [7:0] a, b, c, d, m1, m2, m3;

   initial begin
      a = 10;
      b = 8'bx;
      c = 8'b0011xxzz;
      d = 8'b01010x1z;

      m1 = a > b ? c : d;

      d = 8'b01010x1z;
      // m1 = 'b0xx1xxxz;

      m2 = 0;

      if( a == b ) m2 = c; else m2 = d;

      //  m2 = d = 8'b01010x1z;

      case( a > b )
        1: m3 = c;
        default: m3 = d;
      endcase

      // m3 = d = 8'b01010x1z;
      
   end
   
endmodule // bus