create set/get ports for bitvectors
[soc.git] / src / soc / regfile / regfiles.py
1 # POWER9 Register Files
2 """POWER9 regfiles
3
4 Defines the following register files:
5
6 * INT regfile - 32x 64-bit
7 * SPR regfile - 110x 64-bit
8 * CR regfile - CR0-7
9 * XER regfile - XER.so, XER.ca/ca32, XER.ov/ov32
10 * FAST regfile - CTR, LR, TAR, SRR1, SRR2
11 * STATE regfile - PC, MSR, (SimpleV VL later)
12
13 Note: this should NOT have name conventions hard-coded (dedicated ports per
14 regname). However it is convenient for now.
15
16 Links:
17
18 * https://bugs.libre-soc.org/show_bug.cgi?id=345
19 * https://bugs.libre-soc.org/show_bug.cgi?id=351
20 * https://libre-soc.org/3d_gpu/architecture/regfile/
21 * https://libre-soc.org/openpower/isatables/sprs.csv
22 * https://libre-soc.org/openpower/sv/sprs/ (SVSTATE)
23 """
24
25 # TODO
26
27 from soc.regfile.regfile import RegFile, RegFileArray, RegFileMem
28 from soc.regfile.virtual_port import VirtualRegPort
29 from openpower.decoder.power_enums import SPRfull, SPRreduced
30
31 # XXX MAKE DAMN SURE TO KEEP THESE UP-TO-DATE if changing/adding regs
32 from openpower.consts import StateRegsEnum, XERRegsEnum, FastRegsEnum
33
34 from nmigen import Module
35 from nmigen.cli import rtlil
36
37
38 def create_ports(rf, wr_spec, rd_spec):
39 """create_ports: creates register file ports based on requested specs
40 """
41 rf.r_ports, rf.w_ports = {}, {}
42 # create read ports based on read specs
43 for key, name in rd_spec.items():
44 if hasattr(rf, name): # some regfiles already have a port
45 rf.r_ports[key] = getattr(rf, name)
46 else:
47 rf.r_ports[key] = rf.read_port(name)
48 # create write ports based on write specs
49 for key, name in wr_spec.items():
50 if hasattr(rf, name): # some regfiles already have a port
51 rf.w_ports[key] = getattr(rf, name)
52 else:
53 rf.w_ports[key] = rf.write_port(name)
54
55
56 # "State" Regfile
57 class StateRegs(RegFileArray, StateRegsEnum):
58 """StateRegs
59
60 State regfile - PC, MSR, SVSTATE (for SimpleV)
61
62 * QTY 3of 64-bit registers
63 * 4R3W
64 * Array-based unary-indexed (not binary-indexed)
65 * write-through capability (read on same cycle as write)
66
67 Note: d_wr1 d_rd1 are for use by the decoder, to get at the PC.
68 will probably have to also add one so it can get at the MSR as well.
69 (d_rd2)
70
71 """
72 def __init__(self, svp64_en=False, regreduce_en=False):
73 super().__init__(64, StateRegsEnum.N_REGS)
74 wr_spec, rd_spec = self.get_port_specs()
75 create_ports(self, wr_spec, rd_spec)
76
77 def get_port_specs(self):
78 w_port_spec = {'nia': "nia",
79 'msr': "msr",
80 'svstate': "svstate",
81 'sv': "sv", # writing SVSTATE (issuer)
82 'd_wr1': "d_wr1"} # writing PC (issuer)
83 r_port_spec = {'cia': "cia", # reading PC (issuer)
84 'msr': "msr", # reading MSR (issuer)
85 'sv': "sv", # reading SV (issuer)
86 }
87 return w_port_spec, r_port_spec
88
89
90 # Integer Regfile
91 class IntRegs(RegFileMem): #class IntRegs(RegFileArray):
92 """IntRegs
93
94 * QTY 32of 64-bit registers
95 * 3R2W
96 * Array-based unary-indexed (not binary-indexed)
97 * write-through capability (read on same cycle as write)
98 """
99 def __init__(self, svp64_en=False, regreduce_en=False):
100 super().__init__(64, 32, fwd_bus_mode=not regreduce_en)
101 self.svp64_en = svp64_en
102 self.regreduce_en = regreduce_en
103 wr_spec, rd_spec = self.get_port_specs()
104 create_ports(self, wr_spec, rd_spec)
105
106 def get_port_specs(self):
107 w_port_spec = {'o': "dest1",
108 }
109 r_port_spec = { 'dmi': "dmi" # needed for Debug (DMI)
110 }
111 if self.svp64_en:
112 r_port_spec['pred'] = "pred" # for predicate mask
113 if not self.regreduce_en:
114 w_port_spec['o1'] = "dest2" # (LD/ST update)
115 r_port_spec['ra'] = "src1"
116 r_port_spec['rb'] = "src2"
117 r_port_spec['rc'] = "src3"
118 else:
119 r_port_spec['rabc'] = "src1"
120 return w_port_spec, r_port_spec
121
122
123 # Fast SPRs Regfile
124 class FastRegs(RegFileMem, FastRegsEnum): #RegFileArray):
125 """FastRegs
126
127 FAST regfile - CTR, LR, TAR, SRR1, SRR2, XER, TB, DEC, SVSRR0
128
129 * QTY 6of 64-bit registers
130 * 3R2W
131 * Array-based unary-indexed (not binary-indexed)
132 * write-through capability (read on same cycle as write)
133
134 Note: r/w issue are used by issuer to increment/decrement TB/DEC.
135 """
136 def __init__(self, svp64_en=False, regreduce_en=False):
137 super().__init__(64, FastRegsEnum.N_REGS, fwd_bus_mode=not regreduce_en)
138 self.svp64_en = svp64_en
139 self.regreduce_en = regreduce_en
140 wr_spec, rd_spec = self.get_port_specs()
141 create_ports(self, wr_spec, rd_spec)
142
143 def get_port_specs(self):
144 w_port_spec = {'fast1': "dest1",
145 'issue': "issue", # writing DEC/TB
146 }
147 r_port_spec = {'fast1': "src1",
148 'issue': "issue", # reading DEC/TB
149 }
150 if not self.regreduce_en:
151 r_port_spec['fast2'] = "src2"
152 r_port_spec['fast3'] = "src3"
153 w_port_spec['fast2'] = "dest2"
154 w_port_spec['fast3'] = "dest3"
155
156 return w_port_spec, r_port_spec
157
158
159 # CR Regfile
160 class CRRegs(VirtualRegPort):
161 """Condition Code Registers (CR0-7)
162
163 * QTY 8of 8-bit registers
164 * 3R1W 4-bit-wide with additional 1R1W for the "full" 32-bit width
165 * Array-based unary-indexed (not binary-indexed)
166 * write-through capability (read on same cycle as write)
167 """
168 def __init__(self, svp64_en=False, regreduce_en=False):
169 super().__init__(32, 8, rd2=True)
170 self.svp64_en = svp64_en
171 self.regreduce_en = regreduce_en
172 wr_spec, rd_spec = self.get_port_specs()
173 create_ports(self, wr_spec, rd_spec)
174
175 def get_port_specs(self):
176 w_port_spec = {'full_cr': "full_wr", # 32-bit (masked, 8-en lines)
177 'cr_a': "dest1", # 4-bit, unary-indexed
178 'cr_b': "dest2"} # 4-bit, unary-indexed
179 r_port_spec = {'full_cr': "full_rd", # 32-bit (masked, 8-en lines)
180 'full_cr_dbg': "full_rd2", # for DMI
181 'cr_a': "src1",
182 'cr_b': "src2",
183 'cr_c': "src3"}
184 if self.svp64_en:
185 r_port_spec['cr_pred'] = "cr_pred" # for predicate
186
187 return w_port_spec, r_port_spec
188
189
190 # XER Regfile
191 class XERRegs(VirtualRegPort, XERRegsEnum):
192 """XER Registers (SO, CA/CA32, OV/OV32)
193
194 * QTY 3of 2-bit registers
195 * 3R3W 2-bit-wide with additional 1R1W for the "full" 6-bit width
196 * Array-based unary-indexed (not binary-indexed)
197 * write-through capability (read on same cycle as write)
198 """
199 SO=0 # this is actually 2-bit but we ignore 1 bit of it
200 CA=1 # CA and CA32
201 OV=2 # OV and OV32
202 def __init__(self, svp64_en=False, regreduce_en=False):
203 super().__init__(6, XERRegsEnum.N_REGS)
204 self.svp64_en = svp64_en
205 self.regreduce_en = regreduce_en
206 wr_spec, rd_spec = self.get_port_specs()
207 create_ports(self, wr_spec, rd_spec)
208
209 def get_port_specs(self):
210 w_port_spec = {'full_xer': "full_wr", # 6-bit (masked, 3-en lines)
211 'xer_so': "dest1",
212 'xer_ca': "dest2",
213 'xer_ov': "dest3"}
214 r_port_spec = {'full_xer': "full_rd", # 6-bit (masked, 3-en lines)
215 'xer_so': "src1",
216 'xer_ca': "src2",
217 'xer_ov': "src3"}
218 return w_port_spec, r_port_spec
219
220
221 # SPR Regfile
222 class SPRRegs(RegFileMem):
223 """SPRRegs
224
225 * QTY len(SPRs) 64-bit registers
226 * 1R1W
227 * binary-indexed but REQUIRES MAPPING
228 * write-through capability (read on same cycle as write)
229 """
230 def __init__(self, svp64_en=False, regreduce_en=False):
231 if regreduce_en:
232 n_sprs = len(SPRreduced)
233 else:
234 n_sprs = len(SPRfull)
235 super().__init__(width=64, depth=n_sprs,
236 fwd_bus_mode=not regreduce_en)
237 self.svp64_en = svp64_en
238 self.regreduce_en = regreduce_en
239 wr_spec, rd_spec = self.get_port_specs()
240 create_ports(self, wr_spec, rd_spec)
241
242 def get_port_specs(self):
243 w_port_spec = {'spr1': "spr1"}
244 r_port_spec = {'spr1': "spr1"}
245 return w_port_spec, r_port_spec
246
247
248 # class containing all regfiles: int, cr, xer, fast, spr
249 class RegFiles:
250 # Factory style classes
251 regkls = [('int', IntRegs),
252 ('cr', CRRegs),
253 ('xer', XERRegs),
254 ('fast', FastRegs),
255 ('state', StateRegs),
256 ('spr', SPRRegs),]
257 def __init__(self, pspec, make_hazard_vecs=False):
258 # test is SVP64 is to be enabled
259 svp64_en = hasattr(pspec, "svp64") and (pspec.svp64 == True)
260
261 # and regfile port reduction
262 regreduce_en = hasattr(pspec, "regreduce") and \
263 (pspec.regreduce == True)
264
265 self.rf = {} # register file dict
266 # create regfiles here, Factory style
267 for (name, kls) in RegFiles.regkls:
268 rf = self.rf[name] = kls(svp64_en, regreduce_en)
269 # also add these as instances, self.state, self.fast, self.cr etc.
270 setattr(self, name, rf)
271
272 self.rv, self.wv = {}, {}
273 if make_hazard_vecs:
274 # create a read-hazard and write-hazard vectors for this regfile
275 self.wv = self.make_vecs("wr") # global write vectors
276 self.rv = self.make_vecs("rd") # global read vectors
277
278 def make_vecs(self, name):
279 vec = {}
280 # create regfiles here, Factory style
281 for (name, kls) in RegFiles.regkls:
282 rf = self.rf[name]
283 vec[name] = self.make_hazard_vec(rf, name)
284 return vec
285
286 def make_hazard_vec(self, rf, name):
287 if isinstance(rf, VirtualRegPort):
288 vec = RegFileArray(1, rf.nregs)
289 else:
290 vec = RegFileArray(1, rf.depth)
291 # get read/write port specs and create bitvector ports with same names
292 wr_spec, rd_spec = rf.get_port_specs()
293 # ok, this is complicated/fun.
294 # issue phase for checking whether to issue only needs one read port
295 # however during regfile-read, the corresponding bitvector needs to
296 # be *WRITTEN* to (a 1), and during regfile-write, the corresponding
297 # bitvector *ALSO* needs to be wrtten (a 0). therefore we need to
298 # MERGE the wr_spec and rd_spec with some appropriate name prefixes
299 # to make sure they do not clash
300 rd_bvspec = {'issue': 'issue'}
301 wr_bvspec = {'set': 'set', 'clr': 'clr'}
302 #for k, port in wr_spec.items():
303 # wr_bvspec["wr_%s" % k] = "wr_%s" % port
304 #for k, port in rd_spec.items():
305 # wr_bvspec["rd_%s" % k] = "rd_%s" % port
306 create_ports(vec, wr_bvspec, rd_bvspec)
307 return vec
308
309 def elaborate_into(self, m, platform):
310 for (name, rf) in self.rf.items():
311 setattr(m.submodules, name, rf)
312 for (name, rv) in self.rv.items():
313 setattr(m.submodules, "rv_"+name, rv)
314 for (name, wv) in self.wv.items():
315 setattr(m.submodules, "wv_"+name, wv)
316 return m
317
318 if __name__ == '__main__':
319 m = Module()
320 from soc.config.test.test_loadstore import TestMemPspec
321 pspec = TestMemPspec()
322 rf = RegFiles(pspec, make_hazard_vecs=True)
323 rf.elaborate_into(m, None)
324 vl = rtlil.convert(m)
325 with open("test_regfiles.il", "w") as f:
326 f.write(vl)
327