2 * Copyright (c) 2018 ARM Limited
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.
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.
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.
38 #ifndef __ARCH_ARM_SVE_MACROMEM_HH__
39 #define __ARCH_ARM_SVE_MACROMEM_HH__
41 #include "arch/arm/generated/decoder.hh"
42 #include "arch/arm/insts/pred_inst.hh"
46 template <typename Element,
47 template <typename> class MicroopLdMemType,
48 template <typename> class MicroopDeIntrlvType>
49 class SveLdStructSS : public PredMacroOp
59 SveLdStructSS(const char* mnem, ExtMachInst machInst, OpClass __opClass,
60 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base,
61 IntRegIndex _offset, uint8_t _numregs)
62 : PredMacroOp(mnem, machInst, __opClass),
63 dest(_dest), gp(_gp), base(_base), offset(_offset), numregs(_numregs)
65 numMicroops = numregs * 2;
67 microOps = new StaticInstPtr[numMicroops];
69 for (int i = 0; i < numregs; ++i) {
70 microOps[i] = new MicroopLdMemType<Element>(
71 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i),
72 _gp, _base, _offset, _numregs, i);
74 for (int i = 0; i < numregs; ++i) {
75 microOps[i + numregs] = new MicroopDeIntrlvType<Element>(
76 mnem, machInst, static_cast<IntRegIndex>((_dest + i) % 32),
80 microOps[0]->setFirstMicroop();
81 microOps[numMicroops - 1]->setLastMicroop();
83 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) {
84 (*uop)->setDelayedCommit();
89 execute(ExecContext *, Trace::InstRecord *) const
91 panic("Execute method called when it shouldn't!");
96 generateDisassembly(Addr pc, const SymbolTable *symtab) const
99 printMnemonic(ss, "", false);
101 for (int i = 0; i < numregs; ++i) {
102 printVecReg(ss, (dest + i) % 32, true);
107 printVecPredReg(ss, gp);
108 ccprintf(ss, "/z, [");
109 printIntReg(ss, base);
111 printIntReg(ss, offset);
117 template <typename Element,
118 template <typename> class MicroopStMemType,
119 template <typename> class MicroopIntrlvType>
120 class SveStStructSS : public PredMacroOp
130 SveStStructSS(const char* mnem, ExtMachInst machInst, OpClass __opClass,
131 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base,
132 IntRegIndex _offset, uint8_t _numregs)
133 : PredMacroOp(mnem, machInst, __opClass),
134 dest(_dest), gp(_gp), base(_base), offset(_offset), numregs(_numregs)
136 numMicroops = numregs * 2;
138 microOps = new StaticInstPtr[numMicroops];
140 for (int i = 0; i < numregs; ++i) {
141 microOps[i] = new MicroopIntrlvType<Element>(
142 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i),
143 _dest, _numregs, i, this);
146 for (int i = 0; i < numregs; ++i) {
147 microOps[i + numregs] = new MicroopStMemType<Element>(
148 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i),
149 _gp, _base, _offset, _numregs, i);
152 microOps[0]->setFirstMicroop();
153 microOps[numMicroops - 1]->setLastMicroop();
155 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) {
156 (*uop)->setDelayedCommit();
161 execute(ExecContext *, Trace::InstRecord *) const
163 panic("Execute method called when it shouldn't!");
168 generateDisassembly(Addr pc, const SymbolTable *symtab) const
170 std::stringstream ss;
171 printMnemonic(ss, "", false);
173 for (int i = 0; i < numregs; ++i) {
174 printVecReg(ss, (dest + i) % 32, true);
179 printVecPredReg(ss, gp);
181 printIntReg(ss, base);
183 printIntReg(ss, offset);
190 template <typename Element,
191 template <typename> class MicroopLdMemType,
192 template <typename> class MicroopDeIntrlvType>
193 class SveLdStructSI : public PredMacroOp
203 SveLdStructSI(const char* mnem, ExtMachInst machInst, OpClass __opClass,
204 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base,
205 int64_t _imm, uint8_t _numregs)
206 : PredMacroOp(mnem, machInst, __opClass),
207 dest(_dest), gp(_gp), base(_base), imm(_imm), numregs(_numregs)
209 numMicroops = numregs * 2;
211 microOps = new StaticInstPtr[numMicroops];
213 for (int i = 0; i < numregs; ++i) {
214 microOps[i] = new MicroopLdMemType<Element>(
215 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i),
216 _gp, _base, _imm, _numregs, i);
218 for (int i = 0; i < numregs; ++i) {
219 microOps[i + numregs] = new MicroopDeIntrlvType<Element>(
220 mnem, machInst, static_cast<IntRegIndex>((_dest + i) % 32),
224 microOps[0]->setFirstMicroop();
225 microOps[numMicroops - 1]->setLastMicroop();
227 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) {
228 (*uop)->setDelayedCommit();
233 execute(ExecContext *, Trace::InstRecord *) const
235 panic("Execute method called when it shouldn't!");
240 generateDisassembly(Addr pc, const SymbolTable *symtab) const
242 std::stringstream ss;
243 printMnemonic(ss, "", false);
245 for (int i = 0; i < numregs; ++i) {
246 printVecReg(ss, (dest + i) % 32, true);
251 printVecPredReg(ss, gp);
252 ccprintf(ss, "/z, [");
253 printIntReg(ss, base);
255 ccprintf(ss, ", #%d, MUL VL", imm);
262 template <typename Element,
263 template <typename> class MicroopStMemType,
264 template <typename> class MicroopIntrlvType>
265 class SveStStructSI : public PredMacroOp
275 SveStStructSI(const char* mnem, ExtMachInst machInst, OpClass __opClass,
276 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base,
277 int64_t _imm, uint8_t _numregs)
278 : PredMacroOp(mnem, machInst, __opClass),
279 dest(_dest), gp(_gp), base(_base), imm(_imm), numregs(_numregs)
281 numMicroops = numregs * 2;
283 microOps = new StaticInstPtr[numMicroops];
285 for (int i = 0; i < numregs; ++i) {
286 microOps[i] = new MicroopIntrlvType<Element>(
287 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i),
288 _dest, _numregs, i, this);
291 for (int i = 0; i < numregs; ++i) {
292 microOps[i + numregs] = new MicroopStMemType<Element>(
293 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i),
294 _gp, _base, _imm, _numregs, i);
297 microOps[0]->setFirstMicroop();
298 microOps[numMicroops - 1]->setLastMicroop();
300 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) {
301 (*uop)->setDelayedCommit();
306 execute(ExecContext *, Trace::InstRecord *) const
308 panic("Execute method called when it shouldn't!");
313 generateDisassembly(Addr pc, const SymbolTable *symtab) const
315 std::stringstream ss;
316 printMnemonic(ss, "", false);
318 for (int i = 0; i < numregs; ++i) {
319 printVecReg(ss, (dest + i) % 32, true);
324 printVecPredReg(ss, gp);
326 printIntReg(ss, base);
328 ccprintf(ss, ", #%d, MUL VL", imm);
335 template <typename RegElemType, typename MemElemType,
336 template <typename, typename> class MicroopType,
337 template <typename> class FirstFaultWritebackMicroopType>
338 class SveIndexedMemVI : public PredMacroOp
347 SveIndexedMemVI(const char *mnem, ExtMachInst machInst, OpClass __opClass,
348 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base,
349 uint64_t _imm, bool firstFault)
350 : PredMacroOp(mnem, machInst, __opClass),
351 dest(_dest), gp(_gp), base(_base), imm(_imm)
353 bool isLoad = (__opClass == MemReadOp);
354 assert(!firstFault || isLoad);
356 int num_elems = ((machInst.sveLen + 1) * 16) / sizeof(RegElemType);
358 numMicroops = num_elems;
367 microOps = new StaticInstPtr[numMicroops];
369 StaticInstPtr *uop = microOps;
372 // The first microop of a gather load copies the source vector
373 // register used for address calculation to an auxiliary register,
374 // with all subsequent microops reading from the latter. This is
375 // needed to properly handle cases where the source vector
376 // register is the same as the destination register
377 *uop = new ArmISAInst::SveGatherLoadCpySrcVecMicroop(
378 mnem, machInst, _base, this);
382 for (int i = 0; i < num_elems; i++, uop++) {
383 *uop = new MicroopType<RegElemType, MemElemType>(
384 mnem, machInst, __opClass, _dest, _gp,
385 isLoad ? (IntRegIndex) VECREG_UREG0 : _base, _imm, i,
386 num_elems, firstFault);
390 *uop = new FirstFaultWritebackMicroopType<RegElemType>(
391 mnem, machInst, __opClass, num_elems, this);
396 (*uop)->setLastMicroop();
397 microOps[0]->setFirstMicroop();
399 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) {
400 (*uop)->setDelayedCommit();
405 execute(ExecContext *, Trace::InstRecord *) const
407 panic("Execute method called when it shouldn't!");
412 generateDisassembly(Addr pc, const SymbolTable *symtab) const
414 // TODO: add suffix to transfer and base registers
415 std::stringstream ss;
416 printMnemonic(ss, "", false);
418 printVecReg(ss, dest, true);
420 printVecPredReg(ss, gp);
421 ccprintf(ss, "/z, [");
422 printVecReg(ss, base, true);
424 ccprintf(ss, ", #%d", imm * sizeof(MemElemType));
431 template <typename RegElemType, typename MemElemType,
432 template <typename, typename> class MicroopType,
433 template <typename> class FirstFaultWritebackMicroopType>
434 class SveIndexedMemSV : public PredMacroOp
447 SveIndexedMemSV(const char *mnem, ExtMachInst machInst, OpClass __opClass,
448 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base,
449 IntRegIndex _offset, bool _offsetIs32,
450 bool _offsetIsSigned, bool _offsetIsScaled,
452 : PredMacroOp(mnem, machInst, __opClass),
453 dest(_dest), gp(_gp), base(_base), offset(_offset),
454 offsetIs32(_offsetIs32), offsetIsSigned(_offsetIsSigned),
455 offsetIsScaled(_offsetIsScaled)
457 bool isLoad = (__opClass == MemReadOp);
458 assert(!firstFault || isLoad);
460 int num_elems = ((machInst.sveLen + 1) * 16) / sizeof(RegElemType);
462 numMicroops = num_elems;
471 microOps = new StaticInstPtr[numMicroops];
473 StaticInstPtr *uop = microOps;
476 // The first microop of a gather load copies the source vector
477 // register used for address calculation to an auxiliary register,
478 // with all subsequent microops reading from the latter. This is
479 // needed to properly handle cases where the source vector
480 // register is the same as the destination register
481 *uop = new ArmISAInst::SveGatherLoadCpySrcVecMicroop(
482 mnem, machInst, _offset, this);
486 for (int i = 0; i < num_elems; i++, uop++) {
487 *uop = new MicroopType<RegElemType, MemElemType>(
488 mnem, machInst, __opClass, _dest, _gp, _base,
489 isLoad ? (IntRegIndex) VECREG_UREG0 : _offset, _offsetIs32,
490 _offsetIsSigned, _offsetIsScaled, i, num_elems, firstFault);
494 *uop = new FirstFaultWritebackMicroopType<RegElemType>(
495 mnem, machInst, __opClass, num_elems, this);
500 (*uop)->setLastMicroop();
501 microOps[0]->setFirstMicroop();
503 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) {
504 (*uop)->setDelayedCommit();
509 execute(ExecContext *, Trace::InstRecord *) const
511 panic("Execute method called when it shouldn't!");
516 generateDisassembly(Addr pc, const SymbolTable *symtab) const
518 // TODO: add suffix to transfer and base registers
519 std::stringstream ss;
520 printMnemonic(ss, "", false);
522 printVecReg(ss, dest, true);
524 printVecPredReg(ss, gp);
525 ccprintf(ss, "/z, [");
526 printIntReg(ss, base);
528 printVecReg(ss, offset, true);
534 } // namespace ArmISA
536 #endif // __ARCH_ARM_SVE_MACROMEM_HH__