vhdl questions from a verilog person

On Wed, 28 Jan 2009 16:43:45 -0800 (PST), Mark Brehob wrote:

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.
First, let me be 100% honest: Maybe you *don't* want it.
Some people think this is unhelpful, too far from hardware,
too confusing, too error-prone... you name it. But for me,
and for several other designers I respect, it's an important
technique.

In a clocked process, there are at least three reasons
I can think of for having local variables with immediate-
update behaviour.

(1) Pre-calculating a subexpression
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

always @(posedge clock)
// Labelled begin-end so we can declare
// local variables in it
begin : HasSubexpression
reg Enable;
// Precalculate Enable based on other inputs.
// This has the effect of a piece of combinational
// logic computing Enable from a,b,c,d.
if (a)
Enable = 0;
else if (b ^ c)
Enable = 1;
else
Enable = d;

// Use Enable in various ways:
if (Enable)
Count <= Count + 1;
case (Enable? u[1:0] : u[3:2])
0: ...
1: ...
2: ...
default: ...
endcase
end


(2) Hiding local functionality that
you don't want to expose elsewhere
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In fairness, this one really applies only to VHDL
because in VHDL you can't have local signals in a
process, but only local variables. However, it's
easy to mimic in Verilog too.

always @(posedge clock) begin : RiseDetector
reg Delayed_D;
Rise <= D & ~Delayed_D;
Delayed_D = D;
end

Note here that I've used blocking assignment to Delayed_D,
and consequently the assignment must happen AFTER any use
of the local because in the previous expression I want
the value of Delayed_D that was saved on the previous clock.
In Verilog, but not in VHDL, I could have used nonblocking
assignment to the local and then it would not have
mattered in which order I did the assignments.


(3) Getting a sneak preview of the next-state
value of a state variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This happens to be my personal favoured style
for writing state machines, but of course not
everyone agrees. The reasoning goes like this:
- In a state machine, it is probably *only* the
state machine itself that actually cares about
the state variable. So let's hide the state
variable inside its process.
- To get outputs that are a pure function of
the state, but nevertheless are themselves
registered, I need to update those outputs
based on the next-state value of the state
variable so that they update at the same time
as the state changes.

Here's how it works:

always @(posedge clock) begin: FSM
reg [whatever:0] state;
// state-name constants
localparam IDLE = 0, RUN = 1, HOLD = 2;
// Step 1: Default values for the outputs
running <= 0;
holding <= 0;
// Step 2: State transition logic (NO outputs):
// compute next-state as a function of inputs
case (state)
IDLE : if (start)
state = RUN;
RUN : if (stop)
state = HOLD;
HOLD : if (release)
state = IDLE;
default : state = IDLE;
endcase
// Step 3: Now the local variable "state" contains the
// NEXT-state value; we can use that to determine
// values for registered outputs
case (state)
RUN: running <= 1;
HOLD: holding <= 1;
endcase
end

There are many variations on this theme, and - to repeat -
not everyone agrees that this is a good idea. But it
works for me.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

OK, so where does that leave the "don't mix blocking and
nonblocking" rule? Here's the REAL rule:

In a clocked process:
1.ALWAYS use nonblocking assignment to any variable
whose value will be used outside the process;
2.NEVER mix blocking and nonblocking assignment
to a single variable;
3.any variable assigned by blocking assignment must
be declared locally in the process's begin-end, so
that it can't be referenced from outside (at least,
not for synthesis);
4.be aware of the immediate-update semantics of
blocking assignment. This means...
- if you read such a variable before assigning
to it, you get the value that it was given
on the PREVIOUS clock - held in a flip-flop;
- if you read such a variable after assigning
to it, you get the combinational value that
you just assigned to it.

In a VHDL clocked process, these rules 1,2,3 are
effectively enforced for you by the language;
variables are local to a process and update immediately
by := variable assignment; signals are declared outside
a process and have delayed update by <= signal assignment.
In Verilog you must enforce the rules for yourself.
Rule 1 is essential to avoid simulation races and
consequent mismatch with synthesis. Rule 2 is
essential to maintain your sanity, but is also a
requirement for all synthesis tools I know of.
Rule 3 helps to align Verilog and VHDL coding
styles, and makes it much easier to obey rule 1.

You will also find some people advocating the extensive
use of process-local variables to enable a very
software-like description of a design's behaviour,
with blocking assignment to local variables everywhere.
Internal result values can then be copied on to output
signals by nonblocking assignment when their value is
finally established. This approach gives your synth
tool LOTS of work to do, but hey, that's what it's for.
--
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-29, Mark Brehob <brehob@gmail.com> wrote:
But it is _really_ helpful to understand why good people like to
"break our rules". Otherwise I just know people do, but can't give
examples to the students.
Another example for your consideration. Unrolling a CRC for Ethernet.
You could do this without variables by unrolling it manually, but why
do work yourself when the synthesis tool can do it for you?

/Andreas


-- (This could be done in a neater way using ranges)
process (clk)
variable crc_tmp : std_logic_vector(31 downto 0);
variable fb : std_logic;
begin -- process
if clk'event and clk = '1' then -- rising clock edge
if enable = '1' then
crc_tmp := crc;

-- Unrolled to process a nibble at a time.
for i in 0 to 3 loop
fb := crc_tmp(31);
crc_tmp(31) := crc_tmp(30);
crc_tmp(30) := crc_tmp(29);
crc_tmp(29) := crc_tmp(28);
crc_tmp(28) := crc_tmp(27);
crc_tmp(27) := crc_tmp(26);
crc_tmp(26) := d(i) xor fb xor crc_tmp(25); -- x^26
crc_tmp(25) := crc_tmp(24);
crc_tmp(24) := crc_tmp(23);
crc_tmp(23) := d(i) xor fb xor crc_tmp(22); -- x^23
crc_tmp(22) := d(i) xor fb xor crc_tmp(21); -- x^22
crc_tmp(21) := crc_tmp(20);
crc_tmp(20) := crc_tmp(19);
crc_tmp(19) := crc_tmp(18);
crc_tmp(18) := crc_tmp(17);
crc_tmp(17) := crc_tmp(16);
crc_tmp(16) := d(i) xor fb xor crc_tmp(15); -- x^16
crc_tmp(15) := crc_tmp(14);
crc_tmp(14) := crc_tmp(13);
crc_tmp(13) := crc_tmp(12);
crc_tmp(12) := d(i) xor fb xor crc_tmp(11); -- x^12
crc_tmp(11) := d(i) xor fb xor crc_tmp(10); -- x^11
crc_tmp(10) := d(i) xor fb xor crc_tmp(9); -- x^10
crc_tmp(9) := crc_tmp(8);
crc_tmp(8) := d(i) xor fb xor crc_tmp(7); -- x^8
crc_tmp(7) := d(i) xor fb xor crc_tmp(6); -- x^7
crc_tmp(6) := crc_tmp(5);
crc_tmp(5) := d(i) xor fb xor crc_tmp(4); -- x^5
crc_tmp(4) := d(i) xor fb xor crc_tmp(3); -- x^4
crc_tmp(3) := crc_tmp(2);
crc_tmp(2) := d(i) xor fb xor crc_tmp(1); -- x^2
crc_tmp(1) := d(i) xor fb xor crc_tmp(0); -- x^1
crc_tmp(0) := d(i) xor fb; -- 1

crc <= crc_tmp;


elsif clear = '1' then
crc <= (others => '1');
end if;
end if;
end process;
 
On Wed, 28 Jan 2009 17:09:32 -0800 (PST), Mark Brehob <brehob@gmail.com>
wrote:

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

bringing back Ada nightmares.  

Like having code that actually worked first time once you got it through
the compiler?

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.
There is truth in that, though type errors go beyond confusing boolean
and integer. Writing a loop that iterates off the end of an array is
also a type error; and I've certainly done THAT in my C code!

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.
Fair enough. I was brought up on Algol-W, then Modula-2. Only dealt with
C for about 20 years and still freely admit I don't quite get it - it
seems deliberately designed for fragility in so many odd ways.

