amo.isa revision 12482
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// 36def template AtomicMemOpDeclare {{ 37 /** 38 * Static instruction class for an AtomicMemOp operation 39 */ 40 class %(class_name)s : public %(base_class)s 41 { 42 public: 43 // Constructor 44 %(class_name)s(ExtMachInst machInst); 45 46 protected: 47 48 class %(class_name)sLoad : public %(base_class)sMicro 49 { 50 public: 51 // Constructor 52 %(class_name)sLoad(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 class %(class_name)sStore : public %(base_class)sMicro 62 { 63 public: 64 // Constructor 65 %(class_name)sStore(ExtMachInst machInst, %(class_name)s *_p); 66 67 Fault execute(ExecContext *, Trace::InstRecord *) const override; 68 Fault initiateAcc(ExecContext *, 69 Trace::InstRecord *) const override; 70 Fault completeAcc(PacketPtr, ExecContext *, 71 Trace::InstRecord *) const override; 72 }; 73 }; 74}}; 75 76def template LRSCConstructor {{ 77 %(class_name)s::%(class_name)s(ExtMachInst machInst): 78 %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) 79 { 80 %(constructor)s; 81 if (AQ) 82 memAccessFlags = memAccessFlags | Request::ACQUIRE; 83 if (RL) 84 memAccessFlags = memAccessFlags | Request::RELEASE; 85 } 86}}; 87 88def template AtomicMemOpMacroConstructor {{ 89 %(class_name)s::%(class_name)s(ExtMachInst machInst) 90 : %(base_class)s("%(mnemonic)s", machInst, %(op_class)s) 91 { 92 %(constructor)s; 93 microops = {new %(class_name)sLoad(machInst, this), 94 new %(class_name)sStore(machInst, this)}; 95 } 96}}; 97 98def template AtomicMemOpLoadConstructor {{ 99 %(class_name)s::%(class_name)sLoad::%(class_name)sLoad( 100 ExtMachInst machInst, %(class_name)s *_p) 101 : %(base_class)s("%(mnemonic)s[l]", machInst, %(op_class)s) 102 { 103 %(constructor)s; 104 flags[IsFirstMicroop] = true; 105 flags[IsDelayedCommit] = true; 106 if (AQ) 107 memAccessFlags = Request::ACQUIRE; 108 } 109}}; 110 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) 115 { 116 %(constructor)s; 117 flags[IsLastMicroop] = true; 118 flags[IsNonSpeculative] = true; 119 if (RL) 120 memAccessFlags = Request::RELEASE; 121 } 122}}; 123 124def template StoreCondExecute {{ 125 Fault %(class_name)s::execute(ExecContext *xc, 126 Trace::InstRecord *traceData) const 127 { 128 Addr EA; 129 Fault fault = NoFault; 130 uint64_t result; 131 132 %(op_decl)s; 133 %(op_rd)s; 134 %(ea_code)s; 135 136 if (fault == NoFault) { 137 %(memacc_code)s; 138 } 139 140 if (fault == NoFault) { 141 fault = writeMemAtomic(xc, traceData, Mem, EA, memAccessFlags, 142 &result); 143 // RISC-V has the opposite convention gem5 has for success flags, 144 // so we invert the result here. 145 result = !result; 146 } 147 148 if (fault == NoFault) { 149 %(postacc_code)s; 150 } 151 152 if (fault == NoFault) { 153 %(op_wb)s; 154 } 155 156 return fault; 157 } 158}}; 159 160def template AtomicMemOpLoadExecute {{ 161 Fault %(class_name)s::%(class_name)sLoad::execute(ExecContext *xc, 162 Trace::InstRecord *traceData) const 163 { 164 Addr EA; 165 Fault fault = NoFault; 166 167 %(op_decl)s; 168 %(op_rd)s; 169 %(ea_code)s; 170 171 if (fault == NoFault) { 172 fault = readMemAtomic(xc, traceData, EA, Mem, memAccessFlags); 173 } 174 175 if (fault == NoFault) { 176 %(code)s; 177 } 178 179 if (fault == NoFault) { 180 %(op_wb)s; 181 } 182 183 return fault; 184 } 185}}; 186 187def template AtomicMemOpStoreExecute {{ 188 Fault %(class_name)s::%(class_name)sStore::execute(ExecContext *xc, 189 Trace::InstRecord *traceData) const 190 { 191 Addr EA; 192 Fault fault = NoFault; 193 194 %(op_decl)s; 195 %(op_rd)s; 196 %(ea_code)s; 197 198 if (fault == NoFault) { 199 %(code)s; 200 } 201 202 if (fault == NoFault) { 203 fault = writeMemAtomic(xc, traceData, Mem, EA, memAccessFlags, 204 nullptr); 205 } 206 207 if (fault == NoFault) { 208 %(op_wb)s; 209 } 210 211 return fault; 212 } 213}}; 214 215def template AtomicMemOpLoadInitiateAcc {{ 216 Fault %(class_name)s::%(class_name)sLoad::initiateAcc(ExecContext *xc, 217 Trace::InstRecord *traceData) const 218 { 219 Addr EA; 220 Fault fault = NoFault; 221 222 %(op_src_decl)s; 223 %(op_rd)s; 224 %(ea_code)s; 225 226 if (fault == NoFault) { 227 fault = initiateMemRead(xc, traceData, EA, Mem, memAccessFlags); 228 } 229 230 return fault; 231 } 232}}; 233 234def template AtomicMemOpStoreInitiateAcc {{ 235 Fault %(class_name)s::%(class_name)sStore::initiateAcc( 236 ExecContext *xc, Trace::InstRecord *traceData) const 237 { 238 Addr EA; 239 Fault fault = NoFault; 240 241 %(op_decl)s; 242 %(op_rd)s; 243 %(ea_code)s; 244 245 if (fault == NoFault) { 246 %(code)s; 247 } 248 249 if (fault == NoFault) { 250 fault = writeMemTiming(xc, traceData, Mem, EA, memAccessFlags, 251 nullptr); 252 } 253 254 if (fault == NoFault) { 255 %(op_wb)s; 256 } 257 258 return fault; 259 } 260}}; 261 262def template StoreCondCompleteAcc {{ 263 Fault %(class_name)s::completeAcc(Packet *pkt, ExecContext *xc, 264 Trace::InstRecord *traceData) const 265 { 266 Fault fault = NoFault; 267 268 %(op_dest_decl)s; 269 270 // RISC-V has the opposite convention gem5 has for success flags, 271 // so we invert the result here. 272 uint64_t result = !pkt->req->getExtraData(); 273 274 if (fault == NoFault) { 275 %(postacc_code)s; 276 } 277 278 if (fault == NoFault) { 279 %(op_wb)s; 280 } 281 282 return fault; 283 } 284}}; 285 286def template AtomicMemOpLoadCompleteAcc {{ 287 Fault %(class_name)s::%(class_name)sLoad::completeAcc(PacketPtr pkt, 288 ExecContext *xc, Trace::InstRecord *traceData) const 289 { 290 Fault fault = NoFault; 291 292 %(op_decl)s; 293 %(op_rd)s; 294 295 getMem(pkt, Mem, traceData); 296 297 if (fault == NoFault) { 298 %(code)s; 299 } 300 301 if (fault == NoFault) { 302 %(op_wb)s; 303 } 304 305 return fault; 306 } 307}}; 308 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}}; 316 317def format LoadReserved(memacc_code, postacc_code={{ }}, ea_code={{EA = Rs1;}}, 318 mem_flags=[], inst_flags=[]) {{ 319 mem_flags = makeList(mem_flags) 320 inst_flags = makeList(inst_flags) 321 iop = InstObjParams(name, Name, 'LoadReserved', 322 {'ea_code': ea_code, 'memacc_code': memacc_code, 323 'postacc_code': postacc_code}, inst_flags) 324 iop.constructor += '\n\tmemAccessFlags = memAccessFlags | ' + \ 325 '|'.join(['Request::%s' % flag for flag in mem_flags]) + ';' 326 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) 333}}; 334 335def format StoreCond(memacc_code, postacc_code={{ }}, ea_code={{EA = Rs1;}}, 336 mem_flags=[], inst_flags=[]) {{ 337 mem_flags = makeList(mem_flags) 338 inst_flags = makeList(inst_flags) 339 iop = InstObjParams(name, Name, 'StoreCond', 340 {'ea_code': ea_code, 'memacc_code': memacc_code, 341 'postacc_code': postacc_code}, inst_flags) 342 iop.constructor += '\n\tmemAccessFlags = memAccessFlags | ' + \ 343 '|'.join(['Request::%s' % flag for flag in mem_flags]) + ';' 344 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) \ 350 + StoreCondCompleteAcc.subst(iop) 351}}; 352 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) 356 header_output = AtomicMemOpDeclare.subst(macro_iop) 357 decoder_output = AtomicMemOpMacroConstructor.subst(macro_iop) 358 decode_block = BasicDecode.subst(macro_iop) 359 exec_output = '' 360 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) 369 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) 378}}; 379