amo64.isa revision 14150:1391e94a7b95
1// -*- mode:c++ -*- 2 3// Copyright (c) 2018 Metempsy Technology Consulting 4// All rights reserved 5// 6// The license below extends only to copyright in the software and shall 7// not be construed as granting a license to any other intellectual 8// property including but not limited to intellectual property relating 9// to a hardware implementation of the functionality of the software 10// licensed hereunder. You may use the software subject to the license 11// terms below provided that you ensure that this notice is replicated 12// unmodified and in its entirety in all distributions of the software, 13// modified or unmodified, in source code or in binary form. 14// 15// Redistribution and use in source and binary forms, with or without 16// modification, are permitted provided that the following conditions are 17// met: redistributions of source code must retain the above copyright 18// notice, this list of conditions and the following disclaimer; 19// redistributions in binary form must reproduce the above copyright 20// notice, this list of conditions and the following disclaimer in the 21// documentation and/or other materials provided with the distribution; 22// neither the name of the copyright holders nor the names of its 23// contributors may be used to endorse or promote products derived from 24// this software without specific prior written permission. 25// 26// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 29// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 31// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 32// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37// 38// Authors: Jordi Vaquero 39 40let {{ 41 42 import math 43 44 OP_DICT = { "CAS" : 'if (a == *b){*b = c;}', 45 "SWP" : '*b = c;', 46 "ADD" : '*b += c;', 47 "EOR" : '*b ^= c;', 48 "CLR" : '*b &= ~c;', 49 "SET" : '*b |= c;', 50 "MAX" : '*b = std::max(*b, c);', 51 "MIN" : '*b = std::min(*b, c);', } 52 53 MASKS = { 1: 0xFF, 54 2: 0xFFFF, 55 4: 0xFFFFFFFF, 56 8: 0xFFFFFFFFFFFFFFFF, 57 } 58 59 header_output = "" 60 decoder_output = "" 61 exec_output = "" 62 63 class AtomicInst64(LoadStoreInst): 64 execBase = 'AtomicInst64' 65 micro = False 66 67 def __init__(self, mnem, Name, size=4, user=False, flavor="normal", 68 unsign=True, top = False, paired=False): 69 super(AtomicInst64, self).__init__() 70 71 self.name= mnem 72 self.Name = Name 73 self.size = size 74 self.user = user 75 self.flavor = flavor 76 self.unsign = unsign 77 self.top = top 78 self.paired = paired 79 80 self.memFlags = ["ArmISA::TLB::MustBeOne"] 81 self.instFlags = ["IsAtomic"] 82 self.codeBlobs = { "postacc_code" : "" } 83 self.codeBlobs['usrDecl'] = "" 84 85 # Add memory request flags where necessary 86 if self.user: 87 self.memFlags.append("ArmISA::TLB::UserMode") 88 89 sz = self.size*2 if paired else self.size 90 self.memFlags.append("%d" % int(math.log(sz, 2))) 91 92 if self.micro: 93 self.instFlags.append("IsMicroop") 94 95 if self.flavor in ("release", "acquire_release", "acquire"): 96 self.instFlags.append("IsMemBarrier") 97 if self.flavor in ("release", "acquire_release"): 98 self.instFlags.append("IsWriteBarrier") 99 if self.flavor in ("acquire_release", "acquire"): 100 self.instFlags.append("IsReadBarrier") 101 self.memFlags.append('Request::ATOMIC_RETURN_OP') 102 103 def emitHelper(self, base = 'Memory64', wbDecl = None, ): 104 global header_output, decoder_output, exec_output 105 106 # If this is a microop itself, don't allow anything that would 107 # require further microcoding. 108 if self.micro: 109 assert not wbDecl 110 111 fa_code = None 112 if not self.micro : 113 #and self.flavor in ("normal", "release"): 114 fa_code = ''' 115 fault->annotate(ArmFault::SAS, %s); 116 fault->annotate(ArmFault::SSE, false); 117 fault->annotate(ArmFault::SRT, dest); 118 fault->annotate(ArmFault::SF, %s); 119 fault->annotate(ArmFault::AR, %s); 120 ''' % ("0" if self.size == 1 else 121 "1" if self.size == 2 else 122 "2" if self.size == 4 else "3", 123 "true" if self.size == 8 else "false", 124 "true" if self.flavor != "normal" else "false") 125 sas_code = "3" 126 if self.size == 1 : 127 sas_code = "0" 128 elif self.size == 2: 129 sas_code = "1" 130 elif self.size == 4: 131 sas_code = "2" 132 133 if self.paired and sas_code == "3": 134 sas_code = "4" 135 if self.paired and sas_code == "2": 136 sas_code = "3" 137 138 139 fa_code = ''' 140 fault->annotate(ArmFault::SAS, %s); 141 fault->annotate(ArmFault::SSE, %s); 142 fault->annotate(ArmFault::SRT, dest); 143 fault->annotate(ArmFault::SF, %s); 144 fault->annotate(ArmFault::AR, %s); 145 ''' % (sas_code, 146 "true" if not self.unsign else "false", 147 "true" if self.size == 8 else "false", 148 "true" if self.flavor != "normal" else "false") 149 150 (newHeader, newDecoder, newExec) = \ 151 self.fillTemplates(self.name, self.Name, self.codeBlobs, 152 self.memFlags, self.instFlags, 153 base, wbDecl, faCode=fa_code) 154 155 header_output += newHeader 156 decoder_output += newDecoder 157 exec_output += newExec 158 159 def buildEACode(self): 160 # Address computation 161 eaCode = SPAlignmentCheckCode + "EA = XBase" 162 if self.size == 16: 163 if self.top: 164 eaCode += " + (isBigEndian64(xc->tcBase()) ? 0 : 8)" 165 else: 166 eaCode += " + (isBigEndian64(xc->tcBase()) ? 8 : 0)" 167 if not self.post: 168 eaCode += self.offset 169 eaCode += ";" 170 self.codeBlobs["ea_code"] = eaCode 171 172 173 class AtomicSingleOp(AtomicInst64): 174 decConstBase = 'AmoOp' 175 base = 'ArmISA::MemoryEx64' 176 writeback = True 177 post = False 178 execBase = 'AmoOp' 179 180 def __init__(self, *args, **kargs): 181 super(AtomicSingleOp, self).__init__(*args, **kargs) 182 self.suffix = buildMemSuffix(not self.unsign, self.size) 183 if self.size == 8: 184 self.res = 'XResult_ud' #if self.unsign else 'XResult_sd' 185 self.des = 'XDest_ud' #if self.unsign else 'XDest_sd' 186 self.tp = 'uint64_t' if self.unsign else 'int64_t' 187 self.utp = 'uint64_t' 188 self.suffix = '_sd' if not self.unsign else '_ud' 189 elif self.size == 4: 190 self.res = 'XResult_uw' #if self.unsign else 'XResult_sw' 191 self.des = 'XDest_uw' #if self.unsign else 'XDest_sw' 192 self.tp = 'uint32_t' if self.unsign else 'int32_t' 193 self.utp = 'uint32_t' 194 elif self.size == 2: 195 self.res = 'XResult_uh' #if self.unsign else 'XResult_sh' 196 self.des = 'XDest_uh' #if self.unsign else 'XDest_sh' 197 self.tp = 'uint16_t' if self.unsign else 'int16_t' 198 self.utp = 'uint16_t' 199 elif self.size == 1: 200 self.res = 'XResult_ub' #if self.unsign else 'XResult_sb' 201 self.des = 'XDest_ub' #if self.unsign else 'XDest_sb' 202 self.tp = 'uint8_t' if self.unsign else 'int8_t' 203 self.utp = 'uint8_t' 204 self.offset = "" 205 store_res = ''' 206 %(result)s = cSwap(Mem%(suffix)s, 207 isBigEndian64(xc->tcBase())); 208 ''' 209 store_res = store_res % {"result":self.res, "suffix":self.suffix} 210 self.codeBlobs["postacc_code"] = \ 211 store_res + " SevMailbox = 1; LLSCLock = 0;" 212 213 def emit(self, op): 214 self.buildEACode() 215 usrDecl = "%(type)s valRs;\n" % {'type': self.tp} 216 self.codeBlobs['usrDecl'] = usrDecl 217 218 opcode = "valRs = cSwap(%(dest)s,"\ 219 " isBigEndian64(xc->tcBase()));\n" 220 opcode += "TypedAtomicOpFunctor<%(type)s> *amo_op = "\ 221 "new AtomicGeneric3Op<%(type)s>(Mem%(suffix)s,"\ 222 " valRs, [](%(type)s* b, %(type)s a,"\ 223 " %(type)s c){ %(op)s });\n" 224 225 opcode = opcode % {"suffix": self.suffix, 226 "type": self.tp , 227 "dest": self.des, 228 "op": op} 229 self.codeBlobs['amo_code'] = opcode 230 accCode = "Mem%(suffix)s = cSwap(%(result)s,"\ 231 " isBigEndian64(xc->tcBase()));" 232 accCode = accCode % { "result": self.res, "type":self.tp, 233 "suffix": self.suffix} 234 self.codeBlobs["memacc_code"] = accCode 235 self.emitHelper(self.base) 236 237 238 AtomicSingleOp("cas", "CAS64", 8, unsign=True, 239 flavor="normal").emit(OP_DICT['CAS']) 240 AtomicSingleOp("casa", "CASA64", 8, unsign=True, 241 flavor="acquire").emit(OP_DICT['CAS']) 242 AtomicSingleOp("casal", "CASAL64", 8, unsign=True, 243 flavor="acquire_release").emit(OP_DICT['CAS']) 244 AtomicSingleOp("casl", "CASL64", 8, unsign=True, 245 flavor="release").emit(OP_DICT['CAS']) 246 247 AtomicSingleOp("casb", "CASB", 1, unsign=True, 248 flavor="normal").emit(OP_DICT['CAS']) 249 AtomicSingleOp("casab", "CASAB", 1, unsign=True, 250 flavor="acquire").emit(OP_DICT['CAS']) 251 AtomicSingleOp("casalb", "CASALB", 1, unsign=True, 252 flavor="acquire_release").emit(OP_DICT['CAS']) 253 AtomicSingleOp("caslb", "CASLB", 1, unsign=True, 254 flavor="release").emit(OP_DICT['CAS']) 255 256 AtomicSingleOp("cash", "CASH", 2, unsign=True, 257 flavor="normal").emit(OP_DICT['CAS']) 258 AtomicSingleOp("casah", "CASAH", 2, unsign=True, 259 flavor="acquire").emit(OP_DICT['CAS']) 260 AtomicSingleOp("casalh", "CASALH", 2, unsign=True, 261 flavor="acquire_release").emit(OP_DICT['CAS']) 262 AtomicSingleOp("caslh", "CASLH", 2, unsign=True, 263 flavor="release").emit(OP_DICT['CAS']) 264 265 AtomicSingleOp("cas", "CAS32", 4, unsign=True, 266 flavor="normal").emit(OP_DICT['CAS']) 267 AtomicSingleOp("casa", "CASA32", 4, unsign=True, 268 flavor="acquire").emit(OP_DICT['CAS']) 269 AtomicSingleOp("casal", "CASAL32", 4, unsign=True, 270 flavor="acquire_release").emit(OP_DICT['CAS']) 271 AtomicSingleOp("casl", "CASL32", 4, unsign=True, 272 flavor="release").emit(OP_DICT['CAS']) 273 274 class CasPair64(AtomicInst64): 275 decConstBase = 'AmoPairOp' 276 base = 'ArmISA::MemoryEx64' 277 writeback = True 278 post = False 279 execBase = 'AmoOp' 280 281 def __init__(self, *args, **kargs): 282 super(CasPair64, self).__init__(*args, **kargs) 283 self.paired = True 284 self.offset = "" 285 if self.size == 8: 286 self.res = 'XResult_ud' 287 self.des = 'XDest_ud' 288 self.tp = 'std::array<uint64_t, 2>' 289 self.suffix = "_tud" 290 store_res = ''' 291 %(result)s = cSwap(Mem%(suffix)s[0], 292 isBigEndian64(xc->tcBase())); 293 uint64_t result2 = cSwap(Mem%(suffix)s[1], 294 isBigEndian64(xc->tcBase())); 295 xc->setIntRegOperand(this, r2_dst, (result2) 296 & mask(aarch64 ? 64 : 32)); 297 ''' 298 elif self.size == 4: 299 self.res = 'Result_uw' 300 self.des = 'WDest_uw' 301 self.tp = 'uint64_t' 302 self.suffix = "_ud" 303 store_res = ''' 304 uint64_t data = cSwap(Mem%(suffix)s, 305 isBigEndian64(xc->tcBase())); 306 %(result)s = isBigEndian64(xc->tcBase()) 307 ? (data >> 32) 308 : (uint32_t)data; 309 uint32_t result2 = isBigEndian64(xc->tcBase()) 310 ? (uint32_t)data 311 : (data >> 32); 312 xc->setIntRegOperand(this, r2_dst, (result2) & 313 mask(aarch64 ? 64 : 32)); 314 ''' 315 316 store_res = store_res % {"result":self.res, "suffix":self.suffix} 317 usrDecl = "%(type)s valRs;\n" % {'type': self.tp} 318 self.codeBlobs['usrDecl'] = usrDecl 319 self.codeBlobs["postacc_code"] = \ 320 store_res + " SevMailbox = 1; LLSCLock = 0;" 321 322 def emit(self): 323 self.buildEACode() 324 325 # Code that actually handles the access 326 327 if self.size == 4: 328 accCode = \ 329 "uint32_t result2 = ((xc->readIntRegOperand(this, r2_src))"\ 330 " & mask(aarch64 ? 64 : 32)) ;\n"\ 331 " uint32_t dest2 = ((xc->readIntRegOperand(this, d2_src)) "\ 332 " & mask(aarch64 ? 64 : 32)) ;" 333 accCode += ''' 334 uint64_t data = dest2; 335 data = isBigEndian64(xc->tcBase()) 336 ? ((uint64_t(WDest_uw) << 32) | data) 337 : ((data << 32) | WDest_uw); 338 valRs = cSwap(data, isBigEndian64(xc->tcBase())); 339 uint64_t data2 = result2 ; 340 data2 = isBigEndian64(xc->tcBase()) 341 ? ((uint64_t(Result_uw) << 32) | data2) 342 : ((data2 << 32) | Result_uw); 343 Mem_ud = cSwap(data2, isBigEndian64(xc->tcBase())); 344 ''' 345 346 opcode = "TypedAtomicOpFunctor<%(type)s> *amo_op = "\ 347 "new AtomicGeneric3Op<%(type)s>(Mem%(suffix)s,"\ 348 " valRs, [](%(type)s* b, %(type)s a,"\ 349 " %(type)s c){ %(op)s });\n" 350 351 elif self.size == 8: 352 accCode = ""\ 353 "uint64_t result2 = ((xc->readIntRegOperand(this, r2_src))"\ 354 " & mask(aarch64 ? 64 : 32)) ;\n"\ 355 " uint64_t dest2 = ((xc->readIntRegOperand(this, d2_src)) "\ 356 " & mask(aarch64 ? 64 : 32)) ;" 357 accCode += ''' 358 // This temporary needs to be here so that the parser 359 // will correctly identify this instruction as a store. 360 std::array<uint64_t, 2> temp; 361 temp[0] = cSwap(XDest_ud,isBigEndian64(xc->tcBase())); 362 temp[1] = cSwap(dest2,isBigEndian64(xc->tcBase())); 363 valRs = temp; 364 std::array<uint64_t, 2> temp2; 365 temp2[0] = cSwap(XResult_ud,isBigEndian64(xc->tcBase())); 366 temp2[1] = cSwap(result2,isBigEndian64(xc->tcBase())); 367 Mem_tud = temp2; 368 ''' 369 370 opcode = "TypedAtomicOpFunctor<uint64_t> *amo_op = "\ 371 "new AtomicGenericPair3Op<uint64_t>(Mem_tud, "\ 372 "valRs, [](uint64_t* b, std::array<uint64_t,2> a,"\ 373 ''' 374 std::array<uint64_t,2> c){ 375 if(a[0]==b[0] && a[1]==b[1]){ 376 b[0] = c[0]; b[1] = c[1]; 377 } 378 });''' 379 380 opcode = opcode % { "suffix" : self.suffix, 381 "type": self.tp, 382 "op": OP_DICT['CAS']} 383 self.codeBlobs['amo_code'] = opcode 384 self.codeBlobs["memacc_code"] = accCode % {"type": self.tp} 385 386 # Push it out to the output files 387 self.emitHelper(self.base) 388 389 CasPair64("casp", "CASP64", 8, flavor="normal", paired=True).emit() 390 CasPair64("caspa", "CASPA64", 8, flavor="acquire", paired=True).emit() 391 CasPair64("caspal", "CASPAL64", 8, flavor="acquire_release", 392 paired=True).emit() 393 CasPair64("caspl", "CASPL64", 8, flavor="release", paired=True).emit() 394 395 CasPair64("casp", "CASP32", 4, flavor="normal", paired=True).emit() 396 CasPair64("caspa", "CASPA32", 4, flavor="acquire", paired=True).emit() 397 CasPair64("caspal", "CASPAL32", 4, flavor="acquire_release", 398 paired=True).emit() 399 CasPair64("caspl", "CASPL32", 4, flavor="release", paired=True).emit() 400 401}}; 402