What is wrong with low level code?...

K

Kevin Simonson

Guest
I recently posted a Verilog module to this forum, and someone responded that I was coding at a very low level, which was true; I was referring to XOR gates, NAND gates, NOR gates, and NOT gates. Is there something wrong with writing my code at such a low level? If I have a fairly good understanding of how my algorithm needs to run at such a low level, then what is wrong with writing that kind of low level code?
 
On Sunday, October 4, 2020 at 8:02:07 PM UTC-4, Kevin Simonson wrote:
> I recently posted a Verilog module to this forum, and someone responded that I was coding at a very low level, which was true; I was referring to XOR gates, NAND gates, NOR gates, and NOT gates. Is there something wrong with writing my code at such a low level? If I have a fairly good understanding of how my algorithm needs to run at such a low level, then what is wrong with writing that kind of low level code?

Nothing wrong with it as such, but it is less efficient and requires a lot of extra typing. When you say you \"code at a very low level\" I assume you are instantiating gates and wiring them together rather than just inferring gates using logic operators in assignments? If so, you can infer many, many gates with a simple assignment of an expression to a signal like, A <= B AND C; where A, B and C are each vectors or individual signals.

I\'m not a Verilog user, so I don\'t know the exact syntax. I want to say the logic operators are symbols rather than words, but it\'s the same concept.

Is this method awkward to you?

--

Rick C.

- Get 1,000 miles of free Supercharging
- Tesla referral code - https://ts.la/richard11209
 
Kevin Simonson <kvnsmnsn@hotmail.com> wrote:
I recently posted a Verilog module to this forum, and someone responded
that I was coding at a very low level, which was true; I was referring to
XOR gates, NAND gates, NOR gates, and NOT gates. Is there something wrong
with writing my code at such a low level? If I have a fairly good
understanding of how my algorithm needs to run at such a low level, then
what is wrong with writing that kind of low level code?

It\'s not wrong, but:

1. It may make your code harder for read, for someone who isn\'t familiar
with its workings. That someone could be yourself if you come back to the
code in a decade\'s time.

2. The task you\'re trying to do probably doesn\'t fall naturally into a
representation of NAND and NOR gates. So why not enter the problem in its
natural state, rather than transform it first in your head? That way
there\'s fewer opportunities for mistakes.

3. It may lull you into a false sense of security, because (unless you\'re
instantiating vendor-specific primitives) the first thing any synthesis tool
will do is throw away your gate representation. At which point the
assumptions you may bring to your gate representation (eg about gate delays)
no longer hold.

Theo
 
On Sunday, October 4, 2020 at 8:02:07 PM UTC-4, Kevin Simonson wrote:
> I recently posted a Verilog module to this forum, and someone responded that I was coding at a very low level, which was true; I was referring to XOR gates, NAND gates, NOR gates, and NOT gates. Is there something wrong with writing my code at such a low level? If I have a fairly good understanding of how my algorithm needs to run at such a low level, then what is wrong with writing that kind of low level code?

Unless the algorithm specification that you\'re trying to implement is written in terms of such gates, then long term support of that code would be a reason why coding at a low level is \'wrong\'.

Kevin Jennings
 
On 05/10/2020 01:02:03, Kevin Simonson wrote:
I recently posted a Verilog module to this forum, and someone
responded that I was coding at a very low level, which was true; I
was referring to XOR gates, NAND gates, NOR gates, and NOT gates. Is
there something wrong with writing my code at such a low level? If I
have a fairly good understanding of how my algorithm needs to run at
such a low level, then what is wrong with writing that kind of low
level code?

As others have said readability is everything.

One time when I wrote at a low level was when trying to maximise speed
when pipe-lining numerical algorithms.

There are times when it\'s appropriate.

--
Mike Perkins
Video Solutions Ltd
www.videosolutions.ltd.uk
 
On Tuesday, October 6, 2020 at 7:04:31 PM UTC-4, Mike Perkins wrote:
On 05/10/2020 01:02:03, Kevin Simonson wrote:
I recently posted a Verilog module to this forum, and someone
responded that I was coding at a very low level, which was true; I
was referring to XOR gates, NAND gates, NOR gates, and NOT gates. Is
there something wrong with writing my code at such a low level? If I
have a fairly good understanding of how my algorithm needs to run at
such a low level, then what is wrong with writing that kind of low
level code?

As others have said readability is everything.

