fix DriverConflict over MSR write in Issuer/Core by providing an
[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 }
162 if not self.regreduce_en:
163 r_port_spec['fast2'] = "src2"
164 r_port_spec['fast3'] = "src3"
165 w_port_spec['fast2'] = "dest2"
166 w_port_spec['fast3'] = "dest3"
167
168 return w_port_spec, r_port_spec
169
170
171 # CR Regfile
172 class CRRegs(VirtualRegPort):
173 """Condition Code Registers (CR0-7)
174
175 * QTY 8of 8-bit registers
176 * 3R1W 4-bit-wide with additional 1R1W for the "full" 32-bit width
177 * Array-based unary-indexed (not binary-indexed)
178 * write-through capability (read on same cycle as write)
179 """
180 def __init__(self, svp64_en=False, regreduce_en=False):
181 super().__init__(32, 8, rd2=True)
182 self.svp64_en = svp64_en
183 self.regreduce_en = regreduce_en
184 wr_spec, rd_spec = self.get_port_specs()
185 create_ports(self, wr_spec, rd_spec)
186
187 def get_port_specs(self):
188 w_port_spec = {'full_cr': "full_wr", # 32-bit (masked, 8-en lines)
189 'cr_a': "dest1", # 4-bit, unary-indexed
190 'cr_b': "dest2"} # 4-bit, unary-indexed
191 r_port_spec = {'full_cr': "full_rd", # 32-bit (masked, 8-en lines)
192 'full_cr_dbg': "full_rd2", # for DMI
193 'cr_a': "src1",
194 'cr_b': "src2",
195 'cr_c': "src3"}
196 if self.svp64_en:
197 r_port_spec['cr_pred'] = "cr_pred" # for predicate
198
199 return w_port_spec, r_port_spec
200
201
202 # XER Regfile
203 class XERRegs(VirtualRegPort, XERRegsEnum):
204 """XER Registers (SO, CA/CA32, OV/OV32)
205
206 * QTY 3of 2-bit registers
207 * 3R3W 2-bit-wide with additional 1R1W for the "full" 6-bit width
208 * Array-based unary-indexed (not binary-indexed)
209 * write-through capability (read on same cycle as write)
210 """
211 SO=0 # this is actually 2-bit but we ignore 1 bit of it
212 CA=1 # CA and CA32
213 OV=2 # OV and OV32
214 def __init__(self, svp64_en=False, regreduce_en=False):
215 super().__init__(6, XERRegsEnum.N_REGS)
216 self.svp64_en = svp64_en
217 self.regreduce_en = regreduce_en
218 wr_spec, rd_spec = self.get_port_specs()
219 create_ports(self, wr_spec, rd_spec)
220
221 def get_port_specs(self):
222 w_port_spec = {'full_xer': "full_wr", # 6-bit (masked, 3-en lines)
223 'xer_so': "dest1",
224 'xer_ca': "dest2",
225 'xer_ov': "dest3"}
226 r_port_spec = {'full_xer': "full_rd", # 6-bit (masked, 3-en lines)
227 'xer_so': "src1",
228 'xer_ca': "src2",
229 'xer_ov': "src3"}
230 return w_port_spec, r_port_spec
231
232
233 # SPR Regfile
234 class SPRRegs(RegFileMem):
235 """SPRRegs
236
237 * QTY len(SPRs) 64-bit registers
238 * 1R1W
239 * binary-indexed but REQUIRES MAPPING
240 * write-through capability (read on same cycle as write)
241 """
242 def __init__(self, svp64_en=False, regreduce_en=False):
243 if regreduce_en:
244 n_sprs = len(SPRreduced)
245 else:
246 n_sprs = len(SPRfull)
247 super().__init__(width=64, depth=n_sprs,
248 fwd_bus_mode=False)
249 self.svp64_en = svp64_en
250 self.regreduce_en = regreduce_en
251 wr_spec, rd_spec = self.get_port_specs()
252 create_ports(self, wr_spec, rd_spec)
253
254 def get_port_specs(self):
255 w_port_spec = {'spr1': "spr1"}
256 r_port_spec = {'spr1': "spr1"}
257 return w_port_spec, r_port_spec
258
259
260 # class containing all regfiles: int, cr, xer, fast, spr
261 class RegFiles:
262 # Factory style classes
263 regkls = [('int', IntRegs),
264 ('cr', CRRegs),
265 ('xer', XERRegs),
266 ('fast', FastRegs),
267 ('state', StateRegs),
268 ('spr', SPRRegs),]
269 def __init__(self, pspec, make_hazard_vecs=False,
270 state_resets=None): # state file reset values
271 # test is SVP64 is to be enabled
272 svp64_en = hasattr(pspec, "svp64") and (pspec.svp64 == True)
273
274 # and regfile port reduction
275 regreduce_en = hasattr(pspec, "regreduce") and \
276 (pspec.regreduce == True)
277
278 self.rf = {} # register file dict
279 # create regfiles here, Factory style
280 for (name, kls) in RegFiles.regkls:
281 kwargs = {'svp64_en': svp64_en, 'regreduce_en': regreduce_en}
282 if name == 'state':
283 kwargs['resets'] = state_resets
284 rf = self.rf[name] = kls(**kwargs)
285 # also add these as instances, self.state, self.fast, self.cr etc.
286 setattr(self, name, rf)
287
288 self.rv, self.wv = {}, {}
289 if make_hazard_vecs:
290 # create a read-hazard and write-hazard vectors for this regfile
291 self.wv = self.make_vecs("wr") # global write vectors
292 self.rv = self.make_vecs("rd") # global read vectors
293
294 def make_vecs(self, name):
295 vec = {}
296 # create regfiles here, Factory style
297 for (name, kls) in RegFiles.regkls:
298 rf = self.rf[name]
299 vec[name] = self.make_hazard_vec(rf, name)
300 return vec
301
302 def make_hazard_vec(self, rf, name):
303 if isinstance(rf, VirtualRegPort):
304 vec = SRLatch(sync=False, llen=rf.nregs, name=name)
305 else:
306 vec = SRLatch(sync=False, llen=rf.depth, name=name)
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