/// Code from solution to LSU EE 4702-1 Spring 2000 Final Exam

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

///
/// Problem 1
///

`define FIXED_CODE
`ifdef ORIGINAL_CODE
module rerearrange(y,a);
   input a;
   output y;
   wire [7:0] a;
   reg [7:0]  y;
   wire [0:7] temp;
   
   wire       operation;
   assign     operation = e1.op_reverse;
   rearrange e1(temp,a,operation);

   assign     operation = e1.op_left_shift;   
   rearrange e2(y,temp,operation);
endmodule 

module rearrange(x,a,op);
   input      a, op;
   output     x;
   wire [7:0] a;
   wire [1:0] op;
   reg [7:0]  x;
   reg [2:0]  ptr, ptr_plus_one;

   parameter  op_reverse     = 0;  // Reverse order of bits.            // Okay
   parameter  op_identity    = 1;  // No change.                        // Okay
   parameter  op_left_shift  = 2;  // Circular (end-around) left shift. // Okay
   parameter  op_right_shift = 3;  // Circular (end-around) right shift.// Okay
   
   always @( a ) for(ptr=0; ptr<8; ptr=ptr+1) begin
        ptr_plus_one = ptr + 1;                                         // Okay
        case( op )
          op_reverse:     x[ptr]          = a[7-ptr];                   // Okay
          op_identity:    x[ptr]          = a[ptr];                     // Okay
          op_right_shift: x[ptr]          = a[ptr_plus_one];            // Okay
          op_left_shift:  x[ptr_plus_one] = a[ptr];                     // Okay
        endcase 
     end
endmodule // rearrange


//  # Loading work.rerearrange
//  # Loading work.rearrange
//  # WARNING: fe_sol.v(8): [PCDPC] - Port size does not match connection size (3rd connection).
//  #        Region: /rerearrange/e1
//  # ERROR: fe_sol.v(11): Illegal output port connection (1st connection).
//  #       Region: /rerearrange/e2
//  # WARNING: fe_sol.v(11): [PCDPC] - Port size does not match connection size (3rd connection).
//  #        Region: /rerearrange/e2
//  # Error loading design
`endif // ifdef ORIGINAL_CODE

`ifdef FIXED_CODE
module rerearrange(y,a);
   input a;              
   output y;
   wire [7:0] a;
   // Registers cannot connect to module output ports.
   // reg [7:0]  y;
   wire [7:0]  y;  // FIXED
   wire [0:7] temp;

// B: Wire "operation" wrong size.
//   wire       operation;
   wire       [1:0] operation;  // FIXED
   assign     operation = e1.op_reverse;
   
   rearrange e1(temp,a,operation);

   // Second wire needed for input to second module. (This is not procedural
   // code so ordering of assignments and instantiations is meaningless.)
   //   assign     operation = e1.op_left_shift;   
   wire [1:0] operation2 = e1.op_left_shift;   // FIXED
   rearrange e2(y,temp,operation2);
endmodule 

module rearrange(x,a,op);
   input      a, op;
   output     x;
   wire [7:0] a;
   wire [1:0] op;
   reg [7:0]  x;
   // C: Loop checks if ptr<8, so need more than 3 bits.  Note: ptr_plus_one
   // must be 3 bits since code depends on values wrapping around.
   // reg [2:0]  ptr, ptr_plus_one;
   reg [3:0]  ptr;  // FIXED.
   reg [2:0]  ptr_plus_one;

   parameter  op_reverse     = 0;  // Reverse order of bits.            // Okay
   parameter  op_identity    = 1;  // No change.                        // Okay
   parameter  op_left_shift  = 2;  // Circular (end-around) left shift. // Okay
   parameter  op_right_shift = 3;  // Circular (end-around) right shift.// Okay

   // C: Need to include op in the event list.
   // always @( a ) for(ptr=0; ptr<8; ptr=ptr+1) begin
   always @( a or op ) for(ptr=0; ptr<8; ptr=ptr+1) begin   // FIXED
        ptr_plus_one = ptr + 1;                                         // Okay
        case( op )
          op_reverse:     x[ptr]          = a[7-ptr];                   // Okay
          op_identity:    x[ptr]          = a[ptr];                     // Okay
          op_right_shift: x[ptr]          = a[ptr_plus_one];            // Okay
          op_left_shift:  x[ptr_plus_one] = a[ptr];                     // Okay
        endcase 
     end
