/// LSU EE 3755 -- Fall 2013 -- Computer Organization
//
/// Verilog Notes 6 -- Synthesis of Procedural Code

/// Under Construction, Mostly Complete
//  Time-stamp: <30 September 2013, 9:20:38 CDT, koppel@dmk-laptop>
//
// Possible Changes and Additions
//
//   More illustrations of synthesized hardware.
//   More examples, including one with a state machine.
//   Testbench for population count modules.


/// Contents
//
// Synthesis of Procedural Code (Three Forms)
// Form 1 - Combinational Logic and Level-Triggered Reg
// Form 2 - Edge-Triggered Flip-Flops
// Synthesis of Forms 1 and 2 (Summary of Classes)
// Synthesis: Assignments Class, some FormEnd Class cases.
// Syntax and Simulation of if else
// Synthesis of Conditional Class (if/else)
// Syntax and Simulation of case
// Synthesis of Conditional Class (case, if/else chains)
// Syntax and Simulation of for, while, repeat
// Synthesis of Iteration Class (for, while, repeat)
// Ripple Adder: Combinational v. Sequential
// Miscellaneous Examples


/// References
//
// :P:   Palnitkar, "Verilog HDL"
// :Q:   Qualis, "Verilog HDL Quick Reference Card Revision 1.0"
// :H:   Hyde, "Handbook on Verilog HDL"
// :LRM: IEEE, Verilog Language Reference Manual  (Hawaii Section Numbering)
// :PH:  Patterson & Hennessy, "Computer Organization & Design"
// :LSS: Exemplar Logic, LeonardoSpectrum HDL Synthesis




////////////////////////////////////////////////////////////////////////////////
/// Synthesis of Procedural Code (Three Forms)

// :P: 14.3.3 Covers a few bits and pieces.
// :LSS: 7  Does not follow approach used here.  Provides additional details.

 /// Synthesizable Definition
//
// A property of an HDL description indicating that a synthesis program
// will correctly synthesize it.  Whether a description is synthesizable
// depends upon the synthesis program used.
//
// Not all procedural code is synthesizable.
//
// These notes are for a particular synthesis program, Encounter
// RTL. Other contemporary mid-line synthesis programs are similar but
// not identical.

 /// Note
//
// In these notes flip-flop and registers are used interchangeably.
// (A register is a collection of flip-flops meant to store data. A
// one-bit register is equivalent to a flip-flop as used here.)

 /// The Two Synthesizable Forms
//
// An always block is synthesizable if it is in one of three forms:
//
// Form 1
//   Synthesizes into combinational logic and level-triggered flip-flops.
//
// Form 2
//   Synthesizes into edge triggered flip flops.
//
// The form applies to a procedural block starting with "always."
// A module can have any number of such blocks, each block can
// be in any form.
//
// Blocks starting with initial are not synthesizable.

 /// Synthesis of Forms 1 and 2
//
// Okay, so what will the hardware look like?
//
// See the Synthesis of Forms 1 and 2 section further below.


////////////////////////////////////////////////////////////////////////////////
/// Form 1 - Combinational Logic and Level-Triggered Reg

// Describes combinational logic and level-triggered flip-flops (latches)

// :Syntax:  always @( OBJ1 or OBJ2 or ... ) begin ST1; ST2; ... end
//
// OBJ1, OBJ2, etc are the names of nets are variables; these are
// said to be in the /sensitivity list/.
//
// ST1, ST2, etc are statements that conform to the following rules:
//
//   Every net or variable appearing in an expression must be in the
//   sensitivity list unless that value is written by an earlier
//   statement.  (If this rule is not followed simulation will not
//   match synthesis.)
//
//   ST1, ST2, etc. must not contain delays or event controls (#5,
//   @( a ), wait).
//
//   The number of iterations performed by looping constructs must be
//   determinable by the synthesis program at analysis time (sort of
//   like compile time). 
//
//   System tasks ($display, etc.) not allowed.
//
//   Code between comments "// cadence translate_off" and "// cadence
//   translate_on" will be ignored by the synthesis program and so
//   need not follow the rules above. This code might be used for
//   debugging and sanity checks (checks for design errors).
//
//   Other restrictions to be covered later.
//
// Execution
//
//   Activity flow starts (at ST1) each time there is a change
//   on any of the items in the sensitivity list: OBJ1, OBJ2,


// :Example:
//
// An 8-bit adder in Form 1.

module sum_using_form_1(sum,a,b);
   input [7:0] a, b;
   output      sum;
   reg [8:0]   sum;

   // Code below executes each time a or b changes.
   // always @( OBJ1 or OBJ2 or ... ) -> always @( a or b )
   always @( a or b )
     begin
        sum = a + b;  // ST1
     end

endmodule


// :Example:
//
// Example of something which is almost Form 1.  Unlike the adder
// above, the output of the module will not change when b changes,
// at least according to the simulator. (Some synthesis programs
// incorrectly synthesize this.)

module sum_using_not_quite_form_1(sum,a,b);
   input [7:0] a, b;
   output      sum;
   reg [8:0]   sum;

   // Code below executes each time a changes.  This is close to
   // Form 1, but not the same. (Simulated and synthesized versions
   // will differ.)
   always @( a )
     begin
        sum = a + b;
     end

   // Remember, code above is NOT Form 1 (nor any other synthesizable form).

endmodule


// :Example:
//
// A module for computing a complex product.

module complex_prod(xr,xi,ar,ai,br,bi);
   input [31:0] ar, ai, br, bi;
   output       xr, xi;
   reg [31:0]   xr, xi;

   // Temporary variables to hold products.
   reg [31:0]   p1, p2;

   always @( ar or ai or br or bi )
     begin
        xr = ar * br - ai * bi;
        p1 = ar * bi;
        p2 = ai * br;
        xi = p1 + p2;
     end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Form 2 - Edge-Triggered Flip-Flops

// Describes edge-triggered flip flops.

// The description below is a simplified version of Form 2.  The
// full version of Form 2 (not covered) includes asynchronous resets.

// :Syntax:  always @( posedge CLK ) begin ST1; ST2; ... end
//
// CLK is a net or variable.
//
// ST1, ST2, etc are statements that conform to the following rules:
//
//   ST1, ST2, etc. must not contain delays or event controls (#5,
//   @( a ), wait).
//
//   Each variable can be assigned in only one always block.
//
//   The number of iterations performed by looping constructs (covered
//   soon) must be determinable by the synthesis program at analysis
//   time (sort of like compile time).  This will be explained further
//   when looping constructs are covered.
//
//   No system tasks ($display, etc.).
//
//   Other restrictions to be covered later.


// :Example:
//
// Module describing an adder with a buffered output.  On the positive
// edge of clk output sum is set to a+b; that sum stays there until
// the next positive edge.

module sum_using_form_2(sum,a,b,clk);
   input [7:0] a, b;
   input       clk;
   output      sum;
   reg [7:0]   sum;

   // Code below executed each time clk changes to 1.
   // always @( posedge CLK ) -> always @( posedge clk )
   always @( posedge clk )
     begin
        sum = a + b;   // ST1
     end

endmodule


// :Example:
//
// A module for computing a complex product.  The product
// is updated on the positive edge of the clock.

module complex_prod_2(xr,xi,ar,ai,br,bi,clk);
   input [31:0] ar, ai, br, bi;
   input        clk;
   output       xr, xi;
   reg [31:0]   xr, xi;

   // Holds products.
   reg [31:0]   p1, p2;

   always @( posedge clk )
     begin
        xr = ar * br - ai * bi;
        p1 = ar * bi;
        p2 = ai * br;
        xi = p1 + p2;
     end

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Synthesis of Forms 1 and 2 (Summary of Classes)

