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