Conditional signal assignment or process statement

D

devas

Hi Gurus,

What is your opinion for coding combinational logic (multiplexer) in
VHDL. Using a conditional signal assignment or using a process? What are
the pro's and con's for both?

I can imagine that for simulation performance a process is efficienter
as it will only be reached when one of the signals on the sens. list
changes. A con could be the danger of an incomplete sens. list.

I would like to know your opinion and what your are using.

Thanks,

Devas
 
B

backhus

Hi Gurus,

What is your opinion for coding combinational logic (multiplexer) in
VHDL. Using a conditional signal assignment or using a process? What are
the pro's and con's for both?

I can imagine that for simulation performance a process is efficienter
as it will only be reached when one of the signals on the sens. list
changes. A con could be the danger of an incomplete sens. list.

I would like to know your opinion and what your are using.

Thanks,

Devas

Hi Devas,
with the upcoming of VHDL-2008 and the
process(all)
feature, the differences in performance and danger of simulation
faults should be rendered to almost neglectable.
Also with VHDL-2008 the
when..else
and
with..select
constructs can be used inside processes.
So, even the coding style difference is mostly evened out.

What's left is merely a question of personally prefered coding style.

One might argue, that not all synthesis tools support this yet, but
time flies and before long this won't be a problem anymore.
---
My personal choice is to have as few concurrent code lines in my
architecture as possible, and put every functional part in processes.
Sometimes specific assignments to output ports are necessary, but
that's just one-liners.

Have a nice synthesis
Eilert
 
T

Tricky

Hi Gurus,

What is your opinion for coding combinational logic (multiplexer) in
VHDL. Using a conditional signal assignment or using a process? What are
the pro's and con's for both?

Theres not really a lot of difference. A signal assignment outside of
a formal process is really just another process, with the sensitivity
list set by the signals on the right hand side.

so this code:

output <= a when sel = '0' else b;

is the same as:

process(a, b, sel)
begin
if sel = '0' then
output <= a;
else
output <= b;
end if;
end process;
 
R

rickman

Theres not really a lot of difference. A signal assignment outside of
a formal process is really just another process, with the sensitivity
list set by the signals on the right hand side.

so this code:

output <= a when sel = '0' else b;

is the same as:

process(a, b, sel)
begin
  if sel = '0' then
    output <= a;
  else
    output <= b;
  end if;
end process;

I see one major difference. The process is eight lines of code and
the concurrent statement is only one. Which do you think is easier to
read and provides fewer opportunities for errors?

Rick
 
J

Jonathan Bromley

I see one major difference.  The process is eight lines of code and
the concurrent statement is only one.  Which do you think is easier to
read and provides fewer opportunities for errors?

In the interests of civil discussion I'll
temporarily pretend that this stance doesn't
make my blood boil.

Instead I'll politely point out that, on the
very rare occasions when I really want something
that simple as a standalone thing, then the
concurrent statement is indeed probably better.
Three-state I/O buffers are the best and
commonest example.

And I'll also politely point out that
decomposing designs into pieces small enough
to represent as concurrent statements makes
each piece trivially easy to understand, but
makes the whole design as comprehensible as
a broken-up jigsaw puzzle.

Taking a complicated thing and breaking it
into lots of simple pieces doesn't make it
simpler. It simply turns the complicated
thing into a pile of pieces.
 
K

KJ

Instead I'll politely point out that, on the
very rare occasions when I really want something
that simple as a standalone thing, then the
concurrent statement is indeed probably better.

Based on what devas posted, the 'standalone thing' is all that one can
guess that devas is interested in for the reasons that were listed.
Taking a complicated thing and breaking it
into lots of simple pieces doesn't make it
simpler.  It simply turns the complicated
thing into a pile of pieces.

I agree in principle...but in this case, the only context given by
devas in his posting was in the pros and cons of coding a mux as
either a conditional signal assignment or using a process. In this
case, there is no 'complicated thing' being broken into simpler
pieces.

Your comment though is valid, but should be directed to devas within
the context of 'hey, why are you spending time thinking about the
coding of a mux'? The opportunities to code a mux by itself are
relatively few and far between. The opportunities to describe logic
that also includes mux-like behavior are far more numerous and rarely
are enhanced by the ability to describe this behavior explicitly as a
standalone thing (whether as a process or concurrent statement).

But then again maybe devas is just getting started in design and/or
VHDL or perhaps his interest is not in designing something in VHDL but
is actually in simulator performance, or some theoretical language
aspect, something more abstract, who knows?

In any case, devas was already aware of the major drawback from the
standpoint of creating reliable/maintainable designs of the process
which is that of an incomplete sensitivity list (prior to VHDL-2008).
On the other hand, devas seems misinformed (or maybe needs to
experimentally try) about why he thinks the process approach would be
more efficient in simulation than the concurrent assignment.

Kevin Jennings
 
J

Jonathan Bromley

Based on what devas posted, the 'standalone thing' is all that one can
guess that devas is interested in for the reasons that were listed.

I apologize if I confused or misled the OP. My post
was responding to yet another clear description of the
position that states "bugs increase monotonically with
lines of code, therefore anything that locally reduces
the number of lines of code is good". This I regard as
such pernicious nonsense that I will unapologetically
seize on any opportunity to challenge it, especially
if expressed in a way that encourages the decomposition
of designs into absurdly small and meaningless pieces.
In this case, there is no 'complicated thing'
being broken into simpler pieces.

True. I carefully pointed out that this can happen, in some
very specific situations, and there the shorter description
is entirely appropriate.
Your comment though is valid, but should be directed to devas within
the context of 'hey, why are you spending time thinking about the
coding of a mux'?

It could have been, but wasn't; that was not my target.
The OP's question was reasonable, and evinced reasonable
answers; it was the added spin on those answers that
riled me.
 
A

Andy

For one simple, combinatorial function with one output, I prefer the
concurrent assignment.

Features that make me lean toward using a process include:

more than one output controlled similarly by the same inputs,
logic that feeds a register within the same architecture,
nested if-then logic,
existence of related logic that is already in a process

Since one or more of these features is often present in my projects, I
usually use processes with sequential statements, synchronous when
possible.

Extensive use of concurrent statements starts to look like coding a
netlist (and reads like one too), instead of coding a synthesizeable
behavior with sequential statements, which is usually easier to
understand.

Andy
 
M

Mike Treseler

What is your opinion for coding combinational logic (multiplexer) in
VHDL. Using a conditional signal assignment or using a process? What are
the pro's and con's for both?
I would like to know your opinion and what your are using.

Synthesis requires an entity.
Since each entity has code overhead,
I describe logic at a higher level for less overall code.

I describe the entity output ports only
in terms of input ports and local variables,
rather than muxes and flops.

For example in this stack design: http://bit.ly/fkbaqW
no muxes are described directly,
yet synthesis inferred several: http://bit.ly/g5Asyr


-- Mike Treseler
 
D

daniel.kho

For one simple, combinatorial function with one output, I prefer the
concurrent assignment.

Yes, for me as well. If a block (or sub-block) seems simple enough to
describe as a one-liner (or a few lines) of concurrent statements, go
for it. If my block/sub-block starts getting a bit more complex, I'll
start putting those concurrent statements within a process instead.

When it gets difficult to behaviourally describe your functionality
with just a few concurrent statements, and when you start breaking up
a concurrent statement to multiple smaller concurrent statements,
that's when you're beginning to change your behavioural design to a
structural one, i.e. one that doesn't describe the behaviour and
therefore is difficult to understand. When I could foresee that I'm
heading this (wrong) direction, I'll steer myself back to enclose
those statements in a process, and add whatever other functionality I
need.

Daniel Kho
 
R

rickman

In the interests of civil discussion I'll
temporarily pretend that this stance doesn't
make my blood boil.

Instead I'll politely point out that, on the
very rare occasions when I really want something
that simple as a standalone thing, then the
concurrent statement is indeed probably better.
Three-state I/O buffers are the best and
commonest example.

And I'll also politely point out that
decomposing designs into pieces small enough
to represent as concurrent statements makes
each piece trivially easy to understand, but
makes the whole design as comprehensible as
a broken-up jigsaw puzzle.

Taking a complicated thing and breaking it
into lots of simple pieces doesn't make it
simpler.  It simply turns the complicated
thing into a pile of pieces.

Ok Jonathan, take a deep breath. Now, tell me what you *really*
feel!

I think if you read my post again, you will see that all I am saying
is that the above code is much simpler written as one line of
concurrent code than eight lines of process. I'm not espousing a
philosophy or promoting anything about a standard practice. I'm just
saying that the two code examples do exactly the same thing and one is
*much* simpler than the other.

What exactly did you think was in my post that I am not aware of?

Rick
 
R

rickman

I apologize if I confused or misled the OP.  My post
was responding to yet another clear description of the
position that states "bugs increase monotonically with
lines of code, therefore anything that locally reduces
the number of lines of code is good".  This I regard as
such pernicious nonsense that I will unapologetically
seize on any opportunity to challenge it, especially
if expressed in a way that encourages the decomposition
of designs into absurdly small and meaningless pieces.


True.  I carefully pointed out that this can happen, in some
very specific situations, and there the shorter description
is entirely appropriate.


It could have been, but wasn't; that was not my target.
The OP's question was reasonable, and evinced reasonable
answers; it was the added spin on those answers that
riled me.

I should have read all the posts before I replied to your earlier
one. This tells me a bit more, but you are making claims without
supporting them. Can you tell me why you believe your position? So
far you have simply stated it.

Rick


M: An argument isn't just contradiction.
A: It can be.
M: No it can't. An argument is a connected series of statements
intended to establish a proposition.
A: No it isn't.
M: Yes it is! It's not just contradiction.
A: Look, if I argue with you, I must take up a contrary position.
M: Yes, but that's not just saying 'No it isn't.'
A: Yes it is!
M: No it isn't!
 
R

rickman

Yes, for me as well. If a block (or sub-block) seems simple enough to
describe as a one-liner (or a few lines) of concurrent statements, go
for it. If my block/sub-block starts getting a bit more complex, I'll
start putting those concurrent statements within a process instead.

When it gets difficult to behaviourally describe your functionality
with just a few concurrent statements, and when you start breaking up
a concurrent statement to multiple smaller concurrent statements,
that's when you're beginning to change your behavioural design to a
structural one, i.e. one that doesn't describe the behaviour and
therefore is difficult to understand. When I could foresee that I'm
heading this (wrong) direction, I'll steer myself back to enclose
those statements in a process, and add whatever other functionality I
need.

Daniel Kho

I don't have any grand rules for when I describe combinatorial logic
with a process, but it is seldom, mainly because I don't like
maintaining the sensitivity list. Mostly the logic I code is
included in sequential processes, but there are times when it doesn't
make sense from a decomposition point of view to include some of the
logic in the sequential process. Then I put it is concurrent
statements. A data path mux is a perfect example of that.

If the concurrent statements get too complex, I will use a process. I
did that for some code controlling a couple of status LEDs. The
concurrent logic was getting complex because of multiple modes
displaying different status. The muxing was rather complex and hard
to understand. In a process the IF statement structure was more
clear.

But for signal path logic it is often a series arrangement of
processing steps. Putting that in a process requires that some of the
outputs which feed into the logic for the next step be included in the
sensitivity list. I find this rather messy. Otherwise these
intermediate values need to be expressed with variables. But
variables don't show up in the waveform display, at least in
ActiveHDL. So I find variables harder to use in debug and only use
them when there is a clear advantage, like in test benches. I've
never had any real issues expressing a linear flow in four concurrent
statements rather than four sequential statements inside the several
lines of code to setup a process.

Rick
 
A

Andy

I think there are two arguments in play here: how to describe
combinatorial logic, and whether it needs to be described
combinatorially at all.

I very rarely need to describe combinatorial logic outside the context
of a synchronous process, so that sensitivity lists and latches are
rarely a problem.

I usually debug source code, not waveforms, so variables not showing
up in waveforms would not be a big issue for me, especially compared
to the advantages of using variables.

Andy
 
R

rickman

I think there are two arguments in play here: how to describe
combinatorial logic, and whether it needs to be described
combinatorially at all.

I very rarely need to describe combinatorial logic outside the context
of a synchronous process, so that sensitivity lists and latches are
rarely a problem.

I usually debug source code, not waveforms, so variables not showing
up in waveforms would not be a big issue for me, especially compared
to the advantages of using variables.

Andy

Wow, we work so differently. The big difference between HDL and
software that I love is the fact that I can access any point in the
design with a simulation scope probe to see just what is happening.
The few times I have used the code debugging tools I find them to be
fairly painful to get to the point of the issue. Maybe I'm just not
experienced enough with them.

