Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Wired Or in VHDL

866 views
Skip to first unread message

Marc Jenkins

unread,
Jul 25, 2014, 5:58:07 AM7/25/14
to
Hello folks,

Verilog supports the net type "wor" to implement a wired or logic.
Is something similar possible in VHDL?

Target plattform is an ASIC.

Thanks,
Marc

KJ

unread,
Jul 25, 2014, 10:33:21 AM7/25/14
to
Wired-or simply means that there are multiple drivers on a net. In VHDL land, the std_logic that nearly everybody uses for every signal definition can have multiple drivers.

Kevin Jennings

rickman

unread,
Jul 25, 2014, 1:42:47 PM7/25/14
to
The question is why would you want that? To use a wired or you would
need to have open collector (or open drain) outputs with a pull up
resistor. Compared to just adding an OR gate this is a very slow method
or very power hungry, take your pick.

Do you really plan to use a wired or? Or do you expect this to be
replaced with a real gate and are using it as shorthand?

--

Rick

Mark Curry

unread,
Jul 25, 2014, 2:41:21 PM7/25/14
to
Most synthesis tools I'm aware of correctly map multiple drivers on a "wor" net
to a logical 'or' gate. It's perfectly synthesizable, and quite useful.

We've been using this construct for over 10 years on our Xilinx FPGAs
on our CPU register bus. The returned read data (for when the CPU
is issuing a read) is collected on a "wor" bus. All the slaves
drive 0 when NOT addressed. When addressed, and issued a read, the
one slave drives the actual read data on the bus.

Works a charm, and greatly simplifies our code.

Regards,

Mark


rickman

unread,
Jul 25, 2014, 4:30:18 PM7/25/14
to
Synthesizable yes, useful...?

--

Rick

Mark Curry

unread,
Jul 25, 2014, 5:56:58 PM7/25/14
to
Very useful. We've got a much cleaner, reusable structure setup for
register configuration. There's nothing to do to add/subtract (sometimes
via the setting of a parameter) more registers on the bus. It just works.

It's a bit hard to describe in a small example. But we've got significant
code size reduction using this structure. Some were uncomfortable at first
with the "multi-driver" implications, or collision problems. But we've found
that neither are a problem at all.

Regards,

Mark

rickman

unread,
Jul 25, 2014, 7:04:23 PM7/25/14
to
No need for examples. I understand perfectly what you are describing.
But this is a construct that is in some respects the equivalent of a
global variable and creates issues for verifying code depending on your
methods. If it works for you then great. :)

--

Rick

Mark Curry

unread,
Jul 25, 2014, 8:06:23 PM7/25/14
to
Rickman,

I was among those that cast a suspicious eye on the construct when I
first saw it. But it really works fine and is NOT comparable to
a global variable at all IMHO.

I think of it as the same mux as others do by hand to
mux the readdata back - just broken up. i.e. think
of the readmux as a sum of products:
y = ( sel0 & in0 ) | ( sel1 & in1 ) | ( sel2 & in2 ) | ...

Where we force the slave modules themselves to do the "AND" masking.
Then the 'OR' is taken care of automatically with the 'wor' multi-driver.

There's really no verification issues that we have with using this.
It's very straightforward.

--Mark

rickman

unread,
Jul 25, 2014, 10:15:54 PM7/25/14
to
I might not understand this correctly since I am much more the VHDL
programmer (where the wire or is seldom used, in fact, can that be
done?) than a Verilog programmer... So there is one net with multiple
drivers. When *any* of the drivers outputs a 1 the net is a 1, hence
the wire or name.

So if you have a 1 on the net when you aren't expecting a 1, how do you
identify the driver unless you look at the inputs to all the drivers in
all the different modules? To me that is a problem and is one of the
reasons why buses like this are a PITA to debug in real hardware. This
is commonly referred to as "hanging" the bus.

By using an explicit mux the only signal that can drive the output of
the mux is the signal that is selected at that moment. Look at the
select lines, look at the corresponding input and continue to trace back
from there.

This is not an insurmountable problem. As I said this is commonly used
in real hardware, just not inside chips very often. You say it makes
the code easier to read, I think it splits the logic for a simple mux
across multiple modules and makes it harder to debug.

