VHDL ... Sideways?

S

Sudoer

VHDL is very good at describing a hierarchical system, but I'm trying
to design one now that is more of a... graph. How would I go about
describing the following relationship:

Top<->A
Top<->X
A<->B
B<->C
C->Dx
Dx<->X
Dx->E
E->X
E->F
F->C

(Where Dx indicates a number of entities)

This is a very simplified version of my system, but even this gives a
good indication of how complicated it could be if viewed purely
hierarchically. I have an arbitrary number of different D
architectures, and each D entity connects to the X and E entities
(Data travels back and forth from X, it travels only to E.) The arrows
indicate the direction of data through the system, though in all
instances flow control data is sent in both directions.

Is there any way for me to "bring" ports from entities lower in the
hierarchy up to the top without threading them all the way through?
The issue is that A and B are fairly generic components and I'd rather
they not have to know about C or any of the D's, let alone X. And C
also shouldn't have any clue about X. Right now I just route all the
signals X needs from outside of the design all the way through A, B,
C, and each Dx, but those signals have nothing to do with how D works.
This is making it impossible for me to package A and B in a way that I
can use them in some other designs I'm working on, as well as causing
all sorts of other headaches.

I can see how the configuration keyword would allow me to swap out
different architectures for each Dx, but I don't see how to hide X for
A, B, or C. Hopefully there's a nice solution...

Thanks!
 
B

backhus

VHDL is very good at describing a hierarchical system, but I'm trying
to design one now that is more of a... graph. How would I go about
describing the following relationship:

Top<->A
Top<->X
A<->B
B<->C
C->Dx
Dx<->X
Dx->E
E->X
E->F
F->C

(Where Dx indicates a number of entities)

This is a very simplified version of my system, but even this gives a
good indication of how complicated it could be if viewed purely
hierarchically. I have an arbitrary number of different D
architectures, and each D entity connects to the X and E entities
(Data travels back and forth from X, it travels only to E.) The arrows
indicate the direction of data through the system, though in all
instances flow control data is sent in both directions.

Is there any way for me to "bring" ports from entities lower in the
hierarchy up to the top without threading them all the way through?
The issue is that A and B are fairly generic components and I'd rather
they not have to know about C or any of the D's, let alone X. And C
also shouldn't have any clue about X. Right now I just route all the
signals X needs from outside of the design all the way through A, B,
C, and each Dx, but those signals have nothing to do with how D works.
This is making it impossible for me to package A and B in a way that I
can use them in some other designs I'm working on, as well as causing
all sorts of other headaches.

I can see how the configuration keyword would allow me to swap out
different architectures for each Dx, but I don't see how to hide X for
A, B, or C. Hopefully there's a nice solution...

Thanks!

Hi,
why should one bring ports from the lower end of a deep hierarchy to
the toplevel?
If that would be necessary there would be no need for a hierarchy,
just a number of parallel modules or processes combined by one top
level.
Except for global signals like Clock and Reset, ports from a lower
hierarchy should be seen only by the connected part one hierarchy
level above. The higher level modules don't even know about their
existence.

Configuration is for simulation only and a means to swap different
implementations of the same module for testing purposes (Like you
probably want to do with the Dx architectures).

I suspect you are going to do something weird with VHDL, beyound it's
intended focus.
So here are some tips that might be helpful.

There are so called "shared" objects. Another word for global
variables but basically the same.
They are normally considered bad, because they break up the well
structured world of hardware design. For simulation and experimental
purposes this might be ok.

Another way to save you from typing long port lists is using record
typed ports.
Search this forum, comp.arch.fpga or the forums.xilinx.com for
details.
With these you have just to type one line to route the full port list
of a module through the port description of another module. Should
save you a lot of code lines.

Also, using functions and procedures instead of instances may help.
These can be defined in a Package, and are available to all entities
where the pachage is included via the USE statement.

_________________

You say that A and B are "fairly generic components" and should'nt
know about C and Dx at all if possible?
So why do you connect C to B anyway? If you feed some data from the
top to A and B, then the results could be returned to some toplevel
signals and C is instantiated in the toplevel too.
If you want to communicate from all modules with all modules why do
you create hierarchies then. As you said your design is more like a
graph, well why don't you design it that way.
Graph connections and operators/branching points are drawn on the same
sheet, meaning they share the same hierarchy level. Only if a subgraph
can be isolated from the rest, it can create it's own subhierarchy and
is seen on the toplevel as a single Operator with a defined interface.

It should be similar to the design of hierarchical FSMs. A state can
consist of another sub-FSM. but when the top-FSM enters this state it
halts until the sub-FSM has ended it's actions and the top-FSM can
continue.


Have a nice simulation
Eilert
 
R

rickman

VHDL is very good at describing a hierarchical system, but I'm trying
to design one now that is more of a... graph. How would I go about
describing the following relationship:

Top<->A
Top<->X
A<->B
B<->C
C->Dx
Dx<->X
Dx->E
E->X
E->F
F->C

(Where Dx indicates a number of entities)

This is a very simplified version of my system, but even this gives a
good indication of how complicated it could be if viewed purely
hierarchically. I have an arbitrary number of different D
architectures, and each D entity connects to the X and E entities
(Data travels back and forth from X, it travels only to E.) The arrows
indicate the direction of data through the system, though in all
instances flow control data is sent in both directions.

Is there any way for me to "bring" ports from entities lower in the
hierarchy up to the top without threading them all the way through?
The issue is that A and B are fairly generic components and I'd rather
they not have to know about C or any of the D's, let alone X. And C
also shouldn't have any clue about X. Right now I just route all the
signals X needs from outside of the design all the way through A, B,
C, and each Dx, but those signals have nothing to do with how D works.
This is making it impossible for me to package A and B in a way that I
can use them in some other designs I'm working on, as well as causing
all sorts of other headaches.

I can see how the configuration keyword would allow me to swap out
different architectures for each Dx, but I don't see how to hide X for
A, B, or C. Hopefully there's a nice solution...

Thanks!

I don't get what you are trying to describe. Are you saying that D is
being instantiated within A, B and C, but there are different Ds and
you don't want A,, B or C to specify the type of D (or X)? I don't
really get it... Can you be more concrete?

Rick
 
T

TheProperNoun

Thanks everyone. Yes, it seems that for the structure I should both be
flattening my hierarchy some and using records. I had started my
design before I knew enough HDL to go at it this way - time to go back
and do some re-engineering.

Someone pointed out that procedures could be used as a sort of global
process. Can such a procedure maintain state internally? I.E., when I
declare variables in a procedure does the value of the variable remain
between calls? (My guess is that it doesn't, otherwise there could be
consistency issues involving elaboration of constants passed into it.)
To maintain state I presume I'd also need to use global signals... I
don't think I'll go this route - but considering how deep I am into my
design and how time pressures are building, I could be tempted to
temporarily do this until I can go back and flatten things out.

Also, as per Eilert's suggestion and Brian's response I looked up some
older posts about using records as ports, and one mentioned their hope
that in VHDL 2006 records would allow in and out designations on
records. ISE 12.1 certainly doesn't support this in 200x mode, any
idea if this has been done as of 2008, or if it's planned for the next
revision?

Another question I saw brought up was converting between
STD_LOGIC_VECTOR and Record types. Coming from a C++ background my
first instinct is, rather than writing a custom function instead have
an override of the type's built in conversion functions. I.E.,
TYPE_NAME( ... ) is supposed to convert whatever is passed to it to
TYPE_NAME - is there any way for me to overload this standard
conversion function for STD_LOGIC_VECTOR to and from my record types?

Thanks again!
 
P

Paul Uiterlinden

TheProperNoun said:
Someone pointed out that procedures could be used as a sort of global
process. Can such a procedure maintain state internally? I.E., when I
declare variables in a procedure does the value of the variable remain
between calls?

Yes it can. The trick is just not to leave the procedure. And the procedure
must be called outside from a process, so directly in an architecture. This
is called a "concurrent procedure call". Such a procedure declaration might
look like:

