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