/*! Compiles a stub needed to call C++ translator.process() from asm code. */ inline void NesCpuTranslator::mTranslateCaller() { // r0 - PC address // lr - caller address - lr will not be used to return to the caller, // it's used to fix branch instruction __ bind(&m_translateCallerLabel); mSaveInternalFlags(); // adjust lr to point to branch instruction and move it to r1 as an argument // for translateStub() function __ sub(r1, lr, Operand(4)); mCallCFunction(offsetof(NesCpuRecData,translate)); mRestoreInternalFlags(); // translate function returns address of recompiled code // just jump to it __ mov(pc, r0); }
template <typename Visitor> void enumerateFields_gen(OperandAddress obj, Visitor & vis) { enumerateFields_gen(Operand(obj), vis); vis(obj.symbol(),"symbol"); vis(obj.reg(),"reg"); enumerateFields(obj.offset(), vis); }
//----------------------------------------------------------------------- void FunctionInvocation::pushOperand(ParameterPtr parameter, Operand::OpSemantic opSemantic, int opMask, int indirectionLevel) { mOperands.push_back(Operand(parameter, opSemantic, opMask, indirectionLevel)); }
void CR_ModuleEx::CreateFlowGraph64(CR_Addr64 entrance) { auto cf = Info64()->CodeFuncFromAddr(entrance); assert(cf); CR_Addr64Set leaders; leaders.insert(entrance); // insert jumpees auto& jumpees = cf->Jumpees(); leaders.insert(jumpees.begin(), jumpees.end()); // insert exits' next auto& exits = cf->Exits(); for (auto addr : exits) { auto op_code = Info64()->OpCodeFromAddr(addr); auto size = op_code->Codes().size(); auto next_addr = static_cast<CR_Addr64>(addr + size); leaders.insert(next_addr); } // insert jumpers' next auto& jumpers = cf->Jumpers(); for (auto addr : jumpers) { auto op_code = Info64()->OpCodeFromAddr(addr); auto size = op_code->Codes().size(); auto next_addr = static_cast<CR_Addr64>(addr + size); leaders.insert(next_addr); } // sort std::vector<CR_Addr64> vecLeaders(leaders.begin(), leaders.end()); std::sort(vecLeaders.begin(), vecLeaders.end()); // store leaders cf->Leaders() = std::move(leaders); const size_t size = vecLeaders.size() - 1; for (size_t i = 0; i < size; ++i) { // for every pair of two adjacent leaders auto addr1 = vecLeaders[i], addr2 = vecLeaders[i + 1]; // prepare a basic block CR_BasicBlock64 block; block.m_addr = addr1; CR_Addr64 next_addr = cr_invalid_addr64; for (auto addr = addr1; addr < addr2; ) { if (cf->Leaders().count(addr)) { // set label at each leader block.AddLeaderLabel(addr); } // op.code from addr auto op_code = Info64()->OpCodeFromAddr(addr); if (op_code == NULL) { break; } auto type = op_code->OpCodeType(); if (type == cr_OCT_JMP) { // jump auto oper = op_code->Operand(0); if (oper->GetOperandType() == cr_DF_IMM) { block.m_jump_to = oper->Value64(); // jump to } next_addr = cr_invalid_addr64; } else if (type == cr_OCT_RETURN) { next_addr = cr_invalid_addr64; } else if (type == cr_OCT_JCC || type == cr_OCT_LOOP) { // conditional jump or loop auto oper = op_code->Operand(0); if (oper->GetOperandType() == cr_DF_IMM) { block.m_jump_to = oper->Value64(); // jump to } block.m_cond_code = op_code->CondCode(); next_addr = static_cast<CR_Addr64>(addr + op_code->Codes().size()); } else { next_addr = static_cast<CR_Addr64>(addr + op_code->Codes().size()); } // add op.code block.m_stmts.emplace_back(*op_code); // go to next addr addr += static_cast<CR_Addr64>(op_code->Codes().size()); } // add label at last block.AddLeaderLabel(addr2); // set next addr block.m_next_addr = next_addr; // add block cf->BasicBlocks().emplace_back(block); } } // CR_ModuleEx::CreateFlowGraph64
void CCodeGenerator::enter_scope() { return_val_ = Operand(); block_has_return_ = false; scope_.push_back(new Scope); }
void CCodeGenerator::operator()(FloatLiteral* expression) { return_ = Operand(expression); }
template <typename Visitor> void enumerateFields_gen(OperandString obj, Visitor & vis) { enumerateFields_gen(Operand(obj), vis); vis(obj.string(),"string"); }
bool ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm) { // Guard that R0 is an integer and R1 is an integer. Label failure; masm.branchTestInt32(Assembler::NotEqual, R0, &failure); masm.branchTestInt32(Assembler::NotEqual, R1, &failure); // Add R0 and R1. Don't need to explicitly unbox, just use R2. Register Rscratch = R2_; ARMRegister Wscratch = ARMRegister(Rscratch, 32); #ifdef MERGE // DIV and MOD need an extra non-volatile ValueOperand to hold R0. AllocatableGeneralRegisterSet savedRegs(availableGeneralRegs(2)); savedRegs.set() = GeneralRegisterSet::Intersect(GeneralRegisterSet::NonVolatile(), savedRegs); #endif // get some more ARM-y names for the registers ARMRegister W0(R0_, 32); ARMRegister X0(R0_, 64); ARMRegister W1(R1_, 32); ARMRegister X1(R1_, 64); ARMRegister WTemp(ExtractTemp0, 32); ARMRegister XTemp(ExtractTemp0, 64); Label maybeNegZero, revertRegister; switch(op_) { case JSOP_ADD: masm.Adds(WTemp, W0, Operand(W1)); // Just jump to failure on overflow. R0 and R1 are preserved, so we can // just jump to the next stub. masm.j(Assembler::Overflow, &failure); // Box the result and return. We know R0 already contains the // integer tag, so we just need to move the payload into place. masm.movePayload(ExtractTemp0, R0_); break; case JSOP_SUB: masm.Subs(WTemp, W0, Operand(W1)); masm.j(Assembler::Overflow, &failure); masm.movePayload(ExtractTemp0, R0_); break; case JSOP_MUL: masm.mul32(R0.valueReg(), R1.valueReg(), Rscratch, &failure, &maybeNegZero); masm.movePayload(Rscratch, R0_); break; case JSOP_DIV: case JSOP_MOD: { // Check for INT_MIN / -1, it results in a double. Label check2; masm.Cmp(W0, Operand(INT_MIN)); masm.B(&check2, Assembler::NotEqual); masm.Cmp(W1, Operand(-1)); masm.j(Assembler::Equal, &failure); masm.bind(&check2); Label no_fail; // Check for both division by zero and 0 / X with X < 0 (results in -0). masm.Cmp(W1, Operand(0)); // If x > 0, then it can't be bad. masm.B(&no_fail, Assembler::GreaterThan); // if x == 0, then ignore any comparison, and force // it to fail, if x < 0 (the only other case) // then do the comparison, and fail if y == 0 masm.Ccmp(W0, Operand(0), vixl::ZFlag, Assembler::NotEqual); masm.B(&failure, Assembler::Equal); masm.bind(&no_fail); masm.Sdiv(Wscratch, W0, W1); // Start calculating the remainder, x - (x / y) * y. masm.mul(WTemp, W1, Wscratch); if (op_ == JSOP_DIV) { // Result is a double if the remainder != 0, which happens // when (x/y)*y != x. masm.branch32(Assembler::NotEqual, R0.valueReg(), ExtractTemp0, &revertRegister); masm.movePayload(Rscratch, R0_); } else { // Calculate the actual mod. Set the condition code, so we can see if it is non-zero. masm.Subs(WTemp, W0, WTemp); // If X % Y == 0 and X < 0, the result is -0. masm.Ccmp(W0, Operand(0), vixl::NoFlag, Assembler::Equal); masm.branch(Assembler::LessThan, &revertRegister); masm.movePayload(ExtractTemp0, R0_); } break; } // ORR, EOR, AND can trivially be coerced int // working without affecting the tag of the dest.. case JSOP_BITOR: masm.Orr(X0, X0, Operand(X1)); break; case JSOP_BITXOR: masm.Eor(X0, X0, Operand(W1, vixl::UXTW)); break; case JSOP_BITAND: masm.And(X0, X0, Operand(X1)); break; // LSH, RSH and URSH can not. case JSOP_LSH: // ARM will happily try to shift by more than 0x1f. masm.Lsl(Wscratch, W0, W1); masm.movePayload(Rscratch, R0.valueReg()); break; case JSOP_RSH: masm.Asr(Wscratch, W0, W1); masm.movePayload(Rscratch, R0.valueReg()); break; case JSOP_URSH: masm.Lsr(Wscratch, W0, W1); if (allowDouble_) { Label toUint; // Testing for negative is equivalent to testing bit 31 masm.Tbnz(Wscratch, 31, &toUint); // Move result and box for return. masm.movePayload(Rscratch, R0_); EmitReturnFromIC(masm); masm.bind(&toUint); masm.convertUInt32ToDouble(Rscratch, ScratchDoubleReg); masm.boxDouble(ScratchDoubleReg, R0, ScratchDoubleReg); } else { // Testing for negative is equivalent to testing bit 31 masm.Tbnz(Wscratch, 31, &failure); // Move result for return. masm.movePayload(Rscratch, R0_); } break; default: MOZ_CRASH("Unhandled op for BinaryArith_Int32."); } EmitReturnFromIC(masm); switch (op_) { case JSOP_MUL: masm.bind(&maybeNegZero); // Result is -0 if exactly one of lhs or rhs is negative. masm.Cmn(W0, W1); masm.j(Assembler::Signed, &failure); // Result is +0, so use the zero register. masm.movePayload(rzr, R0_); EmitReturnFromIC(masm); break; case JSOP_DIV: case JSOP_MOD: masm.bind(&revertRegister); break; default: break; } // Failure case - jump to next stub. masm.bind(&failure); EmitStubGuardFailure(masm); return true; }
template <typename Visitor> void enumerateFields_gen(OperandOperandList obj, Visitor & vis) { enumerateFields_gen(Operand(obj), vis); vis(obj.elements(),"elements"); }
template <typename Visitor> void enumerateFields_gen(OperandRegister obj, Visitor & vis) { enumerateFields_gen(Operand(obj), vis); vis(obj.regKind(),"regKind"); vis(obj.regNum(),"regNum"); }
template <typename Visitor> void enumerateFields_gen(OperandConstantBytes obj, Visitor & vis) { enumerateFields_gen(Operand(obj), vis); vis(obj.type(),"type"); vis(obj.bytes(),"bytes"); }
template <typename Visitor> void enumerateFields_gen(OperandCodeRef obj, Visitor & vis) { enumerateFields_gen(Operand(obj), vis); vis(obj.ref(),"ref"); }
template <typename Visitor> void enumerateFields_gen(OperandAlign obj, Visitor & vis) { enumerateFields_gen(Operand(obj), vis); vis(obj.align(),"align"); }
void NesCpuTranslator::mSync() { // r0 - 6502.PC address of the next instruction __ bind(&m_syncLabel); Label exitSync; Label handleEvent; mSaveInternalFlags(); // IRQ can be cleared, so we must fetch additional cycles every time mFetchAdditionalCycles(); mHandleInterrupts(); // IRQ may be pending and P.I can be set, in this case we may not call // nesSync if mCycles < 0 __ mov(mCycles, mCycles, SetCC); __ b(&m_checkInterruptsForNextInstruction, mi); __ bind(&m_syncWithoutInterruptHandling); int preserved = r0.bit() | lr.bit(); #if defined(FRAME_POINTER_FOR_GDB) preserved |= fp.bit(); #endif __ stm(db_w, sp, preserved); #if defined(FRAME_POINTER_FOR_GDB) __ add(fp, sp, Operand(2*4)); #endif Label dontSyncWithApuAndClock; __ ldr(ip, MemOperand(mDataBase, offsetof(NesCpuRecData,startCycles))); __ add(r0, mCycles, ip, SetCC); __ b(&dontSyncWithApuAndClock, eq); mCallCFunction(offsetof(NesCpuRecData,apuClock)); if (nesMapper->hasClock()) { __ ldr(ip, MemOperand(mDataBase, offsetof(NesCpuRecData,startCycles))); __ add(r0, mCycles, ip, SetCC); mCallCFunction(offsetof(NesCpuRecData,mapperClock)); } __ bind(&dontSyncWithApuAndClock); __ mov(r0, mCycles); mCallCFunction(offsetof(NesCpuRecData,nesSync)); __ str(r0, MemOperand(mDataBase, offsetof(NesCpuRecData,startCycles))); __ rsb(mCycles, r0, Operand(0), SetCC); __ ldm(ia_w, sp, preserved); // if r0 >= 0 then it means we should handle an event __ b(&handleEvent, pl); // interrupts handling is a little tricky: // - once interrupt occurs save cycles in the memory // - force mSync to be called next time by setting mCycles to zero // - handle interrupt in the new mSync call __ bind(&m_checkInterruptsForNextInstruction); mClearAlert(); __ ldr(ip, MemOperand(mDataBase, offsetof(NesCpuRecData,interrupts))); __ mov(ip, ip, SetCC); __ b(&exitSync, eq); // interrupt is pending here __ str(mCycles, MemOperand(mDataBase, offsetof(NesCpuRecData,additionalCycles))); __ mov(mCycles, Operand(0)); __ b(&exitSync); // handleEvent: __ bind(&handleEvent); __ rsb(r1, mCycles, Operand(0)); __ mov(mCycles, Operand(0)); __ str(mCycles, MemOperand(mDataBase, offsetof(NesCpuRecData,startCycles))); mHandleEvent(); __ b(&m_syncWithoutInterruptHandling); // exitSync: __ bind(&exitSync); mRestoreInternalFlags(); // r0 must be loaded here with 6502.PC address of the next instruction __ mov(pc, lr); }
template <typename Visitor> void enumerateFields_gen(OperandWavesize obj, Visitor & vis) { enumerateFields_gen(Operand(obj), vis); }
void NesCpuTranslator::mClearAlert() { __ mov(ip, Operand(NesCpuRecData::AlertOff)); __ str(ip, MemOperand(mDataBase, offsetof(NesCpuRecData,alert))); }
void NesSyncCompiler::mClock(int ppuCycles) { /* Here the compiler will generate following function: syncData.baseCycleCounter += baseCycles; u64 cpuCyclesNow = syncData.baseCycleCounter / nesEmu.clockDividerForCpu(); syncData.cpuCycleCounter += additionalCpuCycles; int newCpuCycles = cpuCyclesNow - syncData.cpuCycleCounter; if (newCpuCycles > 0) { syncData.cpuCycleCounter += newCpuCycles; return newCpuCycles; } return 0; If return value != 0 it will return to the cpu emulation also. */ int baseCycles = ppuCycles * nesEmu.clockDividerForPpu(); Q_ASSERT(baseCycles >= 0); __ Ldrd(r0, r1, MemOperand(m_dataBase, offsetof(NesSyncData,baseCycleCounter))); __ add(r0, r0, Operand(baseCycles), SetCC); __ adc(r1, r1, Operand(0)); __ Strd(r0, r1, MemOperand(m_dataBase, offsetof(NesSyncData,baseCycleCounter))); if (nesEmu.clockDividerForCpu() == 12 #if !defined(CAN_USE_ARMV7_INSTRUCTIONS) || nesEmu.clockDividerForCpu() == 16 #endif ) { __ mov(r2, Operand(nesEmu.clockDividerForCpu())); __ mov(r3, Operand(0)); u8 *uldiv = reinterpret_cast<u8 *>(&__aeabi_uldivmod); __ mov(ip, Operand(reinterpret_cast<u32>(uldiv))); __ blx(ip); #if defined(CAN_USE_ARMV7_INSTRUCTIONS) } else if (nesEmu.clockDividerForCpu() == 16) { __ bfi(r0, r1, 0, 4); __ mov(r0, Operand(r0, ROR, 4)); __ mov(r1, Operand(r1, LSR, 4)); #endif } else { UNREACHABLE(); } __ Ldrd(r2, r3, MemOperand(m_dataBase, offsetof(NesSyncData,cpuCycleCounter))); __ add(r2, r2, m_additionalCpuCycles, SetCC); __ adc(r3, r3, Operand(0)); __ Strd(r2, r3, MemOperand(m_dataBase, offsetof(NesSyncData,cpuCycleCounter))); // clear additionalCpuCycles here because mClock can be executed multiple // times in single synchronization step __ mov(m_additionalCpuCycles, Operand(0)); __ sub(r0, r0, r2); __ cmp(r0, Operand(0)); __ mov(r0, Operand(0), LeaveCC, le); Label holdCpu; __ b(&holdCpu, le); __ add(r2, r2, r0, SetCC); __ adc(r3, r3, Operand(0)); __ Strd(r2, r3, MemOperand(m_dataBase, offsetof(NesSyncData,cpuCycleCounter))); mLeaveToCpu(); __ bind(&holdCpu); }
void Processor::RunMemoryProg(int _n_trace) /* MemCell* memory //pointer to an array!, Processor* pProc, int Trace*/ { int StopFlag = 0; char cInput[20]; char cInTrace[20]; Trace = _n_trace; setInstructionCounter(START_ADDRESS); // set counter to the start == 0 do { // copy next memory cell to the Register: this->InstructionRegister(memory->GetCellValue(this->InstructionCounter()) ); // get an operation code and operand from Register: this->GetCOPO(); // save an address of memory cell where data is: memory->SetCellCounter(Operand()); switch ( this->OperationCode() ) { case READ: // 10 - read a word from the terminal to the memory cell printf (" Enter value: > "); gets(cInput); memory->SetCellValue(cInput); // this->incInctructionCounter(); break; case WRITE:// 11 - print a word from the memory cell to the terminal // memory->PrintCurCellNumber(); printf ("Output: \n"); printf ("**************\n"); memory->PrintCellValue(); printf ("\n**************\n\n"); this->incInctructionCounter(); break; case LOAD: // 20 - save a word from the memory cell to an accumulator this->Accumulator( memory->GetCellValue() ); this->incInctructionCounter(); break; case STORE: // 21 - //save a word from accumulator to memory cell memory->SetCellValue(this->Accumulator()); this->incInctructionCounter(); break; case ADD: this->Accumulator(this->Accumulator() + memory->GetCellValue()); this->incInctructionCounter(); break; case SUBTRACT: this->Accumulator(this->Accumulator() - memory->GetCellValue()); // this->incInctructionCounter(); break; case DIVIDE: if (this->Accumulator() == 0) { printf ("ERROR: divide to zero!\n"); printf ("Program complete by error.\n"); StopFlag = 1; } else { this->Accumulator(memory->GetCellValue() / this->Accumulator()); } this->incInctructionCounter(); break; case MULTIPLY: this->Accumulator(this->Accumulator() * memory->GetCellValue()); // this->incInctructionCounter(); break; case BRANCH: //GOTO this->setInstructionCounter(Operand()); break; case BRANCHNEG: // branch if accumulator is negative if (this->Accumulator() < 0) this->setInstructionCounter(Operand()); else this->incInctructionCounter(); break; case BRANCHZERO: if (this->Accumulator() == 0) this->setInstructionCounter(Operand()); else this->incInctructionCounter(); break; case HALT: printf ("Program complete.\n"); StopFlag = 1; break; default: printf ("Unexpected value in the address %d\n", Operand()); StopFlag = 1; }// case if (Trace) { memory->PrintMemoryDump (); this->PrintProcState(); printf("\nPress Enter to TRACE >> "); gets(cInTrace); } } while (!StopFlag); this->PrintProcState(); };
void NesSyncCompiler::mPpuSetVBlank(bool on) { __ mov(r0, Operand(static_cast<int>(on))); mCallCFunction(offsetof(NesSyncData,ppuSetVBlank)); }
void CCodeGenerator::operator()(IntegerLiteral* expression) { //return_ = alloc_temp(expression->type()); //out_ << expression->value()->string() << ";\n"; return_ = Operand(expression); }
#include <minivm/language.h> /* Prints 0 1 2 3 using the stack. */ Instruction code[15] = { Instruction(PUSH, Operand(IMM, 3)), Instruction(MOV, Operand(IMM, 2), Operand(REG, R0)), Instruction(PUSH, Operand(REG, R0)), Instruction(MOV, Operand(IMM, 1), Operand(REG, R1)), Instruction(PUSH, Operand(REG, R1)), Instruction(PUSH, Operand(REG, ZERO)), Instruction(POP, Operand(REG, R0)), Instruction(PRINT, Operand(REG, R0)), Instruction(POP, Operand(REG, R0)), Instruction(PRINT, Operand(REG, R0)), Instruction(POP, Operand(REG, R0)), Instruction(PRINT, Operand(REG, R0)), Instruction(POP, Operand(REG, R0)), Instruction(PRINT, Operand(REG, R0)), Instruction(HLT) };
void CCodeGenerator::operator()(BooleanLiteral* expression) { return_ = Operand(expression); }
/*! Translates 6502 instructions starting from \a instrPointer. \a instrPointer contains value of the 6502.PC register \a caller is a pointer to the branch instruction which initiated the translation */ inline void *NesCpuTranslator::process(u16 instrPointer, u8 *caller) { int count = 128; if (instrPointer < 0x4000) { count = 16; memset32(m_labels + m_lastRecompilationInRam, -m_translateCallerLabel.pos()-1, count * 4); m_lastRecompilationInRam = instrPointer; } // check if already translated if (m_labels[instrPointer] == m_translateCallerLabel) { Q_ASSERT(!m_checkAlertAfterInstruction); m_recPc = instrPointer; int page = nesCpuPageByAddr(instrPointer); int recompiledStart = m_pageTranslationOffset[page]; m_masm->setPcOffset(recompiledStart); // recompile here while (m_labels[m_recPc] == m_translateCallerLabel && nesCpuPageByAddr(m_recPc) == page && count > 0) { m_labels[m_recPc].unuse(); __ bind(&m_labels[m_recPc]); #if defined(ENABLE_DEBUGGING) __ mov(r0, Operand(currentPc())); __ bl(&m_debugStepLabel); #endif #if !defined(DISABLE_RECOMPILER_OPTIMIZATIONS) if (!mTryOptimize()) #endif mSingleInstruction(); if (m_checkAlertAfterInstruction) { mCheckAlert(); m_checkAlertAfterInstruction = false; } count--; } // in the end jump to next instruction label u16 endRecPc = m_recPc; m_recPc = instrPointer; mJump(endRecPc); // flush const pool or any other pending data in the assembler m_masm->flush(); // save translation end pointer for this page int recompiledEnd = m_masm->pcOffset(); m_pageTranslationOffset[page] = recompiledEnd; Q_ASSERT(page == 0 || recompiledEnd < (page+1) * BlockSize); // flush instruction cache int recompiledSize = recompiledEnd - recompiledStart; Cpu::flushICache(m_codeBuffer + recompiledStart, recompiledSize); // mark translation page used m_pageUsedMask |= 1 << page; // handle section boundary because 6502 has variable length of // instructions (m_recPc == 0 on KIL instruction so omit that value) int pageNow = nesCpuPageByAddr(m_recPc); if (m_recPc && pageNow != page) saveTranslationBoundary(page, m_recPc & NesCpuBankMask); } fixCallerInstruction(instrPointer, caller); return m_codeBuffer + m_labels[instrPointer].pos(); }
BOOL CR_ModuleEx::_DisAsmAddr64(CR_Addr64 func, CR_Addr64 va) { if (!IsModuleLoaded() || !Is64Bit()) return FALSE; // calculate int len; char outbuf[256]; CR_Addr64 addr; // add or retrieve the code function auto cf = Info64()->CodeFuncFromAddr(func); if (cf == NULL) { Info64()->MapAddrToCodeFunc().emplace(func, make_shared<CR_CodeFunc64>()); cf = Info64()->CodeFuncFromAddr(func); } assert(cf); if (func == va) { cf->Addr() = func; } auto pCode = CodeSectionHeader(); assert(pCode); DWORD rva = RVAFromVA64(va); LPBYTE input = m_pLoadedImage + rva; LPBYTE iend = m_pLoadedImage + pCode->RVA + pCode->SizeOfRawData; while (input < iend) { // add or retrieve op.code auto oc = Info64()->OpCodeFromAddr(va); if (oc == NULL) { Info64()->MapAddrToOpCode().emplace(va, make_shared<CR_OpCode64>()); oc = Info64()->OpCodeFromAddr(va); // set op.code address oc->Addr() = va; } assert(oc); if (oc->FuncAddrs().count(func) > 0) break; // add function address for this op.code oc->FuncAddrs().emplace(func); if (oc->FuncAddrs().size() > 1) { cf->FuncFlags() |= cr_FF_FUNCINFUNC; // function in function } if (oc->Codes().empty()) { // disassemble len = disasm(input, outbuf, sizeof(outbuf), 64, va, false, 0); // parse insn if (!len || input + len > iend) { len = 1; oc->Name() = "???"; oc->OpCodeType() = cr_OCT_UNKNOWN; // don't decompile if any unknown instruction. cf->FuncFlags() |= cr_FF_INVALID; } else { oc->Parse(outbuf); } // complement operand size oc->DeductOperandSizes(); // add asm codes to op.code oc->Codes().insert(oc->Codes().end(), input, &input[len]); } else { len = int(oc->Codes().size()); } BOOL bBreak = FALSE; switch (oc->OpCodeType()) { case cr_OCT_JCC: // conditional jump switch (oc->Operand(0)->GetOperandType()) { case cr_DF_IMM: addr = oc->Operand(0)->Value64(); cf->Jumpers().emplace(va); cf->Jumpees().emplace(addr); break; default: break; } break; case cr_OCT_JMP: // jump switch (oc->Operand(0)->GetOperandType()) { case cr_DF_IMM: if (func == va) { // func is jumper cf->FuncFlags() |= cr_FF_JUMPERFUNC; addr = oc->Operand(0)->Value64(); Info64()->Entrances().emplace(addr); cf->Callers().emplace(addr); auto newcf = Info64()->CodeFuncFromAddr(addr); if (newcf == NULL) { Info64()->MapAddrToCodeFunc().emplace( addr, make_shared<CR_CodeFunc64>()); newcf = Info64()->CodeFuncFromAddr(addr); } newcf->Addr() = addr; newcf->Callees().emplace(func); } else { addr = oc->Operand(0)->Value64(); cf->Jumpers().emplace(va); cf->Jumpees().emplace(addr); } break; case cr_DF_MEMIMM: if (func == va) { // func is jumper cf->FuncFlags() |= cr_FF_JUMPERFUNC; bBreak = TRUE; } break; default: break; } bBreak = TRUE; break; case cr_OCT_CALL: // call switch (oc->Operand(0)->GetOperandType()) { case cr_DF_IMM: // function call addr = oc->Operand(0)->Value64(); Info64()->Entrances().emplace(addr); cf->Callees().emplace(addr); { auto newcf = Info64()->CodeFuncFromAddr(addr); if (newcf == NULL) { Info64()->MapAddrToCodeFunc().emplace( addr, make_shared<CR_CodeFunc64>()); newcf = Info64()->CodeFuncFromAddr(addr); } newcf->Addr() = addr; newcf->Callers().emplace(func); } break; default: break; } break; case cr_OCT_RETURN: // return if (oc->Operands().size() && oc->Operand(0)->GetOperandType() == cr_DF_IMM) { cf->StackArgSizeRange().Set(oc->Operand(0)->Value64()); } else { if (func == va) { cf->FuncFlags() |= cr_FF_RETURNONLY; } } cf->Exits().insert(va); bBreak = TRUE; break; default: break; } if (bBreak) break; // move to next position input += len; va += len; } return TRUE; } // CR_ModuleEx::_DisAsmAddr64
/*! Increments cycle counter \a n times. */ inline void NesCpuTranslator::mAddCycles(int n, Condition cond) { __ add(mCycles, mCycles, Operand(n), LeaveCC, cond); }
//TODO: Need more work bool Instruction::GetOperandReference(Database const& rDatabase, u8 Oprd, Address const& rAddrSrc, Address& rAddrDst) const { medusa::Operand const* pOprd = Operand(Oprd); TOffset Offset = 0x0; rAddrDst = rAddrSrc; // XXX: Should never happen if (pOprd == NULL) return false; if (pOprd->GetType() & O_NO_REF) return false; if ((pOprd->GetType() & O_REL) || ((pOprd->GetType() & O_REG_PC_REL) && (pOprd->GetType() & O_MEM))) { switch (pOprd->GetType() & DS_MASK) { case DS_8BIT: Offset = static_cast<s8> (pOprd->GetValue()) + GetLength(); break; case DS_16BIT: Offset = static_cast<s16>(pOprd->GetValue()) + GetLength(); break; case DS_32BIT: Offset = static_cast<s32>(pOprd->GetValue()) + GetLength(); break; case DS_64BIT: Offset = static_cast<s64>(pOprd->GetValue()) + GetLength(); break; default: Offset = pOprd->GetValue() + GetLength(); } rAddrDst = rAddrSrc + Offset; return true; } else if ((pOprd->GetType() & O_ABS) || (pOprd->GetType() & O_IMM) || (pOprd->GetType() & O_DISP)) { switch (pOprd->GetType() & DS_MASK) { case DS_8BIT: rAddrDst.SetOffset(static_cast<s8> (pOprd->GetValue())); break; case DS_16BIT: rAddrDst.SetOffset(static_cast<s16>(pOprd->GetValue())); break; case DS_32BIT: rAddrDst.SetOffset(static_cast<s32>(pOprd->GetValue())); break; case DS_64BIT: rAddrDst.SetOffset(static_cast<s64>(pOprd->GetValue())); break; default: rAddrDst.SetOffset(pOprd->GetValue()); } return true; } else if ((pOprd->GetType() & O_MEM)) { if (pOprd->GetType() & O_REG_PC_REL) Offset += rAddrSrc.GetOffset(); switch (pOprd->GetType() & DS_MASK) { case DS_8BIT: Offset += static_cast<s8> (pOprd->GetValue()) + GetLength(); break; case DS_16BIT: Offset += static_cast<s16>(pOprd->GetValue()) + GetLength(); break; case DS_32BIT: Offset += static_cast<s32>(pOprd->GetValue()) + GetLength(); break; case DS_64BIT: Offset += static_cast<s64>(pOprd->GetValue()) + GetLength(); break; default: Offset += pOprd->GetValue() + GetLength(); } rAddrDst.SetOffset(Offset); TOffset RawOffset; MemoryArea const* pMemArea = rDatabase.GetMemoryArea(rAddrDst); if (pMemArea == nullptr) return false; if (!pMemArea->Convert(Offset, RawOffset)) return false; BinaryStream const& rBinStrm = pMemArea->GetBinaryStream(); u64 ReadOffset = 0x0; try { switch (pOprd->GetType() & MS_MASK) { case MS_8BIT: rBinStrm.Read(RawOffset, ReadOffset); ReadOffset &= 0xff; break; case MS_16BIT: rBinStrm.Read(RawOffset, ReadOffset); ReadOffset &= 0xffff; break; case MS_32BIT: rBinStrm.Read(RawOffset, ReadOffset); ReadOffset &= 0xffffffff; break; case MS_64BIT: rBinStrm.Read(RawOffset, ReadOffset); break; default: return false; } } catch(Exception&) { return false; } rAddrDst.SetOffset(ReadOffset); return true; } return false; }
#include <minivm/language.h> /* 3 will print a 3 and exit. Under 3 will ask for another number. * 4+ will exit immediately. */ Instruction code[7] = { Instruction(READ, Operand(REG, R0)), Instruction(CMP, Operand(REG, R0), Operand(IMM, 3)), Instruction(JMPE, Operand(IMM, 5)), Instruction(JMPL, Operand(REG, ZERO)), Instruction(JMP, Operand(IMM, 6)), Instruction(PRINT, Operand(REG, R0)), Instruction(HLT) };