/// Notes  and Demos for LSU EE 4702-1 Spring 2001

//  Material from LRM 4.1

/// Contents

//  Operator Overview
//  Handling of x and z by Logic Operators (Missing but should be here.)
//  Reduction Operators
//  Equality Operators
//  Concatenation (Not started.)
//  Conditional Operator
//  Operator Precedence and Association


/// Operator Overview

//  LRM 4.1

//  Many are identical to C counterparts.
//  Some C operators not present.
//  Some new ones specific to Verilog.
//  Precedence similar to C.


/// Reduction Operators

//  A Reduction Operation is one that converts many operands to one.
//  In Verilog, the operands are the bits of a vector, the result
//   is a single bit.

//  Verilog Reduction Operators
//   &   and
//   |   or
//   ^   exclusive or
//   ~&  not and
//   ~|   not or
//   ~^   xnor (not exclusive or)

 /// WARNING: Table 4-19 in the "Experimental" LRM 4.1 is wrong (or mislabeled).
 /// Correct Tables:   (Generated by test_reduction_xnor module, below.)

//    Reduction Exclusive Or
//    ^zz = x    ^zx = x    ^z1 = x    ^z0 = x
//    ^xz = x    ^xx = x    ^x1 = x    ^x0 = x
//    ^1z = x    ^1x = x    ^11 = 0    ^10 = 1
//    ^0z = x    ^0x = x    ^01 = 1    ^00 = 0


//    Reduction Exclusive Nor
//    ~^zz = x    ~^zx = x    ~^z1 = x    ~^z0 = x
//    ~^xz = x    ~^xx = x    ~^x1 = x    ~^x0 = x
//    ~^1z = x    ~^1x = x    ~^11 = 1    ~^10 = 0
//    ~^0z = x    ~^0x = x    ~^01 = 0    ~^00 = 1

module reduction_examples();

   reg [3:0] a, b, a_xor_b;
   integer   rand1, rand2, rnand1, rnand2, ror1, ror2, rxor1, rxor2;

   initial begin

      a = 8'b0110;

      /// Reduction And
      //  The two lines below do the same thing.
      rand1 = & a;
      rand2 = a[0] & a[1] & a[2] & a[3];
      if( rand1 ) $display("Reg a is 15.");

      /// Reduction Nand
      //  The two lines below do the same thing.
      rnand1 = ~& a;
      rnand2 = ! ( a[0] & a[1] & a[2] & a[3] );
      if( rnand1 ) $display("Reg a is not 15.");

      /// Reduction Or
      //  The two lines below do the same thing.
      ror1 = | a;
      ror2 = a[0] | a[1] | a[2] | a[3];
      if( ror1 ) $display("Reg a is not zero.");

      /// Reduction Xor
      //  The two lines below do the same thing.
      rxor1 = ^ a;
      rxor2 = a[0] ^ a[1] ^ a[2] ^ a[3];
      if( rxor1 ) 
        $display("Reg a's binary representation has an odd number of 1s.");


      /// Testing for Equality Using Reduction Xor
      b = 8'b0111;
      a_xor_b = a ^ b;  // Bitwise xor.
      if( & a_xor_b ) $display("The contents of a and b are the same.");
      // The same thing without the temporary variable, a_xor_b.
      if( & ( a ^ b ) ) $display("The contents of a and b are the same.");
      
   end
endmodule // reduction_examples

module text_reduction_xnor();
   // Print the result of the reduction xnor (~^) on all possible
   // two-bit values.
   
   reg [3:0] vals;   // Used as a constant, holds the four logic values.
   integer   a, b;
   reg [1:0] ab;
   
   initial begin

      vals = 4'b01xz;

      for(a=0; a<4; a=a+1)
        for(b=0; b<4; b=b+1)
          begin
             ab = { vals[a], vals[b] };
             $display("~^%b = %b", ab, ~^ab);
          end
   end

endmodule

  

/// Equality Operators

//  Special handling needed for x's and z's.

//  ==  Logical equality.   Result unknown if operand has x or z.
//  !=  Logical inequality. Result unknown if operand has x or z.
//  === Case equality.      Compares x's and z's.
//  !== Case inequality.    Compares x's and z's.

//  LHS == RHS
//  Evaluates to x if there is an x or z in LHS or RHS 
//  Evaluates to 1 if LHS and RHS are the same numbers.
//  Evaluates to 0 if LHS and RHS are different numbers.

//  LHS === RHS
//  Evaluates to 1 if LHS and RHS are bitwise identical (0's, 1's, x's, and z's).
//  Otherwise evaluates to 0.

//  Operands are made the same size by padding the left-hand side
//  of the smaller operand with zeros.  (Signs are NOT extended.)

//  N.B. neither x nor z act as a wildcard (don't care).

module equality_examples();

   reg [3:0] four_bit_register;
   reg [7:0] eight_bit_register;
   integer   an_integer;
   
   initial begin

      /// Some obvious examples.
      // Since numbers below do not contain x's or z's logical and
      // case equivalence do the same thing.
      if( 3 == 4 ) $display("Something is VERY wrong.");
      if( 3 === 4 ) $display("Something is VERY wrong.");
      if( 3 != 4 ) $display("For this I need Verilog?");
      if( 3 !== 4 ) $display("For this I need Verilog?");

      // Four-bit number is extended to 8 bits.
      if( 8'd3 == 4'd3 ) $display("They're equal.");
      if( 8'd3 === 4'd3 ) $display("They're equal.");

      four_bit_register = 3;
      eight_bit_register = 3;
      if( four_bit_register == eight_bit_register ) $display("Still equal.");
      if( four_bit_register === eight_bit_register ) $display("Still equal.");

      /// Example of Zero Padding and Negative Number Handling
      // Regs and wires are treated as unsigned values.  The assignment
      // of a negative value works correctly.  However if it's converted
      // to a longer form (as with the equality operators) the lhs will
      // be padded with zeros, rather than sign extended and so the
      // result will no longer be a negative integer.
      
      four_bit_register  = -3;  // Value in register: 4'b1101
      eight_bit_register = -3;  // Value in register: 8'b11111101
      $display("Four-bit reg: %d", four_bit_register);
      if( four_bit_register != eight_bit_register )
        $display("They are not equal because the sign was not extended.");
      if( four_bit_register == eight_bit_register[3:0] )
        $display("The low four bits are equal.");

      /// Examples Using x and z
      if( 4'b100x == 4'b100x ) 
        $display("This won't print because of x's, they may not be equal.");
      if( 4'b100x != 4'b100x ) 
        $display("This won't print because of x's, they may be equal.");
      if( 4'b10zx === 4'b10zx ) 
        $display("The two constants are bitwise identical.");
      if( 4'b10zx !== 4'b10zx ) 
        $display("This won't print because they are bitwise identical.");
      if( 4'b100x === 4'b1000 )
        $display("This won't print, x is not the same as 0.");

   end

endmodule 


/// Concatenation

//  {foo,bar,foobar}


/// Conditional

//  CONDITION ? IFTRUE : IFFALSE 

//  The conditional operator (?:) takes three (yes, three) operands.
//  If CONDITION is zero evaluates to IFFALSE.
//  If CONDITION is non-zero and does not contain x or z bits, evaluates
//    to IFTRUE.
//  If CONDITION contains an x or z evaluates to a bitwise combination of
//    IFTRUE and IFFALSE:
//    Combined bit is 0 iff corresponding bits are 0 in IFTRUE and IFFALSE.
//    Combined bit is 1 iff corresponding bits are 1 in IFTRUE and IFFALSE.
//    Otherwise combined bit is x.

module conditional_example(x,y,a,b);
   input a,b;
   output x,y;
   wire [3:0] a,b;

   // Suppose b = 4'b1100;
   // If a = 4'd5    then x = 4'b1100;
   // If a = 4'd10   then x = 4'b1010;
   // If a = 4'b01xz then x = 4'b1xx0;
   wire [15:0] x = a < 10 ? b : 4'b1010;

   // If a < 10 then y = 10
   // else if a < 20 then y = 20
   // else if a < 30 then y = 30
   // else y = 40;
   wire [15:0] y = 
               a < 10 ? 10 :
               a < 20 ? 20 :
               a < 30 ? 30 : 40;
               
endmodule // conditional_example


/// Operator Precedence and Association

//  LRM 4.1 Table 4-4.

//  Operator Precedence
//  + - ! ~ (unary)            highest precedence (Strongest Binding)
//  *  /  %
//  +  - (binary)
//  <<  >>
//  <  <=  >  >=
//  ==  !=  ===  !==
//  &  ~&
//  ^  ^~
//  |  ~|
//  &&
//  ||
//  ?: (conditional operator)  lowest precedence  (Weakest Binding)

//  Association is from left to right except conditional (?:).

module precedence_and_association_examples();

   integer x, a, b, c, d, temp;

   initial begin

      /// Precedence Examples

      // Multiplication has higher precedence than addition so multiply first.
      x = a + b * c;  // Multiply then add.
      x = ( a + b ) * c;  // Add then multiply.

      // Comparison (<,>) has higher precedence than logical or (||),
      // so compare first, then or the results.
      if( a < b || c > d ) $display("Condition true.");

      // Logical equality (==) has higher precedence than bitwise xor (^).
      if( a ^ b == c ) $display("This is probably an error.");
      if( ( a ^ b ) == c ) $display("This is probably okay.");

      // Unary negation (!) has higher precedence than logical or (||).
      if( !a || b ) $display("(Not a) or b.");
      if( !(a || b) ) $display("Not (a or b)");

      // The conditional operator has the lowest precedence, lower than addition.
      // if ( a < 10 ) x = b; else x = c + 1;      
      x = a < 10 ? b : c + 1;
      // if ( a < 10 ) x = b + 1; else x = c + 1;
      x = ( a < 10 ? b : c ) + 1;

      /// Association Examples

      // Addition and subtraction have the same precedence, so the
      // leftmost operation is performed first.
      x = a + b - c; // Add then subtract.
      x = a - b + c; // Subtract then add.

      // The conditional operator has right-to-left association. (All
      // other operators associate left to right.)
      // The three lines below do the same things.
      x = a < 10 ? 10 : a < 20 ? 20 : 30;
      x = a < 10 ? 10 : ( a < 20 ? 20 : 30 );
      if( a < 10 ) x = 10; else begin if ( a < 20 ) x = 20; else x = 30; end

      // The first line below and the next two lines do the same
      // probably-not-too-useful thing. (Which is why conditionals associate
      // right to left.)
      x = ( a < 10 ? 10 : a < 20 ) ? 20 : 30;
      if( a < 10 ) temp = 10; else temp = a < 20;
      if ( temp ) x = 20; else x = 30;
     
   end

endmodule // precedence_examples