]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/op.cpp
Fixed DSP/audio options to be unambiguous and consistent.
[virtualjaguar] / src / op.cpp
index 2978c6dc9541b4ea8e48ce5f9a1cf56b621bcbff..8708d9b34418c81a28ca6f279f5a81e65a51d953 100644 (file)
@@ -3,10 +3,10 @@
 //
 // Original source by David Raingeard (Cal2)
 // GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
-// Extensive cleanups/fixes/rewrites by James L. Hammons
+// Extensive cleanups/fixes/rewrites by James Hammons
 // (C) 2010 Underground Software
 //
-// JLH = James L. Hammons <jlhamm@acm.org>
+// JLH = James Hammons <jlhamm@acm.org>
 //
 // Who  When        What
 // ---  ----------  -------------------------------------------------------------
@@ -20,7 +20,7 @@
 #include "gpu.h"
 #include "jaguar.h"
 #include "log.h"
-#include "m68k.h"
+#include "m68000/m68kinterface.h"
 #include "memory.h"
 #include "tom.h"
 
@@ -36,9 +36,9 @@
 #define OBJECT_TYPE_BRANCH     3                                       // 011
 #define OBJECT_TYPE_STOP       4                                       // 100
 
-#define CONDITION_EQUAL                                0
-#define CONDITION_LESS_THAN                    1
-#define CONDITION_GREATER_THAN         2
+#define CONDITION_EQUAL                                0                       // VC == YPOS
+#define CONDITION_LESS_THAN                    1                       // VC < YPOS
+#define CONDITION_GREATER_THAN         2                       // VC > YPOS
 #define CONDITION_OP_FLAG_SET          3
 #define CONDITION_SECOND_HALF_LINE     4
 
 
 void OPProcessFixedBitmap(uint64 p0, uint64 p1, bool render);
 void OPProcessScaledBitmap(uint64 p0, uint64 p1, uint64 p2, bool render);
+void OPDiscoverObjects(uint32 address);
+void OPDumpObjectList(void);
 void DumpScaledObject(uint64 p0, uint64 p1, uint64 p2);
 void DumpFixedObject(uint64 p0, uint64 p1);
+void DumpBitmapCore(uint64 p0, uint64 p1);
 uint64 OPLoadPhrase(uint32 offset);
 
 // Local global variables
@@ -131,20 +134,33 @@ void OPReset(void)
        objectp_running = 0;
 }
 
