hmmm got naming wrong in regfile-fu connectivity
[soc.git] / src / soc / simple / core.py
1 """simple core
2
3 not in any way intended for production use. connects up FunctionUnits to
4 Register Files in a brain-dead fashion that only permits one and only one
5 Function Unit to be operational.
6 """
7 from nmigen import Elaboratable, Module, Signal
8 from nmigen.cli import rtlil
9
10 from nmutil.picker import PriorityPicker
11 from nmutil.util import treereduce
12
13 from soc.fu.compunits.compunits import AllFunctionUnits
14 from soc.regfile.regfiles import RegFiles
15 from soc.decoder.power_decoder import create_pdecode
16 from soc.decoder.power_decoder2 import PowerDecode2
17
18
19
20 def ortreereduce(tree, attr="data_o"):
21 return treereduce(tree, operator.or_, lambda x: getattr(x, attr))
22
23
24 class NonProductionCore(Elaboratable):
25 def __init__(self):
26 self.fus = AllFunctionUnits()
27 self.regs = RegFiles()
28 self.pdecode = pdecode = create_pdecode()
29 self.pdecode2 = PowerDecode2(pdecode) # instruction decoder
30 self.ivalid_i = self.pdecode2.e.valid # instruction is valid
31
32 def elaborate(self, platform):
33 m = Module()
34 comb = m.d.comb
35
36 m.submodules.pdecode2 = dec2 = self.pdecode2
37 m.submodules.fus = self.fus
38 self.regs.elaborate_into(m, platform)
39 regs = self.regs
40 fus = self.fus.fus
41
42 # enable-signals for each FU, get one bit for each FU (by name)
43 fu_enable = Signal(len(fus), reset_less=True)
44 fu_bitdict = {}
45 for i, funame in enumerate(fus.keys()):
46 fu_bitdict[funame] = fu_enable[i]
47
48 # dictionary of lists of regfile read ports
49 byregfiles_rd = {}
50 byregfiles_rdspec = {}
51 for (funame, fu) in fus.items():
52 print ("read ports for %s" % funame)
53 for idx in range(fu.n_src):
54 (regfile, regname, wid) = fu.get_in_spec(idx)
55 print (" %d %s %s %s" % (idx, regfile, regname, str(wid)))
56 rdflag, read, _ = dec2.regspecmap(regfile, regname)
57 if regfile not in byregfiles_rd:
58 byregfiles_rd[regfile] = {}
59 byregfiles_rdspec[regfile] = {}
60 byregfiles_rdspec[regfile][idx] = (regname, rdflag, read, wid)
61 # here we start to create "lanes"
62 if idx not in byregfiles_rd[regfile]:
63 byregfiles_rd[regfile][idx] = []
64 fuspec = (funame, fu)
65 byregfiles_rd[regfile][idx].append(fuspec)
66
67 # ok just print that out, for convenience
68 for regfile, spec in byregfiles_rd.items():
69 print ("regfile read ports:", regfile)
70 for idx, fuspec in spec.items():
71 print (" regfile read port %s lane: %d" % (regfile, idx))
72 (regname, rdflag, read, wid) = byregfiles_rdspec[regfile][idx]
73 print (" %s" % regname, wid, read, rdflag)
74 for (funame, fu) in fuspec:
75 print (" ", funame, fu, fu.src_i[idx])
76 print ()
77
78 # okaay, now we need a PriorityPicker per regfile per regfile port
79 # loootta pickers... peter piper picked a pack of pickled peppers...
80 rdpickers = {}
81 for regfile, spec in byregfiles_rd.items():
82 rdpickers[regfile] = {}
83 for rpidx, (idx, fuspec) in enumerate(spec.items()):
84 # get the regfile specs for this regfile port
85 (regname, rdflag, read, wid) = byregfiles_rdspec[regfile][idx]
86
87 # "munge" the regfile port index, due to full-port access
88 if regfile in ['xer', 'cr']:
89 if regname.startswith('full'):
90 rpidx = 0 # by convention, first port
91 else:
92 rpidx += 1 # start indexing port 0 from 1
93
94 # select the required read port. these are pre-defined sizes
95 print (regfile, regs.rf.keys())
96 rport = regs.rf[regfile.lower()].r_ports[rpidx]
97
98 # create a priority picker to manage this port
99 rdpickers[regfile][idx] = rdpick = PriorityPicker(len(fuspec))
100 setattr(m.submodules, "rdpick_%s_%d" % (regfile, idx), rdpick)
101
102 # connect the regspec "reg select" number to this port
103 with m.If(rdpick.en_o):
104 comb += rport.ren.eq(read)
105
106 # connect up the FU req/go signals and the reg-read to the FU
107 for pi, (funame, fu) in enumerate(fuspec):
108 # connect request-read to picker input, and output to go-rd
109 fu_active = fu_bitdict[funame]
110 comb += rdpick.i[pi].eq(fu.rd_rel_o[idx] & fu_active)
111 comb += fu.go_rd_i[idx].eq(rdpick.o[pi])
112 # connect regfile port to input
113 print ("reg connect widths",
114 regfile, regname, pi, funame,
115 fu.src_i[idx].shape(), rport.data_o.shape())
116 comb += fu.src_i[idx].eq(rport.data_o)
117
118 return m
119
120 def __iter__(self):
121 yield from self.fus.ports()
122 yield from self.pdecode2.ports()
123 # TODO: regs
124
125 def ports(self):
126 return list(self)
127
128
129 if __name__ == '__main__':
130 dut = NonProductionCore()
131 vl = rtlil.convert(dut, ports=dut.ports())
132 with open("non_production_core.il", "w") as f:
133 f.write(vl)