move SVP64 RM mode decoder into PowerDecodeSubset
[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)
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_Ptype', SVPtype),
35 #('sv_RC1', 1),
36 ]
37
38 """RM Mode
39 there are three Mode variants, two for LD/ST and one for everything else
40 https://libre-soc.org/openpower/sv/svp64/
41 https://libre-soc.org/openpower/sv/ldst/
42
43 LD/ST immed:
44 00 str sz dz normal mode
45 01 inv CR-bit Rc=1: ffirst CR sel
46 01 inv els RC1 Rc=0: ffirst z/nonz
47 10 N dz els sat mode: N=0/1 u/s
48 11 inv CR-bit Rc=1: pred-result CR sel
49 11 inv els RC1 Rc=0: pred-result z/nonz
50
51 LD/ST indexed:
52 00 0 sz dz normal mode
53 00 1 rsvd reserved
54 01 inv CR-bit Rc=1: ffirst CR sel
55 01 inv dz RC1 Rc=0: ffirst z/nonz
56 10 N sz dz sat mode: N=0/1 u/s
57 11 inv CR-bit Rc=1: pred-result CR sel
58 11 inv dz RC1 Rc=0: pred-result z/nonz
59
60 Arithmetic:
61 00 0 sz dz normal mode
62 00 1 dz CRM reduce mode (mapreduce), SUBVL=1
63 00 1 SVM CRM subvector reduce mode, SUBVL>1
64 01 inv CR-bit Rc=1: ffirst CR sel
65 01 inv dz RC1 Rc=0: ffirst z/nonz
66 10 N sz dz sat mode: N=0/1 u/s
67 11 inv CR-bit Rc=1: pred-result CR sel
68 11 inv dz RC1 Rc=0: pred-result z/nonz
69 """
70
71 class SVP64RMModeDecode(Elaboratable):
72 def __init__(self, name=None):
73 self.rm_in = SVP64Rec(name=name)
74 self.fn_in = Signal(Function) # LD/ST is different
75 self.ptype_in = Signal(SVPtype)
76 self.rc_in = Signal()
77 self.ldst_idx = Signal()
78
79 # main mode (normal, reduce, saturate, ffirst, pred-result)
80 self.mode = Signal(SVP64RMMode)
81
82 # predication
83 self.predmode = Signal(SVP64PredMode)
84 self.srcpred = Signal(3) # source predicate
85 self.dstpred = Signal(3) # destination predicate
86 self.pred_sz = Signal(1) # predicate source zeroing
87 self.pred_dz = Signal(1) # predicate dest zeroing
88
89 self.saturate = Signal(SVP64sat)
90 self.RC1 = Signal()
91 self.cr_sel = Signal(2)
92 self.inv = Signal(1)
93 self.map_evm = Signal(1)
94 self.map_crm = Signal(1)
95
96 def elaborate(self, platform):
97 m = Module()
98 comb = m.d.comb
99 mode = self.rm_in.mode
100
101 # decode pieces of mode
102 is_ldst = Signal()
103 comb += is_ldst.eq(self.fn_in == Function.LDST)
104 mode2 = sel(m, mode, SVP64MODE.MOD2)
105 with m.Switch(mode2):
106 with m.Case(0): # needs further decoding (LDST no mapreduce)
107 with m.If(is_ldst):
108 comb += self.mode.eq(SVP64RMMode.NORMAL)
109 with m.Elif(mode[SVP64MODE.REDUCE]):
110 comb += self.mode.eq(SVP64RMMode.MAPREDUCE)
111 with m.Else():
112 comb += self.mode.eq(SVP64RMMode.NORMAL)
113 with m.Case(1):
114 comb += self.mode.eq(SVP64RMMode.FFIRST) # fail-first
115 with m.Case(2):
116 comb += self.mode.eq(SVP64RMMode.SATURATE) # saturate
117 with m.Case(3):
118 comb += self.mode.eq(SVP64RMMode.PREDRES) # predicate result
119
120 # extract zeroing
121 with m.Switch(mode2):
122 with m.Case(0): # needs further decoding (LDST no mapreduce)
123 with m.If(is_ldst):
124 comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
125 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
126 with m.Elif(mode[SVP64MODE.REDUCE]):
127 with m.If(self.rm_in.subvl == Const(0, 2)): # no SUBVL
128 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
129 with m.Else():
130 comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
131 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
132 with m.Case(1, 3):
133 with m.If(is_ldst):
134 with m.If(~self.ldst_idx):
135 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
136 with m.Elif(self.rc_in):
137 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
138 with m.Case(2):
139 with m.If(is_ldst & ~self.ldst_idx):
140 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
141 with m.Else():
142 comb += self.pred_sz.eq(mode[SVP64MODE.SZ])
143 comb += self.pred_dz.eq(mode[SVP64MODE.DZ])
144
145 # extract src/dest predicate. use EXTRA3.MASK because EXTRA2.MASK
146 # is in exactly the same bits
147 srcmask = sel(m, self.rm_in.extra, EXTRA3.MASK)
148 dstmask = self.rm_in.mask
149 with m.If(self.ptype_in == SVPtype.P2):
150 comb += self.srcpred.eq(srcmask)
151 with m.Else():
152 comb += self.srcpred.eq(dstmask)
153 comb += self.dstpred.eq(dstmask)
154
155 # identify predicate mode
156 with m.If(self.rm_in.mmode == 1):
157 comb += self.predmode.eq(SVP64PredMode.CR) # CR Predicate
158 with m.Elif((self.srcpred == 0) & (self.dstpred == 0)):
159 comb += self.predmode.eq(SVP64PredMode.ALWAYS) # No predicate
160 with m.Else():
161 comb += self.predmode.eq(SVP64PredMode.INT) # non-zero src: INT
162
163 # TODO: detect zeroing mode, saturation mode, a few more.
164
165 return m
166