FPGARelated.com
Forums

How powerful is Verilog at using parameters to specify designs?

Started by Kevin Simonson September 21, 2020
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?