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 'issue': "issue", # writing DEC/TB
87 'state1': "state1", # SPR pipeline
88 # these 3 allow writing state by Issuer
89 'sv': "sv", # writing SVSTATE
90 'd_wr1': "d_wr1", # writing PC
91 'd_wr2': "d_wr2"} # writing MSR
92 r_port_spec
= { # these are for reading state by Issuer but
93 # the FUs do not read them: they are passed in
94 # because of multi-issue / pipelining / etc.
95 # the state could be totally different and is
96 # only known *at* issue time, *by* the issuer
97 'cia': "cia", # reading PC (issuer)
98 'msr': "msr", # reading MSR (issuer)
99 'sv': "sv", # reading SV (issuer)
101 'issue': "issue", # reading DEC/TB
102 'state1': "state1", # SPR pipeline
104 return w_port_spec
, r_port_spec
108 class IntRegs(RegFileMem
): #class IntRegs(RegFileArray):
111 * QTY 32of 64-bit registers
113 * Array-based unary-indexed (not binary-indexed)
114 * write-through capability (read on same cycle as write)
116 def __init__(self
, svp64_en
=False, regreduce_en
=False, reg_wid
=64):
117 super().__init
__(reg_wid
, 32, fwd_bus_mode
=False)
118 self
.svp64_en
= svp64_en
119 self
.regreduce_en
= regreduce_en
120 wr_spec
, rd_spec
= self
.get_port_specs()
121 create_ports(self
, wr_spec
, rd_spec
)
123 def get_port_specs(self
):
124 w_port_spec
= {'o': "dest1",
126 r_port_spec
= { 'dmi': "dmi" # needed for Debug (DMI)
129 r_port_spec
['pred'] = "pred" # for predicate mask
130 if not self
.regreduce_en
:
131 w_port_spec
['o1'] = "dest2" # (LD/ST update)
132 r_port_spec
['ra'] = "src1"
133 r_port_spec
['rb'] = "src2"
134 r_port_spec
['rc'] = "src3"
136 r_port_spec
['rabc'] = "src1"
137 return w_port_spec
, r_port_spec
141 class FastRegs(RegFileMem
, FastRegsEnum
): #RegFileArray):
144 FAST regfile - CTR, LR, TAR, SRR1, SRR2, XER, SVSRR0
146 * QTY 6of 64-bit registers
148 * Array-based unary-indexed (not binary-indexed)
149 * write-through capability (read on same cycle as write)
151 Note: r/w issue are used by issuer to increment/decrement TB/DEC.
153 def __init__(self
, svp64_en
=False, regreduce_en
=False):
154 super().__init
__(64, FastRegsEnum
.N_REGS
, fwd_bus_mode
=False)
155 self
.svp64_en
= svp64_en
156 self
.regreduce_en
= regreduce_en
157 wr_spec
, rd_spec
= self
.get_port_specs()
158 create_ports(self
, wr_spec
, rd_spec
)
160 def get_port_specs(self
):
161 w_port_spec
= {'fast1': "dest1",
163 r_port_spec
= {'fast1': "src1",
164 'dmi': "dmi" # needed for Debug (DMI)
166 if not self
.regreduce_en
:
167 r_port_spec
['fast2'] = "src2"
168 r_port_spec
['fast3'] = "src3"
169 w_port_spec
['fast2'] = "dest2"
170 w_port_spec
['fast3'] = "dest3"
172 return w_port_spec
, r_port_spec
176 class CRRegs(VirtualRegPort
):
177 """Condition Code Registers (CR0-7)
179 * QTY 8of 8-bit registers
180 * 3R1W 4-bit-wide with additional 1R1W for the "full" 32-bit width
181 * Array-based unary-indexed (not binary-indexed)
182 * write-through capability (read on same cycle as write)
184 def __init__(self
, svp64_en
=False, regreduce_en
=False):
185 super().__init
__(32, 8, rd2
=True)
186 self
.svp64_en
= svp64_en
187 self
.regreduce_en
= regreduce_en
188 wr_spec
, rd_spec
= self
.get_port_specs()
189 create_ports(self
, wr_spec
, rd_spec
)
191 def get_port_specs(self
):
192 w_port_spec
= {'full_cr': "full_wr", # 32-bit (masked, 8-en lines)
193 'cr_a': "dest1", # 4-bit, unary-indexed
194 'cr_b': "dest2"} # 4-bit, unary-indexed
195 r_port_spec
= {'full_cr': "full_rd", # 32-bit (masked, 8-en lines)
196 'full_cr_dbg': "full_rd2", # for DMI
201 r_port_spec
['cr_pred'] = "cr_pred" # for predicate
203 return w_port_spec
, r_port_spec
207 class XERRegs(VirtualRegPort
, XERRegsEnum
):
208 """XER Registers (SO, CA/CA32, OV/OV32)
210 * QTY 3of 2-bit registers
211 * 3R3W 2-bit-wide with additional 1R1W for the "full" 6-bit width
212 * Array-based unary-indexed (not binary-indexed)
213 * write-through capability (read on same cycle as write)
215 SO
=0 # this is actually 2-bit but we ignore 1 bit of it
218 def __init__(self
, svp64_en
=False, regreduce_en
=False):
219 super().__init
__(6, XERRegsEnum
.N_REGS
)
220 self
.svp64_en
= svp64_en
221 self
.regreduce_en
= regreduce_en
222 wr_spec
, rd_spec
= self
.get_port_specs()
223 create_ports(self
, wr_spec
, rd_spec
)
225 def get_port_specs(self
):
226 w_port_spec
= {'full_xer': "full_wr", # 6-bit (masked, 3-en lines)
230 r_port_spec
= {'full_xer': "full_rd", # 6-bit (masked, 3-en lines)
234 return w_port_spec
, r_port_spec
238 class SPRRegs(RegFileMem
):
241 * QTY len(SPRs) 64-bit registers
243 * binary-indexed but REQUIRES MAPPING
244 * write-through capability (read on same cycle as write)
246 def __init__(self
, svp64_en
=False, regreduce_en
=False):
248 n_sprs
= len(SPRreduced
)
250 n_sprs
= len(SPRfull
)
251 super().__init
__(width
=64, depth
=n_sprs
,
253 self
.svp64_en
= svp64_en
254 self
.regreduce_en
= regreduce_en
255 wr_spec
, rd_spec
= self
.get_port_specs()
256 create_ports(self
, wr_spec
, rd_spec
)
258 def get_port_specs(self
):
259 w_port_spec
= {'spr1': "spr1"}
260 r_port_spec
= {'spr1': "spr1"}
261 return w_port_spec
, r_port_spec
264 # class containing all regfiles: int, cr, xer, fast, spr
266 # Factory style classes
267 regkls
= [('int', IntRegs
),
271 ('state', StateRegs
),
273 def __init__(self
, pspec
, make_hazard_vecs
=False,
274 state_resets
=None): # state file reset values
275 # test is SVP64 is to be enabled
276 svp64_en
= hasattr(pspec
, "svp64") and (pspec
.svp64
== True)
278 # and regfile port reduction
279 regreduce_en
= hasattr(pspec
, "regreduce") and \
280 (pspec
.regreduce
== True)
282 # get Integer File register width
284 if isinstance(pspec
.XLEN
, int):
287 self
.rf
= {} # register file dict
288 # create regfiles here, Factory style
289 for (name
, kls
) in RegFiles
.regkls
:
290 kwargs
= {'svp64_en': svp64_en
, 'regreduce_en': regreduce_en
}
292 kwargs
['resets'] = state_resets
294 kwargs
['reg_wid'] = reg_wid
295 rf
= self
.rf
[name
] = kls(**kwargs
)
296 # also add these as instances, self.state, self.fast, self.cr etc.
297 setattr(self
, name
, rf
)
299 self
.rv
, self
.wv
= {}, {}
301 # create a read-hazard and write-hazard vectors for this regfile
302 self
.wv
= self
.make_vecs("wr") # global write vectors
303 self
.rv
= self
.make_vecs("rd") # global read vectors
305 def make_vecs(self
, name
):
307 # create regfiles here, Factory style
308 for (name
, kls
) in RegFiles
.regkls
:
310 vec
[name
] = self
.make_hazard_vec(rf
, name
)
313 def make_hazard_vec(self
, rf
, name
):
314 if isinstance(rf
, VirtualRegPort
):
315 vec
= SRLatch(sync
=False, llen
=rf
.nregs
, name
=name
)
317 vec
= SRLatch(sync
=False, llen
=rf
.depth
, name
=name
)
320 def elaborate_into(self
, m
, platform
):
321 for (name
, rf
) in self
.rf
.items():
322 setattr(m
.submodules
, name
, rf
)
323 for (name
, rv
) in self
.rv
.items():
324 setattr(m
.submodules
, "rv_"+name
, rv
)
325 for (name
, wv
) in self
.wv
.items():
326 setattr(m
.submodules
, "wv_"+name
, wv
)
329 if __name__
== '__main__':
331 from soc
.config
.test
.test_loadstore
import TestMemPspec
332 pspec
= TestMemPspec(regreduce_en
=True,
333 XLEN
=32) # integer reg width = 32
334 rf
= RegFiles(pspec
, make_hazard_vecs
=True)
335 rf
.elaborate_into(m
, None)
336 vl
= rtlil
.convert(m
)
337 with
open("test_regfiles.il", "w") as f
: