vhdl questions from a verilog person

M

Mark Brehob

Guest
Hello all,
I'm a teacher who has been teaching students Verilog for a while, but
for various reasons I've had to jump to VHDL for a certain course.
I've been writing a fair bit of simple VHDL stuff (basic DSP
algorithms), and found it both powerful and frustrating. Mostly I'm
trying to figure out if there are better ways to do things and why
VHDL and/or VHDL coders do certain things.

As a note most of my verilog experience is doing synthesizable ASIC
(with some FPGA) while my VHDL stuff is all FPGA based.

#1 Why no process(*) statement similar to always@*?

The vast majority of all process statements are either modeling
combinational logic or something that changes only on clock/reset.
Why doesn't VHDL have a process(*) kind of statement as verilog does
saying "this is combinational logic, update if any of the inputs
change". Having to get the process statement right is painful to
student (add a variable and forget to update the process line) and
further, Xilinx software (at least) just adds things to the process
list anyways with just a warning.


#2 How do I add two values both of which are arbitrary in size?

So say I have one STD_LOGIC_VECTOR that is X bits and one that is Y
bits. Is there a clean way to add them (into something of Z bits for
sake of argument)? I find myself casting to an integer (and back) to
get stuff to work but that's neither pretty nor probably a good
idea.


#3 Is there a good way to index an array with a STD_LOGIC_VECTOR?

Again, I found myself casting back and forth. I suspect here there is
a right way to do this and I'm just missing it.


#4 What's up with all the different ways to check for a rising edge of
a clock?

The code base I inherited uses rising_edge, but that seems to be
fairly uncommon if code I find on the net is any indicator. I think
I've seen three other ways to do it. (Old value was 0 new is one,
current value is 1 and there was a change event, and one other.) Is
there a good reason everyone doesn't just use rising_edge? Is there
something I'm missing?



I had a bunch of other questions, but of course I've forgotten (did my
coding over the weekend and I guess 48 hours ago is enough time to
forget). I'm mostly enjoying it, but as you might expect, it's
bringing back Ada nightmares. At the current time I feel like I'm
jumping through hoops to get around the strict type checking (just
like I recall doing years ago with Ada). C/Verilog people should not
have to deal with strict type checking :).

Humm, I guess I'd like thoughts on my coding style, but the students
are finishing "filling in the blanks" on my code, so that will have to
wait until next week.

Thanks in advance,
Mark
 
Mark
#1 Why no process(*) statement similar to always@*?
Process(all) is in the Accellera VHDL 3.0 2006 trial standard
and in IEEE 1076-2008.

To everyone out there, make sure your vendors know this is
important to you as they have had 2.5 years already to work on it.
I would recommend submitting it as a bug report.

#2 How do I add two values both of which are arbitrary in size?

So say I have one STD_LOGIC_VECTOR that is X bits and one that is Y
bits. Is there a clean way to add them (into something of Z bits for
sake of argument)? I find myself casting to an integer (and back) to
get stuff to work but that's neither pretty nor probably a good
idea.
Std_logic_vector is not a math type. Types signed and unsigned are.
See the paper, VHDL Math Tricks of the Trade from the website:
http://www.synthworks.com/papers/index.htm

#3 Is there a good way to index an array with a STD_LOGIC_VECTOR?

Again, I found myself casting back and forth. I suspect here there is
a right way to do this and I'm just missing it.
You need to convert it to integer. The conversion is as follows,
where a_slv is the value you need to convert. See the referenced
paper for details.

to_integer(unsigned(a_slv))


#4 What's up with all the different ways to check for a rising edge of
a clock?
Rising_edge is the newer (from synthesis tool support) and more readable
way to do this.

When coding a simple register:

ARegProc : process(nReset, Clk)
begin
if nReset = '0' then
AReg <= '0' ;
elsif rising_edge(Clk) then
AReg <= A ;
end if ;
end process ;

WRT portable coding styles, I recommend either rising_edge or the following
(note that I prefer rising_edge):
elsif clk='1' and clk'event then
elsif clk'event and clk='1' then

These are real old and may or may not be portable (work in all synthesis tools):
elsif clk='1' and not clk'stable then
elsif not clk'stable and clk='1' then