+static const char * opType[8] =
+{ "(BITMAP)", "(SCALED BITMAP)", "(GPU INT)", "(BRANCH)", "(STOP)", "???", "???", "???" };
+static const char * ccType[8] =
+       { "\"==\"", "\"<\"", "\">\"", "(opflag set)", "(second half line)", "?", "?", "?" };
+static uint32 object[8192];
+static uint32 numberOfObjects;
+//static uint32 objectLink[8192];
+//static uint32 numberOfLinks;
+
 void OPDone(void)
 {
-       const char * opType[8] =
-       { "(BITMAP)", "(SCALED BITMAP)", "(GPU INT)", "(BRANCH)", "(STOP)", "???", "???", "???" };
-       const char * ccType[8] =
-               { "\"==\"", "\"<\"", "\">\"", "(opflag set)", "(second half line)", "?", "?", "?" };
+//#warning "!!! Fix OL dump so that it follows links !!!"
+//     const char * opType[8] =
+//     { "(BITMAP)", "(SCALED BITMAP)", "(GPU INT)", "(BRANCH)", "(STOP)", "???", "???", "???" };
+//     const char * ccType[8] =
+//             { "\"==\"", "\"<\"", "\">\"", "(opflag set)", "(second half line)", "?", "?", "?" };
 
        uint32 olp = OPGetListPointer();
-       WriteLog("OP: OLP = %08X\n", olp);
+       WriteLog("\nOP: OLP = $%08X\n", olp);
        WriteLog("OP: Phrase dump\n    ----------\n");
+
+#if 0
        for(uint32 i=0; i<0x100; i+=8)
        {
                uint32 hi = JaguarReadLong(olp + i, OP), lo = JaguarReadLong(olp + i + 4, OP);
                WriteLog("\t%08X: %08X %08X %s", olp + i, hi, lo, opType[lo & 0x07]);
+
                if ((lo & 0x07) == 3)
                {
                        uint16 ypos = (lo >> 3) & 0x7FF;
@@ -152,16 +168,119 @@ void OPDone(void)
                        uint32 link = ((hi << 11) | (lo >> 21)) & 0x3FFFF8;
                        WriteLog(" YPOS=%u, CC=%s, link=%08X", ypos, ccType[cc], link);
                }
+
                WriteLog("\n");
+
                if ((lo & 0x07) == 0)
                        DumpFixedObject(OPLoadPhrase(olp+i), OPLoadPhrase(olp+i+8));
+
                if ((lo & 0x07) == 1)
                        DumpScaledObject(OPLoadPhrase(olp+i), OPLoadPhrase(olp+i+8), OPLoadPhrase(olp+i+16));
        }
+
        WriteLog("\n");
+#else
+#warning "!!! Fix lockup in OPDiscoverObjects() !!!"
+//temp, to keep the following function from locking up on bad/weird OLs
+return;
+
+       numberOfObjects = 0;
+       OPDiscoverObjects(olp);
+       OPDumpObjectList();
+#endif
+}
+
+void OPDiscoverObjects(uint32 address)
+{
+       // Check to see if we've already seen this object
+       for(uint32 i=0; i<numberOfObjects; i++)
+       {
+               if (address == object[i])
+                       return;
+       }
+
+       // Store the object...
+       object[numberOfObjects++] = address;
+       uint8 objectType = 0;
+
+       do
+       {
+               uint32 hi = JaguarReadLong(address + 0, OP);
+               uint32 lo = JaguarReadLong(address + 4, OP);
+               objectType = lo & 0x07;
+               uint32 link = ((hi << 11) | (lo >> 21)) & 0x3FFFF8;
+
+               if (objectType == 3)
+               {
+                       uint16 ypos = (lo >> 3) & 0x7FF;
+                       uint8  cc   = (lo >> 14) & 0x07;        // Proper # of bits == 3
+
+                       // Recursion needed to follow all links!
+                       OPDiscoverObjects(address + 8);
+               }
+
+               if (address == link)    // Ruh roh...
+               {
+                       // Runaway recursive link is bad!
+                       return;
+               }
+
+               address = link;
+
+               // Check to see if we've already seen this object, and add it if not
+               bool seenObject = false;
+
+               for(uint32 i=0; i<numberOfObjects; i++)
+               {
+                       if (address == object[i])
+                       {
+                               seenObject = true;
+                               break;
+                       }
+               }
+
+               if (!seenObject)
+                       object[numberOfObjects++] = address;
+       }
+       while (objectType != 4);
+}
+
+void OPDumpObjectList(void)
+{
+       for(uint32 i=0; i<numberOfObjects; i++)
+       {
+               uint32 address = object[i];
+
+               uint32 hi = JaguarReadLong(address + 0, OP);
+               uint32 lo = JaguarReadLong(address + 4, OP);
+               uint8 objectType = lo & 0x07;
+               uint32 link = ((hi << 11) | (lo >> 21)) & 0x3FFFF8;
+               WriteLog("%08X: %08X %08X %s", address, hi, lo, opType[objectType]);
+
+               if (objectType == 3)
+               {
+                       uint16 ypos = (lo >> 3) & 0x7FF;
+                       uint8  cc   = (lo >> 14) & 0x07;        // Proper # of bits == 3
+                       WriteLog(" YPOS=%u, CC=%s, link=$%08X", ypos, ccType[cc], link);
+               }
 
-//     memory_free(op_blend_y);
-//     memory_free(op_blend_cr);
+               WriteLog("\n");
+
+               if (objectType == 0)
+                       DumpFixedObject(OPLoadPhrase(address + 0), OPLoadPhrase(address + 8));
+
+               if (objectType == 1)
+                       DumpScaledObject(OPLoadPhrase(address + 0), OPLoadPhrase(address + 8),
+                               OPLoadPhrase(address + 16));
+
+               if (address == link)    // Ruh roh...
+               {
+                       // Runaway recursive link is bad!
+                       WriteLog("***** SELF REFERENTIAL LINK *****\n\n");
+               }
+       }
+
+       WriteLog("\n");
 }
 
 //
