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.
6 https://libre-soc.org/openpower/sv/svp64/
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 |
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
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
),
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/
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
54 00 0 sz dz normal mode
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
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
73 class SVP64RMModeDecode(Elaboratable
):
74 def __init__(self
, name
=None):
76 self
.rm_in
= SVP64Rec(name
=name
)
77 self
.fn_in
= Signal(Function
) # LD/ST is different
78 self
.ptype_in
= Signal(SVPtype
)
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
85 # main mode (normal, reduce, saturate, ffirst, pred-result)
86 self
.mode
= Signal(SVP64RMMode
)
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
95 self
.saturate
= Signal(SVP64sat
)
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)
104 def elaborate(self
, platform
):
107 mode
= self
.rm_in
.mode
109 # decode pieces of mode
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)
116 comb
+= self
.mode
.eq(SVP64RMMode
.NORMAL
)
117 with m
.Elif(mode
[SVP64MODE
.REDUCE
]):
118 comb
+= self
.mode
.eq(SVP64RMMode
.MAPREDUCE
)
120 comb
+= self
.mode
.eq(SVP64RMMode
.NORMAL
)
122 comb
+= self
.mode
.eq(SVP64RMMode
.FFIRST
) # fail-first
124 comb
+= self
.mode
.eq(SVP64RMMode
.SATURATE
) # saturate
126 comb
+= self
.mode
.eq(SVP64RMMode
.PREDRES
) # predicate result
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
136 with m
.Switch(mode2
):
137 with m
.Case(0): # needs further decoding (LDST no mapreduce)
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
])
147 comb
+= self
.pred_sz
.eq(mode
[SVP64MODE
.SZ
])
148 comb
+= self
.pred_dz
.eq(mode
[SVP64MODE
.DZ
])
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
])
156 with m
.If(is_ldst
& ~self
.ldst_ra_vec
):
157 comb
+= self
.pred_dz
.eq(mode
[SVP64MODE
.DZ
])
159 comb
+= self
.pred_sz
.eq(mode
[SVP64MODE
.SZ
])
160 comb
+= self
.pred_dz
.eq(mode
[SVP64MODE
.DZ
])
163 with m
.Switch(mode2
):
165 with m
.If(mode
[SVP64MODE
.N
]):
166 comb
+= self
.saturate
.eq(SVP64sat
.UNSIGNED
)
168 comb
+= self
.saturate
.eq(SVP64sat
.SIGNED
)
170 comb
+= self
.saturate
.eq(SVP64sat
.NONE
)
172 # extract els (element strided mode bit)
173 # see https://libre-soc.org/openpower/sv/ldst/
176 with m
.Switch(mode2
):
178 comb
+= els
.eq(mode
[SVP64MODE
.ELS_NORMAL
])
180 comb
+= els
.eq(mode
[SVP64MODE
.ELS_SAT
])
182 with m
.If(self
.rc_in
):
183 comb
+= els
.eq(mode
[SVP64MODE
.ELS_FFIRST_PRED
])
186 with m
.If(mode
[SVP64MODE
.LDST_BITREV
]):
187 comb
+= self
.ldstmode
.eq(SVP64LDSTmode
.BITREVERSE
)
189 with m
.Elif(self
.ldst_ra_vec
):
190 comb
+= self
.ldstmode
.eq(SVP64LDSTmode
.INDEXED
)
191 # not element-strided, therefore unit...
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
)
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
)
206 comb
+= self
.srcpred
.eq(dstmask
)
207 comb
+= self
.dstpred
.eq(dstmask
)
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
215 comb
+= self
.predmode
.eq(SVP64PredMode
.INT
) # non-zero src: INT
217 # TODO: detect zeroing mode, saturation mode, a few more.