Add Tercel PHY reset synchronization
[microwatt.git] / wishbone_arbiter.vhdl
index 8e2358b253bf53239bb21398613627bec60f8aca..cb632bffafab762ec3395b4649a5eea7fb830961 100644 (file)
@@ -6,76 +6,64 @@ use work.wishbone_types.all;
 
 -- TODO: Use an array of master/slaves with parametric size
 entity wishbone_arbiter is
+    generic(
+       NUM_MASTERS : positive := 3
+       );
     port (clk     : in std_ulogic;
          rst     : in std_ulogic;
 
-         wb1_in  : in wishbone_master_out;
-         wb1_out : out wishbone_slave_out;
+         wb_masters_in  : in wishbone_master_out_vector(0 to NUM_MASTERS-1);
+         wb_masters_out : out wishbone_slave_out_vector(0 to NUM_MASTERS-1);
 
-         wb2_in  : in wishbone_master_out;
-         wb2_out : out wishbone_slave_out;
-
-         wb3_in  : in wishbone_master_out;
-         wb3_out : out wishbone_slave_out;
-
-         wb_out  : out wishbone_master_out;
-         wb_in   : in wishbone_slave_out
+         wb_slave_out  : out wishbone_master_out;
+         wb_slave_in   : in wishbone_slave_out
          );
 end wishbone_arbiter;
 
 architecture behave of wishbone_arbiter is
-    type wishbone_arbiter_state_t is (IDLE, WB1_BUSY, WB2_BUSY, WB3_BUSY);
-    signal state : wishbone_arbiter_state_t := IDLE;
+    subtype wb_arb_master_t is integer range 0 to NUM_MASTERS-1;
+    signal candidate, selected : wb_arb_master_t;
+    signal busy : std_ulogic;
 begin
 
-    wishbone_muxes: process(state, wb_in, wb1_in, wb2_in, wb3_in)
+    busy <= wb_masters_in(selected).cyc;
+
+    wishbone_muxes: process(selected, candidate, busy, wb_slave_in, wb_masters_in)
+       variable early_sel : wb_arb_master_t;
     begin
-       -- Requests from masters are fully muxed
-       wb_out <= wb1_in when state = WB1_BUSY else
-                 wb2_in when state = WB2_BUSY else
-                 wb3_in when state = WB3_BUSY else
-                 wishbone_master_out_init;
+       early_sel := selected;
+       if busy = '0' then
+           early_sel := candidate;
+       end if;
+       wb_slave_out <= wb_masters_in(early_sel);
+       for i in 0 to NUM_MASTERS-1 loop
+           wb_masters_out(i).dat <= wb_slave_in.dat;
+           wb_masters_out(i).ack <= wb_slave_in.ack when early_sel = i else '0';
+           wb_masters_out(i).stall <= wb_slave_in.stall when early_sel = i else '1';
+       end loop;
+    end process;
 
-       -- Responses from slave don't need to mux the data bus
-       wb1_out.dat <= wb_in.dat;
-       wb2_out.dat <= wb_in.dat;
-       wb3_out.dat <= wb_in.dat;
-       wb1_out.ack <= wb_in.ack when state = WB1_BUSY else '0';
-       wb2_out.ack <= wb_in.ack when state = WB2_BUSY else '0';
-       wb3_out.ack <= wb_in.ack when state = WB3_BUSY else '0';
-       wb1_out.stall <= wb_in.stall when state = WB1_BUSY else '1';
-       wb2_out.stall <= wb_in.stall when state = WB2_BUSY else '1';
-       wb3_out.stall <= wb_in.stall when state = WB3_BUSY else '1';
+    -- Candidate selection is dumb, priority order... we could
+    -- instead consider some form of fairness but it's not really
+    -- an issue at the moment.
+    --
+    wishbone_candidate: process(all)
+    begin
+       candidate <= selected;
+       for i in NUM_MASTERS-1 downto 0  loop
+           if wb_masters_in(i).cyc = '1' then
+               candidate <= i;
+           end if;
+       end loop;
     end process;
 
     wishbone_arbiter_process: process(clk)
     begin
        if rising_edge(clk) then
            if rst = '1' then
-               state <= IDLE;
-           else
-               case state is
-               when IDLE =>
-                   if wb1_in.cyc = '1' then
-                       state <= WB1_BUSY;
-                   elsif wb2_in.cyc = '1' then
-                       state <= WB2_BUSY;
-                   elsif wb3_in.cyc = '1' then
-                       state <= WB3_BUSY;
-                   end if;
-               when WB1_BUSY =>
-                   if wb1_in.cyc = '0' then
-                       state <= IDLE;
-                   end if;
-               when WB2_BUSY =>
-                   if wb2_in.cyc = '0' then
-                       state <= IDLE;
-                   end if;
-               when WB3_BUSY =>
-                   if wb3_in.cyc = '0' then
-                       state <= IDLE;
-                   end if;
-               end case;
+               selected <= 0;
+           elsif busy = '0' then
+               selected <= candidate;
            end if;
        end if;
     end process;