endmodule // rearrange
`endif // ifdef FIXED_CODE

module test_rr();

   reg [7:0] orig;
   wire [7:0] arranged;

   rerearrange rr1(arranged,orig);

   initial begin
      orig = 8'b11110000;
      #1;
      orig = 8'b00001111;
      #1;
   end

endmodule // test_rr

///
/// Problem 2  (Unmodified code from exam.)
///


module clocks();
   reg clk, clk2, clk3, clk4, clk5, clk6, clk7, clk8;
   initial begin
      clk  = 0; clk2 = 0; clk3 = 0; clk4 = 0;
      clk5 = 0; clk6 = 0; clk7 = 0; clk8 = 0;
   end

   always #8 clk = ~clk;
   always @( clk ) #4 clk2 = ~clk2;
   always @( clk ) clk3 <= #10 clk;
   always @( posedge clk ) clk4 = ~clk4;
   always #2 forever #8 clk5 = ~clk5;
   always wait( clk ) #3 clk6 = ~clk6;
   always @( clk | clk4 ) clk7 = ~clk7;
   always @( clk or clk4 ) clk8 = ~clk8;

   initial #41 $stop;

endmodule

// Solution: 

///
/// Problem 3  (Unmodified code from exam.)
///

module mod_a(x,y,a,b,c);
   input a,b,c;
   output x,y;
   wire [7:0] b, c;
   reg [8:0]  x, y;

   always @( a or b or c ) begin
      if( a ) begin
         x = b + c;
         y = b - c;
      end else begin
         x = b - c;
      end
   end
endmodule

// Solution:  

module mod_b(x,y,d,e,f,g,h);
   input d,e,f,g,h;
   output x,y;
   reg    x,y;

   always @( posedge d or negedge e or posedge f )
     if( d ) begin
        x = 0;
        y = 1;
     end else if ( f ) begin
        x = 1;
     end else begin
        if( g ) x = h;
        y = h;
     end

endmodule

// Solution:  



module compare(gt, lt, a, b);
   input a, b;
   output gt, lt;
   wire [2:0] a, b;
   reg        gt, lt;
   integer    i;

   always @( a or b ) begin
      gt = 0; lt = 0;
      for(i=2; i>=0; i=i-1) if( !gt && !lt ) begin
         if( a[i] < b[i] ) lt = 1;
         if( a[i] > b[i] ) gt = 1;
      end
   end

endmodule // compare

// Solution:  



///
/// Problem 4
///


// Unmodified from exam.
module compare_comb(gt, lt, a, b);
   input a, b;
   output gt, lt;
   wire [3:0] a, b;
   reg 	      gt, lt;
   integer    i;

   always @( a or b ) begin
      gt = 0; lt = 0;
      for(i=3; i>=0; i=i-1) if( !gt && !lt ) begin
	 if( a[i] < b[i] ) lt = 1;
	 if( a[i] > b[i] ) gt = 1;
      end
   end

endmodule

// Solution.
module compare_ism(gt, lt, valid, a, b, start, clk);
   input a, b, start, clk;
   output gt, lt, valid;
   wire [31:0] a, b;
   reg 	       gt, lt, valid;
   integer     i;

   always @( posedge clk ) if( start ) begin
      gt = 0; lt = 0; valid = 0;
      for(i=31; i>=0 && !lt && !gt; i=i-1) @( posedge clk ) begin
         if( a[i] < b[i] ) lt = 1;
         if( a[i] > b[i] ) gt = 1;
      end
      valid = 1;
   end

endmodule

///
/// Problem 5
///

///
/// Problem 5a
///

// Solution
module watchdog(heartbeat);
   input heartbeat;
   wire  heartbeat;

   always
     fork:F
       @( heartbeat ) disable F;
       # 1000 $stop;
     join
   
endmodule // watchdog

///
/// Problem 5d
///

// Solution.
module whatswrong(a,b);
   input a;       output b;
   wire [8:0] a;  wire [8:0] b;

  // assign b = {a[8:6],0,a[2:0]};
   assign b = {a[8:6],3'b0,a[2:0]};

endmodule