// Verilog Synthesis Notes and code for LSU EE 4702 Spring 2000

`define EDGE2

// Notes on Synthesis of Procedural Code: The Three Forms

// Material below based on LeonardoSpectrum HDL Synthesis manual and
// Ciletti Chapters 8, 9, and 10.  The discussion in Ciletti is of
// synthesis programs in general so some details differ.

`ifdef DONTDEFINEME
////////////////////////////////////////////////////////////////////////////////

// Leonardo (1999.1f) will synthesize procedural code only if it is
// in one of three forms:
//
//   Form 1: Combinational / Level Triggered
//   Form 2: Edge Triggered
//   Form 3: Implicit State Machine
//
//   This applies to each process (code starting with "always").  A
//   module can have any number of processes and each can be in any of
//   these forms. (However a register can only be written in a single
//   process.)
//
// Summary of Forms
//
//  Form 1: Combinational / Level Triggered
//
//    Describes combinational logic.
//    Describes level-triggered registers.
//    Unlimited number of level-trigger conditions.
//
//  Form 2: Edge Triggered
//
//    Describes registers clocked on the edge of a single signal.
//    Registers can also be written with constants at asynchronous trigger.
//
//  Form 3: Implicit State Machine
//
//    Describes a state machine synchronized to a clock.
//
//
//  Caution
//
//    Code which is not in one of these forms may:
//
//      Cause synthesis to stop with a helpful error message.
//
//      Cause the synthesis program to issue a warning message but
//      continue to synthesize.  The synthesized description will
//      function differently than the Verilog code read by the
//      synthesizer.  This is why one must simulate the synthesized
//      code.
//
//      Be processed by the synthesizer without even a warning.  The
//      synthesized description will function differently than the
//      Verilog code read by the synthesizer.  Just think of the
//      "back in my day" stories you can tell your grandchildren
//      if they become EEs!


//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

// Detailed Descriptions

//------------------------------------------------------------------------------

// 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.
//
// Not allowed:
//   Edge trigger in first event control: @( 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:
   
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

//------------------------------------------------------------------------------

// Form 2: Edge Triggered

//    Describes registers clocked on the edge of a single signal which
//    can also be written with a constant at an asynchronous trigger.


// Basic Form

always @( posedge s1 or posedge s2 or posedge s3 or /* ... */ posedge sn )
  if( s1 ) begin
     <constant-assignments>;
  end else if ( s2 ) begin
     <constant-assignments>;
  end else if ( s3 ) begin
     /* ... */
  end else begin
     <non-timing-statements>;
  end

// The form above must be adhered to, in particular:
//
//   All terms in the event expression must be either posedge or negedge
//   of a signal.  No signal can appear more than once.
//
//   The condition in each of the if statements shown above must be
//   one of the signals in the event expression.  If the event
//   expressions is "posedge foo" then the condition must be ( foo ),
//   if the event expression is "negedge foo" the condition must be (
//   !foo ).  All of the signals except one must appear in one of the
//   if conditions. The signal that's not used is called the clock.
//
//   Procedural statements can only be added where <constant-assignments>
//   and <non-timing-statements> appear.  
//
//   Assignments in <constant-assignments> can only assign constants
//   or constant expressions. x1 = 0 is okay but x1 = a1 is not.  If
//   this rule is violated there will be a warning and the synthesized
//   hardware will behave differently than the simulated hardware.
//   One minor exception: signals in the event expression can be
//   tested, except the one in the condition immediately preceding the
//   code. (Whose value is known anyway.)
//
//   Assignments in <non-timing-statements> can assign any valid
//   expression.  That is, a signal can be used in an expression
//   whether or not it appears in the event expression.  Timing
//   controls cannot be used in <non-timing-statements>, nor can loops
//   with a non-constant number of iterations.
//
// Inference of Registers (Synthesis of assignment statements.)
//
//    Registers synthesized for all assignments.
//
//    Unconditional assignment in <non-timing-statements>:
//       Edge-triggered (on clock).
//       x1 = a1 | a2; // x1 loaded with a1 | a2 on edge of clock.
//
//    Conditional assignment in <non-timing-statements>:
//       Edge-triggered (on clock) with enable signal.
//       if( a3 ) x2 = a1 | a2; // x2 loaded with a1 | a2 on edge of clock if a3.
//
//    Assignments in <constant-assignments>
//       Asynchronous set or reset triggered on signal in if condition.
//       x1 = 0; // Load x1 with zero when sx true or false.
//
//    Note: The same register CAN be written in <constant-assignments> and
//    <non-timing-statements>, see "a" below:  On a positive edge of
//    the clock (which may be sn) "a" will be loaded with "c". Whenever
//    "s1" is 1 a will be set to zero, when "s1" and "s2" are 0 "a"
//    will be set to one.
//
// Example:

always @( posedge s1 or negedge s2 or posedge s3 or /* ... */ posedge sn )
   if( s1 ) begin
      // Can only assign constants here.
      a = 0; // Asynchronous reset when s1 true.
      b = c; // WRONG: c not a constant.
   end else if ( !s2 ) begin  // Note condition in if.
      // Can only assign constants here.
      a = 1; // Asynchronous set when s2 false and s1 false.
      b = 0; // Asynchronous reset when s2 false and s1 false.
   end else if ( s3 ) begin
      // ...
   end else begin  // Note that there is no condition after the else.
      // Edge triggered assignments here.
      a = c;  // Assign a to c on a positive edge of the clk.
      if( c ) x1 = a3;  // Edge triggered assignment to x1 if c true.
   end


