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 Element, 49 template <typename> class MicroopLdMemType, 50 template <typename> class MicroopDeIntrlvType> 51class SveLdStructSS : public PredMacroOp 52{ 53 protected: 54 IntRegIndex dest; 55 IntRegIndex gp; 56 IntRegIndex base; 57 IntRegIndex offset; 58 uint8_t numregs; 59 60 public: 61 SveLdStructSS(const char* mnem, ExtMachInst machInst, OpClass __opClass, 62 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base, 63 IntRegIndex _offset, uint8_t _numregs) 64 : PredMacroOp(mnem, machInst, __opClass), 65 dest(_dest), gp(_gp), base(_base), offset(_offset), numregs(_numregs) 66 { 67 numMicroops = numregs * 2; 68 69 microOps = new StaticInstPtr[numMicroops]; 70 71 for (int i = 0; i < numregs; ++i) { 72 microOps[i] = new MicroopLdMemType<Element>( 73 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i), 74 _gp, _base, _offset, _numregs, i); 75 } 76 for (int i = 0; i < numregs; ++i) { 77 microOps[i + numregs] = new MicroopDeIntrlvType<Element>( 78 mnem, machInst, static_cast<IntRegIndex>((_dest + i) % 32), 79 _numregs, i, this); 80 } 81 82 microOps[0]->setFirstMicroop(); 83 microOps[numMicroops - 1]->setLastMicroop(); 84 85 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) { 86 (*uop)->setDelayedCommit(); 87 } 88 } 89 90 Fault 91 execute(ExecContext *, Trace::InstRecord *) const 92 { 93 panic("Execute method called when it shouldn't!"); 94 return NoFault; 95 } 96 97 std::string 98 generateDisassembly(Addr pc, const SymbolTable *symtab) const 99 { 100 std::stringstream ss; 101 printMnemonic(ss, "", false); 102 ccprintf(ss, "{"); 103 for (int i = 0; i < numregs; ++i) { 104 printVecReg(ss, (dest + i) % 32, true); 105 if (i < numregs - 1) 106 ccprintf(ss, ", "); 107 } 108 ccprintf(ss, "}, "); 109 printVecPredReg(ss, gp); 110 ccprintf(ss, "/z, ["); 111 printIntReg(ss, base); 112 ccprintf(ss, ", "); 113 printIntReg(ss, offset); 114 ccprintf(ss, "]"); 115 return ss.str(); 116 } 117}; 118 119template <typename Element, 120 template <typename> class MicroopStMemType, 121 template <typename> class MicroopIntrlvType> 122class SveStStructSS : public PredMacroOp 123{ 124 protected: 125 IntRegIndex dest; 126 IntRegIndex gp; 127 IntRegIndex base; 128 IntRegIndex offset; 129 uint8_t numregs; 130 131 public: 132 SveStStructSS(const char* mnem, ExtMachInst machInst, OpClass __opClass, 133 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base, 134 IntRegIndex _offset, uint8_t _numregs) 135 : PredMacroOp(mnem, machInst, __opClass), 136 dest(_dest), gp(_gp), base(_base), offset(_offset), numregs(_numregs) 137 { 138 numMicroops = numregs * 2; 139 140 microOps = new StaticInstPtr[numMicroops]; 141 142 for (int i = 0; i < numregs; ++i) { 143 microOps[i] = new MicroopIntrlvType<Element>( 144 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i), 145 _dest, _numregs, i, this); 146 } 147 148 for (int i = 0; i < numregs; ++i) { 149 microOps[i + numregs] = new MicroopStMemType<Element>( 150 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i), 151 _gp, _base, _offset, _numregs, i); 152 } 153 154 microOps[0]->setFirstMicroop(); 155 microOps[numMicroops - 1]->setLastMicroop(); 156 157 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) { 158 (*uop)->setDelayedCommit(); 159 } 160 } 161 162 Fault 163 execute(ExecContext *, Trace::InstRecord *) const 164 { 165 panic("Execute method called when it shouldn't!"); 166 return NoFault; 167 } 168 169 std::string 170 generateDisassembly(Addr pc, const SymbolTable *symtab) const 171 { 172 std::stringstream ss; 173 printMnemonic(ss, "", false); 174 ccprintf(ss, "{"); 175 for (int i = 0; i < numregs; ++i) { 176 printVecReg(ss, (dest + i) % 32, true); 177 if (i < numregs - 1) 178 ccprintf(ss, ", "); 179 } 180 ccprintf(ss, "}, "); 181 printVecPredReg(ss, gp); 182 ccprintf(ss, ", ["); 183 printIntReg(ss, base); 184 ccprintf(ss, ", "); 185 printIntReg(ss, offset); 186 ccprintf(ss, "]"); 187 return ss.str(); 188 } 189}; 190 191 192template <typename Element, 193 template <typename> class MicroopLdMemType, 194 template <typename> class MicroopDeIntrlvType> 195class SveLdStructSI : public PredMacroOp 196{ 197 protected: 198 IntRegIndex dest; 199 IntRegIndex gp; 200 IntRegIndex base; 201 int64_t imm; 202 uint8_t numregs; 203 204 public: 205 SveLdStructSI(const char* mnem, ExtMachInst machInst, OpClass __opClass, 206 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base, 207 int64_t _imm, uint8_t _numregs) 208 : PredMacroOp(mnem, machInst, __opClass), 209 dest(_dest), gp(_gp), base(_base), imm(_imm), numregs(_numregs) 210 { 211 numMicroops = numregs * 2; 212 213 microOps = new StaticInstPtr[numMicroops]; 214 215 for (int i = 0; i < numregs; ++i) { 216 microOps[i] = new MicroopLdMemType<Element>( 217 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i), 218 _gp, _base, _imm, _numregs, i); 219 } 220 for (int i = 0; i < numregs; ++i) { 221 microOps[i + numregs] = new MicroopDeIntrlvType<Element>( 222 mnem, machInst, static_cast<IntRegIndex>((_dest + i) % 32), 223 _numregs, i, this); 224 } 225 226 microOps[0]->setFirstMicroop(); 227 microOps[numMicroops - 1]->setLastMicroop(); 228 229 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) { 230 (*uop)->setDelayedCommit(); 231 } 232 } 233 234 Fault 235 execute(ExecContext *, Trace::InstRecord *) const 236 { 237 panic("Execute method called when it shouldn't!"); 238 return NoFault; 239 } 240 241 std::string 242 generateDisassembly(Addr pc, const SymbolTable *symtab) const 243 { 244 std::stringstream ss; 245 printMnemonic(ss, "", false); 246 ccprintf(ss, "{"); 247 for (int i = 0; i < numregs; ++i) { 248 printVecReg(ss, (dest + i) % 32, true); 249 if (i < numregs - 1) 250 ccprintf(ss, ", "); 251 } 252 ccprintf(ss, "}, "); 253 printVecPredReg(ss, gp); 254 ccprintf(ss, "/z, ["); 255 printIntReg(ss, base); 256 if (imm != 0) { 257 ccprintf(ss, ", #%d, MUL VL", imm); 258 } 259 ccprintf(ss, "]"); 260 return ss.str(); 261 } 262}; 263 264template <typename Element, 265 template <typename> class MicroopStMemType, 266 template <typename> class MicroopIntrlvType> 267class SveStStructSI : public PredMacroOp 268{ 269 protected: 270 IntRegIndex dest; 271 IntRegIndex gp; 272 IntRegIndex base; 273 int64_t imm; 274 uint8_t numregs; 275 276 public: 277 SveStStructSI(const char* mnem, ExtMachInst machInst, OpClass __opClass, 278 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base, 279 int64_t _imm, uint8_t _numregs) 280 : PredMacroOp(mnem, machInst, __opClass), 281 dest(_dest), gp(_gp), base(_base), imm(_imm), numregs(_numregs) 282 { 283 numMicroops = numregs * 2; 284 285 microOps = new StaticInstPtr[numMicroops]; 286 287 for (int i = 0; i < numregs; ++i) { 288 microOps[i] = new MicroopIntrlvType<Element>( 289 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i), 290 _dest, _numregs, i, this); 291 } 292 293 for (int i = 0; i < numregs; ++i) { 294 microOps[i + numregs] = new MicroopStMemType<Element>( 295 mnem, machInst, static_cast<IntRegIndex>(INTRLVREG0 + i), 296 _gp, _base, _imm, _numregs, i); 297 } 298 299 microOps[0]->setFirstMicroop(); 300 microOps[numMicroops - 1]->setLastMicroop(); 301 302 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) { 303 (*uop)->setDelayedCommit(); 304 } 305 } 306 307 Fault 308 execute(ExecContext *, Trace::InstRecord *) const 309 { 310 panic("Execute method called when it shouldn't!"); 311 return NoFault; 312 } 313 314 std::string 315 generateDisassembly(Addr pc, const SymbolTable *symtab) const 316 { 317 std::stringstream ss; 318 printMnemonic(ss, "", false); 319 ccprintf(ss, "{"); 320 for (int i = 0; i < numregs; ++i) { 321 printVecReg(ss, (dest + i) % 32, true); 322 if (i < numregs - 1) 323 ccprintf(ss, ", "); 324 } 325 ccprintf(ss, "}, "); 326 printVecPredReg(ss, gp); 327 ccprintf(ss, ", ["); 328 printIntReg(ss, base); 329 if (imm != 0) { 330 ccprintf(ss, ", #%d, MUL VL", imm); 331 } 332 ccprintf(ss, "]"); 333 return ss.str(); 334 } 335}; 336 337template <typename RegElemType, typename MemElemType, 338 template <typename, typename> class MicroopType, 339 template <typename> class FirstFaultWritebackMicroopType> 340class SveIndexedMemVI : public PredMacroOp 341{ 342 protected: 343 IntRegIndex dest; 344 IntRegIndex gp; 345 IntRegIndex base; 346 uint64_t imm; 347 348 public: 349 SveIndexedMemVI(const char *mnem, ExtMachInst machInst, OpClass __opClass, 350 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base, 351 uint64_t _imm, bool firstFault) 352 : PredMacroOp(mnem, machInst, __opClass), 353 dest(_dest), gp(_gp), base(_base), imm(_imm) 354 { 355 bool isLoad = (__opClass == MemReadOp); 356 assert(!firstFault || isLoad); 357 358 int num_elems = ((machInst.sveLen + 1) * 16) / sizeof(RegElemType); 359 360 numMicroops = num_elems; 361 if (isLoad) { 362 if (firstFault) { 363 numMicroops += 2; 364 } else { 365 numMicroops++; 366 } 367 } 368 369 microOps = new StaticInstPtr[numMicroops]; 370 371 StaticInstPtr *uop = microOps; 372 373 if (isLoad) { 374 // The first microop of a gather load copies the source vector 375 // register used for address calculation to an auxiliary register, 376 // with all subsequent microops reading from the latter. This is 377 // needed to properly handle cases where the source vector 378 // register is the same as the destination register 379 *uop = new ArmISAInst::SveGatherLoadCpySrcVecMicroop( 380 mnem, machInst, _base, this); 381 uop++; 382 } 383 384 for (int i = 0; i < num_elems; i++, uop++) { 385 *uop = new MicroopType<RegElemType, MemElemType>( 386 mnem, machInst, __opClass, _dest, _gp, 387 isLoad ? (IntRegIndex) VECREG_UREG0 : _base, _imm, i, 388 num_elems, firstFault); 389 } 390 391 if (firstFault) { 392 *uop = new FirstFaultWritebackMicroopType<RegElemType>( 393 mnem, machInst, __opClass, num_elems, this); 394 } else { 395 --uop; 396 } 397 398 (*uop)->setLastMicroop(); 399 microOps[0]->setFirstMicroop(); 400 401 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) { 402 (*uop)->setDelayedCommit(); 403 } 404 } 405 406 Fault 407 execute(ExecContext *, Trace::InstRecord *) const 408 { 409 panic("Execute method called when it shouldn't!"); 410 return NoFault; 411 } 412 413 std::string 414 generateDisassembly(Addr pc, const SymbolTable *symtab) const 415 { 416 // TODO: add suffix to transfer and base registers 417 std::stringstream ss; 418 printMnemonic(ss, "", false); 419 ccprintf(ss, "{"); 420 printVecReg(ss, dest, true); 421 ccprintf(ss, "}, "); 422 printVecPredReg(ss, gp); 423 ccprintf(ss, "/z, ["); 424 printVecReg(ss, base, true); 425 if (imm != 0) { 426 ccprintf(ss, ", #%d", imm * sizeof(MemElemType)); 427 } 428 ccprintf(ss, "]"); 429 return ss.str(); 430 } 431}; 432 433template <typename RegElemType, typename MemElemType, 434 template <typename, typename> class MicroopType, 435 template <typename> class FirstFaultWritebackMicroopType> 436class SveIndexedMemSV : public PredMacroOp 437{ 438 protected: 439 IntRegIndex dest; 440 IntRegIndex gp; 441 IntRegIndex base; 442 IntRegIndex offset; 443 444 bool offsetIs32; 445 bool offsetIsSigned; 446 bool offsetIsScaled; 447 448 public: 449 SveIndexedMemSV(const char *mnem, ExtMachInst machInst, OpClass __opClass, 450 IntRegIndex _dest, IntRegIndex _gp, IntRegIndex _base, 451 IntRegIndex _offset, bool _offsetIs32, 452 bool _offsetIsSigned, bool _offsetIsScaled, 453 bool firstFault) 454 : PredMacroOp(mnem, machInst, __opClass), 455 dest(_dest), gp(_gp), base(_base), offset(_offset), 456 offsetIs32(_offsetIs32), offsetIsSigned(_offsetIsSigned), 457 offsetIsScaled(_offsetIsScaled) 458 { 459 bool isLoad = (__opClass == MemReadOp); 460 assert(!firstFault || isLoad); 461 462 int num_elems = ((machInst.sveLen + 1) * 16) / sizeof(RegElemType); 463 464 numMicroops = num_elems; 465 if (isLoad) { 466 if (firstFault) { 467 numMicroops += 2; 468 } else { 469 numMicroops++; 470 } 471 } 472 473 microOps = new StaticInstPtr[numMicroops]; 474 475 StaticInstPtr *uop = microOps; 476 477 if (isLoad) { 478 // The first microop of a gather load copies the source vector 479 // register used for address calculation to an auxiliary register, 480 // with all subsequent microops reading from the latter. This is 481 // needed to properly handle cases where the source vector 482 // register is the same as the destination register 483 *uop = new ArmISAInst::SveGatherLoadCpySrcVecMicroop( 484 mnem, machInst, _offset, this); 485 uop++; 486 } 487 488 for (int i = 0; i < num_elems; i++, uop++) { 489 *uop = new MicroopType<RegElemType, MemElemType>( 490 mnem, machInst, __opClass, _dest, _gp, _base, 491 isLoad ? (IntRegIndex) VECREG_UREG0 : _offset, _offsetIs32, 492 _offsetIsSigned, _offsetIsScaled, i, num_elems, firstFault); 493 } 494 495 if (firstFault) { 496 *uop = new FirstFaultWritebackMicroopType<RegElemType>( 497 mnem, machInst, __opClass, num_elems, this); 498 } else { 499 --uop; 500 } 501 502 (*uop)->setLastMicroop(); 503 microOps[0]->setFirstMicroop(); 504 505 for (StaticInstPtr *uop = microOps; !(*uop)->isLastMicroop(); uop++) { 506 (*uop)->setDelayedCommit(); 507 } 508 } 509 510 Fault 511 execute(ExecContext *, Trace::InstRecord *) const 512 { 513 panic("Execute method called when it shouldn't!"); 514 return NoFault; 515 } 516 517 std::string 518 generateDisassembly(Addr pc, const SymbolTable *symtab) const 519 { 520 // TODO: add suffix to transfer and base registers 521 std::stringstream ss; 522 printMnemonic(ss, "", false); 523 ccprintf(ss, "{"); 524 printVecReg(ss, dest, true); 525 ccprintf(ss, "}, "); 526 printVecPredReg(ss, gp); 527 ccprintf(ss, "/z, ["); 528 printIntReg(ss, base); 529 ccprintf(ss, ", "); 530 printVecReg(ss, offset, true); 531 ccprintf(ss, "]"); 532 return ss.str(); 533 } 534}; 535 536} // namespace ArmISA 537 538#endif // __ARCH_ARM_SVE_MACROMEM_HH__ 539