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 the principle here is to take the Function Units, analyse their regspecs,
8 and turn their requirements for access to register file read/write ports
9 into groupings by Register File and Register File Port name.
11 under each grouping - by regfile/port - a list of Function Units that
12 need to connect to that port is created. as these are a contended
13 resource a "Broadcast Bus" per read/write port is then also created,
14 with access to it managed by a PriorityPicker.
16 the brain-dead part of this module is that even though there is no
17 conflict of access, regfile read/write hazards are *not* analysed,
18 and consequently it is safer to wait for the Function Unit to complete
19 before allowing a new instruction to proceed.
22 from nmigen
import Elaboratable
, Module
, Signal
23 from nmigen
.cli
import rtlil
25 from nmutil
.picker
import PriorityPicker
26 from nmutil
.util
import treereduce
28 from soc
.fu
.compunits
.compunits
import AllFunctionUnits
29 from soc
.regfile
.regfiles
import RegFiles
30 from soc
.decoder
.power_decoder
import create_pdecode
31 from soc
.decoder
.power_decoder2
import PowerDecode2
35 def ortreereduce(tree
, attr
="data_o"):
36 return treereduce(tree
, operator
.or_
, lambda x
: getattr(x
, attr
))
39 class NonProductionCore(Elaboratable
):
41 self
.fus
= AllFunctionUnits()
42 self
.regs
= RegFiles()
43 self
.pdecode
= pdecode
= create_pdecode()
44 self
.pdecode2
= PowerDecode2(pdecode
) # instruction decoder
45 self
.ivalid_i
= self
.pdecode2
.e
.valid
# instruction is valid
47 def elaborate(self
, platform
):
51 m
.submodules
.pdecode2
= dec2
= self
.pdecode2
52 m
.submodules
.fus
= self
.fus
53 self
.regs
.elaborate_into(m
, platform
)
57 # enable-signals for each FU, get one bit for each FU (by name)
58 fu_enable
= Signal(len(fus
), reset_less
=True)
60 for i
, funame
in enumerate(fus
.keys()):
61 fu_bitdict
[funame
] = fu_enable
[i
]
63 # connect up instructions
64 for funame
, fu
in fus
.items():
65 fnunit
= fu
.fnunit
.value
66 enable
= Signal(name
="en_%s" % funame
, reset_less
=True)
67 comb
+= enable
.eq(self
.ivalid_i
& (dec2
.e
.fn_unit
& fnunit
).bool())
69 comb
+= fu
.oper_i
.eq_from_execute1(dec2
.e
)
70 comb
+= fu_bitdict
[funame
].eq(enable
)
72 # dictionary of lists of regfile read ports
73 byregfiles_rd
, byregfiles_rdspec
= self
.get_byregfiles(True)
75 # okaay, now we need a PriorityPicker per regfile per regfile port
76 # loootta pickers... peter piper picked a pack of pickled peppers...
78 for regfile
, spec
in byregfiles_rd
.items():
79 fuspecs
= byregfiles_rdspec
[regfile
]
80 rdpickers
[regfile
] = {}
81 for rpidx
, (regname
, fspec
) in enumerate(fuspecs
.items()):
82 # get the regfile specs for this regfile port
83 (rf
, read
, write
, wid
, fuspec
) = fspec
84 name
= "rdflag_%s_%s" % (regfile
, regname
)
85 rdflag
= Signal(name
=name
, reset_less
=True)
88 # "munge" the regfile port index, due to full-port access
89 if regfile
in ['XER', 'CA']:
90 if regname
.startswith('full'):
91 rpidx
= 0 # by convention, first port
93 rpidx
+= 1 # start indexing port 0 from 1
95 # select the required read port. these are pre-defined sizes
96 print (regfile
, regs
.rf
.keys())
97 rport
= regs
.rf
[regfile
.lower()].r_ports
[rpidx
]
99 # create a priority picker to manage this port
100 rdpickers
[regfile
][rpidx
] = rdpick
= PriorityPicker(len(fuspec
))
101 setattr(m
.submodules
, "rdpick_%s_%d" % (regfile
, rpidx
), rdpick
)
103 # connect the regspec "reg select" number to this port
104 with m
.If(rdpick
.en_o
):
105 comb
+= rport
.ren
.eq(read
)
107 # connect up the FU req/go signals and the reg-read to the FU
108 for pi
, (funame
, fu
, idx
) in enumerate(fuspec
):
109 # connect request-read to picker input, and output to go-rd
110 fu_active
= fu_bitdict
[funame
]
111 pick
= fu
.rd_rel_o
[idx
] & fu_active
& rdflag
112 comb
+= rdpick
.i
[pi
].eq(pick
)
113 comb
+= fu
.go_rd_i
[idx
].eq(rdpick
.o
[pi
])
114 # connect regfile port to input
115 print ("reg connect widths",
116 regfile
, regname
, pi
, funame
,
117 fu
.src_i
[idx
].shape(), rport
.data_o
.shape())
118 comb
+= fu
.src_i
[idx
].eq(rport
.data_o
)
120 # dictionary of lists of regfile write ports
121 byregfiles_rd
, byregfiles_rdspec
= self
.get_byregfiles(False)
125 def get_byregfiles(self
, readmode
):
127 mode
= "read" if readmode
else "write"
132 # dictionary of lists of regfile ports
135 for (funame
, fu
) in fus
.items():
136 print ("%s ports for %s" % (mode
, funame
))
137 for idx
in range(fu
.n_src
if readmode
else fu
.n_dst
):
139 (regfile
, regname
, wid
) = fu
.get_in_spec(idx
)
141 (regfile
, regname
, wid
) = fu
.get_out_spec(idx
)
142 print (" %d %s %s %s" % (idx
, regfile
, regname
, str(wid
)))
143 rdflag
, read
, write
= dec2
.regspecmap(regfile
, regname
)
144 if regfile
not in byregfiles
:
145 byregfiles
[regfile
] = {}
146 byregfiles_spec
[regfile
] = {}
147 if regname
not in byregfiles_spec
[regfile
]:
148 byregfiles_spec
[regfile
][regname
] = \
149 [rdflag
, read
, write
, wid
, []]
150 # here we start to create "lanes"
151 if idx
not in byregfiles
[regfile
]:
152 byregfiles
[regfile
][idx
] = []
153 fuspec
= (funame
, fu
, idx
)
154 byregfiles
[regfile
][idx
].append(fuspec
)
155 byregfiles_spec
[regfile
][regname
][4].append(fuspec
)
157 # ok just print that out, for convenience
158 for regfile
, spec
in byregfiles
.items():
159 print ("regfile %s ports:" % mode
, regfile
)
160 fuspecs
= byregfiles_spec
[regfile
]
161 for regname
, fspec
in fuspecs
.items():
162 [rdflag
, read
, write
, wid
, fuspec
] = fspec
163 print (" rf %s port %s lane: %s" % (mode
, regfile
, regname
))
164 print (" %s" % regname
, wid
, read
, write
, rdflag
)
165 for (funame
, fu
, idx
) in fuspec
:
166 fusig
= fu
.src_i
[idx
] if readmode
else fu
.dest
[idx
]
167 print (" ", funame
, fu
, idx
, fusig
)
170 return byregfiles
, byregfiles_spec
173 yield from self
.fus
.ports()
174 yield from self
.pdecode2
.ports()
181 if __name__
== '__main__':
182 dut
= NonProductionCore()
183 vl
= rtlil
.convert(dut
, ports
=dut
.ports())
184 with
open("non_production_core.il", "w") as f
: