format code
[openpower-isa.git] / src / openpower / decoder / power_svp64_extra.py
1 """SVP64 EXTRA field decoder
2 """
3
4 from nmigen import Module, Elaboratable, Signal, Mux, Const, Cat
5 from nmigen.cli import rtlil
6 from nmutil.util import sel
7
8
9 from openpower.decoder.power_enums import (SVEXTRA, SVEType)
10 from openpower.consts import (SPEC, EXTRA2, EXTRA3, SVP64P, field,
11 SPEC_SIZE, SPECb, SPEC_AUG_SIZE, SVP64CROffs)
12
13
14 class SVP64ExtraSpec(Elaboratable):
15 """SVP64ExtraSpec - decodes SVP64 Extra specification.
16
17 selects the required EXTRA2/3 field.
18
19 see https://libre-soc.org/openpower/sv/svp64/
20 """
21
22 def __init__(self):
23 self.extra = Signal(9, reset_less=True)
24 self.etype = Signal(SVEType, reset_less=True) # 2 or 3 bits
25 self.idx = Signal(SVEXTRA, reset_less=True) # which part of extra
26 self.spec = Signal(3) # EXTRA spec for the register
27
28 def elaborate(self, platform):
29 m = Module()
30 comb = m.d.comb
31 spec = self.spec
32 extra = self.extra
33
34 # back in the LDSTRM-* and RM-* files generated by sv_analysis.py
35 # we marked every op with an Etype: EXTRA2 or EXTRA3, and also said
36 # which of the 4 (or 3 for EXTRA3) sub-fields of bits 10:18 contain
37 # the register-extension information. extract those now
38 with m.Switch(self.etype):
39 # 2-bit index selection mode
40 with m.Case(SVEType.EXTRA2):
41 with m.Switch(self.idx):
42 with m.Case(SVEXTRA.Idx0): # 1st 2 bits [0:1]
43 comb += spec[SPEC.VEC].eq(extra[EXTRA2.IDX0_VEC])
44 comb += spec[SPEC.MSB].eq(extra[EXTRA2.IDX0_MSB])
45 with m.Case(SVEXTRA.Idx1): # 2nd 2 bits [2:3]
46 comb += spec[SPEC.VEC].eq(extra[EXTRA2.IDX1_VEC])
47 comb += spec[SPEC.MSB].eq(extra[EXTRA2.IDX1_MSB])
48 with m.Case(SVEXTRA.Idx2): # 3rd 2 bits [4:5]
49 comb += spec[SPEC.VEC].eq(extra[EXTRA2.IDX2_VEC])
50 comb += spec[SPEC.MSB].eq(extra[EXTRA2.IDX2_MSB])
51 with m.Case(SVEXTRA.Idx3): # 4th 2 bits [6:7]
52 comb += spec[SPEC.VEC].eq(extra[EXTRA2.IDX3_VEC])
53 comb += spec[SPEC.MSB].eq(extra[EXTRA2.IDX3_MSB])
54 # 3-bit index selection mode
55 with m.Case(SVEType.EXTRA3):
56 with m.Switch(self.idx):
57 with m.Case(SVEXTRA.Idx0): # 1st 3 bits [0:2]
58 extra3_idx0 = sel(m, extra, EXTRA3.IDX0)
59 comb += spec.eq(extra3_idx0)
60 with m.Case(SVEXTRA.Idx1): # 2nd 3 bits [3:5]
61 extra3_idx1 = sel(m, extra, EXTRA3.IDX1)
62 comb += spec.eq(extra3_idx1)
63 with m.Case(SVEXTRA.Idx2): # 3rd 3 bits [6:8]
64 extra3_idx2 = sel(m, extra, EXTRA3.IDX2)
65 comb += spec.eq(extra3_idx2)
66 # cannot fit more than 9 bits so there is no 4th thing
67
68 return m
69
70
71 class SVP64RegExtra(SVP64ExtraSpec):
72 """SVP64RegExtra - decodes SVP64 Extra fields to determine reg extension
73
74 incoming 5-bit GPR/FP is turned into a 7-bit and marked as scalar/vector
75 depending on info in one of the positions in the EXTRA field.
76
77 designed so that "no change" to the 5-bit register number occurs if
78 SV either does not apply or the relevant EXTRA2/3 field bits are zero.
79
80 see https://libre-soc.org/openpower/sv/svp64/
81 """
82
83 def __init__(self):
84 SVP64ExtraSpec.__init__(self)
85 self.reg_in = Signal(5) # incoming reg number (5 bits, RA, RB)
86 self.reg_out = Signal(7) # extra-augmented output (7 bits)
87 self.isvec = Signal(1) # reg is marked as vector if true
88
89 def elaborate(self, platform):
90 m = super().elaborate(platform) # select required EXTRA2/3
91 comb = m.d.comb
92
93 # first get the spec. if not changed it's "scalar identity behaviour"
94 # which is zero which is ok.
95 spec = self.spec
96
97 # now decode it. bit 0 is "scalar/vector". note that spec could be zero
98 # from above, which (by design) has the effect of "no change", below.
99
100 # simple: isvec is top bit of spec
101 comb += self.isvec.eq(spec[SPEC.VEC])
102 # extra bits for register number augmentation
103 spec_aug = Signal(SPEC_AUG_SIZE)
104 comb += spec_aug.eq(field(spec, SPECb.MSB, SPECb.LSB, SPEC_SIZE))
105
106 # decode vector differently from scalar
107 with m.If(self.isvec):
108 # Vector: shifted up, extra in LSBs (RA << 2) | spec[1:2]
109 comb += self.reg_out.eq(Cat(spec_aug, self.reg_in))
110 with m.Else():
111 # Scalar: not shifted up, extra in MSBs RA | (spec[1:2] << 5)
112 comb += self.reg_out.eq(Cat(self.reg_in, spec_aug))
113
114 return m
115
116
117 class SVP64CRExtra(SVP64ExtraSpec):
118 """SVP64CRExtra - decodes SVP64 Extra fields to determine CR extension
119
120 incoming 3-bit CR is turned into a 7-bit and marked as scalar/vector
121 depending on info in one of the positions in the EXTRA field.
122
123 yes, really, 128 CRs. INT is 128, FP is 128, therefore CRs are 128.
124
125 designed so that "no change" to the 3-bit CR register number occurs if
126 SV either does not apply or the relevant EXTRA2/3 field bits are zero.
127
128 see https://libre-soc.org/openpower/sv/svp64/appendix
129 """
130
131 def __init__(self):
132 SVP64ExtraSpec.__init__(self)
133 self.cr_in = Signal(3) # incoming CR number (3 bits, BA[0:2], BFA)
134 self.cr_out = Signal(7) # extra-augmented CR output (7 bits)
135 self.isvec = Signal(1) # reg is marked as vector if true
136
137 def elaborate(self, platform):
138 m = super().elaborate(platform) # select required EXTRA2/3
139 comb = m.d.comb
140
141 # first get the spec. if not changed it's "scalar identity behaviour"
142 # which is zero which is ok.
143 spec = self.spec
144
145 # now decode it. bit 0 is "scalar/vector". note that spec could be zero
146 # from above, which (by design) has the effect of "no change", below.
147
148 # simple: isvec is top bit of spec
149 comb += self.isvec.eq(spec[SPEC.VEC])
150 # extra bits for register number augmentation
151 spec_aug = Signal(SPEC_AUG_SIZE)
152 comb += spec_aug.eq(field(spec, SPECb.MSB, SPECb.LSB, SPEC_SIZE))
153
154 # decode vector differently from scalar, insert bits 1 and 2 accordingly
155 with m.If(self.isvec):
156 # Vector: shifted up, extra in LSBs (CR << 4) | (spec[1:2] << 2)
157 comb += self.cr_out.eq(Cat(Const(0, 2), spec_aug, self.cr_in))
158 with m.Else():
159 # Scalar: not shifted up, extra in MSBs CR | (spec[1:2] << 3)
160 comb += self.cr_out.eq(Cat(self.cr_in, spec_aug))
161
162 return m
163
164
165 if __name__ == '__main__':
166 pdecode = create_pdecode()
167 dec2 = PowerDecode2(pdecode)
168 vl = rtlil.convert(dec2, ports=dec2.ports() + pdecode.ports())
169 with open("dec2.il", "w") as f:
170 f.write(vl)