Candidate 1: Bundles specified as a type definition
Think of a bundle as being an enhanced version of a record. A bundle uses the concept of conjugated modes, while the traditional record does not.
Example of the proposed bundle specification:
type if_bndl is bundle
signal clk, reset: in std_ulogic;
-- both master and slave can drive at different times.
signal serial: inout std_ulogic;
type m2s is bundle
-- master to slave direction.
signal data: mst_to_slv t;
end bundle m2s;
type s2m is bundle
-- slave to master direction.
signal resp: slv_to_mst t;
signal ack: slv_to_mst std_ulogic;
signal busy: slv_to_mst std_ulogic
end bundle s2m;
-- direction-less objects.
type common is record
signal s1: std_ulogic := '0'; -- Permanent objects of the bundle
signal s2: std_ulogic_vector(ub downto 0) := (others => '0');
shared variable sv : my_protected_type;
end record common;
end bundle if_bndl;
<Brent Hayhoe> 2015-07-01- This candidate would appear to associate the
type object with not only modes but also
bundle objects (signals, variables, constants and bundles). I don't think that this will work within the language as it starts to mix up object relationships.
At present:
- a signal has a type associated with it.
- A port has a signal and a mode associated with it.
This is a sort of hierarchical association which makes it easier to define associations and operations based on this. I think this candidate will confuse this.
</Brent Hayhoe>
<Daniel Kho> 2015-11-19- While your statement is true regarding this proposal as trying to associate the "type" object with modes and bundle objects, consider the "record" structure. VHDL records are similarly defined, at least syntactically. Comparing the syntax of a record object with this proposed bundle (with modes) object leads me to believe that the proposed syntax is consistent with other objects already available in VHDL. Just for the record, a VHDL record type may look like the following:
type if_recrd is record
clk, reset: std_ulogic;
serial: std_ulogic;
data: t;
resp: t;
...
end record if_recrd;
</Daniel Kho>
Candidate 1 Use Cases
Case 1: Bundle using generics from the enclosing uninstantiated package
library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all;
package bundlesTLM is
generic(type t; ub: integer := 7);
mode mst_to_slv is default;
mode slv_to_mst is conjugated of mst_to_slv;
/* The proposed bundle specification. */
type if_bndl is bundle
signal clk, reset: in std_ulogic;
-- both master and slave can drive at different times.
signal serial: inout std_ulogic;
type m2s is bundle
-- master to slave direction.
signal data: mst_to_slv t;
end bundle m2s;
type s2m is bundle
-- slave to master direction.
signal resp: slv_to_mst t;
signal ack: slv_to_mst std_ulogic;
signal busy: slv_to_mst std_ulogic
end bundle s2m;
-- direction-less objects.
type common is record
signal s1: std_ulogic := '0'; -- Permanent objects of the bundle
signal s2: std_ulogic_vector(ub downto 0) := (others => '0');
shared variable sv : my_protected_type;
end record common;
end bundle if_bndl;
end package bundlesTLM;
library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all;
package bundlesTransactor is new work.bundlesTLM generic map(
t => signed(15 downto 0),
ub => 7
);
Assume we have master and slave entities whose declarations have been defined as:
library work; use work.bundlesTransactor.all;
entity master is port(
d: t;
i_port: if_bndl
);
end entity master;
library work; use work.bundlesTransactor.all;
entity slave is port(
i_port: if_bndl
);
end entity slave;
Our top-level design could look like:
library work; use work.bundlesTransactor.all;
entity top is
port(
data_to_mst: in t;
i_port: if_bndl
);
end entity top;
architecture rtl of top is
signal i_bundle: if_bndl;
begin
u_master: entity work.master(rtl)
port map(
d => data_to_mst,
-- bundle
i_port.clk => i_port.clk,
i_port.reset => i_port.reset,
i_port.serial => i_bundle.serial,
i_port.m2s => i_bundle.m2s,
i_port.s2m => i_bundle.s2m
);
u_slave: entity work.slave(rtl)
port map(
i_port.clk => i_port.clk,
i_port.reset => i_port.reset,
i_port.serial => i_bundle.serial,
i_port.m2s => i_bundle.m2s,
i_port.s2m => i_bundle.s2m
);
-- these clock and reset assignments may not be necessary.
i_bundle.clk <= i_port.clk;
i_bundle.reset <= i_port.reset;
-- i_port.clk and i_port.reset are driven externally.
i_port.m2s <= i_bundle.m2s;
i_port.s2m <= i_bundle.s2m;
end architecture rtl;
Case 2: Bundle using generics from a generic package
library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all;
package tlm is
generic(type t; ub: integer := 7);
end package tlm;
library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all;
package bundlesTLM is
generic(
package i_transactor is new work.tlm generic map(<>)
);
use i_transactor.all;
mode mst_to_slv is default;
mode slv_to_mst is conjugated of mst_to_slv;
/* The proposed bundle specification. */
type if_bndl is bundle
signal clk, reset: in std_ulogic;
-- both master and slave can drive at different times.
signal serial: inout std_ulogic;
type m2s is bundle
-- master to slave direction.
signal data: mst_to_slv i_transactor.t;
end bundle m2s;
type s2m is bundle
-- slave to master direction.
signal resp: slv_to_mst i_transactor.t;
signal ack: slv_to_mst std_ulogic;
signal busy: slv_to_mst std_ulogic
end bundle s2m;
-- direction-less objects.
type common is record
signal s1: std_ulogic := '0'; -- Permanent objects of the bundle
signal s2: std_ulogic_vector(i_transactor.ub downto 0) := (others => '0');
shared variable sv : my_protected_type;
end record common;
end bundle if_bndl;
end package bundlesTLM;
library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all;
package bundles0_tlm is new work.tlm generic map(
t => signed(15 downto 0),
ub => 7
);
library ieee; use ieee.std_logic_1164.all, ieee.numeric_std.all;
package bundlesTransactor is new work.bundlesTLM generic map(
i_transactor => work.bundles0_tlm
);
Assume we have master and slave entities whose declarations have been defined as:
library work; use work.bundlesTransactor.all; -- makes i_transactor visible
entity master is port(
d: i_transactor.t;
i_port: if_bndl
);
end entity master;
library work; use work.bundlesTransactor.all;
entity slave is port(
i_port: if_bndl
);
end entity slave;
Our top-level design could look like:
library work; use work.bundlesTransactor.all;
entity top is
port(
data_to_mst: in i_transactor.t;
i_port: if_bndl
);
end entity top;
architecture rtl of top is
signal i_bundle: if_bndl;
begin
u_master: entity work.master(rtl)
port map(
d => data_to_mst,
-- bundle
i_port.clk => i_port.clk,
i_port.reset => i_port.reset,
i_port.serial => i_bundle.serial,
i_port.m2s => i_bundle.m2s,
i_port.s2m => i_bundle.s2m
);
u_slave: entity work.slave(rtl)
port map(
i_port.clk => i_port.clk,
i_port.reset => i_port.reset,
i_port.serial => i_bundle.serial,
i_port.m2s => i_bundle.m2s,
i_port.s2m => i_bundle.s2m
);
-- these clock and reset assignments may not be necessary.
i_bundle.clk <= i_port.clk;
i_bundle.reset <= i_port.reset;
-- i_port.clk and i_port.reset are driven externally.
i_port.m2s <= i_bundle.m2s;
i_port.s2m <= i_bundle.s2m;
end architecture rtl;
As a shorthand, could we also use a variant of "(<>)" or "others"?
u_master: entity work.master(rtl)
port map(
d => data_to_mst,
-- bundle
i_port.clk => i_port.clk,
i_port.reset => i_port.reset,
i_port.others => i_bundle.<>
);