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

 ///  Form 1: Combinational / Level Triggered

//  Sources: Ci:  Ciletti, Modeling, synthesis, and rapid prototyping
//                         with the Verilog HDL
//           Leo: Exemplar Logic (Mentor Graphics),
//                         LeonardoSpectrum HDL Synthesis Manual, October 2000


/// Contents

// Summary of Form 1
// Synthesis of Combinational Logic
// Inference of Arithmetic Units
// Inference of Registers.  (When is a reg a register?)
// Un-synthesizable Code  (barely started)
// Loops (Forms 1 and 2)  (incomplete)
// Case, If / Then /Else  (barely started)


/// Summary of Form 1

 /// Form 1: Combinational / Level Triggered
//
//    Describes combinational logic.
//    Describes level-triggered registers.
//    Unlimited number of level-trigger conditions.
//
 /// Basic Form
//
//  always @( a1 or a2 or /* ... */ an ) begin
//     <non-timing-statements>;
//  end
//
// The non-timing-statements include some but not all Verilog
// statements.  A complete list is not given here.
//

// Expressions used in non-timing-statements should use variables
// listed in the event control (a1, a2, ..., an) or variables that
// will have been written since the last event.

// Examples:

`ifdef NEVER
always @( a1 or a2 ) begin
   x = a1;  // Okay, a1 in event control.
   z1 = x;   // Okay, x written by this point.
   z2 = y;   // Not okay, y not written since last event.
   y = b;   // Not okay, b not in event control and not written here.
   if( a1 ) w = a2;  // Okay.
   v = w;   // Not okay, w may not be written since last event.
   if( a1 ) u = a2; else u = a1;
   s = u;   // Okay, u always written since last event.
end
`endif

// Not allowed:
//   Delays, including delayed nonblocking assignments.
//   Edge trigger: @( a1 or posedge a2 ... )
//   Event controls (other than first): @( foo or bar ).
//   Looping constructs with an infinite or non-constant number of iterations.
//   
 /// Inference of Registers (Synthesis of assignment statements.)
//   
//    Unconditional assignment to register generates wire:
//       x1 = a1 | a2;  // x1 synthesized as a wire, not a register.
//    Conditional assignment to register generates level-triggered register.
//       if( a3 ) x2 = a1 | a2;  // x2 synthesized as a register.
//    If there are multiple conditional assignments to a register and
//      at least one of them will execute, register synthesized as wire.

// Example:
`ifdef NEVER
module ex1();
always @( a1 or a2 or /* ... */ an ) begin
   // No event controls.  Not allowed:  @( a1 )
   // Only signals in event control, a1 .. an, can appear in expressions.
   x1 = a1 | a2;  // Okay.  x1 synthesized as wire.
   x2 = b1 | a1;  // WARNING: b1 not in event control.  syn != sim.
   if( a3 ) x3 = a1 & a2;  // x3 synthesized as level-triggered register.
   if( a1 | a2 ) x4 = a1 | a2;  // x4 synthesized as level-trig. register.
   if( a4 ) x5 = a3;  // Because this or assignment below will execute ...
   if( !a4 ) x5 = a2; // ...x5 synthesized as wire.
end
endmodule
`endif

/// Synthesis of Combinational Logic
   

 /// Describes a few simple gates.

module imply(aib,a,b);
   input a, b;
   output aib;
   wire   a, b;
   reg    aib;

   // Note: all inputs in event control.
   // Though declared as a register, aib will be synthesized as wire.
   
   always @( a or b ) aib = ~a | b;

endmodule


module bfa_behavioral(sum,cout,a,b,c);
   input a,b,c;
   output sum, cout;
   
   reg    sum, cout;
   reg    ab, ac, bc;

   // Because they are always assigned, regs above synthesized as wire.

   always @( a or b or c )
     begin
        sum = a ^ b ^ c;

        ab = a & b;
        ac = a & c;
        bc = b & c;

        cout = ab | ac | bc;
     end

endmodule

module l(q,d,c);
   input d, c;
   output q;

   reg    q;

   always @( d or c )
     if( c ) q = d; else q = ~d;

endmodule

   


/// Inference of Arithmetic Units

// Synthesis programs recognize common complex devices.  Usually
// arithmetic, comparison, and memory.

// Will match to technology-optimized version, if available.
// Otherwise will substitute gates realizing complex device.

 // Describes a simple multiplier.

