Why Doesn't VHDL Have a Wildcard Sensitivity List?

E

evilkidder

Why are we going over the same problems again and again rather than
producing a new language?

I've just snipped a massive rant about VHDL and Verilog I was about to
post ... rather I wonder if anyone feels the same way, and if so what
they think would improve things. Or indeed if they don't need
improving.

FWIW my view is hardware is just a cyclic graph and if you have good
enough tools to manipulate that graph you don't need HDL's.

-Andy
 
J

Jan Decaluwe

Why are we going over the same problems again and again rather than
producing a new language?

At the heart of the matter, there is fundamental disagreement about
where the problems are.
I've just snipped a massive rant about VHDL and Verilog I was about to
post ...

Admirable example. Usually, I'm not very impressed with HDL rants.
More often than not, they merely illustrate the ranter's lack
of knowledge and experience.

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Python as a HDL: http://www.myhdl.org
VHDL development, the modern way: http://www.sigasi.com
Analog design automation: http://www.mephisto-da.com
World-class digital design: http://www.easics.com
 
R

rickman

You said: "I believe the tools will give you warnings about this"

IME, this is not a true statement.


I'm afraid I don't understand what you are talking about. The context
is lost and you are quoting me from somewhere other than the line of
messages. So I have no way of knowing what "this" refers to.

My original post was:
The title is self explanatory. When found that Verilog lets you use a
* in the sensitivity list of a combinatorial process. Why doesn't
VHDL have that? There doesn't seem to be a down side that I can think
of. Didn't they just finalize changes to VHDL in 2008? Isn't seven
years enough time to pick up on a useful feature like this?

Walter replied to that and you replied to Walter, which is all quoted
above.

Please explain how using "all" as a wildcard in the sensitivity list
would hide mistakes...

Rick
 
R

rickman

Consider using a function (for one output, or a procedure for multiple
outputs) instead.  Then the only extra baggage is that of
instantianting the function/procedure call.  The code you would've
written in the process simply moves to the function/procedure.  If you
forget some input, the compiler complains.

KJ

Are you sure about that? If you use a function/procedure in a process
and don't include one of the inputs to that function/procedure in the
sensitivity list, the compiler complains? How is this reported?

Rick
 
R

rickman

It's not clear to me that the simulator will complain about an
incomplete sensitivity list. It should just blithely use the
list it's given. It's the synthesizer that pops up the warnings
about not matching simulation when your list is not complete.
For those who do most of their design work with simulation and
then try to pop off a synthesis at the end of "getting it right"
in simulation, this is a bit late to find out that your design
will not do what you described to the simulator. In this
respect the "all" keyword actually helps prevent problems.
A major issue I have with only seeing a warning during
synthesis and not simulation, is that the synthesis process
is usually rife with warnings that can be safely ignored.
This means I'm more likely to miss the useful ones, like
"incomplete sensitivity list" if I don't also get the
same warning during simulation, where generally speaking
all warnings should be addressed.

My 2 cents,
Gabor

I find that both tools throw many bbwarnings on my first pass of the
code. Although the synthesis tool warns me of things like carry chain
outputs that are not used anywhere in the code... duh, I didn't add
them, the synthesis did! Still, many of the warnings are useful and
need to be addressed.

I have to say that I never implement a design without running it
through both simulator and synthesis periodically as the design
progresses. Two reasons why...

1) To find anything I'm doing that one, the other or both tools think
is not a good idea. That directly applied here.

2) To check the size of the design sections. This helps me spot
anything I am doing that is blowing up the size by poor implementation
(most likely my bad, not the tool).

3) To check that any hardware targeted features are being implemented
properly. FFs in IOs, block rams, LUT rams, etc.

Yes, I know that was three and I said two. See, I needed a tool to
check that for me!

Rick
 
R

rickman

Why are we going over the same problems again and again rather than
producing a new language?

I've just snipped a massive rant about VHDL and Verilog I was about to
post ... rather I wonder if anyone feels the same way, and if so what
they think would improve things. Or indeed if they don't need
improving.

FWIW my view is hardware is just a cyclic graph and if you have good
enough tools to manipulate that graph you don't need HDL's.

-Andy

I agree that HDLs are not even close to ideal. But they seem to be
better than the schematics we had before and the best we currently
have. Also, there is the issue of "good enough". I like to get work
done. Sometimes HDLs get in the way of that, but in many ways they
are a great facilitator.

I'm not ready to toss out the baby with the bath water.

Rick
 
P

Paul Uiterlinden

rickman said:
Are you sure about that? If you use a function/procedure in a process
and don't include one of the inputs to that function/procedure in the
sensitivity list, the compiler complains? How is this reported?

I think what KJ meant (correct me if I'm wrong) is using a function or
procedure outside a process. That solves the sensitivity list problem: no
process, hence no sensitivity list, hence no chance of an incomplete
sensitivity list.

With a procedure you would use a concurrent procedure call (so outside a
process):

my_proc_i: my_proc(sig1, sig2, sig3, sig4, sig5);

The procedure declaration should look like:

PROCEDURE my_proc
(
SIGNAL out1 : OUT sig1_type;
SIGNAL out2 : OUT sig2_type;
SIGNAL in1 : IN sig3_type;
SIGNAL in2 : IN sig4_type;
SIGNAL in3 : IN sig5_type
) IS
BEGIN
...
END PROCEDURE my_proc;

With a function you would use a concurrent signal assignment (again: outside
a process)

sig1 <= my_func(sig2, sig3, sig4);

The function declaration would be something like this:

FUNCTION my_func
(
in1: sig1_type;
in2: sig2_type;
in3: sig3_type
) RETURN sig1_type IS
BEGIN
...
END FUNCTION my_func;
 
K

KJ

Are you sure about that?

Yes...you will get an error message of the form shown below if you
don't connect something up
"No feasible entries for subprogram "xyz"
 If you use a function/procedure in a process
and don't include one of the inputs to that function/procedure in the
sensitivity list, the compiler complains?  

That's not what I was suggesting. What I was suggesting is to take a
process like this...
architecture rtl of foo is
signal a, b, c: std_logic;
begin
process(a, b: std_logic)
begin
c <= a or b;
end process;
end rtl;

and replace it with a function/procedure that is defined in the
architecture, and then call the function/procedure as a concurrent
statement. So the code above would then look like this...

architecture rtl of foo is
signal a, b, c: std_logic;
function my_func(a, b: std_logic) return std_logic is
begin
return(a or b);
end process;
begin
c <= my_func(a, b);
end rtl;

The only extra baggage compared to using the process is the extra
typing of "c <= my_func(a, b);". The rest of the code that was in the
process simply moves to the function/procedure with some minor edits
as shown. In exchange for the bit of extra typing, you get the full
benefit of using 'sequential VHDL statements' like 'if', 'case', etc.,
in a place where you need to implement logic that is not to be
clocked.

The benefit is that the equivalent of missing a signal in the
sensitivity list in the 'process' form will be missing an input to a
function in the 'function/process' form which will result in the
compiler flagging the error.

Use this method where others would use a process and you can ignore
all the chatter about sensitivity list maintenance.

Kevin Jennings
 
R

rickman

Yes...you will get an error message of the form shown below if you
don't connect something up
"No feasible entries for subprogram "xyz"


That's not what I was suggesting. What I was suggesting is to take a
process like this...
architecture rtl of foo is
signal a, b, c: std_logic;
begin
process(a, b: std_logic)
begin
c <= a or b;
end process;
end rtl;

and replace it with a function/procedure that is defined in the
architecture, and then call the function/procedure as a concurrent
statement. So the code above would then look like this...

architecture rtl of foo is
signal a, b, c: std_logic;
function my_func(a, b: std_logic) return std_logic is
begin
return(a or b);
end process;
begin
c <= my_func(a, b);
end rtl;

The only extra baggage compared to using the process is the extra
typing of "c <= my_func(a, b);". The rest of the code that was in the
process simply moves to the function/procedure with some minor edits
as shown. In exchange for the bit of extra typing, you get the full
benefit of using 'sequential VHDL statements' like 'if', 'case', etc.,
in a place where you need to implement logic that is not to be
clocked.

The benefit is that the equivalent of missing a signal in the
sensitivity list in the 'process' form will be missing an input to a
function in the 'function/process' form which will result in the
compiler flagging the error.

Use this method where others would use a process and you can ignore
all the chatter about sensitivity list maintenance.

Kevin Jennings

Ok, that's a different animal. I've used functions like this, but
only for simple functions with few ins and outs... well, one out to be
exact... :^) Paul was saying you can use procedures like this too,
I'm not aware of that.

I guess the downside of this is that it can get pretty messy to
describe a complex process as functions, which is pretty much what we
are talking about. If it doesn't have many inputs and if they are in
a single assignment, then you aren't likely to mess up the sensitivity
list.

I'm expecting this to apply to something like a state machine. That
would have lots of inputs and outputs. Mapping that to functions
would be a bit of a mess. I never realized that a procedure could be
used as a concurrent statement, or maybe I've just never done it and
forgot!

While looking this up just now I found that the Entity declaration can
contain statements including a "passive concurrent procedure call".
They don't define what "passive" means in this context. Also allowed
are "concurrent assertion statements" and "passive process
statements". That is pretty amazing and I'm not even sure exactly
what that means compared to the same statements in the architecture.
When would these statements be evaluated?

Anyone familiar with this?

Rick
 
K

KJ

Ok, that's a different animal.  I've used functions like this, but
only for simple functions with few ins and outs... well, one out to be
exact... :^)   Paul was saying you can use procedures like this too,
I'm not aware of that.

In this case, functions are just a special case of procedures. If you
have more than one output signal to describe with a particular hunk of
code you have to use a procedure since you're unlimited on the number
of outputs. If you *happen* to have only one output signal to
generate you can choose to use either a procedure or a function. For
consistency, maybe you would want to always use procedures, that would
be your choice.
I guess the downside of this is that it can get pretty messy to
describe a complex process as functions, which is pretty much what we
are talking about.  

That's not correct. The code for the 'complex process' will look
nearly identical to the code for a function (if you have only one
output to generate) or a procedure (which you can use for one output
or several). If you think one looks messy, the other will look just
as messy.
If it doesn't have many inputs and if they are in
a single assignment, then you aren't likely to mess up the sensitivity
list.

Your original post was complaining about the lack of wildcards on
sensitivity lists. Presumably that complaint was based on your use of
processes with many signal inputs not processes with only a few.
I'm expecting this to apply to something like a state machine.  That
would have lots of inputs and outputs.  Mapping that to functions
would be a bit of a mess.  

Maybe you're missing the point that you can only use a function *if*
your messy hunk of code just happens to only be generating one
output. Without any extra work you could use a procedure in that
case. The point is you have a choice in that one particular case.
You must use a procedure if your messy hunk of code generates more
than one output.

The syntax for when you call the procedure will look nearly the same
as when you instantiate an entity. If there are a number of I/O, then
the port map will be pretty long. For the particular case of a state
machine that you mention here, the far better approach is the clocked
process which avoids all of this discussion.

All that being said, I haven't happened to need to describe complex
code in an unclocked process so I haven't needed to worry much about
getting the sensitivity list correct. I do recognize the sensitivity
list as a potential design issue though so I avoid using it for the
most part to avoid getting bitten. The general approach is

- Processes are sensitive only to clock
- Concurrent statements picked up most everything else.
- Occasionally, I'll use an unclocked process if there are very few
inputs (like < 4).
- On the rare occasions where none of the above were suitable, I would
use a function or a procedure as described above.
I never realized that a procedure could be
used as a concurrent statement, or maybe I've just never done it and
forgot!

Now you've acquired two approaches to solving your original complaint.
- Use the VHDL-2008 syntax with a tool that supports the updated
syntax
- Use a procedure (in some cases a function if you choose)
While looking this up just now I found that the Entity declaration can
contain statements including a "passive concurrent procedure call".
They don't define what "passive" means in this context.  Also allowed
are "concurrent assertion statements" and "passive process
statements".  That is pretty amazing and I'm not even sure exactly
what that means compared to the same statements in the architecture.
When would these statements be evaluated?

