]> Shamusworld >> Repos - virtualjaguar/commitdiff
Preliminary fixes for memory accesses between $200000 and $7FFFFF, proper
authorShamus Hammons <jlhamm@acm.org>
Mon, 13 Feb 2012 00:31:18 +0000 (00:31 +0000)
committerShamus Hammons <jlhamm@acm.org>
Mon, 13 Feb 2012 00:31:18 +0000 (00:31 +0000)
handling of objects with IWIDTH of zero.

docs/TODO
docs/WHATSNEW
src/blitter.cpp
src/cdrom.cpp
src/dsp.cpp
src/gpu.cpp
src/jaguar.cpp
src/op.cpp

index f8276aff5a9e3015db35be95ca90e82897659deb..75a73d7986a722a3126dd8718e0b3c799047fe02 100644 (file)
--- 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
index 3cfcd9aada8b6d53c187c1991ed11b9b5e49e59f..deaeca6224ee34ddc704d84b61fe1d551d8237ad 100644 (file)
@@ -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
index 4e8ea746388e7bc095609a2d0b75a170fbd0cc52..13960996e6e9acf7afe55f786ac1a2ef6bfede3a 100644 (file)
@@ -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?
index 3f419816b5272346abc57622d4ccd532b31db5b1..93087ac4039c88afe2cef7b5f73ed8f2420b6d38 100644 (file)
@@ -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);
 }
 
index 74839cc4b7eee9b6708d02c8e56a5573ca724ad2..aa12cf504457a1d08a1b8dbeb705b5c3d64a6c9e 100644 (file)
@@ -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);
 }
 
 
index 2ea973d864a0a30ef24175a355352740dc765634..1d7afa79a3bfb46f0e75d553d98ab7d96dbf8e5b 100644 (file)
@@ -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
index b6c9f194ce4d80410e5732882db70d2ba53a6a6c..bb940718ba9122a4fbbc2358f0cf8f4f6c4654a0 100644 (file)
@@ -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");
index 778bf7465bfec870e8deb8e0f48e60fdfc2995d1..682c023edbdbe6d2b8b15c160d453d0cba627700 100644 (file)
@@ -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)