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 decode(self): instrInt = self.instrInt # This one is tricky # The signature looks like a data processing operation, BUT # it sets the "opcode" to an operation beginning with 10**, # and the only operations that match this are TST, TEQ, CMP and CMN # It is said that for these ops, the S flag MUST be set to 1 # With MSR and MRS, the bit representing the S flag is always 0, # so we can differentiate these instructions... if not (utils.checkMask(instrInt, (19, 24), (27, 26, 23, 20))): raise ExecutionException( "Le bytecode à cette adresse ne correspond à aucune instruction valide", internalError=False) # Retrieve the condition field self._decodeCondition() self.usespsr = bool(instrInt & (1 << 22)) self.modeWrite = bool(instrInt & (1 << 21)) self.flagsOnly = not bool(instrInt & (1 << 16)) self.imm = bool(instrInt & (1 << 25)) self.rd = (instrInt >> 12) & 0xF if self.imm and self.flagsOnly: # Immediate mode is allowed only for flags-only mode self.val = instrInt & 0xFF self.shift = utils.shiftInfo( type="ROR", immediate=True, value=((instrInt >> 8) & 0xF) * 2) # see 4.5.3 of ARM doc to understand the * 2 else: self.val = instrInt & 0xF self.shift = utils.shiftInfo( type="ROR", immediate=True, value=0 ) # No rotate with registers for these particular instructions self.opcode = "MSR" if self.modeWrite else "MRS"
def decode(self): instrInt = self.instrInt if not (utils.checkMask(self.instrInt, (26, 25), (4, 27)) or utils.checkMask(self.instrInt, (26, ), (25, 27))): raise ExecutionException( "Le bytecode à cette adresse ne correspond à aucune instruction valide", internalError=False) # Retrieve the condition field self._decodeCondition() # For LDR/STR, imm is 0 if offset IS an immediate value (4-26 datasheet) self.imm = not bool(instrInt & (1 << 25)) self.pre = bool(instrInt & (1 << 24)) self.sign = 1 if instrInt & (1 << 23) else -1 self.byte = bool(instrInt & (1 << 22)) # See 4.9.1 (with post, writeback is redundant and always on) self.writeback = bool(instrInt & (1 << 21)) or not self.pre # See same section, with post-inc, writeback is actually used to indicate an LDRT instruction self.nonprivileged = bool(instrInt & (1 << 21)) and not self.pre self.mode = "LDR" if instrInt & (1 << 20) else "STR" self.basereg = (instrInt >> 16) & 0xF self.rd = (instrInt >> 12) & 0xF if self.imm: self.offsetImm = instrInt & 0xFFF else: self.offsetReg = instrInt & 0xF # Cannot be a register shift self.offsetRegShift = utils.shiftInfo( type=utils.shiftMappingR[(instrInt >> 5) & 0x3], immediate=True, value=(instrInt >> 7) & 0x1F)
def decode(self): instrInt = self.instrInt if not (utils.checkMask(instrInt, (27, 25), (26, )) or utils.checkMask(instrInt, (24, 21, 4) + tuple(range(8, 20)), (27, 26, 25, 23, 22, 20, 7, 6, 5))): raise ExecutionException( "Le bytecode à cette adresse ne correspond à aucune instruction valide (1)", internalError=False) # Retrieve the condition field self._decodeCondition() self.imm = (instrInt >> 25) & 1 != 0 if self.imm: # B or BL self.imm = True self.link = bool(instrInt & (1 << 24)) self.offsetImm = instrInt & 0xFFFFFF if self.offsetImm & 0x800000: # Negative offset self.offsetImm = -2**24 + self.offsetImm # Branch offset is *4 (since an ARM instruction covers 4 bytes) self.offsetImm <<= 2 else: # BX self.link = False self.addrReg = instrInt & 0xF
def decode(self): instrInt = self.instrInt if not (utils.checkMask(instrInt, (24, 25, 26, 27), ())): raise ExecutionException( "Le bytecode à cette adresse ne correspond à aucune instruction valide", internalError=False) # Retrieve the condition field self._decodeCondition() self.datauser = instrInt & 0xFFFFFF
def decode(self): instrInt = self.instrInt if not (utils.checkMask(instrInt, (25, 24, 21), (27, 26, 23, 22, 20, 19, 18, 17, 16))): raise ExecutionException( "Le bytecode à cette adresse ne correspond à aucune instruction valide", internalError=False) # Retrieve the condition field self._decodeCondition()
def decode(self): instrInt = self.instrInt if not (utils.checkMask(instrInt, (7, 4, 24), (27, 26, 25, 23, 21, 20, 11, 10, 9, 8, 6, 5))): raise ExecutionException("Le bytecode à cette adresse ne correspond à aucune instruction valide", internalError=False) # Retrieve the condition field self._decodeCondition() self.byte = bool(instrInt & (1 << 22)) self.rm = instrInt & 0xF self.rd = (instrInt >> 12) & 0xF self.rn = (instrInt >> 16) & 0xF
def decode(self): instrInt = self.instrInt if not (utils.checkMask(instrInt, (7, 4), tuple(range(22, 28)) + (5, 6))): raise ExecutionException( "Le bytecode à cette adresse ne correspond à aucune instruction valide", internalError=False) # Retrieve the condition field self._decodeCondition() self.rd = (instrInt >> 16) & 0xF self.rn = (instrInt >> 12) & 0xF self.rs = (instrInt >> 8) & 0xF self.rm = instrInt & 0xF self.modifyFlags = bool(instrInt & (1 << 20)) self.accumulate = bool(instrInt & (1 << 21))
def execute(self, simulatorContext): if not self._checkCondition(simulatorContext.regs): # Nothing to do, instruction not executed self.countExecConditionFalse += 1 return self.countExec += 1 addr = simulatorContext.regs[self.rn] s = 1 if self.byte else 4 m = simulatorContext.mem.get(addr, 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, addr)) valMem = struct.unpack("<B" if self.byte else "<I", m)[0] # We write to the memory before writing the register in case where rd==rm valWrite = simulatorContext.regs[self.rm] simulatorContext.mem.set(addr, valWrite, size=1 if self.byte else 4) simulatorContext.regs[self.rd] = valMem
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 decode(self): instrInt = self.instrInt if not (utils.checkMask(instrInt, (27, ), (26, 25))): raise ExecutionException( "Le bytecode à cette adresse ne correspond à aucune instruction valide", internalError=False) # Retrieve the condition field self._decodeCondition() self.pre = bool(instrInt & (1 << 24)) self.sign = 1 if instrInt & (1 << 23) else -1 self.sbit = bool(instrInt & (1 << 22)) self.writeback = bool(instrInt & (1 << 21)) self.mode = "LDR" if instrInt & (1 << 20) else "STR" self.basereg = (instrInt >> 16) & 0xF self.regbitmap = instrInt & 0xFFFF reglist = [] for i in range(16): if self.regbitmap & (1 << i): reglist.append(i) self.reglist = tuple(reglist)
def explain(self, simulatorContext): self.resetAccessStates() bank = simulatorContext.regs.mode simulatorContext.regs.deactivateBreakpoints() modifiedFlags = {'Z', 'N'} disassembly = self.opcode description = "<ol>\n" disCond, descCond = self._explainCondition() disassembly += disCond description += descCond if self.modifyFlags and self.opcode not in ("TST", "TEQ", "CMP", "CMN"): disassembly += "S" if self.opcode not in ("MOV", "MVN"): self._readregs |= utils.registerWithCurrentBank(self.rn, bank) op2desc = "" op2dis = "" # Get second operand value if self.imm: op2 = self.shiftedVal op2desc = "La constante {}".format(op2) op2dis = "#{}".format(hex(op2)) else: self._readregs |= utils.registerWithCurrentBank(self.op2reg, bank) if self.shift.type != "LSL" or self.shift.value > 0 or not self.shift.immediate: modifiedFlags.add('C') shiftDesc = utils.shiftToDescription(self.shift, bank) shiftinstr = utils.shiftToInstruction(self.shift) op2desc = "Le registre {} {}".format(utils.regSuffixWithBank(self.op2reg, bank), shiftDesc) op2dis = "R{}{}".format(self.op2reg, shiftinstr) if not self.shift.immediate: self._readregs |= utils.registerWithCurrentBank(self.shift.value, bank) op2 = simulatorContext.regs[self.op2reg] if 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 description += "<li>Effectue une opération ET entre:\n" elif self.opcode in ("EOR", "TEQ"): # These instructions do not affect the C and V flags (ARM Instr. set, 4.5.1) description += "<li>Effectue une opération OU EXCLUSIF (XOR) entre:\n" elif self.opcode in ("SUB", "CMP"): modifiedFlags.update(('C', 'V')) description += "<li>Effectue une soustraction (A-B) entre:\n" if self.opcode == "SUB" and self.rd == simulatorContext.PC: # We change PC, we show it in the editor self._nextInstrAddr = simulatorContext.regs[self.rn] - op2 elif self.opcode == "RSB": modifiedFlags.update(('C', 'V')) description += "<li>Effectue une soustraction inverse (B-A) entre:\n" elif self.opcode in ("ADD", "CMN"): modifiedFlags.update(('C', 'V')) description += "<li>Effectue une addition (A+B) entre:\n" if self.opcode == "ADD" and self.rd == simulatorContext.PC: # We change PC, we show it in the editor self._nextInstrAddr = simulatorContext.regs[self.rn] + op2 elif self.opcode == "ADC": modifiedFlags.update(('C', 'V')) description += "<li>Effectue une addition avec retenue (A+B+carry) entre:\n" elif self.opcode == "SBC": modifiedFlags.update(('C', 'V')) description += "<li>Effectue une soustraction avec emprunt (A-B+carry) entre:\n" elif self.opcode == "RSC": modifiedFlags.update(('C', 'V')) description += "<li>Effectue une soustraction inverse avec emprunt (B-A+carry) entre:\n" elif self.opcode == "ORR": description += "<li>Effectue une opération OU entre:\n" elif self.opcode == "MOV": description += "<li>Lit la valeur de :\n" if self.rd == simulatorContext.PC: # We change PC, we show it in the editor self._nextInstrAddr = op2 elif self.opcode == "BIC": description += "<li>Effectue une opération ET NON entre:\n" elif self.opcode == "MVN": description += "<li>Effectue une opération NOT sur :\n" if self.rd == simulatorContext.PC: # We change PC, we show it in the editor self._nextInstrAddr = ~op2 else: raise ExecutionException("Mnémonique invalide : {}".format(self.opcode)) if self.opcode in ("MOV", "MVN"): description += "<ol type=\"A\"><li>{}</li></ol>\n".format(op2desc) disassembly += " R{}, ".format(self.rd) elif self.opcode in ("TST", "TEQ", "CMP", "CMN"): description += "<ol type=\"A\"><li>Le registre {}</li><li>{}</li></ol>\n".format(utils.regSuffixWithBank(self.rn, bank), op2desc) disassembly += " R{}, ".format(self.rn) else: description += "<ol type=\"A\"><li>Le registre {}</li>\n".format(utils.regSuffixWithBank(self.rn, bank)) description += "<li>{}</li></ol>\n".format(op2desc) disassembly += " R{}, R{}, ".format(self.rd, self.rn) disassembly += op2dis description += "</li>\n" if self.modifyFlags: if self.rd == simulatorContext.PC: description += "<li>Copie le SPSR courant dans CPSR</li>\n" else: self._writeflags = modifiedFlags description += "<li>Met à jour les drapeaux de l'ALU en fonction du résultat de l'opération</li>\n" if self.opcode not in ("TST", "TEQ", "CMP", "CMN"): description += "<li>Écrit le résultat dans {}</li>".format(utils.regSuffixWithBank(self.rd, bank)) self._writeregs |= utils.registerWithCurrentBank(self.rd, bank) description += "</ol>" simulatorContext.regs.reactivateBreakpoints() return disassembly, description
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()