From f7b2692b338aaf37470be0a1d0e5ae42c82e0c65 Mon Sep 17 00:00:00 2001 From: Shamus Hammons Date: Thu, 7 Feb 2013 17:59:36 -0600 Subject: [PATCH] Fix to M68K core vs. DSP thread sync problem. Seems there were some M68K core calls coming from the DSP thread that caused problems with IRQ handling on the latter. There's a kludge in for now that should solve that problem but there may be even more like it lurking in the shadows. :-/ --- Makefile | 8 +-- src/dsp.cpp | 119 ++++++++++++++--------------------- src/dsp.h | 1 + src/file.cpp | 5 ++ src/gpu.cpp | 4 +- src/gpu.h | 4 ++ src/gui/debug/cpubrowser.cpp | 78 ++++++++++++++++++++++- src/gui/mainwin.cpp | 10 +++ src/jagdasm.cpp | 4 +- src/jaguar.cpp | 26 +++++++- src/joystick.cpp | 3 + src/log.cpp | 3 +- src/m68000/m68kinterface.c | 79 +++++++++++++++++------ src/m68000/m68kinterface.h | 7 +++ 14 files changed, 248 insertions(+), 103 deletions(-) diff --git a/Makefile b/Makefile index 88763de..edc1d20 100644 --- a/Makefile +++ b/Makefile @@ -42,10 +42,10 @@ obj: prepare: obj @echo -e "\033[01;33m***\033[00;32m Preparing to compile Virtual Jaguar...\033[00m" - @echo "#define VJ_RELEASE_VERSION \"v2.1.0\"" > src/version.h - @echo "#define VJ_RELEASE_SUBVERSION \"Final\"" >> src/version.h -# @echo "#define VJ_RELEASE_VERSION \"GIT `git log -1 --pretty=format:%ci | cut -d ' ' -f 1 | tr -d -`\"" > src/version.h -# @echo "#define VJ_RELEASE_SUBVERSION \"2.1.0 Prerelease\"" >> src/version.h +# @echo "#define VJ_RELEASE_VERSION \"v2.1.1\"" > src/version.h +# @echo "#define VJ_RELEASE_SUBVERSION \"Final\"" >> src/version.h + @echo "#define VJ_RELEASE_VERSION \"GIT `git log -1 --pretty=format:%ci | cut -d ' ' -f 1 | tr -d -`\"" > src/version.h + @echo "#define VJ_RELEASE_SUBVERSION \"2.1.1 Prerelease\"" >> src/version.h virtualjaguar: sources libs makefile-qt @echo -e "\033[01;33m***\033[00;32m Making Virtual Jaguar GUI...\033[00m" diff --git a/src/dsp.cpp b/src/dsp.cpp index 7a0553f..f39449b 100644 --- a/src/dsp.cpp +++ b/src/dsp.cpp @@ -99,6 +99,9 @@ bool doDSPDis = false; //bool doDSPDis = true; #endif +bool doDSPDis = false; +//#define DSP_DIS_JR +//#define DSP_DIS_JUMP /* No dis yet: @@ -306,6 +309,7 @@ static void dsp_opcode_subc(void); static void dsp_opcode_subq(void); static void dsp_opcode_subqmod(void); static void dsp_opcode_subqt(void); +static void dsp_opcode_illegal(void); uint8 dsp_opcode_cycles[64] = { @@ -351,7 +355,7 @@ void (* dsp_opcode[64])() = dsp_opcode_mirror, dsp_opcode_store_r14_indexed, dsp_opcode_store_r15_indexed, dsp_opcode_move_pc, dsp_opcode_jump, dsp_opcode_jr, dsp_opcode_mmult, dsp_opcode_mtoi, dsp_opcode_normi, dsp_opcode_nop, dsp_opcode_load_r14_ri, dsp_opcode_load_r15_ri, - dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_nop, dsp_opcode_addqmod, + dsp_opcode_store_r14_ri, dsp_opcode_store_r15_ri, dsp_opcode_illegal, dsp_opcode_addqmod, }; uint32 dsp_opcode_use[65]; @@ -389,7 +393,7 @@ uint32 dsp_control; static uint32 dsp_div_control; static uint8 dsp_flag_z, dsp_flag_n, dsp_flag_c; static uint32 * dsp_reg = NULL, * dsp_alternate_reg = NULL; -static uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32]; +uint32 dsp_reg_bank_0[32], dsp_reg_bank_1[32]; static uint32 dsp_opcode_first_parameter; static uint32 dsp_opcode_second_parameter; @@ -418,6 +422,7 @@ uint32 dsp_convert_zero[32] = { 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; + uint8 dsp_branch_condition_table[32 * 8]; static uint16 mirror_table[65536]; static uint8 dsp_ram_8[0x2000]; @@ -537,48 +542,6 @@ uint16 DSPReadWord(uint32 offset, uint32 who/*=UNKNOWN*/) WriteLog("DSP: ReadWord--Attempt to read from DSP register file by %s!\n", whoName[who]); //??? offset &= 0xFFFFFFFE; - // jaguar cd bios -/* if (jaguar_mainRom_crc32==0xa74a97cd) - { - if (offset==0xF1A114) return(0x0000); - if (offset==0xF1A116) return(0x0000); - if (offset==0xF1B000) return(0x1234); - if (offset==0xF1B002) return(0x5678); - }*/ -/* - if (jaguar_mainRom_crc32==0x7ae20823) - { - if (offset==0xF1B9D8) return(0x0000); - if (offset==0xF1B9Da) return(0x0000); - if (offset==0xF1B2C0) return(0x0000); - if (offset==0xF1B2C2) return(0x0000); - } -*/ - // pour permettre � wolfenstein 3d de tourner sans le dsp -/* if ((offset==0xF1B0D0)||(offset==0xF1B0D2)) - return(0); -*/ - - // pour permettre � nba jam de tourner sans le dsp -/* if (jaguar_mainRom_crc32==0x4faddb18) - { - if (offset==0xf1b2c0) return(0); - if (offset==0xf1b2c2) return(0); - if (offset==0xf1b240) return(0); - if (offset==0xf1b242) return(0); - if (offset==0xF1B340) return(0); - if (offset==0xF1B342) return(0); - if (offset==0xF1BAD8) return(0); - if (offset==0xF1BADA) return(0); - if (offset==0xF1B040) return(0); - if (offset==0xF1B042) return(0); - if (offset==0xF1B0C0) return(0); - if (offset==0xF1B0C2) return(0); - if (offset==0xF1B140) return(0); - if (offset==0xF1B142) return(0); - if (offset==0xF1B1C0) return(0); - if (offset==0xF1B1C2) return(0); - }*/ if (offset >= DSP_WORK_RAM_BASE && offset <= DSP_WORK_RAM_BASE+0x1FFF) { @@ -979,6 +942,7 @@ WriteLog("\n"); break; } case 0x18: +WriteLog("DSP: Modulo data %08X written by %s.\n", data, whoName[who]); dsp_modulo = data; break; case 0x1C: @@ -1012,6 +976,10 @@ void DSPUpdateRegisterBanks(void) dsp_reg = dsp_reg_bank_1, dsp_alternate_reg = dsp_reg_bank_0; else dsp_reg = dsp_reg_bank_0, dsp_alternate_reg = dsp_reg_bank_1; + +#ifdef DSP_DEBUG_IRQ + WriteLog("DSP: Register bank #%s active.\n", (bank ? "1" : "0")); +#endif } // @@ -1033,6 +1001,7 @@ void DSPHandleIRQs(void) return; int which = 0; // Determine which interrupt + if (bits & 0x01) which = 0; if (bits & 0x02) @@ -1212,18 +1181,24 @@ DSPUpdateRegisterBanks(); if (bits & 0x20) which = 5; -#ifdef DSP_DEBUG_IRQ - WriteLog("DSP: Generating interrupt #%i...", which); -#endif - - dsp_flags |= IMASK; + dsp_flags |= IMASK; // Force Bank #0 //CC only! #ifdef DSP_DEBUG_CC ctrl1[4] = dsp_flags; #endif //!!!!!!!! +#ifdef DSP_DEBUG_IRQ + WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]); + WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]); +#endif DSPUpdateRegisterBanks(); #ifdef DSP_DEBUG_IRQ + WriteLog("DSP: Bank 0: R30=%08X, R31=%08X\n", dsp_reg_bank_0[30], dsp_reg_bank_0[31]); + WriteLog("DSP: Bank 1: R30=%08X, R31=%08X\n", dsp_reg_bank_1[30], dsp_reg_bank_1[31]); +#endif + +#ifdef DSP_DEBUG_IRQ + WriteLog("DSP: Generating interrupt #%i...", which); WriteLog(" [PC will return to %08X, R31 = %08X]\n", dsp_pc, dsp_reg[31]); #endif @@ -1231,12 +1206,15 @@ ctrl1[4] = dsp_flags; // move pc,r30 ; address of interrupted code // store r30,(r31) ; store return address dsp_reg[31] -= 4; + dsp_reg[30] = dsp_pc - 2; // -2 because we've executed the instruction already + //CC only! #ifdef DSP_DEBUG_CC regs1[31] -= 4; #endif //!!!!!!!! - DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP); +// DSPWriteLong(dsp_reg[31], dsp_pc - 2, DSP); + DSPWriteLong(dsp_reg[31], dsp_reg[30], DSP); //CC only! #ifdef DSP_DEBUG_CC SET32(ram1, regs1[31] - 0xF1B000, dsp_pc - 2); @@ -1271,7 +1249,9 @@ ctrl1[8] = ctrl2[8] = dsp_control; if (state) { dsp_control |= mask; // Set the latch bit - DSPHandleIRQs(); +#warning !!! No checking done to see if we're using pipelined DSP or not !!! +// DSPHandleIRQs(); + DSPHandleIRQsNP(); //CC only! #ifdef DSP_DEBUG_CC ctrl1[8] = ctrl2[8] = dsp_control; @@ -1358,10 +1338,10 @@ void DSPDumpRegisters(void) for(int j=0; j<8; j++) { WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n", - (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0], - (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1], - (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2], - (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]); + (j << 2) + 0, dsp_reg_bank_0[(j << 2) + 0], + (j << 2) + 1, dsp_reg_bank_0[(j << 2) + 1], + (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2], + (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]); } WriteLog("Registers bank 1\n"); @@ -1369,10 +1349,10 @@ void DSPDumpRegisters(void) for(int j=0; j<8; j++) { WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n", - (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0], - (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1], - (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2], - (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]); + (j << 2) + 0, dsp_reg_bank_1[(j << 2) + 0], + (j << 2) + 1, dsp_reg_bank_1[(j << 2) + 1], + (j << 2) + 2, dsp_reg_bank_1[(j << 2) + 2], + (j << 2) + 3, dsp_reg_bank_1[(j << 2) + 3]); } } @@ -1432,15 +1412,6 @@ void DSPDone(void) if (dsp_opcode_use[i]) WriteLog("\t%s %i\n", dsp_opcode_str[i], dsp_opcode_use[i]); }//*/ - -// memory_free(dsp_ram_8); -// memory_free(dsp_reg_bank_0); -// memory_free(dsp_reg_bank_1); -// if (dsp_branch_condition_table) -// free(dsp_branch_condition_table); - -// if (mirror_table) -// free(mirror_table); } @@ -1652,9 +1623,6 @@ for(int k=0; k<2; k++) //static uint32 pcQueue[32], ptrPCQ = 0; void DSPExec(int32 cycles) { -/*HACKS!!! -> if (cycles != 1 && jaguar_mainRom_crc32 == 0xba74c3ed) - dsp_check_if_i2s_interrupt_needed();*/ - #ifdef DSP_SINGLE_STEPPING if (dsp_control & 0x18) { @@ -1687,7 +1655,7 @@ if (dsp_pc == 0xF1B092) if (IMASKCleared) // If IMASK was cleared, { #ifdef DSP_DEBUG_IRQ - WriteLog("DSP: Finished interrupt.\n"); + WriteLog("DSP: Finished interrupt. PC=$%06X\n", dsp_pc); #endif DSPHandleIRQsNP(); // See if any other interrupts are pending! IMASKCleared = false; @@ -2572,6 +2540,7 @@ static void dsp_opcode_shlq(void) if (doDSPDis) WriteLog("%06X: SHLQ #%u, R%02u [NCZ:%u%u%u, R%02u=%08X] -> ", dsp_pc-2, 32 - IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z, IMM_2, RN); #endif + // NB: This instruction is the *only* one that does (32 - immediate data). int32 r1 = 32 - IMM_1; uint32 res = RN << r1; SET_ZN(res); dsp_flag_c = (RN >> 31) & 1; @@ -2761,6 +2730,12 @@ void dsp_opcode_sat16s(void) SET_ZN(res); } +void dsp_opcode_illegal(void) +{ + // Don't know what it does, but it does *something*... + WriteLog("%06X: illegal %u, %u [NCZ:%u%u%u]\n", dsp_pc-2, IMM_1, IMM_2, dsp_flag_n, dsp_flag_c, dsp_flag_z); +} + // // New pipelined DSP core // diff --git a/src/dsp.h b/src/dsp.h index 67e5299..935c6e6 100644 --- a/src/dsp.h +++ b/src/dsp.h @@ -35,6 +35,7 @@ void DSPExecComp(int32 cycles); // Exported vars extern bool doDSPDis; +extern uint32 dsp_reg_bank_0[], dsp_reg_bank_1[]; // DSP interrupt numbers (in $F1A100, bits 4-8 & 16) diff --git a/src/file.cpp b/src/file.cpp index dff0c55..ac81a06 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -223,6 +223,11 @@ WriteLog("FILE: Cartridge run address is reported as $%X...\n", jaguarRunAddress memcpy(jagMemSpace + loadAddress, buffer + 0x2E, jaguarROMSize - 0x2E); delete[] buffer; jaguarRunAddress = runAddress; + +// Hmm. Is this kludge necessary? +SET32(jaguarMainRAM, 0x10, 0x00001000); // Set Exception #4 (Illegal Instruction) +SET16(jaguarMainRAM, 0x1000, 0x60FE); // Here: bra Here + return true; // } // else // Special WTFOMGBBQ type here... diff --git a/src/gpu.cpp b/src/gpu.cpp index 09a664d..e5855fe 100644 --- a/src/gpu.cpp +++ b/src/gpu.cpp @@ -323,8 +323,8 @@ static uint32 gpu_div_control; // a bit before writing a result. I.e., if the result of an operation leaves a zero in // the carry flag, you don't have to zero gpu_flag_c before you can write that zero! static uint8 gpu_flag_z, gpu_flag_n, gpu_flag_c; -static uint32 gpu_reg_bank_0[32]; -static uint32 gpu_reg_bank_1[32]; +uint32 gpu_reg_bank_0[32]; +uint32 gpu_reg_bank_1[32]; static uint32 * gpu_reg; static uint32 * gpu_alternate_reg; diff --git a/src/gpu.h b/src/gpu.h index 97ba4b3..9d3260f 100644 --- a/src/gpu.h +++ b/src/gpu.h @@ -35,4 +35,8 @@ uint32 GPUReadPC(void); enum { GPUIRQ_CPU = 0, GPUIRQ_DSP, GPUIRQ_TIMER, GPUIRQ_OBJECT, GPUIRQ_BLITTER }; +// Exported vars + +extern uint32 gpu_reg_bank_0[], gpu_reg_bank_1[]; + #endif // __GPU_H__ diff --git a/src/gui/debug/cpubrowser.cpp b/src/gui/debug/cpubrowser.cpp index 9951c64..62d6d0a 100644 --- a/src/gui/debug/cpubrowser.cpp +++ b/src/gui/debug/cpubrowser.cpp @@ -46,7 +46,7 @@ CPUBrowserWindow::CPUBrowserWindow(QWidget * parent/*= 0*/): QWidget(parent, Qt: void CPUBrowserWindow::RefreshContents(void) { - char string[1024], buf[64]; + char string[2048]; QString s; // 68K @@ -87,10 +87,86 @@ void CPUBrowserWindow::RefreshContents(void) sprintf(string, "GPU PC: %06X  FLAGS: %08X

