void test_disassembleBytecodes_should_disassemble_an_array_of_bytecode(void) { char buffer[500] = {0}; int bytecode[20] = {0}; bytecode[0] = ldrImm(REG_4, -128); bytecode[1] = ldrMem(REG_0, REG_1, 8); bytecode[2] = strMem(REG_0, REG_1, 8); bytecode[3] = ldrMemSafe(REG_0, REG_1, 8); bytecode[4] = strMemSafe(REG_0, REG_1, 8); bytecode[5] = movReg(REG_0, DATA, REG_4, NOP, NOP); bytecode[6] = movReg(REG_0, DATA, REG_4, LSL, 4); bytecode[7] = movReg(REG_0, DATA, REG_4, LSR, 2); bytecode[8] = movReg(REG_0, DATA, REG_4, ASR, 6); bytecode[9] = movReg(REG_0, DATA, REG_4, RR, 5); bytecode[10] = ldm(REG_7, R4|R5|R6, INC, UPDATE); bytecode[11] = ldm(REG_7, R0|R5|R6, DEC, NO_UPDATE); bytecode[12] = stm(REG_7, R1|R2|R5|R6, DEC, UPDATE); bytecode[13] = stm(REG_7, R3|R4|R5|R6, INC, NO_UPDATE); bytecode[14] = ldms(REG_7, R3|R4|R5|R6, INC, NO_UPDATE); bytecode[15] = stms(REG_7, R0|R1|R2|R3|R4|R5|R6, DEC, NO_UPDATE); bytecode[16] = halt(); // Indicates end of bytecodes disassembleBytecodes(buffer, bytecode); printf("test_disassembleBytecodes_should_disassemble_an_array_of_bytecode\n"); printf("%s\n", &buffer[0]); }
void NesCpuTranslator::mExitPoint() { // restore registers and return to caller #if defined(FRAME_POINTER_FOR_GDB) __ ldm(ia_w, sp, kCalleeSaved | fp.bit() | pc.bit()); #else __ ldm(ia_w, sp, kCalleeSaved | pc.bit()); #endif }
void MacroAssembler::lowLevelDebug(const char *s, Register ra, Register rb, Register rc) { Q_ASSERT(ra.code() < 13 && rb.code() < 13 && rc.code() < 13); int preserved = 0x1fff | lr.bit(); stm(db_w, sp, preserved); add(fp, sp, Operand(12*4)); mrs(r4, CPSR); Label omitString; b(&omitString); int sPtr = intptr_t(buffer_ + pcOffset()); do { db(*s); } while (*(s++)); while (pcOffset() & 3) db('\0'); bind(&omitString); ldr(r3, MemOperand(sp, rc.code()*4)); ldr(r2, MemOperand(sp, rb.code()*4)); ldr(r1, MemOperand(sp, ra.code()*4)); mov(r0, Operand(sPtr)); void (*qDebugPtr)(const char *,...) = &qDebug; mov(ip, Operand(intptr_t(qDebugPtr))); blx(ip); msr(CPSR_f, Operand(r4)); ldm(ia_w, sp, preserved); }
void NesSyncCompiler::mLeaveToCpu() { __ add(r3, pc, Operand(Assembler::kInstrSize)); __ str(r3, MemOperand(m_dataBase, offsetof(NesSyncData,nextPc))); // return to cpu emulation __ ldm(ia_w, sp, m_regList | pc.bit()); // nesSyncRecData.nextPc points here now }
int instruction_cycle(CPU *cpu) { int halted = 1; (*cpu).ir = (*cpu).mem[(*cpu).pc]; handleInstruction(cpu); switch ((*cpu).opcode){ case 0: halted = 0; printf("Halt!"); break; case 1: ld(cpu); break; case 2: st(cpu); break; case 3: add(cpu); break; case 4: neg(cpu); break; case 5: ldm(cpu); break; case 6: addm(cpu); break; case 7: br(cpu); break; case 8: brp(cpu); break; case 9: io(cpu); break; default: printf("Error:Invalid opcode at address %d,Invalid number: %d",(*cpu).pc,(*cpu).mem[(*cpu).pc]); break; } (*cpu).pc++; return halted; // For Lab 7, we just print a message and halt after the 10th call // //char suffix[][4] = {"", "st","nd","rd","th"}; //printf("Calling instruction_cycle for %d%s time\n", call_nbr, suffix[min(call_nbr,4)]); }
void NesCpuTranslator::mHandleEvent() { Label saveState; Label loadState; Label exit; // arguments: r1 = event // reg list for saving state // r0 contains 6502.PC address // r2 contains 6502.P flags RegList regList = r0.bit() | r2.bit() | mA.bit() | mX.bit() | mY.bit() | mS.bit(); // regs member of NesCpuRecData should be placed at the start of the object Q_ASSERT(offsetof(NesCpuRecData,regs) == 0); __ cmp(r1, Operand(NesCpuBase::SaveStateEvent)); __ b(&saveState, eq); __ cmp(r1, Operand(NesCpuBase::LoadStateEvent)); __ b(&loadState, eq); // exitEvent: mExitPoint(); // loadState: __ bind(&loadState); __ ldm(ia, mDataBase, regList); mUnpackFlags(r2, r1); mSaveInternalFlags(); mLoadLabelAddress(r0, lr); // mCycles is zeroed later __ b(&exit); // saveState: __ bind(&saveState); mRestoreInternalFlags(); mPackFlags(r2); __ stm(ia, mDataBase, regList); // saveState occurs on frame end, ticks() will be used on new frame // so set it to zero __ mov(ip, Operand(0)); __ str(ip, MemOperand(mDataBase, offsetof(NesCpuRecData,currentCycles))); // exit: __ bind(&exit); }
static void ldm_t2(uint32_t inst) { uint16_t reg_list = inst & 0x1fff; bool M = !!(inst & 0x4000); bool P = !!(inst & 0x8000); uint8_t rn = (inst & 0xf0000) >> 16; bool W = !!(inst & 0x200000); if ((W == 1) && (rn == 0xd)) CORE_ERR_unpredictable("ldm_t2 --> pop\n"); uint16_t registers = (P << 15) | (M << 14) | reg_list; bool wback = (W == 1); if ((rn == 15) || (hamming(registers) < 2) || ((P == 1) && (M == 1))) CORE_ERR_unpredictable("ldm_t2, long ||'s\n"); if ((registers & 0x8000) && in_ITblock() && !last_in_ITblock()) CORE_ERR_unpredictable("ldm_t2, itstate stuff\n"); if (wback && (registers & (1 << (rn)))) CORE_ERR_unpredictable("ldm_t2, writeback mismatch?\n"); return ldm(rn, registers, wback); }
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); }