Allow the formal engine to perform a same-cycle result in the ALU
[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 from nmutil.latch import SRLatch
37
38
39 def create_ports(rf, wr_spec, rd_spec):
40 """create_ports: creates register file ports based on requested specs
41 """
42 rf.r_ports, rf.w_ports = {}, {}
43 # create read ports based on read specs
44 for key, name in rd_spec.items():
45 if hasattr(rf, name): # some regfiles already have a port
46 rf.r_ports[key] = getattr(rf, name)
47 else:
48 rf.r_ports[key] = rf.read_port(name)
49 # create write ports based on write specs
50 for key, name in wr_spec.items():
51 if hasattr(rf, name): # some regfiles already have a port
52 rf.w_ports[key] = getattr(rf, name)
53 else:
54 rf.w_ports[key] = rf.write_port(name)
55
56
57 # "State" Regfile
58 class StateRegs(RegFileArray, StateRegsEnum):
59 """StateRegs
60
61 State regfile - PC, MSR, SVSTATE (for SimpleV)
62
63 * QTY 3of 64-bit registers
64 * 4R3W
65 * Array-based unary-indexed (not binary-indexed)
66 * write-through capability (read on same cycle as write)
67
68 Note: d_wr1 d_rd1 are for use by the decoder, to get at the PC.
69 will probably have to also add one so it can get at the MSR as well.
70 (d_rd2)
71
72 """
73 def __init__(self, svp64_en=False, regreduce_en=False, resets=None):
74 super().__init__(64, StateRegsEnum.N_REGS, resets=resets)
75 wr_spec, rd_spec = self.get_port_specs()
76 create_ports(self, wr_spec, rd_spec)
77
78 def get_port_specs(self):
79 w_port_spec = { # these 3 allow writing state by Function Units
80 # strictly speaking this should not be allowed,
81 # the information should be passed back to Issuer
82 # to work out what to do
83 'nia': "nia",
84 'msr': "msr",
85 'svstate': "svstate",
86 'issue': "issue", # writing DEC/TB
87 'state1': "state1", # SPR pipeline
88 # these 3 allow writing state by Issuer
89 'sv': "sv", # writing SVSTATE
90 'd_wr1': "d_wr1", # writing PC
91 'd_wr2': "d_wr2"} # writing MSR
92 r_port_spec = { # these are for reading state by Issuer but
93 # the FUs do not read them: they are passed in
94 # because of multi-issue / pipelining / etc.
95 # the state could be totally different and is
96 # only known *at* issue time, *by* the issuer
97 'cia': "cia", # reading PC (issuer)
98 'msr': "msr", # reading MSR (issuer)
99 'sv': "sv", # reading SV (issuer)
100 # SPR and DEC/TB FSM
101 'issue': "issue", # reading DEC/TB
102 'state1': "state1", # SPR pipeline
103 }
104 return w_port_spec, r_port_spec
105
106
107 # Integer Regfile
108 class IntRegs(RegFileMem): #class IntRegs(RegFileArray):
109 """IntRegs
110
111 * QTY 32of 64-bit registers
112 * 3R2W
113 * Array-based unary-indexed (not binary-indexed)
114 * write-through capability (read on same cycle as write)
115 """
116 def __init__(self, svp64_en=False, regreduce_en=False, reg_wid=64):
117 super().__init__(reg_wid, 32, fwd_bus_mode=False)
118 self.svp64_en = svp64_en
119 self.regreduce_en = regreduce_en
120 wr_spec, rd_spec = self.get_port_specs()
121 create_ports(self, wr_spec, rd_spec)
122
123 def get_port_specs(self):
124 w_port_spec = {'o': "dest1",
125 }
126 r_port_spec = { 'dmi': "dmi" # needed for Debug (DMI)
127 }
128 if self.svp64_en:
129 r_port_spec['pred'] = "pred" # for predicate mask
130 if not self.regreduce_en:
131 w_port_spec['o1'] = "dest2" # (LD/ST update)
132 r_port_spec['ra'] = "src1"
133 r_port_spec['rb'] = "src2"
134 r_port_spec['rc'] = "src3"
135 else:
136 r_port_spec['rabc'] = "src1"
137 return w_port_spec, r_port_spec
138
139
140 # Fast SPRs Regfile
141 class FastRegs(RegFileMem, FastRegsEnum): #RegFileArray):
142 """FastRegs
143
144 FAST regfile - CTR, LR, TAR, SRR1, SRR2, XER, SVSRR0
145
146 * QTY 6of 64-bit registers
147 * 3R2W
148 * Array-based unary-indexed (not binary-indexed)
149 * write-through capability (read on same cycle as write)
150
151 Note: r/w issue are used by issuer to increment/decrement TB/DEC.
152 """
153 def __init__(self, svp64_en=False, regreduce_en=False):
154 super().__init__(64, FastRegsEnum.N_REGS, fwd_bus_mode=False)
155 self.svp64_en = svp64_en
156 self.regreduce_en = regreduce_en
157 wr_spec, rd_spec = self.get_port_specs()
158 create_ports(self, wr_spec, rd_spec)
159
160 def get_port_specs(self):
161 w_port_spec = {'fast1': "dest1",
162 }
163 r_port_spec = {'fast1': "src1",
164 'dmi': "dmi" # needed for Debug (DMI)
165 }
166 if not self.regreduce_en:
167 r_port_spec['fast2'] = "src2"
168 r_port_spec['fast3'] = "src3"
169 w_port_spec['fast2'] = "dest2"
170 w_port_spec['fast3'] = "dest3"
171
172 return w_port_spec, r_port_spec
173
174
175 # CR Regfile
176 class CRRegs(VirtualRegPort):
177 """Condition Code Registers (CR0-7)
178
179 * QTY 8of 8-bit registers
180 * 3R1W 4-bit-wide with additional 1R1W for the "full" 32-bit width
181 * Array-based unary-indexed (not binary-indexed)
182 * write-through capability (read on same cycle as write)
183 """
184 def __init__(self, svp64_en=False, regreduce_en=False):
185 super().__init__(32, 8, rd2=True)
186 self.svp64_en = svp64_en
187 self.regreduce_en = regreduce_en
188 wr_spec, rd_spec = self.get_port_specs()
189 create_ports(self, wr_spec, rd_spec)
190
191 def get_port_specs(self):
192 w_port_spec = {'full_cr': "full_wr", # 32-bit (masked, 8-en lines)
193 'cr_a': "dest1", # 4-bit, unary-indexed
194 'cr_b': "dest2"} # 4-bit, unary-indexed
195 r_port_spec = {'full_cr': "full_rd", # 32-bit (masked, 8-en lines)
196 'full_cr_dbg': "full_rd2", # for DMI
197 'cr_a': "src1",
198 'cr_b': "src2",
199 'cr_c': "src3"}
200 if self.svp64_en:
201 r_port_spec['cr_pred'] = "cr_pred" # for predicate
202
203 return w_port_spec, r_port_spec
204
205
206 # XER Regfile
207 class XERRegs(VirtualRegPort, XERRegsEnum):
208 """XER Registers (SO, CA/CA32, OV/OV32)
209
210 * QTY 3of 2-bit registers
211 * 3R3W 2-bit-wide with additional 1R1W for the "full" 6-bit width
212 * Array-based unary-indexed (not binary-indexed)
213 * write-through capability (read on same cycle as write)
214 """
215 SO=0 # this is actually 2-bit but we ignore 1 bit of it
216 CA=1 # CA and CA32
217 OV=2 # OV and OV32
218 def __init__(self, svp64_en=False, regreduce_en=False):
219 super().__init__(6, XERRegsEnum.N_REGS)
220 self.svp64_en = svp64_en
221 self.regreduce_en = regreduce_en
222 wr_spec, rd_spec = self.get_port_specs()
223 create_ports(self, wr_spec, rd_spec)
224
225 def get_port_specs(self):
226 w_port_spec = {'full_xer': "full_wr", # 6-bit (masked, 3-en lines)
227 'xer_so': "dest1",
228 'xer_ca': "dest2",
229 'xer_ov': "dest3"}
230 r_port_spec = {'full_xer': "full_rd", # 6-bit (masked, 3-en lines)
231 'xer_so': "src1",
232 'xer_ca': "src2",
233 'xer_ov': "src3"}
234 return w_port_spec, r_port_spec
235
236
237 # SPR Regfile
238 class SPRRegs(RegFileMem):
239 """SPRRegs
240
241 * QTY len(SPRs) 64-bit registers
242 * 1R1W
243 * binary-indexed but REQUIRES MAPPING
244 * write-through capability (read on same cycle as write)
245 """
246 def __init__(self, svp64_en=False, regreduce_en=False):
247 if regreduce_en:
248 n_sprs = len(SPRreduced)
249 else:
250 n_sprs = len(SPRfull)
251 super().__init__(width=64, depth=n_sprs,
252 fwd_bus_mode=False)
253 self.svp64_en = svp64_en
254 self.regreduce_en = regreduce_en
255 wr_spec, rd_spec = self.get_port_specs()
256 create_ports(self, wr_spec, rd_spec)
257
258 def get_port_specs(self):
259 w_port_spec = {'spr1': "spr1"}
260 r_port_spec = {'spr1': "spr1"}
261 return w_port_spec, r_port_spec
262
263
264 # class containing all regfiles: int, cr, xer, fast, spr
265 class RegFiles:
266 # Factory style classes
267 regkls = [('int', IntRegs),
268 ('cr', CRRegs),
269 ('xer', XERRegs),
270 ('fast', FastRegs),
271 ('state', StateRegs),
272 ('spr', SPRRegs),]
273 def __init__(self, pspec, make_hazard_vecs=False,
274 state_resets=None): # state file reset values
275 # test is SVP64 is to be enabled
276 svp64_en = hasattr(pspec, "svp64") and (pspec.svp64 == True)
277
278 # and regfile port reduction
279 regreduce_en = hasattr(pspec, "regreduce") and \
280 (pspec.regreduce == True)
281
282 # get Integer File register width
283 reg_wid = 64
284 if isinstance(pspec.XLEN, int):
285 reg_wid = pspec.XLEN
286
287 self.rf = {} # register file dict
288 # create regfiles here, Factory style
289 for (name, kls) in RegFiles.regkls:
290 kwargs = {'svp64_en': svp64_en, 'regreduce_en': regreduce_en}
291 if name == 'state':
292 kwargs['resets'] = state_resets
293 if name == 'int':
294 kwargs['reg_wid'] = reg_wid
295 rf = self.rf[name] = kls(**kwargs)
296 # also add these as instances, self.state, self.fast, self.cr etc.
297 setattr(self, name, rf)
298
299 self.rv, self.wv = {}, {}
300 if make_hazard_vecs:
301 # create a read-hazard and write-hazard vectors for this regfile
302 self.wv = self.make_vecs("wr") # global write vectors
303 self.rv = self.make_vecs("rd") # global read vectors
304
305 def make_vecs(self, name):
306 vec = {}
307 # create regfiles here, Factory style
308 for (name, kls) in RegFiles.regkls:
309 rf = self.rf[name]
310 vec[name] = self.make_hazard_vec(rf, name)
311 return vec
312
313 def make_hazard_vec(self, rf, name):
314 if isinstance(rf, VirtualRegPort):
315 vec = SRLatch(sync=False, llen=rf.nregs, name=name)
316 else:
317 vec = SRLatch(sync=False, llen=rf.depth, name=name)
318 return vec
319
320 def elaborate_into(self, m, platform):
321 for (name, rf) in self.rf.items():
322 setattr(m.submodules, name, rf)
323 for (name, rv) in self.rv.items():
324 setattr(m.submodules, "rv_"+name, rv)
325 for (name, wv) in self.wv.items():
326 setattr(m.submodules, "wv_"+name, wv)
327 return m
328
329 if __name__ == '__main__':
330 m = Module()
331 from soc.config.test.test_loadstore import TestMemPspec
332 pspec = TestMemPspec(regreduce_en=True,
333 XLEN=32) # integer reg width = 32
334 rf = RegFiles(pspec, make_hazard_vecs=True)
335 rf.elaborate_into(m, None)
336 vl = rtlil.convert(m)
337 with open("test_regfiles.il", "w") as f:
338 f.write(vl)
339