Re: [vhdl-200x] Records with diectional subtypes

From: Brent Hayhoe <Brent.Hayhoe@Aftonroy.com>
Date: Fri Aug 24 2012 - 17:31:11 PDT

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