XICS addresses in words: divide by 4
[soc.git] / src / soc / interrupts / xics.py
1 """Microwatt xics.vhdl converted to nmigen
2 #
3 # This is a simple XICS compliant interrupt controller. This is a
4 # Presenter (ICP) and Source (ICS) in two small units directly
5 # connected to each other with no routing layer.
6 #
7 # The sources have a configurable IRQ priority set a set of ICS
8 # registers in the source units.
9 #
10 # The source ids start at 16 for int_level_in(0) and go up from
11 # there (ie int_level_in(1) is source id 17). XXX Make a generic
12 #
13 # The presentation layer will pick an interupt that is more
14 # favourable than the current CPPR and present it via the XISR and
15 # send an interrpt to the processor (via e_out). This may not be the
16 # highest priority interrupt currently presented (which is allowed
17 # via XICS)
18 #
19 """
20 from nmigen import Elaboratable, Module, Signal, Cat, Const, Record, Array, Mux
21 from nmutil.iocontrol import RecordObject
22 from nmigen.utils import log2_int
23 from nmigen.cli import rtlil
24 from soc.minerva.wishbone import make_wb_layout
25 from nmutil.util import wrap
26 from soc.bus.test.wb_rw import wb_read, wb_write
27
28
29 cxxsim = False
30 if cxxsim:
31 from nmigen.sim.cxxsim import Simulator, Settle
32 else:
33 from nmigen.back.pysim import Simulator, Settle
34
35
36
37 class ICS2ICP(RecordObject):
38 """
39 # Level interrupts only, ICS just keeps prsenting the
40 # highest priority interrupt. Once handling edge, something
41 # smarter involving handshake & reject support will be needed
42 """
43 def __init__(self, name):
44 super().__init__(name=name)
45 self.src = Signal(4, reset_less=True)
46 self.pri = Signal(8, reset_less=True)
47
48 # hardwire the hardware IRQ priority
49 HW_PRIORITY = Const(0x80, 8)
50
51 # 8 bit offsets for each presentation - all addresses are in "words"
52 XIRR_POLL = 0x00
53 XIRR = 0x01
54 RESV0 = 0x02
55 MFRR = 0x03
56
57
58 class RegInternal(RecordObject):
59 def __init__(self, name=None):
60 super().__init__(name=name)
61 self.xisr = Signal(24)
62 self.cppr = Signal(8)
63 self.mfrr = Signal(8, reset=0xff) # mask everything on reset
64 self.irq = Signal(1)
65 self.wb_rd_data = Signal(32)
66 self.wb_ack = Signal(1)
67
68
69 def bswap(v):
70 return Cat(v[24:32], v[16:24], v[8:16], v[0:8])
71
72
73 class XICS_ICP(Elaboratable):
74
75 def __init__(self):
76 class Spec: pass
77 spec = Spec()
78 spec.addr_wid = 30
79 spec.mask_wid = 4
80 spec.reg_wid = 32
81 self.bus = Record(make_wb_layout(spec), name="icp_wb")
82 self.ics_i = ICS2ICP("ics_i")
83 self.core_irq_o = Signal()
84
85 def elaborate(self, platform):
86 m = Module()
87 comb, sync = m.d.comb, m.d.sync
88
89 r = RegInternal()
90 r_next = RegInternal()
91
92 sync += r.eq(r_next)
93 # We delay core_irq_out by a cycle to help with timing
94 sync += self.core_irq_o.eq(r.irq)
95
96 comb += self.bus.dat_r.eq(r.wb_rd_data)
97 comb += self.bus.ack.eq(r.wb_ack)
98
99 v = RegInternal()
100 xirr_accept_rd = Signal()
101
102 be_in = Signal(32)
103 be_out = Signal(32)
104
105 pending_priority = Signal(8)
106
107 comb += v.eq(r) # start from the register (r)
108 comb += v.wb_ack.eq(0)
109
110 comb += xirr_accept_rd.eq(0)
111
112 comb += be_in.eq(bswap(self.bus.dat_w))
113 comb += be_out.eq(0)
114
115 with m.If(self.bus.cyc & self.bus.stb):
116 comb += v.wb_ack.eq(1) # always ack
117 with m.If(self.bus.we): # write
118 # writes to both XIRR are the same
119 with m.Switch(self.bus.adr[:8]):
120 with m.Case(XIRR_POLL):
121 # report "ICP XIRR_POLL write";
122 comb += v.cppr.eq(be_in[24:32])
123 with m.Case(XIRR):
124 comb += v.cppr.eq(be_in[24:32])
125 with m.If(self.bus.sel == 0xf): # # 4 byte
126 #report "ICP XIRR write word (EOI) :" & \
127 # to_hstring(be_in);
128 pass
129 with m.Elif(self.bus.sel == 0x1): # 1 byte
130 #report "ICP XIRR write byte (CPPR):" & \
131 #to_hstring(be_in(31 downto 24));
132 pass
133 with m.Else():
134 #report "ICP XIRR UNSUPPORTED write ! sel=" & \
135 # to_hstring(self.bus.sel);
136 pass
137 with m.Case(MFRR ):
138 comb += v.mfrr.eq(be_in[24:32])
139 with m.If(self.bus.sel == 0xf): # # 4 byte
140 # report "ICP MFRR write word:" & to_hstring(be_in);
141 pass
142 with m.Elif(self.bus.sel == 0x1): # 1 byte
143 # report "ICP MFRR write byte:" & \
144 # to_hstring(be_in(31 downto 24));
145 pass
146 with m.Else():
147 # report "ICP MFRR UNSUPPORTED write ! sel=" & \
148 # to_hstring(self.bus.sel);
149 pass
150
151 with m.Else(): # read
152
153 with m.Switch(self.bus.adr[:8]):
154 with m.Case(XIRR_POLL):
155 # report "ICP XIRR_POLL read";
156 comb += be_out.eq(r.xisr & r.cppr)
157 with m.Case(XIRR):
158 # report "ICP XIRR read";
159 comb += be_out.eq(Cat(r.xisr, r.cppr))
160 with m.If(self.bus.sel == 0xf): # # 4 byte
161 comb += xirr_accept_rd.eq(1)
162 with m.Case(MFRR):
163 # report "ICP MFRR read";
164 comb += be_out.eq(r.mfrr)
165
166 comb += pending_priority.eq(0xff)
167 comb += v.xisr.eq(0x0)
168 comb += v.irq.eq(0x0)
169
170 # set XISR
171 with m.If(self.ics_i.pri != 0xff):
172 comb += v.xisr.eq(Cat(self.ics_i.src, Const(0x00001, 20)))
173 comb += pending_priority.eq(self.ics_i.pri)
174
175 # Check MFRR
176 with m.If(r.mfrr < pending_priority):
177 comb += v.xisr.eq(Const(0x2)) # special XICS MFRR IRQ source number
178 comb += pending_priority.eq(r.mfrr)
179
180 # Accept the interrupt
181 with m.If(xirr_accept_rd):
182 #report "XICS: ICP ACCEPT" &
183 # " cppr:" & to_hstring(r.cppr) &
184 # " xisr:" & to_hstring(r.xisr) &
185 # " mfrr:" & to_hstring(r.mfrr);
186 comb += v.cppr.eq(pending_priority)
187
188 comb += v.wb_rd_data.eq(bswap(be_out))
189
190 # check if the core needs an interrupt notification (or clearing)
191 comb += v.irq.eq(pending_priority < v.cppr)
192 with m.If(v.irq):
193 with m.If(~r.irq):
194 #report "IRQ set";
195 pass
196 with m.Elif(r.irq):
197 #report "IRQ clr";
198 pass
199
200 comb += r_next.eq(v)
201
202 return m
203
204 def __iter__(self):
205 for field in self.bus.fields.values():
206 yield field
207 yield from self.ics_i
208 yield self.core_irq_o
209
210 def ports(self):
211 return list(self)
212
213
214 class Xive(RecordObject):
215 def __init__(self, name, wid, rst):
216 super().__init__(name=name)
217 self.pri = Signal(wid, reset=rst)
218
219
220
221 class XICS_ICS(Elaboratable):
222 def __init__(self, SRC_NUM=16, PRIO_BITS=8):
223 self.SRC_NUM = SRC_NUM
224 self.PRIO_BITS = PRIO_BITS
225 self.pri_masked = (1<<self.PRIO_BITS)-1
226 class Spec: pass
227 spec = Spec()
228 spec.addr_wid = 30
229 spec.mask_wid = 4
230 spec.reg_wid = 32
231 self.bus = Record(make_wb_layout(spec), name="ics_wb")
232
233 self.int_level_i = Signal(SRC_NUM)
234 self.icp_o = ICS2ICP("icp_o")
235
236 def prio_pack(self, pri8):
237 return pri8[:self.PRIO_BITS]
238
239 def prio_unpack(self, pri):
240 return Mux(pri == self.pri_masked, Const(0xff, 8), pri[:self.PRIO_BITS])
241
242 # A more favored than b ?
243 def a_mf_b(self, a, b):
244 #report "a_mf_b a=" & to_hstring(a) &
245 # " b=" & to_hstring(b) &
246 # " r=" & boolean'image(a < b);
247 return a < b;
248
249 def elaborate(self, platform):
250 m = Module()
251 comb, sync = m.d.comb, m.d.sync
252
253 xives = Array([Xive("xive%d" % i, self.PRIO_BITS, self.pri_masked)
254 for i in range(self.SRC_NUM)])
255
256 wb_valid = Signal()
257 reg_idx = Signal(log2_int(self.SRC_NUM))
258 icp_o_next = ICS2ICP("icp_r")
259 int_level_l = Signal(self.SRC_NUM)
260
261 # Register map
262 # 0 : Config
263 # 4 : Debug/diagnostics
264 # 800 : XIVE0
265 # 804 : XIVE1 ...
266 #
267 # Config register format:
268 #
269 # 23.. 0 : Interrupt base (hard wired to 16)
270 # 27.. 24 : #prio bits (1..8)
271 #
272 # XIVE register format:
273 #
274 # 31 : input bit (reflects interrupt input)
275 # 30 : reserved
276 # 29 : P (mirrors input for now)
277 # 28 : Q (not implemented in this version)
278 # 30 .. : reserved
279 # 19 .. 8 : target (not implemented in this version)
280 # 7 .. 0 : prio/mask
281
282 reg_is_xive = Signal()
283 reg_is_config = Signal()
284 reg_is_debug = Signal()
285
286 assert self.SRC_NUM == 16, "Fixup address decode with log2"
287
288 comb += reg_is_xive.eq(self.bus.adr[9])
289 comb += reg_is_config.eq(self.bus.adr[0:10] == 0x0)
290 comb += reg_is_debug.eq(self.bus.adr[0:10] == 0x4)
291
292 # Register index XX FIXME: figure out bits from SRC_NUM
293 comb += reg_idx.eq(self.bus.adr[:4])
294
295 # Latch interrupt inputs for timing
296 sync += int_level_l.eq(self.int_level_i)
297
298 # We don't stall. Acks are sent by the read machine one cycle
299 # after a request, but we can handle one access per cycle.
300 comb += wb_valid.eq(self.bus.cyc & self.bus.stb)
301
302 # Big read mux. This could be replaced by a slower state
303 # machine iterating registers instead if timing gets tight.
304 be_out = Signal(32)
305 comb += be_out.eq(0)
306
307 # XIVE reg
308 with m.If(reg_is_xive):
309 pri_i = self.prio_unpack(xives[reg_idx].pri)
310 ibit = Signal()
311 comb += ibit.eq(int_level_l.bit_select(reg_idx, 1))
312 comb += be_out.eq(Cat(pri_i, # bits 0..7
313 Const(0, 20), # 8-27
314 0, # 28
315 ibit, # 29
316 0, # 30
317 ibit)) # 31
318 # Config reg
319 with m.Elif(reg_is_config):
320 comb += be_out.eq(Cat(Const(self.SRC_NUM, 24), # 0-23
321 Const(self.PRIO_BITS, 4), # 24-27
322 Const(0, 4))) # 28-31
323 # Debug reg
324 with m.Elif(reg_is_debug):
325 comb += be_out.eq(Cat(icp_o_next.pri, # 0-7
326 Const(0, 20), # 8-27
327 icp_o_next.src)) # 28-31
328
329 sync += self.bus.dat_r.eq(bswap(be_out))
330 sync += self.bus.ack.eq(wb_valid)
331
332 # Register write machine
333 be_in = Signal(32)
334 # Byteswapped input
335 comb += be_in.eq(bswap(self.bus.dat_w))
336
337 with m.If(wb_valid & self.bus.we):
338 with m.If(reg_is_xive):
339 # TODO: When adding support for other bits, make sure to
340 # properly implement self.bus.sel to allow partial writes.
341 sync += xives[reg_idx].pri.eq(self.prio_pack(be_in[:8]))
342 #report "ICS irq " & integer'image(reg_idx) &
343 # " set to:" & to_hstring(be_in(7 downto 0));
344 pass
345
346 # generate interrupt. This is a simple combinational process,
347 # potentially wasteful in HW for large number of interrupts.
348 #
349 # could be replaced with iterative state machines and a message
350 # system between ICSs' (plural) and ICP incl. reject etc...
351 #
352 sync += self.icp_o.eq(icp_o_next)
353
354 max_idx = Signal(log2_int(self.SRC_NUM))
355 max_pri = Signal(self.PRIO_BITS)
356
357 # XXX FIXME: Use a tree (or examine each bit in turn)
358 comb += max_pri.eq(self.pri_masked)
359 comb += max_idx.eq(0)
360 for i in range(self.SRC_NUM):
361 cur_idx = Signal(log2_int(self.SRC_NUM), name="cur_idx%d" % i)
362 cur_pri = Signal(self.PRIO_BITS, name="cur_pri%d" % i)
363 comb += cur_pri.eq(max_pri)
364 comb += cur_idx.eq(max_idx)
365 with m.If(int_level_l[i] & self.a_mf_b(xives[i].pri, max_pri)):
366 comb += cur_pri.eq(xives[i].pri)
367 comb += cur_idx.eq(i)
368 max_pri = cur_pri
369 max_idx = cur_idx
370 with m.If(max_pri != self.pri_masked):
371 #report "MFI: " & integer'image(max_idx) &
372 #" pri=" & to_hstring(prio_unpack(max_pri));
373 pass
374 comb += icp_o_next.src.eq(max_idx)
375 comb += icp_o_next.pri.eq(self.prio_unpack(max_pri))
376
377 return m
378
379 def __iter__(self):
380 for field in self.bus.fields.values():
381 yield field
382 yield self.int_level_i
383 yield from self.icp_o.ports()
384
385 def ports(self):
386 return list(self)
387
388
389
390 def sim_xics_icp(dut):
391
392 # read wb XIRR_MFRR
393 data = yield from wb_read(dut.bus, MFRR)
394 print ("mfrr", hex(data), bin(data))
395 assert (yield dut.core_irq_o) == 0
396
397 yield
398
399 # read wb XIRR (8-bit)
400 data = yield from wb_read(dut.bus, XIRR, False)
401 print ("xirr", hex(data), bin(data))
402 assert (yield dut.core_irq_o) == 0
403
404 yield
405
406 # read wb XIRR (32-bit)
407 data = yield from wb_read(dut.bus, XIRR)
408 print ("xirr", hex(data), bin(data))
409 assert (yield dut.core_irq_o) == 0
410
411 yield
412
413 # read wb XIRR_POLL
414 data = yield from wb_read(dut.bus, XIRR_POLL)
415 print ("xirr poll", hex(data), bin(data))
416 assert (yield dut.core_irq_o) == 0
417
418 ##################
419 # set dut src/pri to something, anything
420
421 yield dut.ics_i.src.eq(9)
422 yield dut.ics_i.pri.eq(0x1e)
423
424 # read wb XIRR_MFRR
425 data = yield from wb_read(dut.bus, MFRR)
426 print ("mfrr", hex(data), bin(data))
427 assert (yield dut.core_irq_o) == 0
428
429 yield
430
431 # read wb XIRR (8-bit)
432 data = yield from wb_read(dut.bus, XIRR, False)
433 print ("xirr", hex(data), bin(data))
434 assert (yield dut.core_irq_o) == 0
435
436 yield
437
438 # read wb XIRR (32-bit)
439 data = yield from wb_read(dut.bus, XIRR)
440 print ("xirr", hex(data), bin(data))
441 assert (yield dut.core_irq_o) == 0
442
443 yield
444
445 # read wb XIRR_POLL
446 data = yield from wb_read(dut.bus, XIRR_POLL)
447 print ("xirr poll", hex(data), bin(data))
448 assert (yield dut.core_irq_o) == 0
449
450 ######################
451 # write XIRR
452 data = 0xfe
453 yield from wb_write(dut.bus, XIRR, data)
454 print ("xirr written", hex(data), bin(data))
455
456 assert (yield dut.core_irq_o) == 1 # ok *now* it should be set
457
458 # read wb XIRR_POLL
459 data = yield from wb_read(dut.bus, XIRR_POLL, False)
460 print ("xirr poll", hex(data), bin(data))
461 assert (yield dut.core_irq_o) == 1 # should not clear
462
463 # read wb XIRR (8-bit)
464 data = yield from wb_read(dut.bus, XIRR, False)
465 print ("xirr", hex(data), bin(data))
466 assert (yield dut.core_irq_o) == 1 # should not clear
467
468 # read wb XIRR (32-bit)
469 data = yield from wb_read(dut.bus, XIRR)
470 print ("xirr", hex(data), bin(data))
471 yield
472 assert (yield dut.core_irq_o) == 0
473
474 yield
475
476
477 def swap32(x):
478 return int.from_bytes(x.to_bytes(4, byteorder='little'),
479 byteorder='big', signed=False)
480
481 def get_field(x, wid, shift):
482 x = x >> shift
483 return x & ((1<<wid)-1)
484
485
486 def sim_xics(icp, ics):
487
488 # read config
489 data = yield from wb_read(ics.bus, 0)
490 print ("config", hex(data), bin(data))
491 data = swap32(data)
492 base = get_field(data, 24, 0)
493 pri = get_field(data, 8, 24)
494 print (" base", hex(base))
495 print (" pri", hex(pri))
496 assert base == 16
497 assert pri == 8
498
499 yield
500 yield
501
502 # read XIVE0
503 data = yield from wb_read(ics.bus, 0x800//4)
504 print ("xive0", hex(data), bin(data))
505 data = swap32(data)
506 irq = get_field(data, 1, 31)
507 rsvd = get_field(data, 1, 30)
508 p = get_field(data, 1, 29)
509 q = get_field(data, 1, 28)
510 rsvd2 = get_field(data, 8, 20)
511 target = get_field(data, 12, 8)
512 prio = get_field(data, 8, 0)
513 print(" irq", hex(irq))
514 print(" rsvd", hex(rsvd))
515 print(" p", hex(p))
516 print(" q", hex(q))
517 print(" rsvd2", hex(rsvd2))
518 print(" target", hex(target))
519 print(" prio", hex(prio))
520 assert irq == 0 # not active
521 assert rsvd == 0
522 assert rsvd2 == 0
523 assert target == 0 # not implemented
524 assert prio == 0xff
525
526 yield
527 yield
528
529 # raise XIVE 1 (just for fun)
530 yield ics.int_level_i.eq(1<<1)
531
532 yield # wait for interrupt to propagate through from ics to icp...
533
534 # read XIVE1
535 data = yield from wb_read(ics.bus, 0x804//4)
536 print ("xive1", hex(data), bin(data))
537 data = swap32(data)
538 irq = get_field(data, 1, 31)
539 rsvd = get_field(data, 1, 30)
540 p = get_field(data, 1, 29)
541 q = get_field(data, 1, 28)
542 rsvd2 = get_field(data, 8, 20)
543 target = get_field(data, 12, 8)
544 prio = get_field(data, 8, 0)
545 print(" irq", hex(irq))
546 print(" rsvd", hex(rsvd))
547 print(" p", hex(p))
548 print(" q", hex(q))
549 print(" rsvd2", hex(rsvd2))
550 print(" target", hex(target))
551 print(" prio", hex(prio))
552 assert irq == 1 # active!
553 assert rsvd == 0
554 assert rsvd2 == 0
555 assert target == 0 # not implemented
556 assert prio == 0xff
557
558 yield
559 yield
560
561 # check that after setting IRQ 2 core is still 0 because priority is 0xff
562 assert (yield icp.core_irq_o) == 0
563 yield
564
565 # set XIVE1 priority to 0xf0
566 data = swap32(0xf0)
567 yield from wb_write(ics.bus, 0x804//4, data)
568 print ("XIVE1 priority written", hex(data), bin(data))
569
570 ######################
571 # write XIRR
572 data = 0xfe
573 yield from wb_write(icp.bus, XIRR, data)
574 print ("xirr written", hex(data), bin(data))
575
576 assert (yield icp.core_irq_o) == 1 # ok *now* it should be set
577
578 # read wb XIRR (32-bit)
579 data = yield from wb_read(icp.bus, XIRR)
580 print ("xirr", hex(data), bin(data))
581 data = swap32(data)
582 cppr = get_field(data, 8, 24)
583 xisr = get_field(data, 24, 0)
584 print(" cppr", hex(cppr))
585 print(" xisr", hex(xisr))
586 yield
587 assert (yield icp.core_irq_o) == 0
588
589 yield
590
591
592
593 def test_xics_icp():
594
595 dut = XICS_ICP()
596 vl = rtlil.convert(dut, ports=dut.ports())
597 with open("test_xics_icp.il", "w") as f:
598 f.write(vl)
599
600 m = Module()
601 m.submodules.xics_icp = dut
602
603 sim = Simulator(m)
604 sim.add_clock(1e-6)
605
606 sim.add_sync_process(wrap(sim_xics_icp(dut)))
607 sim_writer = sim.write_vcd('test_xics_icp.vcd')
608 with sim_writer:
609 sim.run()
610
611 def test_xics_ics():
612
613 dut = XICS_ICS()
614 vl = rtlil.convert(dut, ports=dut.ports())
615 with open("test_xics_ics.il", "w") as f:
616 f.write(vl)
617
618 #run_simulation(dut, ldst_sim(dut), vcd_name='test_ldst_regspec.vcd')
619
620 def test_xics():
621
622 m = Module()
623 m.submodules.icp = icp = XICS_ICP()
624 m.submodules.ics = ics = XICS_ICS()
625 m.d.comb += icp.ics_i.eq(ics.icp_o)
626
627 vl = rtlil.convert(m, ports=icp.ports()+ics.ports())
628 with open("test_xics.il", "w") as f:
629 f.write(vl)
630
631 sim = Simulator(m)
632 sim.add_clock(1e-6)
633
634 sim.add_sync_process(wrap(sim_xics(icp, ics)))
635 sim_writer = sim.write_vcd('test_xics.vcd')
636 with sim_writer:
637 sim.run()
638
639
640 if __name__ == '__main__':
641 test_xics_icp()
642 test_xics_ics()
643 test_xics()
644