X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fsoc%2Fregfile%2Fregfiles.py;h=28f8172d74774bdc8c0a95a4406a21520256f7d6;hb=7cc617c9ea924949ed318930cfffc6b3e75b3861;hp=20826b76dbeb4c70187a1a26ab04f5b178a4302d;hpb=847b84d7e0a1fb8c86512cd85a19844fe066daea;p=soc.git diff --git a/src/soc/regfile/regfiles.py b/src/soc/regfile/regfiles.py index 20826b76..28f8172d 100644 --- a/src/soc/regfile/regfiles.py +++ b/src/soc/regfile/regfiles.py @@ -19,45 +19,77 @@ Links: * 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 nmigen import Memory, Elaboratable +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): +class StateRegs(RegFileArray, StateRegsEnum): """StateRegs - State regfile - PC, MSR and later SimpleV VL + State regfile - PC, MSR, SVSTATE (for SimpleV) - * QTY 2of 64-bit registers - * 3R2W + * 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) + """ - PC = 0 - MSR = 1 - def __init__(self): - super().__init__(64, 2) - self.w_ports = {'nia': self.write_port("nia"), - 'msr': self.write_port("msr"), - 'd_wr1': self.write_port("d_wr1")} # writing PC (issuer) - self.r_ports = {'cia': self.read_port("cia"), # reading PC (issuer) - 'msr': self.read_port("msr"), # reading MSR (issuer) + 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 @@ -65,38 +97,64 @@ class IntRegs(RegFileArray): * 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"), - 'rbc': self.read_port("src3"), - 'dmi': self.read_port("dmi")} # needed for Debug (DMI) + 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 - CTR, LR, TAR, SRR1, SRR2 + FAST regfile - CTR, LR, TAR, SRR1, SRR2, XER, TB, DEC, SVSRR0 - * QTY 5of 64-bit registers - * 2R1W + * 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. """ - CTR = 0 - LR = 1 - TAR = 2 - SRR0 = 3 - SRR1 = 4 - def __init__(self): - super().__init__(64, 5) - self.w_ports = {'fast1': self.write_port("dest3"), - 'fast2': self.write_port("dest4"), + 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 } - self.r_ports = {'fast1': self.read_port("src1"), + 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 @@ -108,19 +166,30 @@ class CRRegs(VirtualRegPort): * 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 @@ -131,20 +200,27 @@ class XERRegs(VirtualRegPort): 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(Memory, Elaboratable): +class SPRRegs(RegFileMem): """SPRRegs * QTY len(SPRs) 64-bit registers @@ -152,35 +228,85 @@ class SPRRegs(Memory, Elaboratable): * binary-indexed but REQUIRES MAPPING * write-through capability (read on same cycle as write) """ - def __init__(self): - n_sprs = len(SPR) - super().__init__(width=64, depth=n_sprs) - self.w_ports = {'spr1': self.write_port()} - self.r_ports = {'spr1': self.read_port()} - - # make read/write ports look like RegFileArray - self.w_ports['spr1'].wen = self.w_ports['spr1'].en - self.w_ports['spr1'].data_i = self.w_ports['spr1'].data - - self.r_ports['spr1'].ren = self.w_ports['spr1'].en - self.r_ports['spr1'].data_o = self.w_ports['spr1'].data + 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), - ('state', StateRegs), - ('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) +