* SPR regfile - 110x 64-bit
* CR regfile - CR0-7
* XER regfile - XER.so, XER.ca/ca32, XER.ov/ov32
- * FAST regfile - PC, MSR, CTR, LR, TAR, SRR1, SRR2
+ * FAST regfile - CTR, LR, TAR, SRR1, SRR2
+ * STATE regfile - PC, MSR, (SimpleV VL later)
Note: this should NOT have name conventions hard-coded (dedicated ports per
regname). However it is convenient for now.
* https://bugs.libre-soc.org/show_bug.cgi?id=351
* https://libre-soc.org/3d_gpu/architecture/regfile/
* https://libre-soc.org/openpower/isatables/sprs.csv
+* https://libre-soc.org/openpower/sv/sprs/ (SVSTATE)
"""
# TODO
-from soc.regfile.regfile import RegFile, RegFileArray
+from soc.regfile.regfile import RegFile, RegFileArray, RegFileMem
from soc.regfile.virtual_port import VirtualRegPort
-from soc.decoder.power_enums import SPR
+from openpower.decoder.power_enums import SPRfull, SPRreduced
+
+# XXX MAKE DAMN SURE TO KEEP THESE UP-TO-DATE if changing/adding regs
+from openpower.consts import StateRegsEnum, XERRegsEnum, FastRegsEnum
+
+from nmigen import Module
+from nmigen.cli import rtlil
+from nmutil.latch import SRLatch
+
+
+def create_ports(rf, wr_spec, rd_spec):
+ """create_ports: creates register file ports based on requested specs
+ """
+ rf.r_ports, rf.w_ports = {}, {}
+ # create read ports based on read specs
+ for key, name in rd_spec.items():
+ if hasattr(rf, name): # some regfiles already have a port
+ rf.r_ports[key] = getattr(rf, name)
+ else:
+ rf.r_ports[key] = rf.read_port(name)
+ # create write ports based on write specs
+ for key, name in wr_spec.items():
+ if hasattr(rf, name): # some regfiles already have a port
+ rf.w_ports[key] = getattr(rf, name)
+ else:
+ rf.w_ports[key] = rf.write_port(name)
+
+
+# "State" Regfile
+class StateRegs(RegFileArray, StateRegsEnum):
+ """StateRegs
+
+ State regfile - PC, MSR, SVSTATE (for SimpleV)
+
+ * QTY 3of 64-bit registers
+ * 4R3W
+ * Array-based unary-indexed (not binary-indexed)
+ * write-through capability (read on same cycle as write)
+
+ Note: d_wr1 d_rd1 are for use by the decoder, to get at the PC.
+ will probably have to also add one so it can get at the MSR as well.
+ (d_rd2)
+
+ """
+ def __init__(self, svp64_en=False, regreduce_en=False):
+ super().__init__(64, StateRegsEnum.N_REGS)
+ wr_spec, rd_spec = self.get_port_specs()
+ create_ports(self, wr_spec, rd_spec)
+
+ def get_port_specs(self):
+ w_port_spec = {'nia': "nia",
+ 'msr': "msr",
+ 'svstate': "svstate",
+ 'sv': "sv", # writing SVSTATE (issuer)
+ 'd_wr1': "d_wr1"} # writing PC (issuer)
+ r_port_spec = {'cia': "cia", # reading PC (issuer)
+ 'msr': "msr", # reading MSR (issuer)
+ 'sv': "sv", # reading SV (issuer)
+ }
+ return w_port_spec, r_port_spec
# Integer Regfile
-class IntRegs(RegFileArray):
+class IntRegs(RegFileMem): #class IntRegs(RegFileArray):
"""IntRegs
* QTY 32of 64-bit registers
* Array-based unary-indexed (not binary-indexed)
* write-through capability (read on same cycle as write)
"""
- def __init__(self):
- super().__init__(64, 32)
- self.w_ports = {'o': self.write_port("dest1"),
- 'o1': self.write_port("dest2")} # for now (LD/ST update)
- self.r_ports = {'ra': self.read_port("src1"),
- 'rb': self.read_port("src2"),
- 'rc': self.read_port("src3")}
+ def __init__(self, svp64_en=False, regreduce_en=False):
+ super().__init__(64, 32, fwd_bus_mode=False)
+ self.svp64_en = svp64_en
+ self.regreduce_en = regreduce_en
+ wr_spec, rd_spec = self.get_port_specs()
+ create_ports(self, wr_spec, rd_spec)
+
+ def get_port_specs(self):
+ w_port_spec = {'o': "dest1",
+ }
+ r_port_spec = { 'dmi': "dmi" # needed for Debug (DMI)
+ }
+ if self.svp64_en:
+ r_port_spec['pred'] = "pred" # for predicate mask
+ if not self.regreduce_en:
+ w_port_spec['o1'] = "dest2" # (LD/ST update)
+ r_port_spec['ra'] = "src1"
+ r_port_spec['rb'] = "src2"
+ r_port_spec['rc'] = "src3"
+ else:
+ r_port_spec['rabc'] = "src1"
+ return w_port_spec, r_port_spec
# Fast SPRs Regfile
-class FastRegs(RegFileArray):
+class FastRegs(RegFileMem, FastRegsEnum): #RegFileArray):
"""FastRegs
- FAST regfile - PC, MSR, CTR, LR, TAR, SRR1, SRR2
+ FAST regfile - CTR, LR, TAR, SRR1, SRR2, XER, TB, DEC, SVSRR0
- * QTY 8of 64-bit registers
+ * QTY 6of 64-bit registers
* 3R2W
* Array-based unary-indexed (not binary-indexed)
* write-through capability (read on same cycle as write)
+
+ Note: r/w issue are used by issuer to increment/decrement TB/DEC.
"""
- PC = 0
- MSR = 1
- CTR = 2
- LR = 3
- TAR = 4
- SRR0 = 5
- SRR1 = 6
- def __init__(self):
- super().__init__(64, 8)
- self.w_ports = {'nia': self.write_port("dest1"),
- 'msr': self.write_port("dest2"),
- 'spr1': self.write_port("dest3"),
- 'spr2': self.write_port("dest3")}
- self.r_ports = {'cia': self.read_port("src1"),
- 'msr': self.read_port("src2"),
- 'spr1': self.read_port("src3"),
- 'spr2': self.read_port("src3")}
+ def __init__(self, svp64_en=False, regreduce_en=False):
+ super().__init__(64, FastRegsEnum.N_REGS, fwd_bus_mode=False)
+ self.svp64_en = svp64_en
+ self.regreduce_en = regreduce_en
+ wr_spec, rd_spec = self.get_port_specs()
+ create_ports(self, wr_spec, rd_spec)
+
+ def get_port_specs(self):
+ w_port_spec = {'fast1': "dest1",
+ 'issue': "issue", # writing DEC/TB
+ }
+ r_port_spec = {'fast1': "src1",
+ 'issue': "issue", # reading DEC/TB
+ }
+ if not self.regreduce_en:
+ r_port_spec['fast2'] = "src2"
+ r_port_spec['fast3'] = "src3"
+ w_port_spec['fast2'] = "dest2"
+ w_port_spec['fast3'] = "dest3"
+
+ return w_port_spec, r_port_spec
# CR Regfile
* Array-based unary-indexed (not binary-indexed)
* write-through capability (read on same cycle as write)
"""
- def __init__(self):
- super().__init__(32, 8)
- self.w_ports = {'full_cr': self.full_wr, # 32-bit (masked, 8-en lines)
- 'cr_a': self.write_port("dest1"), # 4-bit, unary-indexed
- 'cr_b': self.write_port("dest2")} # 4-bit, unary-indexed
- self.r_ports = {'full_cr': self.full_rd, # 32-bit (masked, 8-en lines)
- 'cr_a': self.read_port("src1"),
- 'cr_b': self.read_port("src2"),
- 'cr_c': self.read_port("src3")}
+ def __init__(self, svp64_en=False, regreduce_en=False):
+ super().__init__(32, 8, rd2=True)
+ self.svp64_en = svp64_en
+ self.regreduce_en = regreduce_en
+ wr_spec, rd_spec = self.get_port_specs()
+ create_ports(self, wr_spec, rd_spec)
+
+ def get_port_specs(self):
+ w_port_spec = {'full_cr': "full_wr", # 32-bit (masked, 8-en lines)
+ 'cr_a': "dest1", # 4-bit, unary-indexed
+ 'cr_b': "dest2"} # 4-bit, unary-indexed
+ r_port_spec = {'full_cr': "full_rd", # 32-bit (masked, 8-en lines)
+ 'full_cr_dbg': "full_rd2", # for DMI
+ 'cr_a': "src1",
+ 'cr_b': "src2",
+ 'cr_c': "src3"}
+ if self.svp64_en:
+ r_port_spec['cr_pred'] = "cr_pred" # for predicate
+
+ return w_port_spec, r_port_spec
# XER Regfile
-class XERRegs(VirtualRegPort):
+class XERRegs(VirtualRegPort, XERRegsEnum):
"""XER Registers (SO, CA/CA32, OV/OV32)
* QTY 3of 2-bit registers
SO=0 # this is actually 2-bit but we ignore 1 bit of it
CA=1 # CA and CA32
OV=2 # OV and OV32
- def __init__(self):
- super().__init__(6, 3)
- self.w_ports = {'full_xer': self.full_wr, # 6-bit (masked, 3-en lines)
- 'xer_so': self.write_port("dest1"),
- 'xer_ca': self.write_port("dest2"),
- 'xer_ov': self.write_port("dest3")}
- self.r_ports = {'full_xer': self.full_rd, # 6-bit (masked, 3-en lines)
- 'xer_so': self.read_port("src1"),
- 'xer_ca': self.read_port("src2"),
- 'xer_ov': self.read_port("src3")}
+ def __init__(self, svp64_en=False, regreduce_en=False):
+ super().__init__(6, XERRegsEnum.N_REGS)
+ self.svp64_en = svp64_en
+ self.regreduce_en = regreduce_en
+ wr_spec, rd_spec = self.get_port_specs()
+ create_ports(self, wr_spec, rd_spec)
+
+ def get_port_specs(self):
+ w_port_spec = {'full_xer': "full_wr", # 6-bit (masked, 3-en lines)
+ 'xer_so': "dest1",
+ 'xer_ca': "dest2",
+ 'xer_ov': "dest3"}
+ r_port_spec = {'full_xer': "full_rd", # 6-bit (masked, 3-en lines)
+ 'xer_so': "src1",
+ 'xer_ca': "src2",
+ 'xer_ov': "src3"}
+ return w_port_spec, r_port_spec
# SPR Regfile
-class SPRRegs(RegFile):
+class SPRRegs(RegFileMem):
"""SPRRegs
* QTY len(SPRs) 64-bit registers
* binary-indexed but REQUIRES MAPPING
* write-through capability (read on same cycle as write)
"""
- def __init__(self):
- n_sprs = len(SPR)
- super().__init__(64, n_sprs)
- self.w_ports = {'spr': self.write_port(name="dest")}
- self.r_ports = {'spr': self.read_port("src")}
+ def __init__(self, svp64_en=False, regreduce_en=False):
+ if regreduce_en:
+ n_sprs = len(SPRreduced)
+ else:
+ n_sprs = len(SPRfull)
+ super().__init__(width=64, depth=n_sprs,
+ fwd_bus_mode=False)
+ self.svp64_en = svp64_en
+ self.regreduce_en = regreduce_en
+ wr_spec, rd_spec = self.get_port_specs()
+ create_ports(self, wr_spec, rd_spec)
+
+ def get_port_specs(self):
+ w_port_spec = {'spr1': "spr1"}
+ r_port_spec = {'spr1': "spr1"}
+ return w_port_spec, r_port_spec
# class containing all regfiles: int, cr, xer, fast, spr
class RegFiles:
- def __init__(self):
- self.rf = {}
- for (name, kls) in [('int', IntRegs),
- ('cr', CRRegs),
- ('xer', XERRegs),
- ('fast', FastRegs),
- ('spr', SPRRegs),]:
- rf = self.rf[name] = kls()
+ # Factory style classes
+ regkls = [('int', IntRegs),
+ ('cr', CRRegs),
+ ('xer', XERRegs),
+ ('fast', FastRegs),
+ ('state', StateRegs),
+ ('spr', SPRRegs),]
+ def __init__(self, pspec, make_hazard_vecs=False):
+ # test is SVP64 is to be enabled
+ svp64_en = hasattr(pspec, "svp64") and (pspec.svp64 == True)
+
+ # and regfile port reduction
+ regreduce_en = hasattr(pspec, "regreduce") and \
+ (pspec.regreduce == True)
+
+ self.rf = {} # register file dict
+ # create regfiles here, Factory style
+ for (name, kls) in RegFiles.regkls:
+ rf = self.rf[name] = kls(svp64_en, regreduce_en)
+ # also add these as instances, self.state, self.fast, self.cr etc.
setattr(self, name, rf)
+ self.rv, self.wv = {}, {}
+ if make_hazard_vecs:
+ # create a read-hazard and write-hazard vectors for this regfile
+ self.wv = self.make_vecs("wr") # global write vectors
+ self.rv = self.make_vecs("rd") # global read vectors
+
+ def make_vecs(self, name):
+ vec = {}
+ # create regfiles here, Factory style
+ for (name, kls) in RegFiles.regkls:
+ rf = self.rf[name]
+ vec[name] = self.make_hazard_vec(rf, name)
+ return vec
+
+ def make_hazard_vec(self, rf, name):
+ if isinstance(rf, VirtualRegPort):
+ vec = SRLatch(sync=False, llen=rf.nregs, name=name)
+ else:
+ vec = SRLatch(sync=False, llen=rf.depth, name=name)
+ return vec
+
def elaborate_into(self, m, platform):
for (name, rf) in self.rf.items():
setattr(m.submodules, name, rf)
+ for (name, rv) in self.rv.items():
+ setattr(m.submodules, "rv_"+name, rv)
+ for (name, wv) in self.wv.items():
+ setattr(m.submodules, "wv_"+name, wv)
return m
+if __name__ == '__main__':
+ m = Module()
+ from soc.config.test.test_loadstore import TestMemPspec
+ pspec = TestMemPspec()
+ rf = RegFiles(pspec, make_hazard_vecs=True)
+ rf.elaborate_into(m, None)
+ vl = rtlil.convert(m)
+ with open("test_regfiles.il", "w") as f:
+ f.write(vl)
+