Newbie: Help with Arrays

  • Thread starter jjlindula@hotmail.com
  • Start date
J

jjlindula@hotmail.com

Guest
Hello, I'm hoping someone can help me with my problem. I'm still new
with Verilog/SystemVerilog so please forgive me for this question. I
have three inputs that I would like to put in an array and then use
the array to compare to some constant. I have some code below, please
let me know how I could do this better.


module dsp_if(
input dsp_ms0,
input dsp_ms1,
input dsp_msh,

input dsp_wr,

output dram_wren
);

localparam [2:0] MS0 = 3'b110;
localparam [2:0] MS1 = 3'b101;
localparam [2:0] MSH = 3'b011;

wire [2:0] strobes;

assign strobes[0] = dsp_ms0;
assign strobes[1] = dsp_ms1;
assign strobes[2] = dsp_msh;

assign dram_wren = (strobes[2:0] == MSO);

endmodule

Thanks,
joe
 
jjlindula@hotmail.com <jjlindula@hotmail.com> wrote:
Hello, I'm hoping someone can help me with my problem. I'm still new
with Verilog/SystemVerilog so please forgive me for this question. I
have three inputs that I would like to put in an array and then use
the array to compare to some constant. I have some code below, please
let me know how I could do this better.
Do you want an array (mostly used for memory) or a multiple bit
variable (mostly used for buses, such as a data or address bus).

module dsp_if(
input dsp_ms0,
input dsp_ms1,
input dsp_msh,
input dsp_wr,
output dram_wren
);

localparam [2:0] MS0 = 3'b110;
localparam [2:0] MS1 = 3'b101;
localparam [2:0] MSH = 3'b011;

wire [2:0] strobes;

assign strobes[0] = dsp_ms0;
assign strobes[1] = dsp_ms1;
assign strobes[2] = dsp_msh;
I would have done:

assign strobes={dsp_msh, dsp_ms1, dsp_ms0};

(You can number them either [2:0] or [0:2]. In either case, the
more significant bit (when used as a number) is on the left.

== MSO);
endmodule
Looks fine to me. What does it do?

-- glen
 
On Nov 19, 9:45 am, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
jjlind...@hotmail.com <jjlind...@hotmail.com> wrote:
Hello, I'm hoping someone can help me with my problem. I'm still new
with Verilog/SystemVerilog so please forgive me for this question. I
have three inputs that I would like to put in an array and then use
the array to compare to some constant. I have some code below, please
let me know how I could do this better.

Do you want an array (mostly used for memory) or a multiple bit
variable (mostly used for buses, such as a data or address bus).

module dsp_if(
input dsp_ms0,
input dsp_ms1,
input dsp_msh,
input dsp_wr,
output dram_wren
);
localparam [2:0] MS0 = 3'b110;
localparam [2:0] MS1 = 3'b101;
localparam [2:0] MSH = 3'b011;
wire [2:0] strobes;
assign strobes[0] = dsp_ms0;
assign strobes[1] = dsp_ms1;
assign strobes[2] = dsp_msh;

I would have done:

  assign strobes={dsp_msh, dsp_ms1, dsp_ms0};

(You can number them either [2:0] or [0:2].  In either case, the
more significant bit (when used as a number) is on the left.

assign dram_wren = (strobes[2:0] == MSO);
endmodule

Looks fine to me.  What does it do?

-- glen
Glen,

Thank you so much. The program is doing some address decoding on for a
DSP.

Thanks,
joe
 
On Nov 19, 4:51 pm, "jjlind...@hotmail.com" <jjlind...@hotmail.com>
wrote:
On Nov 19, 9:45 am, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:



jjlind...@hotmail.com <jjlind...@hotmail.com> wrote:
Hello, I'm hoping someone can help me with my problem. I'm still new
with Verilog/SystemVerilog so please forgive me for this question. I
have three inputs that I would like to put in an array and then use
the array to compare to some constant. I have some code below, please
let me know how I could do this better.

Do you want an array (mostly used for memory) or a multiple bit
variable (mostly used for buses, such as a data or address bus).

module dsp_if(
input dsp_ms0,
input dsp_ms1,
input dsp_msh,
input dsp_wr,
output dram_wren
);
localparam [2:0] MS0 = 3'b110;
localparam [2:0] MS1 = 3'b101;
localparam [2:0] MSH = 3'b011;
wire [2:0] strobes;
assign strobes[0] = dsp_ms0;
assign strobes[1] = dsp_ms1;
assign strobes[2] = dsp_msh;

I would have done:

  assign strobes={dsp_msh, dsp_ms1, dsp_ms0};

(You can number them either [2:0] or [0:2].  In either case, the
more significant bit (when used as a number) is on the left.

assign dram_wren = (strobes[2:0] == MSO);
endmodule

Looks fine to me.  What does it do?

-- glen

Glen,

Thank you so much. The program is doing some address decoding on for a
DSP.

Thanks,
joe
Your code looks like you may be somewhat more versed in VHDL than
Verilog. There is no need to size your constants or use binary
for constants that have odd bit lengths. i.e. you could write

localparam MS0 = 6;
or
localparam [2:0] MS0 = 6;

unsized parameters would be 32-bit integers, sized parameters
might cause a truncation of the constant to fit in the bit
field size. In your case, the constant 6 fits in the 3-bit
unsigned field.

The comparison (strobes[2:0] == MSO) would do the right thing
assuming the constant 6 fits in the same size as strobes[2:0]
which is presumed to be unsigned. You could also write
(strobes[2:0] == 6) for that matter. I've found that VHDL
writers tend to add otherwise unnecessary levels to the code
to work around the sized constant issues.

Regards,
Gabor
 
On Nov 20, 3:26 pm, gabor <ga...@alacron.com> wrote:
I've found that VHDL
writers tend to add otherwise unnecessary levels to the code
to work around the sized constant issues.
Verilog users who use serious lint tools, or who are
exposed to careful and paranoid code reviews, may do likewise.
--
Jonathan Bromley
 
gabor <gabor@alacron.com> wrote:
On Nov 19, 4:51?pm, "jjlind...@hotmail.com" <jjlind...@hotmail.com
wrote:
On Nov 19, 9:45?am, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
(snip)
Do you want an array (mostly used for memory) or a multiple bit
variable (mostly used for buses, such as a data or address bus).
(snip)
MS0 = 3'b110;
localparam [2:0] MS1 = 3'b101;
localparam [2:0] MSH = 3'b011;
wire [2:0] strobes;
assign strobes[0] = dsp_ms0;
assign strobes[1] = dsp_ms1;
assign strobes[2] = dsp_msh;
(snip)

Your code looks like you may be somewhat more versed in VHDL than
Verilog. There is no need to size your constants or use binary
for constants that have odd bit lengths. i.e. you could write

localparam MS0 = 6;
or
localparam [2:0] MS0 = 6;
You might get warning messages, though.

I remember Quartus giving warnings when adding two values
and assigning to the same width as the addends. I thought
from my verilog book that it shouldn't do that, but it did.

unsized parameters would be 32-bit integers, sized parameters
might cause a truncation of the constant to fit in the bit
field size. In your case, the constant 6 fits in the 3-bit
unsigned field.

The comparison (strobes[2:0] == MSO) would do the right thing
assuming the constant 6 fits in the same size as strobes[2:0]
which is presumed to be unsigned. You could also write
(strobes[2:0] == 6) for that matter. I've found that VHDL
writers tend to add otherwise unnecessary levels to the code
to work around the sized constant issues.
-- glen
 
On Nov 21, 12:52 am, glen herrmannsfeldt <g...@ugcs.caltech.edu>
wrote:
gabor <ga...@alacron.com> wrote:
Your code looks like you may be somewhat more versed in VHDL than
Verilog.  There is no need to size your constants or use binary
for constants that have odd bit lengths.  i.e. you could write
localparam MS0 = 6;
or
localparam [2:0] MS0 = 6;

You might get warning messages, though.

I remember Quartus giving warnings when adding two values
and assigning to the same width as the addends.  I thought
from my verilog book that it shouldn't do that, but it did.
I got Quartus warnings from things like:

cnt <= cnt + 1;

So I began using:

cnt <= cnt + 'd1;

It'd be very enlightening if Jonathan and the other wizards point any
gotchas or weaknesses in the latter form.
 
On Nov 21, 12:37 pm, vladitx <vlad...@nucleusys.com> wrote:

I got Quartus warnings from things like:

  cnt <= cnt + 1;

So I began using:

  cnt <= cnt + 'd1;

It'd be very enlightening if Jonathan and the other wizards point any
gotchas or weaknesses in the latter form.
It's definitely OK if what you want is a counter the same bit-width
as "cnt", wrapping around from all-1s to zero.

Here's the deal: The rules of the Verilog language - which, remember,
is defined by its SIMULATION behaviour and not in terms of synthesis
results - say that you do arithmetic in the bit-width specified by
the expression context. Given

reg [7:0] cnt; // 8 bits
...
cnt <= cnt + 1'b1;

the context width is the largest of all widths participating in
the arithmetic (including the target): max(8,8,1)=8 of course,
so the context width is 8 bits. The increment value 1'b1 is then
widened to this width, and since the whole expression is unsigned
the widening is done by zero-padding and in effect you get

cnt <= cnt + 8'b0000_0001;

The arithmetic is then done, all in 8-bit width, with any carry
being thrown away; the 8-bit result is then copied into "cnt"
and you get the count behaviour you expected. So far, so good.
If Quartus or any tool gives a warning for this, it's wrong;
the way it's coded, Verilog insists that any carry bit is
thrown away.

Now let's try
cnt <= cnt + 1;
The context width is now 32 bits since the undecorated integer
constant "1" is 32 bits wide (yeah, I know there are wrinkles
about that, but for any practical consideration it's 32 bits).
So the arithmetic is done in 32-bit precision, with the value
of "cnt" first being widened to 32 bits. Again it's unsigned
so the widening is just zero padding and you get, in effect,

cnt <= {24'b0, cnt} + 32'h0000_0001;

The result of the add operation is now 32 bits wide and, of
course, the upper 24 bits may be non-zero. When this result
is copied back into "cnt" the standard Verilog truncation
behaviour kicks in and the upper 24 bits are thrown away.
So you will, in simulation, get exactly the same behaviour
as if you'd specified the constant to be 1'b1; but the
underlying mechanism is a little different. And a smart
linting or synthesis tool could reasonably issue a warning
that you were throwing away 24 bits that might, just possibly,
contain useful information.

So I don't think there are any obvious "gotchas" with using
an increment of 1'b1. However, there most certainly IS a
gotcha if you're trying to use Verilog signed arithmetic.
Obviously for a simple wrap-around counter this is irrelevant,
but there may be applications where it matters.

reg signed [3:0] R4;
reg signed [7:0] R8;
...
R8 <= R8 + R4; // R4 gets correctly sign-extended
R8 <= R8 + R4 + 1'b1; // R4 is NOT sign-extended!!!!

Why the problem in the second calculation? In the first
expression "R8 + R4", ALL participating operands are signed
and so the whole expression is computed using signed arithmetic.
That means R4 is first sign-extended to 8 bits and you get, in
effect,
R8 <= R8 + { {4{R4[3]}}, R4 };

But in the second expression, one of the operands (1'b1) is
unsigned; in the Humpty Dumpty world of Verilog signed
arithmetic, this single unsigned operand "poisons" the entire
expression so that EVERYTHING is done in unsigned arithmetic.
Consequently you get, in effect,
R8 <= R8 + { 4'b0, R4 } + 8'b0000_0001;
and negative values of R4 will not be correctly handled.

So it's important to make the constant signed. And here's
where the big Gotcha! comes in:
R8 <= R8 + R4 + 1'sb1; // make the constant be signed
All operands are now signed, and therefore the whole thing
is done in signed arithmetic. But tell me, O gentle reader:
what happens when you sign-extend 1'sb1 to 8 bit width?
Yes, you got it: the result is 8'b1111_1111, effectively -1.
Twos complement numbers that are only 1 bit wide are bad...

-------

Another place where bit width matters is when you're doing
comparisons or checks, typically in a testbench or an assertion.
Suppose I have an 8-bit counter and I want to verify that
it's counting correctly.

always @(posedge clock) begin
reg [7:0] old_count;
// This is the counter checking code
if (count !== old_count + 1)
$display("Bad count");
// get ready for the next check
old_count = count;
end

This looks fine, but it has a bug. Although "count" and
"old_count" are both 8 bits wide, the calculation of
"old_count+1" is done in 32-bit arithmetic. When
old_count=255 and count correctly contains 0, the
checking code looks like this:

if (count !== old_count + 1)
--- effectively the same as...
if (32'd0 !== {24'b0, old_count} + 32'd1;
--- which is the same as...
if (32'd0 !== 32'd256)

and the check wrongly shows an error. Make the constant
'1' be 8 bits wide or less, and all is well.

Hope this helps a little.
--
Jonathan Bromley
 
vladitx <vladitx@nucleusys.com> wrote:
On Nov 21, 12:52?am, glen herrmannsfeldt <g...@ugcs.caltech.edu
wrote:
(snip on size of constants)

You might get warning messages, though.

I remember Quartus giving warnings when adding two values
and assigning to the same width as the addends. ?I thought
from my verilog book that it shouldn't do that, but it did.

I got Quartus warnings from things like:

cnt <= cnt + 1;

So I began using:

cnt <= cnt + 'd1;
When I was using Quartus, about five years ago, it gave warnings
for both. I didn't think it should, but then started using the
first form, as it wasn't saving me from the warnings.

It'd be very enlightening if Jonathan and the other wizards point any
gotchas or weaknesses in the latter form.
If it works right, with now warning, then use the latter.

-- glen
 
Answering bit late ...

On Nov 21, 7:18 pm, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
vladitx <vlad...@nucleusys.com> wrote:
I got Quartus warnings from things like:
 cnt <= cnt + 1;
So I began using:
 cnt <= cnt + 'd1;

When I was using Quartus, about five years ago, it gave warnings
for both.  I didn't think it should, but then started using the
first form, as it wasn't saving me from the warnings.
The first form is paranoidly reported for the reasons Jonathan cited -
widening the expression to 32 bits (or 64 on some implementations??).
And here comes my confusion - I thought that the latter form <'d1>
fixes it ... and I was wrong. Since I haven't touched Quartus for more
than a year, my recollections were fuzzy.

What I thought is, that <'d1> will widen the literal to the maximal
expression width, hence no warnings.

If it works right, with now warning, then use the latter.
No, warning issued on both. :-(
I tested with Quartus 7.x, then realised how misleading my memory is.
 
On Nov 21, 4:05 pm, Jonathan Bromley <s...@oxfordbromley.plus.com>
wrote:
On Nov 21, 12:37 pm, vladitx <vlad...@nucleusys.com> wrote:

I got Quartus warnings from things like:

  cnt <= cnt + 1;

So I began using:

  cnt <= cnt + 'd1;

It'd be very enlightening if Jonathan and the other wizards point any
gotchas or weaknesses in the latter form.

It's definitely OK if what you want is a counter the same bit-width
as "cnt", wrapping around from all-1s to zero.
I perfectly understand why Quartus is so pedantic about the first.
Probably there is a way to disable this warning, could get annoying.

But I was wrong about the second - it produces same warning, so
similar widening must have occurred. Gotta read carefully the
semantics of apostrophed width-less literals again.

R4;
  reg signed [7:0] R8;
  ...
  R8 <= R8 + R4;  // R4 gets correctly sign-extended
  R8 <= R8 + R4 + 1'b1;  // R4 is NOT sign-extended!!!!

Why the problem in the second calculation?  In the first
expression "R8 + R4", ALL participating operands are signed
and so the whole expression is computed using signed arithmetic.
That means R4 is first sign-extended to 8 bits and you get, in
effect,
  R8 <= R8 + { {4{R4[3]}}, R4 };

But in the second expression, one of the operands (1'b1) is
unsigned; in the Humpty Dumpty world of Verilog signed
arithmetic, this single unsigned operand "poisons" the entire
expression so that EVERYTHING is done in unsigned arithmetic.
Right, this is borrowed from 'C' among other things. If only they
didn't stick to the "begin" / "end" keywords ...

  R8 <= R8 + R4 + 1'sb1;  // make the constant be signed
All operands are now signed, and therefore the whole thing
is done in signed arithmetic.  But tell me, O gentle reader:
what happens when you sign-extend 1'sb1 to 8 bit width?
Yes, you got it: the result is 8'b1111_1111, effectively -1.
Twos complement numbers that are only 1 bit wide are bad...
Well, this is really not that obvious. :)
I admit without being alarmed about this specific quirk, I could stare
at the line for ages before realising what's wrong.

Hope this helps a little.
You've got to be kidding me about the "little" part! This is one of
the most useful comp.xxx posts I have read in a while. Each similar
short essay on the "shady corners" of Verilog brings tons of refined
information together with articulated arguments, so even a caveman
like me is able to digest it. For free.

[OT] I wish to personally thank Jonathan and the other gurus here for
sacrificing their spare time in the name of knowledge spreading. We,
the stalking readers, appreciate it.
 
On Sat, 28 Nov 2009 16:15:43 -0800 (PST), vladitx wrote:

But I was wrong about the second
  cnt <= cnt + 'd1;
- it produces same [truncation] warning, so
similar widening must have occurred. Gotta read carefully the
semantics of apostrophed width-less literals again.
Same width as integer (generally 32 bit), but unsigned. Sorry,
I mis-read your post - I thought you had written 1'b1 there,
hence my detailed description of the behaviour of 1'b1 later.

BTW that's the second time I've been vague about the bit width
of integer - that's because the standard says "at least 32 bits".
Every simulator I've ever met treats integers as 32 bits, but
the language only guarantees "at least". That's why you can't
put unsized integer literals in a concatenation:

a = {2'b0, 1}; // illegal, don't know the width of '1'
a = {2'b0, 'd1}; // similarly illegal
a = {2'b0, 32'd1); // OK, result is 34 bits wide

Twos complement numbers that are only 1 bit wide are bad...
Well, this is really not that obvious. :)
Lots of things are "not that obvious" when you have a
language that understands explicit bit widths. Having
played around with these things at some length in VHDL,
where to some extent you can make your own rules about
the handling of extension and truncation, I'm convinced
that there is no single way of dealing with it that will
answer ALL the needs of convenience, idiot-proofing and
good match to digital hardware. Whatever you do, there
will be some compromise. Verilog has chosen one possible
compromise.

I wish to personally thank Jonathan...
No thanks to me. Many of us have reason to be grateful
to Steven Sharp who, in a series of posts a few years ago,
clarified with beautiful lucidity the arcana of Verilog
arithmetic rules. I think that, at the time, he was
helping to refine the Verilog-2005 standard, which
describes those rules with much more clarity and less
ambiguity than earlier editions. His descriptions put
me (and, I'm sure, many others) on the right track.
--
Jonathan Bromley, Verification Engineer

Verilab www.THAT_COMPANY.com
 
On Nov 29, 2:22 pm, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Sat, 28 Nov 2009 16:15:43 -0800 (PST), vladitx wrote:
But I was wrong about the second
  cnt <= cnt + 'd1;
- it produces same [truncation] warning, so
similar widening must have occurred. Gotta read carefully the
semantics of apostrophed width-less literals again.

Same width as integer (generally 32 bit), but unsigned.
Ok, I won't misuse it again.

I mis-read your post - I thought you had written 1'b1 there,
hence my detailed description of the behaviour of 1'b1 later.
Which came quite useful, explaining stuff I didn't knew. I don't
complain at all. :)

"The error is correct", as a friend of mine used to say.

BTW that's the second time I've been vague about the bit width
of integer - that's because the standard says "at least 32 bits".
Every simulator I've ever met treats integers as 32 bits, but
the language only guarantees "at least".
I suppose 64 bits is not unlikely, even if not yet deployed.

I wish to personally thank Jonathan...

No thanks to me.  Many of us have reason to be grateful
to Steven Sharp who, in a series of posts a few years ago,
clarified with beautiful lucidity the arcana of Verilog
arithmetic rules.  I think that, at the time, he was
helping to refine the Verilog-2005 standard, which
describes those rules with much more clarity and less
ambiguity than earlier editions.  His descriptions put
me (and, I'm sure, many others) on the right track.
You, him, and many others I thank (as I already wrote). Because I self-
taught Verilog and this is still a hobby, and because I joined
comp.lang.verilog after 2005, I am grateful that people continue
investing time to explain subtle things to others.
 

Welcome to EDABoard.com

Sponsor

Back
Top