Can a signal be resolved as 'most recent event wins'?

I

Iwo Mergler

Hi,

This is an exercise in simplifying port maps in
testbench code.

I'm trying to use a record as a bus with signals
going in opposite directions. Is this possible
in VHDL?

Something like this:

type mytype is
record
cmd : with_the_flow type;
busy : against_the_flow type;
end record;

The idea is to have this record be an in-signal
for entity A and an out-signal for entity B.
Which makes signal.busy an out signal for entity
A and an in-signal for entity B.

I'm fairly sure that no such thing exists in VHDL.

To solve the problem, I tried to describe the
record as a resolved bus. The idea is to declare the
bus as inout signals for both entities and fix the
multiple driver problem by resolving the individual
record elements.

Entities A & B know which end of the bus they represent,
so only A ever drives signal.busy and only B ever drives
signal.cmd.

I think the problem boils down to having to resolve such
that the most recent assignment wins. Typical resolution
functions will look at the signal values, I would like
to look at the signal attributes.

Unfortunately, I don't seem to be able to get at the
attributes of the component signals of the record, only
the attributes of the record itself:

package test is
type cmd_t is (idle,read,write);
type operation_t is
record
cmd : cmd_t;
busy : boolean;
end record;
type op_vector is array (integer range <>) of operation_t;
function op_resolve(ov : in op_vector) return operation_t;
subtype op_t is op_resolve operation_t;
end test;

package body test is
function op_resolve(ov : in op_vector) return operation_t is
variable f2p_i : integer := 0;
variable p2f_i : integer := 0;
variable result : operation_t;
begin
-- Current assignment wins
for i in ov'range loop -- OK
if ov(i).cmd'event then -- This breaks
f2p_i := i;
end if;
if ov(i).busy'event then
p2f_i := i;
end if;
end loop;
result.cmd := ov(f2p_i).cmd;
result.busy := ov(p2f_i).busy;
return result;
end function op_resolve;
end package body;

The compiler says

Model Technology ModelSim ALTERA vcom 6.1g Compiler 2006.08 Aug 12 2006
-- Loading package standard
-- Compiling package test
-- Compiling package body test
-- Loading package test
** Error: Z:/resolving.vhd(27): Attribute "event" requires a static signal
prefix.
** Error: Z:/resolving.vhd(30): Attribute "event" requires a static signal
prefix.
** Error: Z:/resolving.vhd(39): VHDL Compiler exiting

Is there a way to get at the record member attributes?

Kind regards,

Iwo
 
J

Jim Lewis

Iwo,
I do this by individually resolving the elements of
the record. The easy way to do this is to assign
the driving value of a port to an identity value when
it is not being driven. The obvious example is to drive
a 'Z' for a std_logic element of the record.

For other types, you can write a resolution function by
deciding that 0 makes a good identity element.
The package ResolutionPkg.vhd shows two different ways
to do this (I generally use resolved):
http://www.synthworks.com/papers/ResolutionPkg.vhd

Cheers,
Jim
 
I

Iwo Mergler

Iwo said:
Hi,

This is an exercise in simplifying port maps in
testbench code.
<snip>

Mike, Jim, Paul,

thank you very much for the pointers. All three responses
together solve my problem.

Jim's suggestion, as implemented in Paul's example shows
resolution by signal value. I now know that an undriven
signal assumes a default value, the leftmost element in
an enumeration. This solves my problem - I can resolve
the signals this way.

Mike, what you describe as remote procedures is exactly
what I'm trying to do. I was under the illusion that
the idea was so clever that there was no need to research
other people's solutions. I feel suitably chastised. :)

This is a bus simulator for use in a testbench. It is
implemented as a package with a whole bunch of bus
activity procedures and an entity which is the actual
bus driver. They communicate over an inout signal which
is my record. The procedures contain handshake waits with
the bus driver which effectively 'block' the procedure
calls for the duration of the bus sequence.

The resulting testbench looks roughly like this:

....
use work.mypackage.all;
....
architecture tb of testbench is
....
component thebusexerciser is
port (
-- global
clk : in std_logic;
reset : in std_logic;
op : inout bus_op_t;

-- bus interface
...
);
end component;

signal op : bus_op_t;

....
begin
master : thebusexerciser
port map (
...
op => op;
...
);
...
simulation : process
variable data : bus_data_t;
begin
wait(5); -- waits 5 clock cycles after reset.
bus_write(op,0x"00000000",0x"DEADBEEF");
while bus_read(op,0x"00000008") = 0x"00000000" loop
null; -- polling
end loop;
data := bus_read(op,0x"00000004");
if data /= 0x"12345678" then
scream_in_terror;
end if;
...
end process;

etc.

The idea is to use a simple sequential process to coordinate
the busmaster with other parts of the testbench.

Kind regards,

Iwo
 
P

Paul Uiterlinden

Iwo said:
The resulting testbench looks roughly like this:

...
use work.mypackage.all;
...
architecture tb of testbench is
...
component thebusexerciser is
port (
-- global
clk : in std_logic;
reset : in std_logic;
op : inout bus_op_t;

-- bus interface
...
);
end component;

signal op : bus_op_t;

...
begin
master : thebusexerciser
port map (
...
op => op;
...
);
...
simulation : process
variable data : bus_data_t;
begin
wait(5); -- waits 5 clock cycles after reset.
bus_write(op,0x"00000000",0x"DEADBEEF");
while bus_read(op,0x"00000008") = 0x"00000000" loop
null; -- polling
end loop;
data := bus_read(op,0x"00000004");
if data /= 0x"12345678" then
scream_in_terror;
end if;
...
end process;

