On 22/08/2012 23:46, Jim Lewis wrote:
> Hi Brent,
> I see a record as an abstraction that hides details and limits
> the number of places where these details need to be known.
> Your example enumerates a very simple case where the record
> does not descend through any block to a subblock. So in your
> example, perhaps it is reasonable to expect the design interface
> to know about the elements of the record.
>
> However, if in entity master or slave, there is a subblock that
> actually handled all of the interactions with the t_cpu_bus typed
> object and then perhaps it is not reasonable to expect master and
> slave to know about the elements of t_cpu_bus. Basically at that
> point, I might as well have use single element ports.
Well, I was going to put together a multi-level example, but that then got me
thinking. John Aynsley's comments then just confirmed it for me. We've been
skirting around the real issue and what we really want is a VHDL interface
language structure.
OK let's take the complexity up a level to a multi-master bus. We now need a
pseudo-master to control the bus - a bus arbiter.
In FPGA and a high proportion of ASIC designs, each slave return signals will
need to be mux'ed back into the master(s). They don't have tri-state capability.
Similarly, every master's control signals (sub-master?) will need to be mux'ed
into a main master output by the bus arbiter
So let's generate this capability with hierarchically defined types as before.
package cpu_bus_pkg is
constant master_max_jc : positive := 2;
subtype master_cs_jrt is natural range master_max_jc-1 downto 0;
constant slave_max_jc : positive := 7+master_max_jc+1; --+1 for arbiter
slave return
subtype slave_cs_jrt is natural range slave_max_jc-1 downto 0;
subtype adr_vst is std_logic_vector(15 downto 0);
subtype dat_vst is std_logic_vector(15 downto 0);
subtype m_en_vst is std_logic_vector(master_cs_jrt);
subtype s_en_vst is std_logic_vector(slave_cs_jrt);
type master_rt is --Master record
record
adr_vl : adr_vst; --Address
dat_vl : dat_vst; --Data from master to slave
we_l : std_logic; --Write enable from master
en_vl : s_en_vst; --Slave enable from master
end record master_rt;
type master_at is
array(master_cs_jrt) of master_rt; --Array of master signals to arbiter
type arbiter_rt is --Arbiter control record
record
master_al : master_at; --Array of hierarchical master
records to arbiter
bus_req_vl : m_en_vst; --Bus requests from masters
bus_grnt_vl : m_en_vst; --Bus grants to masters
end record arbiter_rt;
type slave_rt is --Slave record
record
sdt_vl : dat_vst; --Data from slave to master
ack_l : std_logic; --Acknowledge from slave
err_l : std_logic; --Error from slave
end record slave_rt;
type slave_at is
array(slave_cs_jrt) of slave_rt; --Array of slave return records
type cpu_bus_rt is
record
arbiter_rl : arbiter_rt; --Arbiter master control record
master_rl : master_rt; --Bus master record from arbiter
slave_al : slave_at; --Array of hierarchical slave records
end record cpu_bus_rt;
--now the new interface block
interface cpu_bus_if of cpu_bus_rt is
port config arbiter_cfg is (
port (
arbiter_rl : comp (
master_al, --Array of hierarchical master
records into arbiter
breq_vl : in; --Bus requests from masters
bgrnt_vl : buffer; --Bus grants to masters
);
master_rl : out; --Bus master interface output
slave_al : in --Bus slave interface input
);
end port config arbiter_cfg;
port config master_cfg is (
generic (
master_cs_jg : master_cs_jrt
);
port (
arbiter_rl : comp (
master_al(master_cs_jrt),
breq_vl(master_cs_jrt) : buffer;
bgrnt_vl(master_cs_jrt) : in;
master_al(others),
breq_vl(others),
bgrnt_vl(others) : null
);
master_rl : in;
slave_sl : in
);
end port config master_cfg;
port config slave_cfg is (
generic (
slave_cs_jg : slave_cs_jrt
);
port (
arbiter_rl : null;
master_rl : in;
slave_al(slave_cs_jg) : buffer;
slave_al(others) : null
);
end port config slave_cfg;
end interface cpu_bus_if;
end package cpu_bus_pkg;
This gives a very structured design of the CPU multi-master/arbiter/slave bus.
This is also a first stab at a VHDL 'interface' mixed structure/port/data hybrid
type. An 'interface body' structure could be added to include functions/procedures
for checking/generation of bus cycles, protocols, etc. My compelling use case
for this, you guessed it - SystemVerilog!
Now we define the master and slave entities and I use buffer ports because we
should only have single source drivers on the nets and I like them!
--Arbiter entity
use work.cpu_bus_pkg.all
entity arbiter is
port (
clk_i : in std_logic;
cpu_bus_h : cpu_bus_if(arbiter_cfg)
cpu_bus_rt;
rst_i : in std_logic
);
end entity arbiter;
--Master entity
use work.cpu_bus_pkg.all
entity master is
generic (
master_cs_jg : master_cs_jrt
);
port (
clk_i : in std_logic;
cpu_bus_h : cpu_bus_if(master_cfg)
cpu_bus_rt(
master_cs_jg => master_cs_jg);
rst_i : in std_logic
);
end entity master;
--Slave entity
use work.cpu_bus_pkg.all
entity slave is
generic (
slave_cs_jg : slave_cs_jrt
);
port (
clk_i : in std_logic;
cpu_bus_h : cpu_bus_if(slave_cfg)
cpu_bus_rt(
slave_cs_jg => slave_cs_jg);
rst_i : in std_logic
);
end entity slave;
Now let's introduce some hierarchy - a master & slaves block, a slaves only block
and arbiter and 2nd master at the top level.
Master and slaves block first:bgrnt_vl
--master plus slaves block
use work.cpu_bus_pkg.all
entity m_plus_s is
port (
clk_i : in std_logic;
cpu_bus_h : comp (
arbiter_rl : comp (
master_al,
breq_vl : buffer;
bgrnt_vl : in
);
master_rl : in;
slave_al : in
) cpu_bus_rt;
rst_i : in std_logic
);
end entity master;
architecture rtl of m_plus_s is
begin
i_master : master
generic map (
master_cs_jg => 1.
)
port map (
clk_i => clk_i,
cpu_bus_h => cpu_bus_h,
rst_i => rst_i
);
i_slave_4 : slave
generic map (
slave_cs_jg => 4 --internally 'cpu_bus_h.en(id)'
is the
) --only enable port that exists
port map (
clk_i => clk_i,
cpu_bus_h => cpu_bus_h, --and is mapped to cpu_bus.en(4)
rst_i => rst_i
);
i_slave_2 : slave
generic map (
slave_cs_jg => 2 --internally 'cpu_bus_h.en(id)'
is the
) --only enable port that exists
port map (
clk_i => clk_i,
cpu_bus_h => cpu_bus_h, --and is mapped to cpu_bus.en(2)
rst_i => rst_i
);
end architecture rtl;
Slaves only block next:
--slaves only block
use work.cpu_bus_pkg.all
entity s_only is
port (
clk_i : in std_logic;
cpu_bus_h : comp (
arbiter_rl : null;
master_rl : in;
slave_al : out
) cpu_bus_rt;
);
end entity s_only;
architecture rtl of s_only is
begin
i_master : arbiter --arbiter at top level
port map (
clk_i => clk_i,
cpu_bus_h => cpu_bus_h,
rst_i => rst_i
);
i_master : master --2nd master at top level
generic map (
master_cs_jg => 2.
)
port map (
clk_i => clk_i,
cpu_bus_h => cpu_bus_h,
rst_i => rst_i
);
i_slave_3 : slave
generic map (
slave_cs_jg => 3 --internally 'bus.en(id)' is the
) --only enable port that exists
port map (
clk_i => clk_i,
cpu_bus_h => cpu_bus_h, --and is mapped to cpu_bus.en(3)
rst_i => rst_i
);
i_slave_7 : slave
generic map (
slave_cs_jg => 7 --internally 'bus.en(id)' is the
) --only enable port that exists
port map (
clk_i => clk_i,
cpu_bus_h => cpu_bus_h, --and is mapped to cpu_bus.en(7)
rst_i => rst_i
);
end architecture rtl;
And finally the top level. The previous two levels interconnect using their
respective composite record port. At the top level we need a signal of this
record type and I'll add another slave at this level:
--Top level
use work.cpu_bus_pkg.all
entity top_level is
port (
clk_i : in std_logic;
rst_i : in std_logic
);
end entity top_level;
architecture rtl of top_level is
signal cpu_bus_rs : cpu_bus_rt;
begin
i_m_plus_s : m_plus_s
port map (
clk_i => clk_i,
cpu_bus_h => cpu_bus_rs,
rst_i => rst_i
);
i_slave_6 : slave
generic map (
slave_cs_jg => 6 --internally 'bus.en(id)' is the
) --only enable port that exists
port map (
clk_i => clk_i,
cpu_bus_h => cpu_bus_rs, --and is mapped to cpu_bus.en(6)
rst_i => rst_i
);
i_s_only : s_only
port map (
clk_i => clk_i,
cpu_bus_h => cpu_bus_rs,
rst_i => rst_i
);
end architecture rtl;
The structural levels now become very clean and extremely easy to trace
through. (Avoiding the need for those block level tools!)
Let's pull this apart as there must be loads of problems now. The various
levels may have topology introduced port connection problems. The interface
proposition must generate lots of better ways to do this and at the moment is
just providing user defined port modes.
The complexity of this example is really just to show the various uses of the
proposed new language semantics and it's the flexibility and power of these
rather than whether the example is valid that is important.
The structure of the interface port configurations, along with the bus record
data type, pushes the glue logic generation back into the masters for slave
mux'ing and chip select decoding, with master mux'ing and bus arbitration into
the arbiter.
The verbosity of all this just goes to prove why I must never be allowed to
edit the TWiki ;-)
I'm going to sit back for a bit now and let you all argue the toss over what
does and doesn't work.
--
Regards,
Brent Hayhoe.
Aftonroy Limited Telephone: +44 (0)20-8449-1852
135 Lancaster Road,
New Barnet, Mobile: +44 (0)79-6647-2574
Herts., EN4 8AJ, U.K. Email: Brent.Hayhoe@Aftonroy.com
Registered Number: 1744190 England.
Registered Office:
4th Floor, Imperial House,
15 Kingsway,
London, WC2B 6UN, U.K.
--
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
Received on Fri Aug 24 17:31:46 2012
This archive was generated by hypermail 2.1.8 : Fri Aug 24 2012 - 17:32:15 PDT