Consider a software technique of encapsulating decisions and functions.
The wire or is the opposite of that since the mux logic is spread
across modules.

Different horses for different courses. :)

--

Rick

Daniel Kho

unread,
Jul 31, 2014, 2:53:49 PM7/31/14
to
Haven't tried resolution functions on Xilinx. But from the sound of it, I believe your 'wor' can be easily done with a custom resolution function in VHDL:

entity test is port(d0,d1:in std_ulogic; q:out resolved_wor std_ulogic);
end entity test;

architecture rtl of test is begin
q<=d0;
q<=d1;
end architecture rtl;

Not sure if Vivado supports this though. With a bit of hacking, you can get Quartus to support this. Last I know, Quartus chokes on custom resolved ports, so you need to declare an internal signal that uses the custom resolution function:
signal s:resolved_wor std_ulogic;

and treat s as having multiple drivers from d0 and d1. Then drive the output q from the internal resolved signal s.

You can write custom resolution functions to resolve outputs on OR, AND, or anything you want. We prefer not to have special keywords like wor, wand, etc. that clutter our language. :) These things can be easily written as custom functions by the designer.

-dan

Mark Curry

unread,
Jul 31, 2014, 4:58:39 PM7/31/14
to
In article <b4f036fe-5d34-41ad...@googlegroups.com>,
Daniel Kho <danie...@gmail.com> wrote:

>
>Haven't tried resolution functions on Xilinx. But from the sound of it, I
>believe your 'wor' can be easily done with a custom resolution function in
> VHDL:
>
>entity test is port(d0,d1:in std_ulogic; q:out resolved_wor std_ulogic);
>end entity test;
>
>architecture rtl of test is begin
> q<=d0;
> q<=d1;
>end architecture rtl;
>
>Not sure if Vivado supports this though. With a bit of hacking, you can get
>Quartus to support this. Last I know, Quartus chokes on custom resolved ports,
>so you need to declare an internal signal
>that uses the custom resolution function:
> signal s:resolved_wor std_ulogic;
>
>and treat s as having multiple drivers from d0 and d1. Then drive the output
>q from the internal resolved signal s.
>
>You can write custom resolution functions to resolve outputs on OR, AND, or
>anything you want. We prefer not to have special keywords like wor, wand, etc.
>that clutter our language. :) These things
>can be easily written as custom functions by the designer.

Dan,

I'm not a VHDL person - can you detail more? How's the custom resolution
function written? I.e. How's it support the variable number of inputs to
the function?

i.e. I want the 'resolved_wor' to resolve a variable number of drivers on the
net. There's only one net. The net may driven locally, or thru a connection
to a sub-entity's output port.

Can I do this with VHDL, using custom resolution functions?

Xilinx is dragging their feet supporting wor's in verilog thru Vivado. They've
always supported it in ISE at least since ISE 6.xx, probably forever.
If I can give them a VHDL example too, it might help.

Thanks,

Mark

Daniel Kho

unread,
Jul 31, 2014, 6:04:28 PM7/31/14
to
On Friday, 1 August 2014 04:58:39 UTC+8, Mark Curry wrote:
> Dan,
>
>
>
> I'm not a VHDL person - can you detail more? How's the custom resolution
>
> function written? I.e. How's it support the variable number of inputs to
>
> the function?
>
>
>
> i.e. I want the 'resolved_wor' to resolve a variable number of drivers on the
>
> net. There's only one net. The net may driven locally, or thru a connection
>
> to a sub-entity's output port.
>
>
>
> Can I do this with VHDL, using custom resolution functions?
>
>
>
> Xilinx is dragging their feet supporting wor's in verilog thru Vivado. They've
>
> always supported it in ISE at least since ISE 6.xx, probably forever.
>
> If I can give them a VHDL example too, it might help.
>
>
>
> Thanks,
>
>
>
> Mark

Hi Mark,
There are some pretty good references on designing your own custom resolution functions in VHDL. I just did a search and found this:
http://vhdl.renerta.com/source/vhd00058.htm

There are also predefined (standard) resolution functions within the standard VHDL packages, and anyone can read them.

An example of resolved_or (or resolved_wor in my previous post):

function resolved_or(s:std_ulogic_vector) return std_logic is
variable result:std_ulogic:='0';
begin
for i in s'range loop
result:=result or s(i);
end loop;
return result;
end function resolved_or;

These custom functions may be defined within an architecture (before the BEGIN), or within a VHDL package.

-dan

Daniel Kho

unread,
Jul 31, 2014, 6:23:43 PM7/31/14
to
On Friday, 1 August 2014 04:58:39 UTC+8, Mark Curry wrote:

> I'm not a VHDL person - can you detail more? How's the custom resolution
> function written? I.e. How's it support the variable number of inputs to
> the function?
>

Sorry for the multiple posting. Posted too quickly without reading your entire question. :|

A resolution function accepts as argument, a vector (or array) of the signal you wish to have multiple drivers on. Say for example you have a signal (or output) net q as in my previous example, that you wish to have multiple sources driving it. q is of an unresolved type std_ulogic, but you can apply the resolution function "resolved_wor" to resolve q to a deterministic value from multiple sources driving it.
q:out resolved_wor std_ulogic;

To write a resolution function for q, you create one that accepts a vector of std_ulogic (we can use the predefined std_ulogic_vector), and this array contains all the multiple drivers that would be driving q. The resolution function can then be written to resolve the output based on any resolution logic you want. This can be a simple OR or AND, or can as complex as need be. The output (return value) of a resolution function must therefore be of a resolved type (such as std_logic).

function resolved_wor(s:std_ulogic_vector) return std_logic is begin
...
end function resolved_wor;

-dan

Mark Curry

unread,
Jul 31, 2014, 7:18:47 PM7/31/14
to
In article <078f85e7-b935-403d...@googlegroups.com>,
Yeah - doesn't solve my problem. There's no "std_ulogic_vector" for the
input to the function. There's only *ONE* net. The one net with multiple
(resolved type) drivers on it.

I don't see how this is "custom resolution function" is different
than any other function? (Again, I'm not VHDL person).

What I'm trying to do (verilog speak, sorry):
cpu_reg cpu_reg1 ( `BUS_CONNECT, .data_o( reg1_val ) );

cpu_reg cpu_reg2 ( `BUS_CONNECT, .data_o( reg2_val ) );

cpu_reg cpu_reg3 ( `BUS_CONNECT, .data_o( reg3_val ) );
...

The `BUS_CONNECT is simple a verilog macro (probably a structure (record?)
in VHDL) that hooks up the CPU bus interface. All the read data, is a
wor net.

Theres only one "read_data" net (an output of this entity) on BUS_CONNECT.
(Think of it as 1 bit to make the testcase easier). "read_data" is 'wor'
resolved for the multiple drivers on it.

Generics/etc will conditionally compile in/out many cpu_regs. So I don't
know how many drivers "read_data" has apriori. Nor could I easily define
the width of the "std_ulogic_vector" input to your function.

--Mark


rickman

unread,
Jul 31, 2014, 7:23:38 PM7/31/14
to
The resolved_or function you posted does not implement a wired or. The
type used is just std_ulogic and the assignment is
result := result or s(i);

This is the or of all the bits in a bus.

--

Rick

Rob Gaddi

unread,
Jul 31, 2014, 7:39:58 PM7/31/14
to
Which, when used as a resolution function, makes the signal equal to
the OR of all its drivers, i.e. a wired OR. Doesn't it?

--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com
Email address domain is currently out of order. See above to fix.

rickman

unread,
Jul 31, 2014, 7:42:08 PM7/31/14
to
> ....
>
> The `BUS_CONNECT is simple a verilog macro (probably a structure (record?)
> in VHDL) that hooks up the CPU bus interface. All the read data, is a
> wor net.
>
> Theres only one "read_data" net (an output of this entity) on BUS_CONNECT.
> (Think of it as 1 bit to make the testcase easier). "read_data" is 'wor'
> resolved for the multiple drivers on it.
>
> Generics/etc will conditionally compile in/out many cpu_regs. So I don't
> know how many drivers "read_data" has apriori. Nor could I easily define
> the width of the "std_ulogic_vector" input to your function.

I think I see where Daniel is coming from. Try reading this link. I
guess the function resolved_wor gets applied to your multiple drivers
when you declare the signal q:out resolved_wor std_ulogic;

http://vhdl.renerta.com/mobile/source/vhd00058.htm

So disregard my prior post..... :(

--

Rick

Daniel Kho

unread,
Aug 1, 2014, 3:24:40 AM8/1/14
to
On Friday, 1 August 2014 07:18:47 UTC+8, Mark Curry wrote:
> Yeah - doesn't solve my problem. There's no "std_ulogic_vector" for the
>
> input to the function. There's only *ONE* net. The one net with multiple
>
> (resolved type) drivers on it.
>

Yes, the 'q' in my previous example is also a single net, with multiple drivers driving it.


> What I'm trying to do (verilog speak, sorry):
>
> cpu_reg cpu_reg1 ( `BUS_CONNECT, .data_o( reg1_val ) );
> cpu_reg cpu_reg2 ( `BUS_CONNECT, .data_o( reg2_val ) );
> cpu_reg cpu_reg3 ( `BUS_CONNECT, .data_o( reg3_val ) );
>
> ...
>
> The `BUS_CONNECT is simple a verilog macro (probably a structure (record?)
> in VHDL) that hooks up the CPU bus interface. All the read data, is a
> wor net.
>

Don't really understand this Verilog code, sorry. Is that within an @always block? So are those transactions?


> Generics/etc will conditionally compile in/out many cpu_regs. So I don't
> know how many drivers "read_data" has apriori. Nor could I easily define
> the width of the "std_ulogic_vector" input to your function.

As long as you leave the vector width unconstrained in your resolution function, you don't need to specify how many drivers there are. Upon elaboration of your design, the resolution function takes in the vector of all multiple drivers - it finds all the multiple driving nets, and groups them into an array automatically. The size of the array is automatically calculated upon elaboration. It's all done behind the scenes for you.

-dan

Mark Curry

unread,
Aug 1, 2014, 1:47:30 PM8/1/14
to
In article <5c10d684-fcd4-4bfc...@googlegroups.com>,
Daniel Kho <danie...@gmail.com> wrote:
>On Friday, 1 August 2014 07:18:47 UTC+8, Mark Curry wrote:
>> Yeah - doesn't solve my problem. There's no "std_ulogic_vector" for the
>>
>> input to the function. There's only *ONE* net. The one net with multiple
>>
>> (resolved type) drivers on it.
>>
>
>Yes, the 'q' in my previous example is also a single net, with multiple
>drivers driving it.
>
>
>> What I'm trying to do (verilog speak, sorry):
>>
>> cpu_reg cpu_reg1 ( `BUS_CONNECT, .data_o( reg1_val ) );
>> cpu_reg cpu_reg2 ( `BUS_CONNECT, .data_o( reg2_val ) );
>> cpu_reg cpu_reg3 ( `BUS_CONNECT, .data_o( reg3_val ) );
>>
>> ...
>>
>> The `BUS_CONNECT is simple a verilog macro (probably a structure (record?)
>> in VHDL) that hooks up the CPU bus interface. All the read data, is a
>> wor net.
>>
>
>Don't really understand this Verilog code, sorry. Is that within an
>@always block? So are those transactions?

Sorry, should have been more clear. Those are all just instaciations.
The "multiple driver" read_data is all within `BUS_CONNNECT.
To expand it (leaving some connections out to synplify):

wor rddata_o;
cpu_reg cpu_reg1 ( .addr_i( addr_i ), .cs_i( cs_i ), .wrdata_i( wrdata_i ), .rwn_i( rwn_i ), .rddata_o( rddata_o ) );
cpu_reg cpu_reg2 ( .addr_i( addr_i ), .cs_i( cs_i ), .wrdata_i( wrdata_i ), .rwn_i( rwn_i ), .rddata_o( rddata_o ) );
cpu_reg cpu_reg3 ( .addr_i( addr_i ), .cs_i( cs_i ), .wrdata_i( wrdata_i ), .rwn_i( rwn_i ), .rddata_o( rddata_o ) );