module times_ten(tt,a);
   input a;
   output tt;
   wire [31:0] a;
   reg [31:0] tt;

   always @( a ) tt = a * 10;

endmodule

/// Inference of Registers.  (When is a reg a register?)

// Applies to Form 1

 /// In Form 1 a reg is synthesized as wire if:
//    the synthesis program determines that
//    it will be assigned on every iteration of the always block.


module inf_reg_examp(a, b, clk);
   input a, b, clk;
   wire [7:0] a, b;

   reg [7:0]  x, y, z, w, r;
   
   always @( a or b or clk ) begin

      x = a * 2 + b;
      
      // Assigned when clk is high, y is a level-triggered register.
      if( clk ) y = a + b;

      // Assigned whenever a > b, r is a level-triggered register.
      if( a > b ) r = 2 * a;

      // Combinational logic, probably a mux, with output z and
      // two inputs, a+b and a-b.  (No register.)
      if( clk ) z = a + b; else z = a - b;

      // a will be either 0, 1, or 6, nothing else!!!!!!!!!!!!!!!!!!!!
      // w is a register.  The comment above suggests w can be wire,
      // but the synthesis program can't read and understand it.
      if( a == 1 ) w = b + 5;
      if( a == 6 ) w = b - 5;
      if( a == 0 ) w = 0;
      
   end

endmodule

/// Un-synthesizable Code

// Leonardo 2000 (and many similar programs) will not synthesize:

//  Code in an initial block.
//  System tasks. ($display, etc.)
//  Delays. (#3)
//  Waits (wait( a==2))



/// Loops (Forms 1 and 2)

// Loops are allowed in Forms 1 and 2 iff:
//  the number of iterations can be determined at synthesis time.
//  (Can be determined by the synthesis program.)

// The loop is synthesized as though the loop were completely
// unrolled, that is as if the loop body were repeated for each loop index:

// A loop such as this:
//  for(i=0; i<3; i=i+1) a[i] = b[i];
//
// Is synthesized as though it were written like this:
//  a[0] = b[0];
//  a[1] = b[1];
//  a[2] = b[2];



module yet_another_pop(p,a);
   input a;
   output p;

   wire [31:0] a;
   reg [5:0]   p;

   integer     i;
   always @( a ) begin

      p = 0;

      // Loop okay, it's 32 iterations.
      // Synthesized hardware (before optimization) will use
      // 32 adders.

      // Since this is Form 1 and p always assigned, p is
      // synthesized as wire.

      // Actually, there will be 33 different wires that can be
      // labeled p (before optimization, and not counting the
      // individual bits).  

      // Each assignment defines a new p, the p assigned in the
      // last iteration of the loop is the module output.

      for(i=0; i<32; i=i+1) p = p + a[i];

   end
   
endmodule

module yet_another_pop_II(p,a);
   input a;
   output p;

   wire [31:0] a;
   reg [5:0]   p;

   reg [31:0]  acopy;


   always @( a ) begin

      p = 0;
      acopy = a;

      // Loop okay, it's 32 iterations.

      // This also synthesizes p and acopy as wire since
      // they are always assigned.  Similar to the previous
      // example, there will be 33 different wires that can
      // be called p and acopy.

      repeat( 32 )
        begin
           p = p + acopy[0];
           acopy = acopy >> 1;
        end

   end
   
endmodule

module yet_another_pop_III(p,a);
   input a;
   output p;

   wire [31:0] a;
   reg [5:0]   p;

   reg [31:0]  acopy;


   always @( a ) begin

      p = 0;
      acopy = a;

      // Loop not okay.

      while( acopy )
        begin
           p = p + acopy[0];
           acopy = acopy >> 1;
        end

   end
   
endmodule


/// If / Else

// Here is how code containing if / else statements will be
// synthesized. The inference of logic applies only to Form 1 but the
// combinational logic applies to all forms.

module if_else_example(x,y,z,a,b,s);
   input a, b, s;
   output x, y, z;
   reg    x, y, z;

   always @( a or b or s ) begin

      // Code below might be synthesized as a multiplexor, with
      // s as the control input and a and b as two data inputs.
      //
      // Because x is always assigned it is synthesized as wire.

      // Because y and z are sometimes assigned, they will be
      // synthesized as level-triggered registers. Register y is
      // clocked using s and z using not s.

      if( s )
        begin
           x = a;
           y = a;
        end else begin
           x = b;
           z = b;
        end
        
   end