@@ -268,25 +387,9 @@ void OPStorePhrase(uint32 offset, uint64 p)
 //
 void DumpScaledObject(uint64 p0, uint64 p1, uint64 p2)
 {
-       WriteLog(" (SCALED BITMAP)");
-       WriteLog(" %08X --> phrase %08X %08X\n", op_pointer, (uint32)(p1>>32), (uint32)(p1&0xFFFFFFFF));
-       WriteLog("                 %08X --> phrase %08X %08X ", op_pointer+8, (uint32)(p2>>32), (uint32)(p2&0xFFFFFFFF));
-       uint8 bitdepth = (p1 >> 12) & 0x07;
-//WAS: int16 ypos = ((p0 >> 3) & 0x3FF);                       // ??? What if not interlaced (/2)?
-       int16 ypos = ((p0 >> 3) & 0x7FF);                       // ??? What if not interlaced (/2)?
-       int32 xpos = p1 & 0xFFF;
-       xpos = (xpos & 0x800 ? xpos | 0xFFFFF000 : xpos);
-       uint32 iwidth = ((p1 >> 28) & 0x3FF);
-       uint32 dwidth = ((p1 >> 18) & 0x3FF);           // Unsigned!
-       uint16 height = ((p0 >> 14) & 0x3FF);
-       uint32 link = ((p0 >> 24) & 0x7FFFF) << 3;
-       uint32 ptr = ((p0 >> 43) & 0x1FFFFF) << 3;
-       uint32 firstPix = (p1 >> 49) & 0x3F;
-       uint8 flags = (p1 >> 45) & 0x0F;
-       uint8 idx = (p1 >> 38) & 0x7F;
-       uint32 pitch = (p1 >> 15) & 0x07;
-       WriteLog("\n    [%u (%u) x %u @ (%i, %u) (%u bpp), l: %08X, p: %08X fp: %02X, fl:%s%s%s%s, idx:%02X, pt:%02X]\n",
-               iwidth, dwidth, height, xpos, ypos, op_bitmap_bit_depth[bitdepth], link, ptr, firstPix, (flags&OPFLAG_REFLECT ? "REFLECT " : ""), (flags&OPFLAG_RMW ? "RMW " : ""), (flags&OPFLAG_TRANS ? "TRANS " : ""), (flags&OPFLAG_RELEASE ? "RELEASE" : ""), idx, pitch);
+       WriteLog("          %08X %08X\n", (uint32)(p1>>32), (uint32)(p1&0xFFFFFFFF));
+       WriteLog("          %08X %08X\n", (uint32)(p2>>32), (uint32)(p2&0xFFFFFFFF));
+       DumpBitmapCore(p0, p1);
        uint32 hscale = p2 & 0xFF;
        uint32 vscale = (p2 >> 8) & 0xFF;
        uint32 remainder = (p2 >> 16) & 0xFF;
@@ -295,13 +398,18 @@ void DumpScaledObject(uint64 p0, uint64 p1, uint64 p2)
 
 void DumpFixedObject(uint64 p0, uint64 p1)
 {
-       WriteLog(" (BITMAP)");
-       WriteLog(" %08X --> phrase %08X %08X\n", op_pointer, (uint32)(p1>>32), (uint32)(p1&0xFFFFFFFF));
+       WriteLog("          %08X %08X\n", (uint32)(p1>>32), (uint32)(p1&0xFFFFFFFF));
+       DumpBitmapCore(p0, p1);
+}
+
+void DumpBitmapCore(uint64 p0, uint64 p1)
+{
+       uint32 bdMultiplier[8] = { 64, 32, 16, 8, 4, 2, 1, 1 };
        uint8 bitdepth = (p1 >> 12) & 0x07;
 //WAS: int16 ypos = ((p0 >> 3) & 0x3FF);                       // ??? What if not interlaced (/2)?
        int16 ypos = ((p0 >> 3) & 0x7FF);                       // ??? What if not interlaced (/2)?
        int32 xpos = p1 & 0xFFF;
-       xpos = (xpos & 0x800 ? xpos | 0xFFFFF000 : xpos);
+       xpos = (xpos & 0x800 ? xpos | 0xFFFFF000 : xpos);       // Sign extend that mutha!
        uint32 iwidth = ((p1 >> 28) & 0x3FF);
        uint32 dwidth = ((p1 >> 18) & 0x3FF);           // Unsigned!
        uint16 height = ((p0 >> 14) & 0x3FF);
@@ -311,18 +419,24 @@ void DumpFixedObject(uint64 p0, uint64 p1)
        uint8 flags = (p1 >> 45) & 0x0F;
        uint8 idx = (p1 >> 38) & 0x7F;
        uint32 pitch = (p1 >> 15) & 0x07;
-       WriteLog("    [%u (%u) x %u @ (%i, %u) (%u bpp), l: %08X, p: %08X fp: %02X, fl:%s%s%s%s, idx:%02X, pt:%02X]\n",
-               iwidth, dwidth, height, xpos, ypos, op_bitmap_bit_depth[bitdepth], link, ptr, firstPix, (flags&OPFLAG_REFLECT ? "REFLECT " : ""), (flags&OPFLAG_RMW ? "RMW " : ""), (flags&OPFLAG_TRANS ? "TRANS " : ""), (flags&OPFLAG_RELEASE ? "RELEASE" : ""), idx, pitch);
+       WriteLog("    [%u x %u @ (%i, %u) (iw:%u, dw:%u) (%u bpp), l:%08X, p:%08X fp:%02X, fl:%s%s%s%s, idx:%02X, pt:%02X]\n",
+               iwidth * bdMultiplier[bitdepth],
+               height, xpos, ypos, iwidth, dwidth, op_bitmap_bit_depth[bitdepth], link,
+               ptr, firstPix, (flags&OPFLAG_REFLECT ? "REFLECT " : ""),
+               (flags&OPFLAG_RMW ? "RMW " : ""), (flags&OPFLAG_TRANS ? "TRANS " : ""),
+               (flags&OPFLAG_RELEASE ? "RELEASE" : ""), idx, pitch);
 }
 
 //
 // Object Processor main routine
 //
-//Need to fix this so that when an GPU object IRQ happens, we can pick up OP processing
-//where we left off. !!! FIX !!!
 #warning "Need to fix this so that when an GPU object IRQ happens, we can pick up OP processing where we left off. !!! FIX !!!"
-void OPProcessList(int scanline, bool render)
+void OPProcessList(int halfline, bool render)
 {
+#warning "!!! NEED TO HANDLE MULTIPLE FIELDS PROPERLY !!!
+// We ignore them, for now; not good
+       halfline &= 0x7FF;
+
 extern int op_start_log;
 //     char * condition_to_str[8] =
 //             { "==", "<", ">", "(opflag set)", "(second half line)", "?", "?", "?" };
@@ -331,7 +445,7 @@ extern int op_start_log;
 
 //     objectp_stop_reading_list = false;
 
-//WriteLog("OP: Processing line #%u (OLP=%08X)...\n", scanline, op_pointer);
+//WriteLog("OP: Processing line #%u (OLP=%08X)...\n", halfline, op_pointer);
 //op_done();
 
 // *** BEGIN OP PROCESSOR TESTING ONLY ***
@@ -342,9 +456,9 @@ bool inhibit;
 int bitmapCounter = 0;
 // *** END OP PROCESSOR TESTING ONLY ***
 
-       uint32 opCyclesToRun = 10000;                                   // This is a pulled-out-of-the-air value (will need to be fixed, obviously!)
+       uint32 opCyclesToRun = 30000;                                   // This is a pulled-out-of-the-air value (will need to be fixed, obviously!)
 
-//     if (op_pointer) WriteLog(" new op list at 0x%.8x scanline %i\n",op_pointer,scanline);
+//     if (op_pointer) WriteLog(" new op list at 0x%.8x halfline %i\n",op_pointer,halfline);
        while (op_pointer)
        {
 // *** BEGIN OP PROCESSOR TESTING ONLY ***
@@ -357,14 +471,14 @@ else
 //                     return;
 
                uint64 p0 = OPLoadPhrase(op_pointer);
-//WriteLog("\t%08X type %i\n", op_pointer, (uint8)p0 & 0x07);
                op_pointer += 8;
+//WriteLog("\t%08X type %i\n", op_pointer, (uint8)p0 & 0x07);
 
 #if 1
-if (scanline == TOMGetVDB() && op_start_log)
-//if (scanline == 215 && op_start_log)
-//if (scanline == 28 && op_start_log)
-//if (scanline == 0)
+if (halfline == TOMGetVDB() && op_start_log)
+//if (halfline == 215 && op_start_log)
+//if (halfline == 28 && op_start_log)
+//if (halfline == 0)
 {
 WriteLog("%08X --> phrase %08X %08X", op_pointer - 8, (int)(p0>>32), (int)(p0&0xFFFFFFFF));
 if ((p0 & 0x07) == OBJECT_TYPE_BITMAP)
@@ -454,7 +568,8 @@ WriteLog("    --> List end\n\n");
                                ypos = TOMReadWord(0xF00046, OP) / 2;                   // Get the VDB value
 #endif
 // Actually, no. Any item less than VDB will get only the lines that hang over VDB displayed.
-// So we need to fix this somehow... (and it has... in tom.cpp :-P)
+// Actually, this is incorrect. It seems that VDB value is wrong somewhere and that's
+// what's causing things to fuck up. Still no idea why.
 
                        uint32 height = (p0 & 0xFFC000) >> 14;
                        uint32 oldOPP = op_pointer - 8;
@@ -464,13 +579,13 @@ if (inhibit && op_start_log)
 bitmapCounter++;
 if (!inhibit)  // For OP testing only!
 // *** END OP PROCESSOR TESTING ONLY ***
-                       if (scanline >= ypos && height > 0)
+                       if (halfline >= ypos && height > 0)
                        {
                                uint64 p1 = OPLoadPhrase(op_pointer);
                                op_pointer += 8;
-//WriteLog("OP: Writing scanline %d with ypos == %d...\n", scanline, ypos);
+//WriteLog("OP: Writing halfline %d with ypos == %d...\n", halfline, ypos);
 //WriteLog("--> Writing %u BPP bitmap...\n", op_bitmap_bit_depth[(p1 >> 12) & 0x07]);
-//                             OPProcessFixedBitmap(scanline, p0, p1, render);
+//                             OPProcessFixedBitmap(halfline, p0, p1, render);
                                OPProcessFixedBitmap(p0, p1, render);
 
                                // OP write-backs
@@ -505,8 +620,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:
@@ -519,19 +643,19 @@ if (!inhibit)     // For OP testing only!
 // *** BEGIN OP PROCESSOR TESTING ONLY ***
 if (inhibit && op_start_log)
 {
-       WriteLog("!!! ^^^ This object is INHIBITED! ^^^ !!! (scanline=%u, ypos=%u, height=%u)\n", scanline, ypos, height);
+       WriteLog("!!! ^^^ This object is INHIBITED! ^^^ !!! (halfline=%u, ypos=%u, height=%u)\n", halfline, ypos, height);
        DumpScaledObject(p0, OPLoadPhrase(op_pointer), OPLoadPhrase(op_pointer+8));
 }
 bitmapCounter++;
 if (!inhibit)  // For OP testing only!
 // *** END OP PROCESSOR TESTING ONLY ***
-                       if (scanline >= ypos && height > 0)
+                       if (halfline >= ypos && height > 0)
                        {
                                uint64 p1 = OPLoadPhrase(op_pointer);
                                op_pointer += 8;
                                uint64 p2 = OPLoadPhrase(op_pointer);
                                op_pointer += 8;
-//WriteLog("OP: %08X (%d) %08X%08X %08X%08X %08X%08X\n", oldOPP, scanline, (uint32)(p0>>32), (uint32)(p0&0xFFFFFFFF), (uint32)(p1>>32), (uint32)(p1&0xFFFFFFFF), (uint32)(p2>>32), (uint32)(p2&0xFFFFFFFF));
+//WriteLog("OP: %08X (%d) %08X%08X %08X%08X %08X%08X\n", oldOPP, halfline, (uint32)(p0>>32), (uint32)(p0&0xFFFFFFFF), (uint32)(p1>>32), (uint32)(p1&0xFFFFFFFF), (uint32)(p2>>32), (uint32)(p2&0xFFFFFFFF));
                                OPProcessScaledBitmap(p0, p1, p2, render);
 
                                // OP write-backs
@@ -585,7 +709,7 @@ OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756E8 pitch 1 hflipp
 //Here's another problem:
 //    [hsc: 20, vsc: 20, rem: 00]
 // Since we're not checking for $E0 (but that's what we get from the above), we end
-// up repeating this scanline unnecessarily... !!! FIX !!! [DONE, but... still not quite
+// up repeating this halfline unnecessarily... !!! FIX !!! [DONE, but... still not quite
 // right. Either that, or the Accolade team that wrote Bubsy screwed up royal.]
 //Also note: $E0 = 7.0 which IS a legal vscale value...
 
@@ -651,18 +775,22 @@ OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756E8 pitch 1 hflipp
 //Do something like:
 //OPSuspendedByGPU = true;
 //Dunno if the OP keeps processing from where it was interrupted, or if it just continues
-//on the next scanline...
+//on the next halfline...
 // --> It continues from where it was interrupted! !!! FIX !!!
                        break;
                }
                case OBJECT_TYPE_BRANCH:
                {
                        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;
 
 //                     if ((ypos!=507)&&(ypos!=25))
-//                             WriteLog("\t%i%s%i link=0x%.8x\n",scanline,condition_to_str[cc],ypos>>1,link);
+//                             WriteLog("\t%i%s%i link=0x%.8x\n",halfline,condition_to_str[cc],ypos>>1,link);
                        switch (cc)
                        {
                        case CONDITION_EQUAL:
@@ -693,6 +821,7 @@ OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756E8 pitch 1 hflipp
                                exit(0);
                                break;
                        default:
+                               // Basically, if you do this, the OP does nothing. :-)
                                WriteLog("OP: Unimplemented branch condition %i\n", cc);
                        }
                        break;
@@ -721,7 +850,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;
                }
 
@@ -730,6 +859,7 @@ OP: Scaled bitmap 4x? 4bpp at 34,? hscale=80 fpix=0 data=000756E8 pitch 1 hflipp
                // and bail out/reenter to properly simulate an overloaded OP... !!! FIX !!!
 #warning "Better would be to count how many actual cycles it used and bail out/reenter to properly simulate an overloaded OP... !!! FIX !!!"
                opCyclesToRun--;
+
                if (!opCyclesToRun)
                        return;
        }
@@ -778,11 +908,27 @@ 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)
                return;
 
+//OK, so we know the position in the line buffer is correct. It's the clipping in
+//24bpp mode that's wrong!
+#if 0
+//This is a total kludge, based upon the fact that 24BPP mode puts *4* bytes
+//into the line buffer for each pixel.
+if (depth == 5)        // i.e., 24bpp mode...
+       xpos >>= 1;     // Cut it in half...
+#endif
+
 //#define OP_DEBUG_BMP
 //#ifdef OP_DEBUG_BMP
 //     WriteLog("bitmap %ix%i %ibpp at %i,%i firstpix=%i data=0x%.8x pitch %i hflipped=%s dwidth=%i (linked to 0x%.8x) Transluency=%s\n",
@@ -798,8 +944,12 @@ void OPProcessFixedBitmap(uint64 p0, uint64 p1, bool render)
        // Not sure if this is Jaguar Two only location or what...
        // From the docs, it is... If we want to limit here we should think of something else.
 //     int32 limit = GET16(tom_ram_8, 0x0008);                 // LIMIT
+//     int32 limit = 720;
+//     int32 lbufWidth = (!in24BPPMode ? limit - 1 : (limit / 2) - 1); // Zero based limit...
+//printf("[OP:xpos=%i,spos=%i,epos=%i>", xpos, startPos, endPos);
+       // This is correct, the OP line buffer is a constant size... 
        int32 limit = 720;
-       int32 lbufWidth = (!in24BPPMode ? limit - 1 : (limit / 2) - 1); // Zero based limit...
+       int32 lbufWidth = 719;
 
        // If the image is completely to the left or right of the line buffer, then bail.
 //If in REFLECT mode, then these values are swapped! !!! FIX !!! [DONE]
@@ -876,6 +1026,7 @@ if (depth > 5)
                clippedWidth = startPos - lbufWidth,
                dataClippedWidth = phraseClippedWidth = clippedWidth / phraseWidthToPixels[depth],
                startPos = lbufWidth + (clippedWidth % phraseWidthToPixels[depth]);
+//printf("<OP:spos=%i,epos=%i]", startPos, endPos);
 
        // If the image is sitting on the line buffer left or right edge, we need to compensate
        // by decreasing the image phrase width accordingly.
@@ -891,7 +1042,11 @@ if (depth > 5)
 //     uint32 lbufAddress = 0x1800 + (!in24BPPMode ? leftMargin * 2 : leftMargin * 4);
 //Why does this work right when multiplying startPos by 2 (instead of 4) for 24 BPP mode?
 //Is this a bug in the OP?
-       uint32 lbufAddress = 0x1800 + (!in24BPPMode ? startPos * 2 : startPos * 2);
+//It's because in 24bpp mode, each pixel takes *4* bytes, instead of the usual 2.
+//Though it looks like we're doing it here no matter what...
+//     uint32 lbufAddress = 0x1800 + (!in24BPPMode ? startPos * 2 : startPos * 2);
+//Let's try this:
+       uint32 lbufAddress = 0x1800 + (startPos * 2);
        uint8 * currentLineBuffer = &tomRam8[lbufAddress];
 
        // Render.
@@ -1242,7 +1397,8 @@ if (start_logging)
        // From the docs, it is... If we want to limit here we should think of something else.
 //     int32 limit = GET16(tom_ram_8, 0x0008);                 // LIMIT
        int32 limit = 720;
-       int32 lbufWidth = (!in24BPPMode ? limit - 1 : (limit / 2) - 1); // Zero based limit...
+//     int32 lbufWidth = (!in24BPPMode ? limit - 1 : (limit / 2) - 1); // Zero based limit...
+       int32 lbufWidth = 719;  // Zero based limit...
 
        // If the image is completely to the left or right of the line buffer, then bail.
 //If in REFLECT mode, then these values are swapped! !!! FIX !!! [DONE]