rddata_o has multiple drivers. I want them resolved like a verilog 'wor', but
in VHDL. I'm having trouble figuring out how to tie the VHDL "resolution function" "resolved_wor"
to the single net "rddata_o". "rddata_o" is both the input, and output of the function...
How do I hook it up?

--Mark

Dio Gratia

unread,
Aug 2, 2014, 12:45:10 AM8/2/14
to
On Saturday, August 2, 2014 5:47:30 AM UTC+12, Mark Curry wrote:

> rddata_o has multiple drivers. I want them resolved like a verilog 'wor', but
> in VHDL. I'm having trouble figuring out how to tie the VHDL "resolution function" "resolved_wor"
> to the single net "rddata_o". "rddata_o" is both the input, and output of the function...
> How do I hook it up?

You specify a resolution function to use in a subtype indication declaring signals. The simulator provides an array type of the base type of the signal having a value for every driver on the net and calls the function internally.

A resolution function has one argument, an array vector and returns a result that is of the same base type.

This is from package std_logic_1164 for std_logic:

type stdlogic_table is array(STD_ULOGIC, STD_ULOGIC) of STD_ULOGIC;

-------------------------------------------------------------------
-- resolution function
-------------------------------------------------------------------
constant resolution_table : stdlogic_table := (
-- ---------------------------------------------------------
-- | U X 0 1 Z W L H - | |
-- ---------------------------------------------------------
('U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U'), -- | U |
('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'), -- | X |
('U', 'X', '0', 'X', '0', '0', '0', '0', 'X'), -- | 0 |
('U', 'X', 'X', '1', '1', '1', '1', '1', 'X'), -- | 1 |
('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', 'X'), -- | Z |
('U', 'X', '0', '1', 'W', 'W', 'W', 'W', 'X'), -- | W |
('U', 'X', '0', '1', 'L', 'W', 'L', 'W', 'X'), -- | L |
('U', 'X', '0', '1', 'H', 'W', 'W', 'H', 'X'), -- | H |
('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X') -- | - |
);

function resolved (s : STD_ULOGIC_VECTOR) return STD_ULOGIC is
variable result : STD_ULOGIC := 'Z'; -- weakest state default
begin
-- the test for a single driver is essential otherwise the
-- loop would return 'X' for a single driver of '-' and that
-- would conflict with the value of a single driver unresolved
-- signal.
if (s'length = 1) then return s(s'low);
else
for i in s'range loop
result := resolution_table(result, s(i));
end loop;
end if;
return result;
end function resolved;

Additionally if you were to look at the truth table for wor and trior in the 1064 (Verilog) standard you'd find that wor works identically to using the std_ulogic subtype X01Z (which is also resolved, using the same resolution function shown above).

Further package std_logic_1164 provides To_X01Z conversion functions that can be used to pre-filter std_logic and std_logic_vector values to X01Z values. They are conversion functions (1 input, a return value from a pure function) and functions are expressions ( can be used for example in port map associations) and the result is base type compatible with std_logic.

If you only ever assign 'X', '0', '1' or 'Z' to a standard logic value And you provide a default value that is one of those four values you don't need to do anything to get the same effect as using wor in Verilog.

The To_X01Z functions can be used to filter MVL9 signal values ('U','X','0', '1', 'Z', 'W', 'L','H', '-') to 'X', '0', '1', 'Z' when assignment is out of your control.

VHDL's std_logic_1164 package already provides the functionality you're after.

Daniel Kho

unread,
Aug 2, 2014, 5:21:37 AM8/2/14
to
On Saturday, 2 August 2014 12:45:10 UTC+8, Dio Gratia wrote:

> Additionally if you were to look at the truth table for wor and trior in the 1064 (Verilog) standard you'd find that wor works identically to using the std_ulogic subtype X01Z (which is also resolved, using the same resolution function shown above).
>

Sorry, does the Verilog wor resolve '0' and '1' to an 'X'? Or will it be resolved to a '1'?