One time when I wrote at a low level was when trying to maximise speed
when pipe-lining numerical algorithms.

There are times when it\'s appropriate.

If not in this thread I may have mentioned a former poster here who used schematics for hierarchical construction allowing specification of relative and absolute positioning within a layout. He only converted to VHDL when he was able to do the same specification of location attributes. Then he never looked back. He was essentially designing at the LUT level and simplifying the design process by using hierarchical constructs eliminating much of the detail design process.

This was largely practical for his work because he was designing similar circuits repeatedly, but mostly because he was being paid to do designs no one else could pull off really. The combination of speed and density was hard to achieve. Today the tools are better and the parts are MUCH bigger making large, fast designs easier to do without massive libraries of hand hewn designs much less common.

So wiring together such things as gates is very uncommon these days. It is well worth the while to learn how to describe your design in HDL rather than instantiating gates and such.

--

Rick C.

+ Get 1,000 miles of free Supercharging
+ Tesla referral code - https://ts.la/richard11209
 
On Tuesday, October 6, 2020 at 5:22:11 PM UTC-7, gnuarm.del...@gmail.com wrote:
So wiring together such things as gates is very uncommon these days. It is well worth the while to learn how to describe your design in HDL rather than instantiating gates and such.

--

Rick C.

Okay, I\'m willing to learn how to describe my design in HDL, preferably Verilog, since that\'s what I\'ve concentrated on. How would I go about learning how to write higher level Verilog, rather \"than instantiating gates and such\"? I\'ll include my source code as it stands right now in my next post. I guess I\'d just like to know how to code it at a higher level.
 
// (c) Kevin Simonson 2020

module lessThan
#( 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 = (nmBits << 1) - 1;
localparam integer lvLimit = $clog2( nmBits);
localparam integer nmRships = (nmNodes << 1) - lvLimit - 1;

nodeType ndTypes [ nmNodes:1];
integer inLows [ nmNodes:1];
integer inHighs [ nmBits-1:1];
integer outs [ nmNodes:1];
integer bases [ lvLimit:0];
wire rss [ nmRships:1];
wire ntRght;
genvar gnIx;

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

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

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

endmodule
 
On Monday, October 12, 2020 at 7:27:49 PM UTC-4, Kevin Simonson wrote:
On Tuesday, October 6, 2020 at 5:22:11 PM UTC-7, gnuarm.del...@gmail.com wrote:
So wiring together such things as gates is very uncommon these days. It is well worth the while to learn how to describe your design in HDL rather than instantiating gates and such.

--

Rick C.

Okay, I\'m willing to learn how to describe my design in HDL, preferably Verilog, since that\'s what I\'ve concentrated on. How would I go about learning how to write higher level Verilog, rather \"than instantiating gates and such\"? I\'ll include my source code as it stands right now in my next post. I guess I\'d just like to know how to code it at a higher level.

Sorry, it is too painful for me to read that sort of code. I don\'t say that as an insult, simply that Verilog is a second language to me so I\'m not clear what all the operators are, etc.

If you want to add two numbers, you write

A <= B + C;

That\'s it in VHDL anyway. I think in this case Verilog is the same.

But your code below is not instantiating gates that I can see.

Let\'s try this. How about showing what your code does with a simple math statement if that is possible? Not HDL, just an explanation, a spec like someone might give you to indicate what the calculation would do without specifying any of the implementation details.

--

Rick C.

-- Get 1,000 miles of free Supercharging
-- Tesla referral code - https://ts.la/richard11209
 
On Monday, October 12, 2020 at 7:30:21 PM UTC-4, Kevin Simonson wrote:
// (c) Kevin Simonson 2020

module lessThan
#( 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 = (nmBits << 1) - 1;
localparam integer lvLimit = $clog2( nmBits);
localparam integer nmRships = (nmNodes << 1) - lvLimit - 1;

nodeType ndTypes [ nmNodes:1];
integer inLows [ nmNodes:1];
integer inHighs [ nmBits-1:1];
integer outs [ nmNodes:1];
integer bases [ lvLimit:0];
wire rss [ nmRships:1];
wire ntRght;
genvar gnIx;

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

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

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

endmodule

I found the top level module declaration (third line, duh!) and it looks like you are implementing a subtraction, I\'m guessing the carry out is the flag.

In RTL this would be something like...

Out <= \'1\' when leftOp < rightOp else \'0\';

No need to even define a function/module. At least in VHDL this is built into the language and I\'m pretty sure something equivalent is provided as well.

From what I recall, you were specifying all the details to provide a speed optimized solution. That is probably counter productive in an FPGA and may or may not be in something like a gate array. I don\'t know so much about fully synthesized ASICs.

Is that more clear?

You might try implementing something like this and compare the result to your highly specified code in synthesis. So how they both turn out.

--

Rick C.

-+ Get 1,000 miles of free Supercharging
-+ Tesla referral code - https://ts.la/richard11209
 
gnuarm.del...@gmail.com (Rick C.): \"In RTL this would be something like... / Out <= \'1\' when leftOp < rightOp else \'0\';\"

I tried:

// (c) Kevin Simonson 2020

module lessThan
#( parameter nmBits = 1)
( output lssThn
, input [ nmBits-1:0] leftOp
, input [ nmBits-1:0] rightOp);

assign lssThn = leftOp < rightOp ? 1 : 0;

endmodule

and got the results I was looking for. So there\'s my low level code that I posted yesterday, and this very high level code that I\'ve posted today; is there nothing in between? It just bugs me that with the version posted here I have so little control over how the less than (\"<\") operator is actually implemented. I think my low level code is pretty much guaranteed to do a less than comparison on any two operands with an absolute minimum of worst case time. Can I say the same for how \"leftOp < rightOp\" is implemented?

\"Is that more clear?\" Yes; thanks!

\"You might try implementing something like this and compare the result to your highly specified code in synthesis. So how they both turn out.\" Rich, I\'d really like to do that. Unfortunately the tool I\'m using to simulate is Icarus, and when I try to simulate it I get:

D:\\Hf\\Verilog\\Unpacked\\Src\\Common>\\Icarus\\bin\\iverilog -g2009 -o lessThan.vvp lessThan.sv
lessThan.sv:81: error: Unable to bind parameter `ndTypes[gnIx]\' in `lessThan.$gen1[1]\'
lessThan.sv:81: error: Cannot evaluate genvar case expression: ndTypes[gnIx]
2 error(s) during elaboration.

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

Any idea why Icarus is giving me these error messages?

By the way, you said, \"compare the result to your highly specified code in synthesis.\" Can one synthesize with Icarus? If so, how? If not, can you recommend a tool for synthesis?
 
On Monday, October 12, 2020 at 11:18:13 PM UTC-4, Kevin Simonson wrote:
gnuarm.del...@gmail.com (Rick C.): \"In RTL this would be something like.... / Out <= \'1\' when leftOp < rightOp else \'0\';\"

I tried:

// (c) Kevin Simonson 2020

module lessThan
#( parameter nmBits = 1)
( output lssThn
, input [ nmBits-1:0] leftOp
, input [ nmBits-1:0] rightOp);

assign lssThn = leftOp < rightOp ? 1 : 0;

endmodule

and got the results I was looking for. So there\'s my low level code that I posted yesterday, and this very high level code that I\'ve posted today; is there nothing in between? It just bugs me that with the version posted here I have so little control over how the less than (\"<\") operator is actually implemented. I think my low level code is pretty much guaranteed to do a less than comparison on any two operands with an absolute minimum of worst case time. Can I say the same for how \"leftOp < rightOp\" is implemented?

Sorry, what makes you think your longer version of the code will produce an optimal result? In general, the tools take all the combinational logic and concatenates it into equations. Unless you place tool specific directives to \"keep\" various signals and not combine the logic into LUTs in ways that eliminate those signals there is nothing to stop the tools from turning all your very specific logic into a single equation for the outputs that exactly matches the short version above?

The tools know what the target is and know that very likely the fastest solution is the use of the FPGA specific primitives for adders which will exactly do the logic in the short equation. Because they have a fast carry chain, it is very unlikely the typical ASIC type optimizations will be slow on an FPGA.


> \"Is that more clear?\" Yes; thanks!

I\'m happy to try to help, but I\'m not so big on wading through complex code.. It is hard enough reading my own. lol


\"You might try implementing something like this and compare the result to your highly specified code in synthesis. So how they both turn out.\" Rich, I\'d really like to do that. Unfortunately the tool I\'m using to simulate is Icarus, and when I try to simulate it I get:

D:\\Hf\\Verilog\\Unpacked\\Src\\Common>\\Icarus\\bin\\iverilog -g2009 -o lessThan..vvp lessThan.sv
lessThan.sv:81: error: Unable to bind parameter `ndTypes[gnIx]\' in `lessThan.$gen1[1]\'
lessThan.sv:81: error: Cannot evaluate genvar case expression: ndTypes[gnIx]
2 error(s) during elaboration.

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

Any idea why Icarus is giving me these error messages?

No, I\'ve never used Icarus. But to see how efficient the result is in synthesis you need to use a synthesis tool. Pick an FPGA vendor and download their free tools. Then you can synthesize the design and they often have an RTL viewer which draw a schematic of the primitives allowing you to see how they translated the design into LUTs, FFs, counters, etc.

I need to do this myself for Gowin FPGAs and soon. I like to use constructs like...

if (A - 1 < 0) then
-- do stuff as the counter rolls over
else
-- do stuff the rest of the time
end if;
A <= (A - 1) mod A_modulus;

In previous designs the tools will pick up that I\'m decrementing A in both places and use the same adder block and use the carry out (borrow technically) as the flag for the IF. I need to verify this for the Gowin parts. If it doesn\'t, then I will just use

if (A = 0) then

which will use some LUTs, but many less than a second adder.


> By the way, you said, \"compare the result to your highly specified code in synthesis.\" Can one synthesize with Icarus? If so, how? If not, can you recommend a tool for synthesis?

No, as i mention above you need to download a vendor\'s tool set. I am used to Lattice semi tools which use Synplify as do the Gowin tools I think. Lots of people use the Xilinx tools which are proprietary (I haven\'t worked with Xilinx since they dropped Synplify many years ago). Altera/Intel has their own tools as well, Quartus I believe. They all work pretty well or they wouldn\'t be in business. It\'s as much about the tools as it is the parts. Altera has always had \"better\" tools than Xilinx, which may not be the case any longer.

If you want to work with the Lattice iCE40 parts, there is an open source tool set, but I don\'t recall the name. I\'m sure others here know it well. You can test your ideas with any of these tools and might do well to try more than one!

I didn\'t even notice about the name. Rick, Rich, even Dick is ok.

--

Rick C.

+- Get 1,000 miles of free Supercharging
+- Tesla referral code - https://ts.la/richard11209
 
On Monday, October 12, 2020 at 9:18:13 PM UTC-6, Kevin Simonson wrote:
gnuarm.del...@gmail.com (Rick C.): \"In RTL this would be something like.... / Out <= \'1\' when leftOp < rightOp else \'0\';\"

I tried:
// (c) Kevin Simonson 2020

module lessThan
#( parameter nmBits = 1)
( output lssThn
, input [ nmBits-1:0] leftOp
, input [ nmBits-1:0] rightOp);
assign lssThn = leftOp < rightOp ? 1 : 0;

endmodule

and got the results I was looking for. So there\'s my low level code that I posted yesterday, and this very high level code that I\'ve posted today; is there nothing in between? It just bugs me that with the version posted here I have so little control over how the less than (\"<\") operator is actually implemented. I think my low level code is pretty much guaranteed to do a less than comparison on any two operands with an absolute minimum of worst case time. Can I say the same for how \"leftOp < rightOp\" is implemented?

\"Is that more clear?\" Yes; thanks!

\"You might try implementing something like this and compare the result to your highly specified code in synthesis. So how they both turn out.\" Rich, I\'d really like to do that. Unfortunately the tool I\'m using to simulate is Icarus, and when I try to simulate it I get:

D:\\Hf\\Verilog\\Unpacked\\Src\\Common>\\Icarus\\bin\\iverilog -g2009 -o lessThan..vvp lessThan.sv
lessThan.sv:81: error: Unable to bind parameter `ndTypes[gnIx]\' in `lessThan.$gen1[1]\'
lessThan.sv:81: error: Cannot evaluate genvar case expression: ndTypes[gnIx]
2 error(s) during elaboration.

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

Any idea why Icarus is giving me these error messages?

By the way, you said, \"compare the result to your highly specified code in synthesis.\" Can one synthesize with Icarus? If so, how? If not, can you recommend a tool for synthesis?

First of all, your code needs comments. To you, it might make sense (at least at the moment), but you can\'t expect anybody to be able to help if you publish a hundred lines of incoherence without even a 1-line comment of what it\'s supposed to be.

If all you want is a comparator, you don\'t even need the ?: operator. It\'s just:

wire less_than = left_op < right_op;

I don\'t even know why you\'d want to put this in a separate module; just use it where you need it, or in an if-clause:

