add dma rules
[pinmux.git] / src / bsv / peripheral_gen / base.py
1 import types
2
3
4 class PBase(object):
5 def __init__(self, name):
6 self.name = name
7
8 def extifdecl(self, name, count):
9 sname = self.get_iname(count)
10 return " interface PeripheralSide%s %s;" % (name.upper(), sname)
11
12 def has_axi_master(self):
13 return False
14
15 def irq_name(self):
16 return ""
17
18 def mk_dma_irq(self, name, count):
19 if not self.irq_name():
20 return ''
21 sname = self.get_iname(count)
22 return "{0}_interrupt".format(sname)
23
24 def mk_dma_rule(self, name, count):
25 irqname = self.mk_dma_irq(name, count)
26 if not irqname:
27 return ''
28 pirqname = self.irq_name().format(count)
29 template = " {0}_interrupt.send(\n" + \
30 " slow_peripherals.{1});"
31 return template.format(irqname, pirqname)
32
33 def get_clock_reset(self, name, count):
34 return "slow_clock,slow_reset"
35
36 def mk_dma_sync(self, name, count):
37 irqname = self.mk_dma_irq(name, count)
38 if not irqname:
39 return ''
40 sname = self.peripheral.iname().format(count)
41 template = " SyncBitIfc#(Bit#(1)) {0} <-\n" + \
42 " <-mkSyncBitToCC({1});"
43 return template.format(irqname, self.get_clock_reset(name, count))
44
45 def mk_dma_connect(self, name, count):
46 return ''
47
48 def fastifdecl(self, name, count):
49 return ''
50
51 def slowifdeclmux(self, name, count):
52 return ''
53
54 def slowimport(self):
55 return ''
56
57 def num_axi_regs32(self):
58 return 0
59
60 def slowifdecl(self):
61 return ''
62
63 def get_iname(self, inum):
64 return "{0}{1}".format(self.name, self.mksuffix(self.name, inum))
65
66 def axibase(self, name, ifacenum):
67 name = name.upper()
68 return "%(name)s%(ifacenum)dBase" % locals()
69
70 def axiend(self, name, ifacenum):
71 name = name.upper()
72 return "%(name)s%(ifacenum)dEnd" % locals()
73
74 def axi_reg_def(self, start, name, ifacenum):
75 name = name.upper()
76 offs = self.num_axi_regs32() * 4 * 16
77 if offs == 0:
78 return ('', 0)
79 end = start + offs - 1
80 bname = self.axibase(name, ifacenum)
81 bend = self.axiend(name, ifacenum)
82 comment = "%d 32-bit regs" % self.num_axi_regs32()
83 return (" `define %(bname)s 'h%(start)08X\n"
84 " `define %(bend)s 'h%(end)08X // %(comment)s" % locals(),
85 offs)
86
87 def axi_master_name(self, name, ifacenum, typ=''):
88 name = name.upper()
89 return "{0}{1}_master_num".format(name, ifacenum)
90
91 def axi_slave_name(self, name, ifacenum, typ=''):
92 name = name.upper()
93 return "{0}{1}_{2}slave_num".format(name, ifacenum, typ)
94
95 def axi_master_idx(self, idx, name, ifacenum, typ):
96 name = self.axi_master_name(name, ifacenum, typ)
97 return ("typedef {0} {1};".format(idx, name), 1)
98
99 def axi_slave_idx(self, idx, name, ifacenum, typ):
100 name = self.axi_slave_name(name, ifacenum, typ)
101 return ("typedef {0} {1};".format(idx, name), 1)
102
103 def axi_addr_map(self, name, ifacenum):
104 bname = self.axibase(name, ifacenum)
105 bend = self.axiend(name, ifacenum)
106 name = self.axi_slave_name(name, ifacenum)
107 return """\
108 if(addr>=`{0} && addr<=`{1})
109 return tuple2(True,fromInteger(valueOf({2})));
110 else""".format(bname, bend, name)
111
112 def mk_pincon(self, name, count):
113 # TODO: really should be using bsv.interface_decl.Interfaces
114 # pin-naming rules.... logic here is hard-coded to duplicate
115 # it (see Interface.__init__ outen)
116 ret = []
117 for p in self.peripheral.pinspecs:
118 typ = p['type']
119 pname = p['name']
120 #n = "{0}{1}".format(self.name, self.mksuffix(name, count))
121 n = name # "{0}{1}".format(self.name, self.mksuffix(name, count))
122 ret.append(" //%s %s" % (n, str(p)))
123 sname = self.peripheral.iname().format(count)
124 sname = "{0}.{1}".format(sname, pname)
125 ps = "pinmux.peripheral_side.%s" % sname
126 if typ == 'out' or typ == 'inout':
127 fname = self.pinname_out(pname)
128 if not n.startswith('gpio'): # XXX EURGH! horrible hack
129 n_ = "{0}{1}".format(n, count)
130 else:
131 n_ = n
132 if fname:
133 if p.get('outen'):
134 ps_ = ps + '_out'
135 else:
136 ps_ = ps
137 ret.append(" mkConnection({0},\n\t\t\t{1}.{2});"
138 .format(ps_, n_, fname))
139 fname = None
140 if p.get('outen'):
141 fname = self.pinname_outen(pname)
142 if fname:
143 if isinstance(fname, str):
144 fname = "{0}.{1}".format(n_, fname)
145 fname = self.pinname_tweak(pname, 'outen', fname)
146 ret.append(" mkConnection({0}_outen,\n\t\t\t{1});"
147 .format(ps, fname))
148 if typ == 'in' or typ == 'inout':
149 fname = self.pinname_in(pname)
150 if fname:
151 if p.get('outen'):
152 ps_ = ps + '_in'
153 else:
154 ps_ = ps
155 n_ = "{0}{1}".format(n, count)
156 n_ = '{0}.{1}'.format(n_, fname)
157 n_ = self.ifname_tweak(pname, 'in', n_)
158 ret.append(" mkConnection({1}, {0});".format(ps_, n_))
159 return '\n'.join(ret)
160
161 def mk_cellconn(self, *args):
162 return ''
163
164 def mkfast_peripheral(self, size=0):
165 return ''
166
167 def mkslow_peripheral(self, size=0):
168 return ''
169
170 def mksuffix(self, name, i):
171 return i
172
173 def __mk_connection(self, con, aname, fabricname):
174 txt = " mkConnection ({2}.v_to_slaves\n" + \
175 " [fromInteger(valueOf({1}))],\n" + \
176 " {0});"
177
178 print "PBase __mk_connection", self.name, aname
179 if not con:
180 return ''
181 return txt.format(con, aname, fabricname)
182
183 def __mk_master_connection(self, con, aname):
184 txt = " mkConnection (slow_fabric.v_to_slaves\n" + \
185 " [fromInteger(valueOf({1}))],\n" + \
186 " {0});"
187
188 print "PBase __mk_connection", self.name, aname
189 if not con:
190 return ''
191 return txt.format(con, aname)
192
193 def mk_connection(self, count, fabricname, typ, name=None):
194 if name is None:
195 name = self.name
196 print "PBase mk_conn", self.name, count
197 aname = self.axi_slave_name(name, count, typ)
198 #dname = self.mksuffix(name, count)
199 #dname = "{0}{1}".format(name, dname)
200 con = self._mk_connection(name, count).format(count, aname)
201 return self.__mk_connection(con, aname, fabricname)
202
203 def _mk_connection(self, name=None, count=0):
204 return ''
205
206 def pinname_out(self, pname):
207 return ''
208
209 def pinname_in(self, pname):
210 return ''
211
212 def pinname_outen(self, pname):
213 return ''
214
215 def ifname_tweak(self, pname, typ, txt):
216 return txt
217
218 def pinname_tweak(self, pname, typ, txt):
219 return txt
220
221 def num_irqs(self):
222 return 0
223
224 def mk_plic(self, inum, irq_offs):
225 res = []
226 print "mk_plic", self.name, inum, irq_offs
227 niq = self.num_irqs()
228 if niq == 0:
229 return ('', irq_offs)
230 name = self.get_iname(inum)
231 res.append(" // PLIC rules for {0}".format(name))
232 for idx in range(niq):
233 plic_obj = self.plic_object(name, idx)
234 print "plic_obj", name, idx, plic_obj
235 plic = mkplic_rule.format(name, plic_obj, irq_offs)
236 res.append(plic)
237 irq_offs += 1 # increment to next irq
238 return ('\n'.join(res), irq_offs)
239
240 def mk_ext_ifacedef(self, iname, inum):
241 return ''
242
243 def extfastifinstance(self, name, count):
244 return ''
245
246 def _extifinstance(self, name, count, suffix, prefix, samename=False):
247 pname = self.get_iname(count)
248 if samename:
249 sname = pname
250 else:
251 sname = self.peripheral.iname().format(count)
252 template = " interface {0}{3} = {2}{1};"
253 return template.format(pname, sname, prefix, suffix)
254
255 def extifinstance(self, name, count):
256 return self._extifinstance(name, count, "",
257 "pinmux.peripheral_side.")
258
259
260 mkplic_rule = """\
261 rule rl_connect_{0}_to_plic_{2};
262 if({1} == 1'b1) begin
263 ff_gateway_queue[{2}].enq(1);
264 plic.ifc_external_irq[{2}].irq_frm_gateway(True);
265 end
266 endrule
267 """
268
269 axi_master_declarations= """\
270 typedef 0 Dmem_master_num;
271 typedef 1 Imem_master_num;
272 {0}
273 typedef TAdd#(LastGen_master_num, `ifdef Debug 1 `else 0 `endif ) Debug_master_num;
274 typedef TAdd#(Debug_master_num, `ifdef DMA 1 `else 0 `endif ) DMA_master_num;
275 typedef TAdd#(DMA_master_num,1) Num_Masters;
276 """
277
278 axi_fastslave_declarations = """\
279 {0}
280 typedef TAdd#(LastGen_fastslave_num,1) Sdram_cfg_slave_num;
281 typedef TAdd#(Sdram_slave_num ,`ifdef SDRAM 1 `else 0 `endif ) Sdram_cfg_slave_num;
282 typedef TAdd#(Sdram_cfg_slave_num,`ifdef BOOTROM 1 `else 0 `endif ) BootRom_slave_num ;
283 typedef TAdd#(BootRom_slave_num ,`ifdef Debug 1 `else 0 `endif ) Debug_slave_num ;
284 typedef TAdd#(Debug_slave_num , `ifdef TCMemory 1 `else 0 `endif ) TCM_slave_num;
285 typedef TAdd#(TCM_slave_num ,`ifdef DMA 1 `else 0 `endif ) Dma_slave_num;
286 typedef TAdd#(Dma_slave_num ,1 ) SlowPeripheral_slave_num;
287 typedef TAdd#(SlowPeripheral_slave_num,`ifdef VME 1 `else 0 `endif ) VME_slave_num;
288 typedef TAdd#(VME_slave_num,`ifdef FlexBus 1 `else 0 `endif ) FlexBus_slave_num;
289 typedef TAdd#(FlexBus_slave_num,1) Num_Slaves;
290
291 """
292
293 axi_slave_declarations = """\
294 typedef 0 SlowMaster;
295 {0}
296 typedef TAdd#(LastGen_slave_num,`ifdef CLINT 1 `else 0 `endif )
297 CLINT_slave_num;
298 typedef TAdd#(CLINT_slave_num ,`ifdef PLIC 1 `else 0 `endif )
299 Plic_slave_num;
300 typedef TAdd#(Plic_slave_num ,`ifdef AXIEXP 1 `else 0 `endif )
301 AxiExp1_slave_num;
302 typedef TAdd#(AxiExp1_slave_num,1) Num_Slow_Slaves;
303 """
304
305 pinmux_cellrule = """\
306 rule connect_select_lines_pinmux;
307 {0}
308 endrule
309 """
310
311
312 class CallFn(object):
313 def __init__(self, peripheral, name):
314 self.peripheral = peripheral
315 self.name = name
316
317 def __call__(self, *args):
318 #print "__call__", self.name, self.peripheral.slow, args
319 if not self.peripheral.slow:
320 return ''
321 return getattr(self.peripheral.slow, self.name)(*args[1:])
322
323
324 class PeripheralIface(object):
325 def __init__(self, ifacename):
326 self.slow = None
327 slow = slowfactory.getcls(ifacename)
328 print "Iface", ifacename, slow
329 if slow:
330 self.slow = slow(ifacename)
331 self.slow.peripheral = self
332 for fname in ['slowimport',
333 'extfastifinstance', 'extifinstance', 'extifdecl',
334 'slowifdecl', 'slowifdeclmux',
335 'fastifdecl',
336 'mkslow_peripheral',
337 'mk_dma_sync', 'mk_dma_connect', 'mk_dma_rule',
338 'mkfast_peripheral',
339 'mk_plic', 'mk_ext_ifacedef',
340 'mk_connection', 'mk_cellconn', 'mk_pincon']:
341 fn = CallFn(self, fname)
342 setattr(self, fname, types.MethodType(fn, self))
343
344 #print "PeripheralIface"
345 #print dir(self)
346
347 def mksuffix(self, name, i):
348 if self.slow is None:
349 return i
350 return self.slow.mksuffix(name, i)
351
352 def axi_reg_def(self, start, count):
353 if not self.slow:
354 return ('', 0)
355 return self.slow.axi_reg_def(start, self.ifacename, count)
356
357 def axi_master_idx(self, start, count, typ):
358 if not self.slow or not self.slow.has_axi_master():
359 return ('', 0)
360 return self.slow.axi_master_idx(start, self.ifacename, count, typ)
361
362 def axi_slave_idx(self, start, count, typ):
363 if not self.slow:
364 return ('', 0)
365 return self.slow.axi_slave_idx(start, self.ifacename, count, typ)
366
367 def axi_addr_map(self, count):
368 if not self.slow:
369 return ''
370 return self.slow.axi_addr_map(self.ifacename, count)
371
372
373 class PeripheralInterfaces(object):
374 def __init__(self):
375 self.fastbusmode = False
376
377 def slowimport(self, *args):
378 ret = []
379 for (name, count) in self.ifacecount:
380 #print "slowimport", name, self.data[name].slowimport
381 ret.append(self.data[name].slowimport())
382 return '\n'.join(list(filter(None, ret)))
383
384 def extfastifinstance(self, *args):
385 ret = []
386 for (name, count) in self.ifacecount:
387 for i in range(count):
388 iname = self.data[name].iname().format(i)
389 print "extfast", iname, self.is_on_fastbus(name, i)
390 if self.is_on_fastbus(name, i):
391 continue
392 ret.append(self.data[name].extfastifinstance(name, i))
393 return '\n'.join(list(filter(None, ret)))
394
395 def extifinstance(self, *args):
396 ret = []
397 for (name, count) in self.ifacecount:
398 for i in range(count):
399 iname = self.data[name].iname().format(i)
400 if not self.is_on_fastbus(name, i):
401 continue
402 ret.append(self.data[name].extifinstance(name, i))
403 return '\n'.join(list(filter(None, ret)))
404
405 def extifdecl(self, *args):
406 ret = []
407 for (name, count) in self.ifacecount:
408 for i in range(count):
409 if not self.is_on_fastbus(name, i):
410 continue
411 ret.append(self.data[name].extifdecl(name, i))
412 return '\n'.join(list(filter(None, ret)))
413
414 def slowifdeclmux(self, *args):
415 ret = []
416 for (name, count) in self.ifacecount:
417 for i in range(count):
418 ret.append(self.data[name].slowifdeclmux(name, i))
419 return '\n'.join(list(filter(None, ret)))
420
421 def fastifdecl(self, *args):
422 ret = []
423 for (name, count) in self.ifacecount:
424 for i in range(count):
425 print "fastifdecl", name, i, self.is_on_fastbus(name, i)
426 if self.is_on_fastbus(name, i):
427 continue
428 ret.append(self.data[name].fastifdecl(name, i))
429 return '\n'.join(list(filter(None, ret)))
430
431 def slowifdecl(self, *args):
432 ret = []
433 for (name, count) in self.ifacecount:
434 for i in range(count):
435 if self.is_on_fastbus(name, i):
436 continue
437 ret.append(self.data[name].slowifdecl().format(i, name))
438 return '\n'.join(list(filter(None, ret)))
439
440 def axi_reg_def(self, *args):
441 ret = []
442 start = 0x00011100 # start of AXI peripherals address
443 for (name, count) in self.ifacecount:
444 for i in range(count):
445 if self.is_on_fastbus(name, i):
446 continue
447 x = self.data[name].axi_reg_def(start, i)
448 #print ("ifc", name, x)
449 (rdef, offs) = x
450 ret.append(rdef)
451 start += offs
452 return '\n'.join(list(filter(None, ret)))
453
454 def _axi_num_idx(self, start, template, typ, idxtype, *args):
455 ret = []
456 for (name, count) in self.ifacecount:
457 for i in range(count):
458 if self.is_on_fastbus(name, i):
459 continue
460 if typ == 'master':
461 fn = self.data[name].axi_master_idx
462 else:
463 fn = self.data[name].axi_slave_idx
464 (rdef, offs) = fn(start, i, idxtype)
465 #print ("ifc", name, rdef, offs)
466 ret.append(rdef)
467 start += offs
468 ret.append("typedef %d LastGen_%s_num;" % (start - 1, typ))
469 decls = '\n'.join(list(filter(None, ret)))
470 return template.format(decls)
471
472 def axi_slave_idx(self, *args):
473 return self._axi_num_idx(0, axi_slave_declarations, 'slave',
474 '', *args)
475
476 def axi_fastslave_idx(self, *args):
477 return self._axi_num_idx(0, axi_fastslave_declarations, 'fastslave',
478 'fast', *args)
479
480 def axi_master_idx(self, *args):
481 return self._axi_num_idx(2, axi_master_declarations, 'master',
482 'master', *args)
483
484 def axi_fastslave_idx(self, *args):
485 return self._axi_num_idx(0, axi_fastslave_declarations, 'fastslave',
486 'fast', *args)
487
488 def axi_addr_map(self, *args):
489 ret = []
490 for (name, count) in self.ifacecount:
491 for i in range(count):
492 if self.is_on_fastbus(name, i):
493 continue
494 ret.append(self.data[name].axi_addr_map(i))
495 return '\n'.join(list(filter(None, ret)))
496
497 def mkfast_peripheral(self, *args):
498 ret = []
499 for (name, count) in self.ifacecount:
500 for i in range(count):
501 if self.is_on_fastbus(name, i):
502 continue
503 #print "mkfast", name, count
504 x = self.data[name].mkfast_peripheral()
505 print name, count, x
506 suffix = self.data[name].mksuffix(name, i)
507 ret.append(x.format(suffix))
508 return '\n'.join(list(filter(None, ret)))
509
510 def mkslow_peripheral(self, *args):
511 ret = []
512 for (name, count) in self.ifacecount:
513 for i in range(count):
514 if self.is_on_fastbus(name, i):
515 continue
516 #print "mkslow", name, count
517 x = self.data[name].mkslow_peripheral()
518 print name, count, x
519 suffix = self.data[name].mksuffix(name, i)
520 ret.append(x.format(suffix))
521 return '\n'.join(list(filter(None, ret)))
522
523 def mk_fast_connection(self, *args):
524 ret = []
525 for (name, count) in self.ifacecount:
526 for i in range(count):
527 if self.is_on_fastbus(name, i):
528 continue
529 txt = self.data[name].mk_connection(i, "fabric", "fast")
530 if name == 'gpioa':
531 print "txt", txt
532 print self.data[name].mk_connection
533 ret.append(txt)
534 return '\n'.join(list(filter(None, ret)))
535
536 def mk_connection(self, *args):
537 ret = []
538 for (name, count) in self.ifacecount:
539 for i in range(count):
540 if self.is_on_fastbus(name, i):
541 continue
542 txt = self.data[name].mk_connection(i, "slow_fabric", "")
543 if name == 'gpioa':
544 print "txt", txt
545 print self.data[name].mk_connection
546 ret.append(txt)
547 return '\n'.join(list(filter(None, ret)))
548
549 def mk_cellconn(self):
550 ret = []
551 cellcount = 0
552 for (name, count) in self.ifacecount:
553 for i in range(count):
554 if self.is_on_fastbus(name, i):
555 continue
556 res = self.data[name].mk_cellconn(cellcount, name, i)
557 if not res:
558 continue
559 (txt, cellcount) = res
560 ret.append(txt)
561 ret = '\n'.join(list(filter(None, ret)))
562 return pinmux_cellrule.format(ret)
563
564 def mk_pincon(self):
565 ret = []
566 for (name, count) in self.ifacecount:
567 for i in range(count):
568 if self.is_on_fastbus(name, i):
569 continue
570 txt = self.data[name].mk_pincon(name, i)
571 ret.append(txt)
572 return '\n'.join(list(filter(None, ret)))
573
574 def mk_dma_irq(self):
575 ret = []
576 sync = []
577 rules = []
578 cnct = []
579
580 self.dma_count = 0
581
582 for (name, count) in self.ifacecount:
583 ifacerules = []
584 for i in range(count):
585 if not self.is_on_fastbus(name, i):
586 continue
587 txt = self.data[name].mk_dma_sync(name, i)
588 if txt:
589 self.dma_count += 1
590 sync.append(txt)
591 txt = self.data[name].mk_dma_rule(name, i)
592 ifacerules.append(txt)
593 txt = self.data[name].mk_dma_connect(name, i)
594 cnct.append(txt)
595 ifacerules = list(filter(None, ifacerules))
596 if ifacerules:
597 txt = " rule synchronize_%s_interrupts;" % name
598 rules.append(txt)
599 rules += ifacerules
600 rules.append(" endrule")
601
602 ct = self.dma_count
603 _cnct = [" rule rl_connect_interrupt_to_DMA;",
604 " Bit #(%d) lv_interrupt_to_DMA={" % ct]
605 cnct = _cnct + cnct
606 cnct.append(" };")
607 cnct.append(" dma.interrupt_from_peripherals(\n" + \
608 " lv_interrupt_to_DMA);")
609 cnct.append(" endrule;")
610
611 return '\n'.join(list(filter(None, sync + rules + cnct)))
612
613 def mk_ext_ifacedef(self):
614 ret = []
615 for (name, count) in self.ifacecount:
616 for i in range(count):
617 if self.is_on_fastbus(name, i):
618 continue
619 txt = self.data[name].mk_ext_ifacedef(name, i)
620 ret.append(txt)
621 return '\n'.join(list(filter(None, ret)))
622
623 def mk_plic(self):
624 ret = []
625 irq_offs = 8 # XXX: DMA scovers 0-7?
626 for (name, count) in self.ifacecount:
627 for i in range(count):
628 if self.is_on_fastbus(name, i):
629 continue
630 res = self.data[name].mk_plic(i, irq_offs)
631 if not res:
632 continue
633 (txt, irq_offs) = res
634 ret.append(txt)
635 self.num_slow_irqs = irq_offs
636 return '\n'.join(list(filter(None, ret)))
637
638 def mk_sloirqsdef(self):
639 return " `define NUM_SLOW_IRQS {0}".format(self.num_slow_irqs)
640
641 def is_on_fastbus(self, name, i):
642 #print "fastbus mode", self.fastbusmode, name, i
643 iname = self.data[name].iname().format(i)
644 if self.fastbusmode:
645 return iname not in self.fastbus
646 return iname in self.fastbus
647
648
649 class PFactory(object):
650 def getcls(self, name):
651 from uart import uart
652 from quart import quart
653 from sdmmc import sdmmc
654 from pwm import pwm
655 from eint import eint
656 from rs232 import rs232
657 from twi import twi
658 from eint import eint
659 from jtag import jtag
660 from spi import spi, mspi
661 from qspi import qspi, mqspi
662 from gpio import gpio
663 from rgbttl import rgbttl
664
665 for k, v in {'uart': uart,
666 'rs232': rs232,
667 'twi': twi,
668 'quart': quart,
669 'mqspi': mqspi,
670 'mspi': mspi,
671 'qspi': qspi,
672 'spi': spi,
673 'pwm': pwm,
674 'eint': eint,
675 'sd': sdmmc,
676 'jtag': jtag,
677 'lcd': rgbttl,
678 'gpio': gpio
679 }.items():
680 if name.startswith(k):
681 return v
682 return None
683
684
685 slowfactory = PFactory()
686
687 if __name__ == '__main__':
688 p = uart('uart')
689 print p.slowimport()
690 print p.slowifdecl()
691 i = PeripheralIface('uart')
692 print i, i.slow
693 i = PeripheralIface('gpioa')
694 print i, i.slow