How powerful is Verilog at using parameters to specify designs?...

In article <071797c0-bfc0-4df1-b23e-f1519230330en@googlegroups.com>,
Kevin Simonson <kvnsmnsn@hotmail.com> wrote:
module neilson
#( parameter nmBits = 1)
( output lssThn
, input [ nmBits-1:0] leftOp
, input [ nmBits-1:0] rightOp);

typedef enum { CORNER, E_LEAF, N_LEAF, SIDE, E_INTERIOR, N_INTERIOR } nodeType;

localparam integer nmNodes = 2 * nmBits - 1;
localparam integer nmLevels = $clog2( nmBits) + 1;
localparam integer nmRships = 2 * nmNodes - nmLevels;

nodeType ndTypes [ nmNodes:1];
integer inLows [ nmNodes:1];
integer inHighs [ nmBits-1:1];
integer outs [ nmNodes:1];
integer bases [ nmLevels:0];
wire rships [ nmRships:1];
wire ntRght;
genvar ix;

function automatic integer fillSubtree ( input integer vrtcl
, input integer hrzntl
, input bit equal);
integer rsltLw;
integer rsltHh;
integer ndIx;
integer rlIx;
integer vr;
integer hz;
integer twice;
integer nxVr;
bit nxEq;
begin
ndIx = (1 << vrtcl) + (hrzntl << vrtcl + 1);
vr = vrtcl;
hz = hrzntl;
while (nmNodes < ndIx)
begin
vr = vr - 1;
hz <<= 1;
ndIx = (1 << vr) + (hz << vr + 1);
end
rlIx = bases[ vr] + (hz << 1);
fillSubtree = rlIx;
if (0 < vr)
begin
twice = hz << 1;
nxEq = 0 == hz || ! equal;
nxVr = vr - 1;
rsltLw = fillSubtree( nxVr, twice , nxEq);
rsltHh = fillSubtree( nxVr, twice + 1, nxEq);
ndTypes[ ndIx] = hz == 0 ? SIDE : equal ? E_INTERIOR : N_INTERIOR;
inLows[ ndIx] = rsltLw;
inHighs[ ndIx >> 1] = rsltHh;
outs[ ndIx] = rlIx;
end
else
begin
ndTypes[ ndIx] = hz == 0 ? CORNER : equal ? E_LEAF : N_LEAF;
inLows[ ndIx] = hz;
outs[ ndIx] = rlIx;
end
end
endfunction

initial
begin
integer lvl;
bases[ 0] = 1;
for (lvl = 1; lvl <= nmLevels; lvl = lvl + 1)
begin
bases[ lvl] = bases[ lvl - 1] + ((nmNodes + (1 << lvl - 1) >> lvl << 1) - 1);
end
fillSubtree( nmLevels - 1, 0, true);
end

generate
for (ix = 1; ix <= nmNodes; ix = ix + 1)
begin
integer inLow = inLows[ ix];
integer inHigh = inHighs[ ix >> 1];
integer out = outs[ ix];
case (ndTypes[ ix])
E_INTERIOR
: begin
nor2 pio( rships[ out - 1], rships[ inLow - 1], rships[ inHigh - 1]);
mplex pim( rships[ out], rships[ inHigh - 1], rships[ inHigh], rships[ inLow]);
end
N_INTERIOR
: begin
nand2 mia( rships[ out - 1], rships[ inLow - 1], rships[ inHigh - 1]);
mplex mim( rships[ out], rships[ inHigh - 1], rships[ inLow], rships[ inHigh]);
end
SIDE
: mplex sm( rships[ out], rships[ inHigh - 1], rships[ inLow], rships[ inHigh]);
E_LEAF
: begin
equ2 ple( rships[ out], leftOp[ inLow], rightOp[ inLow]);
assign rships[ out - 1] = rightOp[ inLow];
end
N_LEAF
: begin
xor2 mlx( rships[ out], leftOp[ inLow], rightOp[ inLow]);
assign rships[ out - 1] = rightOp[ inLow];
end
CORNER
: begin
nt1 cn( ntRght, rightOp[ inLow]);
nor2 co( rships[ out], leftOp[ inLow], ntRght);
end
endcase
end
endgenerate
assign lssThn = rships[ bases[ nmLevels - 1]];

endmodule

Your problem now is the generate case() statements. Generate case()
statements agruments DO need to be parameters. (I know I told you to
change it from a localparm to a variable - but I missed the generate case()
usage) However, I still don\'t think you should make these parameters.

Like another poster indicated - you\'re coding at a very low level.
Instatiating \"xor2\" primitives and the like is quite low level. Just
inline the expression using the verilog \"^\", \"|\", \"&\", etc operators.
Change your generate case() to a procedural case().

Another comment on style. Your function should really not be both
sampling, and manipulating non-local variables. Write your function
with a stable API that passes in the neccesary arguments, and returns
the neccesary outputs. Manipulating global variables, makes the
function call pretty purposeless.

There\'s no reason at all for it to be a function if it\'s
just manipulating global variables. Just move it down to the procedural
block if you don\'t want to solidify the API. Or put it in it\'s own
procedural block. Change the function to:
always @*
begin
//function contents that manipulate ndTypes[];
end

Regards,
Mark
 
Gtwrek (Mark): \"Like another poster indicated - you\'re coding at a very low level. Instatiating \'xor2\' primitives and the like is quite low level. Just inline the expression using the verilog \'^\', \'|\', \'&\', etc operators.\" What\'s wrong with writing Verilog at a low level? If someone has a feel for how her/his design should work at a low level, is there something wrong with coding it at that level? If so, what is wrong with it?

\"Change your generate case() to a procedural case().\" What exactly is a procedural case, and how can I find out about it?
 

Welcome to EDABoard.com

Sponsor

Back
Top