Rick
 
K

KJ

Wow, we work so differently.  The big difference between HDL and
software that I love is the fact that I can access any point in the
design with a simulation scope probe to see just what is happening.

I agree. Debugging the source code implies that you have identified
an incorrect behavior (presumably via an assertion or observation of
some other 'incorrect' output) AND you have restarted the simulation
to get it up near the suspected time of the failure so you can step
through or otherwise 'debug the source code'. Not only is restarting
the sim wasted time (although maybe it's not a 'lot' of time depending
on the particular design) but if you guess incorrectly about the time
that the root cause of the failure occurred you may have to restart
the sim again...all because there is no equivalent to 'log -r /*' that
captures the history of all variables in a design.

Debugging with the waveform allows one to easily plop down the entire
history of any signal anywhere in the entire design and testbench.
The cost is a single command ('log -r /*') and some extra wall clock
time and disk space to store the data to disk. Whether or not that
extra bit of wall clock time was 'well spent' or not can be user
dependent, I've found it to be 'worth it'.

Which is 'best', is most likely a very user dependent question.
Either way can work. To be efficient at using one method or the other
may take time, but in the end I would guess that one can be equally
productive either way. If there is a compelling reason for one way
versus the other, I haven't heard about it.

As a side note, to work around the issue of wanting to use sequential
statements (because it more readily conveys the design intent) but
need an unclocked signal but don't want to bother with sensitivity
lists, there is always the ability to define a function or a procedure
and instantiate call that function/procedure out just like a
concurrent assignment. You get all of the benefits of sequential
statement syntax along with proper checking of inputs (no missing
signals in the sensitivity list) and a combinatorial output.

Kevin Jennings
 
A

Andy

I use waveforms occasionally to get a look at an interface (external
or internal) but those are always signals anyway (ports). I use
assertions in both the RTL and the testbench which stop the simulation
when something goes wrong, then I can observe the variables and
signals I need, and insert a few breakpoints and monitors if
necessary. Given the cyclical nature of most hardware designs, it is
often not necessary to "back up" to see what happened, just catch it
again on the next time around. Backing up can be a pain though if I
have to. Most of the RTL assertions get put in during design or unit
testing, so they are already there by the time I have a larger system
simulation that would be time consuming to restart (and that would be
severely slowed down by dumping every signal to a file "just in
case".) I'm a big proponent of self-checking testbenches, and they
don't use waveforms either.

Most of us use methods we are most comfortable with, and using
waveforms is very similar to the typical test equipment in the lab
that we learned on. I started using the source code debugger after
working with the SW driver guys to debug HW/SW issues in the lab. I
had also taken a couple of Ada courses to sharpen my VHDL, and was
exposed to the techniques there. Then I started trying some of those
techniques in my VHDL simulations, and it worked well for me.

But what works well for me may not work for others. Having multiple
examples to accomplish the same thing allows users to find what works
best for them individually.

Andy
 
J

Jonathan Bromley

you are making claims without
supporting them. Can you tell me why you believe your position? So
far you have simply stated it.

OK, let's keep separate things separate.

The bit that got my dander up was your implied, but
clear, statement that fewer lines of code makes for
fewer bugs. Others have stated this much more
starkly than you did. I rather strongly disagree
with it. Whilst it is evidently true that adding
more code to any project will of course increase
the number of bugs, since code is rarely bug-free,
that in itself provides not a shred of evidence
that the implementation of a given set of
functionality will have fewer bugs if implemented
using coding techniques that result in fewer
lines of code. My own experience suggests that
very compact, dense coding styles increase the
risk of subtle hidden bugs and oversights that
are very hard to track down. A more literate
coding style generally leads to more easily
debugged code. Clearly you can go too far
the other way - verbosity for its own
sake is unlikely to help, and in particular
it is never a good idea to have redundancy
in code. But the basic argument that leads
to the mantra "code it in fewer characters
and you'll get fewer bugs" is groundless, and
I'm convinced it has led to misguided choices
in the design and application of HDLs.

More directly related to what you posted
is the question of the most desirable
granularity to which you should decompose
a problem. I think I was clear enough in
my discomfort there. You can always make
each piece of a design trivially easy to
understand, simply by decomposing it into
pieces that are small enough. Is a shift
register small enough for you? A flop?
A mux? A transistor? The snag is, this
simplification comes at an unacceptable
price: it hides the real functionality
of the design or design fragment. As
others have indicated, it's probably
unhelpful to lay down rigid guidelines
here. I can suggest some touchstones:
is the piece of code amenable to testing
that will show whether it does what you
need it to do, without wasting effort by
testing some function such as a mux that's
already well-known to work? Can I write
a few lines of comment in the code that
describe succinctly what it does, and
why it's there? Can I relate this fragment
to any kind of specification or requirement?
The reality, though, is that the optimum
choices depend on the people doing the
work, the nature of the problem, the
customer's demands and a whole pile of
other things.

Despite all this fence-sitting, there is
something that seems obvious to me.
Breaking a design into excessively small
pieces (transistors!!) clearly obscures
its functionality. Leaving a design in
huge monolithic chunks (an entire FPGA
in one VHDL process!!) is clearly hopeless
too; no-one could possibly understand it.
Somewhere in the middle there is an
optimum - not ideal, but certainly better
than either end of that spectrum. Merely
saying "simpler is better" is inadequate.

For me, pieces of design small enough to
write as a single concurrent statement are
almost never big enough to give me useful
clues about how they contribute to the
overall functionality (unless you put a
function call in the expression).

Sorry about the lengthy ramblings. You
did ask for a justification :)
 
T

Tricky

I use waveforms occasionally to get a look at an interface (external
or internal) but those are always signals anyway (ports). I use
assertions in both the RTL and the testbench which stop the simulation
when something goes wrong, then I can observe the variables and
signals I need, and insert a few breakpoints and monitors if
necessary. Given the cyclical nature of most hardware designs, it is
often not necessary to "back up" to see what happened, just catch it
again on the next time around. Backing up can be a pain though if I
have to. Most of the RTL assertions get put in during design or unit
testing, so they are already there by the time I have a larger system
simulation that would be time consuming to restart (and that would be
severely slowed down by dumping every signal to a file "just in
case".) I'm a big proponent of self-checking testbenches, and they
don't use waveforms either.

Most of us use methods we are most comfortable with, and using
waveforms is very similar to the typical test equipment in the lab
that we learned on. I started using the source code debugger after
working with the SW driver guys to debug HW/SW issues in the lab. I
had also taken a couple of Ada courses to sharpen my VHDL, and was
exposed to the techniques there. Then I started trying some of those
techniques in my VHDL simulations, and it worked well for me.

But what works well for me may not work for others. Having multiple
examples to accomplish the same thing allows users to find what works
best for them individually.

Andy

I can see where you're coming from andy. Ideally, your final test
should be a black box test, with a self checking testbench. It worries
me when I see designers stare at waveforms all day and using this for
their verification. They should be using output data as the test - no
waveforms needed. Working in video I use bitmaps for input and output
data. Its so much easier looking at a whole picture than looking at a
stream of pixels. Often this output picture gives you a clue as to
whats wrong - its normally very obviously when something has gone
wrong doing this. Then I can get in amongst the waveform for more
specific debugging, using the clues from the output.
 
M

Martin Thompson

Andy said:
I use waveforms occasionally to get a look at an interface (external
or internal) but those are always signals anyway (ports). I use
assertions in both the RTL and the testbench which stop the simulation
when something goes wrong, then I can observe the variables and
signals I need, and insert a few breakpoints and monitors if
necessary.

That's much the same as the methods I use (and even the odd printf^H^H^H^H^H
report statement :)

I'm sure Aldec can put variables in the wave window - it may be that (as with
Modelsim) you have to do it before the sim for it to log them. At the subblock
level, adding a few variables and restarting is not usually a killer - especially
when you have asserts already in to stop the simulation as soon as things go
wrong.

(The variables I want to see are usually state variables - it'd be great
to be able to do "log -r *state" on variables :)
Most of us use methods we are most comfortable with, and using
waveforms is very similar to the typical test equipment in the lab
that we learned on. I started using the source code debugger after
working with the SW driver guys to debug HW/SW issues in the lab. I
had also taken a couple of Ada courses to sharpen my VHDL, and was
exposed to the techniques there. Then I started trying some of those
techniques in my VHDL simulations, and it worked well for me.

And there are times when I'm writing embedded software that I'd really like a
waveform trace of my C variables :)

Cheers,
Martin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top