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.
7 from nmigen
import Elaboratable
, Module
, Signal
8 from nmigen
.cli
import rtlil
10 from nmutil
.picker
import PriorityPicker
11 from nmutil
.util
import treereduce
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
20 def ortreereduce(tree
, attr
="data_o"):
21 return treereduce(tree
, operator
.or_
, lambda x
: getattr(x
, attr
))
24 class NonProductionCore(Elaboratable
):
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
32 def elaborate(self
, platform
):
36 m
.submodules
.pdecode2
= dec2
= self
.pdecode2
37 m
.submodules
.fus
= self
.fus
38 self
.regs
.elaborate_into(m
, platform
)
42 # enable-signals for each FU, get one bit for each FU (by name)
43 fu_enable
= Signal(len(fus
), reset_less
=True)
45 for i
, funame
in enumerate(fus
.keys()):
46 fu_bitdict
[funame
] = fu_enable
[i
]
48 # connect up instructions
49 for funame
, fu
in fus
.items():
50 fnunit
= fu
.fnunit
.value
51 enable
= Signal(name
="en_%s" % funame
, reset_less
=True)
52 comb
+= enable
.eq(self
.ivalid_i
& (dec2
.e
.fn_unit
& fnunit
).bool())
54 comb
+= fu
.oper_i
.eq_from_execute1(dec2
.e
)
55 comb
+= fu_bitdict
[funame
].eq(enable
)
57 # dictionary of lists of regfile read ports
58 byregfiles_rd
, byregfiles_rdspec
= self
.get_byregfiles(True)
60 # okaay, now we need a PriorityPicker per regfile per regfile port
61 # loootta pickers... peter piper picked a pack of pickled peppers...
63 for regfile
, spec
in byregfiles_rd
.items():
64 fuspecs
= byregfiles_rdspec
[regfile
]
65 rdpickers
[regfile
] = {}
66 for rpidx
, (regname
, fspec
) in enumerate(fuspecs
.items()):
67 # get the regfile specs for this regfile port
68 (rf
, read
, write
, wid
, fuspec
) = fspec
69 name
= "rdflag_%s_%s" % (regfile
, regname
)
70 rdflag
= Signal(name
=name
, reset_less
=True)
73 # "munge" the regfile port index, due to full-port access
74 if regfile
in ['XER', 'CA']:
75 if regname
.startswith('full'):
76 rpidx
= 0 # by convention, first port
78 rpidx
+= 1 # start indexing port 0 from 1
80 # select the required read port. these are pre-defined sizes
81 print (regfile
, regs
.rf
.keys())
82 rport
= regs
.rf
[regfile
.lower()].r_ports
[rpidx
]
84 # create a priority picker to manage this port
85 rdpickers
[regfile
][rpidx
] = rdpick
= PriorityPicker(len(fuspec
))
86 setattr(m
.submodules
, "rdpick_%s_%d" % (regfile
, rpidx
), rdpick
)
88 # connect the regspec "reg select" number to this port
89 with m
.If(rdpick
.en_o
):
90 comb
+= rport
.ren
.eq(read
)
92 # connect up the FU req/go signals and the reg-read to the FU
93 for pi
, (funame
, fu
, idx
) in enumerate(fuspec
):
94 # connect request-read to picker input, and output to go-rd
95 fu_active
= fu_bitdict
[funame
]
96 pick
= fu
.rd_rel_o
[idx
] & fu_active
& rdflag
97 comb
+= rdpick
.i
[pi
].eq(pick
)
98 comb
+= fu
.go_rd_i
[idx
].eq(rdpick
.o
[pi
])
99 # connect regfile port to input
100 print ("reg connect widths",
101 regfile
, regname
, pi
, funame
,
102 fu
.src_i
[idx
].shape(), rport
.data_o
.shape())
103 comb
+= fu
.src_i
[idx
].eq(rport
.data_o
)
105 # dictionary of lists of regfile write ports
106 byregfiles_rd
, byregfiles_rdspec
= self
.get_byregfiles(False)
110 def get_byregfiles(self
, readmode
):
112 mode
= "read" if readmode
else "write"
117 # dictionary of lists of regfile ports
120 for (funame
, fu
) in fus
.items():
121 print ("%s ports for %s" % (mode
, funame
))
122 for idx
in range(fu
.n_src
if readmode
else fu
.n_dst
):
124 (regfile
, regname
, wid
) = fu
.get_in_spec(idx
)
126 (regfile
, regname
, wid
) = fu
.get_out_spec(idx
)
127 print (" %d %s %s %s" % (idx
, regfile
, regname
, str(wid
)))
128 rdflag
, read
, write
= dec2
.regspecmap(regfile
, regname
)
129 if regfile
not in byregfiles
:
130 byregfiles
[regfile
] = {}
131 byregfiles_spec
[regfile
] = {}
132 if regname
not in byregfiles_spec
[regfile
]:
133 byregfiles_spec
[regfile
][regname
] = \
134 [rdflag
, read
, write
, wid
, []]
135 # here we start to create "lanes"
136 if idx
not in byregfiles
[regfile
]:
137 byregfiles
[regfile
][idx
] = []
138 fuspec
= (funame
, fu
, idx
)
139 byregfiles
[regfile
][idx
].append(fuspec
)
140 byregfiles_spec
[regfile
][regname
][4].append(fuspec
)
142 # ok just print that out, for convenience
143 for regfile
, spec
in byregfiles
.items():
144 print ("regfile %s ports:" % mode
, regfile
)
145 fuspecs
= byregfiles_spec
[regfile
]
146 for regname
, fspec
in fuspecs
.items():
147 [rdflag
, read
, write
, wid
, fuspec
] = fspec
148 print (" rf %s port %s lane: %s" % (mode
, regfile
, regname
))
149 print (" %s" % regname
, wid
, read
, write
, rdflag
)
150 for (funame
, fu
, idx
) in fuspec
:
151 fusig
= fu
.src_i
[idx
] if readmode
else fu
.dest
[idx
]
152 print (" ", funame
, fu
, idx
, fusig
)
155 return byregfiles
, byregfiles_spec
158 yield from self
.fus
.ports()
159 yield from self
.pdecode2
.ports()
166 if __name__
== '__main__':
167 dut
= NonProductionCore()
168 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
169 with
open("non_production_core.il", "w") as f
: