⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci_arb.vhd

📁 sparc org, vhdl rtl code
💻 VHD
📖 第 1 页 / 共 2 页
字号:
         pbi     : in  APB_Slv_In_Type;                     -- APB inputs
         pbo     : out APB_Slv_Out_Type                     -- APB outputs
         );

end pci_arb;


architecture rtl of pci_arb is
   signal owner0, owneri0   : agent_t;  -- current owner in level 0
   signal owner1, owneri1   : agent_t;  -- current owner in level 1
   signal cown, cowni       : agent_t;  -- current level
   signal rearb, rearbi     : std_logic;            -- re-arbitration flag
   signal tout, touti       : std_logic_vector(3 downto 0);  -- timeout counter
   signal turn, turni       : std_logic;            -- turnaround cycle
   signal arb_lvl, arb_lvli : arb_lvl_t := ARB_LVL_C;  -- level registers

   type nmstarr is array (0 to 3) of agentno_t;
   type nvalarr is array (0 to 3) of boolean;

   
begin  -- rtl
   
   ----------------------------------------------------------------------------
   -- PCI ARBITER 
   ----------------------------------------------------------------------------
   -- purpose: Grants the bus depending on the request signals. All agents have
   -- equal priority, if another request occurs during a transaction, the bus is
   -- granted to the new agent. However, PCI protocol specifies that the master
   -- can finish the current transaction within the limit of its latency timer.
   arbiter : process(cown, owner0, owner1, req_n, rearb, tout, turn, frame_n,
                     arb_lvl, rst_n)

      variable owner0v, owner1v : agentno_t;  -- integer variables for current owner
      variable new_request      : agentno_t := 0;  -- detected request
      variable nmst             : nmstarr;
      variable nvalid           : nvalarr;

   begin  -- process arbiter

      -- default assignments
      rearbi  <= rearb;
      owneri0 <= owner0;
      owneri1 <= owner1;
      cowni   <= cown;
      touti   <= tout;
      turni   <= '0';                    -- no turnaround
      
      -- re-arbitrate once during the transaction,
      -- or when timeout counter expired (bus idle).
      if (frame_n = '0' and rearb = '0') or turn = '1' then

         owner0v        := conv_integer(owner0);
         owner1v        := conv_integer(owner1);
         new_request    := conv_integer(cown);
         nvalid(0 to 3) := (others => false);
         nmst(0 to 3)   := (others => 0);
         
         -- Determine next request in both priority levels
         rob : for i in NB_AGENTS-1 downto 0 loop
            -- consider all masters with valid request
            if req_n(i) = '0' then
               -- next in prio level 0
               if arb_lvl(i) = '0' then
                  if i > owner0v then
                     nmst(0) := i; nvalid(0) := true;
                  elsif i < owner0v then
                     nmst(1) := i; nvalid(1) := true;
                  end if;
               -- next in prio level 1
               elsif arb_lvl(i) = '1' then
                  if i > owner1v then
                     nmst(2) := i; nvalid(2) := true;
                  elsif i < owner1v then
                     nmst(3) := i; nvalid(3) := true;
                  end if;
               end if;                  -- arb_lvl
            end if;                     -- req_n
         end loop rob;

         -- select new master
         if nvalid(0) then              -- consider level 0 before wrap
            new_request    := nmst(0);
            owner0v        := nmst(0);
         -- consider level 1 only once, except when no request in level 0
         elsif owner0v /= NB_AGENTS-1 or not nvalid(1) then
            if nvalid(2) then           -- level 1 before wrap
               new_request := nmst(2);
               owner0v     := NB_AGENTS-1;
               owner1v     := nmst(2);
            elsif nvalid(3) then        -- level 1 after wrap
               new_request := nmst(3);
               owner0v     := NB_AGENTS-1;
               owner1v     := nmst(3);
            end if;
         elsif nvalid(1) then           -- level 0 after wrap
            new_request    := nmst(1);
            owner0v        := nmst(1);
         end if;

         owneri0 <= std_logic_vector(conv_unsigned(owner0v, ARB_SIZE));
         owneri1 <= std_logic_vector(conv_unsigned(owner1v, ARB_SIZE));
         
         -- rearbitration if any request asserted & different from current owner
         if conv_integer(cown) /= new_request then
            -- if idle state: turnaround cycle required by PCI standard
            cowni <= std_logic_vector(conv_unsigned(new_request, ARB_SIZE));
            touti <= "0000";                 -- reset timeout counter
            if turn = '0' then
               rearbi <= '1';           -- only one re-arbitration
            end if;
         end if;
      elsif frame_n = '1' then
         rearbi <= '0';
      end if;

      -- if frame deasserted, but request asserted: count timeout
      if req_n = all_ones then          -- no request: prepare timeout counter
         touti <= "1111";
      elsif frame_n = '1' then          -- request, but no transaction
         if tout = "1111" then              -- timeout expired, re-arbitrate
            turni <= '1';               -- remove grant, turnaround cycle
            touti <= "0000";                 -- next cycle re-arbitrate
         else
            touti <= tout + 1;
         end if;
      end if;

      grant : for i in 0 to NB_AGENTS-1 loop
         if i = conv_integer(cown) and turn = '0' then
            gnt_n(i) <= '0';
         else  
            gnt_n(i) <= '1';
         end if;
      end loop grant;

      -- synchronous reset
      if rst_n = '0' then
         touti    <= "0000";
         cowni    <= (others => '0');
         owneri0  <= (others => '0');
         owneri1  <= (others => '0');
         rearbi   <= '0';
         turni    <= '0';
      end if;
      
   end process arbiter;

   arb_lvl(NB_AGENTS-1) <= '1';  -- always prio 1.

   fixed_prios : if not APB_PRIOS generate  -- assign constant value
      arb_lvl(NB_AGENTS-2 downto 0) <= ARB_LVL_C(NB_AGENTS-2 downto 0);
   end generate fixed_prios;

   -- Generate APB regs and APB slave
   apbgen : if APB_PRIOS generate
      -- purpose: APB read and write of arb_lvl configuration registers
      -- type:    memoryless
      -- inputs:  pbi, arb_lvl, prst_n
      -- outputs: pbo, arb_lvli
      config : process (pbi, arb_lvl, prst_n)
         
      begin  -- process config
         arb_lvli <= arb_lvl;

         pbo.PRDATA <= (others => '0');  -- default for unimplemented addresses
         
         -- register select at (byte-) addresses 0x80
         if pbi.PADDR(7 downto 0) = "10000000" and pbi.PSEL = '1' then -- address select
            if (pbi.PWRITE and pbi.PENABLE) = '1' then  -- APB write
                  arb_lvli <= pbi.PWDATA(NB_AGENTS-1 downto 0);
            end if;
            pbo.PRDATA(NB_AGENTS-1 downto 0) <= arb_lvl;
         end if;
         -- synchronous reset
         if prst_n = '0' then
            arb_lvli <= ARB_LVL_C;          -- assign default value
         end if;
      end process config;

      -- APB registers

      apb_regs : process (pclk)
      begin  -- process regs
         -- activities triggered by asynchronous reset (active low)
         if pclk'event and pclk = '1' then  -- '
            arb_lvl(NB_AGENTS-2 downto 0) <= arb_lvli(NB_AGENTS-2 downto 0);
         end if;
      end process apb_regs;

   end generate apbgen;

   -- PCI registers

   regs0 : process (clk)
      
   begin  -- process regs
      if clk'event and clk = '1' then  -- '
         tout    <= touti;
         owner0  <= owneri0;
         owner1  <= owneri1;
         cown    <= cowni;
         rearb   <= rearbi;
         turn    <= turni;
      end if;
   end process regs0;

end rtl;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -