How powerful is Verilog at using parameters to specify designs?

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 [/code] 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 i nput and produces a parameterless verion of (xyz) for that version of (nmBi ts). 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 an y given set of parameters, one can also write Verilog code with parameters to do the same thing?

Reply to
Kevin Simonson
Loading thread data ...

nt 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 (nm Bits). 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 parameter s to do the same thing?

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

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

Reply to
Kevin Neilson

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

Reply to
gtwrek

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 [/code] 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 [/code] 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?

Reply to
Kevin Simonson

Gtwrek (Mark?): "Absolutely just stay within Verilog. IMHO it's the excepti on, 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 o f which has (nmBits) bits. At this point I have three (localparams) integer s, defined by:

  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]; [/code] Oh, I almost forgot; (node) is defined by:
  typedef enum { CORNER, E_LEAF, N_LEAF, SIDE, E_INTERIOR, N_INTERIOR } nodeT  ype;  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 fe w not gates. The design does a lot of connecting elements of (rships) to th ose multiplexers, nor gates, and not gates, and the precise way it's done r equires some recursive procedure calls. So I built a recursive function:
  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 (rship s) to connect to which gates, and then I iterate through (nodes) to actuall y connect all the wires. Is that an approach that looks like it should work? Should I be able to do that in System Veril og?

Reply to
Kevin Simonson

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

Reply to
gtwrek

more modern style would be:

erwritten at instantiation)

if I had:

Guide to Digital Design and Synthesis_ by Samir Palnitkar. Is there anothe r 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" k eyword:

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 para meters, but I think it's allowed. You should also avoid the name "queue" s ince that is a keyword in some versions of Verilog.

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

Reply to
Kevin Neilson

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

Reply to
gtwrek

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 s treamlined 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 tur ned up a bunch of links, and "verilog-2001 tutorial" and it turned up a bun hc 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 di rected at people who weren't very experienced with HDLs who wanted to learn how to use Verilog-2001.

Reply to
Kevin Simonson

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?

Reply to
Kevin Simonson

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

--Mark

Reply to
gtwrek

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.

Reply to
Kevin Simonson

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

Reply to
Kevin Simonson

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>

Reply to
Kevin Simonson

eType;

IOR;

inLow]);

nHigh]);

inHigh]);

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 geare d toward circuit modeling, not circuit synthesis. You want "RTL" code, not "structural" code (in which you instantiate gates instead of inferring the m). To xor something, use the xor operator: result = a ^ b; To NAND so mething: result = ~(a & b);

- You are using a lot of "tricky" code, like structures, which are from Ver ilog-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 i s legal, it's going to compile. Your "initial" blocks, functions, and stru ctures might not synthesize.

- You don't have the "generate" keyword before "for (ix ...". That might w ork in some tools, but I think it might be required by a strict interpretat ion. But you really shouldn't have a generate block anyway, because you re ally want RTL code and no gate primitives.

Reply to
Kevin Neilson

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

Reply to
gtwrek

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

Reply to
gtwrek

Okay, I got rid of (struct) type (node) and now just have four arrays, (ndT ypes), (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 m essage? 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.

Reply to
Kevin Simonson

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

Reply to
Kevin Simonson

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>

Reply to
Kevin Simonson

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.