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
38 def create_ports(rf
, wr_spec
, rd_spec
):
39 """create_ports: creates register file ports based on requested specs
41 rf
.r_ports
, rf
.w_ports
= {}, {}
42 # create read ports based on read specs
43 for key
, name
in rd_spec
.items():
44 if hasattr(rf
, name
): # some regfiles already have a port
45 rf
.r_ports
[key
] = getattr(rf
, name
)
47 rf
.r_ports
[key
] = rf
.read_port(name
)
48 # create write ports based on write specs
49 for key
, name
in wr_spec
.items():
50 if hasattr(rf
, name
): # some regfiles already have a port
51 rf
.w_ports
[key
] = getattr(rf
, name
)
53 rf
.w_ports
[key
] = rf
.write_port(name
)
57 class StateRegs(RegFileArray
, StateRegsEnum
):
60 State regfile - PC, MSR, SVSTATE (for SimpleV)
62 * QTY 3of 64-bit registers
64 * Array-based unary-indexed (not binary-indexed)
65 * write-through capability (read on same cycle as write)
67 Note: d_wr1 d_rd1 are for use by the decoder, to get at the PC.
68 will probably have to also add one so it can get at the MSR as well.
72 def __init__(self
, svp64_en
=False, regreduce_en
=False):
73 super().__init
__(64, StateRegsEnum
.N_REGS
)
74 wr_spec
, rd_spec
= self
.get_port_specs()
75 create_ports(self
, wr_spec
, rd_spec
)
77 def get_port_specs(self
):
78 w_port_spec
= {'nia': "nia",
81 'sv': "sv", # writing SVSTATE (issuer)
82 'd_wr1': "d_wr1"} # writing PC (issuer)
83 r_port_spec
= {'cia': "cia", # reading PC (issuer)
84 'msr': "msr", # reading MSR (issuer)
85 'sv': "sv", # reading SV (issuer)
87 return w_port_spec
, r_port_spec
91 class IntRegs(RegFileMem
): #class IntRegs(RegFileArray):
94 * QTY 32of 64-bit registers
96 * Array-based unary-indexed (not binary-indexed)
97 * write-through capability (read on same cycle as write)
99 def __init__(self
, svp64_en
=False, regreduce_en
=False):
100 super().__init
__(64, 32, fwd_bus_mode
=not regreduce_en
)
101 self
.svp64_en
= svp64_en
102 self
.regreduce_en
= regreduce_en
103 wr_spec
, rd_spec
= self
.get_port_specs()
104 create_ports(self
, wr_spec
, rd_spec
)
106 def get_port_specs(self
):
107 w_port_spec
= {'o': "dest1",
109 r_port_spec
= { 'dmi': "dmi" # needed for Debug (DMI)
112 r_port_spec
['pred'] = "pred" # for predicate mask
113 if not self
.regreduce_en
:
114 w_port_spec
['o1'] = "dest2" # (LD/ST update)
115 r_port_spec
['ra'] = "src1"
116 r_port_spec
['rb'] = "src2"
117 r_port_spec
['rc'] = "src3"
119 r_port_spec
['rabc'] = "src1"
120 return w_port_spec
, r_port_spec
124 class FastRegs(RegFileMem
, FastRegsEnum
): #RegFileArray):
127 FAST regfile - CTR, LR, TAR, SRR1, SRR2, XER, TB, DEC, SVSRR0
129 * QTY 6of 64-bit registers
131 * Array-based unary-indexed (not binary-indexed)
132 * write-through capability (read on same cycle as write)
134 Note: r/w issue are used by issuer to increment/decrement TB/DEC.
136 def __init__(self
, svp64_en
=False, regreduce_en
=False):
137 super().__init
__(64, FastRegsEnum
.N_REGS
, fwd_bus_mode
=not regreduce_en
)
138 self
.svp64_en
= svp64_en
139 self
.regreduce_en
= regreduce_en
140 wr_spec
, rd_spec
= self
.get_port_specs()
141 create_ports(self
, wr_spec
, rd_spec
)
143 def get_port_specs(self
):
144 w_port_spec
= {'fast1': "dest1",
145 'issue': "issue", # writing DEC/TB
147 r_port_spec
= {'fast1': "src1",
148 'issue': "issue", # reading DEC/TB
150 if not self
.regreduce_en
:
151 r_port_spec
['fast2'] = "src2"
152 r_port_spec
['fast3'] = "src3"
153 w_port_spec
['fast2'] = "dest2"
154 w_port_spec
['fast3'] = "dest3"
156 return w_port_spec
, r_port_spec
160 class CRRegs(VirtualRegPort
):
161 """Condition Code Registers (CR0-7)
163 * QTY 8of 8-bit registers
164 * 3R1W 4-bit-wide with additional 1R1W for the "full" 32-bit width
165 * Array-based unary-indexed (not binary-indexed)
166 * write-through capability (read on same cycle as write)
168 def __init__(self
, svp64_en
=False, regreduce_en
=False):
169 super().__init
__(32, 8, rd2
=True)
170 self
.svp64_en
= svp64_en
171 self
.regreduce_en
= regreduce_en
172 wr_spec
, rd_spec
= self
.get_port_specs()
173 create_ports(self
, wr_spec
, rd_spec
)
175 def get_port_specs(self
):
176 w_port_spec
= {'full_cr': "full_wr", # 32-bit (masked, 8-en lines)
177 'cr_a': "dest1", # 4-bit, unary-indexed
178 'cr_b': "dest2"} # 4-bit, unary-indexed
179 r_port_spec
= {'full_cr': "full_rd", # 32-bit (masked, 8-en lines)
180 'full_cr_dbg': "full_rd2", # for DMI
185 r_port_spec
['cr_pred'] = "cr_pred" # for predicate
187 return w_port_spec
, r_port_spec
191 class XERRegs(VirtualRegPort
, XERRegsEnum
):
192 """XER Registers (SO, CA/CA32, OV/OV32)
194 * QTY 3of 2-bit registers
195 * 3R3W 2-bit-wide with additional 1R1W for the "full" 6-bit width
196 * Array-based unary-indexed (not binary-indexed)
197 * write-through capability (read on same cycle as write)
199 SO
=0 # this is actually 2-bit but we ignore 1 bit of it
202 def __init__(self
, svp64_en
=False, regreduce_en
=False):
203 super().__init
__(6, XERRegsEnum
.N_REGS
)
204 self
.svp64_en
= svp64_en
205 self
.regreduce_en
= regreduce_en
206 wr_spec
, rd_spec
= self
.get_port_specs()
207 create_ports(self
, wr_spec
, rd_spec
)
209 def get_port_specs(self
):
210 w_port_spec
= {'full_xer': "full_wr", # 6-bit (masked, 3-en lines)
214 r_port_spec
= {'full_xer': "full_rd", # 6-bit (masked, 3-en lines)
218 return w_port_spec
, r_port_spec
222 class SPRRegs(RegFileMem
):
225 * QTY len(SPRs) 64-bit registers
227 * binary-indexed but REQUIRES MAPPING
228 * write-through capability (read on same cycle as write)
230 def __init__(self
, svp64_en
=False, regreduce_en
=False):
232 n_sprs
= len(SPRreduced
)
234 n_sprs
= len(SPRfull
)
235 super().__init
__(width
=64, depth
=n_sprs
,
236 fwd_bus_mode
=not regreduce_en
)
237 self
.svp64_en
= svp64_en
238 self
.regreduce_en
= regreduce_en
239 wr_spec
, rd_spec
= self
.get_port_specs()
240 create_ports(self
, wr_spec
, rd_spec
)
242 def get_port_specs(self
):
243 w_port_spec
= {'spr1': "spr1"}
244 r_port_spec
= {'spr1': "spr1"}
245 return w_port_spec
, r_port_spec
248 # class containing all regfiles: int, cr, xer, fast, spr
250 # Factory style classes
251 regkls
= [('int', IntRegs
),
255 ('state', StateRegs
),
257 def __init__(self
, pspec
, make_hazard_vecs
=False):
258 # test is SVP64 is to be enabled
259 svp64_en
= hasattr(pspec
, "svp64") and (pspec
.svp64
== True)
261 # and regfile port reduction
262 regreduce_en
= hasattr(pspec
, "regreduce") and \
263 (pspec
.regreduce
== True)
265 self
.rf
= {} # register file dict
266 # create regfiles here, Factory style
267 for (name
, kls
) in RegFiles
.regkls
:
268 rf
= self
.rf
[name
] = kls(svp64_en
, regreduce_en
)
269 # also add these as instances, self.state, self.fast, self.cr etc.
270 setattr(self
, name
, rf
)
272 self
.rv
, self
.wv
= {}, {}
274 # create a read-hazard and write-hazard vectors for this regfile
275 self
.wv
= self
.make_vecs("wr") # global write vectors
276 self
.rv
= self
.make_vecs("rd") # global read vectors
278 def make_vecs(self
, name
):
280 # create regfiles here, Factory style
281 for (name
, kls
) in RegFiles
.regkls
:
283 vec
[name
] = self
.make_hazard_vec(rf
, name
)
286 def make_hazard_vec(self
, rf
, name
):
287 if isinstance(rf
, VirtualRegPort
):
288 vec
= VirtualRegPort(rf
.nregs
, rf
.nregs
, wr2
=True)
290 vec
= VirtualRegPort(rf
.depth
, rf
.depth
, wr2
=True)
291 # get read/write port specs and create bitvector ports with same names
292 wr_spec
, rd_spec
= rf
.get_port_specs()
293 # ok, this is complicated/fun.
294 # issue phase for checking whether to issue only needs one read port
295 # however during regfile-read, the corresponding bitvector needs to
296 # be *WRITTEN* to (a 1), and during regfile-write, the corresponding
297 # bitvector *ALSO* needs to be wrtten (a 0). therefore we need to
298 # MERGE the wr_spec and rd_spec with some appropriate name prefixes
299 # to make sure they do not clash
300 rd_bvspec
= {'issue': 'full_rd'}
301 wr_bvspec
= {'set': 'full_wr', 'clr': 'full_wr2'}
302 create_ports(vec
, wr_bvspec
, rd_bvspec
)
305 def elaborate_into(self
, m
, platform
):
306 for (name
, rf
) in self
.rf
.items():
307 setattr(m
.submodules
, name
, rf
)
308 for (name
, rv
) in self
.rv
.items():
309 setattr(m
.submodules
, "rv_"+name
, rv
)
310 for (name
, wv
) in self
.wv
.items():
311 setattr(m
.submodules
, "wv_"+name
, wv
)
314 if __name__
== '__main__':
316 from soc
.config
.test
.test_loadstore
import TestMemPspec
317 pspec
= TestMemPspec()
318 rf
= RegFiles(pspec
, make_hazard_vecs
=True)
319 rf
.elaborate_into(m
, None)
320 vl
= rtlil
.convert(m
)
321 with
open("test_regfiles.il", "w") as f
: