81527ad5a84b285856a5a11237d443881b94c69d
[openpower-isa.git] / src / openpower / decoder / power_svp64_rm.py
1 # SPDX-License-Identifier: LGPLv3+
2 # Copyright (C) 2021 Luke Kenneth Casson Leighton <lkcl@lkcl.net>
3 # Funded by NLnet http://nlnet.nl
4 """SVP64 RM (Remap) Record.
5
6 https://libre-soc.org/openpower/sv/svp64/
7
8 | Field Name | Field bits | Description |
9 |-------------|------------|----------------------------------------|
10 | MASKMODE | `0` | Execution (predication) Mask Kind |
11 | MASK | `1:3` | Execution Mask |
12 | ELWIDTH | `4:5` | Element Width |
13 | ELWIDTH_SRC | `6:7` | Element Width for Source |
14 | SUBVL | `8:9` | Sub-vector length |
15 | EXTRA | `10:18` | context-dependent extra |
16 | MODE | `19:23` | changes Vector behaviour |
17 """
18
19 from nmigen import Elaboratable, Module, Signal, Const
20 from openpower.decoder.power_enums import (SVP64RMMode, Function, SVPtype,
21 SVP64PredMode, SVP64sat, SVP64LDSTmode,
22 SVP64BCPredMode, SVP64BCVLSETMode,
23 SVP64BCGate, SVP64BCStep,
24 )
25 from openpower.consts import EXTRA3, SVP64MODE
26 from openpower.sv.svp64 import SVP64Rec
27 from nmutil.util import sel
28
29 # a list of fields which need to be added to input records in order
30 # pass on vital information needed by each pipeline.
31 # make sure to keep these the same as SVP64RMModeDecode, in fact,
32 # TODO, make SVP64RMModeDecode *use* this as a Record!
33 sv_input_record_layout = [
34 ('sv_pred_sz', 1), # predicate source zeroing
35 ('sv_pred_dz', 1), # predicate dest zeroing
36 ('sv_saturate', SVP64sat),
37 ('sv_ldstmode', SVP64LDSTmode),
38 ('SV_Ptype', SVPtype),
39 #('sv_RC1', 1),
40 ]
41
42 """RM Mode
43 there are four Mode variants, two for LD/ST, one for Branch-Conditional,
44 and one for everything else
45 https://libre-soc.org/openpower/sv/svp64/
46 https://libre-soc.org/openpower/sv/ldst/
47 https://libre-soc.org/openpower/sv/branches/
48
49 LD/ST immed:
50 00 0 dz els normal mode (with element-stride)
51 00 1 dz rsvd bit-reversed mode
52 01 inv CR-bit Rc=1: ffirst CR sel
53 01 inv els RC1 Rc=0: ffirst z/nonz
54 10 N dz els sat mode: N=0/1 u/s
55 11 inv CR-bit Rc=1: pred-result CR sel
56 11 inv els RC1 Rc=0: pred-result z/nonz
57
58 LD/ST indexed:
59 00 0 sz dz normal mode
60 00 1 rsvd reserved
61 01 inv CR-bit Rc=1: ffirst CR sel
62 01 inv dz RC1 Rc=0: ffirst z/nonz
63 10 N sz dz sat mode: N=0/1 u/s
64 11 inv CR-bit Rc=1: pred-result CR sel
65 11 inv dz RC1 Rc=0: pred-result z/nonz
66
67 Arithmetic:
68 00 0 sz dz normal mode
69 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
70 00 1 SVM CRM subvector reduce mode, SUBVL>1
71 01 inv CR-bit Rc=1: ffirst CR sel
72 01 inv dz RC1 Rc=0: ffirst z/nonz
73 10 N sz dz sat mode: N=0/1 u/s
74 11 inv CR-bit Rc=1: pred-result CR sel
75 11 inv dz RC1 Rc=0: pred-result z/nonz
76
77 Branch Conditional:
78 note that additional BC modes are in *other bits*, specifically
79 the element-width fields: SVP64Rec.ewsrc and SVP64Rec.elwidth
80
81 elwidth ewsrc mode
82 4 5 6 7 19 20 21 22 23
83 ALL LRu / / 0 0 / SNZ sz normal mode
84 ALL LRu / VSb 0 1 VLI SNZ sz VLSET mode
85 ALL LRu BRc / 1 0 / SNZ sz svstep mode
86 ALL LRu BRc VSb 1 1 VLI SNZ sz svstep VLSET mode
87 """
88
89
90 class SVP64RMModeDecode(Elaboratable):
91 def __init__(self, name=None):
92 ##### inputs #####
93 self.rm_in = SVP64Rec(name=name)
94 self.fn_in = Signal(Function) # LD/ST and Branch is different
95 self.svp64_vf_in = Signal() # Vertical-First Mode
96 self.ptype_in = Signal(SVPtype)
97 self.rc_in = Signal()
98 self.ldst_ra_vec = Signal() # set when RA is vec, indicate Index mode
99 self.ldst_imz_in = Signal() # set when LD/ST immediate is zero
100
101 ##### outputs #####
102
103 # main mode (normal, reduce, saturate, ffirst, pred-result, branch)
104 self.mode = Signal(SVP64RMMode)
105
106 # Branch Conditional Modes
107 self.bc_vlset = Signal(SVP64BCVLSETMode) # Branch-Conditional VLSET
108 self.bc_step = Signal(SVP64BCStep) # Branch-Conditional svstep mode
109 self.bc_pred = Signal(SVP64BCPredMode) # BC predicate mode
110 self.bc_vsb = Signal() # BC VLSET-branch (like BO[1])
111 self.bc_gate = Signal(SVP64BCGate) # BC ALL or ANY gate
112 self.bc_lru = Signal() # BC Link Register Update
113
114 # predication
115 self.predmode = Signal(SVP64PredMode)
116 self.srcpred = Signal(3) # source predicate
117 self.dstpred = Signal(3) # destination predicate
118 self.pred_sz = Signal(1) # predicate source zeroing
119 self.pred_dz = Signal(1) # predicate dest zeroing
120
121 self.saturate = Signal(SVP64sat)
122 self.RC1 = Signal()
123 self.cr_sel = Signal(2) # bit of CR to test (index 0-3)
124 self.inv = Signal(1) # and whether it's inverted (like branch BO)
125 self.map_evm = Signal(1)
126 self.map_crm = Signal(1)
127 self.reverse_gear = Signal(1) # elements to go VL-1..0
128 self.ldstmode = Signal(SVP64LDSTmode) # LD/ST Mode (strided type)
129
130 def elaborate(self, platform):
131 m = Module()
132 comb = m.d.comb
133 mode = self.rm_in.mode
134
135 # decode pieces of mode
136 is_ldst = Signal()
137 is_bc = Signal()
138 comb += is_ldst.eq(self.fn_in == Function.LDST)
139 comb += is_bc.eq(self.fn_in == Function.BRANCH)
140 mode2 = sel(m, mode, SVP64MODE.MOD2)
141
142 with m.If(is_bc):
143 # Branch-Conditional is completely different
144 # svstep mode
145 with m.If(mode[SVP64MODE.BC_SVSTEP]):
146 with m.If(self.rm_in.ewsrc[0]):
147 comb += self.bc_step.eq(SVP64BCStep.STEP_RC)
148 with m.Else():
149 comb += self.bc_step.eq(SVP64BCStep.STEP)
150 # VLSET mode
151 with m.If(mode[SVP64MODE.BC_VLSET]):
152 with m.If(mode[SVP64MODE.BC_VLI]):
153 comb += self.bc_vlset.eq(SVP64BCVLSETMode.VL_INCL)
154 with m.Else():
155 comb += self.bc_vlset.eq(SVP64BCVLSETMode.VL_EXCL)
156 # BC Mode ALL or ANY (Great-Big-AND-gate or Great-Big-OR-gate)
157 comb += self.bc_gate.eq(self.rm_in.elwidth[0])
158 # Link-Register Update
159 comb += self.bc_lru.eq(self.rm_in.elwidth[1])
160 comb += self.bc_vsb.eq(self.rm_in.ewsrc[1])
161
162 with m.Else():
163 # combined arith / ldst decoding due to similarity
164 with m.Switch(mode2):
165 with m.Case(0): # needs further decoding (LDST no mapreduce)
166 with m.If(is_ldst):
167 comb += self.mode.eq(SVP64RMMode.NORMAL)
168 with m.Elif(mode[SVP64MODE.REDUCE]):
169 comb += self.mode.eq(SVP64RMMode.MAPREDUCE)
170 with m.Else():
171 comb += self.mode.eq(SVP64RMMode.NORMAL)
172 with m.Case(1):
173 comb += self.mode.eq(SVP64RMMode.FFIRST) # fail-first
174 with m.Case(2):
175 comb += self.mode.eq(SVP64RMMode.SATURATE) # saturate
176 with m.Case(3):
177 comb += self.mode.eq(SVP64RMMode.PREDRES) # pred result
178
179 # extract "reverse gear" for mapreduce mode
180 with m.If((~is_ldst) & # not for LD/ST
181 (mode2 == 0) & # first 2 bits == 0
182 mode[SVP64MODE.REDUCE] & # bit 2 == 1
183 (~mode[SVP64MODE.PARALLEL])): # not parallel mapreduce
184 comb += self.reverse_gear.eq(mode[SVP64MODE.RG]) # finally whew
185
186 # extract zeroing
187 with m.Switch(mode2):
188 with m.Case(0): # needs further decoding (LDST no mapreduce)
189 with m.If(is_ldst):
190 # XXX TODO, work out which of these is most
191 # appropriate set both? or just the one?
192 # or one if LD, the other if ST?
193 comb += self.pred_sz.eq(mode[SVP64MODE.DZ])
194 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
195 with m.Elif(mode[SVP64MODE.REDUCE]):
196 with m.If(self.rm_in.subvl == Const(0, 2)): # no SUBVL
197 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
198 with m.Else():
199 comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
200 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
201 with m.Case(1, 3):
202 with m.If(is_ldst):
203 with m.If(~self.ldst_ra_vec):
204 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
205 with m.Elif(self.rc_in):
206 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
207 with m.Case(2):
208 with m.If(is_ldst & ~self.ldst_ra_vec):
209 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
210 with m.Else():
211 comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
212 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
213
214 # extract saturate
215 with m.Switch(mode2):
216 with m.Case(2):
217 with m.If(mode[SVP64MODE.N]):
218 comb += self.saturate.eq(SVP64sat.UNSIGNED)
219 with m.Else():
220 comb += self.saturate.eq(SVP64sat.SIGNED)
221 with m.Default():
222 comb += self.saturate.eq(SVP64sat.NONE)
223
224 # extract els (element strided mode bit)
225 # see https://libre-soc.org/openpower/sv/ldst/
226 els = Signal()
227 with m.If(is_ldst):
228 with m.Switch(mode2):
229 with m.Case(0):
230 comb += els.eq(mode[SVP64MODE.ELS_NORMAL])
231 with m.Case(2):
232 comb += els.eq(mode[SVP64MODE.ELS_SAT])
233 with m.Case(1, 3):
234 with m.If(self.rc_in):
235 comb += els.eq(mode[SVP64MODE.ELS_FFIRST_PRED])
236
237 # Shifted Mode
238 with m.If(mode[SVP64MODE.LDST_SHIFT]):
239 comb += self.ldstmode.eq(SVP64LDSTmode.SHIFT)
240 # RA is vectorised
241 with m.Elif(self.ldst_ra_vec):
242 comb += self.ldstmode.eq(SVP64LDSTmode.INDEXED)
243 # not element-strided, therefore unit...
244 with m.Elif(~els):
245 comb += self.ldstmode.eq(SVP64LDSTmode.UNITSTRIDE)
246 # but if the LD/ST immediate is zero, allow cache-inhibited
247 # loads from same location, therefore don't do element-striding
248 with m.Elif(~self.ldst_imz_in):
249 comb += self.ldstmode.eq(SVP64LDSTmode.ELSTRIDE)
250
251 # extract src/dest predicate. use EXTRA3.MASK because EXTRA2.MASK
252 # is in exactly the same bits
253 srcmask = sel(m, self.rm_in.extra, EXTRA3.MASK)
254 dstmask = self.rm_in.mask
255 with m.If(self.ptype_in == SVPtype.P2):
256 comb += self.srcpred.eq(srcmask)
257 with m.Else():
258 comb += self.srcpred.eq(dstmask)
259 comb += self.dstpred.eq(dstmask)
260
261 # identify predicate mode
262 with m.If(self.rm_in.mmode == 1):
263 comb += self.predmode.eq(SVP64PredMode.CR) # CR Predicate
264 with m.Elif((self.srcpred == 0) & (self.dstpred == 0)):
265 comb += self.predmode.eq(SVP64PredMode.ALWAYS) # No predicate
266 with m.Else():
267 comb += self.predmode.eq(SVP64PredMode.INT) # non-zero src: INT
268
269 # TODO: detect zeroing mode, saturation mode, a few more.
270
271 return m
272