C++ now they added namespaces (after a fashion) and stuff to it, is a
little better. But it undermines any arguments against Ada on the
grounds of size or complexity!

So I'm playing with Ada (2005, not 83) for the first time, and actually
liking it.

Not that my Ada or VHDL code is bug-free or anything like it! But it is
pretty clear to me, that the support I get from them allows me to do a
better job, faster, than I can otherwise.

- Brian
 
In a clocked process:
1.ALWAYS use nonblocking assignment to any variable
  whose value will be used outside the process;
2.NEVER mix blocking and nonblocking assignment
  to a single variable;
3.any variable assigned by blocking assignment must
  be declared locally in the process's begin-end, so
  that it can't be referenced from outside (at least,
  not for synthesis);
4.be aware of the immediate-update semantics of
  blocking assignment.  This means...
  - if you read such a variable before assigning
    to it, you get the value that it was given
    on the PREVIOUS clock - held in a flip-flop;
  - if you read such a variable after assigning
    to it, you get the combinational value that
    you just assigned to it.

This is the best blocking/non-blocking guideline I've seen. Thanks
for sharing.

George K.
 
Jonathan,
(3) Getting a sneak preview of the next-state
value of a state variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This happens to be my personal favoured style
for writing state machines, but of course not
everyone agrees. The reasoning goes like this:
- In a state machine, it is probably *only* the
state machine itself that actually cares about
the state variable. So let's hide the state
variable inside its process.
- To get outputs that are a pure function of
the state, but nevertheless are themselves
registered, I need to update those outputs
based on the next-state value of the state
variable so that they update at the same time
as the state changes.

Here's how it works:

always @(posedge clock) begin: FSM
reg [whatever:0] state;
// state-name constants
localparam IDLE = 0, RUN = 1, HOLD = 2;
// Step 1: Default values for the outputs
running <= 0;
holding <= 0;
// Step 2: State transition logic (NO outputs):
// compute next-state as a function of inputs
case (state)
IDLE : if (start)
state = RUN;
RUN : if (stop)
state = HOLD;
HOLD : if (release)
state = IDLE;
default : state = IDLE;
endcase
// Step 3: Now the local variable "state" contains the
// NEXT-state value; we can use that to determine
// values for registered outputs
case (state)
RUN: running <= 1;
HOLD: holding <= 1;
endcase
end

There are many variations on this theme, and - to repeat -
not everyone agrees that this is a good idea. But it
works for me.

The necessity for this is why I prefer 2 process statemachines
in VHDL and deal with getting the sensitivity list right in
the combinational logic process. I look forward to vendors
implementing process(all).

What I note about this methodology in general is that you
have one statemachine with two bubble diagrams - one for
decoding the state and one for creating the output logic.

Of course every methodology has its other considerations
that make it work well for the people using it. For example,
with the 2 process statemachine, if you give every output a
default value, you no longer have to worry about latches.

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.
 
On Thu, 29 Jan 2009 14:25:36 +0000 (UTC), Andreas Ehliar wrote:

Another example for your consideration. Unrolling a CRC for Ethernet.
You could do this without variables by unrolling it manually, but why
do work yourself when the synthesis tool can do it for you?
Nice example, thanks.

Of course, any example of this level of complexity
immediately sets one to thinking about functions and
procedures - but that's just another way of getting
local variables in a process, isn't 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 Jan 29, 5:59 am, Jonathan Bromley <jonathan.brom...@MYCOMPANY.com>
wrote:
<clip>
--
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.
Thanks! For our courses, we try to avoid things like this and tell
them that while good people do code that way, our way is safer. When
they get more expert, they can be more brave.

But it is _really_ helpful to understand why good people like to
"break our rules". Otherwise I just know people do, but can't give
examples to the students.

Mark

Mark
 
Jim,

congratulations on the publication of 1076-2008!!!!

On Thu, 29 Jan 2009 09:38:33 -0800, Jim Lewis wrote:

