/*=========================================================================*/ /* Fellow */ /* 68000 internal state */ /* */ /* Author: Petter Schau */ /* */ /* Copyright (C) 1991, 1992, 1996 Free Software Foundation, Inc. */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2, or (at your option) */ /* any later version. */ /* */ /* This program is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* */ /* You should have received a copy of the GNU General Public License */ /* along with this program; if not, write to the Free Software Foundation, */ /* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /*=========================================================================*/ #include "defs.h" #include "CpuModule.h" #include "CpuModule_Memory.h" #include "CpuModule_Internal.h" /* M68k registers */ static uint32_t cpu_regs[2][8]; /* 0 - data, 1 - address */ static uint32_t cpu_pc; static uint32_t cpu_usp; static uint32_t cpu_ssp; static uint32_t cpu_msp; static uint32_t cpu_sfc; static uint32_t cpu_dfc; uint32_t cpu_sr; // Not static because flags calculation use it extensively static uint32_t cpu_vbr; static uint16_t cpu_prefetch_word; static uint32_t cpu_cacr; static uint32_t cpu_caar; /* Irq management */ static BOOLE cpu_raise_irq; static uint32_t cpu_raise_irq_level; /* Reset values */ static uint32_t cpu_initial_pc; static uint32_t cpu_initial_sp; /* Flag set if CPU is stopped */ static BOOLE cpu_stop; /* The current CPU model */ static uint32_t cpu_model_major = -1; static uint32_t cpu_model_minor; static uint8_t cpu_model_mask; /* For exception handling */ #ifdef CPU_INSTRUCTION_LOGGING static uint16_t cpu_current_opcode; #endif static uint32_t cpu_original_pc; static bool cpu_instruction_aborted; /* Number of cycles taken by the last intstruction */ static uint32_t cpu_instruction_time; /* Getters and setters */ void cpuSetDReg(uint32_t i, uint32_t value) {cpu_regs[0][i] = value;} uint32_t cpuGetDReg(uint32_t i) {return cpu_regs[0][i];} void cpuSetAReg(uint32_t i, uint32_t value) {cpu_regs[1][i] = value;} uint32_t cpuGetAReg(uint32_t i) {return cpu_regs[1][i];} void cpuSetReg(uint32_t da, uint32_t i, uint32_t value) {cpu_regs[da][i] = value;} uint32_t cpuGetReg(uint32_t da, uint32_t i) {return cpu_regs[da][i];} /// /// Get the supervisor bit from sr. /// BOOLE cpuGetFlagSupervisor(void) { return cpu_sr & 0x2000; } /// /// Get the master/irq state bit from sr. /// BOOLE cpuGetFlagMaster(void) { return cpu_sr & 0x1000; } void cpuSetUspDirect(uint32_t usp) {cpu_usp = usp;} uint32_t cpuGetUspDirect() {return cpu_usp;} uint32_t cpuGetUspAutoMap() {return (cpuGetFlagSupervisor()) ? cpuGetUspDirect() : cpuGetAReg(7);} void cpuSetSspDirect(uint32_t ssp) {cpu_ssp = ssp;} uint32_t cpuGetSspDirect() {return cpu_ssp;} uint32_t cpuGetSspAutoMap() {return (cpuGetFlagSupervisor()) ? cpuGetAReg(7) : cpuGetSspDirect();} void cpuSetMspDirect(uint32_t msp) {cpu_msp = msp;} uint32_t cpuGetMspDirect() {return cpu_msp;} /// /// Returns the master stack pointer. /// uint32_t cpuGetMspAutoMap(void) { if (cpuGetFlagSupervisor() && cpuGetFlagMaster()) { return cpuGetAReg(7); } return cpuGetMspDirect(); } /// /// Sets the master stack pointer. /// void cpuSetMspAutoMap(uint32_t new_msp) { if (cpuGetFlagSupervisor() && cpuGetFlagMaster()) { cpuSetAReg(7, new_msp); } else { cpuSetMspDirect(new_msp); } } /// /// Returns the interrupt stack pointer. ssp is used as isp. /// uint32_t cpuGetIspAutoMap(void) { if (cpuGetFlagSupervisor() && !cpuGetFlagMaster()) { return cpuGetAReg(7); } return cpuGetSspDirect(); } /// /// Sets the interrupt stack pointer. ssp is used as isp. /// void cpuSetIspAutoMap(uint32_t new_isp) { if (cpuGetFlagSupervisor() && !cpuGetFlagMaster()) { cpuSetAReg(7, new_isp); } else { cpuSetSspDirect(new_isp); } } void cpuSetPC(uint32_t address) {cpu_pc = address;} uint32_t cpuGetPC() {return cpu_pc;} void cpuSetStop(BOOLE stop) {cpu_stop = stop;} BOOLE cpuGetStop() {return cpu_stop;} void cpuSetVbr(uint32_t vbr) {cpu_vbr = vbr;} uint32_t cpuGetVbr() {return cpu_vbr;} void cpuSetSfc(uint32_t sfc) {cpu_sfc = sfc;} uint32_t cpuGetSfc() {return cpu_sfc;} void cpuSetDfc(uint32_t dfc) {cpu_dfc = dfc;} uint32_t cpuGetDfc() {return cpu_dfc;} void cpuSetCacr(uint32_t cacr) {cpu_cacr = cacr;} uint32_t cpuGetCacr() {return cpu_cacr;} void cpuSetCaar(uint32_t caar) {cpu_caar = caar;} uint32_t cpuGetCaar() {return cpu_caar;} void cpuSetSR(uint32_t sr) {cpu_sr = sr;} uint32_t cpuGetSR() {return cpu_sr;} void cpuSetInstructionTime(uint32_t cycles) {cpu_instruction_time = cycles;} uint32_t cpuGetInstructionTime() {return cpu_instruction_time;} void cpuSetOriginalPC(uint32_t pc) {cpu_original_pc = pc;} uint32_t cpuGetOriginalPC() {return cpu_original_pc;} void cpuSetInstructionAborted(bool aborted) {cpu_instruction_aborted = aborted;} bool cpuGetInstructionAborted() {return cpu_instruction_aborted;} #ifdef CPU_INSTRUCTION_LOGGING void cpuSetCurrentOpcode(uint16_t opcode) {cpu_current_opcode = opcode;} uint16_t cpuGetCurrentOpcode() {return cpu_current_opcode;} #endif void cpuSetRaiseInterrupt(BOOLE raise_irq) {cpu_raise_irq = raise_irq;} BOOLE cpuGetRaiseInterrupt() {return cpu_raise_irq;} void cpuSetRaiseInterruptLevel(uint32_t raise_irq_level) {cpu_raise_irq_level = raise_irq_level;} uint32_t cpuGetRaiseInterruptLevel() {return cpu_raise_irq_level;} uint32_t cpuGetIrqLevel() {return (cpu_sr & 0x0700) >> 8;} void cpuSetInitialPC(uint32_t pc) {cpu_initial_pc = pc;} uint32_t cpuGetInitialPC() {return cpu_initial_pc;} void cpuSetInitialSP(uint32_t sp) {cpu_initial_sp = sp;} uint32_t cpuGetInitialSP() {return cpu_initial_sp;} void cpuSetModelMask(uint8_t model_mask) {cpu_model_mask = model_mask;} uint8_t cpuGetModelMask() {return cpu_model_mask;} uint32_t cpuGetModelMajor() {return cpu_model_major;} uint32_t cpuGetModelMinor() {return cpu_model_minor;} static void cpuCalculateModelMask(void) { switch (cpuGetModelMajor()) { case 0: cpuSetModelMask(0x01); break; case 1: cpuSetModelMask(0x02); break; case 2: cpuSetModelMask(0x04); break; case 3: cpuSetModelMask(0x08); break; } } void cpuSetModel(uint32_t major, uint32_t minor) { BOOLE makeOpcodeTable = (cpu_model_major != major); cpu_model_major = major; cpu_model_minor = minor; cpuCalculateModelMask(); cpuStackFrameInit(); if (makeOpcodeTable) cpuMakeOpcodeTableForModel(); } #if 0 void cpuSetDRegWord(uint32_t regno, uint16_t val) {*((int16_t*)&cpu_regs[0][regno]) = val;} void cpuSetDRegByte(uint32_t regno, uint8_t val) {*((uint8_t*)&cpu_regs[0][regno]) = val;} #else // MPW -- above assumes little endian. void cpuSetDRegWord(uint32_t regno, uint16_t val) {cpu_regs[0][regno] &= 0xffff0000; cpu_regs[0][regno] |= val;} void cpuSetDRegByte(uint32_t regno, uint8_t val) {cpu_regs[0][regno] &= 0xffffff00; cpu_regs[0][regno] |= val;} #endif uint16_t cpuGetRegWord(uint32_t i, uint32_t regno) {return (uint16_t)cpu_regs[i][regno];} uint16_t cpuGetDRegWord(uint32_t regno) {return (uint16_t)cpu_regs[0][regno];} uint8_t cpuGetDRegByte(uint32_t regno) {return (uint8_t)cpu_regs[0][regno];} uint32_t cpuGetDRegWordSignExtLong(uint32_t regno) {return cpuSignExtWordToLong(cpuGetDRegWord(regno));} uint16_t cpuGetDRegByteSignExtWord(uint32_t regno) {return cpuSignExtByteToWord(cpuGetDRegByte(regno));} uint32_t cpuGetDRegByteSignExtLong(uint32_t regno) {return cpuSignExtByteToLong(cpuGetDRegByte(regno));} uint16_t cpuGetARegWord(uint32_t regno) {return (uint16_t)cpu_regs[1][regno];} uint8_t cpuGetARegByte(uint32_t regno) {return (uint8_t)cpu_regs[1][regno];} typedef uint16_t (*cpuGetWordFunc)(void); typedef uint32_t (*cpuGetLongFunc)(void); static uint16_t cpuGetNextWordInternal(void) { uint16_t data = memoryReadWord(cpuGetPC() + 2); return data; } static uint32_t cpuGetNextLongInternal(void) { uint32_t data = memoryReadLong(cpuGetPC() + 2); return data; } uint16_t cpuGetNextWord(void) { uint16_t tmp = cpu_prefetch_word; cpu_prefetch_word = cpuGetNextWordInternal(); cpuSetPC(cpuGetPC() + 2); return tmp; } uint32_t cpuGetNextWordSignExt(void) { return cpuSignExtWordToLong(cpuGetNextWord()); } uint32_t cpuGetNextLong(void) { uint32_t tmp = cpu_prefetch_word << 16; uint32_t data = cpuGetNextLongInternal(); cpu_prefetch_word = (uint16_t) data; cpuSetPC(cpuGetPC() + 4); return tmp | (data >> 16); } void cpuInitializePrefetch(void) { cpu_prefetch_word = memoryReadWord(cpuGetPC()); } void cpuClearPrefetch(void) { cpu_prefetch_word = 0; } void cpuSkipNextWord(void) { cpuSetPC(cpuGetPC() + 2); cpuInitializePrefetch(); } void cpuSkipNextLong(void) { cpuSetPC(cpuGetPC() + 4); cpuInitializePrefetch(); } void cpuInitializeFromNewPC(uint32_t new_pc) { cpuSetPC(new_pc); cpuInitializePrefetch(); } void cpuSaveState(FILE *F) { fwrite(&cpu_model_major, sizeof(cpu_model_major), 1, F); fwrite(&cpu_model_minor, sizeof(cpu_model_minor), 1, F); for (uint32_t i = 0; i < 2; i++) { for (uint32_t j = 0; j < 7; j++) { fwrite(&cpu_regs[i][j], sizeof(cpu_regs[i][j]), 1, F); } } fwrite(&cpu_pc, sizeof(cpu_pc), 1, F); fwrite(&cpu_usp, sizeof(cpu_usp), 1, F); fwrite(&cpu_ssp, sizeof(cpu_ssp), 1, F); fwrite(&cpu_msp, sizeof(cpu_msp), 1, F); fwrite(&cpu_sfc, sizeof(cpu_sfc), 1, F); fwrite(&cpu_dfc, sizeof(cpu_dfc), 1, F); fwrite(&cpu_sr, sizeof(cpu_sr), 1, F); fwrite(&cpu_prefetch_word, sizeof(cpu_prefetch_word), 1, F); fwrite(&cpu_vbr, sizeof(cpu_vbr), 1, F); fwrite(&cpu_cacr, sizeof(cpu_cacr), 1, F); fwrite(&cpu_caar, sizeof(cpu_caar), 1, F); fwrite(&cpu_initial_pc, sizeof(cpu_initial_pc), 1, F); fwrite(&cpu_initial_sp, sizeof(cpu_initial_sp), 1, F); } void cpuLoadState(FILE *F) { fread(&cpu_model_major, sizeof(cpu_model_major), 1, F); fread(&cpu_model_minor, sizeof(cpu_model_minor), 1, F); for (uint32_t i = 0; i < 2; i++) { for (uint32_t j = 0; j < 7; j++) { fread(&cpu_regs[i][j], sizeof(cpu_regs[i][j]), 1, F); } } fread(&cpu_pc, sizeof(cpu_pc), 1, F); fread(&cpu_usp, sizeof(cpu_usp), 1, F); fread(&cpu_ssp, sizeof(cpu_ssp), 1, F); fread(&cpu_msp, sizeof(cpu_msp), 1, F); fread(&cpu_sfc, sizeof(cpu_sfc), 1, F); fread(&cpu_dfc, sizeof(cpu_dfc), 1, F); fread(&cpu_sr, sizeof(cpu_sr), 1, F); fread(&cpu_prefetch_word, sizeof(cpu_prefetch_word), 1, F); fread(&cpu_vbr, sizeof(cpu_vbr), 1, F); fread(&cpu_cacr, sizeof(cpu_cacr), 1, F); fread(&cpu_caar, sizeof(cpu_caar), 1, F); fread(&cpu_initial_pc, sizeof(cpu_initial_pc), 1, F); fread(&cpu_initial_sp, sizeof(cpu_initial_sp), 1, F); cpuSetModel(cpu_model_major, cpu_model_minor); // Recalculates stack frames etc. }