FPGARelated.com
Forums

How powerful is Verilog at using parameters to specify designs?

Started by Kevin Simonson September 21, 2020
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=20 > #( parameter nmBits =3D 1)=20 > ( output lssThn=20 > , input [ nmBits-1:0] leftOp=20 > , input [ nmBits-1:0] rightOp); > typedef enum { CORNER, E_LEAF, N_LEAF, SIDE, E_INTERIOR, N_INTERIOR } nod=
eType;=20
> typedef struct packed=20 > { nodeType ndType;=20 > integer inLow;=20 > integer inHigh;=20 > integer out;=20 > } node; > localparam integer nmNodes =3D 2 * nmBits - 1;=20 > localparam integer nmLevels =3D $clog2( nmBits) + 1;=20 > localparam integer nmRships =3D 2 * nmNodes - nmLevels; > localparam node nodes [ nmNodes:1];=20 > localparam integer bases [ nmLevels:0];=20 > wire rships [ nmRships:1]; > wire ntRght;=20 > genvar ix; > function automatic integer fillSubtree ( input integer vrtcl=20 > , input integer hrzntl=20 > , input bit equal); > integer rsltLw;=20 > integer rsltHh;=20 > integer ndIx;=20 > integer rlIx;=20 > integer vr;=20 > integer hz;=20 > integer twice;=20 > integer nxVr;=20 > bit nxPs;=20 > begin=20 > ndIx =3D (1 << vrtcl) + (hrzntl << vrtcl + 1);=20 > vr =3D vrtcl;=20 > hz =3D hrzntl;=20 > while (nmNodes < ndIx)=20 > begin=20 > vr =3D vr - 1;=20 > hz <<=3D 1;=20 > ndIx =3D (1 << vr) + (hz << vr + 1);=20 > end=20 > rlIx =3D bases[ vr] + (hz << 1);=20 > fillSubtree =3D rlIx;=20 > if (0 < vr)=20 > begin=20 > twice =3D hz << 1;=20 > nxPs =3D 0 =3D=3D hz || ! equal;=20 > nxVr =3D vr - 1;=20 > rsltLw =3D fillSubtree( nxVr, twice , nxPs);=20 > rsltHh =3D fillSubtree( nxVr, twice + 1, nxPs);=20 > nodes[ ndIx].ndType =3D hz =3D=3D 0 ? SIDE : equal ? E_INTERIOR : N_INTER=
IOR;=20
> nodes[ ndIx].inLow =3D rsltLw;=20 > nodes[ ndIx].inHigh =3D rsltHh;=20 > nodes[ ndIx].out =3D rlIx;=20 > end=20 > else=20 > begin=20 > nodes[ ndIx].ndType =3D hz =3D=3D 0 ? CORNER : equal ? E_LEAF : N_LEAF;=
=20
> nodes[ ndIx].inLow =3D hz;=20 > nodes[ ndIx].out =3D rlIx;=20 > end=20 > end=20 > endfunction=20 >=20 > initial=20 > begin=20 > integer lvl;=20 > bases[ 0] =3D 1;=20 > for (lvl =3D 1; lvl <=3D nmLevels; lvl =3D lvl + 1)=20 > begin=20 > bases[ lvl] =3D bases[ lvl - 1] + ((nmNodes + (1 << lvl - 1) >> lvl << 1)=
- 1);=20
> end=20 > fillSubtree( nmLevels - 1, 0, true);=20 > end=20 >=20 > for (ix =3D 1; ix <=3D nmNodes; ix =3D ix + 1)=20 > begin=20 > localparam node nd =3D nodes[ ix];=20 > localparam integer highEq =3D nd.inHigh - 1;=20 > localparam integer inLow =3D nd.inLow;=20 > case (nd.ndType)=20 > E_INTERIOR=20 > : begin=20 > nor2 pio( rships[ nd.out - 1], rships[ inLow - 1], rships[ highEq]);=20 > mplex pim( rships[ nd.out], rships[ highEq], rships[ nd.inHigh], rships[ =
inLow]);=20
> end=20 > N_INTERIOR=20 > : begin=20 > nand2 mia( rships[ nd.out - 1], rships[ inLow - 1], rships[ highEq]);=20 > mplex mim( rships[ nd.out], rships[ highEq], rships[ inLow], rships[ nd.i=
nHigh]);=20
> end=20 > SIDE=20 > : mplex sm( rships[ nd.out], rships[ highEq], rships[ inLow], rships[ nd.=
inHigh]);=20
> E_LEAF=20 > : begin=20 > equ2 ple( rships[ nd.out], leftOp[ inLow], rightOp[ inLow]);=20 > assign rships[ nd.out - 1] =3D rightOp[ inLow];=20 > end=20 > N_LEAF=20 > : begin=20 > xor2 mlx( rships[ nd.out], leftOp[ inLow], rightOp[ inLow]);=20 > assign rships[ nd.out - 1] =3D rightOp[ inLow];=20 > end=20 > CORNER=20 > : begin=20 > nt1 cn( ntRght, rightOp[ inLow]);=20 > nor2 co( rships[ nd.out], leftOp[ inLow], ntRght);=20 > end=20 > endcase=20 > end=20 > assign lssThn =3D rships[ bases[ nmLevels - 1]];=20 >=20 > 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 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 =3D a ^ b; To NAND so= mething: result =3D ~(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.
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>