xics.vhdl 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. --
  2. -- This is a simple XICS compliant interrupt controller. This is a
  3. -- Presenter (ICP) and Source (ICS) in two small units directly
  4. -- connected to each other with no routing layer.
  5. --
  6. -- The sources have a configurable IRQ priority set a set of ICS
  7. -- registers in the source units.
  8. --
  9. -- The source ids start at 16 for int_level_in(0) and go up from
  10. -- there (ie int_level_in(1) is source id 17). XXX Make a generic
  11. --
  12. -- The presentation layer will pick an interupt that is more
  13. -- favourable than the current CPPR and present it via the XISR and
  14. -- send an interrpt to the processor (via e_out). This may not be the
  15. -- highest priority interrupt currently presented (which is allowed
  16. -- via XICS)
  17. --
  18. library ieee;
  19. use ieee.std_logic_1164.all;
  20. use ieee.numeric_std.all;
  21. library work;
  22. use work.common.all;
  23. use work.wishbone_types.all;
  24. entity xics_icp is
  25. port (
  26. clk : in std_logic;
  27. rst : in std_logic;
  28. wb_in : in wb_io_master_out;
  29. wb_out : out wb_io_slave_out;
  30. ics_in : in ics_to_icp_t;
  31. core_irq_out : out std_ulogic
  32. );
  33. end xics_icp;
  34. architecture behaviour of xics_icp is
  35. type reg_internal_t is record
  36. xisr : std_ulogic_vector(23 downto 0);
  37. cppr : std_ulogic_vector(7 downto 0);
  38. mfrr : std_ulogic_vector(7 downto 0);
  39. irq : std_ulogic;
  40. wb_rd_data : std_ulogic_vector(31 downto 0);
  41. wb_ack : std_ulogic;
  42. end record;
  43. constant reg_internal_init : reg_internal_t :=
  44. (wb_ack => '0',
  45. mfrr => x"ff", -- mask everything on reset
  46. irq => '0',
  47. others => (others => '0'));
  48. signal r, r_next : reg_internal_t;
  49. -- hardwire the hardware IRQ priority
  50. constant HW_PRIORITY : std_ulogic_vector(7 downto 0) := x"80";
  51. -- 8 bit offsets for each presentation
  52. constant XIRR_POLL : std_ulogic_vector(7 downto 0) := x"00";
  53. constant XIRR : std_ulogic_vector(7 downto 0) := x"04";
  54. constant RESV0 : std_ulogic_vector(7 downto 0) := x"08";
  55. constant MFRR : std_ulogic_vector(7 downto 0) := x"0c";
  56. begin
  57. regs : process(clk)
  58. begin
  59. if rising_edge(clk) then
  60. r <= r_next;
  61. -- We delay core_irq_out by a cycle to help with timing
  62. core_irq_out <= r.irq;
  63. end if;
  64. end process;
  65. wb_out.dat <= r.wb_rd_data;
  66. wb_out.ack <= r.wb_ack;
  67. wb_out.stall <= '0'; -- never stall wishbone
  68. comb : process(all)
  69. variable v : reg_internal_t;
  70. variable xirr_accept_rd : std_ulogic;
  71. function bswap(v : in std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
  72. variable r : std_ulogic_vector(31 downto 0);
  73. begin
  74. r( 7 downto 0) := v(31 downto 24);
  75. r(15 downto 8) := v(23 downto 16);
  76. r(23 downto 16) := v(15 downto 8);
  77. r(31 downto 24) := v( 7 downto 0);
  78. return r;
  79. end function;
  80. variable be_in : std_ulogic_vector(31 downto 0);
  81. variable be_out : std_ulogic_vector(31 downto 0);
  82. variable pending_priority : std_ulogic_vector(7 downto 0);
  83. begin
  84. v := r;
  85. v.wb_ack := '0';
  86. xirr_accept_rd := '0';
  87. be_in := bswap(wb_in.dat);
  88. be_out := (others => '0');
  89. if wb_in.cyc = '1' and wb_in.stb = '1' then
  90. v.wb_ack := '1'; -- always ack
  91. if wb_in.we = '1' then -- write
  92. -- writes to both XIRR are the same
  93. case wb_in.adr(7 downto 0) is
  94. when XIRR_POLL =>
  95. report "ICP XIRR_POLL write";
  96. v.cppr := be_in(31 downto 24);
  97. when XIRR =>
  98. v.cppr := be_in(31 downto 24);
  99. if wb_in.sel = x"f" then -- 4 byte
  100. report "ICP XIRR write word (EOI) :" & to_hstring(be_in);
  101. elsif wb_in.sel = x"1" then -- 1 byte
  102. report "ICP XIRR write byte (CPPR):" & to_hstring(be_in(31 downto 24));
  103. else
  104. report "ICP XIRR UNSUPPORTED write ! sel=" & to_hstring(wb_in.sel);
  105. end if;
  106. when MFRR =>
  107. v.mfrr := be_in(31 downto 24);
  108. if wb_in.sel = x"f" then -- 4 bytes
  109. report "ICP MFRR write word:" & to_hstring(be_in);
  110. elsif wb_in.sel = x"1" then -- 1 byte
  111. report "ICP MFRR write byte:" & to_hstring(be_in(31 downto 24));
  112. else
  113. report "ICP MFRR UNSUPPORTED write ! sel=" & to_hstring(wb_in.sel);
  114. end if;
  115. when others =>
  116. end case;
  117. else -- read
  118. case wb_in.adr(7 downto 0) is
  119. when XIRR_POLL =>
  120. report "ICP XIRR_POLL read";
  121. be_out := r.cppr & r.xisr;
  122. when XIRR =>
  123. report "ICP XIRR read";
  124. be_out := r.cppr & r.xisr;
  125. if wb_in.sel = x"f" then
  126. xirr_accept_rd := '1';
  127. end if;
  128. when MFRR =>
  129. report "ICP MFRR read";
  130. be_out(31 downto 24) := r.mfrr;
  131. when others =>
  132. end case;
  133. end if;
  134. end if;
  135. pending_priority := x"ff";
  136. v.xisr := x"000000";
  137. v.irq := '0';
  138. if ics_in.pri /= x"ff" then
  139. v.xisr := x"00001" & ics_in.src;
  140. pending_priority := ics_in.pri;
  141. end if;
  142. -- Check MFRR
  143. if unsigned(r.mfrr) < unsigned(pending_priority) then --
  144. v.xisr := x"000002"; -- special XICS MFRR IRQ source number
  145. pending_priority := r.mfrr;
  146. end if;
  147. -- Accept the interrupt
  148. if xirr_accept_rd = '1' then
  149. report "XICS: ICP ACCEPT" &
  150. " cppr:" & to_hstring(r.cppr) &
  151. " xisr:" & to_hstring(r.xisr) &
  152. " mfrr:" & to_hstring(r.mfrr);
  153. v.cppr := pending_priority;
  154. end if;
  155. v.wb_rd_data := bswap(be_out);
  156. if unsigned(pending_priority) < unsigned(v.cppr) then
  157. if r.irq = '0' then
  158. report "IRQ set";
  159. end if;
  160. v.irq := '1';
  161. elsif r.irq = '1' then
  162. report "IRQ clr";
  163. end if;
  164. if rst = '1' then
  165. v := reg_internal_init;
  166. end if;
  167. r_next <= v;
  168. end process;
  169. end architecture behaviour;
  170. library ieee;
  171. use ieee.std_logic_1164.all;
  172. use ieee.numeric_std.all;
  173. library work;
  174. use work.common.all;
  175. use work.wishbone_types.all;
  176. entity xics_ics is
  177. generic (
  178. SRC_NUM : integer range 1 to 256 := 16;
  179. PRIO_BITS : integer range 1 to 8 := 8
  180. );
  181. port (
  182. clk : in std_logic;
  183. rst : in std_logic;
  184. wb_in : in wb_io_master_out;
  185. wb_out : out wb_io_slave_out;
  186. int_level_in : in std_ulogic_vector(SRC_NUM - 1 downto 0);
  187. icp_out : out ics_to_icp_t
  188. );
  189. end xics_ics;
  190. architecture rtl of xics_ics is
  191. subtype pri_t is std_ulogic_vector(PRIO_BITS-1 downto 0);
  192. type xive_t is record
  193. pri : pri_t;
  194. end record;
  195. constant pri_masked : pri_t := (others => '1');
  196. type xive_array_t is array(0 to SRC_NUM-1) of xive_t;
  197. signal xives : xive_array_t;
  198. signal wb_valid : std_ulogic;
  199. signal reg_idx : integer range 0 to SRC_NUM - 1;
  200. signal icp_out_next : ics_to_icp_t;
  201. signal int_level_l : std_ulogic_vector(SRC_NUM - 1 downto 0);
  202. function bswap(v : in std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
  203. variable r : std_ulogic_vector(31 downto 0);
  204. begin
  205. r( 7 downto 0) := v(31 downto 24);
  206. r(15 downto 8) := v(23 downto 16);
  207. r(23 downto 16) := v(15 downto 8);
  208. r(31 downto 24) := v( 7 downto 0);
  209. return r;
  210. end function;
  211. function get_config return std_ulogic_vector is
  212. variable r: std_ulogic_vector(31 downto 0);
  213. begin
  214. r := (others => '0');
  215. r(23 downto 0) := std_ulogic_vector(to_unsigned(SRC_NUM, 24));
  216. r(27 downto 24) := std_ulogic_vector(to_unsigned(PRIO_BITS, 4));
  217. return r;
  218. end function;
  219. function prio_pack(pri8: std_ulogic_vector(7 downto 0)) return pri_t is
  220. begin
  221. return pri8(PRIO_BITS-1 downto 0);
  222. end function;
  223. function prio_unpack(pri: pri_t) return std_ulogic_vector is
  224. variable r : std_ulogic_vector(7 downto 0);
  225. begin
  226. if pri = pri_masked then
  227. r := x"ff";
  228. else
  229. r := (others => '0');
  230. r(PRIO_BITS-1 downto 0) := pri;
  231. end if;
  232. return r;
  233. end function;
  234. -- Register map
  235. -- 0 : Config
  236. -- 4 : Debug/diagnostics
  237. -- 800 : XIVE0
  238. -- 804 : XIVE1 ...
  239. --
  240. -- Config register format:
  241. --
  242. -- 23.. 0 : Interrupt base (hard wired to 16)
  243. -- 27.. 24 : #prio bits (1..8)
  244. --
  245. -- XIVE register format:
  246. --
  247. -- 31 : input bit (reflects interrupt input)
  248. -- 30 : reserved
  249. -- 29 : P (mirrors input for now)
  250. -- 28 : Q (not implemented in this version)
  251. -- 30 .. : reserved
  252. -- 19 .. 8 : target (not implemented in this version)
  253. -- 7 .. 0 : prio/mask
  254. signal reg_is_xive : std_ulogic;
  255. signal reg_is_config : std_ulogic;
  256. signal reg_is_debug : std_ulogic;
  257. begin
  258. assert SRC_NUM = 16 report "Fixup address decode with log2";
  259. reg_is_xive <= wb_in.adr(11);
  260. reg_is_config <= '1' when wb_in.adr(11 downto 0) = x"000" else '0';
  261. reg_is_debug <= '1' when wb_in.adr(11 downto 0) = x"004" else '0';
  262. -- Register index XX FIXME: figure out bits from SRC_NUM
  263. reg_idx <= to_integer(unsigned(wb_in.adr(5 downto 2)));
  264. -- Latch interrupt inputs for timing
  265. int_latch: process(clk)
  266. begin
  267. if rising_edge(clk) then
  268. int_level_l <= int_level_in;
  269. end if;
  270. end process;
  271. -- We don't stall. Acks are sent by the read machine one cycle
  272. -- after a request, but we can handle one access per cycle.
  273. wb_out.stall <= '0';
  274. wb_valid <= wb_in.cyc and wb_in.stb;
  275. -- Big read mux. This could be replaced by a slower state
  276. -- machine iterating registers instead if timing gets tight.
  277. reg_read: process(clk)
  278. variable be_out : std_ulogic_vector(31 downto 0);
  279. begin
  280. if rising_edge(clk) then
  281. be_out := (others => '0');
  282. if reg_is_xive = '1' then
  283. be_out := int_level_l(reg_idx) &
  284. '0' &
  285. int_level_l(reg_idx) &
  286. '0' &
  287. x"00000" &
  288. prio_unpack(xives(reg_idx).pri);
  289. elsif reg_is_config = '1' then
  290. be_out := get_config;
  291. elsif reg_is_debug = '1' then
  292. be_out := x"00000" & icp_out_next.src & icp_out_next.pri;
  293. end if;
  294. wb_out.dat <= bswap(be_out);
  295. wb_out.ack <= wb_valid;
  296. end if;
  297. end process;
  298. -- Register write machine
  299. reg_write: process(clk)
  300. variable be_in : std_ulogic_vector(31 downto 0);
  301. begin
  302. -- Byteswapped input
  303. be_in := bswap(wb_in.dat);
  304. if rising_edge(clk) then
  305. if rst = '1' then
  306. for i in 0 to SRC_NUM - 1 loop
  307. xives(i) <= (pri => pri_masked);
  308. end loop;
  309. elsif wb_valid = '1' and wb_in.we = '1' then
  310. if reg_is_xive then
  311. -- TODO: When adding support for other bits, make sure to
  312. -- properly implement wb_in.sel to allow partial writes.
  313. xives(reg_idx).pri <= prio_pack(be_in(7 downto 0));
  314. report "ICS irq " & integer'image(reg_idx) &
  315. " set to:" & to_hstring(be_in(7 downto 0));
  316. end if;
  317. end if;
  318. end if;
  319. end process;
  320. -- generate interrupt. This is a simple combinational process,
  321. -- potentially wasteful in HW for large number of interrupts.
  322. --
  323. -- could be replaced with iterative state machines and a message
  324. -- system between ICSs' (plural) and ICP incl. reject etc...
  325. --
  326. irq_gen_sync: process(clk)
  327. begin
  328. if rising_edge(clk) then
  329. icp_out <= icp_out_next;
  330. end if;
  331. end process;
  332. irq_gen: process(all)
  333. variable max_idx : integer range 0 to SRC_NUM-1;
  334. variable max_pri : pri_t;
  335. -- A more favored than b ?
  336. function a_mf_b(a: pri_t; b: pri_t) return boolean is
  337. variable a_i : unsigned(PRIO_BITS-1 downto 0);
  338. variable b_i : unsigned(PRIO_BITS-1 downto 0);
  339. begin
  340. a_i := unsigned(a);
  341. b_i := unsigned(b);
  342. report "a_mf_b a=" & to_hstring(a) &
  343. " b=" & to_hstring(b) &
  344. " r=" & boolean'image(a < b);
  345. return a_i < b_i;
  346. end function;
  347. begin
  348. -- XXX FIXME: Use a tree
  349. max_pri := pri_masked;
  350. max_idx := 0;
  351. for i in 0 to SRC_NUM - 1 loop
  352. if int_level_l(i) = '1' and a_mf_b(xives(i).pri, max_pri) then
  353. max_pri := xives(i).pri;
  354. max_idx := i;
  355. end if;
  356. end loop;
  357. if max_pri /= pri_masked then
  358. report "MFI: " & integer'image(max_idx) & " pri=" & to_hstring(prio_unpack(max_pri));
  359. end if;
  360. icp_out_next.src <= std_ulogic_vector(to_unsigned(max_idx, 4));
  361. icp_out_next.pri <= prio_unpack(max_pri);
  362. end process;
  363. end architecture rtl;