PROCEDURE my_procedure
(
SIGNAL clk: IN std_ulogic;
SIGNAL sig_in1: IN some_type;
SIGNAL sig_in2: IN some_other_type;
SIGNAL sig_out1 OUT blaah_type
) IS
VARIABLE v1: ...;
VARIABLE v2: ...;
BEGIN
... do some (optional) initialisation
...

forever: LOOP
WAIT UNTIL clk = '1';
... do your stuff
...
END LOOP forever;
END PROCEDURE my_procedure;

I guess this is highly unsynthesisable. I use this a lot for behavioral
modeling. The models do not have a clock, they are event driven. So the
WAIT and the rest below looks a bit different:

WAIT ON sig_in1, sig_in2;

IF sig_in1'EVENT THEN
... handle event on sig_in1
END IF;

IF sig_in2'EVENT THEN
... handle event on sig_in2
END IF;
 
A

Andy

As mentioned earlier, record-type ports can make plumbing of
interfaces through levels of hierarchy easier, but there is a major
drawback: the entire record port must be of one direction. So you
could use one port of inout, or you could use three ports of in, out
and inout, and three records for each "interface". The three-port
solution is often cumbersome because different endpoints need
different subsets defined as in vs out vs inout (think about master vs
slave consumers of a common bus). Manipulating the data around between
records when trying to connect a master to a slave is ugly, but can
also be hidden in a procedure.

The single inout port is easier to plumb and manage, but you have to
use only resolved data types, and anywhere a signal is really only
used as an input, you still have to drive 'Z' to keep the port from
getting clobbered with a 'U'. It generally works best if you have a
constant record with all elements assigned to 'Z' or (others => 'Z'),
etc. and assign the port with that constant in all the leaf level
architectures just to be sure. This causes a lot of extra resolution
work for the simulator, but it allows the user to route a complex
interface through hierharchy much more easily.

I have long lobbied for a user-defined port direction declaration for
record types, such that different elements of a single record type
port could be used as ins, outs, and inouts. You could even have
multiple direction declarations for the same record type (e.g.
"master" or "slave", etc.) for use by different endpoints. This would
make using records on ports so much easier and readable, but alas, it
is not here yet.

Andy
 
A

Andy

I use inouts with tri-state logic inside FPGAs, because it is often
simpler to describe than a distributed mux, and less clutter than a
centralized mux. The synthesis tool will convert it to muxes and
separate direction signals for you. Used in records, there's usually
only one leaf level driving the inout, and it never drives 'Z'. The
others (receivers or ignorers) always drive 'Z's. No muxes, the
synthesis tool just figures it out.

The only downside is you can't use enums, integers, booleans, etc.

Andy
 
K

KJ

I have long lobbied for a user-defined port direction declaration for
record types,

A search of the VHDL Analysis and Standardization Group at
http://www.eda-stds.org/vasg/bugrep.htm would indicate that either you
haven't been lobbying the correct place or the records of that
lobbying have been lost.

Searching for 'direction' doesn't produce anything resembling 'user-
defined port direction'
https://bugzilla.mentor.com/buglist...ug_status=__open__&product=&content=direction

Searching for 'port' doesn't produce anything resembling 'user-defined
port direction'
https://bugzilla.mentor.com/buglist...esc&bug_status=__open__&product=&content=port

Kevin Jennings
 
T

Thomas Stanka

There are "shared variables" but they won't help you if the intent is synthesis.
They can be used as test points in testbenches so that you don't need to bring
internal test points all the way up the hierarchy, but synthesis support for
these is likely to be somewhere between poor and non-existent.

You can use global signals in your design and will end up with a good
synthesis result (at least with Synplify)
In therory this would allow you to build all entities without ports
and save a lot of signal routing through hierarchies.

Nevertheless I would recommend not to use global signals in rtl
because you will likely break on several points when maintaining the
code.

bye Thomas
 
T

Tricky

You can use global signals in your design and will end up with a good
synthesis result (at least with Synplify)
In therory this would allow you to build all entities without ports
and save a lot of signal routing through hierarchies.

Nevertheless I would recommend not to use global signals in rtl
because you will likely break on several points when maintaining the
code.

bye Thomas

Altera just refuse to synthesise global signals full stop. I have
raised an issue about this and they say they will never support them
(as they say they are only really for debugging in simulation).
 
S

Sudoer

So I've started using records as ports with client/server records for
input and output. I also have a combined version of each record, and
wherever I use the records I have a procedure that combined the client/
server records into a single record - in this way I have a single
interface with both in and out ports, but as opposed to inout, I don't
risk getting confused - I get an error when I assign to the wrong
direction.

The issue is, it's a bit cumbersome. For each interface I have 6
records (client, server, combined, client unconstrained array, server
unconstrained array, combined unconstrained array, so that I can have
a variable number of items connected to the interface), and 4
procedures (make client in and server out, make server in and client
out, and those two again, but for the unconstrained arrays).

Some quick musings/questions... I don't suppose I can overload the
procedures based on in/out, that way I'd only need two functions (one
for individual "bundles" as I call the records, and one for
"collections", which is what I call the unconstrained arrays of
bundles) and never risk using the wrong one on the wrong side of the
interface.

Next, is there any way for me to combine two records into a new
records - sort of a multiple inheritance? Right now I just list all
the variables in the server and client side records a second time into
the combined record, but if I ever change one of the server of client
records, I'll need to remember to change the combined record and the
procedures I use to change them... I could just list the server and
client records in the combined record, but then that defeats the
purpose of combining them into a single interface...

Any VHDL veterans know a cleaner solution to merging the client and
server records?

Thanks!
 
S

Sudoer

So I've started using records as ports with client/server records for
input and output. I also have a combined version of each record, and
wherever I use the records I have a procedure that combined the client/
server records into a single record - in this way I have a single
interface with both in and out ports, but as opposed to inout, I don't
risk getting confused - I get an error when I assign to the wrong
direction.

The issue is, it's a bit cumbersome. For each interface I have 6
records (client, server, combined, client unconstrained array, server
unconstrained array, combined unconstrained array, so that I can have
a variable number of items connected to the interface), and 4
procedures (make client in and server out, make server in and client
out, and those two again, but for the unconstrained arrays).

Some quick musings/questions... I don't suppose I can overload the
procedures based on in/out, that way I'd only need two functions (one
for individual "bundles" as I call the records, and one for
"collections", which is what I call the unconstrained arrays of
bundles) and never risk using the wrong one on the wrong side of the
interface.

Next, is there any way for me to combine two records into a new
records - sort of a multiple inheritance? Right now I just list all
the variables in the server and client side records a second time into
the combined record, but if I ever change one of the server of client
records, I'll need to remember to change the combined record and the
procedures I use to change them... I could just list the server and
client records in the combined record, but then that defeats the
purpose of combining them into a single interface...

Any VHDL veterans know a cleaner solution to merging the client and
server records?

Thanks!

Oh, and now whenever I try to simulate in iSim I get a compiler
assertion error saying I should open a Xilinx webcase. Of course
they'll just ask me to send them my source, which I can't, and it
wouldn't resolve my issue this century. That said, it synthesizes
nicely... (Although simulation is rather of crucial for me...)
 
S

Sudoer

ISIM is finally starting to look like a real simulator, but still has quite a
few errors.

I suggest a divide-and-conquer to find the specific construct that kills it -
there may well be a usable workround. I can't make specific suggestions of
course; but one anecdote:

In ISE10, ISIM would crash (Segment Violation) returning an access type
(specifically Line, = access-to-string) from a function. Pass the access type as
an OUT parameter from a procedure, and it worked fine...

- Brian

