From 5c2fc47e2c30f1799eed95928578313d9afcb6af Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 17 Jun 2020 22:11:58 +1000 Subject: [PATCH] xics: Add simple ICS Move the external interrupt generation to a separate module "ICS" (source controller) which a register per source containing currently only the priority control. Signed-off-by: Benjamin Herrenschmidt --- common.vhdl | 10 ++ include/microwatt_soc.h | 3 +- soc.vhdl | 68 ++++++--- tests/test_xics.bin | Bin 12384 -> 12392 bytes tests/test_xics.console_out | 1 + tests/xics/xics.c | 88 ++++++++--- tests/xics/xics.h | 26 +++- xics.vhdl | 293 ++++++++++++++++++++++++++++-------- 8 files changed, 381 insertions(+), 108 deletions(-) diff --git a/common.vhdl b/common.vhdl index 52222c3..f80593b 100644 --- a/common.vhdl +++ b/common.vhdl @@ -78,6 +78,16 @@ package common is type irq_state_t is (WRITE_SRR0, WRITE_SRR1); + -- For now, fixed 16 sources, make this either a parametric + -- package of some sort or an unconstrainted array. + type ics_to_icp_t is record + -- Level interrupts only, ICS just keeps prsenting the + -- highest priority interrupt. Once handling edge, something + -- smarter involving handshake & reject support will be needed + src : std_ulogic_vector(3 downto 0); + pri : std_ulogic_vector(7 downto 0); + end record; + -- This needs to die... type ctrl_t is record tb: std_ulogic_vector(63 downto 0); diff --git a/include/microwatt_soc.h b/include/microwatt_soc.h index 39820e6..fd83840 100644 --- a/include/microwatt_soc.h +++ b/include/microwatt_soc.h @@ -11,7 +11,8 @@ #define SYSCON_BASE 0xc0000000 /* System control regs */ #define UART_BASE 0xc0002000 /* UART */ -#define XICS_BASE 0xc0004000 /* Interrupt controller */ +#define XICS_ICP_BASE 0xc0004000 /* Interrupt controller */ +#define XICS_ICS_BASE 0xc0005000 /* Interrupt controller */ #define SPI_FCTRL_BASE 0xc0006000 /* SPI flash controller registers */ #define DRAM_CTRL_BASE 0xc8000000 /* LiteDRAM control registers */ #define SPI_FLASH_BASE 0xf0000000 /* SPI Flash memory map */ diff --git a/soc.vhdl b/soc.vhdl index 6cf9a7f..c096ac1 100644 --- a/soc.vhdl +++ b/soc.vhdl @@ -21,6 +21,7 @@ use work.wishbone_types.all; -- 0xc0000000: SYSCON -- 0xc0002000: UART0 -- 0xc0004000: XICS ICP +-- 0xc0005000: XICS ICS -- 0xc0006000: SPI Flash controller -- 0xc8nnnnnn: External IO bus -- 0xf0000000: Flash "ROM" mapping @@ -130,12 +131,14 @@ architecture behaviour of soc is signal wb_spiflash_is_reg : std_ulogic; signal wb_spiflash_is_map : std_ulogic; - -- XICS0 signals: - signal wb_xics0_in : wb_io_master_out; - signal wb_xics0_out : wb_io_slave_out; - signal int_level_in : std_ulogic_vector(15 downto 0); - - signal core_ext_irq : std_ulogic; + -- XICS signals: + signal wb_xics_icp_in : wb_io_master_out; + signal wb_xics_icp_out : wb_io_slave_out; + signal wb_xics_ics_in : wb_io_master_out; + signal wb_xics_ics_out : wb_io_slave_out; + signal int_level_in : std_ulogic_vector(15 downto 0); + signal ics_to_icp : ics_to_icp_t; + signal core_ext_irq : std_ulogic; -- Main memory signals: signal wb_bram_in : wishbone_master_out; @@ -171,7 +174,8 @@ architecture behaviour of soc is -- IO branch split: type slave_io_type is (SLAVE_IO_SYSCON, SLAVE_IO_UART, - SLAVE_IO_ICP_0, + SLAVE_IO_ICP, + SLAVE_IO_ICS, SLAVE_IO_SPI_FLASH_REG, SLAVE_IO_SPI_FLASH_MAP, SLAVE_IO_EXTERNAL, @@ -441,7 +445,8 @@ begin -- IO wishbone slave intercon. -- slave_io_intercon: process(wb_sio_out, wb_syscon_out, wb_uart0_out, - wb_ext_io_out, wb_xics0_out, wb_spiflash_out) + wb_ext_io_out, wb_xics_icp_out, wb_xics_ics_out, + wb_spiflash_out) variable slave_io : slave_io_type; variable match : std_ulogic_vector(31 downto 12); @@ -462,7 +467,9 @@ begin elsif std_match(match, x"C8---") then slave_io := SLAVE_IO_EXTERNAL; elsif std_match(match, x"C0004") then - slave_io := SLAVE_IO_ICP_0; + slave_io := SLAVE_IO_ICP; + elsif std_match(match, x"C0005") then + slave_io := SLAVE_IO_ICS; elsif std_match(match, x"C0006") then slave_io := SLAVE_IO_SPI_FLASH_REG; end if; @@ -474,11 +481,15 @@ begin wb_spiflash_is_reg <= '0'; wb_spiflash_is_map <= '0'; - -- Only give xics 8 bits of wb addr - wb_xics0_in <= wb_sio_out; - wb_xics0_in.adr <= (others => '0'); - wb_xics0_in.adr(7 downto 0) <= wb_sio_out.adr(7 downto 0); - wb_xics0_in.cyc <= '0'; + -- Only give xics 8 bits of wb addr (for now...) + wb_xics_icp_in <= wb_sio_out; + wb_xics_icp_in.adr <= (others => '0'); + wb_xics_icp_in.adr(7 downto 0) <= wb_sio_out.adr(7 downto 0); + wb_xics_icp_in.cyc <= '0'; + wb_xics_ics_in <= wb_sio_out; + wb_xics_ics_in.adr <= (others => '0'); + wb_xics_ics_in.adr(11 downto 0) <= wb_sio_out.adr(11 downto 0); + wb_xics_ics_in.cyc <= '0'; wb_ext_io_in <= wb_sio_out; wb_ext_io_in.cyc <= '0'; @@ -521,9 +532,12 @@ begin when SLAVE_IO_UART => wb_uart0_in.cyc <= wb_sio_out.cyc; wb_sio_in <= wb_uart0_out; - when SLAVE_IO_ICP_0 => - wb_xics0_in.cyc <= wb_sio_out.cyc; - wb_sio_in <= wb_xics0_out; + when SLAVE_IO_ICP => + wb_xics_icp_in.cyc <= wb_sio_out.cyc; + wb_sio_in <= wb_xics_icp_out; + when SLAVE_IO_ICS => + wb_xics_ics_in.cyc <= wb_sio_out.cyc; + wb_sio_in <= wb_xics_ics_out; when SLAVE_IO_SPI_FLASH_MAP => -- Clear top bits so they don't make their way to the -- fash chip. @@ -614,17 +628,27 @@ begin wb_spiflash_out.stall <= wb_spiflash_in.cyc and not wb_spiflash_out.ack; end generate; - xics0: entity work.xics + xics_icp: entity work.xics_icp + port map( + clk => system_clk, + rst => rst_xics, + wb_in => wb_xics_icp_in, + wb_out => wb_xics_icp_out, + ics_in => ics_to_icp, + core_irq_out => core_ext_irq + ); + + xics_ics: entity work.xics_ics generic map( - LEVEL_NUM => 16 + SRC_NUM => 16 ) port map( clk => system_clk, rst => rst_xics, - wb_in => wb_xics0_in, - wb_out => wb_xics0_out, + wb_in => wb_xics_ics_in, + wb_out => wb_xics_ics_out, int_level_in => int_level_in, - core_irq_out => core_ext_irq + icp_out => ics_to_icp ); -- Assign external interrupts diff --git a/tests/test_xics.bin b/tests/test_xics.bin index 327f98f64e2bb62ea1ca48f98456b1dae59799f6..1e0e7d4efb6797d25fb75383564b2575119dd3e2 100755 GIT binary patch literal 12392 zcmeHMeP~C@dL(S49 ze@L@5J&pWP7sH&v!ZO;dUWcheTN+rQ|E!Z4gk&4cWo0z9EB4AjA8aI)cKWD$_dEAp z#m_Hsw!uIfc>?>Md)|5XoZs)9`y~-s5u&NsrIx9rps8a*OvPq>XVWyjqQ~=NK5Hs= zRI}1VdJmD`ywu`Ppgl@aze$cU*!JH0d5p=lzuDSPO~jww^1t`bW8i;}fkxM+=f8n9 z(cF5+uT71vzXoPsy7urlIs=XM-{}0`>HZs=eeZ1A==y7T{;z)FFSn9bZl}I-2gS-d zWy=rKOnC>*mxHuaHb|@NCVyp!`YNLotC*Cn9H*Je37W4YXsKe6R(*l|)oJRh{)A%H zS14P3jb^HE(R}qCTB_zqt6e64ZGrk~A5g5eNZDGRW@^`HzE-BC+HBMPDQeZqvrVlj zL$(`I7TT{9rE;?WK#DeK<$2*R6PdVw#c}_NRx=zJaFWJBM%$};3xn`0XPc4Q2>qta1?-}031c&C;~?jIEuhg1dbwb6oI1%93|i= z0Y?cqO2AP9juLQ`fTLuz#`3ei({@7*ttIejNE=N)j_d5$N3=9-bN?? zPWOLVpe_aKQlKsc>QbOC1?o~P)!H#9bh7rtrUaW3Y)Y^xL7#_RY1Y@8f^7-5CAMRk zpK+g`u}&kShu-QBf@kxD)gL12Drgjlp{-EPhzOyF?lJ~qIt?UWZ>H3RLwcIubLQn% zV>GKV+_pR>jjoK>^^~5boE~W&4Zuf0`smtEX}UlW_Sba?@`#cTP+IDqQZ3tw6+8J1 zHh>az`>n^wbC`Ks!dwls$-9LKEE2m;{vh+i956pkH)GH&7*j6ZLq;4v;t9#gW;4~h zK0fUBd6V51OLERb-1y`=BV+_ZE7bARU(y}LS}U?1*rA8Q{Qrd$9#{-^Jq z9`4QYyQh0L_m2(H=;>hZuCXDVPD>nJ58Xbu_--kbu(qB->}JBQmF!n&vRkK@_kpu4 z>W1s*OkRk=8~7kNxhFD0k1mVBi{SsK;l*g;f$yh?tT6pn#M{UWpRK){*+4IC*J*Cz zUOL}LbfNn$I&Toob$6h@gVMoYw!~9^weN){#t!|d@~h0*4@E|!o=_W2;@zI)(6v8j zbozKgCo%E5IByIgw~Jrgh)c89x#B`y@|Yj0*u>KN83!Gaj zb^XN_RYzRgmcF{a`90{@VNCZtdgDuuCt6@^qrfJ_vppT-@!&p%?J?BxvKspjkmq5~ zx`NWN{latc;MbHr_jSC#QT63_d+=?*H{){7;YXBjjpnvHeZQy1W%%J?=z}j_npJ~;r9JD^3S+^F5e^SUG}|B$yXs?fj#T4ueW)w+u%(S1~f?<#jgZzeApfJ?jce$2=@@{vEu?{MRw!yWLI7cC8u=s2JS2xT4-; ze@P{O205Z)IOdAsoTJY%Osamp4sMl;x#s%%yPEUEmH#g1G;KsKwG1SEG=T5OjkGfd zYw>b-?bdViqKcV$i7ELW%?xgXJ?r)<9p~m6a+7uRnV08PU-B}oBd$QwX9W5>Ny!v@9_A4^Vyu;2cH*V&$_EhSNFNm<#Sm*zg;dkKhC=U;2&$}VBCIY9=CoT zo{?wX$RuGOaIPbh$|uJcQgRaVGIGnhZH|~PgQuq*edcM8>T}E*&(mBk+H8CrCyJco zb)Dx>*XOxRZ|kFh4gWr(9v7n!qXB@+E#yOD7Fz2RRYa-`*J{N=SB*Ny(-ljO#B2Vy@u z7)V=IKX@Mq2@#O%YY}U?``lFLjmO8h1!1q*wmsJ4e`U{HB8Gq4zP)aXcyTs*J}-V? zSk|++|HXq`zr{7qjqW&|~Am1^I2lBQ}V}W zK==8NUm834U2Z5b7C(99)UlJNjy&S(f6LYXw(JkXREM;yZ_nN~v_pLd4|2=nd=sm| z!vP(dolg!QVT+L`clz7d-1~S8cno+9cno+9cno+9cno+9cno+9cno+9cno+9cno+9 r{9iC&w%cLKuiPN+zT56AHT|M4tbt}hJwJSpZ7{vbZkz90{lY&1=`VvC literal 12384 zcmeHMeP~9}x?1N^Bop^0P9~4sBwE9SP_d8El z_Os$ND{N?x_u%Q?d+xdCoZs)n)4Qz-uwh4VU1x-yG;m~qBLf^6;K%?+1~@XnkpYejaAbia z3mjSC$O1rNF!tn3n?cQea++#bPs_36+eU(8)q43!N->)0Pk&s9G?MObp!KasKKNbYK{^nEt@br^K+|q)!1HQ^Iwes!yffG0x{j#AxQ?Nj1)xhm3#vQ3B(Jd|Ce8I+<_SsKMAZu)*WY{ciy) zQ7}#9X@3fsgm}91&`89)R$}-%>E1s`8^=+fhd#?rOBw5*hyHa-dkXEpmHqO!E%?^p zo8!0o-XVP>FRfPJN99=dvrX1dpdOaKAGP>m-@}$R`~IeEo8Q&oJ1Oq;ebMAQn08k9 z{*oNazW-cX;_h|SuS1_@zm>8w?)NNh_B}7#W#62yO57~#K+cge+`;^fq9ylAW$sm( zdtMJTpw(2Bx7D{i7|;7w^`a8vro1;W(Ch8 zC6hsywh$o-9OX5cpPjakk_q+!+(99_aBmC}*4INLDz7M!`u z{}rH~qNEydX`V2z1!k;|ajdFOH`kQF(b11ZUo#2+;PO7F7{R3HNehtL8~)jDPdsXLf$v_Q z5FT?4&0uf68)s}AHq)ZCE|>JN=H5%6d4&J}SiiZfi&*jeKAXasq2&8%yvIbmJO?s& zIggdkHsx5Yw(6y=&9%b=jN7#H33z#q@HvFfzCyg?FP}jay82V1&F#&YujPHM<)-Ls zq=#DheDqn)Kk~)78bf&jH{#(-F)-hw>%NCGmhSycOB?nwKCd0vp#ay7Wj#|lIvm;m z6+ES_9yPRkch9bYJ>Ljz+y2C^9(SY43Iluhk8*{jjVSw}#pUq+AK({$Fn-S{l=gH~ zw7*)>{u(u#5(N0%E^uFLS2>qz1 ziMne;knt4k&U*BH=VKwhze1;Pg^q^4U*&{2xI*XgB^@u!52DXi5MqdRx;eh1buZPfh_Sm# zcWiHLqAoMae_W~!eWt|Aag6D}EPN0{`C=a5kg~tBz_e$CmbUtI?Y0+qof{SKBm0t=r(!Y zQo?CMG{>KW%Dd3zarR|1U^8GdU^8GdU^8GdU^8GdU^8GdU^8GdU^8GdU^DQ)V?dW5 gjPR+_yw1qBENHS^xl0J6pDT6jlOL '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;