This one was supported by a particular tool (which is now gone) and
I doubt it is portable (which may be confusing as it is very similar
to the rising_edge procedure):
elsif clk='1' and clk'event and clk ='0' then
... and its variations


I had a bunch of other questions, but of course I've forgotten (did my
coding over the weekend and I guess 48 hours ago is enough time to
forget). I'm mostly enjoying it, but as you might expect, it's
bringing back Ada nightmares. At the current time I feel like I'm
jumping through hoops to get around the strict type checking (just
like I recall doing years ago with Ada). C/Verilog people should not
have to deal with strict type checking :).
Yes, but the DVCon paper that I saw that used a lint tool to apply
VHDL type checking rules to Verilog (to simplify code conversion)
indicated that 75% of the time there was a lint violation it was
a real bug. Although you have some rules to learn, it is quite
a bit faster to find a bug at compile/lint time rather than having
debug it in a simulator.

Cheers,
Jim
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis SynthWorks VHDL Training http://www.synthworks.com

A bird in the hand may be worth two in the bush,
but it sure makes it hard to type.
 
"Mark Brehob" <brehob@gmail.com> wrote in message
news:c0fe3c23-6638-41fc-916e-1b5990b6ba67@u18g2000pro.googlegroups.com...
Hello all,

#1 Why no process(*) statement similar to always@*?
To frustrate people mostly.

The vast majority of all process statements are either modeling
combinational logic or something that changes only on clock/reset.
Why doesn't VHDL have a process(*) kind of statement as verilog does
saying "this is combinational logic, update if any of the inputs
change".
I think that is part of VHDL-2008...whenever the vendors get around to
implementing it in the tools.

Having to get the process statement right is painful to
student (add a variable and forget to update the process line)
That's one reason why this newsgroup generally does not recommend using
combinatorial processes. Use only clocked processes (with or without
variables as needs and whims dictate) and concurrent statements. Use
functions and procedures.

Another reason is that combinatorial processes are 'bad' is that one needs
to make sure that every signal gets assigned through every path. Generally
this gets handled by applying the 'default' value at the start of the
process. This is just more typing, effort, and trouble then using clocked
processes and concurrent statements.

and
further, Xilinx software (at least) just adds things to the process
list anyways with just a warning.
And there is the other reason for avoiding such beasts...having simulation
be different than synthesis because you missed the 'warning'.

Try to avoid teaching use of these things, you'll be helping them in the
long run by showing how to avoid three common design errors that require
debug time to root out the cause.

#2 How do I add two values both of which are arbitrary in size?

So say I have one STD_LOGIC_VECTOR that is X bits and one that is Y
bits. Is there a clean way to add them (into something of Z bits for
sake of argument)? I find myself casting to an integer (and back) to
get stuff to work but that's neither pretty nor probably a good
idea.
Not every signal needs to be defined as std_logic_vector though. If
something is inherently an integer, than define it that way you'll avoid the
casting.

If you do need vectors, then look as ieee.numeric_std for your arithmetic,
it will do the things you've mentioned. That package defines two vector
types called 'signed' and 'unsigned' that apply a specific numeric
interpretation to the vector, as opposed to std_logic_vector which is simply
a collection of bits. Again, to avoid a lot of type casting, it is usually
best to define things using the correct type instead of always using
std_logic_vector and casting. One place where you should stick with
std_logic_vector though is at the top level entity ports.

#3 Is there a good way to index an array with a STD_LOGIC_VECTOR?
Yes...use an integer instead, which is what you're doing with the casting
X(to_integer(unsigned(my_slv)) <= '1';

Again, I found myself casting back and forth. I suspect here there is
a right way to do this and I'm just missing it.
Casting is the only way to do it...if you start with the mindset that
everything must be std_logic_vector. Use of other data types that are more
appropriate to start with is the way to avoid the ugliness of excessive type
casts.

#4 What's up with all the different ways to check for a rising edge of
a clock?
I only use "if rising_edge(clock) then..." or "wait until
rising_edge(clock);" It's self documenting. I have no idea why people use
less clear ways of expressing something so simple, but you're right they
certainly do.

The code base I inherited uses rising_edge, but that seems to be
fairly uncommon if code I find on the net is any indicator.
Not everything on the net is worth spit though...

I think
I've seen three other ways to do it. (Old value was 0 new is one,
current value is 1 and there was a change event, and one other.) Is
there a good reason everyone doesn't just use rising_edge? Is there
something I'm missing?
I think the others are the ones missing something, not you.

