//Extract adress according to register offset specification int DecodeRegisterOffset() { char Rm = (char)ExtractBits(code, 0, 3); char Sh = (char)ExtractBits(code, 5, 6); int shiftVal = ExtractBits(code, 7, 11); shiftVal *= U ? 1 : -1; stringValue = ", " + (shiftVal == 0 ? (U ? "" : "-") : "") + "r" + (int)Rm; int regval = Regs.ReadWord(GetReg(Rm)); if (Rm == 15) { regval += 8; } if (shiftVal != 0) { stringValue += ", " + BarrelShifter.CodeToString(Sh) + " #" + shiftVal; } else if (!U) { regval *= -1; } return(BarrelShifter.ShiftByCode(regval, shiftVal, Sh)); }
//fire the interrupt //Interrupts are special. They get special access to the inner guts of the program... public override void Execute() { if (swiType == 0x11) { Flags[SysFlag.Running] = false; Flags[SysFlag.Unsteppable] = true; return; } Regs.WriteWord(Reg.LR_SVC, Regs.ReadWord(Reg.R15)); Regs.WriteWord(Reg.SPSR_SVC, Regs.ReadWord(Reg.CPSR)); int cpsr = Regs.ReadWord(Reg.CPSR) & 0b1111111111111111111111111100000; Regs.WriteWord(Reg.CPSR, cpsr | Mode.Supervisor); //switch to superviser if (swiType == 0x0) { SetCPSRFlag(7, true); } else { SetCPSRFlag(7, false); } Regs.WriteWord(Reg.R15, 0x8); }
//decode instruction based on 'code' parent variable and returns populated version of itself public override Instruction Decode() { IBit = TestFlag(code, 25); P = TestFlag(code, 24); U = TestFlag(code, 23); S = TestFlag(code, 22); W = TestFlag(code, 21); L = TestFlag(code, 20); Rn = (char)ExtractBits(code, 16, 19); address = Regs.ReadWord(GetReg(Rn)); regstr = ""; bool first = true; for (int i = 0; i < regList.Length; i++) { regList[i] = TestFlag(code, i); if (regList[i]) { if (!first) { regstr += ", "; } regstr += "r" + i; first = false; } } return(this); }
//stores the values in the active registers in reglist[] into the address pinted to by Rn //while decrementing the value Rn before the store process void Store() //push { for (int i = regList.Length - 1; i >= 0; i--) { if (regList[i]) { address -= 4; RAM.WriteWord(address, Regs.ReadWord(GetReg(i))); } } }
//Extract the operands op1, op2, op3 from the command void CalculateOperands() { opn = Regs.ReadWord(GetReg(Rn)); //What is stored in Rn if (Rn == 15) { opn += 8; } opd = Regs.ReadWord(GetReg(Rd)); //What is stored in Rd op3 = IBit ? CalulateImmediateOperand3() : CalculateRegisterOperand3(); }
//Transfers value from CPSR or SPSR of the current mode into a general purpose register public override void Execute() { int value = Regs.ReadWord(Reg.CPSR); if (RBit) { char mode = CheckMode(); if (mode == 'V') //supervisor value = Regs.ReadWord(Reg.LR_SVC); else if (mode == 'R') //irq value = Regs.ReadWord(Reg.LR_IRQ); } Regs.WriteWord(GetReg(Rd), value); }
//caculated and returns the reister operand int CalulateRegValue() { char Rm = (char)ExtractBits(code, 0, 3); int val = Regs.ReadWord(GetReg(Rm)); if (Rm == 15) { val += 8; } strVal = "r" + (int)Rm; return(val); }
//Change the value of the program counter, //if L is true, store previous PC value in R14 public override void Execute() { if (isRet) { ExecuteReturn(); return; } if (link) { Regs.WriteWord(GetReg(14), Regs.ReadWord(Reg.R15)); } Regs.WriteWord(Reg.R15, address); }
//Calculate the address to jump to relative to PC void ProcessBranchAddress() { int pc = Regs.ReadWord(Reg.R15); link = TestFlag(code, 24); sign = TestFlag(code, 23); offset = ExtractBits(code, 0, 22); if (sign) { uint mask = 0xFFF00000; offset |= (int)mask; //mask to convert to signed FF000000 } offset <<= 2; address = pc + 8 + offset; }
//Stores value from register Rd in 'address' void Store() { if (B) { int storeVal = Regs.ReadWord(GetReg(Rd)); if (Rd == 15) { storeVal += 8; } RAM.WriteByte(address, (byte)storeVal); } else { int storeVal = Regs.ReadWord(GetReg(Rd)); if (Rd == 15) { storeVal += 8; } RAM.WriteWord(address, storeVal); } }
//Calcultes and returns the register shift operand int CalculateRegisterOperand3() { int shiftVal; Rm = (char)ExtractBits(code, 0, 3); char Sh = (char)ExtractBits(code, 5, 6); bool bit4 = TestFlag(code, 4); char Rs = '0'; strShift = "r" + (int)Rm; if (!bit4) { shiftVal = ExtractBits(code, 7, 11); } else { Rs = (char)ExtractBits(code, 8, 11); shiftVal = Regs.ReadWord(GetReg(Rs)); if (Rs == 15) { shiftVal += 8; } } if (shiftVal != 0) { strShift += ", " + BarrelShifter.CodeToString(Sh) + (bit4 ? " r" + (int)Rs : " #" + shiftVal); } int val = Regs.ReadWord(GetReg(Rm)); if (Rm == 15) { val += 8; } return(BarrelShifter.ShiftByCode(val, shiftVal, Sh)); }
//Decodes loadstore instruction for 'code' parent variable and returns //itself as a fully populated instruction ready for execution public override Instruction Decode() { IBit = TestFlag(code, 25); P = TestFlag(code, 24); U = TestFlag(code, 23); B = TestFlag(code, 22); W = TestFlag(code, 21); L = TestFlag(code, 20); Rn = (char)ExtractBits(code, 16, 19); Rd = (char)ExtractBits(code, 12, 15); int regContent = Regs.ReadWord(GetReg(Rn)); if (Rn == 15) { regContent += 8; } offset = !IBit?DecodeImmediateOffset() : DecodeRegisterOffset(); address = P ? regContent + offset : regContent; return(this); }
//performs the special case for the multiplication instruction, //multiplies the values in Rm and Rn and stores their results in Rd void ExecMUL() { Regs.WriteWord(GetReg(Rd), (Regs.ReadWord(GetReg(Rn)) * Regs.ReadWord(GetReg(Rm)))); }
//Execute BX: jump to address stored in link register void ExecuteReturn() { Regs.WriteWord(Reg.R15, Regs.ReadWord(GetReg(Rm))); }