1// -*- mode:c++ -*- 2 3// Copyright (c) 2015 Riscv Developers 4// Copyright (c) 2016 The University of Virginia 5// All rights reserved. 6// 7// Redistribution and use in source and binary forms, with or without 8// modification, are permitted provided that the following conditions are 9// met: redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer; 11// redistributions in binary form must reproduce the above copyright 12// notice, this list of conditions and the following disclaimer in the 13// documentation and/or other materials provided with the distribution; 14// neither the name of the copyright holders nor the names of its 15// contributors may be used to endorse or promote products derived from 16// this software without specific prior written permission. 17// 18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29// 30// Authors: Alec Roelke 31
|
32////////////////////////////////////////////////////////////////////
33//
34// Atomic memory operation instructions
35//
|
32// Declaration templates |
33def template AtomicMemOpDeclare {{ 34 /** 35 * Static instruction class for an AtomicMemOp operation 36 */ 37 class %(class_name)s : public %(base_class)s 38 { 39 public: 40 // Constructor 41 %(class_name)s(ExtMachInst machInst); 42 43 protected: 44
|
48 class %(class_name)sLoad : public %(base_class)sMicro
|
45 /* 46 * The main RMW part of an AMO 47 */ 48 class %(class_name)sRMW : public %(base_class)sMicro |
49 { 50 public: 51 // Constructor
|
52 %(class_name)sLoad(ExtMachInst machInst, %(class_name)s *_p);
|
52 %(class_name)sRMW(ExtMachInst machInst, %(class_name)s *_p); |
53 54 Fault execute(ExecContext *, Trace::InstRecord *) const override; 55 Fault initiateAcc(ExecContext *, 56 Trace::InstRecord *) const override; 57 Fault completeAcc(PacketPtr, ExecContext *, 58 Trace::InstRecord *) const override; 59 };
|
60 }; 61}}; |
62
|
61 class %(class_name)sStore : public %(base_class)sMicro
|
63def template LRSCDeclare {{ 64 /** 65 * Static instruction class for an AtomicMemOp operation 66 */ 67 class %(class_name)s : public %(base_class)s 68 { 69 public: 70 // Constructor 71 %(class_name)s(ExtMachInst machInst); 72 73 protected: 74 75 class %(class_name)sMicro : public %(base_class)sMicro |
76 { 77 public: 78 // Constructor
|
65 %(class_name)sStore(ExtMachInst machInst, %(class_name)s *_p);
|
79 %(class_name)sMicro(ExtMachInst machInst, %(class_name)s *_p); |
80 81 Fault execute(ExecContext *, Trace::InstRecord *) const override; 82 Fault initiateAcc(ExecContext *, 83 Trace::InstRecord *) const override; 84 Fault completeAcc(PacketPtr, ExecContext *, 85 Trace::InstRecord *) const override; 86 }; 87 }; 88}}; 89
|
76def template LRSCConstructor {{
|
90// Constructor templates 91def template LRSCMacroConstructor {{ |
92 %(class_name)s::%(class_name)s(ExtMachInst machInst): 93 %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) 94 { 95 %(constructor)s;
|
81 if (AQ)
82 memAccessFlags = memAccessFlags | Request::ACQUIRE;
83 if (RL)
84 memAccessFlags = memAccessFlags | Request::RELEASE;
|
96 97 StaticInstPtr rel_fence; 98 StaticInstPtr lrsc; 99 StaticInstPtr acq_fence; 100 101 // set up release fence 102 if (RL) { 103 rel_fence = new MemFenceMicro(machInst, No_OpClass); 104 rel_fence->setFlag(IsFirstMicroop); 105 rel_fence->setFlag(IsMemBarrier); 106 rel_fence->setFlag(IsDelayedCommit); 107 } 108 109 // set up atomic rmw op 110 lrsc = new %(class_name)sMicro(machInst, this); 111 112 if (!RL) { 113 lrsc->setFlag(IsFirstMicroop); 114 } 115 116 if (!AQ) { 117 lrsc->setFlag(IsLastMicroop); 118 } else { 119 lrsc->setFlag(IsDelayedCommit); 120 } 121 122 // set up acquire fence 123 if (AQ) { 124 acq_fence = new MemFenceMicro(machInst, No_OpClass); 125 acq_fence->setFlag(IsLastMicroop); 126 acq_fence->setFlag(IsMemBarrier); 127 } 128 129 if (RL && AQ) { 130 microops = {rel_fence, lrsc, acq_fence}; 131 } else if (RL) { 132 microops = {rel_fence, lrsc}; 133 } else if (AQ) { 134 microops = {lrsc, acq_fence}; 135 } else { 136 microops = {lrsc}; 137 } |
138 } 139}}; 140
|
141def template LRSCMicroConstructor {{ 142 %(class_name)s::%(class_name)sMicro::%(class_name)sMicro( 143 ExtMachInst machInst, %(class_name)s *_p) 144 : %(base_class)sMicro("%(mnemonic)s", machInst, %(op_class)s) 145 { 146 %(constructor)s; 147 } 148}}; 149 |
150def template AtomicMemOpMacroConstructor {{ 151 %(class_name)s::%(class_name)s(ExtMachInst machInst) 152 : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) 153 { 154 %(constructor)s;
|
93 microops = {new %(class_name)sLoad(machInst, this),
94 new %(class_name)sStore(machInst, this)};
|
155 156 StaticInstPtr rel_fence; 157 StaticInstPtr rmw_op; 158 StaticInstPtr acq_fence; 159 160 // set up release fence 161 if (RL) { 162 rel_fence = new MemFenceMicro(machInst, No_OpClass); 163 rel_fence->setFlag(IsFirstMicroop); 164 rel_fence->setFlag(IsMemBarrier); 165 rel_fence->setFlag(IsDelayedCommit); 166 } 167 168 // set up atomic rmw op 169 rmw_op = new %(class_name)sRMW(machInst, this); 170 171 if (!RL) { 172 rmw_op->setFlag(IsFirstMicroop); 173 } 174 175 if (!AQ) { 176 rmw_op->setFlag(IsLastMicroop); 177 } else { 178 rmw_op->setFlag(IsDelayedCommit); 179 } 180 181 // set up acquire fence 182 if (AQ) { 183 acq_fence = new MemFenceMicro(machInst, No_OpClass); 184 acq_fence->setFlag(IsLastMicroop); 185 acq_fence->setFlag(IsMemBarrier); 186 } 187 188 if (RL && AQ) { 189 microops = {rel_fence, rmw_op, acq_fence}; 190 } else if (RL) { 191 microops = {rel_fence, rmw_op}; 192 } else if (AQ) { 193 microops = {rmw_op, acq_fence}; 194 } else { 195 microops = {rmw_op}; 196 } |
197 } 198}}; 199
|
98def template AtomicMemOpLoadConstructor {{
99 %(class_name)s::%(class_name)sLoad::%(class_name)sLoad(
|
200def template AtomicMemOpRMWConstructor {{ 201 %(class_name)s::%(class_name)sRMW::%(class_name)sRMW( |
202 ExtMachInst machInst, %(class_name)s *_p) 203 : %(base_class)s("%(mnemonic)s[l]", machInst, %(op_class)s) 204 { 205 %(constructor)s;
|
104 flags[IsFirstMicroop] = true;
105 flags[IsDelayedCommit] = true;
106 if (AQ)
107 memAccessFlags = Request::ACQUIRE;
|
206 207 // overwrite default flags 208 flags[IsMemRef] = true; 209 flags[IsLoad] = false; 210 flags[IsStore] = false; 211 flags[IsAtomic] = true; |
212 } 213}}; 214
|
111def template AtomicMemOpStoreConstructor {{
112 %(class_name)s::%(class_name)sStore::%(class_name)sStore(
113 ExtMachInst machInst, %(class_name)s *_p)
114 : %(base_class)s("%(mnemonic)s[s]", machInst, %(op_class)s)
|
215// execute() templates 216 217def template LoadReservedExecute {{ 218 Fault 219 %(class_name)s::%(class_name)sMicro::execute( 220 ExecContext *xc, Trace::InstRecord *traceData) const |
221 {
|
116 %(constructor)s;
117 flags[IsLastMicroop] = true;
118 flags[IsNonSpeculative] = true;
119 if (RL)
120 memAccessFlags = Request::RELEASE;
|
222 Addr EA; 223 Fault fault = NoFault; 224 225 %(op_decl)s; 226 %(op_rd)s; 227 %(ea_code)s; 228 229 if (fault == NoFault) { 230 fault = readMemAtomic(xc, traceData, EA, Mem, memAccessFlags); 231 %(memacc_code)s; 232 } 233 234 if (fault == NoFault) { 235 %(op_wb)s; 236 } 237 238 return fault; |
239 } 240}}; 241 242def template StoreCondExecute {{
|
125 Fault %(class_name)s::execute(ExecContext *xc,
|
243 Fault %(class_name)s::%(class_name)sMicro::execute(ExecContext *xc, |
244 Trace::InstRecord *traceData) const 245 { 246 Addr EA; 247 Fault fault = NoFault; 248 uint64_t result; 249 250 %(op_decl)s; 251 %(op_rd)s; 252 %(ea_code)s; 253 254 if (fault == NoFault) { 255 %(memacc_code)s; 256 } 257 258 if (fault == NoFault) { 259 fault = writeMemAtomic(xc, traceData, Mem, EA, memAccessFlags, 260 &result); 261 // RISC-V has the opposite convention gem5 has for success flags, 262 // so we invert the result here. 263 result = !result; 264 } 265 266 if (fault == NoFault) { 267 %(postacc_code)s; 268 } 269 270 if (fault == NoFault) { 271 %(op_wb)s; 272 } 273 274 return fault; 275 } 276}}; 277
|
160def template AtomicMemOpLoadExecute {{
161 Fault %(class_name)s::%(class_name)sLoad::execute(ExecContext *xc,
|
278def template AtomicMemOpRMWExecute {{ 279 Fault %(class_name)s::%(class_name)sRMW::execute(ExecContext *xc, |
280 Trace::InstRecord *traceData) const 281 { 282 Addr EA; 283 Fault fault = NoFault; 284 285 %(op_decl)s; 286 %(op_rd)s; 287 %(ea_code)s;
|
288 %(amoop_code)s; |
289
|
290 assert(amo_op); 291 |
292 if (fault == NoFault) {
|
172 fault = readMemAtomic(xc, traceData, EA, Mem, memAccessFlags);
|
293 fault = amoMemAtomic(xc, traceData, Mem, EA, memAccessFlags, 294 amo_op); 295 %(memacc_code)s; |
296 } 297 298 if (fault == NoFault) {
|
176 %(code)s;
|
299 %(postacc_code)s; |
300 } 301 302 if (fault == NoFault) { 303 %(op_wb)s; 304 } 305 306 return fault; 307 } 308}}; 309
|
187def template AtomicMemOpStoreExecute {{
188 Fault %(class_name)s::%(class_name)sStore::execute(ExecContext *xc,
|
310// initiateAcc() templates 311 312def template LoadReservedInitiateAcc {{ 313 Fault 314 %(class_name)s::%(class_name)sMicro::initiateAcc(ExecContext *xc, |
315 Trace::InstRecord *traceData) const 316 { 317 Addr EA; 318 Fault fault = NoFault; 319
|
320 %(op_src_decl)s; 321 %(op_rd)s; 322 %(ea_code)s; 323 324 if (fault == NoFault) { 325 fault = initiateMemRead(xc, traceData, EA, Mem, memAccessFlags); 326 } 327 328 return fault; 329 } 330}}; 331 332def template StoreCondInitiateAcc {{ 333 Fault 334 %(class_name)s::%(class_name)sMicro::initiateAcc(ExecContext *xc, 335 Trace::InstRecord *traceData) const 336 { 337 Addr EA; 338 Fault fault = NoFault; 339 |
340 %(op_decl)s; 341 %(op_rd)s; 342 %(ea_code)s; 343 344 if (fault == NoFault) {
|
199 %(code)s;
|
345 %(memacc_code)s; |
346 } 347 348 if (fault == NoFault) {
|
203 fault = writeMemAtomic(xc, traceData, Mem, EA, memAccessFlags,
204 nullptr);
|
349 fault = writeMemTiming(xc, traceData, Mem, EA, 350 memAccessFlags, nullptr); |
351 } 352 353 if (fault == NoFault) { 354 %(op_wb)s; 355 } 356 357 return fault; 358 } 359}}; 360
|
215def template AtomicMemOpLoadInitiateAcc {{
216 Fault %(class_name)s::%(class_name)sLoad::initiateAcc(ExecContext *xc,
|
361def template AtomicMemOpRMWInitiateAcc {{ 362 Fault 363 %(class_name)s::%(class_name)sRMW::initiateAcc(ExecContext *xc, |
364 Trace::InstRecord *traceData) const 365 { 366 Addr EA; 367 Fault fault = NoFault; 368 369 %(op_src_decl)s; 370 %(op_rd)s; 371 %(ea_code)s;
|
372 %(amoop_code)s; |
373
|
374 assert(amo_op); 375 |
376 if (fault == NoFault) {
|
227 fault = initiateMemRead(xc, traceData, EA, Mem, memAccessFlags);
|
377 fault = initiateMemAMO(xc, traceData, EA, Mem, memAccessFlags, 378 amo_op); |
379 } 380 381 return fault; 382 } 383}}; 384
|
234def template AtomicMemOpStoreInitiateAcc {{
235 Fault %(class_name)s::%(class_name)sStore::initiateAcc(
|
385// completeAcc() templates 386 387def template LoadReservedCompleteAcc {{ 388 Fault 389 %(class_name)s::%(class_name)sMicro::completeAcc(PacketPtr pkt, |
390 ExecContext *xc, Trace::InstRecord *traceData) const 391 {
|
238 Addr EA;
|
392 Fault fault = NoFault; 393 394 %(op_decl)s; 395 %(op_rd)s;
|
243 %(ea_code)s;
|
396
|
245 if (fault == NoFault) {
246 %(code)s;
247 }
|
397 getMem(pkt, Mem, traceData); |
398 399 if (fault == NoFault) {
|
250 fault = writeMemTiming(xc, traceData, Mem, EA, memAccessFlags,
251 nullptr);
|
400 %(memacc_code)s; |
401 } 402 403 if (fault == NoFault) { 404 %(op_wb)s; 405 } 406 407 return fault; 408 } 409}}; 410 411def template StoreCondCompleteAcc {{
|
263 Fault %(class_name)s::completeAcc(Packet *pkt, ExecContext *xc,
264 Trace::InstRecord *traceData) const
|
412 Fault %(class_name)s::%(class_name)sMicro::completeAcc(Packet *pkt, 413 ExecContext *xc, Trace::InstRecord *traceData) const |
414 { 415 Fault fault = NoFault; 416 417 %(op_dest_decl)s; 418 419 // RISC-V has the opposite convention gem5 has for success flags, 420 // so we invert the result here. 421 uint64_t result = !pkt->req->getExtraData(); 422 423 if (fault == NoFault) { 424 %(postacc_code)s; 425 } 426 427 if (fault == NoFault) { 428 %(op_wb)s; 429 } 430 431 return fault; 432 } 433}}; 434
|
286def template AtomicMemOpLoadCompleteAcc {{
287 Fault %(class_name)s::%(class_name)sLoad::completeAcc(PacketPtr pkt,
|
435def template AtomicMemOpRMWCompleteAcc {{ 436 Fault %(class_name)s::%(class_name)sRMW::completeAcc(Packet *pkt, |
437 ExecContext *xc, Trace::InstRecord *traceData) const 438 { 439 Fault fault = NoFault; 440 441 %(op_decl)s; 442 %(op_rd)s; 443 444 getMem(pkt, Mem, traceData); 445 446 if (fault == NoFault) {
|
298 %(code)s;
|
447 %(memacc_code)s; |
448 } 449 450 if (fault == NoFault) { 451 %(op_wb)s; 452 } 453 454 return fault; 455 } 456}}; 457
|
309def template AtomicMemOpStoreCompleteAcc {{
310 Fault %(class_name)s::%(class_name)sStore::completeAcc(PacketPtr pkt,
311 ExecContext *xc, Trace::InstRecord *traceData) const
312 {
313 return NoFault;
314 }
315}};
|
458// LR/SC/AMO decode formats |
459 460def format LoadReserved(memacc_code, postacc_code={{ }}, ea_code={{EA = Rs1;}}, 461 mem_flags=[], inst_flags=[]) {{
|
462 macro_ea_code = '' 463 macro_inst_flags = [] 464 macro_iop = InstObjParams(name, Name, 'LoadReserved', macro_ea_code, 465 macro_inst_flags) 466 header_output = LRSCDeclare.subst(macro_iop) 467 decoder_output = LRSCMacroConstructor.subst(macro_iop) 468 decode_block = BasicDecode.subst(macro_iop) 469 470 exec_output = '' 471 |
472 mem_flags = makeList(mem_flags) 473 inst_flags = makeList(inst_flags) 474 iop = InstObjParams(name, Name, 'LoadReserved', 475 {'ea_code': ea_code, 'memacc_code': memacc_code, 476 'postacc_code': postacc_code}, inst_flags) 477 iop.constructor += '\n\tmemAccessFlags = memAccessFlags | ' + \ 478 '|'.join(['Request::%s' % flag for flag in mem_flags]) + ';' 479
|
327 header_output = LoadStoreDeclare.subst(iop)
328 decoder_output = LRSCConstructor.subst(iop)
329 decode_block = BasicDecode.subst(iop)
330 exec_output = LoadExecute.subst(iop) \
331 + LoadInitiateAcc.subst(iop) \
332 + LoadCompleteAcc.subst(iop)
|
480 decoder_output += LRSCMicroConstructor.subst(iop) 481 decode_block += BasicDecode.subst(iop) 482 exec_output += LoadReservedExecute.subst(iop) \ 483 + LoadReservedInitiateAcc.subst(iop) \ 484 + LoadReservedCompleteAcc.subst(iop) |
485}}; 486 487def format StoreCond(memacc_code, postacc_code={{ }}, ea_code={{EA = Rs1;}}, 488 mem_flags=[], inst_flags=[]) {{
|
489 macro_ea_code = '' 490 macro_inst_flags = [] 491 macro_iop = InstObjParams(name, Name, 'StoreCond', macro_ea_code, 492 macro_inst_flags) 493 header_output = LRSCDeclare.subst(macro_iop) 494 decoder_output = LRSCMacroConstructor.subst(macro_iop) 495 decode_block = BasicDecode.subst(macro_iop) 496 497 exec_output = '' 498 |
499 mem_flags = makeList(mem_flags) 500 inst_flags = makeList(inst_flags) 501 iop = InstObjParams(name, Name, 'StoreCond', 502 {'ea_code': ea_code, 'memacc_code': memacc_code, 503 'postacc_code': postacc_code}, inst_flags) 504 iop.constructor += '\n\tmemAccessFlags = memAccessFlags | ' + \ 505 '|'.join(['Request::%s' % flag for flag in mem_flags]) + ';' 506
|
345 header_output = LoadStoreDeclare.subst(iop)
346 decoder_output = LRSCConstructor.subst(iop)
347 decode_block = BasicDecode.subst(iop)
348 exec_output = StoreCondExecute.subst(iop) \
349 + StoreInitiateAcc.subst(iop) \
|
507 decoder_output += LRSCMicroConstructor.subst(iop) 508 decode_block += BasicDecode.subst(iop) 509 exec_output += StoreCondExecute.subst(iop) \ 510 + StoreCondInitiateAcc.subst(iop) \ |
511 + StoreCondCompleteAcc.subst(iop) 512}}; 513
|
353def format AtomicMemOp(load_code, store_code, ea_code, load_flags=[],
354 store_flags=[], inst_flags=[]) {{
355 macro_iop = InstObjParams(name, Name, 'AtomicMemOp', ea_code, inst_flags)
|
514def format AtomicMemOp(memacc_code, amoop_code, postacc_code={{ }}, 515 ea_code={{EA = Rs1;}}, mem_flags=[], inst_flags=[]) {{ 516 macro_ea_code = '' 517 macro_inst_flags = [] 518 macro_iop = InstObjParams(name, Name, 'AtomicMemOp', macro_ea_code, 519 macro_inst_flags) |
520 header_output = AtomicMemOpDeclare.subst(macro_iop) 521 decoder_output = AtomicMemOpMacroConstructor.subst(macro_iop) 522 decode_block = BasicDecode.subst(macro_iop)
|
523 |
524 exec_output = '' 525
|
361 load_inst_flags = makeList(inst_flags) + ["IsMemRef", "IsLoad"]
362 load_iop = InstObjParams(name, Name, 'AtomicMemOpMicro',
363 {'ea_code': ea_code, 'code': load_code, 'op_name': 'Load'},
364 load_inst_flags)
365 decoder_output += AtomicMemOpLoadConstructor.subst(load_iop)
366 exec_output += AtomicMemOpLoadExecute.subst(load_iop) \
367 + AtomicMemOpLoadInitiateAcc.subst(load_iop) \
368 + AtomicMemOpLoadCompleteAcc.subst(load_iop)
|
526 rmw_mem_flags = makeList(mem_flags) 527 rmw_inst_flags = makeList(inst_flags) 528 rmw_iop = InstObjParams(name, Name, 'AtomicMemOpMicro', 529 {'ea_code': ea_code, 530 'memacc_code': memacc_code, 531 'postacc_code': postacc_code, 532 'amoop_code': amoop_code}, 533 rmw_inst_flags) |
534
|
370 store_inst_flags = makeList(inst_flags) + ["IsMemRef", "IsStore"]
371 store_iop = InstObjParams(name, Name, 'AtomicMemOpMicro',
372 {'ea_code': ea_code, 'code': store_code, 'op_name': 'Store'},
373 store_inst_flags)
374 decoder_output += AtomicMemOpStoreConstructor.subst(store_iop)
375 exec_output += AtomicMemOpStoreExecute.subst(store_iop) \
376 + AtomicMemOpStoreInitiateAcc.subst(store_iop) \
377 + AtomicMemOpStoreCompleteAcc.subst(store_iop)
|
535 rmw_iop.constructor += '\n\tmemAccessFlags = memAccessFlags | ' + \ 536 '|'.join(['Request::%s' % flag for flag in rmw_mem_flags]) + ';' 537 538 decoder_output += AtomicMemOpRMWConstructor.subst(rmw_iop) 539 decode_block += BasicDecode.subst(rmw_iop) 540 exec_output += AtomicMemOpRMWExecute.subst(rmw_iop) \ 541 + AtomicMemOpRMWInitiateAcc.subst(rmw_iop) \ 542 + AtomicMemOpRMWCompleteAcc.subst(rmw_iop) |
543}};
|