Kevin Jennings
 
On 2009-01-28, Mark Brehob <brehob@gmail.com> wrote:
As a note most of my verilog experience is doing synthesizable ASIC
(with some FPGA) while my VHDL stuff is all FPGA based.

#1 Why no process(*) statement similar to always@*?
Hi,

you have already gotten some nice answers but I thought I'd chip in with
a few additional notes:

* It is much easier to write combinational logic outside of a process
in VHDL. When I was going from VHDL to Verilog I was very frustrated that
the only way to create a condition outside an always block was to use
the ? operation. In VHDL you have the "with foo select ..." construct
which is very nice if you need to create a multiplexer for example.

* I believe that vhdl-mode for Emacs is able to automatically update
a process sensitivity list for you but I haven't tried that myself.


And some encouragement: Think of how nice it will be to know that the
students' code will not contain any blocking/non-blocking races.

/Andreas
 
On Tue, 27 Jan 2009 17:33:44 -0800 (PST), Mark Brehob wrote:

Hello all,
I'm a teacher who has been teaching students Verilog for a while, but
for various reasons I've had to jump to VHDL for a certain course.
[...]
#1 Why no process(*) statement similar to always@*?
Others have answered, but... as a teacher, I trust
you are aware of the various ways in which always@*
is broken? Move to SystemVerilog always_comb instead,
if at all possible. Most tools support it.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On 2009-01-28, Mark Brehob <brehob@gmail.com> wrote:
Actually, good coding style in Verilog completely eliminates that
problem. In my other class, the students build a synthisizable out-of-
order processor starting with an in-order processor. We've found that
blocking/non-blocking problems just don't occur if you follow simple
rules. We teach those rules as "required" and the problem go away.
See http://www.eecs.umich.edu/courses/eecs470/tools/verilog_guidelines.pdf
for a short summary.
Well, we teach more or less the same rules as well, but there is always
at least one group per year who manages to come up with some nice and
interesting blocking/non-blocking race condition :)

The course you are talking about sounds very interesting by the way,
I wish I could have attended such a course as an undergraduate student.
Do you know roughly how much time students spend doing the projects in
this course? Do they have to care about the efficiency of their
RTL code or do they only have to get it synthesizable?

/Andreas
 
Mark Brehob wrote:
On Jan 27, 9:00 pm, Andreas Ehliar <ehliar-nos...@isy.liu.se> wrote:
On 2009-01-28, Mark Brehob <bre...@gmail.com> wrote:


And some encouragement: Think of how nice it will be to know that the
students' code will not contain any blocking/non-blocking races.

/Andreas

Actually, good coding style in Verilog completely eliminates that
problem. In my other class, the students build a synthisizable out-of-
order processor starting with an in-order processor. We've found that
blocking/non-blocking problems just don't occur if you follow simple
rules. We teach those rules as "required" and the problem go away.
See http://www.eecs.umich.edu/courses/eecs470/tools/verilog_guidelines.pdf
for a short summary.
Simple enough, but especially intolerably simplistic.

Do you realize that these rules forbid variable semantics?
Even if you don't want to use variables in synthesizable code
for some awkward reason, you surely want them in test benches,
right? Don't you think you can have races there too? So what rule
do you use then?

No, even in Verilog you need something more sophisticated that
still permits variables: use signals (non-blocking assignments)
for communication, and variables (blocking assignments) for
local computation. It always works, for Verilog, VHDL, synthesis,
test bench, high-level modeling, you name it.

http://www.myhdl.org/doku.php/why#you_are_confused_about_blocking_and_non-blocking_assignments_in_verilog


--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Python as a hardware description language:
http://www.myhdl.org
 
On Tue, 27 Jan 2009 17:33:44 -0800 (PST), Mark Brehob <brehob@gmail.com>
wrote:

