205 } 206 return fault; 207 } 208}}; 209 210def template MicroStoreCompleteAcc {{ 211 Fault %(class_name)s::completeAcc(PacketPtr pkt, 212 %(CPU_exec_context)s * xc, Trace::InstRecord * traceData) const 213 { 214 %(op_decl)s; 215 %(op_rd)s; 216 %(complete_code)s; 217 %(op_wb)s; 218 return NoFault; 219 } 220}}; 221 222// Common templates 223 224//This delcares the initiateAcc function in memory operations 225def template InitiateAccDeclare {{ 226 Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; 227}}; 228 229//This declares the completeAcc function in memory operations 230def template CompleteAccDeclare {{ 231 Fault completeAcc(PacketPtr, %(CPU_exec_context)s *, Trace::InstRecord *) const; 232}}; 233 234def template MicroLdStOpDeclare {{ 235 class %(class_name)s : public %(base_class)s 236 { 237 public: 238 %(class_name)s(ExtMachInst _machInst, 239 const char * instMnem, uint64_t setFlags, 240 uint8_t _scale, InstRegIndex _index, InstRegIndex _base, 241 uint64_t _disp, InstRegIndex _segment, 242 InstRegIndex _data, 243 uint8_t _dataSize, uint8_t _addressSize, 244 Request::FlagsType _memFlags); 245 246 %(BasicExecDeclare)s 247 248 %(InitiateAccDeclare)s 249 250 %(CompleteAccDeclare)s 251 }; 252}}; 253 254def template MicroLdStOpConstructor {{ 255 inline %(class_name)s::%(class_name)s( 256 ExtMachInst machInst, const char * instMnem, uint64_t setFlags, 257 uint8_t _scale, InstRegIndex _index, InstRegIndex _base, 258 uint64_t _disp, InstRegIndex _segment, 259 InstRegIndex _data, 260 uint8_t _dataSize, uint8_t _addressSize, 261 Request::FlagsType _memFlags) : 262 %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags, 263 _scale, _index, _base, 264 _disp, _segment, _data, 265 _dataSize, _addressSize, _memFlags, %(op_class)s) 266 { 267 %(constructor)s; 268 } 269}}; 270 271let {{ 272 class LdStOp(X86Microop): 273 def __init__(self, data, segment, addr, disp, 274 dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec): 275 self.data = data 276 [self.scale, self.index, self.base] = addr 277 self.disp = disp 278 self.segment = segment 279 self.dataSize = dataSize 280 self.addressSize = addressSize 281 self.memFlags = baseFlags 282 if atCPL0: 283 self.memFlags += " | (CPL0FlagBit << FlagShift)" 284 self.instFlags = "" 285 if prefetch: 286 self.memFlags += " | Request::PREFETCH" 287 self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)" 288 if nonSpec: 289 self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)" 290 self.memFlags += " | (machInst.legacy.addr ? " + \ 291 "(AddrSizeFlagBit << FlagShift) : 0)" 292 293 def getAllocator(self, microFlags): 294 allocator = '''new %(class_name)s(machInst, macrocodeBlock, 295 %(flags)s, %(scale)s, %(index)s, %(base)s, 296 %(disp)s, %(segment)s, %(data)s, 297 %(dataSize)s, %(addressSize)s, %(memFlags)s)''' % { 298 "class_name" : self.className, 299 "flags" : self.microFlagsText(microFlags) + self.instFlags, 300 "scale" : self.scale, "index" : self.index, 301 "base" : self.base, 302 "disp" : self.disp, 303 "segment" : self.segment, "data" : self.data, 304 "dataSize" : self.dataSize, "addressSize" : self.addressSize, 305 "memFlags" : self.memFlags} 306 return allocator 307 308 class BigLdStOp(X86Microop): 309 def __init__(self, data, segment, addr, disp, 310 dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec): 311 self.data = data 312 [self.scale, self.index, self.base] = addr 313 self.disp = disp 314 self.segment = segment 315 self.dataSize = dataSize 316 self.addressSize = addressSize 317 self.memFlags = baseFlags 318 if atCPL0: 319 self.memFlags += " | (CPL0FlagBit << FlagShift)" 320 self.instFlags = "" 321 if prefetch: 322 self.memFlags += " | Request::PREFETCH" 323 self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)" 324 if nonSpec: 325 self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)" 326 self.memFlags += " | (machInst.legacy.addr ? " + \ 327 "(AddrSizeFlagBit << FlagShift) : 0)" 328 329 def getAllocator(self, microFlags): 330 allocString = ''' 331 (%(dataSize)s >= 4) ? 332 (StaticInstPtr)(new %(class_name)sBig(machInst, 333 macrocodeBlock, %(flags)s, %(scale)s, %(index)s, 334 %(base)s, %(disp)s, %(segment)s, %(data)s, 335 %(dataSize)s, %(addressSize)s, %(memFlags)s)) : 336 (StaticInstPtr)(new %(class_name)s(machInst, 337 macrocodeBlock, %(flags)s, %(scale)s, %(index)s, 338 %(base)s, %(disp)s, %(segment)s, %(data)s, 339 %(dataSize)s, %(addressSize)s, %(memFlags)s)) 340 ''' 341 allocator = allocString % { 342 "class_name" : self.className, 343 "flags" : self.microFlagsText(microFlags) + self.instFlags, 344 "scale" : self.scale, "index" : self.index, 345 "base" : self.base, 346 "disp" : self.disp, 347 "segment" : self.segment, "data" : self.data, 348 "dataSize" : self.dataSize, "addressSize" : self.addressSize, 349 "memFlags" : self.memFlags} 350 return allocator 351}}; 352 353let {{ 354 355 # Make these empty strings so that concatenating onto 356 # them will always work. 357 header_output = "" 358 decoder_output = "" 359 exec_output = "" 360 361 calculateEA = ''' 362 EA = bits(SegBase + scale * Index + Base + disp, addressSize * 8 - 1, 0); 363 ''' 364 365 def defineMicroLoadOp(mnemonic, code, bigCode='', 366 mem_flags="0", big=True): 367 global header_output 368 global decoder_output 369 global exec_output 370 global microopClasses 371 Name = mnemonic 372 name = mnemonic.lower() 373 374 # Build up the all register version of this micro op 375 iops = [InstObjParams(name, Name, 'X86ISA::LdStOp', 376 {"code": code, "ea_code": calculateEA})] 377 if big: 378 iops += [InstObjParams(name, Name + "Big", 'X86ISA::LdStOp', 379 {"code": bigCode, "ea_code": calculateEA})] 380 for iop in iops: 381 header_output += MicroLdStOpDeclare.subst(iop) 382 decoder_output += MicroLdStOpConstructor.subst(iop) 383 exec_output += MicroLoadExecute.subst(iop) 384 exec_output += MicroLoadInitiateAcc.subst(iop) 385 exec_output += MicroLoadCompleteAcc.subst(iop) 386 387 base = LdStOp 388 if big: 389 base = BigLdStOp 390 class LoadOp(base): 391 def __init__(self, data, segment, addr, disp = 0, 392 dataSize="env.dataSize", 393 addressSize="env.addressSize", 394 atCPL0=False, prefetch=False, nonSpec=False): 395 super(LoadOp, self).__init__(data, segment, addr, 396 disp, dataSize, addressSize, mem_flags, 397 atCPL0, prefetch, nonSpec) 398 self.className = Name 399 self.mnemonic = name 400 401 microopClasses[name] = LoadOp 402 403 defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);', 404 'Data = Mem & mask(dataSize * 8);') 405 defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);', 406 'Data = Mem & mask(dataSize * 8);', 407 '(StoreCheck << FlagShift)') 408 defineMicroLoadOp('Ldstl', 'Data = merge(Data, Mem, dataSize);', 409 'Data = Mem & mask(dataSize * 8);', 410 '(StoreCheck << FlagShift) | Request::LOCKED') 411 defineMicroLoadOp('Ldfp', 'FpData.uqw = Mem;', big = False) 412 413 def defineMicroStoreOp(mnemonic, code, completeCode="", mem_flags="0"): 414 global header_output 415 global decoder_output 416 global exec_output 417 global microopClasses 418 Name = mnemonic 419 name = mnemonic.lower() 420 421 # Build up the all register version of this micro op 422 iop = InstObjParams(name, Name, 'X86ISA::LdStOp', 423 {"code": code, 424 "complete_code": completeCode, 425 "ea_code": calculateEA}) 426 header_output += MicroLdStOpDeclare.subst(iop) 427 decoder_output += MicroLdStOpConstructor.subst(iop) 428 exec_output += MicroStoreExecute.subst(iop) 429 exec_output += MicroStoreInitiateAcc.subst(iop) 430 exec_output += MicroStoreCompleteAcc.subst(iop) 431 432 class StoreOp(LdStOp): 433 def __init__(self, data, segment, addr, disp = 0, 434 dataSize="env.dataSize", 435 addressSize="env.addressSize", 436 atCPL0=False, nonSpec=False): 437 super(StoreOp, self).__init__(data, segment, addr, disp, 438 dataSize, addressSize, mem_flags, atCPL0, False, 439 nonSpec) 440 self.className = Name 441 self.mnemonic = name 442 443 microopClasses[name] = StoreOp 444 445 defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);') 446 defineMicroStoreOp('Stul', 'Mem = pick(Data, 2, dataSize);', 447 mem_flags="Request::LOCKED") 448 defineMicroStoreOp('Stfp', 'Mem = FpData.uqw;') 449 defineMicroStoreOp('Cda', 'Mem = 0;', mem_flags="Request::NO_ACCESS") 450 451 iop = InstObjParams("lea", "Lea", 'X86ISA::LdStOp', 452 {"code": "Data = merge(Data, EA, dataSize);", 453 "ea_code": ''' 454 EA = bits(scale * Index + Base + disp, addressSize * 8 - 1, 0); 455 '''}) 456 header_output += MicroLeaDeclare.subst(iop) 457 decoder_output += MicroLdStOpConstructor.subst(iop) 458 exec_output += MicroLeaExecute.subst(iop) 459 460 class LeaOp(LdStOp): 461 def __init__(self, data, segment, addr, disp = 0, 462 dataSize="env.dataSize", addressSize="env.addressSize"): 463 super(LeaOp, self).__init__(data, segment, addr, disp, 464 dataSize, addressSize, "0", False, False, False) 465 self.className = "Lea" 466 self.mnemonic = "lea" 467 468 microopClasses["lea"] = LeaOp 469 470 471 iop = InstObjParams("tia", "Tia", 'X86ISA::LdStOp', 472 {"code": "xc->demapPage(EA, 0);", 473 "ea_code": calculateEA}) 474 header_output += MicroLeaDeclare.subst(iop) 475 decoder_output += MicroLdStOpConstructor.subst(iop) 476 exec_output += MicroLeaExecute.subst(iop) 477 478 class TiaOp(LdStOp): 479 def __init__(self, segment, addr, disp = 0, 480 dataSize="env.dataSize", 481 addressSize="env.addressSize"): 482 super(TiaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment, 483 addr, disp, dataSize, addressSize, "0", False, False, 484 False) 485 self.className = "Tia" 486 self.mnemonic = "tia" 487 488 microopClasses["tia"] = TiaOp 489 490 class CdaOp(LdStOp): 491 def __init__(self, segment, addr, disp = 0, 492 dataSize="env.dataSize", 493 addressSize="env.addressSize", atCPL0=False): 494 super(CdaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment, 495 addr, disp, dataSize, addressSize, "Request::NO_ACCESS", 496 atCPL0, False, False) 497 self.className = "Cda" 498 self.mnemonic = "cda" 499 500 microopClasses["cda"] = CdaOp 501}}; 502
| 207 } 208 return fault; 209 } 210}}; 211 212def template MicroStoreCompleteAcc {{ 213 Fault %(class_name)s::completeAcc(PacketPtr pkt, 214 %(CPU_exec_context)s * xc, Trace::InstRecord * traceData) const 215 { 216 %(op_decl)s; 217 %(op_rd)s; 218 %(complete_code)s; 219 %(op_wb)s; 220 return NoFault; 221 } 222}}; 223 224// Common templates 225 226//This delcares the initiateAcc function in memory operations 227def template InitiateAccDeclare {{ 228 Fault initiateAcc(%(CPU_exec_context)s *, Trace::InstRecord *) const; 229}}; 230 231//This declares the completeAcc function in memory operations 232def template CompleteAccDeclare {{ 233 Fault completeAcc(PacketPtr, %(CPU_exec_context)s *, Trace::InstRecord *) const; 234}}; 235 236def template MicroLdStOpDeclare {{ 237 class %(class_name)s : public %(base_class)s 238 { 239 public: 240 %(class_name)s(ExtMachInst _machInst, 241 const char * instMnem, uint64_t setFlags, 242 uint8_t _scale, InstRegIndex _index, InstRegIndex _base, 243 uint64_t _disp, InstRegIndex _segment, 244 InstRegIndex _data, 245 uint8_t _dataSize, uint8_t _addressSize, 246 Request::FlagsType _memFlags); 247 248 %(BasicExecDeclare)s 249 250 %(InitiateAccDeclare)s 251 252 %(CompleteAccDeclare)s 253 }; 254}}; 255 256def template MicroLdStOpConstructor {{ 257 inline %(class_name)s::%(class_name)s( 258 ExtMachInst machInst, const char * instMnem, uint64_t setFlags, 259 uint8_t _scale, InstRegIndex _index, InstRegIndex _base, 260 uint64_t _disp, InstRegIndex _segment, 261 InstRegIndex _data, 262 uint8_t _dataSize, uint8_t _addressSize, 263 Request::FlagsType _memFlags) : 264 %(base_class)s(machInst, "%(mnemonic)s", instMnem, setFlags, 265 _scale, _index, _base, 266 _disp, _segment, _data, 267 _dataSize, _addressSize, _memFlags, %(op_class)s) 268 { 269 %(constructor)s; 270 } 271}}; 272 273let {{ 274 class LdStOp(X86Microop): 275 def __init__(self, data, segment, addr, disp, 276 dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec): 277 self.data = data 278 [self.scale, self.index, self.base] = addr 279 self.disp = disp 280 self.segment = segment 281 self.dataSize = dataSize 282 self.addressSize = addressSize 283 self.memFlags = baseFlags 284 if atCPL0: 285 self.memFlags += " | (CPL0FlagBit << FlagShift)" 286 self.instFlags = "" 287 if prefetch: 288 self.memFlags += " | Request::PREFETCH" 289 self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)" 290 if nonSpec: 291 self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)" 292 self.memFlags += " | (machInst.legacy.addr ? " + \ 293 "(AddrSizeFlagBit << FlagShift) : 0)" 294 295 def getAllocator(self, microFlags): 296 allocator = '''new %(class_name)s(machInst, macrocodeBlock, 297 %(flags)s, %(scale)s, %(index)s, %(base)s, 298 %(disp)s, %(segment)s, %(data)s, 299 %(dataSize)s, %(addressSize)s, %(memFlags)s)''' % { 300 "class_name" : self.className, 301 "flags" : self.microFlagsText(microFlags) + self.instFlags, 302 "scale" : self.scale, "index" : self.index, 303 "base" : self.base, 304 "disp" : self.disp, 305 "segment" : self.segment, "data" : self.data, 306 "dataSize" : self.dataSize, "addressSize" : self.addressSize, 307 "memFlags" : self.memFlags} 308 return allocator 309 310 class BigLdStOp(X86Microop): 311 def __init__(self, data, segment, addr, disp, 312 dataSize, addressSize, baseFlags, atCPL0, prefetch, nonSpec): 313 self.data = data 314 [self.scale, self.index, self.base] = addr 315 self.disp = disp 316 self.segment = segment 317 self.dataSize = dataSize 318 self.addressSize = addressSize 319 self.memFlags = baseFlags 320 if atCPL0: 321 self.memFlags += " | (CPL0FlagBit << FlagShift)" 322 self.instFlags = "" 323 if prefetch: 324 self.memFlags += " | Request::PREFETCH" 325 self.instFlags += " | (1ULL << StaticInst::IsDataPrefetch)" 326 if nonSpec: 327 self.instFlags += " | (1ULL << StaticInst::IsNonSpeculative)" 328 self.memFlags += " | (machInst.legacy.addr ? " + \ 329 "(AddrSizeFlagBit << FlagShift) : 0)" 330 331 def getAllocator(self, microFlags): 332 allocString = ''' 333 (%(dataSize)s >= 4) ? 334 (StaticInstPtr)(new %(class_name)sBig(machInst, 335 macrocodeBlock, %(flags)s, %(scale)s, %(index)s, 336 %(base)s, %(disp)s, %(segment)s, %(data)s, 337 %(dataSize)s, %(addressSize)s, %(memFlags)s)) : 338 (StaticInstPtr)(new %(class_name)s(machInst, 339 macrocodeBlock, %(flags)s, %(scale)s, %(index)s, 340 %(base)s, %(disp)s, %(segment)s, %(data)s, 341 %(dataSize)s, %(addressSize)s, %(memFlags)s)) 342 ''' 343 allocator = allocString % { 344 "class_name" : self.className, 345 "flags" : self.microFlagsText(microFlags) + self.instFlags, 346 "scale" : self.scale, "index" : self.index, 347 "base" : self.base, 348 "disp" : self.disp, 349 "segment" : self.segment, "data" : self.data, 350 "dataSize" : self.dataSize, "addressSize" : self.addressSize, 351 "memFlags" : self.memFlags} 352 return allocator 353}}; 354 355let {{ 356 357 # Make these empty strings so that concatenating onto 358 # them will always work. 359 header_output = "" 360 decoder_output = "" 361 exec_output = "" 362 363 calculateEA = ''' 364 EA = bits(SegBase + scale * Index + Base + disp, addressSize * 8 - 1, 0); 365 ''' 366 367 def defineMicroLoadOp(mnemonic, code, bigCode='', 368 mem_flags="0", big=True): 369 global header_output 370 global decoder_output 371 global exec_output 372 global microopClasses 373 Name = mnemonic 374 name = mnemonic.lower() 375 376 # Build up the all register version of this micro op 377 iops = [InstObjParams(name, Name, 'X86ISA::LdStOp', 378 {"code": code, "ea_code": calculateEA})] 379 if big: 380 iops += [InstObjParams(name, Name + "Big", 'X86ISA::LdStOp', 381 {"code": bigCode, "ea_code": calculateEA})] 382 for iop in iops: 383 header_output += MicroLdStOpDeclare.subst(iop) 384 decoder_output += MicroLdStOpConstructor.subst(iop) 385 exec_output += MicroLoadExecute.subst(iop) 386 exec_output += MicroLoadInitiateAcc.subst(iop) 387 exec_output += MicroLoadCompleteAcc.subst(iop) 388 389 base = LdStOp 390 if big: 391 base = BigLdStOp 392 class LoadOp(base): 393 def __init__(self, data, segment, addr, disp = 0, 394 dataSize="env.dataSize", 395 addressSize="env.addressSize", 396 atCPL0=False, prefetch=False, nonSpec=False): 397 super(LoadOp, self).__init__(data, segment, addr, 398 disp, dataSize, addressSize, mem_flags, 399 atCPL0, prefetch, nonSpec) 400 self.className = Name 401 self.mnemonic = name 402 403 microopClasses[name] = LoadOp 404 405 defineMicroLoadOp('Ld', 'Data = merge(Data, Mem, dataSize);', 406 'Data = Mem & mask(dataSize * 8);') 407 defineMicroLoadOp('Ldst', 'Data = merge(Data, Mem, dataSize);', 408 'Data = Mem & mask(dataSize * 8);', 409 '(StoreCheck << FlagShift)') 410 defineMicroLoadOp('Ldstl', 'Data = merge(Data, Mem, dataSize);', 411 'Data = Mem & mask(dataSize * 8);', 412 '(StoreCheck << FlagShift) | Request::LOCKED') 413 defineMicroLoadOp('Ldfp', 'FpData.uqw = Mem;', big = False) 414 415 def defineMicroStoreOp(mnemonic, code, completeCode="", mem_flags="0"): 416 global header_output 417 global decoder_output 418 global exec_output 419 global microopClasses 420 Name = mnemonic 421 name = mnemonic.lower() 422 423 # Build up the all register version of this micro op 424 iop = InstObjParams(name, Name, 'X86ISA::LdStOp', 425 {"code": code, 426 "complete_code": completeCode, 427 "ea_code": calculateEA}) 428 header_output += MicroLdStOpDeclare.subst(iop) 429 decoder_output += MicroLdStOpConstructor.subst(iop) 430 exec_output += MicroStoreExecute.subst(iop) 431 exec_output += MicroStoreInitiateAcc.subst(iop) 432 exec_output += MicroStoreCompleteAcc.subst(iop) 433 434 class StoreOp(LdStOp): 435 def __init__(self, data, segment, addr, disp = 0, 436 dataSize="env.dataSize", 437 addressSize="env.addressSize", 438 atCPL0=False, nonSpec=False): 439 super(StoreOp, self).__init__(data, segment, addr, disp, 440 dataSize, addressSize, mem_flags, atCPL0, False, 441 nonSpec) 442 self.className = Name 443 self.mnemonic = name 444 445 microopClasses[name] = StoreOp 446 447 defineMicroStoreOp('St', 'Mem = pick(Data, 2, dataSize);') 448 defineMicroStoreOp('Stul', 'Mem = pick(Data, 2, dataSize);', 449 mem_flags="Request::LOCKED") 450 defineMicroStoreOp('Stfp', 'Mem = FpData.uqw;') 451 defineMicroStoreOp('Cda', 'Mem = 0;', mem_flags="Request::NO_ACCESS") 452 453 iop = InstObjParams("lea", "Lea", 'X86ISA::LdStOp', 454 {"code": "Data = merge(Data, EA, dataSize);", 455 "ea_code": ''' 456 EA = bits(scale * Index + Base + disp, addressSize * 8 - 1, 0); 457 '''}) 458 header_output += MicroLeaDeclare.subst(iop) 459 decoder_output += MicroLdStOpConstructor.subst(iop) 460 exec_output += MicroLeaExecute.subst(iop) 461 462 class LeaOp(LdStOp): 463 def __init__(self, data, segment, addr, disp = 0, 464 dataSize="env.dataSize", addressSize="env.addressSize"): 465 super(LeaOp, self).__init__(data, segment, addr, disp, 466 dataSize, addressSize, "0", False, False, False) 467 self.className = "Lea" 468 self.mnemonic = "lea" 469 470 microopClasses["lea"] = LeaOp 471 472 473 iop = InstObjParams("tia", "Tia", 'X86ISA::LdStOp', 474 {"code": "xc->demapPage(EA, 0);", 475 "ea_code": calculateEA}) 476 header_output += MicroLeaDeclare.subst(iop) 477 decoder_output += MicroLdStOpConstructor.subst(iop) 478 exec_output += MicroLeaExecute.subst(iop) 479 480 class TiaOp(LdStOp): 481 def __init__(self, segment, addr, disp = 0, 482 dataSize="env.dataSize", 483 addressSize="env.addressSize"): 484 super(TiaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment, 485 addr, disp, dataSize, addressSize, "0", False, False, 486 False) 487 self.className = "Tia" 488 self.mnemonic = "tia" 489 490 microopClasses["tia"] = TiaOp 491 492 class CdaOp(LdStOp): 493 def __init__(self, segment, addr, disp = 0, 494 dataSize="env.dataSize", 495 addressSize="env.addressSize", atCPL0=False): 496 super(CdaOp, self).__init__("InstRegIndex(NUM_INTREGS)", segment, 497 addr, disp, dataSize, addressSize, "Request::NO_ACCESS", 498 atCPL0, False, False) 499 self.className = "Cda" 500 self.mnemonic = "cda" 501 502 microopClasses["cda"] = CdaOp 503}}; 504
|