📄 pci_arb.vhd
字号:
gnt_n : out std_logic_vector(0 to NB_AGENTS-1); -- bus grant pclk : in clk_type; -- APB clock prst_n : in std_logic; -- APB reset 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 + -