///  LSU EE 4755 -- Fall 2018 -- Digital Design / HDL
//
/// Verilog Notes -- Synthesis of Combinational Logic: Structural

/// Under Construction


/// Contents
//
 // Inference of Expressions
 // Inference of Non-Arithmetic Operators
 // Synthesis of The Conditional Operator, Index Op
 // Inference of Comparison Operators

/// References

// :SV12: IEEE 1800-2012 -- The SystemVerilog Standard
//        http://standards.ieee.org/getieee/1800/download/1800-2012.pdf
//
// :BV3:  Brown & Vranesic, Fundamentals of Digital Logic with Verilog, 3rd Ed.
//        The text used in LSU EE 2740.

//  Step-by-Step Genus Instructions (For this Course)
//        https://www.ece.lsu.edu/v/proc.html#synthesis
//
//  Genus HDL Modeling Guide -- Access from LSU Only.
//        https://www.ece.lsu.edu/v/s/genus_hdlmod.pdf
//
//  Links to More Documentation and References
//        https://www.ece.lsu.edu/v/ref.html


////////////////////////////////////////////////////////////////////////////////
/// Inference of Expressions
//
 // :Def: Expression
 // An arrangement of operators and operands which returns a result, as
 // defined by some language, such as C++11 or SystemVerilog 2012.
 //
 // :Sample: x = a + b * ( c - d );
 //
 // We should be familiar with expressions in many computer languages.
 //

 // :Def: Operator Syntax
 // The rules for using the operator in code written in the language.

 // :Def: Operator Semantics
 // A description of how an operator transforms its operands into a result.
 //
 // :Sample: int a,b; ... a + b;
 // Semantics of +: Result is signed integer sum, overflow ignored.


 /// SystemVerilog Operator Treatment -- Simulation
 //
 //  SystemVerilog 2012 defines operators and expressions in Chapter 12.
 //  Syntax and semantics must (shall!) follow standard.
 //  Semantics exactly described.


 /// SystemVerilog Operator Treatment -- Synthesis
 //
 //  Each synthesis program defines a synthesizable subset.
 //
 //  Cadence Encounter
 //
 //    Synthesizable Subset Described In
 //      HDL Modeling in Encounter RTL Compiler
 //        See Chapter 4, "Supported" sections.


 // :Def: Synthesizable Operator
 // An operator that's synthesizable by a particular synthesis program.


 /// Arithmetic Operators v. Other Operators
 //
 //  For logical operators it is easy to infer hardware,
 //   for example  assign x = a && b; would be inferred as an AND gate.
 //
 //  Arithmetic operators inference is not so simple because of:
 //   Operand width (number of bits).
 //   Operand type (signed v. unsigned).
 //   Need to provide optimization flexibility.
 //
 //  Inference of arithmetic and non-arithmetic operators covered in
 //  this set.


////////////////////////////////////////////////////////////////////////////////
/// Inference of Arbitrary Expressions

 /// Steps
 //
 //  - Use precedence and association to determine order.
 //  - Draw diagram.


module arb_exp
  ( output [7:0] x,
    input [8:0] a,
    input [6:0] b, c,
    input [2:0] e, f );

   assign x = a + b * c << ( e + f );

   /// Based on precedence and association:
   //
   // i1 = b*c;
   // i2 = a + i1;
   // i3 = e + f;
   // x = i2 << i3;

endmodule

 // 


////////////////////////////////////////////////////////////////////////////////
/// Inference of Non-Arithmetic Operators
///


 /// Boolean Two-Operand Logical Operators
 //
 //  &&,  ||  (AND, OR)
 //  <->, ->  (XNOR (equivalence), implication)  Note: not implemented.
 //
 //  - Both arguments are Boolean types.
 //  - Result is a 1-bit unsigned integer.
 //  - Arguments are converted into Boolean types if necessary.
 //
 //  All these can be inferred in a straightforward manner.
 //  Synthesizes into the gate that you would expect.

module example_bool_and_or
  (output uwire x, y,
   input uwire a, b);

   assign x = a && b;
   assign y = a || b;

endmodule

// 

 /// Conversion from Integer Types to Boolean Type
 //
 //  Integer Types
 //   Set l020 will cover types in detail.
 //   An example of an integer type is: uwire [7:0] a;
 //
 //  Conversion value a to Boolean:
 //    If a == 0, Boolean value is False.
 //    If a != 0, Boolean value is True.
 //    If a contains x's (undefined), Boolean value is x.
 //
 //  Synthesis of Integer-to-Boolean Conversion
 //
 //    For course assignments, assume that an n-bit integer
 //     is converted to a Boolean with an n-input OR gate.


// :Example:
//
// Convert 4-bit inputs a and b into Booleans, then perform AND operation.

module example_conversion
  (output uwire x,
   input uwire [3:0] a, b);

   assign x = a && b;
   //
   // Note that a and b are 4 bits each and that x is 1 bit.

endmodule

 // 


 /// Bitwise Logical Operators
 //
 //  &, |, ^,  (AND, OR, XOR)
 //
 //  - Both arguments are bit vectors.
 //  - Result is a bit vector at least as large as larger operand.
 //
 //  All these can be inferred in a straightforward manner.
 //  Synthesizes into a collection of gates, one gate for each bit.


module example_bitw_and
  (output uwire [3:0] x,
   input uwire [3:0] a, b);

   assign x = a & b;

endmodule

 // 

module example_bitw_and_or_xor
  (output uwire [3:0] x, y, z,
   input uwire [3:0] a, b);

   assign x = a & b;
   assign y = a | b;
   assign z = a ^ b;

endmodule



 /// Reduction Operators
 //
 //  Reduction operators convert multiple bits into one bit.
 //
 //  &, ~&, |, ~|, ^, ~^
 //
 //  - There is one argument, a bit vector.
 //  - In effect the operator is placed between adjacent bits ..
 //    .. for example, &x is equivalent to
 //    .. x[0] && x[1] && x[2] ..
 //    .. for x declared: logic x[0:2].
 //  - The result is one bit.
 //
 //  All these can be inferred in a straightforward manner.
 //  Synthesizes into a w-input gate, where w is the width of the operand.

module example_redlop
  (input uwire [3:0] a,
   output uwire x, y, z );

   assign x = &a;   // Equivalent to x = a[3] && a[2] && a[1] && a[0];
   assign y = |a;   // Reduction OR, same as conversion to Boolean.
   assign z = ^a;   // Reduction XOR, true if odd number of bits 1.

endmodule



 /// Shift
 //
 //  <<, <<<, >>, >>>
 //
 //  All these can be inferred in a straightforward manner.


 /// Concatenation
 //
 //  {}
 //
 //  Nothing to synthesize.




////////////////////////////////////////////////////////////////////////////////
/// Synthesis of The Conditional Operator, Index Op

 /// The conditional operator (s?a:b) is synthesized as a multiplexor.
//
// :Sample: assign x = s ? a : b;
// Two-input mux, x is control, a and b are data inputs.

module mux2
  ( output uwire [7:0] x,
    input uwire s,
    input uwire [7:0] a, b );

   assign x = s == 0 ? a : b;

endmodule

// 


// Note that a two-input multiplexor can be implemented using
// three gates per bit:

// 



// The following code containing chained conditional operators
// usually synthesizes to a single multiple-input multiplexor.
//
// :Example:

module mux4
  ( output uwire [7:0] x,
    input uwire [1:0] s,
    input uwire [7:0] a0, a1, a2, a3 );

    assign x =  s==0 ? a0 : s==1 ? a1 : s==2 ? a2 : a3;

endmodule

// 


 /// The index operator [] is inferred as a mux.
//
//   Consider a[s] where
//     s is n-bit vector 
//     a is a 2^n-element array of vectors.

module mux16
  ( output uwire [7:0] x,
    input uwire [3:0] s,
    input uwire [15:0][7:0] a );

   assign      x = a[s];

endmodule

module muxn
  #( int w = 16,
     int n = 4,
     int lgn = $clog2(n) )
  ( output uwire [w-1:0] x,
    input uwire [lgn-1:0] s,
    input uwire [w-1:0] a[n] );

   assign      x = a[s];

endmodule




////////////////////////////////////////////////////////////////////////////////
/// Inference of Comparison Operators
///

 /// Comparison
 //
 //  Ordinary comparison:  ==, !=,  >,   >=, <, <=
 //  Four-state compare:  ===, !==, ==?, !=?
 //
 //  - Result of all comparisons is one bit.
 //  - Several argument types possible: bit vectors, reals.
 //
 //  
 //  Synthesis programs will only work with ordinary comparisons of int types.
 //  Typically inferred into a library module.
 //  Magnitude comparison, such as >, <, can be implemented using subtraction.

module example_comparison
  (output uwire x,
   input uwire [7:0] a, b);

   assign x = a > b;

endmodule


 /// Arithmetic Operators
 //
 //  +, -, /, *, **, %
 //
 //  - Multiple argument types, eg, signed bit vector, integer, real.
 //  - Result type and width depends on operands.
 //
 //  Synthesis programs (so far) limit operator and operand combinations.
 //  Typically inferred into a library module.
 //
 /// Be Careful
 //
 //  - Pay attention to rules on bit widths.
 //  - Pay attention to rules on sign/unsigned integers.
 //  - Don't impede optimization by limiting widths or by touching bits.

module example_arithmetic
  (output uwire [8:0] x,
   input uwire [7:0] a, b);

   assign x = a + b;
   //
   // Note: because of x's size, a+b performed at width of 9 bits.

endmodule

 // :Example: Example of how helping hurts.
 //
 // Goal is to compute (a+b)/2  ...
 // ... but using formula a + (b-a)/2.
 //
 // We would like efficient hardware with a + (b-a)/2.
 //
 // If arithmetic expression written cleanly ..
 // .. synthesis program will transform a+(b-a)/2 to (a+b)/2.
 //
 // If arithmetic expression mixed with logic ..
 // .. synthesis program may not be able to transform expression.

module example_avg_helping_hurt
  ( output uwire [7:0] avg,
    input uwire [7:0] a, b );

   uwire [7:0]   a_inv = ~a;
   uwire [7:0]   minus_a = a_inv + 1;

   uwire logic [7:0] diff = b + minus_a;
   assign avg = diff[7:1] + a;

endmodule

module example_avg_good
  ( output uwire signed [7:0] avg,
    input uwire signed [7:0] a, b );

   assign avg = a + ( b - a ) / 2;

endmodule

module example_avg_best
  ( output uwire signed [7:0] avg,
    input uwire signed [7:0] a, b );

   assign avg = ( 0 + a + b ) / 2;

endmodule




 /// Pay Attention To
 //
 //  Data type and number of bits of inputs.
 //  Data type and number of bits of outputs.
 //
 //  Changes in the number of bits.
 //  Interpretation of integer as signed or unsigned.

 /// Widths (Size)
 //
 //  :Def: Self-Determined Expression Context
 //  Size determined by expression itself, not the surrounding context.
 //
 //  :Example:
 //
 //  x = a << E;   // E is in a self-determined context (by def of << operator).
 //                // Therefore size of E does not depend on a or x.
 //
 //
 //  :Def: Context-Determined Expression Context
 //  Size determined by expression itself, and by how or where it is used.
 //
 //  :Example:
 //
 //  x = E << b;  // E is in a context-determined context.
 //               // Size of E depends on size of x.

module example
  ( output uwire [4:0] x1, x2,
    input uwire [3:0] a, b,
    input uwire [6:0] c );

   assign x1 = ( a + b ) + c;
   //
   // Operands of + are context-determined,
   //  therefore width of adder inputs and outputs will be max(4,5,7) = 7;
   // x1 gets 5 LSB of result, the rest is discarded.

   assign x2 = a + b << c;
   //
   // c is self-determined, so its size stays at 7 (which is overkill).
   // Size of others is max(4,5) = 5.
   // Shifter's data input and outputs are 5 bits, shift amt is 7 bits.

endmodule




module bool_v_1bit
  ( output y1, output y2,
    input [7:0] a, b );

   // Consider
   //
   assign y1 = a && b;
   //
   //  The && is defined for 1-bit operands.
   //  


   assign y2 = a & b;
   //
   // Note: y2's size should match a and b's.


endmodule