📄 pci_arb.vhd
字号:
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 + -