-dan

Dio Gratia

unread,
Aug 2, 2014, 6:47:50 PM8/2/14
to
On Saturday, August 2, 2014 9:21:37 PM UTC+12, Daniel Kho wrote:

> Sorry, does the Verilog wor resolve '0' and '1' to an 'X'? Or will it be
resolved to a '1'?


Opps! Wrong table, Dan is right. My bad.

4-4 from 1364-2005:

wor/trior 0 1 x z
0 0 1 x 0
1 1 1 1 1
x x 1 x x
z 0 1 x z

std_logic matches 4-2, wire/tri.

Which says yes a different resolution function for wor, and begs the question of
who can synthesize logic from single rail transfer gate models in VHDL.

A demo case for penance:

library ieee;
use ieee.std_logic_1164.all;

package wor_stuff is

type wortrior is ('X', '0', '1', 'Z');
type wortrior_vector is array (natural range <>) of wortrior;

function wor_trior (s: wortrior_vector) return wortrior;

subtype wor is wor_trior wortrior;
type wor_vector is array (natural range <>) of wor;

function wor_image(inp: wor_vector) return string;

end package;

package body wor_stuff is

type wor_table is array (wortrior, wortrior) of wortrior;

constant resolution_table : wor_table := (
-- --------------------------------
-- | X 0 1 Z | |
-- --------------------------------
('X', 'X', '1', 'X'), -- | X |
('X', '0', '1', '0'), -- | 0 |
('1', '1', '1', '1'), -- | 1 |
('X', '0', '1', 'Z') -- | Z |
);

function wor_trior ( s: wortrior_vector ) return wortrior is
variable result: wortrior := 'Z';
begin
if (s'length = 1) then return (s(s'low));
else
for i in s'range loop
result := resolution_table(result, s(i));
end loop;
end if;
return result;
end wor_trior;