", GPUReadLong(0xF02010), GPUReadLong(0xF02000)); s += QString(string); + sprintf(string, "Bank 0:
" + "R00: %08X  R01: %08X  R02: %08X  R03: %08X
" + "R04: %08X  R05: %08X  R06: %08X  R07: %08X
" + "R08: %08X  R09: %08X  R10: %08X  R11: %08X
" + "R12: %08X  R13: %08X  R14: %08X  R15: %08X
" + "R16: %08X  R17: %08X  R18: %08X  R19: %08X
" + "R20: %08X  R21: %08X  R22: %08X  R23: %08X
" + "R24: %08X  R25: %08X  R26: %08X  R27: %08X
" + "R28: %08X  R29: %08X  R30: %08X  R31: %08X

", + gpu_reg_bank_0[0], gpu_reg_bank_0[1], gpu_reg_bank_0[2], gpu_reg_bank_0[3], + gpu_reg_bank_0[4], gpu_reg_bank_0[5], gpu_reg_bank_0[6], gpu_reg_bank_0[7], + gpu_reg_bank_0[8], gpu_reg_bank_0[9], gpu_reg_bank_0[10], gpu_reg_bank_0[11], + gpu_reg_bank_0[12], gpu_reg_bank_0[13], gpu_reg_bank_0[14], gpu_reg_bank_0[15], + gpu_reg_bank_0[16], gpu_reg_bank_0[17], gpu_reg_bank_0[18], gpu_reg_bank_0[19], + gpu_reg_bank_0[20], gpu_reg_bank_0[21], gpu_reg_bank_0[22], gpu_reg_bank_0[23], + gpu_reg_bank_0[24], gpu_reg_bank_0[25], gpu_reg_bank_0[26], gpu_reg_bank_0[27], + gpu_reg_bank_0[28], gpu_reg_bank_0[29], gpu_reg_bank_0[30], gpu_reg_bank_0[31]); + s += QString(string); + + sprintf(string, "Bank 1:
" + "R00: %08X  R01: %08X  R02: %08X  R03: %08X
" + "R04: %08X  R05: %08X  R06: %08X  R07: %08X
" + "R08: %08X  R09: %08X  R10: %08X  R11: %08X
" + "R12: %08X  R13: %08X  R14: %08X  R15: %08X
" + "R16: %08X  R17: %08X  R18: %08X  R19: %08X
" + "R20: %08X  R21: %08X  R22: %08X  R23: %08X
" + "R24: %08X  R25: %08X  R26: %08X  R27: %08X
" + "R28: %08X  R29: %08X  R30: %08X  R31: %08X

