@ -1,11 +1,13 @@
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				--
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- This is a simple XICS compliant interrupt controller.  This is a
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- Presenter (ICP) and Source (ICS) in a single unit with no routing
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- layer.
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- Presenter (ICP) and Source (ICS) in two small units directly
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- connected to each other with no routing layer.
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				--
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- The sources have a fixed IRQ priority set by HW_PRIORITY. The
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- source id starts at 16 for int_level_in(0) and go up from
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- there (ie int_level_in(1) is source id 17).
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- The sources have a configurable IRQ priority set a set of ICS
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- registers in the source units.
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				--
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- The source ids start at 16 for int_level_in(0) and go up from
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- there (ie int_level_in(1) is source id 17). XXX Make a generic
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				--
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- The presentation layer will pick an interupt that is more
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				-- favourable than the current CPPR and present it via the XISR and
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -22,38 +24,31 @@ library work;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				use work.common.all;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				use work.wishbone_types.all;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				entity xics is
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    generic (
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        LEVEL_NUM : positive := 16
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        );
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				entity xics_icp is
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    port (
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        clk          : in std_logic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        rst          : in std_logic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        wb_in   : in wb_io_master_out;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        wb_out  : out wb_io_slave_out;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					int_level_in : in std_ulogic_vector(LEVEL_NUM - 1 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        wb_in        : in wb_io_master_out;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        wb_out       : out wb_io_slave_out;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					ics_in       : in ics_to_icp_t;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					core_irq_out : out std_ulogic
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        );
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				end xics;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				end xics_icp;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				architecture behaviour of xics is
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				architecture behaviour of xics_icp is
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    type reg_internal_t is record
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					xisr : std_ulogic_vector(23 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					cppr : std_ulogic_vector(7 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					pending_priority : std_ulogic_vector(7 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					mfrr : std_ulogic_vector(7 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					mfrr_pending : std_ulogic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					irq : std_ulogic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					wb_rd_data : std_ulogic_vector(31 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					wb_ack : std_ulogic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    end record;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    constant reg_internal_init : reg_internal_t :=
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					(wb_ack => '0',
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					 mfrr_pending => '0',
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					 mfrr => x"ff", -- no IPI on reset
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					 mfrr => x"ff", -- mask everything on reset
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					 irq => '0',
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					 others => (others => '0'));
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -74,18 +69,19 @@ begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					if rising_edge(clk) then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    r <= r_next;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            -- We delay core_irq_out by a cycle to help with timing
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            core_irq_out <= r.irq;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    end process;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    wb_out.dat <= r.wb_rd_data;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    wb_out.ack <= r.wb_ack;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    wb_out.stall <= '0'; -- never stall wishbone
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    core_irq_out <= r.irq;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    comb : process(all)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					variable v : reg_internal_t;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					variable xirr_accept_rd : std_ulogic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					variable irq_eoi : std_ulogic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        function  bswap(v : in std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            variable r : std_ulogic_vector(31 downto 0);
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -99,13 +95,14 @@ begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        variable be_in  : std_ulogic_vector(31 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        variable be_out : std_ulogic_vector(31 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					variable pending_priority : std_ulogic_vector(7 downto 0);        
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					v := r;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					v.wb_ack := '0';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					xirr_accept_rd := '0';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					irq_eoi := '0';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        be_in := bswap(wb_in.dat);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        be_out := (others => '0');
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -122,7 +119,6 @@ begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    v.cppr := be_in(31 downto 24);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    if wb_in.sel = x"f"  then -- 4 byte
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                        report "ICP XIRR write word (EOI) :" & to_hstring(be_in);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
							irq_eoi := '1';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    elsif wb_in.sel = x"1"  then -- 1 byte
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                        report "ICP XIRR write byte (CPPR):" & to_hstring(be_in(31 downto 24));
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    else
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -130,7 +126,6 @@ begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						when MFRR =>
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    v.mfrr := be_in(31 downto 24);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    v.mfrr_pending := '1';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    if wb_in.sel = x"f" then -- 4 bytes
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                        report "ICP MFRR write word:" & to_hstring(be_in);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    elsif wb_in.sel = x"1" then -- 1 byte
 
			
		 
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
			
			 
			 
			
				@ -161,49 +156,40 @@ begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					-- generate interrupt
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					if r.irq = '0' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    -- Here we just present any interrupt that's valid and
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    -- below cppr. For ordering, we ignore hardware
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    -- priorities.
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    if unsigned(HW_PRIORITY) < unsigned(r.cppr) then --
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						-- lower HW sources are higher priority
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						for i in LEVEL_NUM - 1 downto 0 loop
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    if int_level_in(i) = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
							v.irq := '1';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
							v.xisr := std_ulogic_vector(to_unsigned(16 + i, 24));
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
							v.pending_priority := HW_PRIORITY; -- hardware HW IRQs
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						end loop;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        pending_priority := x"ff";
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        v.xisr := x"000000";
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        v.irq := '0';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    -- Do mfrr as a higher priority so mfrr_pending is cleared
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    if unsigned(r.mfrr) < unsigned(r.cppr) then --
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						report "XICS: MFRR INTERRUPT";
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						-- IPI
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						if r.mfrr_pending = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    v.irq := '1';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    v.xisr := x"000002"; -- special XICS MFRR IRQ source number
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    v.pending_priority := r.mfrr;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						    v.mfrr_pending := '0';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        if ics_in.pri /= x"ff" then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            v.xisr := x"00001" & ics_in.src;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            pending_priority := ics_in.pri;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        -- Check MFRR
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        if unsigned(r.mfrr) < unsigned(pending_priority) then --
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            v.xisr := x"000002"; -- special XICS MFRR IRQ source number
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            pending_priority := r.mfrr;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					-- Accept the interrupt
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					if xirr_accept_rd = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    report "XICS: ACCEPT" &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						" cppr:" &  to_hstring(r.cppr) &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						" xisr:" & to_hstring(r.xisr) &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
						" mfrr:" & to_hstring(r.mfrr);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    v.cppr := r.pending_priority;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            report "XICS: ICP ACCEPT" &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                " cppr:" &  to_hstring(r.cppr) &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                " xisr:" & to_hstring(r.xisr) &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                " mfrr:" & to_hstring(r.mfrr);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    v.cppr := pending_priority;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        v.wb_rd_data := bswap(be_out);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					if irq_eoi = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    v.irq := '0';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        if unsigned(pending_priority) < unsigned(v.cppr) then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            if r.irq = '0' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                report "IRQ set";
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            v.irq := '1';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        elsif r.irq = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            report "IRQ clr";
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					if rst = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					    v := reg_internal_init;
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -214,3 +200,192 @@ begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    end process;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				end architecture behaviour;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				library ieee;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				use ieee.std_logic_1164.all;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				use ieee.numeric_std.all;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				library work;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				use work.common.all;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				use work.wishbone_types.all;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				entity xics_ics is
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    generic (
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        SRC_NUM  : positive := 16
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        );
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    port (
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        clk          : in std_logic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        rst          : in std_logic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        wb_in        : in wb_io_master_out;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        wb_out       : out wb_io_slave_out;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					int_level_in : in std_ulogic_vector(SRC_NUM - 1 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
					icp_out      : out ics_to_icp_t
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        );
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				end xics_ics;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				architecture rtl of xics_ics is
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    subtype pri_t is std_ulogic_vector(7 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    type xive_t is record
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        pri : pri_t;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    end record;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    type xive_array_t is array(0 to SRC_NUM-1) of xive_t;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    signal xives : xive_array_t;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    signal wb_valid : std_ulogic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    signal reg_idx : integer range 0 to SRC_NUM - 1;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    signal icp_out_next : ics_to_icp_t;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    signal int_level_l : std_ulogic_vector(SRC_NUM - 1 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    function  bswap(v : in std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        variable r : std_ulogic_vector(31 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        r( 7 downto  0) := v(31 downto 24);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        r(15 downto  8) := v(23 downto 16);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        r(23 downto 16) := v(15 downto  8);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        r(31 downto 24) := v( 7 downto  0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        return r;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    end function;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- Register map
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --     0  : Config (currently hard wired base irq#)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --     4  : Debug/diagnostics
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --   800  : XIVE0
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --   804  : XIVE1 ...
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- Config register format:
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --  23..  0 : Interrupt base (hard wired to 16)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- XIVE register format:
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --       31 : input bit (reflects interrupt input)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --       30 : reserved
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --       29 : P (mirrors input for now)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --       28 : Q (not implemented in this version)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- 30 ..    : reserved
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- 19 ..  8 : target (not implemented in this version)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --  7 ..  0 : prio/mask
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    signal reg_is_xive   : std_ulogic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    signal reg_is_config : std_ulogic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    signal reg_is_debug  : std_ulogic;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    assert SRC_NUM = 16 report "Fixup address decode with log2";
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    reg_is_xive   <= wb_in.adr(11);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    reg_is_config <= '1' when wb_in.adr(11 downto 0) = x"000" else '0';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    reg_is_debug  <= '1' when wb_in.adr(11 downto 0) = x"004" else '0';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- Register index XX FIXME: figure out bits from SRC_NUM
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    reg_idx <= to_integer(unsigned(wb_in.adr(5 downto 2)));
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- Latch interrupt inputs for timing
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    int_latch: process(clk)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        if rising_edge(clk) then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            int_level_l <= int_level_in;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    end process;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- We don't stall. Acks are sent by the read machine one cycle
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- after a request, but we can handle one access per cycle.
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    wb_out.stall <= '0';
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    wb_valid <= wb_in.cyc and wb_in.stb;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- Big read mux. This could be replaced by a slower state
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- machine iterating registers instead if timing gets tight.
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    reg_read: process(clk)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        variable be_out : std_ulogic_vector(31 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        if rising_edge(clk) then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            be_out := (others => '0');
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            if reg_is_xive = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                be_out := int_level_l(reg_idx) &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                          '0' &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                          int_level_l(reg_idx) &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                          '0' &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                          x"00000" &
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                          xives(reg_idx).pri;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            elsif reg_is_config = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                be_out := std_ulogic_vector(to_unsigned(SRC_NUM, 32));
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            elsif reg_is_debug = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                be_out := x"00000" & icp_out_next.src & icp_out_next.pri;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            wb_out.dat <= bswap(be_out);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            wb_out.ack <= wb_valid;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    end process;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- Register write machine
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    reg_write: process(clk)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        variable be_in  : std_ulogic_vector(31 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        -- Byteswapped input
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        be_in := bswap(wb_in.dat);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        if rising_edge(clk) then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            if rst = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                for i in 0 to SRC_NUM - 1 loop
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    xives(i) <= (pri => x"ff");
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                end loop;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            elsif wb_valid = '1' and wb_in.we = '1' then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                if reg_is_xive then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    -- TODO: When adding support for other bits, make sure to
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    -- properly implement wb_in.sel to allow partial writes.
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    xives(reg_idx).pri <= be_in(7 downto 0);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                    report "ICS irq " & integer'image(reg_idx) & " set to:" & to_hstring(be_in(7 downto 0));
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    end process;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- generate interrupt. This is a simple combinational process,
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- potentially wasteul in HW for large number of interrupts.
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- could be replaced with iterative state machines and a message
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    -- system between ICSs' (plural) and ICP  incl. reject etc...
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    --
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    irq_gen_sync: process(clk)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        if rising_edge(clk) then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            icp_out <= icp_out_next;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    end process;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    irq_gen: process(all)
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        variable max_idx : integer range 0 to SRC_NUM-1;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        variable max_pri : pri_t;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        -- A more favored than b ?
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        function a_mf_b(a: pri_t; b: pri_t) return boolean is
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            variable a_i : integer range 0 to 255;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            variable b_i : integer range 0 to 255;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            a_i := to_integer(unsigned(a));
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            b_i := to_integer(unsigned(b));
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            return a < b;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        end function;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    begin
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        -- XXX FIXME: Use a tree
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        max_pri := x"ff";
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        max_idx := 0;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        for i in 0 to SRC_NUM - 1 loop
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            if int_level_l(i) = '1' and a_mf_b(xives(i).pri, max_pri) then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                max_pri := xives(i).pri;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				                max_idx := i;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        end loop;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        if max_pri /= x"ff" then
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            report "MFI: " & integer'image(max_idx) & " pri=" & to_hstring(max_pri);
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        end if;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        icp_out_next.src <= std_ulogic_vector(to_unsigned(max_idx, 4));
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        icp_out_next.pri <= max_pri;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    end process;
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				end architecture rtl;