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

//  Form 2: Edge 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

// Form 2: Edge Triggered  Summary
// Form 2, Basic
// Form 2, Asynchronous Reset



/// Form 2: Edge Triggered  Summary

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


// Basic Form

`ifdef XX
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
`endif

// 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
//   expression is "posedge foo" then the condition must be ( foo )
//   and if the event expression is "negedge foo" the condition must
//   be ( !foo ).  All of the signals in the event expression 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.

//   A register can be assigned multiple times within an always
//   block, but the same register CANNOT be assigned in different
//   always blocks. (This is true for all forms.)   

 /// 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:

`ifdef NEVER
module dummy();
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
endmodule
`endif


/// Form 2, Basic


`define xFORM2_FF1
`ifdef FORM2_FF1

module form2_basic(q, d, clk);
   input d, clk;
   output q;
   reg    q;

   // A simple edge-triggered flip-flop.

   always @( posedge clk )
     begin

        q = d;
        
     end

endmodule
`endif

`define xFORM2_FF2
`ifdef FORM2_FF2
module form2_basic(q, d, r, clk);
   input d, r, clk;
   output q;
   reg    q;

   always @( posedge clk )
     begin

        // Synchronous reset
        if( r ) q = 0; else q = d;
        
     end

endmodule
`endif

 /// Multiple flip-flops clocked by same signal (clk).
 //
`define xFORM2_FF3
`ifdef FORM2_FF3
module form2_basic(q1, q2, d1, d2, clk);
   input d1, d2, clk;
   output q1, q2;
   reg    q1, q2;

   always @( posedge clk )
     begin
        q1 = d1 | d2;
        q2 = d1 & d2;
     end

endmodule
`endif

 /// Multiple flip-flops, individually clocked.
 //
`define xFORM2_FF4
`ifdef FORM2_FF4
module form2_basic(q1, q2, d1, d2, clk1, clk2);
   input d1, d2, clk1, clk2;
   output q1, q2;
   reg    q1, q2;

   // Note: each always updates a different register.
   
   always @( posedge clk1 )
     begin
        q1 = d1 | d2;
     end

   always @( posedge clk2 )
     begin
        // Commented line not allowed.
        // q1 = d1 ^ d2;
        q2 = d1 & d2;
     end

endmodule
`endif



`define xFORM2_UPDOWN
`ifdef FORM2_UPDOWN
module up_down_counter(count,op,din,clk);
   input op, din, clk;
   output count;

   wire [1:0] op;
   wire [3:0] din;
   wire       clk;
   reg [3:0]  count;

   parameter  op_hold = 0;
   parameter  op_up   = 1;
   parameter  op_down = 2;
   parameter  op_load = 3;

   always @( posedge clk )
        case( op )
          op_hold: count = count;
          op_up:   count = count + 1;
          op_down: count = count - 1;
          op_load: count = din;
        endcase
      
endmodule
`endif

/// Form 2, Asynchronous Reset


`define FORM2sr_FF1
`ifdef FORM2sr_FF1
module form2_sr(q, q1, q2, d, r, rx, clk, a, b);
   input d, r, clk, a, b, rx;
   output q, q1, q2;
   reg    q;
   reg    q1, q2;

   always @( posedge clk or posedge r or posedge rx )
     begin

        // Asynchronous reset
        if( r ) begin
           q = 0;
           q1 = 1;
        end else if( rx ) begin 
           q = 0;
           q1 = 0;
        end else begin 
           q = d;
           q1 = a + b;
        end
        
     end

endmodule
`endif