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