code-morph regfile port specs to a dictionary format rather than hardcoded
[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
153 return w_port_spec, r_port_spec
154
155
156 # CR Regfile
157 class CRRegs(VirtualRegPort):
158 """Condition Code Registers (CR0-7)
159
160 * QTY 8of 8-bit registers
161 * 3R1W 4-bit-wide with additional 1R1W for the "full" 32-bit width
162 * Array-based unary-indexed (not binary-indexed)
163 * write-through capability (read on same cycle as write)
164 """
165 def __init__(self, svp64_en=False, regreduce_en=False):
166 super().__init__(32, 8, rd2=True)
167 self.svp64_en = svp64_en
168 self.regreduce_en = regreduce_en
169 wr_spec, rd_spec = self.get_port_specs()
170 create_ports(self, wr_spec, rd_spec)
171
172 def get_port_specs(self):
173 w_port_spec = {'full_cr': "full_wr", # 32-bit (masked, 8-en lines)
174 'cr_a': "dest1", # 4-bit, unary-indexed
175 'cr_b': "dest2"} # 4-bit, unary-indexed
176 r_port_spec = {'full_cr': "full_rd", # 32-bit (masked, 8-en lines)
177 'full_cr_dbg': "full_rd2", # for DMI
178 'cr_a': "src1",
179 'cr_b': "src2",
180 'cr_c': "src3"}
181 if self.svp64_en:
182 r_port_spec['cr_pred'] = "cr_pred" # for predicate
183
184 return w_port_spec, r_port_spec
185
186
187 # XER Regfile
188 class XERRegs(VirtualRegPort, XERRegsEnum):
189 """XER Registers (SO, CA/CA32, OV/OV32)
190
191 * QTY 3of 2-bit registers
192 * 3R3W 2-bit-wide with additional 1R1W for the "full" 6-bit width
193 * Array-based unary-indexed (not binary-indexed)
194 * write-through capability (read on same cycle as write)
195 """
196 SO=0 # this is actually 2-bit but we ignore 1 bit of it
197 CA=1 # CA and CA32
198 OV=2 # OV and OV32
199 def __init__(self, svp64_en=False, regreduce_en=False):
200 super().__init__(6, XERRegsEnum.N_REGS)
201 self.svp64_en = svp64_en
202 self.regreduce_en = regreduce_en
203 wr_spec, rd_spec = self.get_port_specs()
204 create_ports(self, wr_spec, rd_spec)
205
206 def get_port_specs(self):
207 w_port_spec = {'full_xer': "full_wr", # 6-bit (masked, 3-en lines)
208 'xer_so': "dest1",
209 'xer_ca': "dest2",
210 'xer_ov': "dest3"}
211 r_port_spec = {'full_xer': "full_rd", # 6-bit (masked, 3-en lines)
212 'xer_so': "src1",
213 'xer_ca': "src2",
214 'xer_ov': "src3"}
215 return w_port_spec, r_port_spec
216
217
218 # SPR Regfile
219 class SPRRegs(RegFileMem):
220 """SPRRegs
221
222 * QTY len(SPRs) 64-bit registers
223 * 1R1W
224 * binary-indexed but REQUIRES MAPPING
225 * write-through capability (read on same cycle as write)
226 """
227 def __init__(self, svp64_en=False, regreduce_en=False):
228 if regreduce_en:
229 n_sprs = len(SPRreduced)
230 else:
231 n_sprs = len(SPRfull)
232 super().__init__(width=64, depth=n_sprs,
233 fwd_bus_mode=not regreduce_en)
234 self.svp64_en = svp64_en
235 self.regreduce_en = regreduce_en
236 wr_spec, rd_spec = self.get_port_specs()
237 create_ports(self, wr_spec, rd_spec)
238
239 def get_port_specs(self):
240 w_port_spec = {'spr1': "spr1"}
241 r_port_spec = {'spr1': "spr1"}
242 return w_port_spec, r_port_spec
243
244
245 # class containing all regfiles: int, cr, xer, fast, spr
246 class RegFiles:
247 # Factory style classes
248 regkls = [('int', IntRegs),
249 ('cr', CRRegs),
250 ('xer', XERRegs),
251 ('fast', FastRegs),
252 ('state', StateRegs),
253 ('spr', SPRRegs),]
254 def __init__(self, pspec, make_hazard_vecs=False):
255 # test is SVP64 is to be enabled
256 svp64_en = hasattr(pspec, "svp64") and (pspec.svp64 == True)
257
258 # and regfile port reduction
259 regreduce_en = hasattr(pspec, "regreduce") and \
260 (pspec.regreduce == True)
261
262 self.rf = {} # register file dict
263 # create regfiles here, Factory style
264 for (name, kls) in RegFiles.regkls:
265 rf = self.rf[name] = kls(svp64_en, regreduce_en)
266 # also add these as instances, self.state, self.fast, self.cr etc.
267 setattr(self, name, rf)
268
269 self.rv, self.wv = {}, {}
270 if make_hazard_vecs:
271 # create a read-hazard and write-hazard vectors for this regfile
272 self.wv = make_vecs(self, "wr") # global write vectors
273 self.rv = make_vecs(self, "rd") # global read vectors
274
275 def make_vecs(self, name):
276 vec = {}
277 # create regfiles here, Factory style
278 for (name, kls) in RegFiles.regkls:
279 vec[name] = self.make_hazard_vec(rf, name)
280 return vec
281
282 def make_hazard_vec(self, rf, name):
283 if isinstance(rf, VirtualRegPort):
284 vec = RegFileArray(rf.bitwidth, 1)
285 else:
286 vec = RegFileArray(rf.depth, 1)
287 if name in ['int', 'cr', 'xer']:
288 n_wrs = 3
289 elif name in ['fast']:
290 n_wrs = 2
291 else:
292 n_wrs = 1
293 # add write ports
294 vec.w_ports = {}
295 for i in range(n_wrs):
296 pname = "wr%d" % i
297 vec.w_ports[pname] = vec.write_port("%s_%s" % (name, pname))
298 # add read port
299 vec.r_ports = {}
300 pname = "rd%d" % 0
301 vec.r_ports[pname] = vec.read_port("%s_%s" % (name, pname))
302 return vec
303
304 def elaborate_into(self, m, platform):
305 for (name, rf) in self.rf.items():
306 setattr(m.submodules, name, rf)
307 for (name, rv) in self.rv.items():
308 setattr(m.submodules, "rv_"+name, rv)
309 for (name, wv) in self.wv.items():
310 setattr(m.submodules, "wv_"+name, wv)
311 return m
312
313 if __name__ == '__main__':
314 m = Module()
315 from soc.config.test.test_loadstore import TestMemPspec
316 pspec = TestMemPspec()
317 rf = RegFiles(pspec, make_hazard_vecs=True)
318 rf.elaborate_into(m, None)
319 vl = rtlil.convert(m)
320 with open("test_regfiles.il", "w") as f:
321 f.write(vl)
322