function wor_image(inp: wor_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: wor_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(wortrior'IMAGE(input_str(i)));
end loop;
return image_str;
end;

end package body;

library ieee;
use ieee.std_logic_1164.all;
use work.wor_stuff.all;

entity cpu_reg_dummy is
generic ( value: wor_vector(3 downto 0) := (others => 'Z') );
port ( rddata_o: out wor_vector(3 downto 0) );
end entity;

architecture foo of cpu_reg_dummy is

begin
rddata_o <= value after 0.5 ns;
end architecture;

library ieee;
use ieee.std_logic_1164.all;
use work.wor_stuff.all;

entity foo is
end entity;

architecture fum of foo is

component cpu_reg_dummy
generic ( value: wor_vector(3 downto 0) := (others => 'Z') );
port ( rddata_o: out wor_vector(3 downto 0) );
end component;

signal rddata_o: wor_vector (3 downto 0);

begin

CPU_REG1:
cpu_reg_dummy
generic map (value => "0000")
port map (rddata_o => rddata_o);

CPU_REG2:
cpu_reg_dummy
generic map (value => "1001")
port map (rddata_o => rddata_o);

CPU_REG3:
cpu_reg_dummy
generic map (value => "ZZZZ")
port map (rddata_o => rddata_o);

CPU_REG4:
cpu_reg_dummy
generic map (value => "ZZZX")
port map (rddata_o => rddata_o);

WHAT:
process
begin
wait for 0.6 ns;
report "rddata_o = " & wor_image(rddata_o);
wait;
end process;
end architecture;

Which analyzes, elaborates and simulates the test case foowith the following
assertion output:

** Note: 600ps+0: Report Note: rddata_o = 1001
Process :foo:what
File wor.vhdl, Line 113

(and yes the resolution function wor_trior is shamelessly derived from package
std_logic_1164's resolution function).

Daniel Kho

unread,
Aug 3, 2014, 11:07:48 AM8/3/14
to
On Saturday, 2 August 2014 01:47:30 UTC+8, Mark Curry wrote:
> Sorry, should have been more clear. Those are all just instaciations.
>
> The "multiple driver" read_data is all within `BUS_CONNNECT.
>
> To expand it (leaving some connections out to synplify):
>
>
>
> wor rddata_o;
>
> cpu_reg cpu_reg1 ( .addr_i( addr_i ), .cs_i( cs_i ), .wrdata_i( wrdata_i ), .rwn_i( rwn_i ), .rddata_o( rddata_o ) );
>
> cpu_reg cpu_reg2 ( .addr_i( addr_i ), .cs_i( cs_i ), .wrdata_i( wrdata_i ), .rwn_i( rwn_i ), .rddata_o( rddata_o ) );
>
> cpu_reg cpu_reg3 ( .addr_i( addr_i ), .cs_i( cs_i ), .wrdata_i( wrdata_i ), .rwn_i( rwn_i ), .rddata_o( rddata_o ) );
>
>
>
> rddata_o has multiple drivers. I want them resolved like a verilog 'wor', but
>
> in VHDL. I'm having trouble figuring out how to tie the VHDL "resolution function" "resolved_wor"
>
> to the single net "rddata_o". "rddata_o" is both the input, and output of the function...
>
> How do I hook it up?
>
>
>
> --Mark


architecture rtl of test is
signal rddata_o:resolved_wor std_ulogic;

/* declare the other internal non-resolved signals here (addr_i,
cs_i, wrdata_i, rwn_i).
*/

begin
cpu_reg1: entity work.cpu_reg(rtl) port map(addr_i=>addr_i, cs_i=>cs_i, wrdata_i=>wrdata_i, rwn_i=>rwn_i, rddata_o=>rddata_o);

cpu_reg2: entity work.cpu_reg(rtl) port map(addr_i=>addr_i, cs_i=>cs_i, wrdata_i=>wrdata_i, rwn_i=>rwn_i, rddata_o=>rddata_o);

cpu_reg3: entity work.cpu_reg(rtl) port map(addr_i=>addr_i, cs_i=>cs_i, wrdata_i=>wrdata_i, rwn_i=>rwn_i, rddata_o=>rddata_o);

end architecture rtl;

Here all the 3 entity instances (cpu_reg1, cpu_reg2, cpu_reg3) will be driving the single resolved wire "rddata_o". The resolved_wor resolution function will be used to resolve the multiple drivers.

Of course, you can have more instances driving the net, without needing to specify the array width (or the number of drivers) into the resolution function, provided your function does not constrain the input argument's width.

To write the resolution function 'resolved_wor', you can use the examples Dio or I provided earlier. Just place it within a VHDL package, and remember to add a library-use clause to 'import' this package into your design.

-dan

Dio Gratia

unread,
Aug 4, 2014, 12:33:19 AM8/4/14
to

VHDL2008 also has this neat feature the Jim and Peter call Resolved Elements in 3.2 of their book VHDL2008 Just the New Stuff. If you were to look through previous versions of the standard you'd find it's new, although parts those standards imply you can do it while otherwise explicitly not allowing it.

The idea is that you can specify the resolution function to use on elements of a composite types subtype declaration.

Previously if I provided a resolution indication on a composite type:

signal rddata_o: rddata_o_resolv std_logic_vector (rddata_o_range);

The resolution function would have to be of the signal's type in this case std_logic_vector (and it can be, because a composite type resolution function will replace any element resolution).

So they've added a feature to the language to allow you to specify element resolution:

signal rddata_o: (wor_trior) std_logic_vector (rddata_o_range);

And this works for records two, where you'd specify multiple resolution function names inside the parentheses.

Resolution is subtype bound and every declaration of a signal is a subtype declaration.

So, historically why this is important can be demonstrated by writing a VHDL design specification compatible with a previous edition of the spec.

This is the previous demonstration re-written to specify a resolution function for a std_logic_vector array subtype:

library ieee;
use ieee.std_logic_1164.all;

package wor_std is
subtype rddata_o_range is integer range 3 downto 0;
type rddata_o_array is array (natural range <>) of std_logic_vector(rddata_o_range);

function rddata_o_resolv (s: rddata_o_array) return std_logic_vector;

function wor_trior (s: std_logic_vector) return std_logic;

function slv_image(inp: std_logic_vector) return string;

end package;

package body wor_std is

type wor_table is array (X01Z, X01Z) of std_ulogic;

constant resolution_table : wor_table := (
-- --------------------------------
-- | X 0 1 Z | |
-- --------------------------------
('X', 'X', '1', 'X'), -- | X |
('X', '0', '1', '0'), -- | 0 |
('1', '1', '1', '1'), -- | 1 |
('X', '0', '1', 'Z') -- | Z |
);

function wor_trior ( s: std_logic_vector ) return std_logic is
variable result: std_logic := 'Z';
begin
if (s'length = 1) then return (To_X01Z(s(s'low)));
else
for i in s'range loop
result := resolution_table(result, To_X01Z(s(i)));
end loop;
end if;
return result;
end wor_trior;

function rddata_o_resolv (s: rddata_o_array) return std_logic_vector is
variable wor: std_logic_vector (s'range);
variable result: std_logic_vector (rddata_o_range);
begin
for i in result'range loop
for j in s'range loop
wor(j) := s(j)(i);
end loop;
report "wor = " & slv_image(wor);
result(i) := wor_trior(wor);
end loop;
return result;
end function;

function slv_image(inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end;

end package body;

library ieee;
use ieee.std_logic_1164.all;
use work.wor_std.all;

entity cpu_reg_dummy is
generic ( value: std_logic_vector(3 downto 0) := (others => 'Z') );
port ( rddata_o: out std_logic_vector(3 downto 0) );
end entity;

architecture foo of cpu_reg_dummy is

begin
rddata_o <= value after 0.5 ns;
end architecture;

library ieee;
use ieee.std_logic_1164.all;
use work.wor_std.all;

entity foe is
end entity;

architecture fum of foe is

component cpu_reg_dummy
generic ( value: std_logic_vector(rddata_o_range) := (others => 'Z') );
port ( rddata_o: out std_logic_vector(rddata_o_range) );
end component;

signal rddata_o: rddata_o_resolv std_logic_vector (rddata_o_range);
-- signal rddata_o: (wor_trior) std_logic_vector (rddata_o_range); -- -2008

begin

CPU_REG1:
cpu_reg_dummy
generic map (value => "0000")
port map (rddata_o => rddata_o);

CPU_REG2:
cpu_reg_dummy
generic map (value => "1001")
port map (rddata_o => rddata_o);

CPU_REG3:
cpu_reg_dummy
generic map (value => "ZZZZ")
port map (rddata_o => rddata_o);

CPU_REG4:
cpu_reg_dummy
generic map (value => "ZZZX")
port map (rddata_o => rddata_o);

WHAT:
process
begin
wait for 0.6 ns;
report "rddata_o = " & slv_image(rddata_o);
wait;
end process;
end architecture;

The really harsh part of using a tool complying to an earlier standard is for the resolution function rddata_o_resolv we can't specify an array type with a unconstrained element type, which means for the demo the index range of rddata_o has been fixed where everything can see it in the package wor_std.

This gives you an idea what a simulator does, assembling arrays of each element and resolving those.

wor_std.vhdl:50:13:@500ps:(report note): wor = 01zz
wor_std.vhdl:50:13:@500ps:(report note): wor = 00zz
wor_std.vhdl:50:13:@500ps:(report note): wor = 00zz
wor_std.vhdl:50:13:@500ps:(report note): wor = 01zx
wor_std.vhdl:126:9:@600ps:(report note): rddata_o = 1001

And the line 50 reports are in the resolution function and taking those values vertically we see values written out by the cpu_reg_dummy instantiations.

Take horizontally the wor_trior resolution of those tells us what each of the index values for rdata_o is going to be.

You can also note that those logical operators for std_ulogic related types use table look up to speed things up.

Mark Curry

unread,
Aug 5, 2014, 1:01:19 PM8/5/14
to
In article <afcfd1a5-253b-4c9f...@googlegroups.com>,
Dan, and all.

Thanks for the detailied example (and having the patience to beat its use thru my thick skull).

That is indeed a useful tool in the language. I'm going to play around with this
when I get some time, and see what the tool support is like.

Thanks,

Mark


0 new messages