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