Hello all,
I'm a teacher who has been teaching students Verilog for a while, but
for various reasons I've had to jump to VHDL for a certain course.
I've been writing a fair bit of simple VHDL stuff (basic DSP
algorithms), and found it both powerful and frustrating. Mostly I'm
trying to figure out if there are better ways to do things and why
VHDL and/or VHDL coders do certain things.

As a note most of my verilog experience is doing synthesizable ASIC
(with some FPGA) while my VHDL stuff is all FPGA based.

#1 Why no process(*) statement similar to always@*?
There is basically very little need for it.

Simple combinatorial processes are built without the overhead of a
process statement, and in forms that take care of their own sensitivity
lists.

Most complex combinatorial processes I meet are inherited from third
party code; usually 2-process state machines and are better re-written
into single-process form anyway.

#2 How do I add two values both of which are arbitrary in size?

So say I have one STD_LOGIC_VECTOR that is X bits and one that is Y
bits. Is there a clean way to add them (into something of Z bits for
sake of argument)?
Yes there is: don't add std_logic_vectors.

If you're using a lot of casts, you're fighting against the type system
instead of letting it do a lot of the work for you. That's usually a
hint that you're not "getting" something about the problem.

Use numeric_std.
Declare subtypes of [un]signed and use them extensively.
Use attributes of those subtypes (x'range, x'high downto x'low) for loop
indices, slicing, declaring local variables, etc.
Use generics to control those subtypes.

Or use unconstrained port sizes.
And use the port's attributes (inport'range) to declare the local
subtypes.

Your components should then work without modification when you change
the size of the input ports.

#3 Is there a good way to index an array with a STD_LOGIC_VECTOR?
As above; but arrays can only be indexed by discrete types (not just
integers, but booleans or any other enumeration type.
So from unsigned you do need to convert.

#4 What's up with all the different ways to check for a rising edge of
a clock?
History. Stick to rising_edge.

I had a bunch of other questions, but of course I've forgotten (did my
coding over the weekend and I guess 48 hours ago is enough time to
forget). I'm mostly enjoying it, but as you might expect, it's
bringing back Ada nightmares.
Like having code that actually worked first time once you got it through
the compiler?

C/Verilog people should not
have to deal with strict type checking :).
It eats into their precious debugging time...

- Brian
 
On Wed, 28 Jan 2009 06:13:58 -0800 (PST), Mark Brehob wrote:

Actually I'm unaware of @* being broken. Is it that @* doesn't handle
functions correctly? I've seen something about that, but we rarely
use functions, so...
Yes, it's functions (mainly). @* sensitizes to function *arguments*,
but not to signals that are read within a function as side-effects.

So, for (artificial) example:

module broken_at_star(input clock, d, output reg q);
reg dd;
always @(posedge clock) dd <= d;
function rise(input x);
rise = x & !dd;
endfunction

always @*
q = rise(d);

endmodule

In this case, the always @* would be sensitive to d
but not to dd, which is clearly wrong.

There are also issues about sensitivity to memory
arrays, for stuff like

reg [7:0] the_mem [0:1023];
always @*
q = the_mem[adrs];

In this case, clearly the process is sensitive to adrs
but what about the_mem? Suppose adrs is fixed, and is
pointing to some location that is then updated by
another process? It's fairly clear that the process
is intended to represent asynchronous readout and
therefore it should update to follow the memory location,
but Verilog-2001 says you can't put a memory in a
sensitivity list. I'm not sure what the real story
is here - I try to avoid that kind of code - but I
suspect that tools do The Right Thing (tm).

SystemVerilog always_comb fixes all these things.

Finally, always @* doesn't stop you writing latches
by mistake:

always @* if (e) y = d;

Strictly speaking, always_comb doesn't fix this either;
but simulators are encouraged to give warnings for such
violations of combinational synthesis rules in an always_comb.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Wed, 28 Jan 2009 06:06:09 -0800 (PST), Mark Brehob wrote:

We teach those rules as "required" and the problem go away.
See http://www.eecs.umich.edu/courses/eecs470/tools/verilog_guidelines.pdf
for a short summary.
Ooooh, don't get me started about

10. Do not mix blocking and nonblocking assignments
in the same always block.

As a start, for beginners, it's fine. For anything
serious, it cramps the style horribly. Cliff Cummings
is an undoubted expert and a nice guy to boot, but he
and I part company in a big way on that point. You can't
get the behaviour of VHDL variables in a clocked process
without breaking that rule.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
 
On Jan 27, 9:00 pm, Andreas Ehliar <ehliar-nos...@isy.liu.se> wrote:
On 2009-01-28, Mark Brehob <bre...@gmail.com> wrote:



And some encouragement: Think of how nice it will be to know that the
students' code will not contain any blocking/non-blocking races.

/Andreas
Actually, good coding style in Verilog completely eliminates that
problem. In my other class, the students build a synthisizable out-of-
order processor starting with an in-order processor. We've found that
blocking/non-blocking problems just don't occur if you follow simple
rules. We teach those rules as "required" and the problem go away.
See http://www.eecs.umich.edu/courses/eecs470/tools/verilog_guidelines.pdf
for a short summary.

Verilog has lots of problems (generate statement can really be a pain,
multi-port memories can be a huge challenge, etc.), but blocking/non-
blocking problems don't pop up after the first 2 weeks of the class.
Heck, type-checking problems are rare (but certainly happen).
Mark
 
On Jan 27, 8:53 pm, Jim Lewis <j...@synthworks.com> wrote:
Mark> #1 Why no process(*) statement similar to always@*?

Process(all) is in the Accellera VHDL 3.0 2006 trial standard
and in IEEE 1076-2008.

To everyone out there, make sure your vendors know this is
important to you as they have had 2.5 years already to work on it.
I would recommend submitting it as a bug report.

#2 How do I add two values both of which are arbitrary in size?

So say I have one STD_LOGIC_VECTOR that is X bits and one that is Y
bits.  Is there a clean way to add them (into something of Z bits for
sake of argument)?  I find myself casting to an integer (and back) to
get stuff to work but that's neither pretty nor probably a good
idea.

Std_logic_vector is not a math type.  Types signed and unsigned are.
See the paper, VHDL Math Tricks of the Trade from the website:http://www.synthworks.com/papers/index.htm

#3 Is there a good way to index an array with a STD_LOGIC_VECTOR?

Again, I found myself casting back and forth.  I suspect here there is
a right way to do this and I'm just missing it.

You need to convert it to integer.  The conversion is as follows,
where a_slv is the value you need to convert.  See the referenced
paper for details.

   to_integer(unsigned(a_slv))

#4 What's up with all the different ways to check for a rising edge of
a clock?

Rising_edge is the newer (from synthesis tool support) and more readable
way to do this.

When coding a simple register:

ARegProc : process(nReset, Clk)
begin
   if nReset = '0' then
     AReg <= '0' ;
   elsif rising_edge(Clk) then
     AReg <= A ;
   end if ;
end process ;

WRT portable coding styles, I recommend either rising_edge or the following
(note that I prefer rising_edge):
   elsif clk='1' and clk'event then
   elsif clk'event and clk='1' then

These are real old and may or may not be portable (work in all synthesis tools):
   elsif clk='1' and not clk'stable then
   elsif not clk'stable and clk='1' then

This one was supported by a particular tool (which is now gone) and
I doubt it is portable (which may be confusing as it is very similar
to the rising_edge procedure):
   elsif clk='1' and clk'event and clk ='0' then
   ... and its variations

I had a bunch of other questions, but of course I've forgotten (did my
coding over the weekend and I guess 48 hours ago is enough time to
forget).  I'm mostly enjoying it, but as you might expect, it's
bringing back Ada nightmares.  At the current time I feel like I'm
jumping through hoops to get around the strict type checking (just
like I recall doing years ago with Ada).  C/Verilog people should not
have to deal with strict type checking :).

Yes, but the DVCon paper that I saw that used a lint tool to apply
VHDL type checking rules to Verilog (to simplify code conversion)
indicated that 75% of the time there was a lint violation it was
a real bug.  Although you have some rules to learn, it is quite
a bit faster to find a bug at compile/lint time rather than having
debug it in a simulator.