", + gpu_reg_bank_1[0], gpu_reg_bank_1[1], gpu_reg_bank_1[2], gpu_reg_bank_1[3], + gpu_reg_bank_1[4], gpu_reg_bank_1[5], gpu_reg_bank_1[6], gpu_reg_bank_1[7], + gpu_reg_bank_1[8], gpu_reg_bank_1[9], gpu_reg_bank_1[10], gpu_reg_bank_1[11], + gpu_reg_bank_1[12], gpu_reg_bank_1[13], gpu_reg_bank_1[14], gpu_reg_bank_1[15], + gpu_reg_bank_1[16], gpu_reg_bank_1[17], gpu_reg_bank_1[18], gpu_reg_bank_1[19], + gpu_reg_bank_1[20], gpu_reg_bank_1[21], gpu_reg_bank_1[22], gpu_reg_bank_1[23], + gpu_reg_bank_1[24], gpu_reg_bank_1[25], gpu_reg_bank_1[26], gpu_reg_bank_1[27], + gpu_reg_bank_1[28], gpu_reg_bank_1[29], gpu_reg_bank_1[30], gpu_reg_bank_1[31]); + s += QString(string); + // DSP sprintf(string, "DSP PC: %06X  FLAGS: %08X

", DSPReadLong(0xF1A110), DSPReadLong(0xF1A100)); s += QString(string); + sprintf(string, "Bank 0:
" + "R00: %08X  R01: %08X  R02: %08X  R03: %08X
" + "R04: %08X  R05: %08X  R06: %08X  R07: %08X
" + "R08: %08X  R09: %08X  R10: %08X  R11: %08X
" + "R12: %08X  R13: %08X  R14: %08X  R15: %08X
" + "R16: %08X  R17: %08X  R18: %08X  R19: %08X
" + "R20: %08X  R21: %08X  R22: %08X  R23: %08X
" + "R24: %08X  R25: %08X  R26: %08X  R27: %08X
" + "R28: %08X  R29: %08X  R30: %08X  R31: %08X