if (left_op < right_op) do_stuff;

Sometimes the synthesizer will not do a great job with abstract code. This is not such a case. You do not need to write low-level code for a subtractor. In an FPGA, for example, the line I wrote above will be synthesized using a built-in carry chain logic. Your code, in which you instantiate primitives, will end up with poorer results, because it won\'t use the fast carry chain. Some notes:

- Use lots of comments.
- Don\'t instantiate any primitives unless absolutely necessary for performance.
- Avoid unnecessary hierarchy and \"generate\" blocks.

I have not used it much but I recently found a site called \"EDA Playground\" in which you can simulate using various simulators and also synthesize using Mentor Questa, a commercial synthesizer. I\'m not familiar with Questa, but here is a link with a simple example. You could set up your own \"playground\" and synthesize. I don\'t know if you can view the resulting schematics, but you can at least get resulting utilization statistics:

https://www.edaplayground.com/x/2BmJ
 
On Tuesday, October 13, 2020 at 10:41:12 AM UTC-6, Kevin Neilson wrote:
On Monday, October 12, 2020 at 9:18:13 PM UTC-6, Kevin Simonson wrote:
gnuarm.del...@gmail.com (Rick C.): \"In RTL this would be something like.... / Out <= \'1\' when leftOp < rightOp else \'0\';\"

I tried:
// (c) Kevin Simonson 2020

module lessThan
#( parameter nmBits = 1)
( output lssThn
, input [ nmBits-1:0] leftOp
, input [ nmBits-1:0] rightOp);
assign lssThn = leftOp < rightOp ? 1 : 0;

endmodule

and got the results I was looking for. So there\'s my low level code that I posted yesterday, and this very high level code that I\'ve posted today; is there nothing in between? It just bugs me that with the version posted here I have so little control over how the less than (\"<\") operator is actually implemented. I think my low level code is pretty much guaranteed to do a less than comparison on any two operands with an absolute minimum of worst case time. Can I say the same for how \"leftOp < rightOp\" is implemented?

\"Is that more clear?\" Yes; thanks!

\"You might try implementing something like this and compare the result to your highly specified code in synthesis. So how they both turn out.\" Rich, I\'d really like to do that. Unfortunately the tool I\'m using to simulate is Icarus, and when I try to simulate it I get:

D:\\Hf\\Verilog\\Unpacked\\Src\\Common>\\Icarus\\bin\\iverilog -g2009 -o lessThan.vvp lessThan.sv
lessThan.sv:81: error: Unable to bind parameter `ndTypes[gnIx]\' in `lessThan.$gen1[1]\'
lessThan.sv:81: error: Cannot evaluate genvar case expression: ndTypes[gnIx]
2 error(s) during elaboration.

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

Any idea why Icarus is giving me these error messages?

By the way, you said, \"compare the result to your highly specified code in synthesis.\" Can one synthesize with Icarus? If so, how? If not, can you recommend a tool for synthesis?
First of all, your code needs comments. To you, it might make sense (at least at the moment), but you can\'t expect anybody to be able to help if you publish a hundred lines of incoherence without even a 1-line comment of what it\'s supposed to be.

If all you want is a comparator, you don\'t even need the ?: operator. It\'s just:

wire less_than = left_op < right_op;

I don\'t even know why you\'d want to put this in a separate module; just use it where you need it, or in an if-clause:

if (left_op < right_op) do_stuff;

Sometimes the synthesizer will not do a great job with abstract code. This is not such a case. You do not need to write low-level code for a subtractor. In an FPGA, for example, the line I wrote above will be synthesized using a built-in carry chain logic. Your code, in which you instantiate primitives, will end up with poorer results, because it won\'t use the fast carry chain. Some notes:

- Use lots of comments.
- Don\'t instantiate any primitives unless absolutely necessary for performance.
- Avoid unnecessary hierarchy and \"generate\" blocks.

I have not used it much but I recently found a site called \"EDA Playground\" in which you can simulate using various simulators and also synthesize using Mentor Questa, a commercial synthesizer. I\'m not familiar with Questa, but here is a link with a simple example. You could set up your own \"playground\" and synthesize. I don\'t know if you can view the resulting schematics, but you can at least get resulting utilization statistics:

https://www.edaplayground.com/x/2BmJ

Sorry; I meant the Mentor *Precision* synthesizer. Questa (née Modelsim) is the simulator.
 

Welcome to EDABoard.com

Sponsor

Back
Top