handling of objects with IWIDTH of zero.
- 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
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
// 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?
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);
}
#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)]
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;
}
}
}
WriteLog("\n---[DSP code at 00F1B000]---------------------------\n");
uint32 j = 0xF1B000;
+
while (j <= 0xF1CFFF)
{
uint32 oldj = j;
//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",
(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",
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
(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",
(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",
static char buffer[512];
j = DSP_WORK_RAM_BASE;
+
while (j <= 0xF1BFFF)
{
uint32 oldj = j;
}//*/
WriteLog("DSP opcodes use:\n");
+
for (i=0;i<64;i++)
{
if (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 (dsp_branch_condition_table)
+// free(dsp_branch_condition_table);
- if (mirror_table)
- free(mirror_table);
+// if (mirror_table)
+// free(mirror_table);
}
// 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
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
// 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;
#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))
#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))
// 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)
{
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);
// 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)
{
}//*/
#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;*/
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];
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))
{
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))
offset &= 0xFFFFFF;
- if (offset <= 0x3FFFFE)
+ if (offset <= 0x1FFFFE)
{
/*
GPU Table (CD BIOS)
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)
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...
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
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");
/* 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:
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;
// break;
}
default:
- WriteLog("op: unknown object type %i\n", ((uint8)p0 & 0x07));
+// WriteLog("op: unknown object type %i\n", ((uint8)p0 & 0x07));
return;
}
// 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)