ignore /abc.history
[microwatt.git] / xics.vhdl
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
19 library ieee;
20 use ieee.std_logic_1164.all;
21 use ieee.numeric_std.all;
22
23 library work;
24 use work.common.all;
25 use work.wishbone_types.all;
26
27 entity xics_icp is
28 port (
29 clk : in std_logic;
30 rst : in std_logic;
31
32 wb_in : in wb_io_master_out;
33 wb_out : out wb_io_slave_out;
34
35 ics_in : in ics_to_icp_t;
36 core_irq_out : out std_ulogic
37 );
38 end xics_icp;
39
40 architecture behaviour of xics_icp is
41 type reg_internal_t is record
42 xisr : std_ulogic_vector(23 downto 0);
43 cppr : std_ulogic_vector(7 downto 0);
44 mfrr : std_ulogic_vector(7 downto 0);
45 irq : std_ulogic;
46 wb_rd_data : std_ulogic_vector(31 downto 0);
47 wb_ack : std_ulogic;
48 end record;
49 constant reg_internal_init : reg_internal_t :=
50 (wb_ack => '0',
51 mfrr => x"ff", -- mask everything on reset
52 irq => '0',
53 others => (others => '0'));
54
55 signal r, r_next : reg_internal_t;
56
57 -- 8 bit offsets for each presentation
58 constant XIRR_POLL : std_ulogic_vector(7 downto 0) := x"00";
59 constant XIRR : std_ulogic_vector(7 downto 0) := x"04";
60 constant RESV0 : std_ulogic_vector(7 downto 0) := x"08";
61 constant MFRR : std_ulogic_vector(7 downto 0) := x"0c";
62
63 begin
64
65 regs : process(clk)
66 begin
67 if rising_edge(clk) then
68 r <= r_next;
69
70 -- We delay core_irq_out by a cycle to help with timing
71 core_irq_out <= r.irq;
72 end if;
73 end process;
74
75 wb_out.dat <= r.wb_rd_data;
76 wb_out.ack <= r.wb_ack;
77 wb_out.stall <= '0'; -- never stall wishbone
78
79 comb : process(all)
80 variable v : reg_internal_t;
81 variable xirr_accept_rd : std_ulogic;
82
83 function bswap(vec : in std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
84 variable rout : std_ulogic_vector(31 downto 0);
85 begin
86 rout( 7 downto 0) := vec(31 downto 24);
87 rout(15 downto 8) := vec(23 downto 16);
88 rout(23 downto 16) := vec(15 downto 8);
89 rout(31 downto 24) := vec( 7 downto 0);
90 return rout;
91 end function;
92
93 variable be_in : std_ulogic_vector(31 downto 0);
94 variable be_out : std_ulogic_vector(31 downto 0);
95
96 variable pending_priority : std_ulogic_vector(7 downto 0);
97 begin
98 v := r;
99
100 v.wb_ack := '0';
101
102 xirr_accept_rd := '0';
103
104 be_in := bswap(wb_in.dat);
105 be_out := (others => '0');
106
107 if wb_in.cyc = '1' and wb_in.stb = '1' then
108 v.wb_ack := '1'; -- always ack
109 if wb_in.we = '1' then -- write
110 -- writes to both XIRR are the same
111 case wb_in.adr(5 downto 0) & "00" is
112 when XIRR_POLL =>
113 report "ICP XIRR_POLL write";
114 v.cppr := be_in(31 downto 24);
115 when XIRR =>
116 v.cppr := be_in(31 downto 24);
117 if wb_in.sel = x"f" then -- 4 byte
118 report "ICP XIRR write word (EOI) :" & to_hstring(be_in);
119 elsif wb_in.sel = x"1" then -- 1 byte
120 report "ICP XIRR write byte (CPPR):" & to_hstring(be_in(31 downto 24));
121 else
122 report "ICP XIRR UNSUPPORTED write ! sel=" & to_hstring(wb_in.sel);
123 end if;
124 when MFRR =>
125 v.mfrr := be_in(31 downto 24);
126 if wb_in.sel = x"f" then -- 4 bytes
127 report "ICP MFRR write word:" & to_hstring(be_in);
128 elsif wb_in.sel = x"1" then -- 1 byte
129 report "ICP MFRR write byte:" & to_hstring(be_in(31 downto 24));
130 else
131 report "ICP MFRR UNSUPPORTED write ! sel=" & to_hstring(wb_in.sel);
132 end if;
133 when others =>
134 end case;
135
136 else -- read
137
138 case wb_in.adr(5 downto 0) & "00" is
139 when XIRR_POLL =>
140 report "ICP XIRR_POLL read";
141 be_out := r.cppr & r.xisr;
142 when XIRR =>
143 report "ICP XIRR read";
144 be_out := r.cppr & r.xisr;
145 if wb_in.sel = x"f" then
146 xirr_accept_rd := '1';
147 end if;
148 when MFRR =>
149 report "ICP MFRR read";
150 be_out(31 downto 24) := r.mfrr;
151 when others =>
152 end case;
153 end if;
154 end if;
155
156 pending_priority := x"ff";
157 v.xisr := x"000000";
158 v.irq := '0';
159
160 if ics_in.pri /= x"ff" then
161 v.xisr := x"00001" & ics_in.src;
162 pending_priority := ics_in.pri;
163 end if;
164
165 -- Check MFRR
166 if unsigned(r.mfrr) < unsigned(pending_priority) then --
167 v.xisr := x"000002"; -- special XICS MFRR IRQ source number
168 pending_priority := r.mfrr;
169 end if;
170
171 -- Accept the interrupt
172 if xirr_accept_rd = '1' then
173 report "XICS: ICP ACCEPT" &
174 " cppr:" & to_hstring(r.cppr) &
175 " xisr:" & to_hstring(r.xisr) &
176 " mfrr:" & to_hstring(r.mfrr);
177 v.cppr := pending_priority;
178 end if;
179
180 v.wb_rd_data := bswap(be_out);
181
182 if unsigned(pending_priority) < unsigned(v.cppr) then
183 if r.irq = '0' then
184 report "IRQ set";
185 end if;
186 v.irq := '1';
187 elsif r.irq = '1' then
188 report "IRQ clr";
189 end if;
190
191 if rst = '1' then
192 v := reg_internal_init;
193 end if;
194
195 r_next <= v;
196
197 end process;
198
199 end architecture behaviour;
200
201 library ieee;
202 use ieee.std_logic_1164.all;
203 use ieee.numeric_std.all;
204
205 library work;
206 use work.common.all;
207 use work.utils.all;
208 use work.wishbone_types.all;
209 use work.helpers.all;
210
211 entity xics_ics is
212 generic (
213 SRC_NUM : integer range 1 to 256 := 16;
214 PRIO_BITS : integer range 1 to 8 := 3
215 );
216 port (
217 clk : in std_logic;
218 rst : in std_logic;
219
220 wb_in : in wb_io_master_out;
221 wb_out : out wb_io_slave_out;
222
223 int_level_in : in std_ulogic_vector(SRC_NUM - 1 downto 0);
224 icp_out : out ics_to_icp_t
225 );
226 end xics_ics;
227
228 architecture rtl of xics_ics is
229
230 constant SRC_NUM_BITS : natural := log2(SRC_NUM);
231
232 subtype pri_t is std_ulogic_vector(PRIO_BITS-1 downto 0);
233 type xive_t is record
234 pri : pri_t;
235 end record;
236 constant pri_masked : pri_t := (others => '1');
237
238 subtype pri_vector_t is std_ulogic_vector(2**PRIO_BITS - 1 downto 0);
239
240 type xive_array_t is array(0 to SRC_NUM-1) of xive_t;
241 signal xives : xive_array_t;
242
243 signal wb_valid : std_ulogic;
244 signal reg_idx : integer range 0 to SRC_NUM - 1;
245 signal icp_out_next : ics_to_icp_t;
246 signal int_level_l : std_ulogic_vector(SRC_NUM - 1 downto 0);
247
248 function bswap(v : in std_ulogic_vector(31 downto 0)) return std_ulogic_vector is
249 variable r : std_ulogic_vector(31 downto 0);
250 begin
251 r( 7 downto 0) := v(31 downto 24);
252 r(15 downto 8) := v(23 downto 16);
253 r(23 downto 16) := v(15 downto 8);
254 r(31 downto 24) := v( 7 downto 0);
255 return r;
256 end function;
257
258 function get_config return std_ulogic_vector is
259 variable r: std_ulogic_vector(31 downto 0);
260 begin
261 r := (others => '0');
262 r(23 downto 0) := std_ulogic_vector(to_unsigned(SRC_NUM, 24));
263 r(27 downto 24) := std_ulogic_vector(to_unsigned(PRIO_BITS, 4));
264 return r;
265 end function;
266
267 function prio_pack(pri8: std_ulogic_vector(7 downto 0)) return pri_t is
268 variable masked : std_ulogic_vector(7 downto 0);
269 begin
270 masked := x"00";
271 masked(PRIO_BITS - 1 downto 0) := (others => '1');
272 if unsigned(pri8) >= unsigned(masked) then
273 return pri_masked;
274 else
275 return pri8(PRIO_BITS-1 downto 0);
276 end if;
277 end function;
278
279 function prio_unpack(pri: pri_t) return std_ulogic_vector is
280 variable r : std_ulogic_vector(7 downto 0);
281 begin
282 if pri = pri_masked then
283 r := x"ff";
284 else
285 r := (others => '0');
286 r(PRIO_BITS-1 downto 0) := pri;
287 end if;
288 return r;
289 end function;
290
291 function prio_decode(pri: pri_t) return pri_vector_t is
292 variable v: pri_vector_t;
293 begin
294 v := (others => '0');
295 v(to_integer(unsigned(pri))) := '1';
296 return v;
297 end function;
298
299 -- Assumes nbits <= 6; v is 2^nbits wide
300 function priority_encoder(v: std_ulogic_vector; nbits: natural) return std_ulogic_vector is
301 variable h: std_ulogic_vector(2**nbits - 1 downto 0);
302 variable p: std_ulogic_vector(5 downto 0);
303 begin
304 -- Set the lowest-priority (highest-numbered) bit
305 h := v;
306 h(2**nbits - 1) := '1';
307 p := count_right_zeroes(h);
308 return p(nbits - 1 downto 0);
309 end function;
310
311 -- Register map
312 -- 0 : Config
313 -- 4 : Debug/diagnostics
314 -- 800 : XIVE0
315 -- 804 : XIVE1 ...
316 --
317 -- Config register format:
318 --
319 -- 23.. 0 : Interrupt base (hard wired to 16)
320 -- 27.. 24 : #prio bits (1..8)
321 --
322 -- XIVE register format:
323 --
324 -- 31 : input bit (reflects interrupt input)
325 -- 30 : reserved
326 -- 29 : P (mirrors input for now)
327 -- 28 : Q (not implemented in this version)
328 -- 30 .. : reserved
329 -- 19 .. 8 : target (not implemented in this version)
330 -- 7 .. 0 : prio/mask
331
332 signal reg_is_xive : std_ulogic;
333 signal reg_is_config : std_ulogic;
334 signal reg_is_debug : std_ulogic;
335
336 begin
337
338 assert SRC_NUM = 16 report "Fixup address decode with log2";
339
340 reg_is_xive <= wb_in.adr(9);
341 reg_is_config <= '1' when wb_in.adr(9 downto 0) = 10x"000" else '0';
342 reg_is_debug <= '1' when wb_in.adr(9 downto 0) = 10x"001" else '0';
343
344 -- Register index XX FIXME: figure out bits from SRC_NUM
345 reg_idx <= to_integer(unsigned(wb_in.adr(3 downto 0)));
346
347 -- Latch interrupt inputs for timing
348 int_latch: process(clk)
349 begin
350 if rising_edge(clk) then
351 int_level_l <= int_level_in;
352 end if;
353 end process;
354
355 -- We don't stall. Acks are sent by the read machine one cycle
356 -- after a request, but we can handle one access per cycle.
357 wb_out.stall <= '0';
358 wb_valid <= wb_in.cyc and wb_in.stb;
359
360 -- Big read mux. This could be replaced by a slower state
361 -- machine iterating registers instead if timing gets tight.
362 reg_read: process(clk)
363 variable be_out : std_ulogic_vector(31 downto 0);
364 begin
365 if rising_edge(clk) then
366 be_out := (others => '0');
367
368 if reg_is_xive = '1' then
369 be_out := int_level_l(reg_idx) &
370 '0' &
371 int_level_l(reg_idx) &
372 '0' &
373 x"00000" &
374 prio_unpack(xives(reg_idx).pri);
375 elsif reg_is_config = '1' then
376 be_out := get_config;
377 elsif reg_is_debug = '1' then
378 be_out := x"00000" & icp_out_next.src & icp_out_next.pri;
379 end if;
380 wb_out.dat <= bswap(be_out);
381 wb_out.ack <= wb_valid;
382 end if;
383 end process;
384
385 -- Register write machine
386 reg_write: process(clk)
387 variable be_in : std_ulogic_vector(31 downto 0);
388 begin
389 -- Byteswapped input
390 be_in := bswap(wb_in.dat);
391
392 if rising_edge(clk) then
393 if rst = '1' then
394 for i in 0 to SRC_NUM - 1 loop
395 xives(i) <= (pri => pri_masked);
396 end loop;
397 elsif wb_valid = '1' and wb_in.we = '1' then
398 if reg_is_xive then
399 -- TODO: When adding support for other bits, make sure to
400 -- properly implement wb_in.sel to allow partial writes.
401 xives(reg_idx).pri <= prio_pack(be_in(7 downto 0));
402 report "ICS irq " & integer'image(reg_idx) &
403 " set to:" & to_hstring(be_in(7 downto 0));
404 end if;
405 end if;
406 end if;
407 end process;
408
409 -- generate interrupt. This is a simple combinational process,
410 -- potentially wasteful in HW for large number of interrupts.
411 --
412 -- could be replaced with iterative state machines and a message
413 -- system between ICSs' (plural) and ICP incl. reject etc...
414 --
415 irq_gen_sync: process(clk)
416 begin
417 if rising_edge(clk) then
418 icp_out <= icp_out_next;
419 end if;
420 end process;
421
422 irq_gen: process(all)
423 variable max_idx : std_ulogic_vector(SRC_NUM_BITS - 1 downto 0);
424 variable max_pri : pri_t;
425 variable pending_pri : pri_vector_t;
426 variable pending_at_pri : std_ulogic_vector(SRC_NUM - 1 downto 0);
427 begin
428 -- Work out the most-favoured (lowest) priority of the pending interrupts
429 pending_pri := (others => '0');
430 for i in 0 to SRC_NUM - 1 loop
431 if int_level_l(i) = '1' then
432 pending_pri := pending_pri or prio_decode(xives(i).pri);
433 end if;
434 end loop;
435 max_pri := priority_encoder(pending_pri, PRIO_BITS);
436
437 -- Work out which interrupts are pending at that priority
438 pending_at_pri := (others => '0');
439 for i in 0 to SRC_NUM - 1 loop
440 if int_level_l(i) = '1' and xives(i).pri = max_pri then
441 pending_at_pri(i) := '1';
442 end if;
443 end loop;
444 max_idx := priority_encoder(pending_at_pri, SRC_NUM_BITS);
445
446 if max_pri /= pri_masked then
447 report "MFI: " & integer'image(to_integer(unsigned(max_idx))) & " pri=" & to_hstring(prio_unpack(max_pri));
448 end if;
449 icp_out_next.src <= max_idx;
450 icp_out_next.pri <= prio_unpack(max_pri);
451 end process;
452
453 end architecture rtl;