It turns out the crashing had nothing to do with the records as ports
or merging them in a single record on each end - it had to do with a
TO_SLV I wrote for some special datatypes. Kind of hard to tell when
all you get is an assert out of Xilinx's compiler with nothing but an
error indicating which line in their code it occurred on (less useful
since we don't have their code...) Now I'm getting a silly error that
leads me to believe somewhere I'm reading AND writing to an in or out
port somewhere, but only on some of of the records as ports. More
interesting is that it synthesized without so much as a squeak.

Since Simulation will likely be possible, that still begs the question
of whether or not there's a neater way for me to handle the merged/
combination record as port. There's no way for me to use a function as
the target of an alias, is there? (Man would that be a nice feature...)
 
S

Sudoer

Even if you trace that sort of error to a real mistake in your code, it's still
worth reporting as a Webcase, with the simplest possible illustrating case.
It ought to fail compilation with a meaningful message rather than crash
randomly.

I believe there are some good guys behind ISIM who want to make a good product
of it ... you just have to reach them through the lolcats providing first level
support.

At one time I had 8 open Webcases, and 5 of them were real ISIM bugs.
Some of them have even been fixed...


Heh, in Ada you can "rename" (=alias) functions as well as anything else.
But I would expect overloading to work for your purpose.

- Brian

So, it turns out my procedure to merge all the client and server side
of the records as ports was the issue. Because I took one record as
in, one record as out, and has the merged record be inout, well ...
here's an example...

type client_record is record
A : std_logic;
end record;

type server_record is record
B : std_logic;
end record;

type both_record is record
A : std_logic;
B : std_logic;
end record;

procedure merger(
signal client : in client_record;
signal server : out server_record;
signal both : inout both_record) IS
BEGIN
both.A <= client.A;
server.B <= both.B;
END merger

All looks well. Then when I try the following:

....
signal client : client_record;
signal server : server_record;
signal both : both_record;

begin

merger( client, server, both ); -- Line produces an error
...
both.B <= '1'; -- Line produces an error
....


The issue here is that both merger and the line below it are assigning
to the "both" record, so Xilinx's XST asks me for a resolution
function even though they never assign to the same members.

My question is: is this a VHDL thing, or is this a Xilinx thing?
 
A

Andy

I have not lobbied in any of your list of the "right places". A review
of my posting record here would indicate that I have advocated for
this for a long time (perhaps in hopes of someone else championing the
issue :) .

Andy
 
A

Andy

You can use global signals in your design and will end up with a good
synthesis result (at least with Synplify)
In therory this would allow you to build all entities without ports
and save a lot of signal routing through hierarchies.

Nevertheless I would recommend not to use global signals in rtl
because you will likely break on several points when maintaining the
code.

bye Thomas

I have not tried it lately, but Synplify used to accept a global
signal declaration, but each invocation was a separate, local signal
and they were not global. I don't remember the details about what
constituted a separate invocation, but I know that two architectures
of two entities both had the signal, but not connected between them.
This was a long time ago, and they may well have fixed it by now.

Andy
 
A

Andreas Ehliar

others (receivers or ignorers) always drive 'Z's. No muxes, the
synthesis tool just figures it out.

The only downside is you can't use enums, integers, booleans, etc.

Another downside is that you may cause a mismatch between synthesis
and simulation if you are not careful.

Consider the following part of a process:

if ctrl = '1' then
led1_o <= data;
end if;

if ctrl = '0' then
led2_o <= data;
end if;

Lets just say that this code is unlikely to behave in the same way in
both synthesis and simulation if ctrl is set to 'Z'.

regards
/Andreas
 
A

Andy

In most cases where you would use an inout port instead of an in port
or an out port, if ctrl = 'Z', then there was no driver connected, and
neither of these if statements will get implemented, just like neither
of these will be executed in simulation. But no errors would be
generated in simulation (warnings are generated in synthesis). If the
inout is used for a truly bidirectional signal (that would be
implemented with two unidirectional signals), you would still have to
safely handle the condition when nobody was driving (or nobody's mux
input was enabled).

I use home-grown functions is1() and is0() that test for meta-values,
and convert weak values. Is1(ctrl) asserts an error if ctrl is 'Z' (or
'-', 'X', 'U', or 'W'), but returns true if ctrl is 'H' or '1'. I can
default a tri-state signal to 'H' or 'L' instead of 'Z' (or just
create a continuous driver to 'H' or 'L'), but that might hide cases
where a driver was mistakenly omitted.

I use is1() or is0() everywhere I need a boolean condition, not just
when I think there might be a meta-value. I use Rising_edge(clk)
because it correctly handles transitions to and from weak values (not
to mention it is more self-documenting).

Andy
 

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

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top