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

K

Kevin Simonson

Guest
I have a design in mind that would fit in this skeleton:
Code:
module xyz ( result, leftOp, rightOp);
parameter  integer nmBits = 1;
localparam integer highBit = nmBits - 1;
output             result;
input [ highBit:0] leftOp;
input [ highBit:0] rightOp;

// ...

endmodule
The way (xyz) is designed, this module would work differently for different values of (nmBits), but in a way that can be precisely defined. In fact, I\'m seriously thinking of writing a Java program that takes (nmBits) as an input and produces a parameterless verion of (xyz) for that version of (nmBits). So I\'m wondering, is it a true statement that, if one can write such a Java program to produce the equivalent (parameterless) Verilog code for any given set of parameters, one can also write Verilog code with parameters to do the same thing?
 
On Monday, September 21, 2020 at 4:23:25 PM UTC-6, Kevin Simonson wrote:
I have a design in mind that would fit in this skeleton:
Code:
module xyz ( result, leftOp, rightOp);
parameter integer nmBits = 1;
localparam integer highBit = nmBits - 1;
output result;
input [ highBit:0] leftOp;
input [ highBit:0] rightOp;

// ...

endmodule
The way (xyz) is designed, this module would work differently for different values of (nmBits), but in a way that can be precisely defined. In fact, I\'m seriously thinking of writing a Java program that takes (nmBits) as an input and produces a parameterless verion of (xyz) for that version of (nmBits). So I\'m wondering, is it a true statement that, if one can write such a Java program to produce the equivalent (parameterless) Verilog code for any given set of parameters, one can also write Verilog code with parameters to do the same thing?

Your code seems fine, although your port list style is Verilog 1995. A more modern style would be:

module xyz
#(parameter WIDTH=8) // Width of input operators (default 8 if not overwritten at instantiation)
(input [WIDTH-1:0] leftOp,
input [WIDTH-1:0] rightOp,
output result);
....
endmodule
 
In article <1bf811ef-9787-46c9-ac5a-81159e8560e0n@googlegroups.com>,
Kevin Simonson <kvnsmnsn@hotmail.com> wrote:
I have a design in mind that would fit in this skeleton:
Code:
module xyz ( result, leftOp, rightOp);
parameter  integer nmBits = 1;
localparam integer highBit = nmBits - 1;
output             result;
input [ highBit:0] leftOp;
input [ highBit:0] rightOp;

// ...

endmodule
The way (xyz) is designed, this module would work differently for different values of (nmBits), but in a way that can be precisely defined. In fact, I\'m seriously thinking
of writing a Java program that takes (nmBits) as an input and produces a parameterless verion of (xyz) for that version of (nmBits). So I\'m wondering, is it a true
statement that, if one can write such a Java program to produce the equivalent (parameterless) Verilog code for any given set of parameters, one can also write Verilog code
with parameters to do the same thing?

Absolutely just stay within Verilog. IMHO it\'s the exception, not the
rule to move things out of verilog and use another language (to describe
hardware).

However many in industry do so. There\'s a common reference people use
that uses a web page to generate CRC codes. While that reference gives
excellant results, its quite puzzling to me in that the equivalent code
in verilog is much more straightforward, clear, and concise.

The problem with these sorts of things is that it frames everything
as \"instance based\" design as opposed to module based design. Flows within
Vivado, for instance, are unfortunetly based on instance based designs.

Regards,
Mark
 
On Monday, September 21, 2020 at 6:31:29 PM UTC-7, Kevin Neilson wrote:

Your code seems fine, although your port list style is Verilog 1995. A more modern style would be:

module xyz
#(parameter WIDTH=8) // Width of input operators (default 8 if not overwritten at instantiation)
(input [WIDTH-1:0] leftOp,
input [WIDTH-1:0] rightOp,
output result);
...
endmodule

Kevin (Neilson), what if I had more than one parameter? For example, what if I had:
Code:
module queue ( dataOut, clock, shift, dataIn);
parameter integer nmBits = 1;
parameter integer nmElems = 1;
localparam integer highBit = nmBits - 1;
output [highBit:0] dataOut;
input clock;
input shift;
input [highBit:0] dataIn;

// ...

endmodule
Could I do the following?
Code:
module queue
  #( parameter integer nmBits = 1, parameter integer nmElems = 1)
  ( output [nmBits-1:0] dataOut
  , input clock
  , input shift
  , input [nmBits-1:0] dataIn);

// ...

endmodule
Or am I messing up the syntax? Any info on this would be appreciated.
By the way, everything I know about Verilog has come from _Verilog HDL: A Guide to Digital Design and Synthesis_ by Samir Palnitkar. Is there another book out there that explains how to use System Verilog post 1995?
 
Gtwrek (Mark?): \"Absolutely just stay within Verilog. IMHO it\'s the exception, not the rule to move things out of verilog and use another language (to describe hardware).\" Okay. As modified by Kevin Neilson my design has one output bit (result) and two input parameters (leftOp) and (rightOp), each of which has (nmBits) bits. At this point I have three (localparams) integers, defined by:
Code:
localparam integer nmNodes  = 2 * nmBits - 1;
localparam integer nmLevels = $clog2( nmBits) + 1;
localparam integer nmRships = 2 * nmNodes - nmLevels;
and then I have three arrays, defined by:
Code:
localparam node    nodes  [  nmNodes:1];
localparam integer bases  [ nmLevels:0];
wire               rships [ nmRships:1];
Oh, I almost forgot; (node) is defined by:
Code:
typedef enum { CORNER, E_LEAF, N_LEAF, SIDE, E_INTERIOR, N_INTERIOR } nodeType;
typedef struct packed
{ nodeType ndType;
   integer inLow;
   integer inHigh;
   integer out;
} node;
Now to build my design I need multiplexers, nor gates, nand gates, and a few not gates. The design does a lot of connecting elements of (rships) to those multiplexers, nor gates, and not gates, and the precise way it\'s done requires some recursive procedure calls. So I built a recursive function:
Code:
function automatic integer fillSubtree ( input integer vrtcl
                                       , input integer hrzntl
                                       , input     bit equal);

// ...

endfunction
whose purpose is to build up array (nodes) to show which elements of (rships) to connect to which gates, and then I iterate through (nodes) to actually connect all the wires. Is that an approach
that looks like it should work? Should I be able to do that in System Verilog?
 
In article <450660fa-8852-4f23-b82a-7d762a760ee0n@googlegroups.com>,
Kevin Simonson <kvnsmnsn@hotmail.com> wrote:
Gtwrek (Mark?): \"Absolutely just stay within Verilog. IMHO it\'s the exception, not the rule to move things out of verilog and use another language (to describe hardware).\"
Okay. As modified by Kevin Neilson my design has one output bit (result) and two input parameters (leftOp) and (rightOp), each of which has (nmBits) bits. At this point I
have three (localparams) integers, defined by:
Code:
localparam integer nmNodes  = 2 * nmBits - 1;
localparam integer nmLevels = $clog2( nmBits) + 1;
localparam integer nmRships = 2 * nmNodes - nmLevels;
and then I have three arrays, defined by:
Code:
localparam node    nodes  [  nmNodes:1];
localparam integer bases  [ nmLevels:0];
wire               rships [ nmRships:1];
Oh, I almost forgot; (node) is defined by:
Code:
typedef enum { CORNER, E_LEAF, N_LEAF, SIDE, E_INTERIOR, N_INTERIOR } nodeType;
typedef struct packed
{ nodeType ndType;
integer inLow;
integer inHigh;
integer out;
} node;
Now to build my design I need multiplexers, nor gates, nand gates, and a few not gates. The design does a lot of connecting elements of (rships) to those multiplexers, nor
gates, and not gates, and the precise way it\'s done requires some recursive procedure calls. So I built a recursive function:
Code:
function automatic integer fillSubtree ( input integer vrtcl
, input integer hrzntl
, input     bit equal);

// ...

endfunction
whose purpose is to build up array (nodes) to show which elements of (rships) to connect to which gates, and then I iterate through (nodes) to actually connect all the
wires. Is that an approach
that looks like it should work? Should I be able to do that in System Verilog?

All of the above looks reasonable. Recursive functions are
synthesizable as long as the terminating conditions are static (in
software speak, the loop can be unrolled during elaboration)

Some other thoughts - parameters are VERY useful, and all my designs
have loads of them. But don\'t discount using constant input wires as
well. Some things you must utilize with a parameter - anything that
affects an actual size for example.

But other things don\'t, and you can just use a constant input wire.
Today\'s synthesizers will produce equilvalent quality of results with
either case. A common example - some sort of bus decode (like a cpu
register):

module reg
#(
parameter BUS_SIZE = 32
// parameter MY_ADDRESS = 32\'h1000 // Commonly done, but don\'t!
)
(
input [ BUS_SIZE - 1 : 0 ] bus_addr_i,
// other bus signals...

input [ BUS_SIZE - 1 : 0 ] my_addr_i
// other register I/O
);

wire this_is_my_address = bus_addr_i == my_addr_i; // Use this!
//wire this_is_my_address = bus_addr_i == MY_ADDRESS; // Don\'t use this!

endmodule

Declaring things as wire\'s are more flexible in designs. (And arguably)
easier to debug in wave tools.

Regards,
Mark
 
On Tuesday, September 22, 2020 at 4:16:36 PM UTC-6, Kevin Simonson wrote:
On Monday, September 21, 2020 at 6:31:29 PM UTC-7, Kevin Neilson wrote:

Your code seems fine, although your port list style is Verilog 1995. A more modern style would be:

module xyz
#(parameter WIDTH=8) // Width of input operators (default 8 if not overwritten at instantiation)
(input [WIDTH-1:0] leftOp,
input [WIDTH-1:0] rightOp,
output result);
...
endmodule
Kevin (Neilson), what if I had more than one parameter? For example, what if I had:
Code:
module queue ( dataOut, clock, shift, dataIn);
parameter integer nmBits = 1;
parameter integer nmElems = 1;
localparam integer highBit = nmBits - 1;
output [highBit:0] dataOut;
input clock;
input shift;
input [highBit:0] dataIn;

// ...

endmodule
Could I do the following?
Code:
module queue
#( parameter integer nmBits = 1, parameter integer nmElems = 1)
( output [nmBits-1:0] dataOut
, input clock
, input shift
, input [nmBits-1:0] dataIn);

// ...

endmodule
Or am I messing up the syntax? Any info on this would be appreciated.
By the way, everything I know about Verilog has come from _Verilog HDL: A Guide to Digital Design and Synthesis_ by Samir Palnitkar. Is there another book out there that explains how to use System Verilog post 1995?

That\'s almost right. I think you need to leave out the extra \"parameter\" keyword:

module queue
#( parameter nmBits = 1,
nmElems = 1)
( output [nmBits-1:0] dataOut ,
input clock,
input shift,
input [nmBits-1:0] dataIn);

Also, the keyword \"integer\" is superfluous, since it\'s the default for parameters, but I think it\'s allowed. You should also avoid the name \"queue\" since that is a keyword in some versions of Verilog.

I do not like the Palnitkar book. Unless it\'s been updated, it might use outmoded syntax from Verilog-1995. The port list syntax was streamlined in Verilog-2001. Unfortunately, most Verilog books are bad, so I don\'t have one to recommend. You\'re probably best-off with finding online resources.
 
In article <0c595586-edfc-41bb-9ab4-3334788e53e1n@googlegroups.com>,
Kevin Neilson <kevin.neilson@xilinx.com> wrote:
module queue
#( parameter nmBits = 1,
nmElems = 1)
( output [nmBits-1:0] dataOut ,
input clock,
input shift,
input [nmBits-1:0] dataIn);

Also, the keyword \"integer\" is superfluous, since it\'s the default for parameters, but I think it\'s allowed. You should also avoid the name \"queue\" since that is
a keyword in some versions of Verilog.

A parameter type is NOT default \"integer\". It\'s default \"as big as it
needs to be\". There\'s weird corner-cases neccesary to be compatible
with Verilog-XL (basically the pseudo-standard).

I suggest always explicitly typing parameters IF YOU CAN. Sometimes,
you need to make use of that \"as big as it needs to be\" clause.

Regards,
Mark
 
Kevin Neilson: \"I do not like the Palnitkar book. Unless it\'s been updated, it might use outmoded syntax from Verilog-1995. The port list syntax was streamlined in Verilog-2001. Unfortunately, most Verilog books are bad, so I don\'t have one to recommend. You\'re probably best-off with finding online resources.\"

Kevin, do you know of any online resources you can recommend? I tried doing a Google search on \"on-line resource for learning verilog-2001\" and it turned up a bunch of links, and \"verilog-2001 tutorial\" and it turned up a bunhc of links, but some of them that said they were for Verilog-2001 used the old style for module interfaces, and none of them looked like they were directed at people who weren\'t very experienced with HDLs who wanted to learn how to use Verilog-2001.
 
Gtwrek (Mark): \"All of the above looks reasonable. Recursive functions are synthesizable as long as the terminating conditions are static (in software speak, the loop can be unrolled during elaboration)\".

Mark, can I post my Verilog so you can take a look at it, and then post the error messages Icarus is giving me when I try to simulate it? Or e-mail them to you?
 
In article <c8f86dc5-fccc-4ec0-bd93-c7bd38809bccn@googlegroups.com>,
Kevin Simonson <kvnsmnsn@hotmail.com> wrote:
Gtwrek (Mark): \"All of the above looks reasonable. Recursive functions are synthesizable as long as the terminating conditions are static (in software speak, the
loop can be unrolled during elaboration)\".

Mark, can I post my Verilog so you can take a look at it, and then post the error messages Icarus is giving me when I try to simulate it? Or e-mail them to you?

If it\'s a minimal example, I\'ll give it a shot. Post here.

--Mark
 
Gtwrek (Mark): \"If it\'s a minimal example, I\'ll give it a shot. Post here.\"

It\'s kind of complicated, but it\'s not huge. I\'ll post it and you can decide whether it\'s too big or not. It will be my next post, and the post after that will be the error messages Icarus gave me.
 
module forMark
#( 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;
typedef struct packed
{ nodeType ndType;
integer inLow;
integer inHigh;
integer out;
} node;

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

localparam node nodes [ nmNodes:1];
localparam 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 nxPs;
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;
nxPs = 0 == hz || ! equal;
nxVr = vr - 1;
rsltLw = fillSubtree( nxVr, twice , nxPs);
rsltHh = fillSubtree( nxVr, twice + 1, nxPs);
nodes[ ndIx].ndType = hz == 0 ? SIDE : equal ? E_INTERIOR : N_INTERIOR;
nodes[ ndIx].inLow = rsltLw;
nodes[ ndIx].inHigh = rsltHh;
nodes[ ndIx].out = rlIx;
end
else
begin
nodes[ ndIx].ndType = hz == 0 ? CORNER : equal ? E_LEAF : N_LEAF;
nodes[ ndIx].inLow = hz;
nodes[ ndIx].out = 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

for (ix = 1; ix <= nmNodes; ix = ix + 1)
begin
localparam node nd = nodes[ ix];
localparam integer highEq = nd.inHigh - 1;
localparam integer inLow = nd.inLow;
case (nd.ndType)
E_INTERIOR
: begin
nor2 pio( rships[ nd.out - 1], rships[ inLow - 1], rships[ highEq]);
mplex pim( rships[ nd.out], rships[ highEq], rships[ nd.inHigh], rships[ inLow]);
end
N_INTERIOR
: begin
nand2 mia( rships[ nd.out - 1], rships[ inLow - 1], rships[ highEq]);
mplex mim( rships[ nd.out], rships[ highEq], rships[ inLow], rships[ nd.inHigh]);
end
SIDE
: mplex sm( rships[ nd.out], rships[ highEq], rships[ inLow], rships[ nd.inHigh]);
E_LEAF
: begin
equ2 ple( rships[ nd.out], leftOp[ inLow], rightOp[ inLow]);
assign rships[ nd.out - 1] = rightOp[ inLow];
end
N_LEAF
: begin
xor2 mlx( rships[ nd.out], leftOp[ inLow], rightOp[ inLow]);
assign rships[ nd.out - 1] = rightOp[ inLow];
end
CORNER
: begin
nt1 cn( ntRght, rightOp[ inLow]);
nor2 co( rships[ nd.out], leftOp[ inLow], ntRght);
end
endcase
end
assign lssThn = rships[ bases[ nmLevels - 1]];

endmodule
 
D:\\Hf\\Verilog\\Unpacked\\Src\\Common>\\Icarus\\bin\\iverilog -g2009 -o forMark.vvp forMark.sv
forMark.sv:19: sorry: cannot currently create a parameter of type \'node\' which was defined at: forMark.sv:8.
forMark.sv:19: syntax error
forMark.sv:19: error: syntax error localparam list.
forMark.sv:20: syntax error
forMark.sv:20: error: syntax error localparam list.
forMark.sv:83: sorry: cannot currently create a parameter of type \'node\' which was defined at: forMark.sv:8.

D:\\Hf\\Verilog\\Unpacked\\Src\\Common>
 
On Wednesday, September 23, 2020 at 4:45:55 PM UTC-6, Kevin Simonson wrote:
module forMark
#( 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;
typedef struct packed
{ nodeType ndType;
integer inLow;
integer inHigh;
integer out;
} node;
localparam integer nmNodes = 2 * nmBits - 1;
localparam integer nmLevels = $clog2( nmBits) + 1;
localparam integer nmRships = 2 * nmNodes - nmLevels;
localparam node nodes [ nmNodes:1];
localparam 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 nxPs;
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;
nxPs = 0 == hz || ! equal;
nxVr = vr - 1;
rsltLw = fillSubtree( nxVr, twice , nxPs);
rsltHh = fillSubtree( nxVr, twice + 1, nxPs);
nodes[ ndIx].ndType = hz == 0 ? SIDE : equal ? E_INTERIOR : N_INTERIOR;
nodes[ ndIx].inLow = rsltLw;
nodes[ ndIx].inHigh = rsltHh;
nodes[ ndIx].out = rlIx;
end
else
begin
nodes[ ndIx].ndType = hz == 0 ? CORNER : equal ? E_LEAF : N_LEAF;
nodes[ ndIx].inLow = hz;
nodes[ ndIx].out = 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

for (ix = 1; ix <= nmNodes; ix = ix + 1)
begin
localparam node nd = nodes[ ix];
localparam integer highEq = nd.inHigh - 1;
localparam integer inLow = nd.inLow;
case (nd.ndType)
E_INTERIOR
: begin
nor2 pio( rships[ nd.out - 1], rships[ inLow - 1], rships[ highEq]);
mplex pim( rships[ nd.out], rships[ highEq], rships[ nd.inHigh], rships[ inLow]);
end
N_INTERIOR
: begin
nand2 mia( rships[ nd.out - 1], rships[ inLow - 1], rships[ highEq]);
mplex mim( rships[ nd.out], rships[ highEq], rships[ inLow], rships[ nd.inHigh]);
end
SIDE
: mplex sm( rships[ nd.out], rships[ highEq], rships[ inLow], rships[ nd.inHigh]);
E_LEAF
: begin
equ2 ple( rships[ nd.out], leftOp[ inLow], rightOp[ inLow]);
assign rships[ nd.out - 1] = rightOp[ inLow];
end
N_LEAF
: begin
xor2 mlx( rships[ nd.out], leftOp[ inLow], rightOp[ inLow]);
assign rships[ nd.out - 1] = rightOp[ inLow];
end
CORNER
: begin
nt1 cn( ntRght, rightOp[ inLow]);
nor2 co( rships[ nd.out], leftOp[ inLow], ntRght);
end
endcase
end
assign lssThn = rships[ bases[ nmLevels - 1]];

endmodule

I have a few comments:
- You probably don\'t want to instantiate primitives like xor2. Maybe this is some idea you got from the Palnitkar book. The old books are more geared toward circuit modeling, not circuit synthesis. You want \"RTL\" code, not \"structural\" code (in which you instantiate gates instead of inferring them). To xor something, use the xor operator: result = a ^ b; To NAND something: result = ~(a & b);

- You are using a lot of \"tricky\" code, like structures, which are from Verilog-2009 (aka SystemVerilog). Many synthesizers aren\'t going to like this.. I don\'t know about Icarus, but since it\'s free, I\'d be wary. Synthesis tools are not great. It\'s not like a C compiler, where as long as your C is legal, it\'s going to compile. Your \"initial\" blocks, functions, and structures might not synthesize.

- You don\'t have the \"generate\" keyword before \"for (ix ...\". That might work in some tools, but I think it might be required by a strict interpretation. But you really shouldn\'t have a generate block anyway, because you really want RTL code and no gate primitives.
 
In article <949f0dc7-6333-4b8e-b631-c4c82b825b04n@googlegroups.com>,
Kevin Simonson <kvnsmnsn@hotmail.com> wrote:
localparam node nodes [ nmNodes:1];
localparam integer bases [ nmLevels:0];

Going to break feedback down into parts...

A localparam without an assignment makes no sense, and is likely a
syntax error. Did you mean for these to be variables instead of
localparams?

Regards,
Mark
 
In article <rkibc5$jl0$1@dont-email.me>, gtwrek <gtwrek@sonic.net> wrote:
In article <949f0dc7-6333-4b8e-b631-c4c82b825b04n@googlegroups.com>,
Kevin Simonson <kvnsmnsn@hotmail.com> wrote:
localparam node nodes [ nmNodes:1];
localparam integer bases [ nmLevels:0];

Going to break feedback down into parts...

A localparam without an assignment makes no sense, and is likely a
syntax error. Did you mean for these to be variables instead of
localparams?

Briefly reading through the rest of the code, and how you\'re using/manipulating
\"nodes\" and \"bases\" - I think this is the root cause of your troubles.
Just try and make these variables instead of localparams. I don\'t think
there\'s any reason why they must be localparams.

Regards,
Mark
 
Okay, I got rid of (struct) type (node) and now just have four arrays, (ndTypes), (inLows), (inHighs), and (outs). Then I used Icarus to simulate it, and only got one error message. Any idea how to get rid of that one error message? As before, the next post I make will be of my \"neilson.sv\" Verilog file, and the post after that will be the results of my attempt to simulate it.
 
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
 
D:\\Hf\\Verilog\\Unpacked\\Src\\Common>\\Icarus\\bin\\iverilog -g2009 -o neilson.vvp neilson.sv
neilson.sv:84: error: Unable to bind parameter `ndTypes[ix]\' in `neilson.$gen1[1]\'
neilson.sv:84: error: Cannot evaluate genvar case expression: ndTypes[ix]
2 error(s) during elaboration.

D:\\Hf\\Verilog\\Unpacked\\Src\\Common>
 

Welcome to EDABoard.com

Sponsor

Back
Top