//------------------------------------------------------------------------------

// Form 3: Implicit State Machine (To be covered 14 April 2000 or later.)
//
//    Describes a state machine synchronized to clock.
//
// Basic Form
//
//    always <clk-or-non-timing-statements>;

// <clk-or-non-timing-statements> can include one kind of timing
// statement:  @( posedge clk ).  (negedge can be used, clk can
// be any signal.).
//
// The timing statement must appear at least once on every cycle through
// a non-constant or infinite loop. (See examples.)
//

//   Okay, timing control appears once:
      always @( posedge clk ) a = a + 1;
      always begin @( posedge clk ); a = a + 1; end
      always begin if( a1 ) @(posedge clk ) a = a + 1; else @(posedge clk );

//   Okay, timing control appears twice:
      always @( posedge clk ) begin @(posedge clk) a = a + 1; end
      always begin @( posedge clk ); @(posedge clk) a = a + 1; end

//   NOT okay, timing control may appear zero times (if a1 false).
      always begin if( a1 ) @(posedge clk ) a = a + 1;

// Inference of Registers (Synthesis of assignment statements.)
//
//   Registers synthesized for all assignments, edge triggered on clk.
//
//   State register inferred, state corresponds to position in procedural
//   code.

`endif
////////////////////////////////////////////////////////////////////////////////

// Code Examples:

`ifdef EDGE1

// Plain old edge triggered flip flop.

module edge_triggered(q, d, clk);

   input d, clk;
   output q;

   wire   d, clk;
   reg    q;

   // Synthesis program will use an edge-triggered flip-flop to
   // hold q.
   
   always @( posedge clk ) q = d;
   
endmodule // edge_triggered
`endif

`ifdef EDGE2
module misc_edge_trig(x1, x2, x3, a, b, c, clk);

   input a, b, c, clk;
   output x1, x2, x3;

   wire   a, b, c, clk;
   reg    x1, x2, x3;

   // Synthesis program uses edge triggered flip-flops for x1, x2, and x3.
   // The clocking of x2 and x3 use the positive edge of clk and are
   // also enabled: by a & c for x2, and a & b for x3.

   always @( posedge clk )
     begin
        x1 = a;
        if( a & c ) x2 = a | b;
        if( a & b ) x3 = c;
     end

   // Below: Rejected by synthesizer because of concurrent assignment to x1.
   // always @( c ) if( c ) x1 = 0;
   
endmodule 
`endif

`ifdef EDGE3
module misc_edge_trig(x1, x2, x3, a, b, c, clk);

   input a, b, c, clk;
   output x1, x2, x3;

   wire   a, b, c, clk;
   reg    x1, x2, x3;

   // Synthesis program will chose an edge triggered flip-flop
   // for x1 with an asynchronous reset input.  On a positive edge
   // of clk a will be clocked into x1, whenever c is high x1 is
   // set to zero.  Signal clk is used as an edge trigger because
   // its value is not tested (unlike c).
   
   always @( posedge clk or posedge c )
     begin
        if( c ) x1 = 0; else x1 = a;
     end

   // Edge triggered flip-flops used for x2 and x3; x3 uses a
   // clock enable.

   always @( posedge clk )
     begin
        x2 = a | b;
        if( a & b ) x3 = c;
     end
endmodule 
`endif // ifdef EDGE3


// Example of a multifunction counter.

`ifdef COUNTER
module counter(cnt,op,d,clk);
   input op, d, clk;
   output cnt;

   reg [7:0] cnt;
   wire [1:0] op;
   wire [7:0] d;
   wire       clk;

   parameter  op_incr = 0;
   parameter  op_decr = 1;
   parameter  op_load = 2;
   parameter  op_hold = 3;

   // Leonardo will synthesize an edge triggered register for cnt.

   always @( posedge clk )
     case ( op )
       op_incr: cnt = cnt + 1;
       op_decr: cnt = cnt - 1;
       op_load: cnt = d;
     endcase // case( op )

endmodule // counter
`endif

// Basic level-triggered flip-flop.

`ifdef LEVEL1
module level_triggered(q1, q2, d, enable);

   input d, enable;
   output q1, q2;

   wire   d, enable;
   reg    q1, q2;

   // A level-triggered flip-flop is chosen for q1.

   always @( enable or d ) if( enable ) q1 = d;

   // WARNING: The Leonardo synthesized code will function differently
   // than the simulated code.  In the synthesized code q2 is
   // connected directly to d whereas the Verilog code says q2 should
   // only be assigned when enable changes.
   
   always @( enable ) q2 = d;
   
endmodule 
`endif


`ifdef LEVEL2
module test(qlevelm,qlevelc,qclk,enable,d,x);

   input enable, d, x;
   output qlevelm, qlevelc, qclk;

   reg qlevelm, qlevelc, qclk;
   wire enable, d, x;

   // Level triggered chosen for qlevelm.
   always @( enable or d or x ) if( enable ) qlevelm = d ^ x;

   // This WILL NOT synthesize a level-triggered flip-flop.  Do
   // not use code like this.
   always @( enable or d or x ) qlevelc = enable ? d ^ x : qlevelc;

   // Edge triggered flip-flop chosen for qclk.
   always @( posedge enable ) qclk = d ^ x;

endmodule // test
`endif // ifdef LATCH