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

From: Peter Flake <flake@elda.demon.co.uk>
Date: Thu Aug 30 2012 - 06:15:03 PDT

Hi Brent,

It turns out that SystemVerilog would be better if modports could be defined
outside interfaces (which maybe should have been called channels). It is
too late to change this, but we should not make the same mistake in VHDL.

I think that the interface construct in your example can be removed, and we
can just use the port config. I have done this below.

BTW I do not understand exactly what comp is doing.

Regards,

Peter Flake

   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 port configs

       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 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 : arbiter_cfg;
       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 : master_cfg(
                         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 : slave_cfg(
                         slave_cs_jg => slave_cs_jg);
       rst_i : in std_logic
     );
   end entity slave;

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;

-- 
This message has been scanned for viruses and
dangerous content by MailScanner, and is
believed to be clean.
Received on Thu Aug 30 06:15:39 2012

This archive was generated by hypermail 2.1.8 : Thu Aug 30 2012 - 06:16:15 PDT