def execute(self, simulatorContext): if not self._checkCondition(simulatorContext.regs): # Nothing to do, instruction not executed self.countExecConditionFalse += 1 return self.countExec += 1 if self.modeWrite: if self.usespsr and simulatorContext.regs.mode == "User": # Check if SPSR exists (we are not in user mode) raise ExecutionException( "Erreur : écriture de SPSR en mode 'User' (ce mode ne possede pas de registre SPSR)" ) if self.flagsOnly: if self.imm: valToSet = self.val if self.shift[2] != 0: _unused, valToSet = utils.applyShift( valToSet, self.shift, simulatorContext.regs.C) else: valToSet = simulatorContext.regs[ self. val] & 0xF0000000 # We only keep the condition flag bits if self.usespsr: valToSet |= simulatorContext.regs.SPSR & 0x0FFFFFFF else: valToSet |= simulatorContext.regs.CPSR & 0x0FFFFFFF else: valToSet = simulatorContext.regs[self.val] if (valToSet & 0x1F) not in simulatorContext.regs.bits2mode: raise ExecutionException( "Erreur : les bits ({:05b}) du mode du {} ne correspondent à aucun mode valide!" .format(valToSet & 0x1F, "SPSR" if self.usespsr else "CPSR")) if self.usespsr: simulatorContext.regs.SPSR = valToSet else: if not simulatorContext.allowSwitchModeInUserMode and simulatorContext.regs.mode == "User" and simulatorContext.regs.CPSR & 0x1F != valToSet & 0x1F: raise ExecutionException( "Erreur : tentative de changer le mode du processeur à partir d'un mode non privilégié!" ) simulatorContext.regs.CPSR = valToSet else: # Read if self.usespsr and simulatorContext.regs.mode == "User": # Check if SPSR exists (we are not in user mode) raise ExecutionException( "Erreur : lecture de SPSR en mode 'User' (ce mode ne possede pas de registre SPSR)" ) else: simulatorContext.regs[ self. rd] = simulatorContext.regs.SPSR if self.usespsr else simulatorContext.regs.CPSR
def explain(self, simulatorContext): self.resetAccessStates() bank = simulatorContext.regs.mode simulatorContext.regs.deactivateBreakpoints() disassembly = self.opcode description = "<ol>\n" disCond, descCond = self._explainCondition() description += descCond disassembly += disCond if self.modeWrite: disassembly += " SPSR" if self.usespsr else " CPSR" if self.flagsOnly: disassembly += "_flg" if self.imm: _unused, valToSet = utils.applyShift( self.val, self.shift, simulatorContext.regs.C) description += "<li>Écrit la constante {} dans {}</li>\n".format( valToSet, "SPSR" if self.usespsr else "CPSR") disassembly += ", #{}".format(hex(valToSet)) else: disassembly += ", R{}".format(self.val) self._writeregs |= utils.registerWithCurrentBank( self.val, bank) description += "<li>Lit la valeur de {}</li>\n".format( utils.regSuffixWithBank(self.val, bank)) description += "<li>Écrit les 4 bits les plus significatifs de cette valeur (qui correspondent aux drapeaux) dans {}</li>\n".format( "SPSR" if self.usespsr else "CPSR") else: description += "<li>Lit la valeur de {}</li>\n".format( utils.regSuffixWithBank(self.val, bank)) description += "<li>Écrit cette valeur dans {}</li>\n".format( "SPSR" if self.usespsr else "CPSR") disassembly += ", R{}".format(self.val) else: # Read disassembly += " R{}, {}".format( self.rd, "SPSR" if self.usespsr else "CPSR") self._writeregs |= utils.registerWithCurrentBank(self.rd, bank) description += "<li>Lit la valeur de {}</li>\n".format( "SPSR" if self.usespsr else "CPSR") description += "<li>Écrit le résultat dans {}</li>\n".format( utils.regSuffixWithBank(self.rd, bank)) description += "</ol>" simulatorContext.regs.reactivateBreakpoints() return disassembly, description
def decode(self): instrInt = self.instrInt if not utils.checkMask(instrInt, (), (27, 26)): raise ExecutionException("Le bytecode à cette adresse ne correspond à aucune instruction valide (2)", internalError=False) # Retrieve the condition field self._decodeCondition() # Get the opcode self.opcodeNum = (instrInt >> 21) & 0xF self.opcode = utils.dataOpcodeMappingR[self.opcodeNum] # "Immediate" and "set flags" self.imm = bool(instrInt & (1 << 25)) self.modifyFlags = bool(instrInt & (1 << 20)) self.rd = (instrInt >> 12) & 0xF # Destination register self.rn = (instrInt >> 16) & 0xF # First operand register if self.imm: self.shiftedVal = instrInt & 0xFF # see 4.5.3 of ARM doc to understand the * 2 self.shift = utils.shiftInfo(type="ROR", immediate=True, value=((instrInt >> 8) & 0xF) * 2) self.carryOutImmShift = 0 if self.shift.value != 0: # If it is a constant, we shift as we decode self.carryOutImmShift, self.shiftedVal = utils.applyShift(self.shiftedVal, self.shift, False) else: self.op2reg = instrInt & 0xF if instrInt & (1 << 4): self.shift = utils.shiftInfo(type=utils.shiftMappingR[(instrInt >> 5) & 0x3], immediate=False, value=(instrInt >> 8) & 0xF) else: self.shift = utils.shiftInfo(type=utils.shiftMappingR[(instrInt >> 5) & 0x3], immediate=True, value=(instrInt >> 7) & 0x1F)
def execute(self, simulatorContext): self.pcmodified = False if not self._checkCondition(simulatorContext.regs): # Nothing to do, instruction not executed self.countExecConditionFalse += 1 return self.countExec += 1 addr = baseval = simulatorContext.regs[self.basereg] if self.imm: addr += self.sign * self.offsetImm else: _, sval = utils.applyShift(simulatorContext.regs[self.offsetReg], self.offsetRegShift, simulatorContext.regs.C) addr += self.sign * sval realAddr = addr if self.pre else baseval s = 1 if self.byte else 4 if self.mode == 'LDR': m = simulatorContext.mem.get(realAddr, size=s) if m is None: # No such address in the mapped memory, we cannot continue raise ExecutionException( "Tentative de lecture de {} octets à partir de l'adresse {} invalide : mémoire non initialisée" .format(s, realAddr)) res = struct.unpack("<B" if self.byte else "<I", m)[0] simulatorContext.regs[self.rd] = res if self.rd == simulatorContext.PC: self.pcmodified = True else: # STR valWrite = simulatorContext.regs[self.rd] if self.rd == simulatorContext.PC and simulatorContext.PCSpecialBehavior: valWrite += 4 # Special case for PC (see ARM datasheet, 4.9.4) simulatorContext.mem.set(realAddr, valWrite, size=1 if self.byte else 4) if self.writeback: simulatorContext.regs[self.basereg] = addr
def execute(self, simulatorContext): self.pcmodified = False if not self._checkCondition(simulatorContext.regs): # Nothing to do, instruction not executed self.countExecConditionFalse += 1 return self.countExec += 1 workingFlags = {} workingFlags['C'] = 0 # "On logical operations, if the S bit is set (and Rd is not R15) # the V flag in the CPSR will be unaffected" # (ARM Reference 4.5.1) workingFlags['V'] = simulatorContext.regs.V # Get first operand value op1 = simulatorContext.regs[self.rn] # Get second operand value if self.imm: op2 = self.shiftedVal if self.shift.value != 0: # We change the carry flag only if we did a shift workingFlags['C'] = self.carryOutImmShift else: workingFlags['C'] = simulatorContext.regs.C else: op2 = simulatorContext.regs[self.op2reg] if self.op2reg == simulatorContext.PC and not self.shift.immediate and simulatorContext.PCSpecialBehavior: op2 += 4 # Special case for PC where we use PC+12 instead of PC+8 (see 4.5.5 of ARM Instr. set) carry, op2 = utils.applyShift(op2, self.shift, simulatorContext.regs.C) workingFlags['C'] = bool(carry) if self.opcode == "MOV": res = op2 elif self.opcode in ("ADD", "CMN"): res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(op1, op2, 0) elif self.opcode in ("SUB", "CMP"): # For a subtraction, including the comparison instruction CMP, C is set to 0 # if the subtraction produced a borrow (that is, an unsigned underflow), and to 1 otherwise. # http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0801a/CIADCDHH.html res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(op1, ~op2, 1) elif self.opcode == "MVN": res = ~op2 elif self.opcode in ("AND", "TST"): # These instructions do not affect the V flag (ARM Instr. set, 4.5.1) # However, C flag "is set to the carry out from the barrel shifter [if the shift is not LSL #0]" (4.5.1) # this was already done when we called _shiftVal res = op1 & op2 elif self.opcode == "ORR": res = op1 | op2 elif self.opcode == "BIC": res = op1 & ~op2 # Bit clear? elif self.opcode in ("EOR", "TEQ"): # These instructions do not affect the C and V flags (ARM Instr. set, 4.5.1) res = op1 ^ op2 elif self.opcode == "RSB": res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(~op1, op2, 1) elif self.opcode== "ADC": res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(op1, op2, int(simulatorContext.regs.C)) elif self.opcode == "SBC": res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(op1, ~op2, int(simulatorContext.regs.C)) elif self.opcode == "RSC": res, workingFlags['C'], workingFlags['V'] = utils.addWithCarry(~op1, op2, int(simulatorContext.regs.C)) else: raise ExecutionException("Mnémonique invalide : {}".format(self.opcode)) # Get the result back to 32 bits, if applicable (else it's just a no-op) res &= 0xFFFFFFFF workingFlags['Z'] = res == 0 # "N flag will be set to the value of bit 31 of the result" (4.5.1) workingFlags['N'] = res & 0x80000000 if self.modifyFlags: if self.rd == simulatorContext.PC: # Combining writing to PC and the S flag is a special case (see ARM Instr. set, 4.5.5) # "When Rd is R15 and the S flag is set the result of the operation is placed in R15 and # the SPSR corresponding to the current mode is moved to the CPSR. This allows state # changes which atomically restore both PC and CPSR. This form of instruction should # not be used in User mode." if simulatorContext.regs.mode == "User": raise ExecutionException("L'utilisation de PC comme registre de destination en combinaison avec la mise a jour des drapeaux est interdite en mode User!") if (simulatorContext.regs.SPSR & 0x1F) not in simulatorContext.regs.bits2mode: # The mode in SPSR is invalid raise ExecutionException("SPSR devrait ici être copié dans CPSR, mais le mode contenu dans SPSR est invalide!") simulatorContext.regs.CPSR = simulatorContext.regs.SPSR # Put back the saved SPSR in CPSR else: simulatorContext.regs.setAllFlags(workingFlags) if self.opcode not in ("TST", "TEQ", "CMP", "CMN"): # We actually write the result simulatorContext.regs[self.rd] = res if self.rd == simulatorContext.PC: self.pcmodified = True # We consider writing into LR as stepping out of a function # This does not change anything for the emulation, but has consequences # for the emulation stopping criterion if self.rd == 14 and simulatorContext.stepCondition > 0: simulatorContext.stepCondition -= 1 if len(simulatorContext.callStack) > 0: simulatorContext.callStack.pop()
def explain(self, simulatorContext): self.resetAccessStates() bank = simulatorContext.regs.mode simulatorContext.regs.deactivateBreakpoints() disassembly = self.mode description = "<ol>\n" disCond, descCond = self._explainCondition() description += descCond disassembly += disCond self._readregs = utils.registerWithCurrentBank(self.basereg, bank) addr = baseval = simulatorContext.regs[self.basereg] description += "<li>Utilise la valeur du registre {} comme adresse de base</li>\n".format( utils.regSuffixWithBank(self.basereg, bank)) descoffset = "" if self.imm: addr += self.sign * self.offsetImm if self.offsetImm > 0: if self.sign > 0: descoffset = "<li>Additionne la constante {} à l'adresse de base</li>\n".format( self.offsetImm) else: descoffset = "<li>Soustrait la constante {} à l'adresse de base</li>\n".format( self.offsetImm) else: shiftDesc = utils.shiftToDescription(self.offsetRegShift, bank) regDesc = utils.regSuffixWithBank(self.offsetReg, bank) if self.sign > 0: descoffset = "<li>Additionne le registre {} {} à l'adresse de base</li>\n".format( regDesc, shiftDesc) else: descoffset = "<li>Soustrait le registre {} {} à l'adresse de base</li>\n".format( regDesc, shiftDesc) _, sval = utils.applyShift(simulatorContext.regs[self.offsetReg], self.offsetRegShift, simulatorContext.regs.C) addr += self.sign * sval self._readregs |= utils.registerWithCurrentBank( self.offsetReg, bank) realAddr = addr if self.pre else baseval sizeaccess = 1 if self.byte else 4 sizedesc = "1 octet" if sizeaccess == 1 else "{} octets".format( sizeaccess) disassembly += "B" if sizeaccess == 1 else "" if self.nonprivileged: disassembly += "T" disassembly += " R{}, [R{}".format(self.rd, self.basereg) if self.mode == 'LDR': if self.pre: description += descoffset description += "<li>Lit {} à partir de l'adresse obtenue (pré-incrément) et stocke le résultat dans {} (LDR)</li>\n".format( sizedesc, utils.regSuffixWithBank(self.rd, bank)) else: description += "<li>Lit {} à partir de l'adresse de base et stocke le résultat dans {} (LDR)</li>\n".format( sizedesc, utils.regSuffixWithBank(self.rd, bank)) description += descoffset self._readmem = set(range(realAddr, realAddr + sizeaccess)) self._writeregs |= utils.registerWithCurrentBank(self.rd, bank) if self.rd == simulatorContext.PC: try: m = simulatorContext.mem.get(realAddr, size=sizeaccess, mayTriggerBkpt=False) except ExecutionException as ex: # We do not want to handle user errors here; # If there is an issue with the memory access, we simply carry on pass else: if m is not None: res = struct.unpack("<B" if self.byte else "<I", m)[0] self._nextInstrAddr = res else: # STR if self.pre: description += descoffset description += "<li>Copie la valeur du registre {} dans la mémoire, à l'adresse obtenue à l'étape précédente (pré-incrément), sur {} (STR)</li>\n".format( utils.regSuffixWithBank(self.rd, bank), sizedesc) else: description += "<li>Copie la valeur du registre {} dans la mémoire, à l'adresse de base, sur {} (STR)</li>\n".format( utils.regSuffixWithBank(self.rd, bank), sizedesc) description += descoffset self._writemem = set(range(realAddr, realAddr + sizeaccess)) self._readregs |= utils.registerWithCurrentBank(self.rd, bank) if self.pre: if self.imm: if self.offsetImm == 0: disassembly += "]" else: disassembly += ", #{}]".format( hex(self.sign * self.offsetImm)) else: disassembly += ", R{}".format(self.offsetReg) disassembly += utils.shiftToInstruction( self.offsetRegShift) + "]" else: # Post (a post-incrementation of 0 is useless) disassembly += "]" if self.imm and self.offsetImm != 0: disassembly += ", #{}".format(hex(self.sign * self.offsetImm)) elif not self.imm: disassembly += ", R{}".format(self.offsetReg) disassembly += utils.shiftToInstruction(self.offsetRegShift) if self.writeback: self._writeregs |= utils.registerWithCurrentBank( self.basereg, bank) description += "<li>Écrit l'adresse effective dans le registre de base {} (mode writeback)</li>\n".format( utils.regSuffixWithBank(self.basereg, bank)) if self.pre: disassembly += "!" description += "</ol>" simulatorContext.regs.reactivateBreakpoints() return disassembly, description