endmodule

module nested_if_example(x,a,b);
   input a, b;
   output x;
   wire [7:0] a, b;
   reg [7:0]  x;

   // Since x is always assigned it will be synthesized as wire
   // (no registers).
   
   // The logic will consist of multiplexors, a multiplier (for b*a),
   // and two subtractors. (The synthesis program probably won't use
   // one subtractor for both a-b and b-a.)

   always @( a or b ) begin

      if( a > 100 ) begin

         if( b == 0 ) x = 1; else x = b * a;
         
      end else begin

         if( b < a ) x = a - b; else x = b - a;
         
      end

   end

endmodule


module if_else_example2(x,a,b,c,d,s);
   input a, b, c, d, s;
   output x;
   wire [2:0] s;
   reg        x;

   always @( a or b or c or d or s ) begin

      // Code below might be synthesized as a multiplexor, or
      // a cascade of three two-input multiplexors. 
      //
      // Because x is always assigned it is synthesized as wire.

      if( s[0] ) x = a;
      else if ( s[1] ) x = b;
      else if ( s[2] ) x = c;
      else x = d;
        
   end

endmodule


module if_else_example3(x,a,b,c,d,s);
   input a, b, c, d, s;
   output x;
   wire [3:0] s;
   reg        x;

   always @( a or b or c or d or s ) begin

      // Code below might be synthesized as a multiplexor, or
      // a cascade of three two-input multiplexors. 
      //
      // Unlike the example above, here x may not be assigned (when
      // s == 0, and so it will be synthesized as a register.
      // The register is clocked when x is assigned, which is
      // when s is nonzero.

      if( s[0] ) x = a;
      else if ( s[1] ) x = b;
      else if ( s[2] ) x = c;
      else if ( s[3] ) x = d;
        
   end

endmodule



/// Case

// A case statement can be converted to an if/else chain (see
// Case_eq_if) example below), and so alot of the synthesis rules for
// if/else chains apply to case statements.  However, synthesis
// programs can sometimes recognize special forms of case statements
// that result in simpler logic.

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

   always @( a or b ) begin

      // A case statement.

      // Since x is always assigned it is synthesized as
      // a wire.  Multiplexors pass the correct value of x,
      // the control inputs are based on the case conditions.
      
      casez( {a,b<c} )
        {b,      c[1]}: x = 3;
        {4'd5,   1'd1}: x = c;
        {4'b???, a<b}:  x = b;
        default:        x = a;
      endcase

      // The equivalent if/else chain.

      if      ( a === b    && (b<c) == c[1]  ) y = 3;
      else if ( a === 4'd5 && (b<c) == 1'd1  ) y = c;
      else if (               (b<c) == (a<b) ) y = c;
      else                                     y = a; 
      
   end

endmodule


// The example below shows a case statement as it will more
// commonly be used.

module alu(op,r,a,b);
   input op, a, b;
   output r;
   reg    r;

   wire [1:0] op;

   // Because the case items are sequential constants, the
   // synthesis program should use a multiplexor controlled by
   // op, rather than a cascade of multiplexors, as would
   // be used by the code above.  Also, the synthesis program
   // will realize that r is always assigned because op is
   // two bits and all cases are present, and so r is wire,
   // not a register.

   always @( op or a or b )
     case ( op )
       2: r = a & b;
       3: r = a | b;
       1: r = a + b;
       0: r = a - b;
     endcase

endmodule



///  Case Statement Synthesis Directives  
 /// (Leonardo Spectrum v1999.1f)
//
 /// Purpose:
//   Tell synthesis program which case expression values are impossible.
//   With this information unnecessary hardware omitted.
//
 /// Directives:
//   parallel_case: At most one case item is true.
//   full_case:     At least one case item is true.
//
 /// full_case
//   At least one case item is true.
//   With this directive synthesis program will omit latches under
//   certain circumstances.
//
 /// parallel_case
//   At most one case item is true.
//   Simplifies case logic.
//
 /// Automatic Detection of Case Item Possibilities
//   Leonardo can automatically detect when full_case and parallel_case
//     apply to case statements.
//   Its detection capabilities are limited though:
//     In some cases it cannot detect parallel and full case even though
//      there is enough information in the case statement to do so.
//     In other cases information not present in the module (and
//      unavailable to the synthesizer) is needed to prove that cases
//      are parallel or full.