convert hazard bitvectors to Reset-Priority SRLatch from nmutil
[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):
74 super().__init__(64, StateRegsEnum.N_REGS)
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=not regreduce_en)
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=not regreduce_en)
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=not regreduce_en)
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 # test is SVP64 is to be enabled
260 svp64_en = hasattr(pspec, "svp64") and (pspec.svp64 == True)
261
262 # and regfile port reduction
263 regreduce_en = hasattr(pspec, "regreduce") and \
264 (pspec.regreduce == True)
265
266 self.rf = {} # register file dict
267 # create regfiles here, Factory style
268 for (name, kls) in RegFiles.regkls:
269 rf = self.rf[name] = kls(svp64_en, regreduce_en)
270 # also add these as instances, self.state, self.fast, self.cr etc.
271 setattr(self, name, rf)
272
273 self.rv, self.wv = {}, {}
274 if make_hazard_vecs:
275 # create a read-hazard and write-hazard vectors for this regfile
276 self.wv = self.make_vecs("wr") # global write vectors
277 self.rv = self.make_vecs("rd") # global read vectors
278
279 def make_vecs(self, name):
280 vec = {}
281 # create regfiles here, Factory style
282 for (name, kls) in RegFiles.regkls:
283 rf = self.rf[name]
284 vec[name] = self.make_hazard_vec(rf, name)
285 return vec
286
287 def make_hazard_vec(self, rf, name):
288 if isinstance(rf, VirtualRegPort):
289 vec = SRLatch(sync=False, llen=rf.nregs, name=name)
290 else:
291 vec = SRLatch(sync=False, llen=rf.depth, name=name)
292 return vec
293
294 def elaborate_into(self, m, platform):
295 for (name, rf) in self.rf.items():
296 setattr(m.submodules, name, rf)
297 for (name, rv) in self.rv.items():
298 setattr(m.submodules, "rv_"+name, rv)
299 for (name, wv) in self.wv.items():
300 setattr(m.submodules, "wv_"+name, wv)
301 return m
302
303 if __name__ == '__main__':
304 m = Module()
305 from soc.config.test.test_loadstore import TestMemPspec
306 pspec = TestMemPspec()
307 rf = RegFiles(pspec, make_hazard_vecs=True)
308 rf.elaborate_into(m, None)
309 vl = rtlil.convert(m)
310 with open("test_regfiles.il", "w") as f:
311 f.write(vl)
312