%(fp_enable_check)s;
%(op_dest_decl)s;
- uint64_t write_result = pkt->req->getScResult();
+ uint64_t write_result = pkt->req->getExtraData();
if (fault == NoFault) {
%(postacc_code)s;
if (req->isUncacheable()) {
// Funky Turbolaser mailbox access...don't update
// result register (see stq_c in decoder.isa)
- req->setScResult(2);
+ req->setExtraData(2);
} else {
// standard store conditional
bool lock_flag = xc->readMiscReg(MISCREG_LOCKFLAG);
if (!lock_flag || (req->getPaddr() & ~0xf) != lock_addr) {
// Lock flag not set or addr mismatch in CPU;
// don't even bother sending to memory system
- req->setScResult(0);
+ req->setExtraData(0);
xc->setMiscReg(MISCREG_LOCKFLAG, false);
// the rest of this code is not architectural;
// it's just a debugging aid to help detect
typedef uint8_t RegIndex;
typedef uint64_t IntReg;
+ typedef uint64_t LargestRead;
// floating point register file entry type
typedef double FloatReg;
ctype = 'float'
elif size == 64:
ctype = 'double'
+ elif desc == 'twin int':
+ is_signed = 0
+ ctype = 'Twin64_t'
if ctype == '':
error(lineno, 'Unrecognized type description "%s" in userDict')
operandTypeMap[ext] = (size, ctype, is_signed)
# template must be careful not to use it if it doesn't apply.
if self.isMem():
self.mem_acc_size = self.makeAccSize()
- self.mem_acc_type = self.ctype
+ if self.ctype == 'Twin64_t':
+ self.mem_acc_type = 'Twin'
+ else:
+ self.mem_acc_type = 'uint'
# Finalize additional fields (primarily code fields). This step
# is done separately since some of these fields may depend on the
# Note that initializations in the declarations are solely
# to avoid 'uninitialized variable' errors from the compiler.
# Declare memory data variable.
+ if self.ctype == 'Twin64_t':
+ return "%s %s; %s.a = 0; %s.b = 0;\n" % (self.ctype, self.base_name,
+ self.base_name, self.base_name)
c = '%s %s = 0;\n' % (self.ctype, self.base_name)
return c
typedef uint8_t RegIndex;
typedef uint32_t IntReg;
+ typedef uint64_t LargestRead;
+
// floating point register file entry type
typedef uint32_t FloatReg32;
}});
//7-14 should cause an illegal instruction exception
0x0F: decode I {
- 0x0: Nop::stbar({{/*stuff*/}});
- 0x1: Nop::membar({{/*stuff*/}});
+ 0x0: Nop::stbar({{/*stuff*/}}, IsWriteBarrier, MemWriteOp);
+ 0x1: Nop::membar({{/*stuff*/}}, IsMemBarrier, MemReadOp);
}
0x10: Priv::rdpcr({{Rd = Pcr;}});
0x11: PrivCheck::rdpic({{Rd = Pic;}}, {{Pcr<0:>}});
0x0A: ldsh({{Rd = (int16_t)Mem.shw;}});
0x0B: ldx({{Rd = (int64_t)Mem.sdw;}});
}
- 0x0D: LoadStore::ldstub(
- {{uReg0 = Mem.ub;}},
- {{Rd.ub = uReg0;
- Mem.ub = 0xFF;}});
+ 0x0D: Swap::ldstub({{Mem.ub = 0xFF;}},
+ {{
+ uint8_t tmp = mem_data;
+ Rd.ub = tmp;
+ }}, MEM_SWAP);
0x0E: Store::stx({{Mem.udw = Rd}});
- 0x0F: LoadStore::swap(
- {{ uReg0 = Mem.uw}},
- {{ Mem.uw = Rd.uw;
- Rd.uw = uReg0;}});
+ 0x0F: Swap::swap({{Mem.uw = Rd.uw}},
+ {{
+ uint32_t tmp = mem_data;
+ Rd.uw = tmp;
+ }}, MEM_SWAP);
format LoadAlt {
0x10: lduwa({{Rd = Mem.uw;}}, {{EXT_ASI}});
0x11: lduba({{Rd = Mem.ub;}}, {{EXT_ASI}});
0x13: decode EXT_ASI {
//ASI_LDTD_AIUP
0x22: TwinLoad::ldtx_aiup(
- {{RdTwin.udw = Mem.udw;}}, {{EXT_ASI}});
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
//ASI_LDTD_AIUS
0x23: TwinLoad::ldtx_aius(
- {{RdTwin.udw = Mem.udw;}}, {{EXT_ASI}});
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
//ASI_QUAD_LDD
0x24: TwinLoad::ldtx_quad_ldd(
- {{RdTwin.udw = Mem.udw;}}, {{EXT_ASI}});
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
//ASI_LDTX_REAL
0x26: TwinLoad::ldtx_real(
- {{RdTwin.udw = Mem.udw;}}, {{EXT_ASI}});
- //ASI_LDTX_N
- 0x27: TwinLoad::ldtx_n(
- {{RdTwin.udw = Mem.udw;}}, {{EXT_ASI}});
- //ASI_LDTX_L
- 0x2C: TwinLoad::ldtx_l(
- {{RdTwin.udw = Mem.udw;}}, {{EXT_ASI}});
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
+ //ASI_LDTX_N
+ 0x27: TwinLoad::ldtx_n(
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
+ //ASI_LDTX_AIUP_L
+ 0x2A: TwinLoad::ldtx_aiup_l(
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
+ //ASI_LDTX_AIUS_L
+ 0x2B: TwinLoad::ldtx_aius_l(
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
+ //ASI_LDTX_L
+ 0x2C: TwinLoad::ldtx_l(
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
//ASI_LDTX_REAL_L
0x2E: TwinLoad::ldtx_real_l(
- {{RdTwin.udw = Mem.udw;}}, {{EXT_ASI}});
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
//ASI_LDTX_N_L
0x2F: TwinLoad::ldtx_n_l(
- {{RdTwin.udw = Mem.udw;}}, {{EXT_ASI}});
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
//ASI_LDTX_P
0xE2: TwinLoad::ldtx_p(
- {{RdTwin.udw = Mem.udw;}}, {{EXT_ASI}});
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
//ASI_LDTX_S
0xE3: TwinLoad::ldtx_s(
- {{RdTwin.udw = Mem.udw;}}, {{EXT_ASI}});
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
+ //ASI_LDTX_PL
+ 0xEA: TwinLoad::ldtx_pl(
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
+ //ASI_LDTX_SL
+ 0xEB: TwinLoad::ldtx_sl(
+ {{RdLow.udw = (Mem.tudw).a;
+ RdHigh.udw = (Mem.tudw).b;}}, {{EXT_ASI}});
default: ldtwa({{
uint64_t val = Mem.udw;
RdLow = val<31:0>;
0x1A: ldsha({{Rd = (int16_t)Mem.shw;}}, {{EXT_ASI}});
0x1B: ldxa({{Rd = (int64_t)Mem.sdw;}}, {{EXT_ASI}});
}
- 0x1D: LoadStoreAlt::ldstuba(
- {{uReg0 = Mem.ub;}},
- {{Rd.ub = uReg0;
- Mem.ub = 0xFF;}}, {{EXT_ASI}});
+ 0x1D: SwapAlt::ldstuba({{Mem.ub = 0xFF;}},
+ {{
+ uint8_t tmp = mem_data;
+ Rd.ub = tmp;
+ }}, {{EXT_ASI}}, MEM_SWAP);
0x1E: StoreAlt::stxa({{Mem.udw = Rd}}, {{EXT_ASI}});
- 0x1F: LoadStoreAlt::swapa(
- {{ uReg0 = Mem.uw}},
- {{ Mem.uw = Rd.uw;
- Rd.uw = uReg0;}}, {{EXT_ASI}});
+ 0x1F: SwapAlt::swapa({{Mem.uw = Rd.uw}},
+ {{
+ uint32_t tmp = mem_data;
+ Rd.uw = tmp;
+ }}, {{EXT_ASI}}, MEM_SWAP);
+
format Trap {
0x20: Load::ldf({{Frds.uw = Mem.uw;}});
0x21: decode RD {
{{fault = new DataAccessException;}});
}
}
- 0x3C: Cas::casa(
- {{uReg0 = Mem.uw;}},
- {{if(Rs2.uw == uReg0)
- Mem.uw = Rd.uw;
- else
- storeCond = false;
- Rd.uw = uReg0;}}, {{EXT_ASI}});
+ 0x3C: CasAlt::casa({{
+ mem_data = htog(Rs2.uw);
+ Mem.uw = Rd.uw;}},
+ {{
+ uint32_t tmp = mem_data;
+ Rd.uw = tmp;
+ }}, {{EXT_ASI}}, MEM_SWAP_COND);
0x3D: Nop::prefetcha({{ }});
- 0x3E: Cas::casxa(
- {{uReg0 = Mem.udw;}},
- {{if(Rs2 == uReg0)
- Mem.udw = Rd;
- else
- storeCond = false;
- Rd = uReg0;}}, {{EXT_ASI}});
+ 0x3E: CasAlt::casxa({{mem_data = gtoh(Rs2);
+ Mem.udw = Rd.udw; }},
+ {{ Rd.udw = mem_data; }}, {{EXT_ASI}}, MEM_SWAP_COND);
}
}
}
-// Copyright (c) 2006 The Regents of The University of Michigan
+// Copyright (c) 2006-2007 The Regents of The University of Michigan
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
}};
let {{
- def doMemFormat(code, execute, faultCode, name, Name, asi, opt_flags):
+ def doMemFormat(code, execute, faultCode, name, Name, asi, opt_flags, postacc_code = ''):
addrCalcReg = 'EA = Rs1 + Rs2;'
addrCalcImm = 'EA = Rs1 + imm;'
iop = InstObjParams(name, Name, 'Mem',
- {"code": code, "fault_check": faultCode,
- "ea_code": addrCalcReg},
- opt_flags)
+ {"code": code, "postacc_code" : postacc_code,
+ "fault_check": faultCode, "ea_code": addrCalcReg}, opt_flags)
iop_imm = InstObjParams(name, Name + "Imm", 'MemImm',
- {"code": code, "fault_check": faultCode,
- "ea_code": addrCalcImm},
- opt_flags)
+ {"code": code, "postacc_code" : postacc_code,
+ "fault_check": faultCode, "ea_code": addrCalcImm}, opt_flags)
header_output = MemDeclare.subst(iop) + MemDeclare.subst(iop_imm)
decoder_output = BasicConstructor.subst(iop) + BasicConstructor.subst(iop_imm)
decode_block = ROrImmDecode.subst(iop)
- exec_output = doDualSplitExecute(code, addrCalcReg, addrCalcImm,
- execute, faultCode, name, name + "Imm",
+ exec_output = doDualSplitExecute(code, postacc_code, addrCalcReg,
+ addrCalcImm, execute, faultCode, name, name + "Imm",
Name, Name + "Imm", asi, opt_flags)
return (header_output, decoder_output, exec_output, decode_block)
}};
decode_block) = doMemFormat(code,
StoreFuncs, '', name, Name, 0, opt_flags)
}};
+
+def format TwinLoad(code, asi, *opt_flags) {{
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doMemFormat(code, LoadFuncs,
+ AlternateASIPrivFaultCheck + TwinAlignmentFaultCheck,
+ name, Name, asi, opt_flags)
+}};
+
};
}};
-output header {{
-
- class TwinMem : public SparcMacroInst
- {
- protected:
-
- // Constructor
- // We make the assumption that all block memory operations
- // Will take 8 instructions to execute
- TwinMem(const char *mnem, ExtMachInst _machInst) :
- SparcMacroInst(mnem, _machInst, No_OpClass, 2)
- {}
- };
-
- class TwinMemImm : public BlockMem
- {
- protected:
-
- // Constructor
- TwinMemImm(const char *mnem, ExtMachInst _machInst) :
- BlockMem(mnem, _machInst)
- {}
- };
-
- class TwinMemMicro : public SparcMicroInst
- {
- protected:
-
- // Constructor
- TwinMemMicro(const char *mnem, ExtMachInst _machInst,
- OpClass __opClass, int8_t _offset) :
- SparcMicroInst(mnem, _machInst, __opClass),
- offset(_offset)
- {}
-
- std::string generateDisassembly(Addr pc,
- const SymbolTable *symtab) const;
-
- const int8_t offset;
- };
-
- class TwinMemImmMicro : public BlockMemMicro
- {
- protected:
-
- // Constructor
- TwinMemImmMicro(const char *mnem, ExtMachInst _machInst,
- OpClass __opClass, int8_t _offset) :
- BlockMemMicro(mnem, _machInst, __opClass, _offset),
- imm(sext<13>(SIMM13))
- {}
-
- std::string generateDisassembly(Addr pc,
- const SymbolTable *symtab) const;
-
- const int32_t imm;
- };
-}};
-
output decoder {{
std::string BlockMemMicro::generateDisassembly(Addr pc,
const SymbolTable *symtab) const
}};
-output decoder {{
- std::string TwinMemMicro::generateDisassembly(Addr pc,
- const SymbolTable *symtab) const
- {
- std::stringstream response;
- bool load = flags[IsLoad];
- bool save = flags[IsStore];
-
- printMnemonic(response, mnemonic);
- if(save)
- {
- printReg(response, _srcRegIdx[0]);
- ccprintf(response, ", ");
- }
- ccprintf(response, "[ ");
- printReg(response, _srcRegIdx[!save ? 0 : 1]);
- ccprintf(response, " + ");
- printReg(response, _srcRegIdx[!save ? 1 : 2]);
- ccprintf(response, " ]");
- if(load)
- {
- ccprintf(response, ", ");
- printReg(response, _destRegIdx[0]);
- }
-
- return response.str();
- }
-
- std::string TwinMemImmMicro::generateDisassembly(Addr pc,
- const SymbolTable *symtab) const
- {
- std::stringstream response;
- bool load = flags[IsLoad];
- bool save = flags[IsStore];
-
- printMnemonic(response, mnemonic);
- if(save)
- {
- printReg(response, _srcRegIdx[1]);
- ccprintf(response, ", ");
- }
- ccprintf(response, "[ ");
- printReg(response, _srcRegIdx[0]);
- if(imm >= 0)
- ccprintf(response, " + 0x%x ]", imm);
- else
- ccprintf(response, " + -0x%x ]", -imm);
- if(load)
- {
- ccprintf(response, ", ");
- printReg(response, _destRegIdx[0]);
- }
-
- return response.str();
- }
-
-}};
-
def template BlockMemDeclare {{
/**
* Static instruction class for a block memory operation
};
}};
-def template TwinMemDeclare {{
- /**
- * Static instruction class for a block memory operation
- */
- class %(class_name)s : public %(base_class)s
- {
- public:
- //Constructor
- %(class_name)s(ExtMachInst machInst);
-
- protected:
- class %(class_name)s_0 : public %(base_class)sMicro
- {
- public:
- //Constructor
- %(class_name)s_0(ExtMachInst machInst);
- %(BasicExecDeclare)s
- %(InitiateAccDeclare)s
- %(CompleteAccDeclare)s
- };
-
- class %(class_name)s_1 : public %(base_class)sMicro
- {
- public:
- //Constructor
- %(class_name)s_1(ExtMachInst machInst);
- %(BasicExecDeclare)s
- %(InitiateAccDeclare)s
- %(CompleteAccDeclare)s
- };
- };
-}};
-
// Basic instruction class constructor template.
def template BlockMemConstructor {{
inline %(class_name)s::%(class_name)s(ExtMachInst machInst)
}
}};
-// Basic instruction class constructor template.
-def template TwinMemConstructor {{
- inline %(class_name)s::%(class_name)s(ExtMachInst machInst)
- : %(base_class)s("%(mnemonic)s", machInst)
- {
- %(constructor)s;
- microOps[0] = new %(class_name)s_0(machInst);
- microOps[1] = new %(class_name)s_1(machInst);
- }
-}};
-
def template BlockMemMicroConstructor {{
inline %(class_name)s::
%(class_name)s_%(micro_pc)s::
decoder_output += BlockMemMicroConstructor.subst(iop)
decoder_output += BlockMemMicroConstructor.subst(iop_imm)
exec_output += doDualSplitExecute(
- pcedCode, addrCalcReg, addrCalcImm, execute, faultCode,
- makeMicroName(name, microPc),
- makeMicroName(name + "Imm", microPc),
- makeMicroName(Name, microPc),
- makeMicroName(Name + "Imm", microPc),
- asi, opt_flags);
- faultCode = ''
- return (header_output, decoder_output, exec_output, decode_block)
-
- def doTwinLoadFormat(code, faultCode, name, Name, asi, opt_flags):
- addrCalcReg = 'EA = Rs1 + Rs2 + offset;'
- addrCalcImm = 'EA = Rs1 + imm + offset;'
- iop = InstObjParams(name, Name, 'TwinMem', code, opt_flags)
- iop_imm = InstObjParams(name, Name + 'Imm', 'TwinMemImm', code, opt_flags)
- header_output = TwinMemDeclare.subst(iop) + TwinMemDeclare.subst(iop_imm)
- decoder_output = TwinMemConstructor.subst(iop) + TwinMemConstructor.subst(iop_imm)
- decode_block = ROrImmDecode.subst(iop)
- matcher = re.compile(r'RdTwin')
- exec_output = ''
- for microPc in range(2):
- flag_code = ''
- pcedCode = ''
- if (microPc == 1):
- flag_code = "flags[IsLastMicroOp] = true;"
- pcedCode = "RdLow = uReg0;\n"
- pcedCode += matcher.sub("RdHigh", code)
- else:
- flag_code = "flags[IsDelayedCommit] = true; flags[IsFirstMicroOp] = true;"
- pcedCode = matcher.sub("uReg0", code)
- iop = InstObjParams(name, Name, 'TwinMem',
- {"code": pcedCode, "ea_code": addrCalcReg,
- "fault_check": faultCode, "micro_pc": microPc,
- "set_flags": flag_code}, opt_flags)
- iop_imm = InstObjParams(name, Name + 'Imm', 'TwinMemImm',
- {"code": pcedCode, "ea_code": addrCalcImm,
- "fault_check": faultCode, "micro_pc": microPc,
- "set_flags": flag_code}, opt_flags)
- decoder_output += BlockMemMicroConstructor.subst(iop)
- decoder_output += BlockMemMicroConstructor.subst(iop_imm)
- exec_output += doDualSplitExecute(
- pcedCode, addrCalcReg, addrCalcImm, LoadFuncs, faultCode,
+ pcedCode, '', addrCalcReg, addrCalcImm, execute, faultCode,
makeMicroName(name, microPc),
makeMicroName(name + "Imm", microPc),
makeMicroName(Name, microPc),
asi, opt_flags);
faultCode = ''
return (header_output, decoder_output, exec_output, decode_block)
-
}};
def format BlockLoad(code, asi, *opt_flags) {{
decode_block) = doBlockMemFormat(code, faultCode,
StoreFuncs, name, Name, asi, opt_flags)
}};
-
-def format TwinLoad(code, asi, *opt_flags) {{
- faultCode = AlternateASIPrivFaultCheck + TwinAlignmentFaultCheck
- (header_output,
- decoder_output,
- exec_output,
- decode_block) = doTwinLoadFormat(code, faultCode, name, Name, asi, opt_flags)
-}};
-// Copyright (c) 2006 The Regents of The University of Michigan
+// Copyright (c) 2006-2007 The Regents of The University of Michigan
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
##include "blockmem.isa"
//Include the load/store and cas memory format
-##include "loadstore.isa"
+##include "swap.isa"
--- /dev/null
+// Copyright (c) 2007 The Regents of The University of Michigan
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met: redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer;
+// redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution;
+// neither the name of the copyright holders nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Authors: Gabe Black
+// Ali Saidi
+
+//This template provides the execute functions for a swap
+def template SwapExecute {{
+ Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
+ Trace::InstRecord *traceData) const
+ {
+ Fault fault = NoFault;
+ //This is to support the conditional store in cas instructions.
+ //It should be optomized out in all the others
+ bool storeCond = true;
+ Addr EA;
+ %(fp_enable_check)s;
+ %(op_decl)s;
+ uint64_t mem_data;
+
+ %(op_rd)s;
+ %(ea_code)s;
+ DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
+ %(fault_check)s;
+ if(fault == NoFault)
+ {
+ %(code)s;
+ }
+ if(storeCond && fault == NoFault)
+ {
+ fault = xc->write((uint%(mem_acc_size)s_t)Mem,
+ EA, %(asi_val)s, &mem_data);
+ }
+ if(fault == NoFault)
+ {
+ //Handle the swapping
+ %(postacc_code)s;
+ }
+ if(fault == NoFault)
+ {
+ //Write the resulting state to the execution context
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+
+def template SwapInitiateAcc {{
+ Fault %(class_name)s::initiateAcc(%(CPU_exec_context)s * xc,
+ Trace::InstRecord * traceData) const
+ {
+ Fault fault = NoFault;
+ Addr EA;
+ %(fp_enable_check)s;
+ uint64_t mem_data = 0;
+ %(op_decl)s;
+ %(op_rd)s;
+ %(ea_code)s;
+
+ DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
+ %(fault_check)s;
+
+ if(fault == NoFault)
+ {
+ %(code)s;
+ }
+ if(fault == NoFault)
+ {
+ fault = xc->write((uint%(mem_acc_size)s_t)Mem,
+ EA, %(asi_val)s, &mem_data);
+ }
+ return fault;
+ }
+}};
+
+
+
+def template SwapCompleteAcc {{
+ Fault %(class_name)s::completeAcc(PacketPtr pkt, %(CPU_exec_context)s * xc,
+ Trace::InstRecord * traceData) const
+ {
+ Fault fault = NoFault;
+ %(op_decl)s;
+
+ uint64_t mem_data = pkt->get<uint%(mem_acc_size)s_t>();
+
+ if(fault == NoFault)
+ {
+ //Handle the swapping
+ %(postacc_code)s;
+ }
+ if(fault == NoFault)
+ {
+ //Write the resulting state to the execution context
+ %(op_wb)s;
+ }
+
+ return fault;
+ }
+}};
+
+let {{
+ SwapFuncs = [SwapExecute, SwapInitiateAcc, SwapCompleteAcc]
+}};
+
+
+def format Swap(code, postacc_code, mem_flags, *opt_flags) {{
+ mem_flags = makeList(mem_flags)
+ flags = string.join(mem_flags, '|')
+
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doMemFormat(code, SwapFuncs, '', name, Name, flags,
+ opt_flags, postacc_code)
+}};
+
+def format SwapAlt(code, postacc_code, asi, mem_flags, *opt_flags) {{
+ mem_flags = makeList(mem_flags)
+ mem_flags.append(asi)
+ flags = string.join(mem_flags, '|')
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doMemFormat(code, SwapFuncs, AlternateASIPrivFaultCheck,
+ name, Name, flags, opt_flags, postacc_code)
+}};
+
+
+let {{
+ def doCasFormat(code, execute, faultCode, name, Name, asi, opt_flags, postacc_code = ''):
+ addrCalcReg = 'EA = Rs1;'
+ iop = InstObjParams(name, Name, 'Mem',
+ {"code": code, "postacc_code" : postacc_code,
+ "fault_check": faultCode, "ea_code": addrCalcReg}, opt_flags)
+ header_output = MemDeclare.subst(iop)
+ decoder_output = BasicConstructor.subst(iop)
+ decode_block = BasicDecode.subst(iop)
+ microParams = {"code": code, "postacc_code" : postacc_code,
+ "ea_code" : addrCalcReg, "fault_check" : faultCode}
+ exec_output = doSplitExecute(execute, name, Name, asi, opt_flags,
+ microParams);
+ return (header_output, decoder_output, exec_output, decode_block)
+}};
+
+
+def format CasAlt(code, postacc_code, asi, mem_flags, *opt_flags) {{
+ mem_flags = makeList(mem_flags)
+ mem_flags.append(asi)
+ flags = string.join(mem_flags, '|')
+ (header_output,
+ decoder_output,
+ exec_output,
+ decode_block) = doCasFormat(code, SwapFuncs, AlternateASIPrivFaultCheck,
+ name, Name, flags, opt_flags, postacc_code)
+}};
+
+
%(fault_check)s;
if(fault == NoFault)
{
- fault = xc->read(EA, (uint%(mem_acc_size)s_t&)Mem, %(asi_val)s);
+ fault = xc->read(EA, (%(mem_acc_type)s%(mem_acc_size)s_t&)Mem, %(asi_val)s);
}
if(fault == NoFault)
{
%(fault_check)s;
if(fault == NoFault)
{
- fault = xc->read(EA, (uint%(mem_acc_size)s_t&)Mem, %(asi_val)s);
+ fault = xc->read(EA, (%(mem_acc_type)s%(mem_acc_size)s_t&)Mem, %(asi_val)s);
}
return fault;
}
Addr EA;
%(fp_enable_check)s;
%(op_decl)s;
+
%(op_rd)s;
%(ea_code)s;
DPRINTF(Sparc, "%s: The address is 0x%x\n", mnemonic, EA);
let {{
LoadFuncs = [LoadExecute, LoadInitiateAcc, LoadCompleteAcc]
StoreFuncs = [StoreExecute, StoreInitiateAcc, StoreCompleteAcc]
+
# The LSB can be zero, since it's really the MSB in doubles and quads
# and we're dealing with doubles
BlockAlignmentFaultCheck = '''
return execf.subst(iop) + initf.subst(iop) + compf.subst(iop)
- def doDualSplitExecute(code, eaRegCode, eaImmCode, execute,
+ def doDualSplitExecute(code, postacc_code, eaRegCode, eaImmCode, execute,
faultCode, nameReg, nameImm, NameReg, NameImm, asi, opt_flags):
executeCode = ''
for (eaCode, name, Name) in (
(eaRegCode, nameReg, NameReg),
(eaImmCode, nameImm, NameImm)):
- microParams = {"code": code, "ea_code": eaCode,
- "fault_check": faultCode}
+ microParams = {"code": code, "postacc_code" : postacc_code,
+ "ea_code": eaCode, "fault_check": faultCode}
executeCode += doSplitExecute(execute, name, Name,
asi, opt_flags, microParams)
return executeCode
#include <cmath>
#include "arch/sparc/asi.hh"
+#include "base/bigint.hh"
#include "cpu/base.hh"
#include "cpu/exetrace.hh"
#include "sim/sim_exit.hh"
'uw' : ('unsigned int', 32),
'sdw' : ('signed int', 64),
'udw' : ('unsigned int', 64),
+ 'tudw' : ('twin int', 64),
'sf' : ('float', 32),
'df' : ('float', 64),
'qf' : ('float', 128)
#define __ARCH_SPARC_TYPES_HH__
#include <inttypes.h>
+#include "base/bigint.hh"
namespace SparcISA
{
typedef uint64_t ExtMachInst;
typedef uint64_t IntReg;
+ typedef Twin64_t LargestRead;
typedef uint64_t MiscReg;
typedef double FloatReg;
typedef uint64_t FloatRegBits;
--- /dev/null
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+#ifndef __BASE_BIGINT_HH__
+#define __BASE_BIGINT_HH__
+// Create a couple of large int types for atomic reads
+struct m5_twin64_t {
+ uint64_t a;
+ uint64_t b;
+ inline m5_twin64_t& operator=(const uint64_t x)
+ {
+ a = x;
+ b = x;
+ return *this;
+ }
+};
+
+// This is for twin loads (two 64 bit values), not 1 128 bit value (as far as
+// endian conversion is concerned!
+typedef m5_twin64_t Twin64_t;
+
+
+#endif // __BASE_BIGINT_HH__
+
if (res) {
// always return some result to keep misspeculated paths
// (which will ignore faults) deterministic
- *res = (fault == NoFault) ? req->getScResult() : 0;
+ *res = (fault == NoFault) ? req->getExtraData() : 0;
}
return fault;
#include "arch/locked_mem.hh"
#include "arch/mmaped_ipr.hh"
#include "arch/utility.hh"
+#include "base/bigint.hh"
#include "cpu/exetrace.hh"
#include "cpu/simple/atomic.hh"
#include "mem/packet.hh"
data_write_req->setThreadContext(p->cpu_id, 0); // Add thread ID here too
data_write_pkt = new Packet(data_write_req, MemCmd::WriteReq,
Packet::Broadcast);
+ data_swap_pkt = new Packet(data_write_req, MemCmd::SwapReq,
+ Packet::Broadcast);
}
#ifndef DOXYGEN_SHOULD_SKIP_THIS
+template
+Fault
+AtomicSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
+
template
Fault
AtomicSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
{
// use the CPU's statically allocated write request and packet objects
Request *req = data_write_req;
- PacketPtr pkt = data_write_pkt;
+ PacketPtr pkt;
req->setVirt(0, addr, sizeof(T), flags, thread->readPC());
+ if (req->isSwap())
+ pkt = data_swap_pkt;
+ else
+ pkt = data_write_pkt;
+
if (traceData) {
traceData->setAddr(addr);
}
if (req->isLocked()) {
do_access = TheISA::handleLockedWrite(thread, req);
}
+ if (req->isCondSwap()) {
+ assert(res);
+ req->setExtraData(*res);
+ }
+
if (do_access) {
pkt->reinitFromRequest();
#endif
}
+ if (req->isSwap()) {
+ assert(res);
+ *res = pkt->get<T>();
+ }
+
if (req->isLocked()) {
- uint64_t scResult = req->getScResult();
+ uint64_t scResult = req->getExtraData();
if (scResult != 0) {
// clear failure counter
thread->setStCondFailures(0);
}
if (res) {
- *res = req->getScResult();
+ *res = req->getExtraData();
}
}
}
PacketPtr data_read_pkt;
Request *data_write_req;
PacketPtr data_write_pkt;
+ PacketPtr data_swap_pkt;
bool dcache_access;
Tick dcache_latency;
MachInst inst;
// Static data storage
- TheISA::IntReg dataReg;
+ TheISA::LargestRead dataReg;
StaticInstPtr curStaticInst;
StaticInstPtr curMacroStaticInst;
#include "arch/locked_mem.hh"
#include "arch/utility.hh"
+#include "base/bigint.hh"
#include "cpu/exetrace.hh"
#include "cpu/simple/timing.hh"
#include "mem/packet.hh"
#ifndef DOXYGEN_SHOULD_SKIP_THIS
+template
+Fault
+TimingSimpleCPU::read(Addr addr, Twin64_t &data, unsigned flags);
+
template
Fault
TimingSimpleCPU::read(Addr addr, uint64_t &data, unsigned flags);
new Request(/* asid */ 0, addr, sizeof(T), flags, thread->readPC(),
cpu_id, /* thread ID */ 0);
+ if (traceData) {
+ traceData->setAddr(req->getVaddr());
+ }
+
// translate to physical address
Fault fault = thread->translateDataWriteReq(req);
// Now do the access.
if (fault == NoFault) {
assert(dcache_pkt == NULL);
- dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);
+ if (req->isSwap())
+ dcache_pkt = new Packet(req, MemCmd::SwapReq, Packet::Broadcast);
+ else
+ dcache_pkt = new Packet(req, MemCmd::WriteReq, Packet::Broadcast);
dcache_pkt->allocate();
dcache_pkt->set(data);
if (req->isLocked()) {
do_access = TheISA::handleLockedWrite(thread, req);
}
+ if (req->isCondSwap()) {
+ assert(res);
+ req->setExtraData(*res);
+ }
if (do_access) {
if (!dcachePort.sendTiming(dcache_pkt)) {
}
}
- req->setScResult(success ? 1 : 0);
+ req->setExtraData(success ? 1 : 0);
clearLoadLocks();
return success;
} else {
// complete miss (no matching block)
if (pkt->req->isLocked() && pkt->isWrite()) {
// miss on store conditional... just give up now
- pkt->req->setScResult(0);
+ pkt->req->setExtraData(0);
pkt->flags |= SATISFIED;
}
}
}
if (pkt->isWrite() && (pkt->req->isLocked())) {
- pkt->req->setScResult(1);
+ pkt->req->setExtraData(1);
}
myCache()->access(pkt);
return true;
ReadExResp, "ReadExReq" },
/* ReadExResp */
{ SET4(IsRead, IsInvalidate, IsResponse, HasData),
- InvalidCmd, "ReadExResp" }
+ InvalidCmd, "ReadExResp" },
+ /* SwapReq -- for Swap ldstub type operations */
+ { SET4(IsReadWrite, IsRequest, HasData, NeedsResponse),
+ SwapResp, "SwapReq" },
+ /* SwapResp -- for Swap ldstub type operations */
+ { SET3(IsReadWrite, IsResponse, HasData),
+ InvalidCmd, "SwapResp" }
};
if (p.isRead())
o << "Read ";
if (p.isWrite())
- o << "Read ";
+ o << "Write ";
+ if (p.isReadWrite())
+ o << "Read/Write ";
if (p.isInvalidate())
- o << "Read ";
+ o << "Invalidate ";
if (p.isRequest())
o << "Request ";
if (p.isResponse())
UpgradeReq,
ReadExReq,
ReadExResp,
+ SwapReq,
+ SwapResp,
NUM_MEM_CMDS
};
IsHWPrefetch,
IsUpgrade,
HasData,
+ IsReadWrite,
NUM_COMMAND_ATTRIBUTES
};
bool needsResponse() const { return testCmdAttrib(NeedsResponse); }
bool isInvalidate() const { return testCmdAttrib(IsInvalidate); }
bool hasData() const { return testCmdAttrib(HasData); }
+ bool isReadWrite() const { return testCmdAttrib(IsReadWrite); }
const Command responseCommand() const {
return commandInfo[cmd].response;
bool needsResponse() const { return cmd.needsResponse(); }
bool isInvalidate() const { return cmd.isInvalidate(); }
bool hasData() const { return cmd.hasData(); }
+ bool isReadWrite() const { return cmd.isReadWrite(); }
bool isCacheFill() const { return (flags & CACHE_LINE_FILL) != 0; }
bool isNoAllocate() const { return (flags & NO_ALLOCATE) != 0; }
*/
#include "arch/isa_traits.hh"
+#include "base/bigint.hh"
#include "mem/packet.hh"
#include "sim/byteswap.hh"
// these functions and make the users do their own byte swapping since
// the memory system does not in fact have an endianness.
+template<>
+inline Twin64_t
+Packet::get()
+{
+ Twin64_t d;
+ assert(staticData || dynamicData);
+ assert(sizeof(Twin64_t) <= size);
+ d.a = TheISA::gtoh(*(uint64_t*)data);
+ d.b = TheISA::gtoh(*((uint64_t*)data + 1));
+ return d;
+}
+
+
/** return the value of what is pointed to in the packet. */
template <typename T>
inline T
PhysicalMemory::new_page()
{
Addr return_addr = pagePtr << LogVMPageSize;
- return_addr += params()->addrRange.start;
+ return_addr += start();
++pagePtr;
return return_addr;
}
if (isLocked) {
- req->setScResult(success ? 1 : 0);
+ req->setExtraData(success ? 1 : 0);
}
return success;
void
PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
{
- assert(pkt->getAddr() >= params()->addrRange.start &&
- pkt->getAddr() + pkt->getSize() <= params()->addrRange.start +
- params()->addrRange.size());
+ assert(pkt->getAddr() >= start() &&
+ pkt->getAddr() + pkt->getSize() <= start() + size());
if (pkt->isRead()) {
if (pkt->req->isLocked()) {
trackLoadLocked(pkt->req);
}
- memcpy(pkt->getPtr<uint8_t>(),
- pmemAddr + pkt->getAddr() - params()->addrRange.start,
+ memcpy(pkt->getPtr<uint8_t>(), pmemAddr + pkt->getAddr() - start(),
pkt->getSize());
#if TRACING_ON
switch (pkt->getSize()) {
}
else if (pkt->isWrite()) {
if (writeOK(pkt->req)) {
- memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
- pkt->getPtr<uint8_t>(), pkt->getSize());
+ memcpy(pmemAddr + pkt->getAddr() - start(), pkt->getPtr<uint8_t>(),
+ pkt->getSize());
#if TRACING_ON
switch (pkt->getSize()) {
case sizeof(uint64_t):
}
#endif
}
- }
- else if (pkt->isInvalidate()) {
+ } else if (pkt->isInvalidate()) {
//upgrade or invalidate
pkt->flags |= SATISFIED;
- }
- else {
+ } else if (pkt->isReadWrite()) {
+ IntReg overwrite_val;
+ bool overwrite_mem;
+ uint64_t condition_val64;
+ uint32_t condition_val32;
+ uint64_t test_val64;
+ uint32_t test_val32;
+
+ assert(sizeof(IntReg) >= pkt->getSize());
+
+ overwrite_mem = true;
+ // keep a copy of our possible write value, and copy what is at the
+ // memory address into the packet
+ memcpy(&overwrite_val, pkt->getPtr<uint8_t>(), pkt->getSize());
+ memcpy(pkt->getPtr<uint8_t>(), pmemAddr + pkt->getAddr() - start(),
+ pkt->getSize());
+
+ if (pkt->req->isCondSwap()) {
+ if (pkt->getSize() == sizeof(uint64_t)) {
+ condition_val64 = htog(pkt->req->getExtraData());
+ memcpy(&test_val64, pmemAddr + pkt->getAddr() - start(), sizeof(uint64_t));
+ overwrite_mem = test_val64 == condition_val64;
+ } else if (pkt->getSize() == sizeof(uint32_t)) {
+ condition_val32 = htog((uint32_t)pkt->req->getExtraData());
+ memcpy(&test_val32, pmemAddr + pkt->getAddr() - start(), sizeof(uint32_t));
+ overwrite_mem = test_val32 == condition_val32;
+ } else
+ panic("Invalid size for conditional read/write\n");
+ }
+
+ if (overwrite_mem)
+ memcpy(pmemAddr + pkt->getAddr() - start(),
+ &overwrite_val, pkt->getSize());
+
+#if TRACING_ON
+ switch (pkt->getSize()) {
+ case sizeof(uint64_t):
+ DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
+ pkt->getSize(), pkt->getAddr(),pkt->get<uint64_t>());
+ DPRINTF(MemoryAccess, "New Data 0x%x %s conditional (0x%x) and %s \n",
+ overwrite_mem, pkt->req->isCondSwap() ? "was" : "wasn't",
+ condition_val64, overwrite_mem ? "happened" : "didn't happen");
+ break;
+ case sizeof(uint32_t):
+ DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
+ pkt->getSize(), pkt->getAddr(),pkt->get<uint32_t>());
+ DPRINTF(MemoryAccess, "New Data 0x%x %s conditional (0x%x) and %s \n",
+ overwrite_mem, pkt->req->isCondSwap() ? "was" : "wasn't",
+ condition_val32, overwrite_mem ? "happened" : "didn't happen");
+ break;
+ case sizeof(uint16_t):
+ DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
+ pkt->getSize(), pkt->getAddr(),pkt->get<uint16_t>());
+ DPRINTF(MemoryAccess, "New Data 0x%x wasn't conditional and happned\n",
+ overwrite_mem);
+ break;
+ case sizeof(uint8_t):
+ DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x old data 0x%x\n",
+ pkt->getSize(), pkt->getAddr(),pkt->get<uint8_t>());
+ DPRINTF(MemoryAccess, "New Data 0x%x wasn't conditional and happned\n",
+ overwrite_mem);
+ break;
+ default:
+ DPRINTF(MemoryAccess, "Read/Write of size %i on address 0x%x\n",
+ pkt->getSize(), pkt->getAddr());
+ }
+#endif
+ } else {
panic("unimplemented");
}
{
snoop.clear();
resp.clear();
- resp.push_back(RangeSize(params()->addrRange.start,
+ resp.push_back(RangeSize(start(),
params()->addrRange.size()));
}
// no locked addrs: nothing to check, store_conditional fails
bool isLocked = req->isLocked();
if (isLocked) {
- req->setScResult(0);
+ req->setExtraData(0);
}
return !isLocked; // only do write if not an sc
} else {
public:
Addr new_page();
uint64_t size() { return params()->addrRange.size(); }
+ uint64_t start() { return params()->addrRange.start; }
struct Params
{
const uint32_t NO_ALIGN_FAULT = 0x40000;
/** The request was an instruction read. */
const uint32_t INST_READ = 0x80000;
+/** This request is for a memory swap. */
+const uint32_t MEM_SWAP = 0x100000;
+const uint32_t MEM_SWAP_COND = 0x200000;
+
class Request
{
/** The virtual address of the request. */
Addr vaddr;
- /** The return value of store conditional. */
- uint64_t scResult;
+ /** Extra data for the request, such as the return value of
+ * store conditional or the compare value for a CAS. */
+ uint64_t extraData;
/** The cpu number (for statistics, typically). */
int cpuNum;
/** Whether or not the asid & vaddr are valid. */
bool validAsidVaddr;
/** Whether or not the sc result is valid. */
- bool validScResult;
+ bool validExData;
/** Whether or not the cpu number & thread ID are valid. */
bool validCpuAndThreadNums;
/** Whether or not the pc is valid. */
/** Minimal constructor. No fields are initialized. */
Request()
: validPaddr(false), validAsidVaddr(false),
- validScResult(false), validCpuAndThreadNums(false), validPC(false)
+ validExData(false), validCpuAndThreadNums(false), validPC(false)
{}
/**
validPaddr = true;
validAsidVaddr = false;
validPC = false;
- validScResult = false;
+ validExData = false;
mmapedIpr = false;
}
validPaddr = false;
validAsidVaddr = true;
validPC = true;
- validScResult = false;
+ validExData = false;
mmapedIpr = false;
}
void setMmapedIpr(bool r) { assert(validAsidVaddr); mmapedIpr = r; }
/** Accessor function to check if sc result is valid. */
- bool scResultValid() { return validScResult; }
+ bool extraDataValid() { return validExData; }
/** Accessor function for store conditional return value.*/
- uint64_t getScResult() { assert(validScResult); return scResult; }
+ uint64_t getExtraData() { assert(validExData); return extraData; }
/** Accessor function for store conditional return value.*/
- void setScResult(uint64_t _scResult)
- { scResult = _scResult; validScResult = true; }
+ void setExtraData(uint64_t _extraData)
+ { extraData = _extraData; validExData = true; }
/** Accessor function for cpu number.*/
int getCpuNum() { assert(validCpuAndThreadNums); return cpuNum; }
bool isLocked() { return (getFlags() & LOCKED) != 0; }
+ bool isSwap() { return (getFlags() & MEM_SWAP ||
+ getFlags() & MEM_SWAP_COND); }
+
+ bool isCondSwap() { return (getFlags() & MEM_SWAP_COND) != 0; }
+
+
friend class Packet;
};