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