```///  LSU EE 4755 -- Fall 2017 -- 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
//
// :BV3:  Brown & Vranesic, Fundamentals of Digital Logic with Verilog, 3rd Ed.
//        The text used in LSU EE 2740.

////////////////////////////////////////////////////////////////////////////////
/// 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.
//
//
//    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
//  Context in which size determined by expression itself, not the 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

```