From b5a4d95811db487d946200bf103e2af376db7690 Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Mon, 12 Feb 2007 13:06:30 -0500 Subject: [PATCH] rename store conditional stuff as extra data so it can be used for conditional swaps as well Add support for a twin 64 bit int load Add Memory barrier and write barrier flags as appropriate Make atomic memory ops atomic src/arch/alpha/isa/mem.isa: src/arch/alpha/locked_mem.hh: src/cpu/base_dyn_inst.hh: src/mem/cache/cache_blk.hh: src/mem/cache/cache_impl.hh: rename store conditional stuff as extra data so it can be used for conditional swaps as well src/arch/alpha/types.hh: src/arch/mips/types.hh: src/arch/sparc/types.hh: add a largest read data type for statically allocating read buffers in atomic simple cpu src/arch/isa_parser.py: Add support for a twin 64 bit int load src/arch/sparc/isa/decoder.isa: Make atomic memory ops atomic Add Memory barrier and write barrier flags as appropriate src/arch/sparc/isa/formats/mem/basicmem.isa: add post access code block and define a twinload format for twin loads src/arch/sparc/isa/formats/mem/blockmem.isa: remove old microcoded twin load coad src/arch/sparc/isa/formats/mem/mem.isa: swap.isa replaces the code in loadstore.isa src/arch/sparc/isa/formats/mem/util.isa: add a post access code block src/arch/sparc/isa/includes.isa: need bigint.hh for Twin64_t src/arch/sparc/isa/operands.isa: add a twin 64 int type src/cpu/simple/atomic.cc: src/cpu/simple/atomic.hh: src/cpu/simple/base.hh: src/cpu/simple/timing.cc: add support for twinloads add support for swap and conditional swap instructions rename store conditional stuff as extra data so it can be used for conditional swaps as well src/mem/packet.cc: src/mem/packet.hh: Add support for atomic swap memory commands src/mem/packet_access.hh: Add endian conversion function for Twin64_t type src/mem/physical.cc: src/mem/physical.hh: src/mem/request.hh: Add support for atomic swap memory commands Rename sc code to extradata --HG-- extra : convert_revision : 69d908512fb34a4e28b29a6e58b807fb1a6b1656 --- src/arch/alpha/isa/mem.isa | 2 +- src/arch/alpha/locked_mem.hh | 4 +- src/arch/alpha/types.hh | 1 + src/arch/isa_parser.py | 11 +- src/arch/mips/types.hh | 2 + src/arch/sparc/isa/decoder.isa | 119 ++++++----- src/arch/sparc/isa/formats/mem/basicmem.isa | 28 ++- src/arch/sparc/isa/formats/mem/blockmem.isa | 212 +------------------- src/arch/sparc/isa/formats/mem/mem.isa | 4 +- src/arch/sparc/isa/formats/mem/swap.isa | 183 +++++++++++++++++ src/arch/sparc/isa/formats/mem/util.isa | 12 +- src/arch/sparc/isa/includes.isa | 1 + src/arch/sparc/isa/operands.isa | 1 + src/arch/sparc/types.hh | 2 + src/base/bigint.hh | 51 +++++ src/cpu/base_dyn_inst.hh | 2 +- src/cpu/simple/atomic.cc | 28 ++- src/cpu/simple/atomic.hh | 1 + src/cpu/simple/base.hh | 2 +- src/cpu/simple/timing.cc | 18 +- src/mem/cache/cache_blk.hh | 2 +- src/mem/cache/cache_impl.hh | 4 +- src/mem/packet.cc | 14 +- src/mem/packet.hh | 5 + src/mem/packet_access.hh | 14 ++ src/mem/physical.cc | 91 +++++++-- src/mem/physical.hh | 3 +- src/mem/request.hh | 31 ++- 28 files changed, 533 insertions(+), 315 deletions(-) create mode 100644 src/arch/sparc/isa/formats/mem/swap.isa create mode 100644 src/base/bigint.hh diff --git a/src/arch/alpha/isa/mem.isa b/src/arch/alpha/isa/mem.isa index c0bdd2c05..a82435a85 100644 --- a/src/arch/alpha/isa/mem.isa +++ b/src/arch/alpha/isa/mem.isa @@ -475,7 +475,7 @@ def template StoreCondCompleteAcc {{ %(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; diff --git a/src/arch/alpha/locked_mem.hh b/src/arch/alpha/locked_mem.hh index 52fe24173..44b002c6c 100644 --- a/src/arch/alpha/locked_mem.hh +++ b/src/arch/alpha/locked_mem.hh @@ -60,7 +60,7 @@ handleLockedWrite(XC *xc, Request *req) 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); @@ -68,7 +68,7 @@ handleLockedWrite(XC *xc, Request *req) 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 diff --git a/src/arch/alpha/types.hh b/src/arch/alpha/types.hh index ae42552d8..6433ea3ca 100644 --- a/src/arch/alpha/types.hh +++ b/src/arch/alpha/types.hh @@ -42,6 +42,7 @@ namespace AlphaISA typedef uint8_t RegIndex; typedef uint64_t IntReg; + typedef uint64_t LargestRead; // floating point register file entry type typedef double FloatReg; diff --git a/src/arch/isa_parser.py b/src/arch/isa_parser.py index 07ae72cb8..39500df36 100755 --- a/src/arch/isa_parser.py +++ b/src/arch/isa_parser.py @@ -1124,6 +1124,9 @@ def buildOperandTypeMap(userDict, lineno): 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) @@ -1156,7 +1159,10 @@ class Operand(object): # 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 @@ -1386,6 +1392,9 @@ class MemOperand(Operand): # 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 diff --git a/src/arch/mips/types.hh b/src/arch/mips/types.hh index d4fa296fd..fc45ea253 100644 --- a/src/arch/mips/types.hh +++ b/src/arch/mips/types.hh @@ -40,6 +40,8 @@ namespace MipsISA typedef uint8_t RegIndex; typedef uint32_t IntReg; + typedef uint64_t LargestRead; + // floating point register file entry type typedef uint32_t FloatReg32; diff --git a/src/arch/sparc/isa/decoder.isa b/src/arch/sparc/isa/decoder.isa index fb606c7cc..0be7defba 100644 --- a/src/arch/sparc/isa/decoder.isa +++ b/src/arch/sparc/isa/decoder.isa @@ -472,8 +472,8 @@ decode OP default Unknown::unknown() }}); //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:>}}); @@ -1168,15 +1168,17 @@ decode OP default Unknown::unknown() 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}}); @@ -1184,34 +1186,60 @@ decode OP default Unknown::unknown() 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>; @@ -1231,15 +1259,18 @@ decode OP default Unknown::unknown() 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 { @@ -1438,21 +1469,17 @@ decode OP default Unknown::unknown() {{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); } } } diff --git a/src/arch/sparc/isa/formats/mem/basicmem.isa b/src/arch/sparc/isa/formats/mem/basicmem.isa index 1d9075a57..751262811 100644 --- a/src/arch/sparc/isa/formats/mem/basicmem.isa +++ b/src/arch/sparc/isa/formats/mem/basicmem.isa @@ -1,4 +1,4 @@ -// 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 @@ -52,22 +52,20 @@ def template MemDeclare {{ }}; 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) }}; @@ -103,3 +101,13 @@ def format Store(code, *opt_flags) {{ 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) +}}; + diff --git a/src/arch/sparc/isa/formats/mem/blockmem.isa b/src/arch/sparc/isa/formats/mem/blockmem.isa index 9795d2342..499685a5c 100644 --- a/src/arch/sparc/isa/formats/mem/blockmem.isa +++ b/src/arch/sparc/isa/formats/mem/blockmem.isa @@ -91,65 +91,6 @@ output header {{ }; }}; -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 @@ -208,64 +149,6 @@ output decoder {{ }}; -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 @@ -359,39 +242,6 @@ def template BlockMemDeclare {{ }; }}; -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) @@ -409,17 +259,6 @@ def template BlockMemConstructor {{ } }}; -// 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:: @@ -467,47 +306,7 @@ let {{ 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), @@ -515,7 +314,6 @@ let {{ asi, opt_flags); faultCode = '' return (header_output, decoder_output, exec_output, decode_block) - }}; def format BlockLoad(code, asi, *opt_flags) {{ @@ -541,11 +339,3 @@ def format BlockStore(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) -}}; diff --git a/src/arch/sparc/isa/formats/mem/mem.isa b/src/arch/sparc/isa/formats/mem/mem.isa index fedece2b8..db45e226d 100644 --- a/src/arch/sparc/isa/formats/mem/mem.isa +++ b/src/arch/sparc/isa/formats/mem/mem.isa @@ -1,4 +1,4 @@ -// 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 @@ -42,4 +42,4 @@ ##include "blockmem.isa" //Include the load/store and cas memory format -##include "loadstore.isa" +##include "swap.isa" diff --git a/src/arch/sparc/isa/formats/mem/swap.isa b/src/arch/sparc/isa/formats/mem/swap.isa new file mode 100644 index 000000000..818597a84 --- /dev/null +++ b/src/arch/sparc/isa/formats/mem/swap.isa @@ -0,0 +1,183 @@ +// 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(); + + 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) +}}; + + diff --git a/src/arch/sparc/isa/formats/mem/util.isa b/src/arch/sparc/isa/formats/mem/util.isa index dbaabdca4..1d884d6c3 100644 --- a/src/arch/sparc/isa/formats/mem/util.isa +++ b/src/arch/sparc/isa/formats/mem/util.isa @@ -149,7 +149,7 @@ def template LoadExecute {{ %(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) { @@ -179,7 +179,7 @@ def template LoadInitiateAcc {{ %(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; } @@ -246,6 +246,7 @@ def template StoreInitiateAcc {{ 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); @@ -290,6 +291,7 @@ def template CompleteAccDeclare {{ 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 = ''' @@ -337,14 +339,14 @@ let {{ 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 diff --git a/src/arch/sparc/isa/includes.isa b/src/arch/sparc/isa/includes.isa index d2ef67154..b46ef011e 100644 --- a/src/arch/sparc/isa/includes.isa +++ b/src/arch/sparc/isa/includes.isa @@ -74,6 +74,7 @@ output exec {{ #include #include "arch/sparc/asi.hh" +#include "base/bigint.hh" #include "cpu/base.hh" #include "cpu/exetrace.hh" #include "sim/sim_exit.hh" diff --git a/src/arch/sparc/isa/operands.isa b/src/arch/sparc/isa/operands.isa index 140055010..f624c3e2b 100644 --- a/src/arch/sparc/isa/operands.isa +++ b/src/arch/sparc/isa/operands.isa @@ -37,6 +37,7 @@ def operand_types {{ '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) diff --git a/src/arch/sparc/types.hh b/src/arch/sparc/types.hh index 88fb24153..15386adca 100644 --- a/src/arch/sparc/types.hh +++ b/src/arch/sparc/types.hh @@ -32,6 +32,7 @@ #define __ARCH_SPARC_TYPES_HH__ #include +#include "base/bigint.hh" namespace SparcISA { @@ -39,6 +40,7 @@ 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; diff --git a/src/base/bigint.hh b/src/base/bigint.hh new file mode 100644 index 000000000..aa60eeb04 --- /dev/null +++ b/src/base/bigint.hh @@ -0,0 +1,51 @@ +/* + * 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__ + diff --git a/src/cpu/base_dyn_inst.hh b/src/cpu/base_dyn_inst.hh index 515cd0836..9ccdcdccc 100644 --- a/src/cpu/base_dyn_inst.hh +++ b/src/cpu/base_dyn_inst.hh @@ -868,7 +868,7 @@ BaseDynInst::write(T data, Addr addr, unsigned flags, uint64_t *res) 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; diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index fa47b0eee..6904ed936 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -31,6 +31,7 @@ #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" @@ -151,6 +152,8 @@ AtomicSimpleCPU::AtomicSimpleCPU(Params *p) 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); } @@ -316,6 +319,10 @@ AtomicSimpleCPU::read(Addr addr, T &data, unsigned flags) #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); @@ -363,10 +370,15 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) { // 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); } @@ -381,6 +393,11 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) if (req->isLocked()) { do_access = TheISA::handleLockedWrite(thread, req); } + if (req->isCondSwap()) { + assert(res); + req->setExtraData(*res); + } + if (do_access) { pkt->reinitFromRequest(); @@ -401,14 +418,19 @@ AtomicSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) #endif } + if (req->isSwap()) { + assert(res); + *res = pkt->get(); + } + 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(); } } } diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index 42c7bf23a..5bffb7666 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -118,6 +118,7 @@ class AtomicSimpleCPU : public BaseSimpleCPU PacketPtr data_read_pkt; Request *data_write_req; PacketPtr data_write_pkt; + PacketPtr data_swap_pkt; bool dcache_access; Tick dcache_latency; diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index c4853b916..b7d93c702 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -125,7 +125,7 @@ class BaseSimpleCPU : public BaseCPU MachInst inst; // Static data storage - TheISA::IntReg dataReg; + TheISA::LargestRead dataReg; StaticInstPtr curStaticInst; StaticInstPtr curMacroStaticInst; diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index e4748c966..ff3606a74 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -30,6 +30,7 @@ #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" @@ -310,6 +311,10 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags) #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); @@ -359,13 +364,20 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 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); @@ -374,6 +386,10 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res) 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)) { diff --git a/src/mem/cache/cache_blk.hh b/src/mem/cache/cache_blk.hh index 7b999e4b1..a4df1b03f 100644 --- a/src/mem/cache/cache_blk.hh +++ b/src/mem/cache/cache_blk.hh @@ -249,7 +249,7 @@ class CacheBlk } } - req->setScResult(success ? 1 : 0); + req->setExtraData(success ? 1 : 0); clearLoadLocks(); return success; } else { diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index ff35a0749..dac2b93a4 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -206,7 +206,7 @@ Cache::handleAccess(PacketPtr &pkt, int & lat, // 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; } } @@ -1147,7 +1147,7 @@ Cache::CpuSidePort::recvTiming(PacketPtr pkt) } if (pkt->isWrite() && (pkt->req->isLocked())) { - pkt->req->setScResult(1); + pkt->req->setExtraData(1); } myCache()->access(pkt); return true; diff --git a/src/mem/packet.cc b/src/mem/packet.cc index dde6c00d5..14d08db1b 100644 --- a/src/mem/packet.cc +++ b/src/mem/packet.cc @@ -94,7 +94,13 @@ MemCmd::commandInfo[] = 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" } }; @@ -238,9 +244,11 @@ operator<<(std::ostream &o, const Packet &p) 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()) diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 65d2207db..16410594a 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -88,6 +88,8 @@ class MemCmd UpgradeReq, ReadExReq, ReadExResp, + SwapReq, + SwapResp, NUM_MEM_CMDS }; @@ -106,6 +108,7 @@ class MemCmd IsHWPrefetch, IsUpgrade, HasData, + IsReadWrite, NUM_COMMAND_ATTRIBUTES }; @@ -141,6 +144,7 @@ class MemCmd 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; @@ -300,6 +304,7 @@ class Packet 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; } diff --git a/src/mem/packet_access.hh b/src/mem/packet_access.hh index aac0c3ae5..882aa98d0 100644 --- a/src/mem/packet_access.hh +++ b/src/mem/packet_access.hh @@ -30,6 +30,7 @@ */ #include "arch/isa_traits.hh" +#include "base/bigint.hh" #include "mem/packet.hh" #include "sim/byteswap.hh" @@ -40,6 +41,19 @@ // 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 inline T diff --git a/src/mem/physical.cc b/src/mem/physical.cc index eccd42bec..381669d4d 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -92,7 +92,7 @@ Addr PhysicalMemory::new_page() { Addr return_addr = pagePtr << LogVMPageSize; - return_addr += params()->addrRange.start; + return_addr += start(); ++pagePtr; return return_addr; @@ -187,7 +187,7 @@ PhysicalMemory::checkLockedAddrList(Request *req) } if (isLocked) { - req->setScResult(success ? 1 : 0); + req->setExtraData(success ? 1 : 0); } return success; @@ -196,16 +196,14 @@ PhysicalMemory::checkLockedAddrList(Request *req) 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(), - pmemAddr + pkt->getAddr() - params()->addrRange.start, + memcpy(pkt->getPtr(), pmemAddr + pkt->getAddr() - start(), pkt->getSize()); #if TRACING_ON switch (pkt->getSize()) { @@ -233,8 +231,8 @@ PhysicalMemory::doFunctionalAccess(PacketPtr pkt) } else if (pkt->isWrite()) { if (writeOK(pkt->req)) { - memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start, - pkt->getPtr(), pkt->getSize()); + memcpy(pmemAddr + pkt->getAddr() - start(), pkt->getPtr(), + pkt->getSize()); #if TRACING_ON switch (pkt->getSize()) { case sizeof(uint64_t): @@ -259,12 +257,77 @@ PhysicalMemory::doFunctionalAccess(PacketPtr pkt) } #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(), pkt->getSize()); + memcpy(pkt->getPtr(), 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()); + 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()); + 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()); + 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()); + 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"); } @@ -315,7 +378,7 @@ PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) { snoop.clear(); resp.clear(); - resp.push_back(RangeSize(params()->addrRange.start, + resp.push_back(RangeSize(start(), params()->addrRange.size())); } diff --git a/src/mem/physical.hh b/src/mem/physical.hh index af88bcaa0..f7200b502 100644 --- a/src/mem/physical.hh +++ b/src/mem/physical.hh @@ -131,7 +131,7 @@ class PhysicalMemory : public MemObject // 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 { @@ -148,6 +148,7 @@ class PhysicalMemory : public MemObject public: Addr new_page(); uint64_t size() { return params()->addrRange.size(); } + uint64_t start() { return params()->addrRange.start; } struct Params { diff --git a/src/mem/request.hh b/src/mem/request.hh index de0512e1c..43d8ff1d5 100644 --- a/src/mem/request.hh +++ b/src/mem/request.hh @@ -71,6 +71,10 @@ const uint32_t EVICT_NEXT = 0x20000; 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 { @@ -104,8 +108,9 @@ 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; @@ -120,7 +125,7 @@ class Request /** 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. */ @@ -130,7 +135,7 @@ class Request /** Minimal constructor. No fields are initialized. */ Request() : validPaddr(false), validAsidVaddr(false), - validScResult(false), validCpuAndThreadNums(false), validPC(false) + validExData(false), validCpuAndThreadNums(false), validPC(false) {} /** @@ -169,7 +174,7 @@ class Request validPaddr = true; validAsidVaddr = false; validPC = false; - validScResult = false; + validExData = false; mmapedIpr = false; } @@ -187,7 +192,7 @@ class Request validPaddr = false; validAsidVaddr = true; validPC = true; - validScResult = false; + validExData = false; mmapedIpr = false; } @@ -237,12 +242,12 @@ class Request 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; } @@ -259,6 +264,12 @@ class Request 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; }; -- 2.30.2