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