Cheers,
Jim
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis    SynthWorks VHDL Training    http://www.synthworks.com

A bird in the hand may be worth two in the bush,
but it sure makes it hard to type.
Thanks to Jim and Kevin for the feedback. It was quite helpful. In
particular using integers in place of vectors seems interesting (and
unusual to a Verilog person). I'll have to think about that.

Thanks again,
Mark
 
On Jan 28, 4:08 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Tue, 27 Jan 2009 17:33:44 -0800 (PST), Mark Brehob wrote:
Hello all,
I'm a teacher who has been teaching students Verilog for a while, but
for various reasons I've had to jump to VHDL for a certain course.
[...]
#1 Why no process(*) statement similar to always@*?

Others have answered, but... as a teacher, I trust
you are aware of the various ways in which always@*
is broken?  Move to SystemVerilog always_comb instead,
if at all possible.  Most tools support it.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.brom...@MYCOMPANY.comhttp://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
Actually I'm unaware of @* being broken. Is it that @* doesn't handle
functions correctly? I've seen something about that, but we rarely
use functions, so...

In any case, could you elaborate?

Thanks,
Mark
 
On Jan 28, 6:17 am, Andreas Ehliar <ehliar-nos...@isy.liu.se> wrote:
On 2009-01-28, Mark Brehob <bre...@gmail.com> wrote:

Actually, good coding style in Verilog completely eliminates that
problem.  In my other class, the students build a synthisizable out-of-
order processor starting with an in-order processor.  We've found that
blocking/non-blocking problems just don't occur if you follow simple
rules.  We teach those rules as "required" and the problem go away.
Seehttp://www.eecs.umich.edu/courses/eecs470/tools/verilog_guidelines.pdf
for a short summary.

Well, we teach more or less the same rules as well, but there is always
at least one group per year who manages to come up with some nice and
interesting blocking/non-blocking race condition :)

The course you are talking about sounds very interesting by the way,
I wish I could have attended such a course as an undergraduate student.
Do you know roughly how much time students spend doing the projects in
this course?  Do they have to care about the efficiency of their
RTL code or do they only have to get it synthesizable?

/Andreas
I recently read a text titled "FPGA Prototyping by Verilog
Examples." There is a section discussing the use/mixing of blocking/
no-blocking statements. Perhaps the best explanation I've seen. If
you have a chance, borrow it from a library and look at sections 7.1
and 7.2.

GK
 
Just remember to restrict the range of your integers (or subtypes), or
synthesis will promote everything to 32 bits signed (integer'range).
For an integer of unsigned(n-1 downto 0):

variable count : integer range 0 to 2**n-1;

I like to use the natural subtype just for more readability, but both
are equivalent:

variable count : natural range 0 to 2**n-1;

Also, expressions are promoted to 32 bit signed, only assignments are
restricted. So something like this works with natural subtypes, but
not with unsigned vectors:

if count - 1 < 0 then
do_something;
count := 2**n - 1;
else
count := count - 1;
end if;

This also has the benefit of automatically using the carry output from
the decrement logic, which is sometimes quicker and smaller. The two
decrementors from the comparison and the assignment end up being
shared in synthesis.

This also works for an up counter:

if count + 1 > 2**n-1 then
do_something;
count := 0;
else
count := count + 1;
end if;

Don't worry, because storage is limited to N bits, the operation's
promotion is pruned anyway.

Similarly, if you want integer arithmetic to rollover, you need to
tell it to do so:

count := (count - 1) mod 2**n; -- don't forget the parentheses!

In simulation, integer arithmetic is MUCH faster than vector
arithmetic.

Andy
 
There is always a tendency to teach a new design method/langauge in
terms of translating the elements of the old method or language. When
teaching HDL to folks who know schematics with gates and registers, we
tend to focus on HDL descriptions of gates and registers. When we
teach vhdl to verilog users, we tend to focus on translating verilog
elements into their vhdl equivalents.

This method of teaching tends to restrict the use of the new language
to the limits imposed by the old one. Thus it is with vhdl's variables
and signals vs verilog's blocking and non-blocking assignment
statements. Because there are so many easy ways to get into trouble
with verilog blocking and non-blocking assignments, most tend not to
use one or the other effectively (usually blocking assignments).
However vhdl enforces Jan's restrictions on communication (signals) vs
local computation (variables), so using both effectively is much
safer.

This in turn allows one to focus on fewer, more complex, clocked vhdl
processes that describe the desired rusults in terms of cycle by cycle
behavior, instead of in terms of registers and gates. The increase in
abstraction allows designing something based on its intended behavior,
not its intended structure, which would have to be worked out
separately in one's head or on paper or whatever.

To be fair, with less concentration on the registers and gates it
takes to effect a desired behavior, it is easier to design something
that works, if only it would fit in the desired device or run at the
desired clock speed! However, even when faced with this dillema,
considering behavioral modifications in terms of adding cycles of
latency and spreading the behavioral complexity between them, instead
of structural additions of registered pipeline stages, is often
helpful, especially if the spreading step is an optimization available
in the synthesis tool (aka register retiming).

Hope this helps,

Andy
 
I guess the first point is to keep in mind the students will have done
a handful of trivial verilog modules before taking this class. And
they have to learn a huge number of other things. So we necessarily
oversimplify things. That said, it would be very useful for me to
understand why people believe these are over simplified. Even if we
don't change our rules, it's important for me to understand "truth" so
I can let them know the issues involved.

On Jan 28, 9:30 am, Jan Decaluwe <j...@jandecaluwe.com> wrote:
Mark Brehob wrote:
On Jan 27, 9:00 pm, Andreas Ehliar <ehliar-nos...@isy.liu.se> wrote:
On 2009-01-28, Mark Brehob <bre...@gmail.com> wrote:

And some encouragement: Think of how nice it will be to know that the
students' code will not contain any blocking/non-blocking races.

/Andreas

Actually, good coding style in Verilog completely eliminates that
problem.  In my other class, the students build a synthisizable out-of-
order processor starting with an in-order processor.  We've found that
blocking/non-blocking problems just don't occur if you follow simple
rules.  We teach those rules as "required" and the problem go away.
Seehttp://www.eecs.umich.edu/courses/eecs470/tools/verilog_guidelines.pdf
for a short summary.

Simple enough, but especially intolerably simplistic.

Do you realize that these rules forbid variable semantics?
Even if you don't want to use variables in synthesizable code
for some awkward reason, you surely want them in test benches,
right? Don't you think you can have races there too? So what rule
do you use then?
It's in that list and I think it works fairly well. We change inputs
from the testbench only on the falling edge of the clock. As we don't
worry about the testbench being synthisizable we don't worry too much
about the "rules" there. It has caused occasional problems, but
nothing I can think of as a huge or common problem at all.


No, even in Verilog you need something more sophisticated that
still permits variables: use signals (non-blocking assignments)
for communication, and variables (blocking assignments) for
local computation. It always works, for Verilog, VHDL, synthesis,
test bench, high-level modeling, you name it.

http://www.myhdl.org/doku.php/why#you_are_confused_about_blocking_and...
At a quick glance, I'm not seeing the definition of communication vs.
local. It would seem that sometimes things are both, but I'd guess
you have a formal definition that handles that. However, I'll note
that our rules are really simple to understand and a lint program can
be written to check for it. (In fact there is one some students wrote
on sourceforge). This is really handy when dealing with fairly novice
coders.

Thanks again!



Mark

--
Jan Decaluwe - Resources bvba -http://www.jandecaluwe.com
     Python as a hardware description language:
     http://www.myhdl.org
 
On Jan 28, 9:43 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
On Wed, 28 Jan 2009 06:06:09 -0800 (PST), Mark Brehob wrote:
We teach those rules as "required" and the problem go away.
Seehttp://www.eecs.umich.edu/courses/eecs470/tools/verilog_guidelines.pdf
for a short summary.

Ooooh, don't get me started about

    10. Do not mix blocking and nonblocking assignments
        in the same always block.

As a start, for beginners, it's fine.  For anything
serious, it cramps the style horribly.  Cliff Cummings
is an undoubted expert and a nice guy to boot, but he
and I part company in a big way on that point.  You can't
get the behaviour of VHDL variables in a clocked process
without breaking that rule.
--
Jonathan Bromley, Consultant

DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services

Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.brom...@MYCOMPANY.comhttp://www.MYCOMPANY.com

The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
Could you give an example or otherwise illustrate the issue here? I'm
not sure what "the behaviour of VHDL variables in a clocked process"
is, or why I'd want it.

Thanks!
Mark
 
On Jan 28, 6:17 am, Andreas Ehliar <ehliar-nos...@isy.liu.se> wrote:
On 2009-01-28, Mark Brehob <bre...@gmail.com> wrote:

Actually, good coding style in Verilog completely eliminates that
problem.  In my other class, the students build a synthisizable out-of-
order processor starting with an in-order processor.  We've found that
blocking/non-blocking problems just don't occur if you follow simple
rules.  We teach those rules as "required" and the problem go away.
Seehttp://www.eecs.umich.edu/courses/eecs470/tools/verilog_guidelines.pdf
for a short summary.

Well, we teach more or less the same rules as well, but there is always
at least one group per year who manages to come up with some nice and
interesting blocking/non-blocking race condition :)
Other than with testbenches I can't think of a time it has come up.
And even then, it requires effort. Of course students seem really
good at generating that effort.

The course you are talking about sounds very interesting by the way,
I wish I could have attended such a course as an undergraduate student.
Do you know roughly how much time students spend doing the projects in
this course?  
A lot. We assign the project with 8-9 weeks left and they can count on
200+ hours of work each. It's crazy, but we have 80-100 people take
it a year and it certainly isn't required (though for computer
engineers there aren't a lot of other options...) We've also gotten
very good at giving them starting points (in-order processor, *very*
basic I-cache and RS) and teaching them exactly the right things to be
able to tackle the problem with the tools we have. Plus we have people
(instructor, TA, staff member) who are good a debugging when things
are really crazy. But they spend 15+ hours just on the high level
design before they even start coding. It's really cool to watch.

Do they have to care about the efficiency of their
RTL code or do they only have to get it synthesizable?
Clock cycle matters, but is a second-order issue. The way we grade
things about 20% of the grade is for performance, and that is
basically measured by how long it takes the various testbenches to
run. Good architecture can get you there (lots of CPI) but clock
cycle obviously plays a big role too. And as memory latency is held
constant, going slow isn't _that_ bad. Generally 1 group out of 10
will not have synthesis working, 1 other will have a cycle time that
is 2-3x what it should be and one will be very low indeed for the
process used.

The real problem is that until most everything is built it can be hard
for them to judge clock-cycle. Individual parts may come in quite
well, but their might be (will be) a combinational path they didn't
think about. So they have to hunt and fix these in 2-10 days
depending on how fast they were at everything else.

Mark


> /Andreas
 
On Jan 28, 9:35 am, Brian Drummond <brian_drumm...@btconnect.com>
wrote:
On Tue, 27 Jan 2009 17:33:44 -0800 (PST), Mark Brehob <bre...@gmail.com
<clip>
I had a bunch of other questions, but of course I've forgotten (did my
coding over the weekend and I guess 48 hours ago is enough time to
forget).  I'm mostly enjoying it, but as you might expect, it's
bringing back Ada nightmares.  

Like having code that actually worked first time once you got it through
the compiler?
First of all, thanks for the comments above. They help me understand
the "VHDL way". Which is important if I'm going to teach it.

That said, I never had that "problem" Ada. I guess I'm lucky, but
type problems rarely burn me. Logic errors or syntax errors do, but
type checking doesn't help much there.

C/Verilog people should not
have to deal with strict type checking :).

It eats into their precious debugging time...
*laugh* that literally made me laugh out loud. Yeah, I understand
that viewpoint. Just doesn't match my experience for the most part.

Although thinking about it, I've had problems with C on Atmel
processors. But they were actual _bugs_ a real compiler with -Wall
would have caught. I will admit, the strong desire to save a few
bytes here and there on the small embedded processors can make you
dream of strict checking of sizes...

Again, thanks!
Mark
Tha
 

Welcome to EDABoard.com

Sponsor

Back
Top