From: Shamus Hammons Date: Mon, 13 Feb 2012 00:31:18 +0000 (+0000) Subject: Preliminary fixes for memory accesses between $200000 and $7FFFFF, proper X-Git-Tag: 2.1.0~38 X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4906545f5d77d6d7a006fa0d765dc0ae522e477f;p=virtualjaguar Preliminary fixes for memory accesses between $200000 and $7FFFFF, proper handling of objects with IWIDTH of zero. --- diff --git a/docs/TODO b/docs/TODO index f8276af..75a73d7 100644 --- a/docs/TODO +++ b/docs/TODO @@ -19,6 +19,8 @@ Stuff to add/fix for the next release of Virtual Jaguar - Command line switches for frontends. [Shamus] - In emulator screenshots. [Shamus] - Audio/video dumping. [Shamus] +- Full screen option. [Shamus] +- Controller handling. [Shamus] Stuff that was added/fixed diff --git a/docs/WHATSNEW b/docs/WHATSNEW index 3cfcd9a..deaeca6 100644 --- a/docs/WHATSNEW +++ b/docs/WHATSNEW @@ -5,6 +5,9 @@ Virtual Jaguar v2.0.3 GCC/Qt playback. Note that there could still be problems with this approach, as it can be easily fooled. Thanks to Dr. Typo for the initial analysis and insight into this bug. :-) [Shamus] +* Preliminary fixes for proper emulation of memory reads between $200000 and + $800000. [Shamus] +* Proper handling in the OP of objects with 0 IWIDTH. [Shamus] Virtual Jaguar v2.0.2 GCC/Qt diff --git a/src/blitter.cpp b/src/blitter.cpp index 4e8ea74..1396099 100644 --- a/src/blitter.cpp +++ b/src/blitter.cpp @@ -1559,10 +1559,17 @@ uint8 BlitterReadByte(uint32 offset, uint32 who/*=UNKNOWN*/) // status register //This isn't cycle accurate--how to fix? !!! FIX !!! //Probably have to do some multi-threaded implementation or at least a reentrant safe implementation... +//Real hardware returns $00000805, just like the JTRM says. + if (offset == (0x38 + 0)) + return 0x00; + if (offset == (0x38 + 1)) + return 0x00; + if (offset == (0x38 + 2)) + return 0x08; if (offset == (0x38 + 3)) - return 0x01; // always idle + return 0x05; // always idle/never stopped (collision detection ignored!) -// CHECK HERE ONCE THIS FIX HAS BEEN TESTED: [ ] +// CHECK HERE ONCE THIS FIX HAS BEEN TESTED: [X] //Fix for AvP: if (offset >= 0x04 && offset <= 0x07) //This is it. I wonder if it just ignores the lower three bits? diff --git a/src/cdrom.cpp b/src/cdrom.cpp index 3f41981..93087ac 100644 --- a/src/cdrom.cpp +++ b/src/cdrom.cpp @@ -841,8 +841,9 @@ if (cdBufPtr % 32 == 30) bool ButchIsReadyToSend(void) { +#ifdef LOG_CDROM_VERBOSE WriteLog("Butch is%s ready to send...\n", cdRam[I2CNTRL + 3] & 0x02 ? "" : " not"); - +#endif return (cdRam[I2CNTRL + 3] & 0x02 ? true : false); } diff --git a/src/dsp.cpp b/src/dsp.cpp index 74839cc..aa12cf5 100644 --- a/src/dsp.cpp +++ b/src/dsp.cpp @@ -413,9 +413,12 @@ static uint32 dsp_opcode_second_parameter; #define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b) #define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b) -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 = NULL; -static uint16 * mirror_table = NULL; +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]; #define BRANCH_CONDITION(x) dsp_branch_condition_table[(x) + ((jaguar_flags & 7) << 5)] @@ -454,49 +457,39 @@ void DSPReleaseTimeslice(void) void dsp_build_branch_condition_table(void) { - // Allocate the mirror table - if (!mirror_table) - mirror_table = (uint16 *)malloc(65536 * sizeof(uint16)); - // Fill in the mirror table - if (mirror_table) - for(int i=0; i<65536; i++) - mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) | - ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) | - ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) | - ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) | - ((i << 1) & 0x0100) | ((i << 3) & 0x0200) | - ((i << 5) & 0x0400) | ((i << 7) & 0x0800) | - ((i << 9) & 0x1000) | ((i << 11) & 0x2000) | - ((i << 13) & 0x4000) | ((i << 15) & 0x8000); - - if (!dsp_branch_condition_table) + for(int i=0; i<65536; i++) { - dsp_branch_condition_table = (uint8 *)malloc(32 * 8 * sizeof(uint8)); + mirror_table[i] = ((i >> 15) & 0x0001) | ((i >> 13) & 0x0002) + | ((i >> 11) & 0x0004) | ((i >> 9) & 0x0008) + | ((i >> 7) & 0x0010) | ((i >> 5) & 0x0020) + | ((i >> 3) & 0x0040) | ((i >> 1) & 0x0080) + | ((i << 1) & 0x0100) | ((i << 3) & 0x0200) + | ((i << 5) & 0x0400) | ((i << 7) & 0x0800) + | ((i << 9) & 0x1000) | ((i << 11) & 0x2000) + | ((i << 13) & 0x4000) | ((i << 15) & 0x8000); + } - // Fill in the condition table - if (dsp_branch_condition_table) + // Fill in the condition table + for(int i=0; i<8; i++) + { + for(int j=0; j<32; j++) { - for(int i=0; i<8; i++) - { - for(int j=0; j<32; j++) - { - int result = 1; - if (j & 1) - if (i & ZERO_FLAG) - result = 0; - if (j & 2) - if (!(i & ZERO_FLAG)) - result = 0; - if (j & 4) - if (i & (CARRY_FLAG << (j >> 4))) - result = 0; - if (j & 8) - if (!(i & (CARRY_FLAG << (j >> 4)))) - result = 0; - dsp_branch_condition_table[i * 32 + j] = result; - } - } + int result = 1; + + if ((j & 1) && (i & ZERO_FLAG)) + result = 0; + + if ((j & 2) && (!(i & ZERO_FLAG))) + result = 0; + + if ((j & 4) && (i & (CARRY_FLAG << (j >> 4)))) + result = 0; + + if ((j & 8) && (!(i & (CARRY_FLAG << (j >> 4))))) + result = 0; + + dsp_branch_condition_table[i * 32 + j] = result; } } } @@ -1313,6 +1306,7 @@ void DSPDumpDisassembly(void) WriteLog("\n---[DSP code at 00F1B000]---------------------------\n"); uint32 j = 0xF1B000; + while (j <= 0xF1CFFF) { uint32 oldj = j; @@ -1326,6 +1320,7 @@ void DSPDumpRegisters(void) //Shoud add modulus, etc to dump here... WriteLog("\n---[DSP flags: NCZ %d%d%d, DSP PC: %08X]------------\n", dsp_flag_n, dsp_flag_c, dsp_flag_z, dsp_pc); WriteLog("\nRegisters bank 0\n"); + for(int j=0; j<8; j++) { WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n", @@ -1334,7 +1329,9 @@ void DSPDumpRegisters(void) (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"); + for(int j=0; j<8; j++) { WriteLog("\tR%02i = %08X R%02i = %08X R%02i = %08X R%02i = %08X\n", @@ -1348,7 +1345,7 @@ void DSPDumpRegisters(void) void DSPDone(void) { int i, j; - WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp %s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "was" : "wasn't")); + WriteLog("DSP: Stopped at PC=%08X dsp_modulo=%08X (dsp was%s running)\n", dsp_pc, dsp_modulo, (DSP_RUNNING ? "" : "n't")); WriteLog("DSP: %sin interrupt handler\n", (dsp_flags & IMASK ? "" : "not ")); // get the active interrupt bits @@ -1361,6 +1358,7 @@ void DSPDone(void) (mask & 0x04 ? "Timer0 " : ""), (mask & 0x08 ? "Timer1 " : ""), (mask & 0x10 ? "Ext0 " : ""), (mask & 0x20 ? "Ext1" : "")); WriteLog("\nRegisters bank 0\n"); + for(int j=0; j<8; j++) { WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n", @@ -1369,7 +1367,9 @@ void DSPDone(void) (j << 2) + 2, dsp_reg_bank_0[(j << 2) + 2], (j << 2) + 3, dsp_reg_bank_0[(j << 2) + 3]); } + WriteLog("\nRegisters bank 1\n"); + for (j=0; j<8; j++) { WriteLog("\tR%02i=%08X R%02i=%08X R%02i=%08X R%02i=%08X\n", @@ -1382,6 +1382,7 @@ void DSPDone(void) static char buffer[512]; j = DSP_WORK_RAM_BASE; + while (j <= 0xF1BFFF) { uint32 oldj = j; @@ -1390,6 +1391,7 @@ void DSPDone(void) }//*/ WriteLog("DSP opcodes use:\n"); + for (i=0;i<64;i++) { if (dsp_opcode_use[i]) @@ -1399,11 +1401,11 @@ void DSPDone(void) // 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 (dsp_branch_condition_table) +// free(dsp_branch_condition_table); - if (mirror_table) - free(mirror_table); +// if (mirror_table) +// free(mirror_table); } diff --git a/src/gpu.cpp b/src/gpu.cpp index 2ea973d..1d7afa7 100644 --- a/src/gpu.cpp +++ b/src/gpu.cpp @@ -1981,6 +1981,17 @@ static void gpu_opcode_loadw(void) // Also, Power Drive Rally seems to contradict the idea that only LOADs in // the $F03000-$F03FFF range are aligned... #warning "!!! Alignment issues, need to find definitive final word on this !!!" +/* +Preliminary testing on real hardware seems to confirm that something strange goes on +with unaligned reads in main memory. When the address is off by 1, the result is the +same as the long address with the top byte replaced by something. So if the read is +from $401, and $400 has 12 34 56 78, the value read will be $nn345678, where nn is a currently unknown vlaue. +When the address is off by 2, the result would be $nnnn5678, where nnnn is unknown. +When the address is off by 3, the result would be $nnnnnn78, where nnnnnn is unknown. +It may be that the "unknown" values come from the prefetch queue, but not sure how +to test that. They seem to be stable, though, which would indicate such a mechanism. +Sometimes, however, the off by 2 case returns $12345678! +*/ static void gpu_opcode_load(void) { #ifdef GPU_DIS_LOAD @@ -1988,10 +1999,16 @@ static void gpu_opcode_load(void) WriteLog("%06X: LOAD (R%02u), R%02u [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN); #endif #ifdef GPU_CORRECT_ALIGNMENT + uint32 mask[4] = { 0x00000000, 0xFF000000, 0xFFFF0000, 0xFFFFFF00 }; // if ((RM >= 0xF03000) && (RM <= 0xF03FFF)) RN = GPUReadLong(RM & 0xFFFFFFFC, GPU); +// RN = GPUReadLong(RM & 0x00FFFFFC, GPU); // else // RN = GPUReadLong(RM, GPU); + // Simulate garbage in unaligned reads... +//seems that this behavior is different in GPU mem vs. main mem... +// if ((RM < 0xF03000) || (RM > 0xF0BFFF)) +// RN |= mask[RM & 0x03]; #else RN = GPUReadLong(RM, GPU); #endif diff --git a/src/jaguar.cpp b/src/jaguar.cpp index b6c9f19..bb94071 100644 --- a/src/jaguar.cpp +++ b/src/jaguar.cpp @@ -942,7 +942,8 @@ unsigned int m68k_read_memory_8(unsigned int address) // Musashi does this automagically for you, UAE core does not :-P address &= 0x00FFFFFF; #ifdef CPU_DEBUG_MEMORY - if ((address >= 0x000000) && (address <= 0x3FFFFF)) + // Note that the Jaguar only has 2M of RAM, not 4! + if ((address >= 0x000000) && (address <= 0x1FFFFF)) { if (startMemLog) readMem[address] = 1; @@ -956,7 +957,8 @@ unsigned int m68k_read_memory_8(unsigned int address) #ifndef USE_NEW_MMU unsigned int retVal = 0; - if ((address >= 0x000000) && (address <= 0x3FFFFF)) + // Note that the Jaguar only has 2M of RAM, not 4! + if ((address >= 0x000000) && (address <= 0x1FFFFF)) retVal = jaguarMainRAM[address]; // else if ((address >= 0x800000) && (address <= 0xDFFFFF)) else if ((address >= 0x800000) && (address <= 0xDFFEFF)) @@ -1054,7 +1056,8 @@ unsigned int m68k_read_memory_16(unsigned int address) #ifndef USE_NEW_MMU unsigned int retVal = 0; - if ((address >= 0x000000) && (address <= 0x3FFFFE)) + // Note that the Jaguar only has 2M of RAM, not 4! + if ((address >= 0x000000) && (address <= 0x1FFFFE)) // retVal = (jaguar_mainRam[address] << 8) | jaguar_mainRam[address+1]; retVal = GET16(jaguarMainRAM, address); // else if ((address >= 0x800000) && (address <= 0xDFFFFE)) @@ -1108,7 +1111,8 @@ void m68k_write_memory_8(unsigned int address, unsigned int value) // Musashi does this automagically for you, UAE core does not :-P address &= 0x00FFFFFF; #ifdef CPU_DEBUG_MEMORY - if ((address >= 0x000000) && (address <= 0x3FFFFF)) + // Note that the Jaguar only has 2M of RAM, not 4! + if ((address >= 0x000000) && (address <= 0x1FFFFF)) { if (startMemLog) { @@ -1136,7 +1140,8 @@ void m68k_write_memory_8(unsigned int address, unsigned int value) printf("M68K: (8) Tripwire hit...\n");//*/ #ifndef USE_NEW_MMU - if ((address >= 0x000000) && (address <= 0x3FFFFF)) + // Note that the Jaguar only has 2M of RAM, not 4! + if ((address >= 0x000000) && (address <= 0x1FFFFF)) jaguarMainRAM[address] = value; else if ((address >= 0xDFFF00) && (address <= 0xDFFFFF)) CDROMWriteByte(address, value, M68K); @@ -1156,7 +1161,8 @@ void m68k_write_memory_16(unsigned int address, unsigned int value) // Musashi does this automagically for you, UAE core does not :-P address &= 0x00FFFFFF; #ifdef CPU_DEBUG_MEMORY - if ((address >= 0x000000) && (address <= 0x3FFFFE)) + // Note that the Jaguar only has 2M of RAM, not 4! + if ((address >= 0x000000) && (address <= 0x1FFFFE)) { if (startMemLog) { @@ -1211,7 +1217,8 @@ if (address == 0xF02110) }//*/ #ifndef USE_NEW_MMU - if ((address >= 0x000000) && (address <= 0x3FFFFE)) + // Note that the Jaguar only has 2M of RAM, not 4! + if ((address >= 0x000000) && (address <= 0x1FFFFE)) { /* jaguar_mainRam[address] = value >> 8; jaguar_mainRam[address + 1] = value & 0xFF;*/ @@ -1458,7 +1465,7 @@ uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/) uint8 data = 0x00; offset &= 0xFFFFFF; - if (offset < 0x400000) + if (offset < 0x200000) data = jaguarMainRAM[offset & 0x3FFFFF]; else if ((offset >= 0x800000) && (offset < 0xC00000)) data = jaguarMainROM[offset - 0x800000]; @@ -1481,9 +1488,9 @@ uint8 JaguarReadByte(uint32 offset, uint32 who/*=UNKNOWN*/) uint16 JaguarReadWord(uint32 offset, uint32 who/*=UNKNOWN*/) { offset &= 0xFFFFFF; - if (offset <= 0x3FFFFE) + if (offset <= 0x1FFFFE) { - return (jaguarMainRAM[(offset+0) & 0x3FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x3FFFFF]; + return (jaguarMainRAM[(offset+0) & 0x1FFFFF] << 8) | jaguarMainRAM[(offset+1) & 0x1FFFFF]; } else if ((offset >= 0x800000) && (offset <= 0xBFFFFE)) { @@ -1515,9 +1522,9 @@ void JaguarWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/) WriteLog("JWB: Byte %02X written at %08X by %s\n", data, offset, whoName[who]);//*/ offset &= 0xFFFFFF; - if (offset < 0x400000) + if (offset < 0x200000) { - jaguarMainRAM[offset & 0x3FFFFF] = data; + jaguarMainRAM[offset & 0x1FFFFF] = data; return; } else if ((offset >= 0xDFFF00) && (offset <= 0xDFFFFF)) @@ -1559,7 +1566,7 @@ if (offset == 0x0102)//64*4) offset &= 0xFFFFFF; - if (offset <= 0x3FFFFE) + if (offset <= 0x1FFFFE) { /* GPU Table (CD BIOS) @@ -1647,8 +1654,8 @@ if (who == GPU && (gpu_pc == 0xF03604 || gpu_pc == 0xF03638)) if (offset == 0x11D31A + 0x48000 || offset == 0x11D31A) WriteLog("JWW: %s writing star %04X at %08X...\n", whoName[who], data, offset);//*/ - jaguarMainRAM[(offset+0) & 0x3FFFFF] = data >> 8; - jaguarMainRAM[(offset+1) & 0x3FFFFF] = data & 0xFF; + jaguarMainRAM[(offset+0) & 0x1FFFFF] = data >> 8; + jaguarMainRAM[(offset+1) & 0x1FFFFF] = data & 0xFF; return; } else if (offset >= 0xDFFF00 && offset <= 0xDFFFFE) @@ -1717,7 +1724,7 @@ void JaguarInit(void) memset(writeMemMin, 0xFF, 0x400000); memset(writeMemMax, 0x00, 0x400000); #endif - memset(jaguarMainRAM, 0x00, 0x400000); + memset(jaguarMainRAM, 0x00, 0x200000); // memset(jaguar_mainRom, 0xFF, 0x200000); // & set it to all Fs... // memset(jaguar_mainRom, 0x00, 0x200000); // & set it to all 0s... //NOTE: This *doesn't* fix FlipOut... @@ -1726,6 +1733,8 @@ void JaguarInit(void) memset(jaguarMainROM, 0x01, 0x600000); // & set it to all 01s... // memset(jaguar_mainRom, 0xFF, 0x600000); // & set it to all Fs... lowerField = false; // Reset the lower field flag +//temp, for crappy crap that sux +memset(jaguarMainRAM + 0x804, 0xFF, 4); m68k_set_cpu_type(M68K_CPU_TYPE_68000); m68k_pulse_reset(); // Need to do this so UAE disasm doesn't segfault on exit @@ -1895,7 +1904,7 @@ void JaguarDone(void) JaguarDasm(0x4000, 10000); WriteLog("\n");//*/ // WriteLog("\n\nM68000 disassembly at $802000...\n"); -// JaguarDasm(0x800830, 0x1000); +// JaguarDasm(0x802000, 0x1000); // WriteLog("\n\nM68000 disassembly at $4100...\n"); // JaguarDasm(0x4100, 200); // WriteLog("\n\nM68000 disassembly at $800800...\n"); diff --git a/src/op.cpp b/src/op.cpp index 778bf74..682c023 100644 --- a/src/op.cpp +++ b/src/op.cpp @@ -616,8 +616,17 @@ if (!inhibit) // For OP testing only! /* if (op_pointer > ((p0 & 0x000007FFFF000000LL) >> 21)) return;*/ - op_pointer = (p0 & 0x000007FFFF000000LL) >> 21; +// NOTE: The link address only replaces bits 3-21 in the OLP, and this replaces +// EVERYTHING. !!! FIX !!! [DONE] +#warning "!!! Link address is not linked properly for all object types !!!" +#warning "!!! Only BITMAP is properly handled !!!" + op_pointer &= 0xFFC00007; + op_pointer |= (p0 & 0x000007FFFF000000LL) >> 21; //WriteLog("New OP: %08X\n", op_pointer); +//kludge: Seems that memory access is mirrored in the first 8MB of memory... +if (op_pointer > 0x1FFFFF && op_pointer < 0x800000) + op_pointer &= 0xFF1FFFFF; // Knock out bits 21-23 + break; } case OBJECT_TYPE_SCALE: @@ -771,6 +780,7 @@ OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756E8 pitch 1 hflipp uint16 ypos = (p0 >> 3) & 0x7FF; // NOTE: The JTRM sez there are only 2 bits used for the CC, but lists *five* // conditions! Need at least one more bit for that! :-P +// Also, the ASIC nets imply that it uses bits 14-16 (height in BM & SBM objects) #warning "!!! Possibly bad CC handling in OP (missing 1 bit) !!!" uint8 cc = (p0 >> 14) & 0x03; uint32 link = (p0 >> 21) & 0x3FFFF8; @@ -836,7 +846,7 @@ OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756E8 pitch 1 hflipp // break; } default: - WriteLog("op: unknown object type %i\n", ((uint8)p0 & 0x07)); +// WriteLog("op: unknown object type %i\n", ((uint8)p0 & 0x07)); return; } @@ -894,6 +904,13 @@ void OPProcessFixedBitmap(uint64 p0, uint64 p1, bool render) // Is it OK to have a 0 for the data width??? (i.e., undocumented?) // Seems to be... Seems that dwidth *can* be zero (i.e., reuse same line) as well. // Pitch == 0 is OK too... + +//kludge: Seems that the OP treats iwidth == 0 as iwidth == 1... Need to investigate +// on real hardware... +#warning "!!! Need to investigate iwidth == 0 behavior on real hardware !!!" +if (iwidth == 0) + iwidth = 1; + // if (!render || op_pointer == 0 || ptr == 0 || pitch == 0) //I'm not convinced that we need to concern ourselves with data & op_pointer here either! if (!render || iwidth == 0)