", + dsp_reg_bank_0[0], dsp_reg_bank_0[1], dsp_reg_bank_0[2], dsp_reg_bank_0[3], + dsp_reg_bank_0[4], dsp_reg_bank_0[5], dsp_reg_bank_0[6], dsp_reg_bank_0[7], + dsp_reg_bank_0[8], dsp_reg_bank_0[9], dsp_reg_bank_0[10], dsp_reg_bank_0[11], + dsp_reg_bank_0[12], dsp_reg_bank_0[13], dsp_reg_bank_0[14], dsp_reg_bank_0[15], + dsp_reg_bank_0[16], dsp_reg_bank_0[17], dsp_reg_bank_0[18], dsp_reg_bank_0[19], + dsp_reg_bank_0[20], dsp_reg_bank_0[21], dsp_reg_bank_0[22], dsp_reg_bank_0[23], + dsp_reg_bank_0[24], dsp_reg_bank_0[25], dsp_reg_bank_0[26], dsp_reg_bank_0[27], + dsp_reg_bank_0[28], dsp_reg_bank_0[29], dsp_reg_bank_0[30], dsp_reg_bank_0[31]); + s += QString(string); + + sprintf(string, "Bank 1:
" + "R00: %08X  R01: %08X  R02: %08X  R03: %08X
" + "R04: %08X  R05: %08X  R06: %08X  R07: %08X
" + "R08: %08X  R09: %08X  R10: %08X  R11: %08X
" + "R12: %08X  R13: %08X  R14: %08X  R15: %08X
" + "R16: %08X  R17: %08X  R18: %08X  R19: %08X
" + "R20: %08X  R21: %08X  R22: %08X  R23: %08X
" + "R24: %08X  R25: %08X  R26: %08X  R27: %08X
" + "R28: %08X  R29: %08X  R30: %08X  R31: %08X
", + dsp_reg_bank_1[0], dsp_reg_bank_1[1], dsp_reg_bank_1[2], dsp_reg_bank_1[3], + dsp_reg_bank_1[4], dsp_reg_bank_1[5], dsp_reg_bank_1[6], dsp_reg_bank_1[7], + dsp_reg_bank_1[8], dsp_reg_bank_1[9], dsp_reg_bank_1[10], dsp_reg_bank_1[11], + dsp_reg_bank_1[12], dsp_reg_bank_1[13], dsp_reg_bank_1[14], dsp_reg_bank_1[15], + dsp_reg_bank_1[16], dsp_reg_bank_1[17], dsp_reg_bank_1[18], dsp_reg_bank_1[19], + dsp_reg_bank_1[20], dsp_reg_bank_1[21], dsp_reg_bank_1[22], dsp_reg_bank_1[23], + dsp_reg_bank_1[24], dsp_reg_bank_1[25], dsp_reg_bank_1[26], dsp_reg_bank_1[27], + dsp_reg_bank_1[28], dsp_reg_bank_1[29], dsp_reg_bank_1[30], dsp_reg_bank_1[31]); + s += QString(string); + text->clear(); text->setText(s); } diff --git a/src/gui/mainwin.cpp b/src/gui/mainwin.cpp index 1c990fa..1dbafa0 100644 --- a/src/gui/mainwin.cpp +++ b/src/gui/mainwin.cpp @@ -403,12 +403,22 @@ void MainWin::closeEvent(QCloseEvent * event) void MainWin::keyPressEvent(QKeyEvent * e) { + // From jaguar.cpp + extern bool startM68KTracing; + // We ignore the Alt key for now, since it causes problems with the GUI if (e->key() == Qt::Key_Alt) { e->accept(); return; } + else if (e->key() == Qt::Key_F11) + { + startM68KTracing = true; + e->accept(); + return; + } + /* if (e->key() == Qt::Key_F9) { diff --git a/src/jagdasm.cpp b/src/jagdasm.cpp index e273049..71c531a 100644 --- a/src/jagdasm.cpp +++ b/src/jagdasm.cpp @@ -114,7 +114,7 @@ unsigned dasmjag(int dsp_type, char * bufferOut, unsigned pc) case 21: sprintf(buffer, "DIV R%02d,R%02d", reg1, reg2); break; case 22: sprintf(buffer, "ABS R%02d", reg2); break; case 23: sprintf(buffer, "SH R%02d,R%02d", reg1, reg2); break; - case 24: sprintf(buffer, "SHLQ $%X,R%02d", 32 - convert_zero[reg1], reg2); break; + case 24: sprintf(buffer, "SHLQ $%X,R%02d", 32 - reg1, reg2); break; case 25: sprintf(buffer, "SHRQ $%X,R%02d", convert_zero[reg1], reg2); break; case 26: sprintf(buffer, "SHA R%02d,R%02d", reg1, reg2); break; case 27: sprintf(buffer, "SHARQ $%X,R%02d", convert_zero[reg1], reg2); break; @@ -171,7 +171,7 @@ unsigned dasmjag(int dsp_type, char * bufferOut, unsigned pc) case 62: if (dsp_type == JAGUAR_GPU) sprintf(buffer, "SAT24 R%02d", reg2); else - sprintf(buffer, "illegal"); + sprintf(buffer, "illegal [%d,%d]", reg1, reg2); break; case 63: if (dsp_type == JAGUAR_GPU) sprintf(buffer, (reg1 ? "UNPACK R%02d" : "PACK R%02d"), reg2); diff --git a/src/jaguar.cpp b/src/jaguar.cpp index f930c9a..5f23f1b 100644 --- a/src/jaguar.cpp +++ b/src/jaguar.cpp @@ -38,10 +38,11 @@ //Do this in makefile??? Yes! Could, but it's easier to define here... //#define LOG_UNMAPPED_MEMORY_ACCESSES //#define ABORT_ON_UNMAPPED_MEMORY_ACCESS -#define ABORT_ON_ILLEGAL_INSTRUCTIONS +//#define ABORT_ON_ILLEGAL_INSTRUCTIONS //#define ABORT_ON_OFFICIAL_ILLEGAL_INSTRUCTION #define CPU_DEBUG_MEMORY //#define LOG_CD_BIOS_CALLS +#define CPU_DEBUG_TRACING // Private function prototypes @@ -78,6 +79,7 @@ uint32 returnAddr[4000], raPtr = 0xFFFFFFFF; uint32 pcQueue[0x400]; uint32 pcQPtr = 0; +bool startM68KTracing = false; // // Callback function to detect illegal instructions @@ -121,6 +123,17 @@ if (inRoutine) instSeen++; #endif +// For code tracing... +#ifdef CPU_DEBUG_TRACING + if (startM68KTracing) + { + static char buffer[2048]; + + m68k_disassemble(buffer, m68kPC, 0); + WriteLog("%06X: %s\n", m68kPC, buffer); + } +#endif + // For tracebacks... // Ideally, we'd save all the registers as well... pcQueue[pcQPtr++] = m68kPC; @@ -270,7 +283,7 @@ if (m68kPC == 0x802058) start = true; m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2)); }//*/ - if (m68kPC == 0x82E1A) +/* if (m68kPC == 0x82E1A) { static char buffer[2048]; m68k_disassemble(buffer, m68kPC, 0);//M68K_CPU_TYPE_68000); @@ -279,7 +292,7 @@ if (m68kPC == 0x802058) start = true; m68k_get_reg(NULL, M68K_REG_A0), m68k_get_reg(NULL, M68K_REG_A1), m68k_get_reg(NULL, M68K_REG_D0), m68k_get_reg(NULL, M68K_REG_D1), m68k_get_reg(NULL, M68K_REG_D2)); }//*/ - if (m68kPC == 0x82E58) +/* if (m68kPC == 0x82E58) WriteLog("--> [Routine end]\n"); if (m68kPC == 0x80004) { @@ -929,6 +942,13 @@ handler: #endif int irq_ack_handler(int level) { +#ifdef CPU_DEBUG_TRACING + if (startM68KTracing) + { + WriteLog("irq_ack_handler: M68K PC=%06X\n", m68k_get_reg(NULL, M68K_REG_PC)); + } +#endif + // Tracing the IPL lines on the Jaguar schematic yields the following: // IPL1 is connected to INTL on TOM (OUT to 68K) // IPL0-2 are also tied to Vcc via 4.7K resistors! diff --git a/src/joystick.cpp b/src/joystick.cpp index 14b5ff7..208b58b 100644 --- a/src/joystick.cpp +++ b/src/joystick.cpp @@ -283,6 +283,8 @@ void JoystickExec(void) joypad_0_buttons[BUTTON_D] = 0; #endif +// This is handled by the GUI layer, as it should +#if 0 // Joystick support [nwagenaar] if (vjs.useJoystick) @@ -310,6 +312,7 @@ void JoystickExec(void) // Needed to ensure that the events queue is empty [nwagenaar] SDL_PumpEvents(); +#endif } void JoystickReset(void) diff --git a/src/log.cpp b/src/log.cpp index 2782c93..4f6619d 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -22,7 +22,8 @@ #include #include "types.h" -#define MAX_LOG_SIZE 10000000 // Maximum size of log file (10 MB) +//#define MAX_LOG_SIZE 10000000 // Maximum size of log file (10 MB) +#define MAX_LOG_SIZE 100000000 // Maximum size of log file (100 MB) static FILE * log_stream = NULL; static uint32 logSize = 0; diff --git a/src/m68000/m68kinterface.c b/src/m68000/m68kinterface.c index bdaa0c4..528d7e7 100644 --- a/src/m68000/m68kinterface.c +++ b/src/m68000/m68kinterface.c @@ -12,12 +12,12 @@ // #include "m68kinterface.h" +//#include #include "cpudefs.h" #include "inlines.h" #include "cpuextra.h" #include "readcpu.h" - // Exception Vectors handled by emulation #define EXCEPTION_BUS_ERROR 2 /* This one is not emulated! */ #define EXCEPTION_ADDRESS_ERROR 3 /* This one is partially emulated (doesn't stack a proper frame yet) */ @@ -54,11 +54,17 @@ STATIC_INLINE uint32_t m68ki_init_exception(void); STATIC_INLINE void m68ki_stack_frame_3word(uint32_t pc, uint32_t sr); unsigned long IllegalOpcode(uint32_t opcode); void BuildCPUFunctionTable(void); +void m68k_set_irq2(unsigned int intLevel); // Local "Global" vars static int32_t initialCycles; cpuop_func * cpuFunctionTable[65536]; +// By virtue of the fact that m68k_set_irq() can be called asychronously by +// another thread, we need something along the lines of this: +static int checkForIRQToHandle = 0; +//static pthread_mutex_t executionLock = PTHREAD_MUTEX_INITIALIZER; +static int IRQLevelToHandle = 0; #if 0 #define ADD_CYCLES(A) m68ki_remaining_cycles += (A) @@ -311,6 +317,16 @@ if (inRoutine) //94C0: 6A02 BPL.B $94C4 //94C2: 2452 MOVEA.L (A2), A2 ; <--- HERE //94C4: 4283 CLR.L D3 +#endif +// pthread_mutex_lock(&executionLock); + if (checkForIRQToHandle) + { + checkForIRQToHandle = 0; + m68k_set_irq2(IRQLevelToHandle); + } + +#ifdef M68K_HOOK_FUNCTION + M68KInstructionHook(); #endif uint32_t opcode = get_iword(0); //if ((opcode & 0xFFF8) == 0x31C0) @@ -319,14 +335,12 @@ if (inRoutine) //} int32_t cycles = (int32_t)(*cpuFunctionTable[opcode])(opcode); regs.remainingCycles -= cycles; +// pthread_mutex_unlock(&executionLock); + //printf("Executed opcode $%04X (%i cycles)...\n", opcode, cycles); #endif } -#if 0 - while (GET_CYCLES() > 0); -#else while (regs.remainingCycles > 0); -#endif #if 0 /* set previous PC to current PC for the next entry into the loop */ @@ -348,20 +362,21 @@ if (inRoutine) } -/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */ void m68k_set_irq(unsigned int intLevel) { -#if 0 - uint old_level = CPU_INT_LEVEL; - CPU_INT_LEVEL = int_level << 8; + // Since this can be called asynchronously, we need to fix it so that it + // doesn't fuck up the main execution loop. + IRQLevelToHandle = intLevel; + checkForIRQToHandle = 1; +} + + +/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */ +void m68k_set_irq2(unsigned int intLevel) +{ +// pthread_mutex_lock(&executionLock); +// printf("m68k_set_irq: Could not get the lock!!!\n"); - /* A transition from < 7 to 7 always interrupts (NMI) */ - /* Note: Level 7 can also level trigger like a normal IRQ */ - if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700) - m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */ - else - m68ki_check_interrupts(); /* Level triggered (IRQ) */ -#else int oldLevel = regs.intLevel; regs.intLevel = intLevel; @@ -371,7 +386,8 @@ void m68k_set_irq(unsigned int intLevel) m68ki_exception_interrupt(7); // Edge triggered level 7 (NMI) else m68ki_check_interrupts(); // Level triggered (IRQ) -#endif + +// pthread_mutex_unlock(&executionLock); } @@ -485,9 +501,24 @@ void m68ki_exception_interrupt(uint32_t intLevel) // Set the interrupt mask to the level of the one being serviced regs.intmask = intLevel; +#if 0 +extern int startM68KTracing; +if (startM68KTracing) +{ + printf("IRQ: old PC=%06X, ", regs.pc); +} +#endif + // Get the new PC uint32_t newPC = m68k_read_memory_32(vector << 2); +#if 0 +if (startM68KTracing) +{ + printf("new PC=%06X, vector=%u, ", newPC, vector); +} +#endif + // If vector is uninitialized, call the uninitialized interrupt vector if (newPC == 0) newPC = m68k_read_memory_32(EXCEPTION_UNINITIALIZED_INTERRUPT << 2); @@ -496,6 +527,12 @@ void m68ki_exception_interrupt(uint32_t intLevel) m68ki_stack_frame_3word(regs.pc, sr); m68k_setpc(newPC); +#if 0 +if (startM68KTracing) +{ + printf("(PC=%06X)\n", regs.pc); +} +#endif // Defer cycle counting until later regs.interruptCycles += 56; // NOT ACCURATE-- !!! FIX !!! @@ -605,10 +642,16 @@ unsigned int m68k_disassemble(char * str_buff, unsigned int pc, unsigned int cpu int m68k_cycles_run(void) {} /* Number of cycles run so far */ int m68k_cycles_remaining(void) {} /* Number of cycles left */ -void m68k_modify_timeslice(int cycles) {} /* Modify cycles left */ +//void m68k_modify_timeslice(int cycles) {} /* Modify cycles left */ //void m68k_end_timeslice(void) {} /* End timeslice now */ +void m68k_modify_timeslice(int cycles) +{ + regs.remainingCycles = cycles; +} + + void m68k_end_timeslice(void) { #if 0 diff --git a/src/m68000/m68kinterface.h b/src/m68000/m68kinterface.h index f96bf68..613bb11 100644 --- a/src/m68000/m68kinterface.h +++ b/src/m68000/m68kinterface.h @@ -90,6 +90,13 @@ int irq_ack_handler(int); // Convenience functions +// Uncomment this to have the emulated CPU call a hook function after every instruction +// NB: This must be implemented by the user! +#define M68K_HOOK_FUNCTION +#ifdef M68K_HOOK_FUNCTION +void M68KInstructionHook(void); +#endif + /* Peek at the internals of a CPU context. This can either be a context * retrieved using m68k_get_context() or the currently running context. * If context is NULL, the currently running CPU context will be used. -- 2.37.2