// Synthesis
//
//   Synthesizable code will be decomposed into four classes,
//   each with its own simple synthesis rules.
//
//   The Classes:
//
//      Assignment:   (Covered here)
//      Conditional:  (Covered soon) if/else and case.
//      Iterative:    (Covered later) for, while, repeat, [forever]
//      FormEnd:      (Covered soon.) Indicates the end of a procedural block.
//
//   Notation:
//
//      SStatement -> Assignment | Conditional | Iterative
//      (SStatement can refer to either Assignment, Conditional, or Iterative.)

// Structure of Form 1 always Block:
//
//   :Syntax: always @( SLIST ) SStatement FormEnd
//   :Syntax: always @( SLIST ) begin SStatement SStatement ... end FormEnd
//
// See first example below.

// Structure of Form 2 always Block:
//
//   :Syntax: always @( posedge CLK ) SStatement FormEnd
//   :Syntax: always @( posedge CLK )
//               begin SStatement SStatement ... end FormEnd


// :Example:
//
// Module with comments indicating how the code is classified.

module syn_example_f1(x,y,a,b,c);
   input [7:0] a, b, c;
   output      x, y;
   reg [8:0]   x, y;

   // SLIST -> a or b or c
   always @( a or b or c )
     begin
        x = a + b;          // SStatement -> Assignment -> x = a + b;
        y = x & c | b;      // SStatement -> Assignment -> y = x & c | b;
        x = b + 7;          // SStatement -> Assignment -> x = b + 7;
     end
   // FormEnd   There is no code here, it's just a place marker.

endmodule


 /// Classes
//
// For Each Class:
//
//  Hardware is synthesized.
//  The hardware emits updated values of variables.
//
// So, for each class we need to:
//
//  Determine what hardware is synthesized.
//  Determine which variables get updated values.
//
// Warning:
//
//  The descriptions of synthesized hardware below are occasionally
//  simplified and may omit special cases, especially special cases
//  that the writer (me) is not aware of!


 /// Summary of Classes
//
// Assignment
//
//  :Sample:  x = a + b;
//
//   Hardware:
//      Combinational logic for right-hand side (RHS) of assignment.
//      An adder for the sample above.
//   Updated Variable:
//      The assigned variable. Variable x in the sample above.
//
// Conditional (Based on material covered later.)
//
//  :Sample: if ( a ) begin x = y; c = 5; end else begin c = z; end
//   Note: also includes case.

module syn_example_f1(x,y,a,b,c);
   input [7:0] a, b, c;
   output      x, y;
   reg [8:0]   x, y;
   integer     i;

   integer     lc;

   always @( a or b or c )
     begin
        x = 0;
        for ( i=0; i<8; i=i+1 ) begin x = x + a[i]; end
     end

endmodule;

//
//   Hardware:
//      One multiplexor for each updated variable, each input
//      from a different path (if, else).
//   Updated Variables:
//      All variables modified in "if" or "else" parts.
//
//
// Iterative (Based on material covered later.)
//
//  :Sample: for (i=0;i<5;i=i+1) begin s = s + a[i]; end
//   Note: also includes while, repeat, [forever].
//
//   Hardware:
//      Synthesize n copies of hardware corresponding to the loop body,
//      where n is the number of iterations.
//   Updated Variables:
//      All variables updated in last (or any) iteration.
//
//
// FormEnd
//
//   This one is important and is described in several places below.
//
//   Each variable may synthesize in to a register, which means
//   a variable may NOT synthesize in to a register.  This has
//   nothing to do with the declared type, since that should be
//   reg (though one might get away with integer).
//
//   Hardware:
//      Form 1: Level-triggered registers (latches) for some modified variables.
//      Form 2: Edge-triggered registers for some modified variables.
//   Updated Variables:
//      Those for which registers synthesized.


////////////////////////////////////////////////////////////////////////////////
/// Synthesis: Assignments Class, some FormEnd Class cases.

 /// Assignment Class
//
// :Sample: sum = a + b;
//
// Hardware:
//
//   Combinational logic corresponding to RHS, (the same hardware that
//   would be synthesized for an assign).
//
// Updated Variable
//
//   Variable on LHS.


 /// FormEnd Class -- Form 1, No Conditional Code
//
// Hardware:
//
//   None.
//
// Updated Variables.
//
//   None, since there is no hardware.

 /// FormEnd Class -- Form 2, No Conditional Code
//
// Hardware:
//
//   For each variable assigned in the always block an edge-triggered
//   flip-flop is synthesized. The latest value connects to the data
//   (d) input and CLK connects to the clock input.  The q output is
//   the value used by all non-procedural code and the first statement
//   of all procedural code.
//
// Updated Variables:
//
//   One for each flip-flop output.


// :Example:
//
// Module showing how its code is classified by structure above.

module syn_example2_f1(z,x,y,a,b,c);
   input [7:0] a, b, c;
   output      x, y, z;
   reg [8:0]   x, y;
   wire [8:0]  z;

   assign      z = x + 5;

   always @( a or b or c )
     begin
        x = a + b;       // HW: adder.       Updated Variable: x
        y = x & c | b;   // HW: AND and OR.  Updated Variable: y.
        x = b + 7;       // HW: adder.       Updated Variable: x
     end
   // FormEnd:   Nothing synthesized.

endmodule


// :Example:
//
// Module showing how its code is classified by structure above.

module syn_example2_f2(z,x,y,a,b,c,clk);
   input [7:0] a, b, c;
   input       clk;
   output      x, y, z;
   reg [8:0]   x, y;
   wire [8:0]  z;

   assign      z = x + 5;

   always @( posedge clk )
     begin
        x = a + b;       // HW: adder.       Updated Variable: x
        y = x & c | b;   // HW: AND and OR.  Updated Variable: y.
        x = b + 7;       // HW: adder.       Updated Variable: x
     end
   // FormEnd:   Edge-triggered FF for y and x.

endmodule


////////////////////////////////////////////////////////////////////////////////
/// Synthesis of Conditional Class (if/else)


 /// Conditional - if / else
//
//:Syntax: if ( COND ) IFPART
//:Syntax: if ( COND ) IFPART else ELSEPART;
//
// Hardware:
//
//   Synthesize hardware for IFPART and ELSEPART.
//
//   Synthesize hardware to evaluate COND, call the output cond.
//
//   Determine the union of variables modified in IFPART and ELSEPART.
//   For each variable in the union:
//
//      Synthesize a two-input multiplexor.
//
//      Connect one input to the latest value in IFPART, or if the
//      variable isn't updated in IFPART, the latest value before the
//      "if".
//
//      Connect the other input to the latest value in ELSEPART, or if
//      the variable isn't updated in ELSEPART, the latest value
//      before the "if".
//
//      Connect cond to the control input.
//
//      The multiplexor output is the updated value.
//
//      A multiplexor might be eliminated in an optimization step,
//      see FormEnd below.
//
// Updated Values
//
//   All variables modified in "if" or "else" parts.


 /// FormEnd Class Form 1, Conditional
//
// Updated Variables
//
//    Those which may be unchanged due to an if or case condition.
//    (Such as y in the example below.)
//
// Hardware
//
//    For each possibly unchanged variable:
//
//       A level-triggered flip-flop (latch).
//
//       Logic that determines whether the variable will change, that
//       logic connects to the flip-flop clock (or enable) input.
//       (This may be the same or similar to the multiplexor input
//       from Conditional class logic.)
//
//       The latest value connects to the data (d) input.
//
// Optimization
//
//    In many cases multiplexors can be eliminated. (See y in
//    the example below.)


 /// FormEnd Class Form 2, Conditional
//
// Updated Variables
//
//    All assigned variables.
//
// Hardware
//
//    For each variable:
//
//       An edge-triggered flip-flop.
//
//       CLK (see Form 2 syntax) connects to the clock input.
//
//       Logic that determines whether the variable will change, that
//       logic connects to the flip-flop enable input.  (This may be
//       the same or similar to the multiplexor input from Conditional
//       class logic.)
//
//       The latest value connects to the data (d) input.


// :Example:
//
// Very simple module to illustrate synthesis of if statement
// in Form 1 code.