Anyone familiar with this?

Practically speaking, I haven't found it to mean much compared to
putting the same code in the architecture. The syntax for the
assertion in an entity is
entity foo is port(
...);
begin
assert ... report "OOPS!" severity ERROR;
end foo;

So you could put assertions to check that related items in the entity
have the proper relationship. However, you won't get any feedback
from the compiler that you've connected anything incorrectly since
that check won't come until you start the simulator. When you do
start sim though the assertion will fire but that is the same time
that the same assertion would be checked if it had been put into the
architecture.

If for some reason you wanted to keep the architecture code secret but
allow access to the entity then you may be motivated to put the
assertions in the entity so the user would have the information they
need to connect things properly. I haven't had such a need, maybe
others have.

Lastly, brand 'S' synthesis tool didn't used to support assertions in
the entity at all. I reported the bug and I think it has been fixed.
I tend to use brand 'A' tools now though and don't use brand 'S'
anymore, in part due to the number of bugs I reported, the length of
time it took to fix them and the obscure error message that made it
next to impossible to figure out what the work around is while they
work the problem. Brand 'A' supports (or at least doesn't choke on)
assertions in the entity, I haven't tried with brand 'X'.

Kevin Jennings
 
M

Mike Treseler

Ok, that's a different animal. I've used functions like this, but
only for simple functions with few ins and outs... well, one out to be
exact... :^)

I can use more than one.
Paul was saying you can use procedures like this too,

A function returns a value.
A procedure returns a block of code.
A concurrent procedure returns a process.
I guess the downside of this is that it can get pretty messy to
describe a complex process as functions, which is pretty much what we
are talking about.

I disagree. A function is a clean way
to hide an asynchronous process and
the wires and sensitivity that go with it.
I never realized that a procedure could be
used as a concurrent statement, or maybe I've just never done it and
forgot!

It would be hard for me to forget that experience.
I prefer using an direct instance in this case.

-- Mike Treseler
 
R

rickman

I can use more than one.

If you replace a process that assigns multiple signals with multiple
functions, you are likely going to duplicate a lot of code. It is
very likely that because you would use a process to begin with, the
signals were not easy to describe with concurrent assignments anyway,
so functions would likely be using IFs and CASEs. If the signal
assignments partitioned very cleanly, then yes, functions could be
ok. But it is very likely that much of the IF and CASE structure
would need to be duplicated.

Of course, procedures are a different matter. Then the entire process
can be shoved into the procedure if you wanted. Personally, I prefer
not to do this mainly because it separates relevant code so that I
can't see it together in one screen. Or can you define procedures
anywhere you wish in the concurrent code? I believe they have to be
at the head of the architecture in the definitions.

A function returns a value.
A procedure returns a block of code.
A concurrent procedure returns a process.

That was the part I wasn't aware of. Not that I am likely to use a
concurrent procedure. But it is something to keep in mind. I mostly
use subprograms when there is a likelihood of reuse. But I am aware
that it can help with design partitioning and decision hiding.

Too bad I am working on learning Verilog. Simpler tools for simpler
minds perhaps. :^)

I disagree. A function is a clean way
to hide an asynchronous process and
the wires and sensitivity that go with it.

Whaaa..? What wires does it hide that doesn't happen in a process?


Rick
 
J

Jan Decaluwe

rickman said:
Whaaa..? What wires does it hide that doesn't happen in a process?

A function that works on intermediate/temporary variables
within a clocked process can create combinatorial logic
without requiring sensitivity specifications.

Big news?

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Python as a HDL: http://www.myhdl.org
VHDL development, the modern way: http://www.sigasi.com
Analog design automation: http://www.mephisto-da.com
World-class digital design: http://www.easics.com
 
P

Paul Uiterlinden

Mike said:
I can use more than one.


A function returns a value.
A procedure returns a block of code.
A concurrent procedure returns a process.

In my opinion this tends to unneeded mystification. A procedure does not
return anything. The only thing that happens are the assignments via the
OUT an INOUT mode parameters.

Every concurrent procedure call has its equivalent process description.

