split out 2nd dct outer butterfly scheduler
[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 from openpower.consts import EXTRA3, SVP64MODE
23 from openpower.sv.svp64 import SVP64Rec
24 from nmutil.util import sel
25
26 # a list of fields which need to be added to input records in order
27 # pass on vital information needed by each pipeline.
28 # make sure to keep these the same as SVP64RMModeDecode, in fact,
29 # TODO, make SVP64RMModeDecode *use* this as a Record!
30 sv_input_record_layout = [
31 ('sv_pred_sz', 1), # predicate source zeroing
32 ('sv_pred_dz', 1), # predicate dest zeroing
33 ('sv_saturate', SVP64sat),
34 ('sv_ldstmode', SVP64LDSTmode),
35 ('SV_Ptype', SVPtype),
36 #('sv_RC1', 1),
37 ]
38
39 """RM Mode
40 there are three Mode variants, two for LD/ST and one for everything else
41 https://libre-soc.org/openpower/sv/svp64/
42 https://libre-soc.org/openpower/sv/ldst/
43
44 LD/ST immed:
45 00 0 dz els normal mode (with element-stride)
46 00 1 dz rsvd bit-reversed mode
47 01 inv CR-bit Rc=1: ffirst CR sel
48 01 inv els RC1 Rc=0: ffirst z/nonz
49 10 N dz els sat mode: N=0/1 u/s
50 11 inv CR-bit Rc=1: pred-result CR sel
51 11 inv els RC1 Rc=0: pred-result z/nonz
52
53 LD/ST indexed:
54 00 0 sz dz normal mode
55 00 1 rsvd reserved
56 01 inv CR-bit Rc=1: ffirst CR sel
57 01 inv dz RC1 Rc=0: ffirst z/nonz
58 10 N sz dz sat mode: N=0/1 u/s
59 11 inv CR-bit Rc=1: pred-result CR sel
60 11 inv dz RC1 Rc=0: pred-result z/nonz
61
62 Arithmetic:
63 00 0 sz dz normal mode
64 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
65 00 1 SVM CRM subvector reduce mode, SUBVL>1
66 01 inv CR-bit Rc=1: ffirst CR sel
67 01 inv dz RC1 Rc=0: ffirst z/nonz
68 10 N sz dz sat mode: N=0/1 u/s
69 11 inv CR-bit Rc=1: pred-result CR sel
70 11 inv dz RC1 Rc=0: pred-result z/nonz
71 """
72
73 class SVP64RMModeDecode(Elaboratable):
74 def __init__(self, name=None):
75 ##### inputs #####
76 self.rm_in = SVP64Rec(name=name)
77 self.fn_in = Signal(Function) # LD/ST is different
78 self.ptype_in = Signal(SVPtype)
79 self.rc_in = Signal()
80 self.ldst_ra_vec = Signal() # set when RA is vec, indicate Index mode
81 self.ldst_imz_in = Signal() # set when LD/ST immediate is zero
82
83 ##### outputs #####
84
85 # main mode (normal, reduce, saturate, ffirst, pred-result)
86 self.mode = Signal(SVP64RMMode)
87
88 # predication
89 self.predmode = Signal(SVP64PredMode)
90 self.srcpred = Signal(3) # source predicate
91 self.dstpred = Signal(3) # destination predicate
92 self.pred_sz = Signal(1) # predicate source zeroing
93 self.pred_dz = Signal(1) # predicate dest zeroing
94
95 self.saturate = Signal(SVP64sat)
96 self.RC1 = Signal()
97 self.cr_sel = Signal(2) # bit of CR to test (index 0-3)
98 self.inv = Signal(1) # and whether it's inverted (like branch BO)
99 self.map_evm = Signal(1)
100 self.map_crm = Signal(1)
101 self.reverse_gear = Signal(1) # elements to go VL-1..0
102 self.ldstmode = Signal(SVP64LDSTmode) # LD/ST Mode (strided type)
103
104 def elaborate(self, platform):
105 m = Module()
106 comb = m.d.comb
107 mode = self.rm_in.mode
108
109 # decode pieces of mode
110 is_ldst = Signal()
111 comb += is_ldst.eq(self.fn_in == Function.LDST)
112 mode2 = sel(m, mode, SVP64MODE.MOD2)
113 with m.Switch(mode2):
114 with m.Case(0): # needs further decoding (LDST no mapreduce)
115 with m.If(is_ldst):
116 comb += self.mode.eq(SVP64RMMode.NORMAL)
117 with m.Elif(mode[SVP64MODE.REDUCE]):
118 comb += self.mode.eq(SVP64RMMode.MAPREDUCE)
119 with m.Else():
120 comb += self.mode.eq(SVP64RMMode.NORMAL)
121 with m.Case(1):
122 comb += self.mode.eq(SVP64RMMode.FFIRST) # fail-first
123 with m.Case(2):
124 comb += self.mode.eq(SVP64RMMode.SATURATE) # saturate
125 with m.Case(3):
126 comb += self.mode.eq(SVP64RMMode.PREDRES) # predicate result
127
128 # extract "reverse gear" for mapreduce mode
129 with m.If((~is_ldst) & # not for LD/ST
130 (mode2 == 0) & # first 2 bits == 0
131 mode[SVP64MODE.REDUCE] & # bit 2 == 1
132 (~mode[SVP64MODE.PARALLEL])): # not parallel mapreduce
133 comb += self.reverse_gear.eq(mode[SVP64MODE.RG]) # finally, whew
134
135 # extract zeroing
136 with m.Switch(mode2):
137 with m.Case(0): # needs further decoding (LDST no mapreduce)
138 with m.If(is_ldst):
139 # XXX TODO, work out which of these is most appropriate
140 # set both? or just the one? or one if LD, the other if ST?
141 comb += self.pred_sz.eq(mode[SVP64MODE.DZ])
142 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
143 with m.Elif(mode[SVP64MODE.REDUCE]):
144 with m.If(self.rm_in.subvl == Const(0, 2)): # no SUBVL
145 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
146 with m.Else():
147 comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
148 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
149 with m.Case(1, 3):
150 with m.If(is_ldst):
151 with m.If(~self.ldst_ra_vec):
152 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
153 with m.Elif(self.rc_in):
154 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
155 with m.Case(2):
156 with m.If(is_ldst & ~self.ldst_ra_vec):
157 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
158 with m.Else():
159 comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
160 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
161
162 # extract saturate
163 with m.Switch(mode2):
164 with m.Case(2):
165 with m.If(mode[SVP64MODE.N]):
166 comb += self.saturate.eq(SVP64sat.UNSIGNED)
167 with m.Else():
168 comb += self.saturate.eq(SVP64sat.SIGNED)
169 with m.Default():
170 comb += self.saturate.eq(SVP64sat.NONE)
171
172 # extract els (element strided mode bit)
173 # see https://libre-soc.org/openpower/sv/ldst/
174 els = Signal()
175 with m.If(is_ldst):
176 with m.Switch(mode2):
177 with m.Case(0):
178 comb += els.eq(mode[SVP64MODE.ELS_NORMAL])
179 with m.Case(2):
180 comb += els.eq(mode[SVP64MODE.ELS_SAT])
181 with m.Case(1, 3):
182 with m.If(self.rc_in):
183 comb += els.eq(mode[SVP64MODE.ELS_FFIRST_PRED])
184
185 # Bit-reversed Mode
186 with m.If(mode[SVP64MODE.LDST_BITREV]):
187 comb += self.ldstmode.eq(SVP64LDSTmode.BITREVERSE)
188 # RA is vectorised
189 with m.Elif(self.ldst_ra_vec):
190 comb += self.ldstmode.eq(SVP64LDSTmode.INDEXED)
191 # not element-strided, therefore unit...
192 with m.Elif(~els):
193 comb += self.ldstmode.eq(SVP64LDSTmode.UNITSTRIDE)
194 # but if the LD/ST immediate is zero, allow cache-inhibited
195 # loads from same location, therefore don't do element-striding
196 with m.Elif(~self.ldst_imz_in):
197 comb += self.ldstmode.eq(SVP64LDSTmode.ELSTRIDE)
198
199 # extract src/dest predicate. use EXTRA3.MASK because EXTRA2.MASK
200 # is in exactly the same bits
201 srcmask = sel(m, self.rm_in.extra, EXTRA3.MASK)
202 dstmask = self.rm_in.mask
203 with m.If(self.ptype_in == SVPtype.P2):
204 comb += self.srcpred.eq(srcmask)
205 with m.Else():
206 comb += self.srcpred.eq(dstmask)
207 comb += self.dstpred.eq(dstmask)
208
209 # identify predicate mode
210 with m.If(self.rm_in.mmode == 1):
211 comb += self.predmode.eq(SVP64PredMode.CR) # CR Predicate
212 with m.Elif((self.srcpred == 0) & (self.dstpred == 0)):
213 comb += self.predmode.eq(SVP64PredMode.ALWAYS) # No predicate
214 with m.Else():
215 comb += self.predmode.eq(SVP64PredMode.INT) # non-zero src: INT
216
217 # TODO: detect zeroing mode, saturation mode, a few more.
218
219 return m
220