LIBRARY ieee; USE ieee.std_logic_1164.ALL; -- simple arbiter. Implements round robin priority scheme -- Author: B. Reese, Summer'97 VHDL class entity arbiter is port ( clk : in std_logic; -- input clock reset : in std_logic; -- input reset breq : in std_logic_vector(7 downto 0); -- bus request bgrant : out std_logic_vector(7 downto 0); -- bus grant bbusy : in std_logic -- bus busy ); end arbiter; architecture behv of arbiter is type fsmstate is (NOGRANTS,ONEGRANT_WAIT,ONEGRANT,OVERLAP,OVERLAP2); signal pstate,nstate : fsmstate; signal breq_int: std_logic_vector(7 downto 0); signal bgrant_int: std_logic_vector(7 downto 0); signal pending_next, pending: std_logic_vector(2 downto 0); signal current_next, current: std_logic_vector(2 downto 0); signal current_mux :std_logic; signal startp_next, startp: std_logic_vector(2 downto 0) := "000"; signal request,request_int: std_logic_vector(2 downto 0); signal valid_req: std_logic; signal load_pending, load_current, load_startp: std_logic; signal bgrant_set, bgrant_clr: std_logic_vector(7 downto 0); signal bgrant_set_index, bgrant_clr_index:std_logic_vector (2 downto 0); signal bgrant_set_all: std_logic; signal bgrant_load : std_logic; signal bgrant_clr_en : std_logic; signal bgrant_set_en : std_logic; signal c:std_logic_vector(3 downto 0); begin -- dumb 3 bit incrementer inc3bit:process (startp) begin startp_next <= "000"; if (startp = "000") then startp_next <= "001"; end if; if (startp = "001") then startp_next <= "010"; end if; if (startp = "010") then startp_next <= "011"; end if; if (startp = "011") then startp_next <= "100"; end if; if (startp = "100") then startp_next <= "101"; end if; if (startp = "101") then startp_next <= "110"; end if; if (startp = "110") then startp_next <= "111"; end if; if (startp = "111") then startp_next <= "000"; end if; end process inc3bit; -- basic priority process, determines priority pending -- will give NEXT pending request is current grant is asserted rcheck: process (breq_int,bgrant_int) begin valid_req <= '0'; request_int <= "000"; if ((breq_int(7) = '0')) then valid_req <= '1'; request_int <= "111"; end if; if ((breq_int(6) = '0')) then valid_req <= '1'; request_int <= "110"; end if; if ((breq_int(5) = '0')) then valid_req <= '1'; request_int <= "101"; end if; if ((breq_int(4) = '0')) then valid_req <= '1'; request_int <= "100"; end if; if ((breq_int(3) = '0')) then valid_req <= '1'; request_int <= "011"; end if; if ((breq_int(2) = '0')) then valid_req <= '1'; request_int <= "010"; end if; if ((breq_int(1) = '0')) then valid_req <= '1'; request_int <= "001"; end if; if ((breq_int(0) = '0')) then valid_req <= '1'; request_int <= "000"; end if; end process rcheck; bgrant_reg: process(clk,reset) begin if (reset = '0') then bgrant_int <= "00000000"; elsif (clk'event and clk = '1') then if (bgrant_load = '1') then for i in bgrant'range loop if (bgrant_clr(i) = '1') then bgrant_int(i) <= '0' ; end if; if (bgrant_set(i) = '1') then bgrant_int(i) <= '1' ; end if; end loop; end if; end if; end process bgrant_reg; -- set one bit of the bgrant register based on 'bgrant_val', other bits -- get old values set_bgrant: process (bgrant_clr_index, bgrant_set_index, bgrant_set_all,bgrant_clr_en,bgrant_set_en) begin bgrant_clr <= "00000000"; bgrant_set <= "00000000"; if (bgrant_set_all = '1') then bgrant_set <= "11111111"; end if; if (bgrant_set_en = '1') then if (bgrant_set_index = "000") then bgrant_set(0) <= '1'; end if; if (bgrant_set_index = "001") then bgrant_set(1) <= '1'; end if; if (bgrant_set_index = "010") then bgrant_set(2) <= '1'; end if; if (bgrant_set_index = "011") then bgrant_set(3) <= '1'; end if; if (bgrant_set_index = "100") then bgrant_set(4) <= '1'; end if; if (bgrant_set_index = "101") then bgrant_set(5) <= '1'; end if; if (bgrant_set_index = "110") then bgrant_set(6) <= '1'; end if; if (bgrant_set_index = "111") then bgrant_set(7) <= '1'; end if; end if; if (bgrant_clr_en = '1') then if (bgrant_clr_index = "000") then bgrant_clr(0) <= '1'; end if; if (bgrant_clr_index = "001") then bgrant_clr(1) <= '1'; end if; if (bgrant_clr_index = "010") then bgrant_clr(2) <= '1'; end if; if (bgrant_clr_index = "011") then bgrant_clr(3) <= '1'; end if; if (bgrant_clr_index = "100") then bgrant_clr(4) <= '1'; end if; if (bgrant_clr_index = "101") then bgrant_clr(5) <= '1'; end if; if (bgrant_clr_index = "110") then bgrant_clr(6) <= '1'; end if; if (bgrant_clr_index = "111") then bgrant_clr(7) <= '1'; end if; end if; end process set_bgrant; -- map input request signals to internal request breq_map: process (breq,startp, bgrant_int) begin -- for right now, just do straight mapping -- internal breq is masked by bgrant -- if bgrant is low, then internal breq are high for i in 0 to 7 loop breq_int(i) <= breq(i) or (not bgrant_int(i)); end loop; if (startp = "001") then for i in 0 to 7 loop breq_int(i) <= breq((i+1) mod 8) or (not bgrant_int((i+1) mod 8)); end loop; end if; if (startp = "010") then for i in 0 to 7 loop breq_int(i) <= breq((i+2) mod 8) or (not bgrant_int((i+2) mod 8)); end loop; end if; if (startp = "011") then for i in 0 to 7 loop breq_int(i) <= breq((i+3) mod 8) or (not bgrant_int((i+3) mod 8)); end loop; end if; if (startp = "100") then for i in 0 to 7 loop breq_int(i) <= breq((i+4) mod 8) or (not bgrant_int((i+4) mod 8)); end loop; end if; if (startp = "101") then for i in 0 to 7 loop breq_int(i) <= breq((i+5) mod 8) or (not bgrant_int((i+5) mod 8)); end loop; end if; if (startp = "110") then for i in 0 to 7 loop breq_int(i) <= breq((i+6) mod 8) or (not bgrant_int((i+6) mod 8)); end loop; end if; if (startp = "111") then for i in 0 to 7 loop breq_int(i) <= breq((i+7) mod 8) or (not bgrant_int((i+7) mod 8)); end loop; end if; end process breq_map; -- map grant signals just map straight through bgrant_map: process (bgrant_int,startp) begin -- for right now, just do straight mapping bgrant <= bgrant_int; end process bgrant_map; -- map request signals based on start priority request_map: process (request_int,startp,c) begin -- just add start priority to request number c(0) <= '0'; for i in 0 to 2 loop request(i) <= request_int(i) xor startp(i) xor c(i); c(i+1) <= (request_int(i) and startp(i)) or (c(i) and (request_int(i) or startp(i))); end loop; end process request_map; ff:process (clk,reset) begin if (reset = '0') then pstate <= fsmstate'LEFT; pending <= "000"; current <= "000"; startp <= "000"; elsif (clk'event and clk = '1') then pstate <= nstate ; if (load_pending = '1') then pending <= pending_next ; end if; if (load_current = '1') then if (current_mux = '0') then current <= current_next ; else current <= pending ; end if; end if; if (load_startp = '1') then startp <= startp_next ; end if; end if; end process ff; -- grant the request. --Converted from non-synthesizeable code which is commented out. -- fsm: process (breq_int,bbusy,pstate, valid_req,request, current,pending) -- variable i,j: integer; -- variable pendreq :boolean; -- variable pending_grant : natural; -- variable current_grant : natural; -- variable start_priority: natural; begin load_pending <= '0'; load_current <= '0'; bgrant_clr_index <= "000"; bgrant_set_index <= "000"; bgrant_set_all <= '0'; bgrant_load <= '0'; current_mux <= '0'; current_next <= "000"; pending_next <= "000"; load_startp <= '0'; bgrant_set_en <= '0'; bgrant_clr_en <= '0'; nstate <= pstate; case pstate is when NOGRANTS => -- no current grants, make sure all grants are high -- bgrant_int <= (others =>'1') after 4 ns; bgrant_set_all <= '1'; bgrant_load <= '1'; -- i := 0; -- j := start_priority; -- while (i < N) loop -- if (breq_int(j) = '0') then -- current_grant := j; -- nstate <= ONEGRANT_WAIT; -- exit; -- exit the loop -- end if; -- i := i + 1; -- j := (j+1) mod N; -- end loop; if (valid_req = '1') then load_current <= '1'; current_next <= request; nstate <= ONEGRANT_WAIT; -- because bus grant is registered, we need to cause bus grant -- to be loaded from here, bus grant for 'request' will be granted -- next state, and we will remember what grant was made. -- this will cause the bgrant line indexed by 'request' to go low bgrant_clr_index <= request; bgrant_clr_en <= '1'; bgrant_set_all <= '0'; load_startp <= '1'; end if; when ONEGRANT_WAIT => -- if (pstate'event and pstate'last_value = NOGRANTS) then -- if (ROUND_ROBIN = TRUE ) then -- start_priority := (start_priority+1) mod N; -- end if; -- end if; -- grant goes valid in clock cycle after seeing the breq_int -- done in previous state bgrant_int(current_grant) <= '0' after 4 ns; -- grant bus -- one grant, wait for Bus Busy before allowing other grants if (bbusy = '0') then nstate <= ONEGRANT; if (valid_req = '1') then load_pending <= '1'; pending_next <= request; nstate <= OVERLAP; load_startp <= '1'; -- need to swap bus grants bgrant_load <= '1'; bgrant_clr_en <= '1'; bgrant_set_en <= '1'; bgrant_set_index <= current; -- negate current grant bgrant_clr_index <= request; -- assert pending grant end if; -- while we are waiting, see if we have overlapping grants -- see if we should go to the OVERLAP state instead -- i := 0; -- j := start_priority; -- while (i < N) loop -- if ((breq_int(j) = '0') and (j /= current_grant)) then -- -- we have a pending grant, what do we do? -- -- ok, we need to negate the current grant, and assert -- -- the pending grant -- pending_grant := j; -- nstate <= OVERLAP; -- exit; -- end if; -- i := i + 1; -- j := (j+1) mod N; -- end loop; end if; when ONEGRANT => -- ok, have done one grant and seen busy bus. Lets see if have any more pending grants -- i := 0; -- j := start_priority; -- while (i < N) loop -- if ((breq_int(j) = '0') and (j /= current_grant)) then -- -- we have a pending grant, what do we do? -- -- ok, we need to negate the current grant, and assert -- -- the pending grant -- pending_grant := j; -- pendreq := TRUE; -- nstate <= OVERLAP; -- exit; -- end if; -- i := i + 1; -- j := (j+1) mod N; -- end loop; if (valid_req = '1') then load_pending <= '1'; pending_next <= request; nstate <= OVERLAP; load_startp <= '1'; -- need to swap bus grants bgrant_load <= '1'; bgrant_clr_en <= '1'; bgrant_set_en <= '1'; bgrant_set_index <= current; -- negate current grant bgrant_clr_index <= request; -- assert pending grant end if; -- regardless of whether or not we have a pending request -- if the master has released the bus we need to release the grant -- and go to the no grant state if (bbusy /= '0') then -- release the grant bgrant_load <= '1'; bgrant_set_all <= '1'; load_startp <= '0'; nstate <= NOGRANTS; end if; -- we will bounce back/forth between OVERLAP, OVERLAP2 if we keep getting -- overlapped requests when OVERLAP => -- IN SYNTHESIZED model, we do this in states that TRANSISTION to this state -- on first entry to this state, we need to negate current grant, assert pending grant -- if (pstate'event) then -- -- use pstate'event to make sure we only make this assignment once -- -- because the current_grant variable may change -- bgrant_int(current_grant) <= '1' after 4 ns; -- negate pending grant -- bgrant_int(pending_grant) <= '0' after 4 ns; -- assert pending grant -- end if; -- ok, we have overlapped grants -- we need to wait until the current bus master releases if (bbusy /= '0') then -- ok, what is actually happening here? We are definititely going -- to transision to either ONEGRANT_WAIT or OVERLAP. -- either way we HAVE ALREADY granted the bus to the pending -- bus master so we need to transfer the pending grant index -- to the current grant index -- if (bbusy /= '0' and bbusy'event) then -- -- ok, current bus master is swapping -- -- make sure swap only happens one time -- current_grant := pending_grant; -- if (ROUND_ROBIN = TRUE ) then -- start_priority := (start_priority+1) mod N; -- end if; -- end if; current_mux <= '1'; -- current_grant := pending_grant; load_current <= '1'; -- check to see if we have ANOTHER pending grant. -- pendreq := FALSE; -- i := 0; -- j := start_priority; -- while (i < N) loop -- if ((breq_int(j) = '0') and (j /= current_grant)) then -- -- we have a pending grant, what do we do? -- -- ok, we need to negate the current grant, and assert -- -- the pending grant -- pending_grant := j; -- pendreq := TRUE; -- nstate <= OVERLAP2; -- exit; -- end if; -- i := i + 1; -- j := (j+1) mod N; -- end loop; -- if ((pendreq = FALSE)) then -- -- we know we have at least one grant -- nstate <= ONEGRANT_WAIT; -- end if; if (valid_req = '1') then load_pending <= '1'; pending_next <= request; load_startp <= '1'; nstate <= OVERLAP2; -- need to swap bus grants bgrant_load <= '1'; bgrant_clr_en <= '1'; bgrant_set_en <= '1'; -- bgrant_set_index <= current; -- negate current grant -- pending is actually the current grant because the current -- grant has not been updated yet. bgrant_set_index <= pending; -- negate current grant bgrant_clr_index <= request; -- assert pending grant else nstate <= ONEGRANT_WAIT; end if; end if; when OVERLAP2 => -- IN SYNTHESIZED model, we do this in states that TRANSISTION to this state -- on first entry to this state, we need to negate current grant, assert pending grant -- if (pstate'event) then -- -- use pstate'event to make sure we only make this assignment once -- -- because the current_grant variable may change -- bgrant_int(current_grant) <= '1' after 4 ns; -- negate pending grant -- bgrant_int(pending_grant) <= '0' after 4 ns; -- assert pending grant -- end if; -- ok, we have overlapped grants -- we need to wait until the current bus master releases if (bbusy /= '0') then -- if (bbusy /= '0' and bbusy'event) then -- -- ok, current bus master is swapping -- -- make sure swap only happens one time -- current_grant := pending_grant; -- if (ROUND_ROBIN = TRUE ) then -- start_priority := (start_priority+1) mod N; -- end if; -- end if; current_mux <= '1'; -- current_grant := pending_grant; load_current <= '1'; -- check to see if we have ANOTHER pending grant. -- pendreq := FALSE; -- i := 0; -- j := start_priority; -- while (i < N) loop -- if ((breq_int(j) = '0') and (j /= current_grant)) then -- -- we have a pending grant, what do we do? -- -- ok, we need to negate the current grant, and assert -- -- the pending grant -- pending_grant := j; -- pendreq := TRUE; -- nstate <= OVERLAP; -- exit; -- end if; -- i := i + 1; -- j := (j+1) mod N; -- end loop; -- if ((pendreq = FALSE)) then -- -- we know we have at least one grant -- nstate <= ONEGRANT_WAIT; -- end if; -- end if; if (valid_req = '1') then load_pending <= '1'; pending_next <= request; nstate <= OVERLAP; load_startp <= '1'; -- need to swap bus grants bgrant_load <= '1'; bgrant_clr_en <= '1'; bgrant_set_en <= '1'; -- bgrant_set_index <= current; -- negate current grant -- pending is actually the current grant because the current -- grant has not been updated yet. bgrant_set_index <= pending; -- negate current grant bgrant_clr_index <= request; -- assert pending grant else nstate <= ONEGRANT_WAIT; end if; end if; end case; end process; end behv;