"""SVP64 EXTRA field decoder """ from nmigen import Module, Elaboratable, Signal, Mux, Const, Cat from nmigen.cli import rtlil from nmutil.util import sel from soc.decoder.power_enums import (SVEXTRA, SVEtype) from soc.consts import (SPEC, EXTRA2, EXTRA3, SVP64P, field, SPEC_SIZE, SPECb, SPEC_AUG_SIZE, SVP64CROffs) class SVP64ExtraSpec(Elaboratable): """SVP64ExtraSpec - decodes SVP64 Extra specification. selects the required EXTRA2/3 field. see https://libre-soc.org/openpower/sv/svp64/ """ def __init__(self): self.extra = Signal(9, reset_less=True) self.etype = Signal(SVEtype, reset_less=True) # 2 or 3 bits self.idx = Signal(SVEXTRA, reset_less=True) # which part of extra self.spec = Signal(3) # EXTRA spec for the register def elaborate(self, platform): m = Module() comb = m.d.comb spec = self.spec extra = self.extra # back in the LDSTRM-* and RM-* files generated by sv_analysis.py # we marked every op with an Etype: EXTRA2 or EXTRA3, and also said # which of the 4 (or 3 for EXTRA3) sub-fields of bits 10:18 contain # the register-extension information. extract those now with m.Switch(self.etype): # 2-bit index selection mode with m.Case(SVEtype.EXTRA2): with m.Switch(self.idx): with m.Case(SVEXTRA.Idx0): # 1st 2 bits [0:1] comb += spec[SPEC.VEC].eq(extra[EXTRA2.IDX0_VEC]) comb += spec[SPEC.MSB].eq(extra[EXTRA2.IDX0_MSB]) with m.Case(SVEXTRA.Idx1): # 2nd 2 bits [2:3] comb += spec[SPEC.VEC].eq(extra[EXTRA2.IDX1_VEC]) comb += spec[SPEC.MSB].eq(extra[EXTRA2.IDX1_MSB]) with m.Case(SVEXTRA.Idx2): # 3rd 2 bits [4:5] comb += spec[SPEC.VEC].eq(extra[EXTRA2.IDX2_VEC]) comb += spec[SPEC.MSB].eq(extra[EXTRA2.IDX2_MSB]) with m.Case(SVEXTRA.Idx3): # 4th 2 bits [6:7] comb += spec[SPEC.VEC].eq(extra[EXTRA2.IDX3_VEC]) comb += spec[SPEC.MSB].eq(extra[EXTRA2.IDX3_MSB]) # 3-bit index selection mode with m.Case(SVEtype.EXTRA3): with m.Switch(self.idx): with m.Case(SVEXTRA.Idx0): # 1st 3 bits [0:2] extra3_idx0 = sel(m, extra, EXTRA3.IDX0) comb += spec.eq(extra3_idx0) with m.Case(SVEXTRA.Idx1): # 2nd 3 bits [3:5] extra3_idx1 = sel(m, extra, EXTRA3.IDX1) comb += spec.eq(extra3_idx1) with m.Case(SVEXTRA.Idx2): # 3rd 3 bits [6:8] extra3_idx2 = sel(m, extra, EXTRA3.IDX2) comb += spec.eq(extra3_idx2) # cannot fit more than 9 bits so there is no 4th thing return m class SVP64RegExtra(SVP64ExtraSpec): """SVP64RegExtra - decodes SVP64 Extra fields to determine reg extension incoming 5-bit GPR/FP is turned into a 7-bit and marked as scalar/vector depending on info in one of the positions in the EXTRA field. designed so that "no change" to the 5-bit register number occurs if SV either does not apply or the relevant EXTRA2/3 field bits are zero. see https://libre-soc.org/openpower/sv/svp64/ """ def __init__(self): SVP64ExtraSpec.__init__(self) self.reg_in = Signal(5) # incoming reg number (5 bits, RA, RB) self.reg_out = Signal(7) # extra-augmented output (7 bits) self.isvec = Signal(1) # reg is marked as vector if true def elaborate(self, platform): m = super().elaborate(platform) # select required EXTRA2/3 comb = m.d.comb # first get the spec. if not changed it's "scalar identity behaviour" # which is zero which is ok. spec = self.spec # now decode it. bit 0 is "scalar/vector". note that spec could be zero # from above, which (by design) has the effect of "no change", below. # simple: isvec is top bit of spec comb += self.isvec.eq(spec[SPEC.VEC]) # extra bits for register number augmentation spec_aug = Signal(SPEC_AUG_SIZE) comb += spec_aug.eq(field(spec, SPECb.MSB, SPECb.LSB, SPEC_SIZE)) # decode vector differently from scalar with m.If(self.isvec): # Vector: shifted up, extra in LSBs (RA << 2) | spec[1:2] comb += self.reg_out.eq(Cat(spec_aug, self.reg_in)) with m.Else(): # Scalar: not shifted up, extra in MSBs RA | (spec[1:2] << 5) comb += self.reg_out.eq(Cat(self.reg_in, spec_aug)) return m class SVP64CRExtra(SVP64ExtraSpec): """SVP64CRExtra - decodes SVP64 Extra fields to determine CR extension incoming 3-bit CR is turned into a 7-bit and marked as scalar/vector depending on info in one of the positions in the EXTRA field. yes, really, 128 CRs. INT is 128, FP is 128, therefore CRs are 128. designed so that "no change" to the 3-bit CR register number occurs if SV either does not apply or the relevant EXTRA2/3 field bits are zero. see https://libre-soc.org/openpower/sv/svp64/appendix """ def __init__(self): SVP64ExtraSpec.__init__(self) self.cr_in = Signal(3) # incoming CR number (3 bits, BA[0:2], BFA) self.cr_out = Signal(7) # extra-augmented CR output (7 bits) self.isvec = Signal(1) # reg is marked as vector if true def elaborate(self, platform): m = super().elaborate(platform) # select required EXTRA2/3 comb = m.d.comb # first get the spec. if not changed it's "scalar identity behaviour" # which is zero which is ok. spec = self.spec # now decode it. bit 0 is "scalar/vector". note that spec could be zero # from above, which (by design) has the effect of "no change", below. # simple: isvec is top bit of spec comb += self.isvec.eq(spec[SPEC.VEC]) # extra bits for register number augmentation spec_aug = Signal(SPEC_AUG_SIZE) comb += spec_aug.eq(field(spec, SPECb.MSB, SPECb.LSB, SPEC_SIZE)) # decode vector differently from scalar, insert bits 1 and 2 accordingly with m.If(self.isvec): # Vector: shifted up, extra in LSBs (CR << 4) | (spec[1:2] << 2) comb += self.cr_out.eq(Cat(Const(0, 2), spec_aug, self.cr_in)) with m.Else(): # Scalar: not shifted up, extra in MSBs CR | (spec[1:2] << 3) comb += self.cr_out.eq(Cat(self.cr_in, spec_aug)) return m if __name__ == '__main__': pdecode = create_pdecode() dec2 = PowerDecode2(pdecode) vl = rtlil.convert(dec2, ports=dec2.ports() + pdecode.ports()) with open("dec2.il", "w") as f: f.write(vl)