So in my example:

my_proc_i: my_proc(sig1, sig2, sig3, sig4, sig5);

where the third to fifth formal parameter are of mode IN, the equivalent
process description would be:

my_proc_i: PROCESS IS
BEGIN
my_proc(sig1, sig2, sig3, sig4, sig5);
WAIT ON sig3, sig4, sig5;
END PROCESS my_proc_i;

No more, no less.

It also shows that any local varaible declared in in the procedure will not
hold its value over time. Each time one or more signals changes (has an
event), the procedure is called and the local variable are initialized
again.
It would be hard for me to forget that experience.
I prefer using an direct instance in this case.

I use concurrent procedure calls in behavioral code.

Another trick I use then is to make an endless loop in the body of the
procedure. That way the local variables of the procedure hold their values
over time. That is because the procedure is never left: it does not contain
a RETURN statement, nor does it ever reach the end. Of course, the
procedure will contain a WAIT statement in the endless loop.

All this of course is highly non-synthesisable! But I guess the simple
concurrent procedure call is synthesisable. Never tried it though: I hardly
ever write synthesisable code. Synthesizers are sooo limiting.... ;-)
 
P

Paul Uiterlinden

rickman said:
While looking this up just now I found that the Entity declaration can
contain statements including a "passive concurrent procedure call".
They don't define what "passive" means in this context.

From the LRM (Language Reference Manual):

A process statement is said to be a passive process if neither the process
itself, nor any procedure of which the process is a parent, contains a
signal assignment statement. It is an error if a process or a concurrent
statement, other than a passive process or a concurrent statement
equivalent to such a process, appears in the entity statement part of an
entity declaration.
 
M

Mike Treseler

In my opinion this tends to unneeded mystification.
> A procedure does not return anything.

Yes, that is a simplification,
but I could elaborate a procedure call in my editor
by pasting the procedure, and replacing the formal parameters.
That's my mental picture.
The only thing that happens are the assignments via the
OUT an INOUT mode parameters.

The structural view is also valid.
I often use process variables in scope, so I don't see the wires.

....
It also shows that any local variable declared in in the procedure will not
hold its value over time.

But process variables do, and synthesis will make
the gates or flops as needed.

-- Mike Treseler
 
P

Paul Uiterlinden

Mike said:
The structural view is also valid.
I often use process variables in scope, so I don't see the wires.

You mean that you use the process variables within the procedure body
without passing them as procedure arguments, right?
But process variables do, and synthesis will make
the gates or flops as needed.

Indeed they do. I merely wanted to make clear that local variables in
procedures don't, even if the procedure is used with a concurrent procedure
call.
 
K

KJ

Personally, I prefer
not to do this mainly because it separates relevant code so that I
can't see it together in one screen.  Or can you define procedures
anywhere you wish in the concurrent code?  I believe they have to be
at the head of the architecture in the definitions.

Not necessarily. With a few more keystrokes you can make the
procedure right where you want it in the code using a block
statement. The 'block' is essentially the same as an architecture in
structure allowing you to define functions, procedure, signals, etc.
Not much extra typing to get this, and can be worth it in terms of
keeping the code readable without having to jump around.

Example:

my_block: block
-- Define your procedures and functions here
-- You can also define 'local' signals here that are
-- not visible outside of the block.
begin
-- Put your code here that uses the procedure
end block my_block;
 
R

rickman

A function that works on intermediate/temporary variables
within a clocked process can create combinatorial logic
without requiring sensitivity specifications.

Big news?

And how exactly is that different from a process??? Sounds to me like
no news at all.

Rick
 
J

Jan Decaluwe

rickman said:
And how exactly is that different from a process???

Again, because functions don't have sensitivity lists of course!

Still, they are guaranteed to have combinatorial semantics as
they can't have side effects in VHDL.

Jan

--
Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com
Python as a HDL: http://www.myhdl.org
VHDL development, the modern way: http://www.sigasi.com
Analog design automation: http://www.mephisto-da.com
World-class digital design: http://www.easics.com
 

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,755
Messages
2,569,536
Members
45,008
Latest member
HaroldDark

Latest Threads

Top