module cond_form_1_example1(x,a,b,c);
   input a, b,c;
   output x;
   reg    x;

   always @( a or b or c )
     begin
        if ( a ) x = b | c;  // SStatement1
     end
   // FormEnd

endmodule

// Here is how the module above should be /parsed/:
//
// SStatement1 -> Conditional -> if ( COND ) IFPART
//   COND -> a
//   IFPART -> x = b | c;
//


// :Example:
//
// Simple module to illustrate synthesis of if/else statements in
// Form 1 code.
// Level-Triggered Registers: y, enabled by a.

module cond_form_1_example2(x,y,a,b,c);
   input a,b,c;
   output x,y;
   wire [7:0] b, c;
   reg [8:0]  x, y;

   always @( a or b or c ) begin
      if ( a ) begin
         x = b + c;
         y = b - c;
      end else begin
         x = b - c;
      end
   end
endmodule

// Synthesized Hardware:  
// :Example: // // Simple module to illustrate synthesis of if/else statements in // Form 2 code. // Edge-Triggered Registers: x and y. module cond_form_2_example2(x,y,a,b,c,clk); input a,b,c; input clk; output x,y; wire [7:0] b, c; reg [8:0] x, y; always @( posedge clk ) begin if ( a ) begin x = b + c; y = b - c; end else begin x = b - c; end end endmodule // :Example: // // Example of an if/else if/else chain. // Registers: None. (x assigned on all paths.) module anotherif (x,a); input [7:0] a; output x; reg [7:0] x; always @( a ) begin if ( a < 10 ) x = 1; // IFPART1 else // ELSEPART1 if ( a < 50 ) x = 2; // IFPART2 else // ELSEPART2 if ( a < 200 ) x = 3; else x = 4; end endmodule // :Example: // // Example of an if/else if/else chain. // Level-Triggered Registers: x. module yetanotherif (x,a); input [7:0] a; output x; reg [7:0] x; always @( a ) begin if ( a & 2 ) x = 6; if ( a < 10 ) x = 1; else if ( a < 50 ) x = 2; end endmodule // :Example: // // An example with lots of if's. // Registers: None. (x is always assigned.) module andyetanotherif (x,a); input [7:0] a; output x; reg [7:0] x; always @( a ) begin x = a; if ( a[0] ) begin x = x + 2; if ( a[1] & a[2] ) x = x + 1; end else begin if ( a[3] ^ a[4] ) x = x + ( a >> 1 ); else x = x + ( a << 1 ); x = 3 * x; end if ( x[7] ) x = x - 1; end endmodule // :Example: // // Another ALU. // Registers: None module form1_alu(result, a, b, add); input [31:0] a, b; input add; output result; reg [31:0] result; always @( a or b or add ) begin if ( add ) result = a + b; else result = a - b; end endmodule // :Example: // // An ALU with an overflow output. // Registers: None. module form1_alu_with_overflow(result,overflow,carry,a,b,add); input [31:0] a, b; input add; output result; output carry, overflow; reg carry, overflow; reg [31:0] result; always @( a or b or add ) begin if ( add ) result = a + b; else result = a - b; overflow = a[31] != b[31] && a[31] != result[31]; end endmodule //////////////////////////////////////////////////////////////////////////////// /// Synthesis of Conditional Class (case, if/else chains) /// Conditional - if/else chains and case. // // General Conditions: (See also Sequential Conditions) // // :Syntax: if ( C1 ) ST1; // else if ( C2 ) ST2; // else if ( C3 ) ST3; // ... // else STD; // Optional // // :Syntax: case ( EXPR ) // CEXP1:ST1; // CEXP2:ST2; // CEXP3:ST3; // ... // default:STD; // Optional // endcase // // Hardware: // // Synthesize hardware for ST1, ST2, ..., STD // // Synthesize hardware to evaluate either: // C1, C2, ...; call respective outputs c1, c2,... // EXPR == CEXP1, EXPR == CEXP2, ... call respective outputs c1, c2,... // // Determine the union of variables modified in ST1, ST2, ..., STD // For each variable in the union: // // Synthesize a selector with one input per STx. // // For each STx: // Connect the latest value of the variable in STx to a // selector input, or if the variable isn't updated in STx, // the latest value before the "case" or "if". // // Connect cx to the corresponding control input. // // The selector output is the updated value. // // // Sequential Conditions: // // :Syntax: if ( EXPR == 0 ) ST0; // else if ( EXPR == 1 ) ST1; // else if ( EXPR == 2 ) ST2; // ... // // :Syntax: case ( EXPR ) // 0:ST0; // 1:ST1; // 2:ST2; // ... // endcase // // Hardware: // // Synthesize hardware for ST0, ST1, ... // // Synthesize hardware to evaluate EXPR, call the output expr. // // Determine the union of variables modified in ST0, ST1, ... // For each variable in the union: // // Synthesize a multiplexor with one input per STx. // // Connect expr to the control input. // // For each STx: // Connect the latest value of the variable in STx to a // multiplexor input, or if the variable isn't updated in STx, // the latest value before the "case" or "if". // // The multiplexor output is the updated value. // /// More Information // // The synthesis program may be smart enough to use a multiplexor // instead of a selector for situations other than those implied under // "Sequential Conditions" above. // :Example: // // An up/down counter. // This falls under "General Conditions" above. // Edge-triggered registers: count. module up_down_counter(count,up,reset,clk); input up, reset, clk; output count; reg [7:0] count; always @( posedge clk ) begin if ( reset ) count = 0; else if ( up ) count = count + 1; else count = count - 1; end endmodule // :Example: // // A mux, the hard way, but look at how the if/else chain works. // Because the if conditions check for consecutive constants (0,1,2) // instead of using three two-input muxen, Leonardo (the synthesis // program) uses one four-input multiplexor. // This falls under "Sequential Conditions" above. // Registers: None. module mux(x,select,i0,i1,i2,i3); input [1:0] select; input [7:0] i0, i1, i2, i3; output x; reg [7:0] x; always @( select or i0 or i1 or i2 or i3 ) begin if ( select == 0 ) x = i0; else if ( select == 1 ) x = i1; else if ( select == 2 ) x = i2; else x = i3; end endmodule // :Example: // // It looks like a selector but it's not. The synthesized hardware // will make use of a selector, but the entire module is not a // selector. How is it not a selector? module not_exactly_a_selector(x,c0,c1,c2,c3,i0,i1,i2,i3); input c0, c1, c2, c3; input [7:0] i0, i1, i2, i3; output x; reg x; always @( c0 or c1 or c2 or c3 or i0 or i1 or i2 or i3 ) begin case( 1 ) c0: x = i0; c1: x = i1; c2: x = i2; c3: x = i3; endcase end endmodule // Variable x is not always assigned, so the selector output // goes to a level-triggered flip-flop. When none of the // control inputs are set the module output is set to the // last input with an asserted control. // // Level-Triggered Register: x //////////////////////////////////////////////////////////////////////////////// /// Synthesis of Iteration Class (for, while, repeat) /// Iteration - for, while, repeat // // :Syntax: for ( INIT_ASSIGN; CONDITION; STEP_ASSIGN ) BODY // :Syntax: while ( CONDITION ) BODY // :Syntax: repeat ( COUNT ) BODY // // Remember // // The number of iterations must be determinable by the synthesis // program (and it may not be as smart as you'd like) at analysis // (sort of synthesis or compile) time. // // Hardware: // // Let n denote number of iterations. // // Synthesize and cascade (connect in series) n copies of BODY. // // For a "for" loop, determine value of iteration variable (e.g., i) // at each iteration, and use that as an input into the hardware // for the corresponding iteration. // // Updated Variables: // // Variables updated in the last iteration. // :Example: // // Simple repeat example. module times_five(five_a,a); input [7:0] a; output [10:0] five_a; reg [10:0] five_a; always @( a ) begin five_a = 0; repeat ( 5 ) five_a = five_a + a; end endmodule // :Example: // // Simple for-loop example. module sumthing(sum,a); input [7:0] a; output [15:0] sum; integer i; always @( a ) begin sum = a; for (i = 0; i < 5; i = i + 1 ) sum = a + sum * i; end endmodule // :Example: // // Simple for-loop example. module times_five_f(five_a,a); input [7:0] a; output [10:0] five_a; reg [10:0] five_a; integer i; always @( a ) begin five_a = 0; for (i = 0; i < 5; i = i + 1 ) five_a = five_a + a; end endmodule // // Note: synthesized hardware identical to version with repeat loop. // :Example: // // Another population count module, but with five bits. module pop_combinational_s(p,a); input [4:0] a; output p; reg [2:0] p; // In good coding style items to be synthesized are wires or regs // and integers are used for testbench code. // Nevertheless, there is a good reason why i is an integer. integer i; // Form 1 always @( a ) begin // ST1 -> Assignment -> p = 0; p = 0; // ST2 -> Iteration -> for ( INIT_ASSIGN; CONDITION; STEP_ASSIGN ) BODY // INIT_ASSIGN -> i=0 // CONDITION -> i<5 // STEP_ASSIGN -> i=i+1 // BODY -> p=p+a[i]; for (i=0; i<5; i=i+1) p = p + a[i]; end // FormEnd // A register is not needed for p because it's always assigned. // A register is not needed for i because it is not live out (it's // not referenced elsewhere). (Even if it were, it's value would // be the constant 5 so a register would not be needed anyway.) endmodule // Note: // // Make five copies of body, p = p + a[i]; (an adder). // In first copy set i -> 0, in second set i -> 1, etc. // :Example: // // A comparison module. Output gt is asserted if a < b // and lt is asserted if a > b. (Appeared on a 2000 final exam.) module compare(gt, lt, a, b); input a, b; output gt, lt; wire [2:0] a, b; reg gt, lt; integer i; always @( a or b ) begin gt = 0; lt = 0; for (i=2; i>=0; i=i-1) if ( !gt && !lt ) begin if ( ~a[i] && b[i] ) lt = 1; if ( a[i] > b[i] ) gt = 1; end end endmodule // compare // Synthesized Hardware:
// :Example: // // Non-synthesizable loop. The loop cannot be synthesized because the // number of iterations in not a constant (it depends on the module // input, a). For this particular case one could set the sum to // a(a+1)/2. module not_synthesizable_sum(sum,a); input [7:0] a; output [10:0] sum; reg [10:0] sum; integer i; always @( a ) begin sum = 0; for (i=0; i<a; i=i+1) sum = sum + i; end endmodule // // Leonardo message: Error, expression does not evaluate to a constant. // :Example: // // The code below is synthesizable but requires 256 copies of the loop // body and so is probably impractical. Computing a(a+1)/2 is much // easier. module synthesizable_sum_but(sum,a); input [7:0] a; output [10:0] sum; reg [10:0] sum; integer i; always @( a ) begin sum = 0; for (i=0; i<256; i=i+1) if ( i < a ) sum = sum + i; end endmodule //////////////////////////////////////////////////////////////////////////////// /// Ripple Adder: Combinational v. Sequential /// // Q: I need to iterate lots of times, but I just can't afford the hardware. // What do I do? // // A: Use sequential logic. // Three approaches to ripple adder will be shown: // // (1) Ripple Classic: // Combinational Logic using structural code. // // (2) Ripple Procedural Combinational: // Hardware identical to ripple classic. // // (3) Ripple Sequential: // Uses sequential logic. // // In terms of synthesized hardware, (1) and (2) are very similar // (possibly identical). Choose the one which is more readable. // // (3) uses only one BFA, but its slower since it requires one clock // cycle per bit. // // If a BFA used lots of gates, (3) would be the low-cost solution. // // :Example: // // Classic ripple counter. module ripple_classic(sum,cout,a,b); input [3:0] a, b; output [3:0] sum; output cout; wire c0, c1, c2; bfa_implicit bfa0(sum[0],c0,a[0],b[0],1'b0); bfa_implicit bfa1(sum[1],c1,a[1],b[1],c0); bfa_implicit bfa2(sum[2],c2,a[2],b[2],c1); bfa_implicit bfa3(sum[3],cout,a[3],b[3],c2); endmodule // :Example: // // A ripple adder made from binary full adders, but using // procedural code. Except for the number of bits, equivalent // to the one above. module ripple_redux(sum,a,b); input [31:0] a, b; output sum; reg [32:0] sum; reg carry; integer i; always @( a or b ) begin carry = 0; for (i=0; i<32; i=i+1) begin sum[i] = a[i] ^ b[i] ^ carry; carry = a[i] & b[i] | a[i] & carry | b[i] & carry; end sum[32] = carry; end endmodule // :Example: // // A sequential ripple counter. It uses less hardware but is slower. // (There is not much point in dividing an adder in to several cycles, // but such an approach is used for multipliers.) module ripple_redux_comb(sum,a,b,clk); input [31:0] a, b; input clk; output sum; reg [32:0] sum; reg carry; reg [4:0] i; initial i = 0; always @( posedge clk ) begin if ( i == 0 ) begin sum[32] = carry; carry = 0; end sum[i] = a[i] ^ b[i] ^ carry; carry = a[i] & b[i] | a[i] & carry | b[i] & carry; i = i + 1; end endmodule //////////////////////////////////////////////////////////////////////////////// /// Miscellaneous Examples // :Example: // // Clocked population count module. The correct output // appears at most 32 clock cycles after the input. Other // than counting cycles or knowing what the correct output should be, // there is no way to tell that the // output is ready. module pop(p,a,clk); input [31:0] a; input clk; output p; reg [6:0] p; reg [31:0] acopy; reg [6:0] pcopy; always @( posedge clk ) begin if ( acopy == 0 ) begin p = pcopy; pcopy = 0; acopy = a; end else begin pcopy = pcopy + acopy[0]; acopy = acopy >> 1; end end endmodule // :Example: // // Population count with handshaking. Handshaking is the use of // control signals between two modules to coordinate activities. // // In this case: // The external module waits (if necessary) for ready to be 1. // The external module then puts a number on "a" and asserts start. // pop_with_handshaking_1 copies the number and sets ready to zero. // When start goes to zero, pop_with_handshaking_1 starts computing. // When pop_with_handshaking_1 is finished it asserts ready. module pop_with_handshaking_1(p,ready,a,start,clk); input [31:0] a; input start, clk; output p, ready; reg [6:0] p; reg ready; reg [31:0] acopy; always @( posedge clk ) begin if ( start ) begin // Block I acopy = a; p = 0; ready = 0; end else if ( !ready && acopy ) // Block E begin p = p + acopy[0]; acopy = acopy >> 1; end else if ( !ready && !acopy ) // Block F begin ready = 1; end end endmodule /// Material below this point is under construction. module text_to_binary(bin,valid,text,clk); input [7:0] text; input clk; output bin, valid; reg [31:0] bin; reg valid; always @( posedge clk ) begin end endmodule // :Keyword: $stop (System task) // // Stops simulation. Used for testbenches and debugging. module demo_counter(); wire [7:0] count; reg up, reset, clk; up_down_counter c1(count,up,reset,clk); integer i; initial begin i = 0; up = 1; reset = 1; for (i=0; i<4; i=i+1) @( posedge clk ); reset = 0; for (i=0; i<20; i=i-1) begin if ( i != count ) begin $display("Something wrong at i=%d, count=%d",i,count); $stop; end @( posedge clk ); #1; end up = 0; for (i=i; i>=0; i=i-1) begin if ( i != count ) begin $display("Something wrong at i=%d, count=%d",i,count); $stop; end @( posedge clk ); #1; end $display("Done with tests."); end always begin clk = 0; #5; clk = 1; #5; end endmodule