[me]
(3) Getting a sneak preview of the next-state
value of a state variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This happens to be my personal favoured style
for writing state machines, but of course not
everyone agrees.
[snip]
What I note about this methodology in general is that you
have one statemachine with two bubble diagrams - one for
decoding the state and one for creating the output logic.
I beg to differ. The whole point is that it allows you
to take a Moore-style (outputs are a pure function of state)
bubble diagram and mindlessly map it to a registered-Mealy
implementation that's functionally identical; it's just
that you do the state transitions and the output calculations
in two steps. Both steps are derived from the same, standard
Moore-style bubble diagram. The number of lines of code is
invariably no more than for a 2-process implementation, and
often less because there is no explicit next-state signal.
It also provides some interesting hooks for unconventional
behaviours that are hard to describe on a bubble chart,
such as outputs that hang over for one clock after you've
left the state in which they were set - I've found this
to be useful surprisingly often.

I completely agree that if you try to do Moore outputs
using a conventional single-process style then you are
forced to rework all your output assignments so that they
happen on entry to a state rather than when you're in a
state, and that is unacceptably painful and error-prone.

Of course every methodology has its other considerations
that make it work well for the people using it.
Sure. I long ago gave up being dogmatic about this. [*]

[*] That's untrue. I dogmatically think that three-process
state machines are completely stupid :)
--
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.
 
Andy,
Interesting references to Ada; back in the 90's I took a couple of ada
training classes so that I could learn some "software" techniqes for
vhdl that are not generally taught in vhdl classes (at least the ones
I had taken). I learned general stuff about using types/subtypes
effectively, using scope to control access, applications of packages,
deferred constants (still not synthesizable?!), procedures/functions,
etc. The type-based genericity of ada was really nice; completely
different from what vhdl generics offer.
VHDL-2008 allows both type and subprograms to be generics.
It also adds generics to packages and subprograms. Hopefully
this gets us closer to the capability that you liked.

I probably need that Ada training class as I don't know how
similar what we have is to Ada.

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.
 
Jonathan,
(3) Getting a sneak preview of the next-state
value of a state variable
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This happens to be my personal favoured style
for writing state machines, but of course not
everyone agrees.
[snip]
[jim] What I note about this methodology in general is that you
have one statemachine with two bubble diagrams - one for
decoding the state and one for creating the output logic.

I beg to differ. The whole point is that it allows you
to take a Moore-style (outputs are a pure function of state)
bubble diagram and mindlessly map it to a registered-Mealy
implementation that's functionally identical; it's just
that you do the state transitions and the output calculations
in two steps. Both steps are derived from the same, standard
Moore-style bubble diagram.
For me, the bubble diagram in the specification is intentionally
terse and the code is the implementation specification. So I
really like collecting both in the same case statement.
I visualize this case statement as the bubble diagram. So
adding another one, I see two. Of course for simple things
it is not big deal.

How do you handle the rare case where you need a mealy
output unregistered? I have had some that go to the
load enable input of a datapath register, and hence,
its timing path terminates there. It seems like your
choices would be:
1) Eat a clock cycle of latency
2) Move data path into statemachine
3) Write code outside of statemachine

Most designs can't accept 1. I don't like 2. 3 will be
messy, especially with the state variable implemented as
a variable.

The number of lines of code is
invariably no more than for a 2-process implementation, and
often less because there is no explicit next-state signal.
You mean the following default assignment before a case statement
adds too many lines :)
NextState <= CurrentState ; -- Default value

Honestly though, I am more concerned about readability than line
count. Sometimes a few more lines may make something more
readable and sometimes it makes it less readable. VHDL is just
a method to capture design intent. It does not take me that long
to type in a design once I have a visual of what I want to implement.

It also provides some interesting hooks for unconventional
behaviours that are hard to describe on a bubble chart,
such as outputs that hang over for one clock after you've
left the state in which they were set - I've found this
to be useful surprisingly often.
By setting it using the present state rather than using the
next state?

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.
 
Interesting references to Ada; back in the 90's I took a couple of ada
training classes so that I could learn some "software" techniqes for
vhdl that are not generally taught in vhdl classes (at least the ones
I had taken). I learned general stuff about using types/subtypes
effectively, using scope to control access, applications of packages,
deferred constants (still not synthesizable?!), procedures/functions,
etc. The type-based genericity of ada was really nice; completely
different from what vhdl generics offer.

Andy
 
I was fine with two process (combinatorial & clocked) styles, until I
had to infer clock enabled registers; so much for the simple
functional boundary between logic and registers.

Jonathan's "two-bubble" state machine example is one I do not
personally use. I use a single clocked process with variables, and any
outputs that need to be "on" in a given state are assigned at every
entrance to that state. Sometimes a little more coding, but not
usually. One tends to modify their approach to state machine design to
suit their favorite coding style anyway.

Andy
 
Andy wrote:
deferred constants (still not synthesizable?!), procedures/functions,
Synplicity has handled deferred constants for years. I agree it's lame
that XST does not.

-Jeff
 
Mark Brehob wrote:
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.
Presumably they have also done some programming in a "normal"
programming language. So they know variables already. Nothing new to
teach here, except bizarre Verilog terminology ("blocking assignments").
Between variables and signals, variables are the easy stuff!

So it's likely that your students will want to use the things they
already know for their modeling: variable semantics, for loops,
while loops, ... and for good reason. Teaching that they shouldn't is
artificial and confusing.

For modelling (e.g. test benches), the only thing they need to know is
that variables shouldn't be used for communication. For synthesis,
unfortunately, they will need to know about the restrictions. But not
using variable semantics is not part of that, and never was. Actually
it's the best part of RTL synthesis, the part that at least raises
the abstraction level a little bit above schematic entry.

Jan

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Python as a hardware description language:
http://www.myhdl.org
 
On Jan 28, 6:58 pm, Mark Brehob <bre...@gmail.com> wrote:
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.  
I assume you are talking about simulated time (i.e. simulated clock
cycles), not wall time running the simulation? Do the students get to
optimize the clock speed?

While RTL coding style does not have a direct impact on simulated time
performance, it does impact wall time spent in simulation. Faster
simulations (wall time) yield more time for debugging, "what if"
evaluations, etc., which then can improve simulated time performance.

Single process coding styles simulate faster than dual process
(combinatorial & clocked) styles. Most modern simulators "merge"
multiple processes that share the same sensitivity list, saving
overhead. Single process coding styles maximize this optimization,
since all the processes are sensitive to the same clock and async
reset signals. Combinatorial processes rarely share complete
sensitivity lists, so there is little optimization.

Integer types simulate MUCH faster than slv/signed/unsigned. Use
multiply/divide for shifting, divide/mod for slicing, and multiply/add
for concatenation. The synthesis tool will reduce it down to the
shifts & masks just fine. If their any good at writing low level SW,
they'll be right at home anyway.

Variables are slightly faster than signals that are used only locally,
but not by much with a good simulator.

Andy
 
On Thu, 29 Jan 2009 14:25:36 +0000 (UTC), Andreas Ehliar wrote:

Another example for your consideration. Unrolling a CRC for Ethernet.
You could do this without variables by unrolling it manually, but why
do work yourself when the synthesis tool can do it for you?
Jonathan Bromley wrote:
Nice example, thanks.

Of course, any example of this level of complexity
immediately sets one to thinking about functions and
procedures
Me too.
But that's exactly where the hardware guys head for the exits.
I think Andreas' version might make a nice
intro comment for the function below.

-- Mike Treseler

