1 # POWER9 Register Files
4 Defines the following register files:
6 * INT regfile - 32x 64-bit
7 * SPR regfile - 110x 64-bit
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)
13 Note: this should NOT have name conventions hard-coded (dedicated ports per
14 regname). However it is convenient for now.
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)
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
31 # XXX MAKE DAMN SURE TO KEEP THESE UP-TO-DATE if changing/adding regs
32 from openpower
.consts
import StateRegsEnum
, XERRegsEnum
, FastRegsEnum
34 from nmigen
import Module
35 from nmigen
.cli
import rtlil
36 from nmutil
.latch
import SRLatch
39 def create_ports(rf
, wr_spec
, rd_spec
):
40 """create_ports: creates register file ports based on requested specs
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
)
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
)
54 rf
.w_ports
[key
] = rf
.write_port(name
)
58 class StateRegs(RegFileArray
, StateRegsEnum
):
61 State regfile - PC, MSR, SVSTATE (for SimpleV)
63 * QTY 3of 64-bit registers
65 * Array-based unary-indexed (not binary-indexed)
66 * write-through capability (read on same cycle as write)
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.
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
)
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
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)
99 return w_port_spec
, r_port_spec
103 class IntRegs(RegFileMem
): #class IntRegs(RegFileArray):
106 * QTY 32of 64-bit registers
108 * Array-based unary-indexed (not binary-indexed)
109 * write-through capability (read on same cycle as write)
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
)
118 def get_port_specs(self
):
119 w_port_spec
= {'o': "dest1",
121 r_port_spec
= { 'dmi': "dmi" # needed for Debug (DMI)
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"
131 r_port_spec
['rabc'] = "src1"
132 return w_port_spec
, r_port_spec
136 class FastRegs(RegFileMem
, FastRegsEnum
): #RegFileArray):
139 FAST regfile - CTR, LR, TAR, SRR1, SRR2, XER, TB, DEC, SVSRR0
141 * QTY 6of 64-bit registers
143 * Array-based unary-indexed (not binary-indexed)
144 * write-through capability (read on same cycle as write)
146 Note: r/w issue are used by issuer to increment/decrement TB/DEC.
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
)
155 def get_port_specs(self
):
156 w_port_spec
= {'fast1': "dest1",
157 'issue': "issue", # writing DEC/TB
159 r_port_spec
= {'fast1': "src1",
160 'issue': "issue", # reading DEC/TB
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"
168 return w_port_spec
, r_port_spec
172 class CRRegs(VirtualRegPort
):
173 """Condition Code Registers (CR0-7)
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)
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
)
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
197 r_port_spec
['cr_pred'] = "cr_pred" # for predicate
199 return w_port_spec
, r_port_spec
203 class XERRegs(VirtualRegPort
, XERRegsEnum
):
204 """XER Registers (SO, CA/CA32, OV/OV32)
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)
211 SO
=0 # this is actually 2-bit but we ignore 1 bit of it
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
)
221 def get_port_specs(self
):
222 w_port_spec
= {'full_xer': "full_wr", # 6-bit (masked, 3-en lines)
226 r_port_spec
= {'full_xer': "full_rd", # 6-bit (masked, 3-en lines)
230 return w_port_spec
, r_port_spec
234 class SPRRegs(RegFileMem
):
237 * QTY len(SPRs) 64-bit registers
239 * binary-indexed but REQUIRES MAPPING
240 * write-through capability (read on same cycle as write)
242 def __init__(self
, svp64_en
=False, regreduce_en
=False):
244 n_sprs
= len(SPRreduced
)
246 n_sprs
= len(SPRfull
)
247 super().__init
__(width
=64, depth
=n_sprs
,
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
)
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
260 # class containing all regfiles: int, cr, xer, fast, spr
262 # Factory style classes
263 regkls
= [('int', IntRegs
),
267 ('state', StateRegs
),
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)
274 # and regfile port reduction
275 regreduce_en
= hasattr(pspec
, "regreduce") and \
276 (pspec
.regreduce
== True)
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
}
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
)
288 self
.rv
, self
.wv
= {}, {}
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
294 def make_vecs(self
, name
):
296 # create regfiles here, Factory style
297 for (name
, kls
) in RegFiles
.regkls
:
299 vec
[name
] = self
.make_hazard_vec(rf
, name
)
302 def make_hazard_vec(self
, rf
, name
):
303 if isinstance(rf
, VirtualRegPort
):
304 vec
= SRLatch(sync
=False, llen
=rf
.nregs
, name
=name
)
306 vec
= SRLatch(sync
=False, llen
=rf
.depth
, name
=name
)
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
)
318 if __name__
== '__main__':
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
: