sve_macromem.hh revision 14091:090449e74135
1/*
2 * Copyright (c) 2018 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Giacomo Gabrielli
38 */
39
40#ifndef __ARCH_ARM_SVE_MACROMEM_HH__
41#define __ARCH_ARM_SVE_MACROMEM_HH__
42
43#include "arch/arm/generated/decoder.hh"
44#include "arch/arm/insts/pred_inst.hh"
45
46namespace ArmISA {
47
48template <typename RegElemType, typename MemElemType,
49          template <typename, typename> class MicroopType,
50          template <typename> class FirstFaultWritebackMicroopType>
51class SveIndexedMemVI : public PredMacroOp
52{
53  protected:
54    IntRegIndex dest;
55    IntRegIndex gp;
56    IntRegIndex base;
57    uint64_t imm;
58
59  public:
60    SveIndexedMemVI(const char *mnem, ExtMachInst machInst, OpClass __opClass,
61                    IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base,
62                    uint64_t _imm, bool firstFault)
63        : PredMacroOp(mnem, machInst, __opClass),
64          dest(_dest), gp(_gp), base(_base), imm(_imm)
65    {
66        bool isLoad = (__opClass == MemReadOp);
67        assert(!firstFault || isLoad);
68
69        int num_elems = ((machInst.sveLen + 1) * 16) / sizeof(RegElemType);
70
71        numMicroops = num_elems;
72        if (isLoad) {
73            if (firstFault) {
74                numMicroops += 2;
75            } else {
76                numMicroops++;
77            }
78        }
79
80        microOps = new StaticInstPtr[numMicroops];
81
82        StaticInstPtr *uop = microOps;
83
84        if (isLoad) {
85            // The first microop of a gather load copies the source vector
86            // register used for address calculation to an auxiliary register,
87            // with all subsequent microops reading from the latter.  This is
88            // needed to properly handle cases where the source vector
89            // register is the same as the destination register
90            *uop = new ArmISAInst::SveGatherLoadCpySrcVecMicroop(
91                mnem, machInst, _base, this);
92            uop++;
93        }
94
95        for (int i = 0; i < num_elems; i++, uop++) {
96            *uop = new MicroopType<RegElemType, MemElemType>(
97                mnem, machInst, __opClass, _dest, _gp,
98                isLoad ? (IntRegIndex) VECREG_UREG0 : _base, _imm, i,
99                num_elems, firstFault);
100        }
101
102        if (firstFault) {
103            *uop = new FirstFaultWritebackMicroopType<RegElemType>(
104                mnem, machInst, __opClass, num_elems, this);
105        } else {
106            --uop;
107        }
108
109        (*uop)->setLastMicroop();
110        microOps[0]->setFirstMicroop();
111
112        for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) {
113            (*uop)->setDelayedCommit();
114        }
115    }
116
117    Fault
118    execute(ExecContext *, Trace::InstRecord *) const
119    {
120        panic("Execute method called when it shouldn't!");
121        return NoFault;
122    }
123
124    std::string
125    generateDisassembly(Addr pc, const SymbolTable *symtab) const
126    {
127        // TODO: add suffix to transfer and base registers
128        std::stringstream ss;
129        printMnemonic(ss, "", false);
130        ccprintf(ss, "{");
131        printVecReg(ss, dest, true);
132        ccprintf(ss, "}, ");
133        printVecPredReg(ss, gp);
134        ccprintf(ss, "/z, [");
135        printVecReg(ss, base, true);
136        if (imm != 0) {
137            ccprintf(ss, ", #%d", imm * sizeof(MemElemType));
138        }
139        ccprintf(ss, "]");
140        return ss.str();
141    }
142};
143
144template <typename RegElemType, typename MemElemType,
145          template <typename, typename> class MicroopType,
146          template <typename> class FirstFaultWritebackMicroopType>
147class SveIndexedMemSV : public PredMacroOp
148{
149  protected:
150    IntRegIndex dest;
151    IntRegIndex gp;
152    IntRegIndex base;
153    IntRegIndex offset;
154
155    bool offsetIs32;
156    bool offsetIsSigned;
157    bool offsetIsScaled;
158
159  public:
160    SveIndexedMemSV(const char *mnem, ExtMachInst machInst, OpClass __opClass,
161                    IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base,
162                    IntRegIndex _offset, bool _offsetIs32,
163                    bool _offsetIsSigned, bool _offsetIsScaled,
164                    bool firstFault)
165        : PredMacroOp(mnem, machInst, __opClass),
166          dest(_dest), gp(_gp), base(_base), offset(_offset),
167          offsetIs32(_offsetIs32), offsetIsSigned(_offsetIsSigned),
168          offsetIsScaled(_offsetIsScaled)
169    {
170        bool isLoad = (__opClass == MemReadOp);
171        assert(!firstFault || isLoad);
172
173        int num_elems = ((machInst.sveLen + 1) * 16) / sizeof(RegElemType);
174
175        numMicroops = num_elems;
176        if (isLoad) {
177            if (firstFault) {
178                numMicroops += 2;
179            } else {
180                numMicroops++;
181            }
182        }
183
184        microOps = new StaticInstPtr[numMicroops];
185
186        StaticInstPtr *uop = microOps;
187
188        if (isLoad) {
189            // The first microop of a gather load copies the source vector
190            // register used for address calculation to an auxiliary register,
191            // with all subsequent microops reading from the latter.  This is
192            // needed to properly handle cases where the source vector
193            // register is the same as the destination register
194            *uop = new ArmISAInst::SveGatherLoadCpySrcVecMicroop(
195                mnem, machInst, _offset, this);
196            uop++;
197        }
198
199        for (int i = 0; i < num_elems; i++, uop++) {
200            *uop = new MicroopType<RegElemType, MemElemType>(
201                mnem, machInst, __opClass, _dest, _gp, _base,
202                isLoad ? (IntRegIndex) VECREG_UREG0 : _offset, _offsetIs32,
203                _offsetIsSigned, _offsetIsScaled, i, num_elems, firstFault);
204        }
205
206        if (firstFault) {
207            *uop = new FirstFaultWritebackMicroopType<RegElemType>(
208                mnem, machInst, __opClass, num_elems, this);
209        } else {
210            --uop;
211        }
212
213        (*uop)->setLastMicroop();
214        microOps[0]->setFirstMicroop();
215
216        for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) {
217            (*uop)->setDelayedCommit();
218        }
219    }
220
221    Fault
222    execute(ExecContext *, Trace::InstRecord *) const
223    {
224        panic("Execute method called when it shouldn't!");
225        return NoFault;
226    }
227
228    std::string
229    generateDisassembly(Addr pc, const SymbolTable *symtab) const
230    {
231        // TODO: add suffix to transfer and base registers
232        std::stringstream ss;
233        printMnemonic(ss, "", false);
234        ccprintf(ss, "{");
235        printVecReg(ss, dest, true);
236        ccprintf(ss, "}, ");
237        printVecPredReg(ss, gp);
238        ccprintf(ss, "/z, [");
239        printIntReg(ss, base);
240        ccprintf(ss, ", ");
241        printVecReg(ss, offset, true);
242        ccprintf(ss, "]");
243        return ss.str();
244    }
245};
246
247}  // namespace ArmISA
248
249#endif  // __ARCH_ARM_SVE_MACROMEM_HH__
250