--________________
-- Base serial shifter, all of the other crc_shifts end up here
-- This gets called n times for the parallel versions above
function crc_shift
(
data : in std_ulogic; -- input bit
crc : in unsigned; -- crc starting value
crc_type : in crc_t
)
return unsigned is
variable crc_v : unsigned(crc'range); -- CRC value
constant reg_len : natural :=
crc_table(crc_type).crc_len; -- look up length
subtype crc_vec is unsigned(reg_len-1 downto 0);
constant mask : crc_vec :=
crc_table(crc_type).poly_vec(crc_vec'range);
begin
crc_v := crc sll 1; -- shift it
if (crc(crc'left) xor data) = '1' then -- maybe invert mask bits
crc_v := crc_v xor mask;
end if;
return unsigned(crc_v); -- whole register value each shift
end function crc_shift;
--________________
 
Jim Lewis wrote:

I probably need that Ada training class as I don't know how
similar what we have is to Ada.
see chapter 30 here:
http://www.infres.enst.fr/~pautet/Ada95/a95list.htm

-- Mike Treseler
 
On Jan 28, 6:41 pm, Mark Brehob <bre...@gmail.com> wrote:
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.
From your verilog guidelines:

8. When modeling sequential logic, use nonblocking assignments.
9. When modeling combinational logic with an always block, use
blocking assignments.
10. Do not mix blocking and nonblocking assignments in the same always
block.

These, taken together, prohibit a single process style. They are good
advice to avoid problems in verilog. They do not avoid any problems in
vhdl.

14. Make sure that all paths through a combinatorial always block
assign all variables.

This is a moot point with single process style. You cannot get a latch
from a clocked process.

2. Make your squential block as simple as possible. They shouldn’t
have much control flow.
12. while and for don’t work like you think, make sure that you
actually should be using them!

These two seem related. The most common reason users have problems
with while/for loops has to do with non-blocking assignments not
updating for each loop iteration, rendering combinatorial iteration
difficult. If you use blocking assignments, they work just like you'd
think. There remain synthesizable restrictions on them, but most of it
has to do with the synthesis tool needing to unroll the loops, which
means the iteration bounds need to be static.

Consider the following non-blocking (vhdl signal) assignment
statements:

if rising_edge(clk) then
a <= input1;
b <= a;
c <= b;
end if;

They'd have exactly the same behavior, regardless of which order they
are written in.

But if I do something like:

if rising_edge(clk) then
a <= input1;
b <= a;
c <= b;
a <= input2;
end if;

Suddenly the relative order of the first and last assignments matters
a lot! But their order relative to the middle assignments still
doesn't matter. Confusing? Thus it is with the "pseudo-sequential"
behavior of non-blocking assignments in sequential contexts.

Why not write the code such that the order is uniformly important?
Given that your students have only limited experience with verilog, I
bet they have much more experience with programming languages. Why not
use the order that every other programming language uses: pure
sequential execution. This also provides for a cleaner separation
between sequential and concurrent contexts: statements are
(completely) sequential with each other, processes are concurrent with
each other.

Re-writing the second example for equivalent functionality, with
blocking assignments (vhdl variables):

if rising_edge(clk) then
c := b;
b := a;
a := input1;
a := input2;
end if;

Andy
 
On Jan 29, 2:29 pm, Jeff Cunningham <j...@sover.net> wrote:
Andy wrote:
deferred constants (still not synthesizable?!), procedures/functions,

Synplicity has handled deferred constants for years. I agree it's lame
that XST does not.

-Jeff
The last time I checked, Synplicity handled deferred constants just
like regular ones. You had to recompile the package body and the
package itself (and everything that referenced it) to promote the new
value. Deferred constants in simulation only require the package body
to be recompiled, and then nothing else.

On the other hand, with direct entity instantiation, I get a lot more
recompilations than I used to anyway.

BTW, Mark, be sure to let your students know about direct entity
instantiations! It completely avoids component declarations and
configurations. Much simpler and easier in the vast majority of
applications.

Andy
 
Andy wrote:
On Jan 29, 2:29 pm, Jeff Cunningham <j...@sover.net> wrote:
Andy wrote:
deferred constants (still not synthesizable?!), procedures/functions,
Synplicity has handled deferred constants for years. I agree it's lame
that XST does not.

-Jeff

The last time I checked, Synplicity handled deferred constants just
like regular ones. You had to recompile the package body and the
package itself (and everything that referenced it) to promote the new
value. Deferred constants in simulation only require the package body
to be recompiled, and then nothing else.

On the other hand, with direct entity instantiation, I get a lot more
recompilations than I used to anyway.
I see your point. At least Synplicity doesn't abort with a fatal error
with a deferred constant like XST does (or did last time I checked).

-Jeff
 

Welcome to EDABoard.com

Sponsor

Back
Top