bbe03a601290d8c7e4f8089962a9424db9b35b61
[soc.git] / src / soc / sv / svp64.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 Record, Elaboratable, Module, Signal
20 from soc.decoder.power_enums import (SVP64RMMode, Function, SVPtype,
21 SVP64PredMode, SVP64sat)
22 from soc.consts import EXTRA3
23
24 # in nMigen, Record begins at the LSB and fills upwards
25 class SVP64Rec(Record):
26 def __init__(self, name=None):
27 Record.__init__(self, layout=[("mode" , 5),
28 ("extra" , 9),
29 ("subvl" , 2),
30 ("ewsrc" , 2),
31 ("elwidth" , 2),
32 ("mask" , 3),
33 ("mmode" , 1)], name=name)
34
35 def ports(self):
36 return [self.mmode, self.mask, self.elwidth, self.ewsrc,
37 self.extra, self.mode]
38
39 """RM Mode
40
41 LD/ST immed:
42 00 str sz dz normal mode
43 01 inv CR-bit Rc=1: ffirst CR sel
44 01 inv els RC1 Rc=0: ffirst z/nonz
45 10 N sz els sat mode: N=0/1 u/s
46 11 inv CR-bit Rc=1: pred-result CR sel
47 11 inv els RC1 Rc=0: pred-result z/nonz
48
49 LD/ST indexed:
50 00 0 sz dz normal mode
51 00 rsv rsvd reserved
52 01 inv CR-bit Rc=1: ffirst CR sel
53 01 inv sz RC1 Rc=0: ffirst z/nonz
54 10 N sz dz sat mode: N=0/1 u/s
55 11 inv CR-bit Rc=1: pred-result CR sel
56 11 inv sz RC1 Rc=0: pred-result z/nonz
57
58 Arithmetic:
59 00 0 sz dz normal mode
60 00 1 sz CRM reduce mode (mapreduce), SUBVL=1
61 00 1 SVM CRM subvector reduce mode, SUBVL>1
62 01 inv CR-bit Rc=1: ffirst CR sel
63 01 inv sz RC1 Rc=0: ffirst z/nonz
64 10 N sz dz sat mode: N=0/1 u/s
65 11 inv CR-bit Rc=1: pred-result CR sel
66 11 inv sz RC1 Rc=0: pred-result z/nonz
67 """
68
69 class SVP64RMMode(Elaboratable):
70 def __init__(self, name=None):
71 self.rm_in = SVP64Rec(name=name)
72 self.fn_in = Signal(Function) # LD/ST is different
73 self.ptype_in = Signal(SVPtype)
74 self.rc_in = Signal()
75
76 # main mode (normal, reduce, saturate, ffirst, pred-result)
77 self.mode = Signal(SVP64RMMode)
78
79 # predication
80 self.predmode = Signal(SVP64PredMode)
81 self.srcpred = Signal(3) # source predicate
82 self.dstpred = Signal(3) # destination predicate
83 self.pred_sz = Signal(1) # predicate source zeroing
84 self.pred_dz = Signal(1) # predicate dest zeroing
85
86 self.saturate = Signal(SVP64sat)
87 self.RC1 = Signal()
88 self.cr_sel = Signal(2)
89 self.inv = Signal(1)
90 self.map_evm = Signal(1)
91 self.map_crm = Signal(1)
92
93 def elaborate(self, platform):
94 m = Module()
95 comb = m.d.comb
96
97 # decode pieces of mode
98 is_ldst = Signal()
99 mode2 = Signal(2)
100 comb += is_ldst.eq(self.fn_in == Function.LDST)
101 comb += mode2.eq(mode[0:2])
102 with m.Switch(mode2):
103 with m.Case(0): # needs further decoding (LDST no mapreduce)
104 with m.If(is_ldst):
105 comb += self.mode.eq(SVP64RMMode.NORMAL)
106 with m.Elif(mode[3] == 1):
107 comb += self.mode.eq(SVP64RMMode.MAPREDUCE)
108 with m.Else():
109 comb += self.mode.eq(SVP64RMMode.NORMAL)
110 with m.Case(1):
111 comb += self.mode.eq(SVP64RMMode.FFIRST) # fail-first
112 with m.Case(2):
113 comb += self.mode.eq(SVP64RMMode.SATURATE) # saturate
114 with m.Case(3):
115 comb += self.mode.eq(SVP64RMMode.PREDRES) # predicate result
116
117 # identify predicate mode
118 with m.If(self.rm_in.mmode == 1):
119 comb += self.predmode.eq(SVP64PredMode.CR) # CR Predicate
120 with m.Elif(self.srcpred == 0):
121 comb += self.predmode.eq(SVP64PredMode.ALWAYS) # No predicate
122 with m.Else():
123 comb += self.predmode.eq(SVP64PredMode.INT) # non-zero src: INT
124
125 # extract src/dest predicate. use EXTRA3.MASK because EXTRA2.MASK
126 # is in exactly the same bits
127 srcmask = sel(m, self.rm_in.extra, EXTRA3.MASK)
128 dstmask = self.rm_in.mask
129 with m.If(self.ptype_in == SVPtype.P2):
130 comb += self.srcpred.eq(srcmask)
131 comb += self.dstpred.eq(dstmask)
132
133 # TODO: detect zeroing mode, saturation mode, a few more.
134
135 return m
136