etc.

The idea is to use a simple sequential process to coordinate
the busmaster with other parts of the testbench.

Yup, that's the way I use it.

A problem that is see with your example is in this piece:

while bus_read(op,0x"00000008") = 0x"00000000" loop
null; -- polling
end loop;

Subprogram bus_read clearly is a function and it must have a wait statement
inside (or calls another procedure with a wait statement). That is a
combination that is not possible in VHDL. So bus_read should be a
procedure.

The result value should either be returned via an out or inout mode
parameter of bus_read, or it could be retrieved from signal op with a
second function, like get_data.

I use the latter solution, because the first solution tends to clutter the
bus_read procedure with a lot of parameters. And if you want to make them
optional, you end up with a whole lot of overloaded procedures.

So my solution would be:

bus_read(op, 0x"00000008");
poll: while get_data(op) = 0x"00000000" loop
bus_read((op, 0x"00000008");
end loop poll;

bus_read(op, 0x"00000004");
if get_data(op) /= 0x"12345678" then
scream_in_terror;
end if;

The duplicated read in the poll part can be avoided with an exit statement

poll: loop
bus_read((op, 0x"00000008");
exit poll when get_data(op) /= 0x"00000000";
end loop poll;

Or if you don't like exit statements, with an extra boolean variable:

variable poll_end: boolean;
...
while not poll_end loop
bus_read((op, 0x"00000008");
poll_end := get_data(op) /= 0x"00000000";
end loop;

Or with a loop-until construct, which VHDL unfortunately does not have...
 
J

Jim Lewis

Iwo,
Mike, what you describe as remote procedures is exactly
what I'm trying to do. I was under the illusion that
the idea was so clever that there was no need to research
other people's solutions. I feel suitably chastised. :)

Been teaching this in our VHDL Testbench classes since the
late 90's. At that time mainly focused on std_logic.

A paper on applying this technique to both subblocks and
chips (and hence not writing duplicating tests at both
levels) is posted here:
http://www.synthworks.com/papers/

under the title:
"Accelerating Verification Through Pre-Use of
System-Level Testbench Components"

I did not start using integer, time, and real resolution
functions until last fall. Ironically Paul U had posted
something about them earlier and I had missed it and instead
I had to learn it in a less direct way. So me too, I wish
I had been collaborating more and sooner.

My current plan is to make more of our packages publicly
available in some form - time permitting.

Cheers,
Jim Lewis
SynthWorks VHDL Training
 
M

Mike Treseler

Iwo said:
Mike, what you describe as remote procedures is exactly
what I'm trying to do. I was under the illusion that
the idea was so clever that there was no need to research
other people's solutions. I feel suitably chastised. :)

The idea is from Jonathan Bromley.
I just coded the simplest possible example.
But I'm happy that it made sense to you.
This is a bus simulator for use in a testbench. It is
implemented as a package with a whole bunch of bus
activity procedures and an entity which is the actual
bus driver. They communicate over an inout signal which
is my record. The procedures contain handshake waits with
the bus driver which effectively 'block' the procedure
calls for the duration of the bus sequence.

Do your procedures use signals
or process variables to retain
state information?
The resulting testbench looks roughly like this:

Thanks for the outline. Looks interesting.
Maybe you can make us a small example when
you get it all worked out.

All the verification gurus like the client-server
architecture arbitrating multiple processes,
so it sounds like you are on a solid track.

I prefer to use a single test process
where the only signals are the wires to the UUT.
But I'm an over-the-top procedural guy.

Good luck on your project.

-- Mike Treseler
 
I

Iwo Mergler

Paul said:
Yup, that's the way I use it.

A problem that is see with your example is in this piece:

while bus_read(op,0x"00000008") = 0x"00000000" loop
null; -- polling
end loop;

Subprogram bus_read clearly is a function and it must have a wait
statement inside (or calls another procedure with a wait statement). That
is a combination that is not possible in VHDL. So bus_read should be a
procedure.

The result value should either be returned via an out or inout mode
parameter of bus_read, or it could be retrieved from signal op with a
second function, like get_data.

I use the latter solution, because the first solution tends to clutter the
bus_read procedure with a lot of parameters. And if you want to make them
optional, you end up with a whole lot of overloaded procedures.

So my solution would be:

bus_read(op, 0x"00000008");
poll: while get_data(op) = 0x"00000000" loop
bus_read((op, 0x"00000008");
end loop poll;

bus_read(op, 0x"00000004");
if get_data(op) /= 0x"12345678" then
scream_in_terror;
end if;

Thanks for solving my next problem. :)
I added a results array to my state record and implemented your suggestion.

Kind regards,

Iwo
 
I

Iwo Mergler

Mike said:
Do your procedures use signals
or process variables to retain
state information?

Signals. I admit I didn't think of using process variables.
Is there an advantage in doing so?

Kind regards,

Iwo
 
P

Paul Uiterlinden

Iwo said:
Signals. I admit I didn't think of using process variables.
Is there an advantage in doing so?

Variables are easier to use (no delta needed to see the updated value),
consume about ten times less memory than signals (important for modeling
memories) and consume less processor power (variables do not have an event
queue to be maintained).

In short: only use signals for communication between processes. For data
that stays in a process and need not be visible outside it, use variables.
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top