Annotation of uae/src/picasso96.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * UAE - The U*nix Amiga Emulator
        !             3:  *
        !             4:  * Picasso96 Support Module
        !             5:  *
        !             6:  * Copyright 1997 Brian King <[email protected], [email protected]>
        !             7:  *
        !             8:  * Theory of operation:
        !             9:  * On the Amiga side, a Picasso card consists mainly of a memory area that
        !            10:  * contains the frame buffer.  On the UAE side, we allocate a block of memory
        !            11:  * that will hold the frame buffer.  This block is in normal memory, it is
        !            12:  * never directly on the graphics card.  All graphics operations, which are
        !            13:  * mainly reads and writes into this block and a few basic operations like
        !            14:  * filling a rectangle, operate on this block of memory.
        !            15:  * Since the memory is not on the graphics card, some work must be done to
        !            16:  * synchronize the display with the data in the Picasso frame buffer.  There
        !            17:  * are various ways to do this.  One possibility is to allocate a second
        !            18:  * buffer of the same size, and perform all write operations twice.  Since
        !            19:  * we never read from the second buffer, it can actually be placed in video
        !            20:  * memory.  The X11 driver could be made to use the Picasso frame buffer as
        !            21:  * the data buffer of an XImage, which could then be XPutImage()d from time
        !            22:  * to time.  Another possibility is to translate all Picasso accesses into
        !            23:  * Xlib (or GDI, or whatever your graphics system is) calls.  This possibility
        !            24:  * is a bit tricky, since there is a risk of generating very many single pixel
        !            25:  * accesses which may be rather slow.
        !            26:  *
        !            27:  * TODO:
        !            28:  * - add an 8 bit emulation for hicolor/truecolor screens. This would allow
        !            29:  *   users to select an 8 bit Workbench resolution that would work regardless
        !            30:  *   of which color depth the display is currently in.
        !            31:  * - add panning capability
        !            32:  */
        !            33: 
        !            34: #include "sysconfig.h"
        !            35: #include "sysdeps.h"
        !            36: 
        !            37: #include "config.h"
        !            38: #include "options.h"
        !            39: #include "threaddep/penguin.h"
        !            40: #include "uae.h"
        !            41: #include "memory.h"
        !            42: #include "custom.h"
        !            43: #include "readcpu.h"
        !            44: #include "newcpu.h"
        !            45: #include "xwin.h"
        !            46: #include "picasso96.h"
        !            47: 
        !            48: #ifdef PICASSO96
        !            49: 
        !            50: extern uae_u8 *lockscr (void);
        !            51: extern void unlockscr (void);
        !            52: 
        !            53: #define MyOutputDebugString printf
        !            54: 
        !            55: static uae_u32 gfxmem_lget (uaecptr) REGPARAM;
        !            56: static uae_u32 gfxmem_wget (uaecptr) REGPARAM;
        !            57: static uae_u32 gfxmem_bget (uaecptr) REGPARAM;
        !            58: static void gfxmem_lput (uaecptr, uae_u32) REGPARAM;
        !            59: static void gfxmem_wput (uaecptr, uae_u32) REGPARAM;
        !            60: static void gfxmem_bput (uaecptr, uae_u32) REGPARAM;
        !            61: static int gfxmem_check (uaecptr addr, uae_u32 size) REGPARAM;
        !            62: static uae_u8 *gfxmem_xlate (uaecptr addr) REGPARAM;
        !            63: 
        !            64: static void write_gfx_long (uaecptr addr, uae_u32 value);
        !            65: static void write_gfx_word (uaecptr addr, uae_u16 value);
        !            66: static void write_gfx_byte (uaecptr addr, uae_u8 value);
        !            67: 
        !            68: static uae_u8 all_ones_bitmap, all_zeros_bitmap; /* yuk */
        !            69: 
        !            70: struct picasso96_state_struct picasso96_state;
        !            71: struct picasso_vidbuf_description picasso_vidinfo;
        !            72: 
        !            73: /* These are the maximum resolutions... They are filled in by GetSupportedResolutions() */
        !            74: /* have to fill this in, otherwise problems occur
        !            75:  * @@@ ??? what problems?
        !            76:  */
        !            77: struct ScreenResolution planar = { 320, 240 };
        !            78: struct ScreenResolution chunky = { 640, 480 };
        !            79: struct ScreenResolution hicolour = { 640, 480 };
        !            80: struct ScreenResolution truecolour = { 640, 480 };
        !            81: struct ScreenResolution alphacolour = { 460, 480 };
        !            82: 
        !            83: uae_u16 picasso96_pixel_format = RGBFF_CHUNKY;
        !            84: 
        !            85: struct PicassoResolution DisplayModes[MAX_PICASSO_MODES];
        !            86: 
        !            87: static int mode_count = 0;
        !            88: 
        !            89: static uae_u32 p2ctab[256][2];
        !            90: 
        !            91: /*
        !            92:  * Debugging dumps
        !            93:  */
        !            94: 
        !            95: static void DumpModeInfoStructure (uaecptr amigamodeinfoptr)
        !            96: {
        !            97:     int i;
        !            98:     MyOutputDebugString ("ModeInfo Structure Dump:\n");
        !            99:     MyOutputDebugString ("  Node.ln_Succ  = 0x%x\n", get_long (amigamodeinfoptr));
        !           100:     MyOutputDebugString ("  Node.ln_Pred  = 0x%x\n", get_long (amigamodeinfoptr + 4));
        !           101:     MyOutputDebugString ("  Node.ln_Type  = 0x%x\n", get_byte (amigamodeinfoptr + 8));
        !           102:     MyOutputDebugString ("  Node.ln_Pri   = %d\n", get_byte (amigamodeinfoptr + 9));
        !           103:     /*MyOutputDebugString ("  Node.ln_Name  = %s\n", uaememptr->Node.ln_Name); */
        !           104:     MyOutputDebugString ("  OpenCount     = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_OpenCount));
        !           105:     MyOutputDebugString ("  Active        = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Active));
        !           106:     MyOutputDebugString ("  Width         = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Width));
        !           107:     MyOutputDebugString ("  Height        = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_Height));
        !           108:     MyOutputDebugString ("  Depth         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Depth));
        !           109:     MyOutputDebugString ("  Flags         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_Flags));
        !           110:     MyOutputDebugString ("  HorTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorTotal));
        !           111:     MyOutputDebugString ("  HorBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorBlankSize));
        !           112:     MyOutputDebugString ("  HorSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncStart));
        !           113:     MyOutputDebugString ("  HorSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSize));
        !           114:     MyOutputDebugString ("  HorSyncSkew   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorSyncSkew));
        !           115:     MyOutputDebugString ("  HorEnableSkew = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_HorEnableSkew));
        !           116:     MyOutputDebugString ("  VerTotal      = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerTotal));
        !           117:     MyOutputDebugString ("  VerBlankSize  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerBlankSize));
        !           118:     MyOutputDebugString ("  VerSyncStart  = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncStart));
        !           119:     MyOutputDebugString ("  VerSyncSize   = %d\n", get_word (amigamodeinfoptr + PSSO_ModeInfo_VerSyncSize));
        !           120:     MyOutputDebugString ("  Clock         = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_first_union));
        !           121:     MyOutputDebugString ("  ClockDivide   = %d\n", get_byte (amigamodeinfoptr + PSSO_ModeInfo_second_union));
        !           122:     MyOutputDebugString ("  PixelClock    = %d\n", get_long (amigamodeinfoptr + PSSO_ModeInfo_PixelClock));
        !           123: }
        !           124: 
        !           125: static void DumpLibResolutionStructure (uaecptr amigalibresptr)
        !           126: {
        !           127:     int i;
        !           128:     uaecptr amigamodeinfoptr;
        !           129:     struct LibResolution *uaememptr = (struct LibResolution *)get_mem_bank(amigalibresptr).xlateaddr(amigalibresptr);
        !           130:     
        !           131:     return;
        !           132: 
        !           133:     MyOutputDebugString ("LibResolution Structure Dump:\n");
        !           134: 
        !           135:     if (get_long (amigalibresptr + PSSO_LibResolution_DisplayID) == 0xFFFFFFFF) {
        !           136:        MyOutputDebugString ("  Finished With LibResolutions...\n");
        !           137:     } else {
        !           138:        MyOutputDebugString ("  Name      = %s\n", uaememptr->P96ID);
        !           139:        MyOutputDebugString ("  DisplayID = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_DisplayID));
        !           140:        MyOutputDebugString ("  Width     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Width));
        !           141:        MyOutputDebugString ("  Height    = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Height));
        !           142:        MyOutputDebugString ("  Flags     = %d\n", get_word (amigalibresptr + PSSO_LibResolution_Flags));
        !           143:        for (i = 0; i < MAXMODES; i++) {
        !           144:            amigamodeinfoptr = get_long (amigalibresptr + PSSO_LibResolution_Modes + i*4);
        !           145:            MyOutputDebugString ("  ModeInfo[%d] = 0x%x\n", i, amigamodeinfoptr);
        !           146:            if (amigamodeinfoptr)
        !           147:                DumpModeInfoStructure(amigamodeinfoptr);
        !           148:        }
        !           149:        MyOutputDebugString ("  BoardInfo = 0x%x\n", get_long (amigalibresptr + PSSO_LibResolution_BoardInfo));
        !           150:     }
        !           151: }
        !           152: 
        !           153: static char binary_byte[8];
        !           154: 
        !           155: static char *BuildBinaryString (uae_u8 value)
        !           156: {
        !           157:     int i;
        !           158:     for (i = 0; i < 8; i++) {
        !           159:        binary_byte[i] = (value & (1 << (7 - i))) ? '#' : '.';
        !           160:     }
        !           161:     return binary_byte;
        !           162: }
        !           163: 
        !           164: static void DumpPattern (struct Pattern *patt)
        !           165: {
        !           166:     uae_u8 *mem;
        !           167:     int row, col;
        !           168:     for (row = 0; row < (1 << patt->Size); row++) {
        !           169:        mem = patt->Memory + row * 2;
        !           170:        for (col = 0; col < 2; col++) {
        !           171:            MyOutputDebugString ("%s", BuildBinaryString (*mem++));
        !           172:        }
        !           173:        MyOutputDebugString ("\n");
        !           174:     }
        !           175: }
        !           176: 
        !           177: static void DumpTemplate (struct Template *tmp, uae_u16 w, uae_u16 h)
        !           178: {
        !           179:     uae_u8 *mem = tmp->Memory;
        !           180:     int row, col, width;
        !           181:     width = (w + 7) >> 3;
        !           182:     MyOutputDebugString ("xoffset = %d, bpr = %d\n", tmp->XOffset, tmp->BytesPerRow);
        !           183:     for (row = 0; row < h; row++) {
        !           184:        mem = tmp->Memory + row * tmp->BytesPerRow;
        !           185:        for (col = 0; col < width; col++) {
        !           186:            MyOutputDebugString ("%s", BuildBinaryString (*mem++));
        !           187:        }
        !           188:        MyOutputDebugString ("\n");
        !           189:     }
        !           190: }
        !           191: 
        !           192: static void ShowSupportedResolutions (void)
        !           193: {
        !           194:     int i;
        !           195:     
        !           196:     return;
        !           197: 
        !           198:     for (i = 0; i < mode_count; i++)
        !           199:        MyOutputDebugString ("%s\n", DisplayModes[i].name);
        !           200: }
        !           201: 
        !           202: /*
        !           203:  * Amiga <-> native structure conversion functions
        !           204:  */
        !           205: 
        !           206: static int CopyRenderInfoStructureA2U (uaecptr amigamemptr, struct RenderInfo *ri)
        !           207: {
        !           208:     uaecptr memp = get_long (amigamemptr + PSSO_RenderInfo_Memory);
        !           209: 
        !           210:     if (valid_address (memp, 1 /* FIXME */)) {
        !           211:        ri->Memory = get_real_address (memp);
        !           212:        ri->BytesPerRow = get_word (amigamemptr + PSSO_RenderInfo_BytesPerRow);
        !           213:        ri->RGBFormat = get_long (amigamemptr + PSSO_RenderInfo_RGBFormat);
        !           214:        return 1;
        !           215:     }
        !           216:     MyOutputDebugString ("ERROR - Invalid RenderInfo memory area...\n");
        !           217:     return 0;
        !           218: }
        !           219: 
        !           220: static int CopyPatternStructureA2U (uaecptr amigamemptr, struct Pattern *pattern)
        !           221: {
        !           222:     uaecptr memp = get_long (amigamemptr + PSSO_Pattern_Memory);
        !           223:     if (valid_address (memp, 1 /* FIXME */)) {
        !           224:        pattern->Memory = get_real_address (memp);
        !           225:        pattern->XOffset = get_word (amigamemptr + PSSO_Pattern_XOffset);
        !           226:        pattern->YOffset = get_word (amigamemptr + PSSO_Pattern_YOffset);
        !           227:        pattern->FgPen = get_long (amigamemptr + PSSO_Pattern_FgPen);
        !           228:        pattern->BgPen = get_long (amigamemptr + PSSO_Pattern_BgPen);
        !           229:        pattern->Size = get_byte (amigamemptr + PSSO_Pattern_Size);
        !           230:        pattern->DrawMode = get_byte (amigamemptr + PSSO_Pattern_DrawMode);
        !           231:        return 1;
        !           232:     }
        !           233:     MyOutputDebugString ("ERROR - Invalid Pattern memory area...\n");
        !           234:     return 0;
        !           235: }
        !           236: 
        !           237: static void CopyColorIndexMappingA2U (uaecptr amigamemptr, struct ColorIndexMapping *cim)
        !           238: {
        !           239:     int i;
        !           240:     cim->ColorMask = get_long (amigamemptr);
        !           241:     for (i = 0; i < 256; i++, amigamemptr += 4)
        !           242:        cim->Colors[i] = get_long (amigamemptr + 4);
        !           243: }
        !           244: 
        !           245: static int CopyBitMapStructureA2U (uaecptr amigamemptr, struct BitMap *bm)
        !           246: {
        !           247:     int i;
        !           248: 
        !           249:     bm->BytesPerRow = get_word (amigamemptr + PSSO_BitMap_BytesPerRow);
        !           250:     bm->Rows = get_word (amigamemptr + PSSO_BitMap_Rows);
        !           251:     bm->Flags = get_byte (amigamemptr + PSSO_BitMap_Flags);
        !           252:     bm->Depth = get_byte (amigamemptr + PSSO_BitMap_Depth);
        !           253: 
        !           254:     for (i = 0; i < bm->Depth; i++) {
        !           255:        uaecptr plane = get_long (amigamemptr + PSSO_BitMap_Planes + i*4);
        !           256:        switch (plane) {
        !           257:         case 0:
        !           258:            bm->Planes[i] = &all_zeros_bitmap;
        !           259:            break;
        !           260:         case 0xFFFFFFFF:
        !           261:            bm->Planes[i] = &all_ones_bitmap;
        !           262:            break;
        !           263:         default:
        !           264:            if (valid_address (plane, bm->BytesPerRow * bm->Rows))
        !           265:                bm->Planes[i] = get_real_address (plane);
        !           266:            else
        !           267:                return 0;
        !           268:            break;
        !           269:        }
        !           270:     }
        !           271:     return 1;
        !           272: }
        !           273: 
        !           274: static int CopyTemplateStructureA2U (uaecptr amigamemptr, struct Template *tmpl)
        !           275: {
        !           276:     uaecptr memp = get_long (amigamemptr + PSSO_Template_Memory);
        !           277: 
        !           278:     if (valid_address (memp, 1 /* FIXME */)) {
        !           279:        tmpl->Memory = get_real_address (memp);
        !           280:        tmpl->BytesPerRow = get_word (amigamemptr + PSSO_Template_BytesPerRow);
        !           281:        tmpl->XOffset = get_byte (amigamemptr + PSSO_Template_XOffset);
        !           282:        tmpl->DrawMode = get_byte (amigamemptr + PSSO_Template_DrawMode);
        !           283:        tmpl->FgPen = get_long (amigamemptr + PSSO_Template_FgPen);
        !           284:        tmpl->BgPen = get_long (amigamemptr + PSSO_Template_BgPen);
        !           285:        return 1;
        !           286:     }
        !           287:     MyOutputDebugString ("ERROR - Invalid Template memory area...\n");
        !           288:     return 0;
        !           289: }
        !           290: 
        !           291: static void CopyLibResolutionStructureU2A (struct LibResolution *libres, uaecptr amigamemptr)
        !           292: {
        !           293:     char *uaememptr = 0;
        !           294:     int i;
        !           295: 
        !           296:     uaememptr = gfxmem_xlate(amigamemptr); /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
        !           297:     memset(uaememptr, 0, PSSO_LibResolution_sizeof); /* zero out our LibResolution structure */
        !           298:     strcpy(uaememptr + PSSO_LibResolution_P96ID, libres->P96ID);
        !           299:     put_long(amigamemptr + PSSO_LibResolution_DisplayID, libres->DisplayID);
        !           300:     put_word(amigamemptr + PSSO_LibResolution_Width, libres->Width);
        !           301:     put_word(amigamemptr + PSSO_LibResolution_Height, libres->Height);
        !           302:     put_word(amigamemptr + PSSO_LibResolution_Flags, libres->Flags);
        !           303:     for (i = 0; i < MAXMODES; i++)
        !           304:        put_long(amigamemptr + PSSO_LibResolution_Modes + i*4, libres->Modes[i]);
        !           305: #if 0
        !           306:     put_long(amigamemptr, libres->Node.ln_Succ);
        !           307:     put_long(amigamemptr + 4, libres->Node.ln_Pred);
        !           308:     put_byte(amigamemptr + 8, libres->Node.ln_Type);
        !           309:     put_byte(amigamemptr + 9, libres->Node.ln_Pri);
        !           310: #endif
        !           311:     put_long(amigamemptr + 10, amigamemptr + PSSO_LibResolution_P96ID);
        !           312:     put_long(amigamemptr + PSSO_LibResolution_BoardInfo, libres->BoardInfo);
        !           313: }
        !           314: 
        !           315: /* list is Amiga address of list, in correct endian format for UAE
        !           316:  * node is Amiga address of node, in correct endian format for UAE */
        !           317: static void AmigaListAddTail (uaecptr list, uaecptr node)
        !           318: {
        !           319:     uaecptr amigamemptr = 0;
        !           320: 
        !           321:     if (get_long (list + 8) == list) {
        !           322:        /* Empty list - set it up */
        !           323:        put_long(list, node);     /* point the lh_Head to our new node */
        !           324:        put_long(list + 4, 0);    /* set the lh_Tail to NULL */
        !           325:        put_long(list + 8, node); /* point the lh_TailPred to our new node */
        !           326: 
        !           327:        /* Adjust the new node - don't rely on it being zeroed out */
        !           328:        put_long(node, 0); /* ln_Succ */
        !           329:        put_long(node + 4, 0); /* ln_Pred */
        !           330:     } else {
        !           331:        amigamemptr = get_long (list + 8); /* get the lh_TailPred contents */
        !           332: 
        !           333:        put_long(list + 8, node); /* point the lh_TailPred to our new node */
        !           334: 
        !           335:        /* Adjust the previous lh_TailPred node */
        !           336:        put_long(amigamemptr, node); /* point the ln_Succ to our new node */
        !           337: 
        !           338:        /* Adjust the new node - don't rely on it being zeroed out */
        !           339:        put_long(node, 0); /* ln_Succ */
        !           340:        put_long(node + 4, amigamemptr); /* ln_Pred */
        !           341:     }
        !           342: }
        !           343: 
        !           344: /*
        !           345:  * Functions to perform an action on the real screen
        !           346:  */
        !           347: 
        !           348: /*
        !           349:  * Fill a rectangle on the screen.  src points to the start of a line of the
        !           350:  * filled rectangle in the frame buffer; it can be used as a memcpy source if
        !           351:  * there is no OS specific function to fill the rectangle.
        !           352:  */
        !           353: 
        !           354: static void do_fillrect (uae_u8 *src, int x, int y, int width, int height)
        !           355: {
        !           356:     int lines;
        !           357:     uae_u8 *dst;
        !           358:     /* Try OS specific fillrect function here; and return if successful.  */
        !           359: 
        !           360:     DX_Invalidate (y, y + height - 1);
        !           361:     if (! picasso_vidinfo.extra_mem)
        !           362:        return;
        !           363: 
        !           364:     width *= picasso96_state.BytesPerPixel;
        !           365:     dst = lockscr ();
        !           366:     if (!dst)
        !           367:        return;
        !           368: 
        !           369:     dst += y*picasso_vidinfo.rowbytes + x*picasso96_state.BytesPerPixel;
        !           370:     while (height-- > 0) {
        !           371:        memcpy (dst, src, width);
        !           372:        dst += picasso_vidinfo.rowbytes;
        !           373:     }
        !           374:     unlockscr ();
        !           375: }
        !           376: 
        !           377: /*
        !           378:  * This routine modifies the real screen buffer after a blit has been
        !           379:  * performed in the save area. If can_do_blit is nonzero, the blit can
        !           380:  * be performed within the real screen buffer; otherwise, this routine
        !           381:  * must do it by hand using the data in the save area, pointed to by
        !           382:  * srcp.
        !           383:  */
        !           384: 
        !           385: static void do_blit (uae_u8 *srcp, unsigned long src_rowbytes,
        !           386:                     int srcx, int srcy, int dstx, int dsty,
        !           387:                     int width, int height, int can_do_blit)
        !           388: {
        !           389:     uae_u8 *dstp;
        !           390:     /* If this RenderInfo points at something else than the currently visible
        !           391:      * screen, we must ignore the blit.  */
        !           392:     if (can_do_blit) {
        !           393:        /*
        !           394:         * Call OS blitting function that can do it in video memory.
        !           395:         * Should return if it was successful
        !           396:         */
        !           397:     }
        !           398: 
        !           399:     DX_Invalidate (dsty, dsty + height - 1);
        !           400:     if (! picasso_vidinfo.extra_mem)
        !           401:        return;
        !           402: 
        !           403:     width *= picasso96_state.BytesPerPixel;
        !           404:     dstp = lockscr ();
        !           405:     if (dstp == 0)
        !           406:        return;
        !           407: 
        !           408:     /* The areas can't overlap: the source is always in the Picasso frame buffer,
        !           409:      * and the destination is a different buffer owned by the graphics code.  */
        !           410: 
        !           411:     dstp += dsty * picasso_vidinfo.rowbytes + dstx * picasso96_state.BytesPerPixel;
        !           412:     while (height-- > 0) {
        !           413:        memcpy (dstp, srcp, width);
        !           414:        srcp += src_rowbytes;
        !           415:        dstp += picasso_vidinfo.rowbytes;
        !           416:     }
        !           417:     unlockscr ();
        !           418: }
        !           419: 
        !           420: /*
        !           421:  * Invert a rectangle on the screen.  src and src_rowbytes describe the
        !           422:  * inverted rectangle in the frame buffer, so that do_blit can be used if
        !           423:  * there is no OS specific function to fill the rectangle.
        !           424:  */
        !           425: 
        !           426: static void do_invertrect (uae_u8 *src, unsigned long src_rowbytes,
        !           427:                           int x, int y, int width, int height)
        !           428: {
        !           429:     /* Try OS specific invertrect function here; and return if successful.  */
        !           430: 
        !           431:     do_blit (src, src_rowbytes, 0, 0, x, y, width, height, 0);
        !           432: }
        !           433: 
        !           434: static uaecptr wgfx_linestart;
        !           435: static uaecptr wgfx_lineend;
        !           436: static uaecptr wgfx_min, wgfx_max;
        !           437: static unsigned long wgfx_y;
        !           438: 
        !           439: static void wgfx_do_flushline (void)
        !           440: {
        !           441:     uae_u8 *src, *dstp;
        !           442: 
        !           443:     DX_Invalidate (wgfx_y, wgfx_y);
        !           444:     if (! picasso_vidinfo.extra_mem)
        !           445:        goto out;
        !           446: 
        !           447:     dstp = lockscr ();
        !           448:     if (dstp == 0)
        !           449:        goto out;
        !           450:     /*printf("flushing %d (%x %x %x)\n", wgfx_y, wgfx_linestart, wgfx_min, wgfx_max); */
        !           451:     src = (gfxmemory + wgfx_min);
        !           452: 
        !           453:     dstp += wgfx_y * picasso_vidinfo.rowbytes + wgfx_min - wgfx_linestart;
        !           454:     memcpy (dstp, src, wgfx_max - wgfx_min);
        !           455:     unlockscr ();
        !           456: 
        !           457:     out:
        !           458:     wgfx_linestart = 0xFFFFFFFF;
        !           459: }
        !           460: 
        !           461: static __inline__ void wgfx_flushline (void)
        !           462: {
        !           463:     if (wgfx_linestart == 0xFFFFFFFF)
        !           464:        return;
        !           465:     wgfx_do_flushline ();
        !           466: }
        !           467: 
        !           468: 
        !           469: static int renderinfo_is_current_screen (struct RenderInfo *ri)
        !           470: {
        !           471:     if (! picasso_on)
        !           472:        return 0;
        !           473:     if (ri->Memory != gfxmemory + (picasso96_state.Address - gfxmem_start)) {
        !           474:        return 0;
        !           475:     }
        !           476:     return 1;
        !           477: }
        !           478: 
        !           479: /* Clear our screen, since we've got a new Picasso screen-mode, and refresh with the proper contents
        !           480:  * NOTE: This is called in two cases:
        !           481:  *       1. Amiga-->Picasso transition, via SetSwitch()
        !           482:  *       2. Picasso-->Picasso transition, via SetPanning().  */
        !           483: static void picasso_refresh (void)
        !           484: {
        !           485:     struct RenderInfo ri;
        !           486: 
        !           487:     if (! picasso_on)
        !           488:        return;
        !           489: 
        !           490:     /* Make sure that the first time we show a Picasso video mode, we don't blit any crap.
        !           491:      * We can do this by checking if we have an Address yet.  */
        !           492:     if (picasso96_state.Address) {
        !           493:        /* blit the stuff from our static frame-buffer to the gfx-card */
        !           494:        uae_u8 *ptr = gfxmemory + (picasso96_state.Address - gfxmem_start);
        !           495:        ri.BytesPerRow = picasso96_state.BytesPerRow;
        !           496:        ri.RGBFormat = picasso96_state.RGBFormat;
        !           497:        do_blit (ptr, picasso96_state.BytesPerRow, 0, 0, 0, 0,
        !           498:                 picasso96_state.Width, picasso96_state.Height, 0);
        !           499:        MyOutputDebugString ("picasso_refresh() successful.\n");
        !           500:     } else
        !           501:        MyOutputDebugString ("ERROR - picasso_refresh() can't refresh!\n");
        !           502: }
        !           503: 
        !           504: /*
        !           505:  * BOOL FindCard(struct BoardInfo *bi);       and
        !           506:  *
        !           507:  * FindCard is called in the first stage of the board initialisation and
        !           508:  * configuration and is used to look if there is a free and unconfigured
        !           509:  * board of the type the driver is capable of managing. If it finds one,
        !           510:  * it immediately reserves it for use by Picasso96, usually by clearing
        !           511:  * the CDB_CONFIGME bit in the flags field of the ConfigDev struct of
        !           512:  * this expansion card. But this is only a common example, a driver can
        !           513:  * do whatever it wants to mark this card as used by the driver. This
        !           514:  * mechanism is intended to ensure that a board is only configured and
        !           515:  * used by one driver. FindBoard also usually fills some fields of the
        !           516:  * BoardInfo struct supplied by the caller, the rtg.library, for example
        !           517:  * the MemoryBase, MemorySize and RegisterBase fields.
        !           518:  */
        !           519: uae_u32 picasso_FindCard (void)
        !           520: {
        !           521:     int loop;
        !           522:     uaecptr AmigaBoardInfo = m68k_areg(regs, 0);
        !           523:     /* NOTES: See BoardInfo struct definition in Picasso96 dev info */
        !           524: 
        !           525:     if (gfxmem_size && !picasso96_state.CardFound) {
        !           526:        /* Fill in MemoryBase, MemorySize */
        !           527:        put_long(AmigaBoardInfo + PSSO_BoardInfo_MemoryBase, gfxmem_start);
        !           528:        /* size of memory, minus a 32K chunk: 16K for pattern bitmaps, 16K for resolution list */
        !           529:        put_long(AmigaBoardInfo + PSSO_BoardInfo_MemorySize, gfxmem_size - 32768);
        !           530: 
        !           531:        picasso96_state.CardFound = 1; /* mark our "card" as being found */
        !           532:        return -1;
        !           533:     } else
        !           534:        return 0;
        !           535: }
        !           536: 
        !           537: static void FillBoardInfo (uaecptr amigamemptr, struct LibResolution *res, struct PicassoResolution *dm)
        !           538: {
        !           539:     char *uaememptr;
        !           540:     switch (dm->depth) {
        !           541:     case 1:
        !           542:        res->Modes[CHUNKY] = amigamemptr;
        !           543:        break;
        !           544:     case 2:
        !           545:        res->Modes[HICOLOR] = amigamemptr;
        !           546:        break;
        !           547:     case 3:
        !           548:        res->Modes[TRUECOLOR] = amigamemptr;
        !           549:        break;
        !           550:     default:
        !           551:        res->Modes[TRUEALPHA] = amigamemptr;
        !           552:        break;
        !           553:     }
        !           554:     uaememptr = gfxmem_xlate(amigamemptr); /* I know that amigamemptr is inside my gfxmem chunk, so I can just do the xlate() */
        !           555:     memset(uaememptr, 0, PSSO_ModeInfo_sizeof); /* zero out our ModeInfo struct */
        !           556: 
        !           557:     put_word(amigamemptr + PSSO_ModeInfo_Width, dm->res.width);
        !           558:     put_word(amigamemptr + PSSO_ModeInfo_Height, dm->res.height);
        !           559:     put_byte(amigamemptr + PSSO_ModeInfo_Depth, dm->depth * 8);
        !           560:     put_byte(amigamemptr + PSSO_ModeInfo_Flags, 0);
        !           561:     put_word(amigamemptr + PSSO_ModeInfo_HorTotal, dm->res.width);
        !           562:     put_word(amigamemptr + PSSO_ModeInfo_HorBlankSize, 0);
        !           563:     put_word(amigamemptr + PSSO_ModeInfo_HorSyncStart, 0);
        !           564:     put_word(amigamemptr + PSSO_ModeInfo_HorSyncSize, 0);
        !           565:     put_byte(amigamemptr + PSSO_ModeInfo_HorSyncSkew, 0);
        !           566:     put_byte(amigamemptr + PSSO_ModeInfo_HorEnableSkew, 0);
        !           567: 
        !           568:     put_word(amigamemptr + PSSO_ModeInfo_VerTotal, dm->res.height);
        !           569:     put_word(amigamemptr + PSSO_ModeInfo_VerBlankSize, 0);
        !           570:     put_word(amigamemptr + PSSO_ModeInfo_VerSyncStart, 0);
        !           571:     put_word(amigamemptr + PSSO_ModeInfo_VerSyncSize, 0);
        !           572: 
        !           573:     put_byte(amigamemptr + PSSO_ModeInfo_first_union, 98);
        !           574:     put_byte(amigamemptr + PSSO_ModeInfo_second_union, 14);
        !           575: 
        !           576:     put_long(amigamemptr + PSSO_ModeInfo_PixelClock, dm->res.width * dm->res.height * dm->refresh);
        !           577: }
        !           578: 
        !           579: /****************************************
        !           580: * InitCard()
        !           581: *
        !           582: * a2: BoardInfo structure ptr - Amiga-based address in Intel endian-format
        !           583: *
        !           584: * Job - fill in the following structure members:
        !           585: * gbi_RGBFormats: the pixel formats that the host-OS of UAE supports
        !           586: *     If UAE is running in a window, it should ONLY report the pixel format of the host-OS desktop
        !           587: *     If UAE is running full-screen, it should report ALL pixel formats that the host-OS can handle in full-screen
        !           588: *     NOTE: If full-screen, and the user toggles to windowed-mode, all hell will break loose visually.  Must inform
        !           589: *           user that they're doing something stupid (unless their desktop and full-screen colour modes match).
        !           590: * gbi_SoftSpriteFlags: should be the same as above for now, until actual cursor support is added
        !           591: * gbi_BitsPerCannon: could be 6 or 8 or ???, depending on the host-OS gfx-card
        !           592: * gbi_MaxHorResolution: fill this in for all modes (even if you don't support them)
        !           593: * gbi_MaxVerResolution: fill this in for all modes (even if you don't support them)
        !           594: */
        !           595: uae_u32 picasso_InitCard (void)
        !           596: {
        !           597:     struct LibResolution res;
        !           598:     int i;
        !           599:     int ModeInfoStructureCount = 1, LibResolutionStructureCount = 0;
        !           600:     uaecptr amigamemptr = 0;
        !           601:     uaecptr AmigaBoardInfo = m68k_areg(regs, 2);
        !           602:     put_word(AmigaBoardInfo + PSSO_BoardInfo_BitsPerCannon, DX_BitsPerCannon());
        !           603:     put_word(AmigaBoardInfo + PSSO_BoardInfo_RGBFormats, picasso96_pixel_format);
        !           604:     put_word(AmigaBoardInfo + PSSO_BoardInfo_SoftSpriteFlags, picasso96_pixel_format);
        !           605:     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 0, planar.width);
        !           606:     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 2, chunky.width);
        !           607:     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 4, hicolour.width);
        !           608:     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 6, truecolour.width);
        !           609:     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxHorResolution + 8, alphacolour.width);
        !           610:     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 0, planar.height);
        !           611:     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 2, chunky.height);
        !           612:     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 4, hicolour.height);
        !           613:     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 6, truecolour.height);
        !           614:     put_word(AmigaBoardInfo + PSSO_BoardInfo_MaxVerResolution + 8, alphacolour.height);
        !           615: 
        !           616:     for (i = 0; i < mode_count;) {
        !           617:        int j = i;
        !           618:        /* Add a LibResolution structure to the ResolutionsList MinList in our BoardInfo */
        !           619:        res.DisplayID = 0x50001000 + LibResolutionStructureCount * 0x10000;
        !           620:        res.BoardInfo = AmigaBoardInfo;
        !           621:        res.Width = DisplayModes[i].res.width;
        !           622:        res.Height = DisplayModes[i].res.height;
        !           623:        res.Flags = P96F_PUBLIC;
        !           624:        res.P96ID[0] = 'P';
        !           625:        res.P96ID[1] = '9';
        !           626:        res.P96ID[2] = '6';
        !           627:        res.P96ID[3] = '-';
        !           628:        res.P96ID[4] = '0';
        !           629:        res.P96ID[5] = ':';
        !           630:        strcpy (res.Name, "uaegfx:");
        !           631:        strncat (res.Name, DisplayModes[i].name, strchr(DisplayModes[i].name, ',') - DisplayModes[i].name);
        !           632:        res.Modes[PLANAR] = 0;
        !           633:        res.Modes[CHUNKY] = 0;
        !           634:        res.Modes[HICOLOR] = 0;
        !           635:        res.Modes[TRUECOLOR] = 0;
        !           636:        res.Modes[TRUEALPHA] = 0;
        !           637: 
        !           638:        do {
        !           639:            /* Handle this display mode's depth */
        !           640:            amigamemptr = gfxmem_start + gfxmem_size - (PSSO_ModeInfo_sizeof * ModeInfoStructureCount++);
        !           641:            FillBoardInfo(amigamemptr, &res, &DisplayModes[i]);
        !           642:            i++;
        !           643:        } while (i < mode_count
        !           644:                 && DisplayModes[i].res.width == DisplayModes[j].res.width
        !           645:                 && DisplayModes[i].res.height == DisplayModes[j].res.height);
        !           646: 
        !           647:        amigamemptr = gfxmem_start + gfxmem_size - 16384 + (PSSO_LibResolution_sizeof * LibResolutionStructureCount++);
        !           648:        CopyLibResolutionStructureU2A (&res, amigamemptr);
        !           649:        DumpLibResolutionStructure( amigamemptr);
        !           650:        AmigaListAddTail (AmigaBoardInfo + PSSO_BoardInfo_ResolutionsList, amigamemptr);
        !           651:     }
        !           652: 
        !           653:     return 0;
        !           654: }
        !           655: 
        !           656: extern int x_size, y_size;
        !           657: 
        !           658: /*
        !           659:  * SetSwitch:
        !           660:  * a0: struct BoardInfo
        !           661:  * d0.w:       BOOL state
        !           662:  * this function should set a board switch to let the Amiga signal pass
        !           663:  * through when supplied with a 0 in d0 and to show the board signal if
        !           664:  * a 1 is passed in d0. You should remember the current state of the
        !           665:  * switch to avoid unneeded switching. If your board has no switch, then
        !           666:  * simply supply a function that does nothing except a RTS.
        !           667:  *
        !           668:  * NOTE: Return the opposite of the switch-state. BDK
        !           669: */
        !           670: uae_u32 picasso_SetSwitch (void)
        !           671: {
        !           672:     uae_u16 flag = m68k_dreg(regs, 0) & 0xFFFF;
        !           673:     uae_u32 result;
        !           674: 
        !           675:     /* Do not switch immediately.  Tell the custom chip emulation about the
        !           676:      * desired state, and wait for custom.c to call picasso_enablescreen
        !           677:      * whenever it is ready to change the screen state.  */
        !           678:     picasso_requested_on = !!flag;
        !           679:     MyOutputDebugString ("SetSwitch() - trying to show %s screen\n", flag ? "picasso96":"amiga");
        !           680: 
        !           681:     /* Put old switch-state in D0 */
        !           682:     return !flag;
        !           683: }
        !           684: 
        !           685: void picasso_enablescreen (int on)
        !           686: {
        !           687:     wgfx_linestart = 0xFFFFFFFF;
        !           688:     picasso_refresh ();
        !           689:     MyOutputDebugString ("SetSwitch() - showing %s screen\n", on ? "picasso96":"amiga");
        !           690: }
        !           691: 
        !           692: /*
        !           693:  * SetColorArray:
        !           694:  * a0: struct BoardInfo
        !           695:  * d0.w: startindex
        !           696:  * d1.w: count
        !           697:  * when this function is called, your driver has to fetch "count" color
        !           698:  * values starting at "startindex" from the CLUT field of the BoardInfo
        !           699:  * structure and write them to the hardware. The color values are always
        !           700:  * between 0 and 255 for each component regardless of the number of bits
        !           701:  * per cannon your board has. So you might have to shift the colors
        !           702:  * before writing them to the hardware.
        !           703:  */
        !           704: uae_u32 picasso_SetColorArray (void)
        !           705: {
        !           706:     /* Fill in some static UAE related structure about this new CLUT setting
        !           707:      * We need this for CLUT-based displays, and for mapping CLUT to hi/true colour */
        !           708:     uae_u16 start = m68k_dreg(regs, 0);
        !           709:     uae_u16 count = m68k_dreg(regs, 1);
        !           710:     int i;
        !           711:     uaecptr boardinfo = m68k_areg(regs, 0);
        !           712:     uaecptr clut = boardinfo + PSSO_BoardInfo_CLUT + start * 3;
        !           713: 
        !           714:     for (i = start; i < start + count; i++) {
        !           715:        picasso96_state.CLUT[i].Red = get_byte (clut);
        !           716:        picasso96_state.CLUT[i].Green = get_byte (clut + 1);
        !           717:        picasso96_state.CLUT[i].Blue = get_byte (clut + 2);
        !           718:        clut += 3;
        !           719:     }
        !           720:     DX_SetPalette(start, count);
        !           721:     /*MyOutputDebugString ("SetColorArray(%d,%d)\n", start, count); */
        !           722:     return m68k_dreg(regs, 0);
        !           723: }
        !           724: 
        !           725: static uae_u8 GetBytesPerPixel(uae_u32 RGBfmt)
        !           726: {
        !           727:     switch (RGBfmt) {
        !           728:      case RGBFB_CLUT:
        !           729:        return 1;
        !           730: 
        !           731:      case RGBFB_A8R8G8B8:
        !           732:      case RGBFB_A8B8G8R8:
        !           733:      case RGBFB_R8G8B8A8:
        !           734:      case RGBFB_B8G8R8A8:
        !           735:        return 4;
        !           736: 
        !           737:      case RGBFB_B8G8R8:
        !           738:      case RGBFB_R8G8B8:
        !           739:        return 3;
        !           740: 
        !           741:      case RGBFB_R5G5B5:
        !           742:      case RGBFB_R5G6B5:
        !           743:      case RGBFB_R5G6B5PC:
        !           744:      case RGBFB_R5G5B5PC:
        !           745:      case RGBFB_B5G6R5PC:
        !           746:      case RGBFB_B5G5R5PC:
        !           747:        return 2;
        !           748:      default:
        !           749:        MyOutputDebugString ("ERROR - GetBytesPerPixel() was unsuccessful with 0x%x?!\n", RGBfmt);
        !           750:        return 0;
        !           751:     }
        !           752: }
        !           753: 
        !           754: /*
        !           755:  * SetDAC:
        !           756:  * a0: struct BoardInfo
        !           757:  * d7: RGBFTYPE RGBFormat
        !           758:  * This function is called whenever the RGB format of the display changes,
        !           759:  * e.g. from chunky to TrueColor. Usually, all you have to do is to set
        !           760:  * the RAMDAC of your board accordingly.
        !           761:  */
        !           762: uae_u32 picasso_SetDAC (void)
        !           763: {
        !           764:     /* Fill in some static UAE related structure about this new DAC setting
        !           765:      * Lets us keep track of what pixel format the Amiga is thinking about in our frame-buffer */
        !           766: 
        !           767:     MyOutputDebugString ("SetDAC()\n");
        !           768:     return m68k_dreg(regs, 0);
        !           769: }
        !           770: 
        !           771: /*
        !           772:  * SetGC:
        !           773:  * a0: struct BoardInfo
        !           774:  * a1: struct ModeInfo
        !           775:  * d0: BOOL Border
        !           776:  * This function is called whenever another ModeInfo has to be set. This
        !           777:  * function simply sets up the CRTC and TS registers to generate the
        !           778:  * timing used for that screen mode. You should not set the DAC, clocks
        !           779:  * or linear start adress. They will be set when appropriate by their
        !           780:  * own functions.
        !           781:  */
        !           782: uae_u32 picasso_SetGC (void)
        !           783: {
        !           784:     /* Fill in some static UAE related structure about this new ModeInfo setting */
        !           785:     uaecptr modeinfo = m68k_areg(regs, 1);
        !           786: 
        !           787:     picasso96_state.Width = get_word (modeinfo + PSSO_ModeInfo_Width);
        !           788:     picasso96_state.VirtualWidth = picasso96_state.Width; /* in case SetPanning doesn't get called */
        !           789: 
        !           790:     picasso96_state.Height = get_word (modeinfo + PSSO_ModeInfo_Height);
        !           791:     picasso96_state.VirtualHeight = picasso96_state.Height;
        !           792: 
        !           793:     picasso96_state.GC_Depth = get_byte (modeinfo + PSSO_ModeInfo_Depth);
        !           794:     picasso96_state.GC_Flags = get_byte (modeinfo + PSSO_ModeInfo_Flags);
        !           795: 
        !           796:     MyOutputDebugString ("SetGC(%d,%d,%d)\n", picasso96_state.Width, picasso96_state.Height, picasso96_state.GC_Depth);
        !           797: 
        !           798:     gfx_set_picasso_modeinfo (picasso96_state.Width, picasso96_state.Height,
        !           799:                              picasso96_state.GC_Depth);
        !           800:     wgfx_linestart = 0xFFFFFFFF;
        !           801:     picasso_refresh ();
        !           802: 
        !           803:     return m68k_dreg(regs, 0);
        !           804: }
        !           805: 
        !           806: /*
        !           807:  * SetPanning:
        !           808:  * a0: struct BoardInfo
        !           809:  * a1: UBYTE *Memory
        !           810:  * d0: uae_u16 Width
        !           811:  * d1: WORD XOffset
        !           812:  * d2: WORD YOffset
        !           813:  * d7: RGBFTYPE RGBFormat
        !           814:  * This function sets the view origin of a display which might also be
        !           815:  * overscanned. In register a1 you get the start address of the screen
        !           816:  * bitmap on the Amiga side. You will have to subtract the starting
        !           817:  * address of the board memory from that value to get the memory start
        !           818:  * offset within the board. Then you get the offset in pixels of the
        !           819:  * left upper edge of the visible part of an overscanned display. From
        !           820:  * these values you will have to calculate the LinearStartingAddress
        !           821:  * fields of the CRTC registers.
        !           822: 
        !           823:  * NOTE: SetPanning() can be used to know when a Picasso96 screen is
        !           824:  * being opened.  Better to do the appropriate clearing of the
        !           825:  * background here than in SetSwitch() derived functions,
        !           826:  * because SetSwitch() is not called for subsequent Picasso screens.
        !           827:  */
        !           828: uae_u32 picasso_SetPanning (void)
        !           829: {
        !           830:     uae_u16 Width = m68k_dreg(regs, 0);
        !           831:     uaecptr start_of_screen = m68k_areg(regs, 1);
        !           832: 
        !           833:     picasso96_state.Address = start_of_screen; /* Amiga-side address */
        !           834:     picasso96_state.XOffset = (uae_s16)m68k_dreg(regs, 1);
        !           835:     picasso96_state.YOffset = (uae_s16)m68k_dreg(regs, 2);
        !           836:     picasso96_state.VirtualWidth = Width;
        !           837:     picasso96_state.RGBFormat = m68k_dreg(regs, 7);
        !           838:     picasso96_state.BytesPerPixel = GetBytesPerPixel(picasso96_state.RGBFormat);
        !           839:     picasso96_state.BytesPerRow = Width * picasso96_state.BytesPerPixel;
        !           840: 
        !           841:     /* I assume SetGC() has been called, so I can calculate the Extent */
        !           842:     picasso96_state.Extent = picasso96_state.Address + (picasso96_state.BytesPerRow * picasso96_state.Height);
        !           843: 
        !           844:     MyOutputDebugString ("SetPanning(%d, %d, %d) Start 0x%x, BPR %d\n",
        !           845:                        Width,picasso96_state.XOffset, picasso96_state.YOffset,
        !           846:                        start_of_screen, picasso96_state.BytesPerRow);
        !           847:     DX_SetPalette(0, 256);
        !           848: 
        !           849:     wgfx_linestart = 0xFFFFFFFF;
        !           850:     picasso_refresh ();
        !           851: 
        !           852:     return m68k_dreg(regs, 0);
        !           853: }
        !           854: 
        !           855: static void do_xor8 (uae_u8 *ptr, long len, uae_u32 val)
        !           856: {
        !           857:     int i;
        !           858: #if 0 && defined ALIGN_POINTER_TO32
        !           859:     int align_adjust = ALIGN_POINTER_TO32(ptr);
        !           860:     int len2;
        !           861: 
        !           862:     len -= align_adjust;
        !           863:     while (align_adjust) {
        !           864:        *ptr ^= val;
        !           865:        ptr++;
        !           866:        align_adjust--;
        !           867:     }
        !           868:     len2 = len >> 2;
        !           869:     len -= len2 << 2;
        !           870:     for (i = 0; i < len2; i++, ptr += 4) {
        !           871:        *(uae_u32 *)ptr ^= val;
        !           872:     }
        !           873:     while (len) {
        !           874:        *ptr ^= val;
        !           875:        ptr++;
        !           876:        len--;
        !           877:     }
        !           878:     return;
        !           879: #endif
        !           880:     for (i = 0; i < len; i++, ptr++) {
        !           881:        do_put_mem_byte (ptr, do_get_mem_byte (ptr) ^ val);
        !           882:     }
        !           883: }
        !           884: 
        !           885: /*
        !           886:  * InvertRect:
        !           887:  * 
        !           888:  * Inputs:
        !           889:  * a0:struct BoardInfo *bi
        !           890:  * a1:struct RenderInfo *ri
        !           891:  * d0.w:X
        !           892:  * d1.w:Y
        !           893:  * d2.w:Width
        !           894:  * d3.w:Height
        !           895:  * d4.l:Mask
        !           896:  * d7.l:RGBFormat
        !           897:  * 
        !           898:  * This function is used to invert a rectangular area on the board. It is called by BltBitMap,
        !           899:  * BltPattern and BltTemplate.
        !           900:  */
        !           901: uae_u32 picasso_InvertRect (void)
        !           902: {
        !           903:     uaecptr boardinfo = m68k_areg(regs, 0);
        !           904:     uaecptr renderinfo = m68k_areg(regs, 1);
        !           905:     long X = (uae_u16)m68k_dreg(regs, 0);
        !           906:     long Y = (uae_u16)m68k_dreg(regs, 1);
        !           907:     long Width = (uae_u16)m68k_dreg(regs, 2);
        !           908:     long Height = (uae_u16)m68k_dreg(regs, 3);
        !           909:     uae_u32 mask = m68k_dreg(regs, 4);
        !           910:     int Bpp = GetBytesPerPixel (m68k_dreg(regs, 7));
        !           911:     uae_u32 xorval;
        !           912:     int lines;
        !           913:     struct RenderInfo ri;
        !           914:     uae_u8 *uae_mem, *rectstart;
        !           915:     long width_in_bytes;
        !           916: 
        !           917:     wgfx_flushline ();
        !           918: 
        !           919:     if (!CopyRenderInfoStructureA2U (renderinfo, &ri))
        !           920:        return 0;
        !           921: 
        !           922:     /*MyOutputDebugString ("InvertRect %d %lx\n", Bpp, (long)mask);*/
        !           923: 
        !           924:     /* ??? Brian? mask used to be 32 bit, but it appears that only 8 bit
        !           925:      * values are passed to this function.  This code here seems to work
        !           926:      * much better... */
        !           927:     if (mask != 0xFF && Bpp > 8) {
        !           928:        MyOutputDebugString ("InvertRect: not obeying mask 0x%x properly with Bpp %d.\n", mask, Bpp);
        !           929:        mask = 0xFF;
        !           930:     }
        !           931:     if ((mask & ~0xFF) != 0) {
        !           932:        MyOutputDebugString ("InvertRect: mask has high bits set!\n");
        !           933:     }
        !           934:     xorval = 0x01010101 * (mask & 0xFF);
        !           935:     width_in_bytes = Bpp * Width;
        !           936:     rectstart = uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
        !           937: 
        !           938:     for (lines = 0; lines < Height; lines++, uae_mem += ri.BytesPerRow) {
        !           939:        int j;
        !           940:        uae_u8 *start = uae_mem;
        !           941:        do_xor8 (uae_mem, width_in_bytes, xorval);
        !           942:     }
        !           943:     if (renderinfo_is_current_screen (&ri)) {
        !           944:        if (mask == 0xFF)
        !           945:            do_invertrect (rectstart, ri.BytesPerRow, X, Y, Width, Height);
        !           946:        else
        !           947:            do_blit (rectstart, ri.BytesPerRow, 0, 0, X, Y, Width, Height, 0);
        !           948:     }
        !           949: 
        !           950:     return 1; /* 1 if supported, 0 otherwise */
        !           951: }
        !           952: 
        !           953: /***********************************************************
        !           954: FillRect:
        !           955: ***********************************************************
        !           956: * a0:  struct BoardInfo *
        !           957: * a1:  struct RenderInfo *
        !           958: * d0:  WORD X
        !           959: * d1:  WORD Y
        !           960: * d2:  WORD Width
        !           961: * d3:  WORD Height
        !           962: * d4:  uae_u32 Pen
        !           963: * d5:  UBYTE Mask
        !           964: * d7:  uae_u32 RGBFormat
        !           965: ***********************************************************/
        !           966: uae_u32 picasso_FillRect (void)
        !           967: {
        !           968:     uaecptr boardinfo = m68k_areg(regs, 0);
        !           969:     uaecptr renderinfo = m68k_areg(regs, 1);
        !           970:     unsigned long X = (uae_u16)m68k_dreg(regs, 0);
        !           971:     unsigned long Y = (uae_u16)m68k_dreg(regs, 1);
        !           972:     unsigned long Width = (uae_u16)m68k_dreg(regs, 2);
        !           973:     unsigned long Height = (uae_u16)m68k_dreg(regs, 3);
        !           974:     uae_u32 Pen = m68k_dreg(regs, 4);
        !           975:     uae_u8 Mask = (uae_u8)m68k_dreg(regs, 5);
        !           976:     uae_u32 RGBFormat = m68k_dreg(regs, 7);
        !           977: 
        !           978:     uae_u8 *src, *dst;
        !           979:     uae_u8 *start, *oldstart;
        !           980:     struct RenderInfo local_ri;
        !           981:     unsigned long lines, cols;
        !           982:     int Bpp;
        !           983:     struct RenderInfo ri;
        !           984: 
        !           985:     wgfx_flushline ();
        !           986: 
        !           987:     if (! CopyRenderInfoStructureA2U(renderinfo, &ri) || Y == 0xFFFF)
        !           988:        return 0;
        !           989: 
        !           990:     if (ri.RGBFormat != RGBFormat)
        !           991:        MyOutputDebugString ("Weird Stuff!\n");
        !           992: 
        !           993:     Bpp = GetBytesPerPixel(RGBFormat);
        !           994: 
        !           995:     /*MyOutputDebugString ("FillRect(%d, %d, %d, %d) Pen 0x%x BPP %d BPR %d Mask 0x%x\n",
        !           996:                          X, Y, Width, Height, Pen, Bpp, ri.BytesPerRow, Mask); */
        !           997: 
        !           998:     if (Mask == 0xFF) {
        !           999:        /* Do our virtual frame-buffer memory.  First, we do a single line fill by hand */
        !          1000:        oldstart = start = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
        !          1001:        switch (Bpp) {
        !          1002:         case 1:
        !          1003:            memset (start, Pen, Width);
        !          1004:            break;
        !          1005:         case 2:
        !          1006:            for (cols = 0; cols < Width; cols++) {
        !          1007:                do_put_mem_word ((uae_u16 *)start, Pen);
        !          1008:                start += 2;
        !          1009:            }
        !          1010:            break;
        !          1011:         case 3:
        !          1012:            for (cols = 0; cols < Width; cols++) {
        !          1013:                do_put_mem_byte (start, Pen & 0x000000FF);
        !          1014:                start++;
        !          1015:                *(uae_u16 *)(start) = (Pen & 0x00FFFF00) >> 8;
        !          1016:                start+=2;
        !          1017:            }
        !          1018:            break;
        !          1019:         case 4:
        !          1020:            for (cols = 0; cols < Width; cols++) {
        !          1021:                /**start = Pen; */
        !          1022:                do_put_mem_long ((uae_u32 *)start, Pen);
        !          1023:                start += 4;
        !          1024:            }
        !          1025:            break;
        !          1026:        }
        !          1027:        src = oldstart;
        !          1028:        dst = src + ri.BytesPerRow;
        !          1029:        /* next, we do the remaining line fills via memcpy() */
        !          1030:        for (lines = 0; lines < (Height - 1); lines++, dst += ri.BytesPerRow)
        !          1031:            memcpy(dst, src, Width * Bpp);
        !          1032: 
        !          1033:        if (renderinfo_is_current_screen (&ri)) {
        !          1034:            do_fillrect (src, X, Y, Width, Height);
        !          1035:        }
        !          1036:        return 1;
        !          1037:     }
        !          1038: 
        !          1039:     /* We get here only if Mask != 0xFF */
        !          1040:     if (Bpp != 1) {
        !          1041:        write_log ("Picasso: mask != 0xFF in truecolor mode!\n");
        !          1042:        return 0;
        !          1043:     }
        !          1044:     Pen &= Mask;
        !          1045:     Mask = ~Mask;
        !          1046: 
        !          1047:     oldstart = start = ri.Memory + Y*ri.BytesPerRow + X*Bpp;
        !          1048:     for (lines = 0; lines < Height; lines++, start += ri.BytesPerRow) {
        !          1049:        uae_u8 *p = start;
        !          1050:        for (cols = 0; cols < Width; cols++) {
        !          1051:            uae_u32 tmpval = do_get_mem_byte (p) & Mask;
        !          1052:            do_put_mem_byte (p, Pen | tmpval);
        !          1053:            p++;
        !          1054:        }
        !          1055:     }
        !          1056:     if (renderinfo_is_current_screen (&ri))
        !          1057:        do_blit (oldstart, ri.BytesPerRow, 0, 0, X, Y, Width, Height, 0);
        !          1058: 
        !          1059:     return 1;
        !          1060: }
        !          1061: 
        !          1062: /*
        !          1063:  * BlitRect() is a generic (any chunky pixel format) rectangle copier
        !          1064:  * NOTE: If dstri is NULL, then we're only dealing with one RenderInfo area, and called from picasso_BlitRect()
        !          1065:  */
        !          1066: static void BlitRect (struct RenderInfo *ri, struct RenderInfo *dstri,
        !          1067:                      uae_u16 srcx, uae_u16 srcy, uae_u16 dstx, uae_u16 dsty,
        !          1068:                      uae_u16 width, uae_u16 height, uae_u8 mask)
        !          1069: {
        !          1070:     uae_u8 *src, *dst, *tmp, *tmp2, *tmp3;
        !          1071:     int lines;
        !          1072:     uae_u8 Bpp = GetBytesPerPixel(ri->RGBFormat);
        !          1073:     uae_u8 *blitsrc;
        !          1074:     unsigned long total_width = width * Bpp;
        !          1075:     unsigned long linewidth = (total_width + 15) & ~15;
        !          1076:     int cant_blit = 1;
        !          1077: 
        !          1078:     /*
        !          1079:      * If we have no destination RenderInfo, then we're dealing with a single-buffer action, called
        !          1080:      * from picasso_BlitRect().  The code up to the DX_xxxxx() functions deals with the frame-buffer,
        !          1081:      * while the DX_ functions actually deal with the visible screen.
        !          1082:      *
        !          1083:      * If we have a destination RenderInfo, then we've been called from picasso_BlitRectNoMaskComplete()
        !          1084:      * and we need to put the results on the screen from the frame-buffer.
        !          1085:      */
        !          1086:     if (dstri == NULL) {
        !          1087:        dstri = ri;
        !          1088:        cant_blit = 0;
        !          1089:     }
        !          1090: 
        !          1091:     /* Do our virtual frame-buffer memory first */
        !          1092:     src = ri->Memory + srcx*Bpp + srcy*ri->BytesPerRow;
        !          1093:     dst = dstri->Memory + dstx*Bpp + dsty*dstri->BytesPerRow;
        !          1094:     blitsrc = dst;
        !          1095:     if (mask != 0xFF && Bpp > 1)
        !          1096:        MyOutputDebugString ("ERROR - not obeying BlitRect() mask 0x%x properly with Bpp %d.\n", mask, Bpp);
        !          1097: 
        !          1098:     if (mask == 0xFF || Bpp > 1) {
        !          1099:        /* handle normal case efficiently */
        !          1100:        if (ri->Memory == dstri->Memory && dsty == srcy) {
        !          1101:            int i;
        !          1102:            for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
        !          1103:                memmove (dst, src, total_width);
        !          1104:        } else if (dsty < srcy) {
        !          1105:            int i;
        !          1106:            for (i = 0; i < height; i++, src += ri->BytesPerRow, dst += dstri->BytesPerRow)
        !          1107:                memcpy (dst, src, total_width);
        !          1108:        } else {
        !          1109:            int i;
        !          1110:            src += (height-1) * ri->BytesPerRow;
        !          1111:            dst += (height-1) * dstri->BytesPerRow;
        !          1112:            for (i = 0; i < height; i++, src -= ri->BytesPerRow, dst -= dstri->BytesPerRow)
        !          1113:                memcpy (dst, src, total_width);
        !          1114:        }
        !          1115:        if (renderinfo_is_current_screen (dstri))
        !          1116:            do_blit (blitsrc, dstri->BytesPerRow, srcx, srcy, dstx, dsty,
        !          1117:                     width, height, ! cant_blit);
        !          1118:        return;
        !          1119:     }
        !          1120: 
        !          1121:     tmp3 = tmp2 = tmp = xmalloc (linewidth * height); /* allocate enough memory for the src-rect */
        !          1122:     if (!tmp)
        !          1123:        return;
        !          1124: 
        !          1125:     /* copy the src-rect into our temporary buffer space */
        !          1126:     for (lines = 0; lines < height; lines++, src += ri->BytesPerRow, tmp2 += linewidth) {
        !          1127:        memcpy (tmp2, src, total_width);
        !          1128:     }
        !          1129: 
        !          1130:     /* copy the temporary buffer to the destination */
        !          1131:     for (lines = 0; lines < height; lines++, dst += dstri->BytesPerRow, tmp += linewidth) {
        !          1132:        int cols;
        !          1133:        for (cols = 0; cols < width; cols++) {
        !          1134:            dst[cols] &= ~mask;
        !          1135:            dst[cols] |= tmp[cols] & mask;
        !          1136:        }
        !          1137:     }
        !          1138:     if (renderinfo_is_current_screen (dstri))
        !          1139:        do_blit (blitsrc, dstri->BytesPerRow, srcx, srcy, dstx, dsty,
        !          1140:                 width, height, 0);
        !          1141:     /* free the temp-buf */
        !          1142:     free (tmp3);
        !          1143: 
        !          1144: }
        !          1145: 
        !          1146: /***********************************************************
        !          1147: BlitRect:
        !          1148: ***********************************************************
        !          1149: * a0:  struct BoardInfo
        !          1150: * a1:  struct RenderInfo
        !          1151: * d0:  WORD SrcX
        !          1152: * d1:  WORD SrcY
        !          1153: * d2:  WORD DstX
        !          1154: * d3:  WORD DstY
        !          1155: * d4:   WORD Width
        !          1156: * d5:   WORD Height
        !          1157: * d6:  UBYTE Mask
        !          1158: * d7:  uae_u32 RGBFormat
        !          1159: ***********************************************************/
        !          1160: uae_u32 picasso_BlitRect (void)
        !          1161: {
        !          1162:     uaecptr boardinfo = m68k_areg(regs, 0);
        !          1163:     uaecptr renderinfo = m68k_areg(regs, 1);
        !          1164:     uae_u16 srcx = (uae_u16)m68k_dreg(regs, 0);
        !          1165:     uae_u16 srcy = (uae_u16)m68k_dreg(regs, 1);
        !          1166:     uae_u16 dstx = (uae_u16)m68k_dreg(regs, 2);
        !          1167:     uae_u16 dsty = (uae_u16)m68k_dreg(regs, 3);
        !          1168:     uae_u16 width = (uae_u16)m68k_dreg(regs, 4);
        !          1169:     uae_u16 height = (uae_u16)m68k_dreg(regs, 5);
        !          1170:     uae_u8  Mask = (uae_u8)m68k_dreg(regs, 6);
        !          1171:     uae_u32 RGBFormat = m68k_dreg(regs, 7);
        !          1172: 
        !          1173:     struct RenderInfo ri;
        !          1174: 
        !          1175:     wgfx_flushline ();
        !          1176: 
        !          1177:     if (!CopyRenderInfoStructureA2U (renderinfo, &ri))
        !          1178:        return 0;
        !          1179: 
        !          1180:     BlitRect(&ri, NULL, srcx, srcy, dstx, dsty, width, height, Mask);
        !          1181:     /*MyOutputDebugString ("BlitRect(%d, %d, %d, %d, %d, %d, 0x%x)\n", srcx, srcy, dstx, dsty, width, height, Mask); */
        !          1182: 
        !          1183:     return 1;
        !          1184: }
        !          1185: 
        !          1186: /***********************************************************
        !          1187: BlitRectNoMaskComplete:
        !          1188: ***********************************************************
        !          1189: * a0:  struct BoardInfo
        !          1190: * a1:  struct RenderInfo (src)
        !          1191: * a2:   struct RenderInfo (dst)
        !          1192: * d0:  WORD SrcX
        !          1193: * d1:  WORD SrcY
        !          1194: * d2:  WORD DstX
        !          1195: * d3:  WORD DstY
        !          1196: * d4:   WORD Width
        !          1197: * d5:   WORD Height
        !          1198: * d6:  UBYTE OpCode
        !          1199: * d7:  uae_u32 RGBFormat
        !          1200: * NOTE: MUST return 0 in D0 if we're not handling this operation
        !          1201: *       because the RGBFormat or opcode aren't supported.
        !          1202: *       OTHERWISE return 1
        !          1203: ***********************************************************/
        !          1204: uae_u32 picasso_BlitRectNoMaskComplete (void)
        !          1205: {
        !          1206:     uaecptr boardinfo = m68k_areg(regs, 0);
        !          1207:     uaecptr srcri = m68k_areg(regs, 1);
        !          1208:     uaecptr dstri = m68k_areg(regs, 2);
        !          1209:     uae_u16 srcx = m68k_dreg(regs, 0);
        !          1210:     uae_u16 srcy = m68k_dreg(regs, 1);
        !          1211:     uae_u16 dstx = m68k_dreg(regs, 2);
        !          1212:     uae_u16 dsty = m68k_dreg(regs, 3);
        !          1213:     uae_u16 width = m68k_dreg(regs, 4);
        !          1214:     uae_u16 height = m68k_dreg(regs, 5);
        !          1215:     uae_u8 OpCode = m68k_dreg(regs, 6);
        !          1216:     uae_u32 RGBFmt = m68k_dreg(regs, 7);
        !          1217: 
        !          1218:     uae_u8 Bpp = GetBytesPerPixel(RGBFmt), *srcri_ptr = NULL, *dstri_ptr = NULL;
        !          1219:     struct RenderInfo src_ri, dst_ri;
        !          1220: 
        !          1221:     wgfx_flushline ();
        !          1222: 
        !          1223:     if (!CopyRenderInfoStructureA2U(srcri, &src_ri) || !CopyRenderInfoStructureA2U(dstri, &dst_ri))
        !          1224:        return 0;
        !          1225: 
        !          1226:     /*MyOutputDebugString ("BlitRectNoMaskComplete() op 0x%2x, Bpp %d, xy(%4d,%4d) --> xy(%4d,%4d), wh(%4d,%4d)\n",
        !          1227:                          OpCode, Bpp, srcx, srcy, dstx, dsty, width, height); */
        !          1228:     /*MyOutputDebugString ("-- src mem 0x%x BPR %d, dst mem 0x%x BPR %d, screen-mem 0x%x - 0x%x\n",
        !          1229:                          src_ri.Memory, src_ri.BytesPerRow, dst_ri.Memory, dst_ri.BytesPerRow, picasso96_state.Address, picasso96_state.Extent); */
        !          1230: 
        !          1231:     switch (OpCode) {
        !          1232:      case 0x0C:
        !          1233:        BlitRect(&src_ri, &dst_ri, srcx, srcy, dstx, dsty, width, height, 0xFF);
        !          1234:        return 1;
        !          1235: 
        !          1236:      default:
        !          1237:        /* FOR NOW! */
        !          1238:        return 0;
        !          1239:     }
        !          1240: }
        !          1241: 
        !          1242: /* This utility function is used both by BlitTemplate() and BlitPattern() */
        !          1243: static __inline__ void PixelWrite1(uae_u8 *mem, int bits, uae_u32 fgpen, uae_u32 mask)
        !          1244: {
        !          1245:     if (mask != 0xFF)
        !          1246:        fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
        !          1247:     do_put_mem_byte (mem + bits, fgpen);
        !          1248: }
        !          1249: 
        !          1250: static __inline__ void PixelWrite2(uae_u8 *mem, int bits, uae_u32 fgpen)
        !          1251: {
        !          1252:     do_put_mem_word (((uae_u16 *)mem) + bits, fgpen);
        !          1253: }
        !          1254: 
        !          1255: static __inline__ void PixelWrite3(uae_u8 *mem, int bits, uae_u32 fgpen)
        !          1256: {
        !          1257:     do_put_mem_byte (mem + bits*3, fgpen & 0x000000FF);
        !          1258:     *(uae_u16 *)(mem + bits*3+1) = (fgpen & 0x00FFFF00) >> 8;
        !          1259: }
        !          1260: 
        !          1261: static __inline__ void PixelWrite4(uae_u8 *mem, int bits, uae_u32 fgpen)
        !          1262: {
        !          1263:     do_put_mem_long (((uae_u32 *)mem) + bits, fgpen);
        !          1264: }
        !          1265: 
        !          1266: static __inline__ void PixelWrite(uae_u8 *mem, int bits, uae_u32 fgpen, uae_u8 Bpp, uae_u32 mask)
        !          1267: {
        !          1268:     switch (Bpp) {
        !          1269:     case 1:
        !          1270:        if (mask != 0xFF)
        !          1271:            fgpen = (fgpen & mask) | (do_get_mem_byte (mem + bits) & ~mask);
        !          1272:        do_put_mem_byte (mem + bits, fgpen);
        !          1273:        break;
        !          1274:     case 2:
        !          1275:        do_put_mem_word (((uae_u16 *)mem) + bits, fgpen);
        !          1276:        break;
        !          1277:     case 3:
        !          1278:        do_put_mem_byte (mem + bits*3, fgpen & 0x000000FF);
        !          1279:        *(uae_u16 *)(mem + bits*3+1) = (fgpen & 0x00FFFF00) >> 8;
        !          1280:        break;
        !          1281:     case 4:
        !          1282:        do_put_mem_long (((uae_u32 *)mem) + bits, fgpen);
        !          1283:        break;
        !          1284:     }
        !          1285: }
        !          1286: 
        !          1287: /*
        !          1288:  * BlitPattern:
        !          1289:  * 
        !          1290:  * Synopsis:BlitPattern(bi, ri, pattern, X, Y, Width, Height, Mask, RGBFormat);
        !          1291:  * Inputs:
        !          1292:  * a0:struct BoardInfo *bi
        !          1293:  * a1:struct RenderInfo *ri
        !          1294:  * a2:struct Pattern *pattern
        !          1295:  * d0.w:X
        !          1296:  * d1.w:Y
        !          1297:  * d2.w:Width
        !          1298:  * d3.w:Height
        !          1299:  * d4.w:Mask
        !          1300:  * d7.l:RGBFormat
        !          1301:  * 
        !          1302:  * This function is used to paint a pattern on the board memory using the blitter. It is called by
        !          1303:  * BltPattern, if a AreaPtrn is used with positive AreaPtSz. The pattern consists of a b/w image
        !          1304:  * using a single plane of image data which will be expanded repeatedly to the destination RGBFormat
        !          1305:  * using ForeGround and BackGround pens as well as draw modes. The width of the pattern data is
        !          1306:  * always 16 pixels (one word) and the height is calculated as 2^Size. The data must be shifted up
        !          1307:  * and to the left by XOffset and YOffset pixels at the beginning.
        !          1308:  */
        !          1309: uae_u32 picasso_BlitPattern (void)
        !          1310: {
        !          1311:     uaecptr boardinfo = m68k_areg(regs, 0);
        !          1312:     uaecptr rinf = m68k_areg(regs, 1);
        !          1313:     uaecptr pinf = m68k_areg(regs, 2);
        !          1314:     long X = (uae_u16)m68k_dreg(regs, 0);
        !          1315:     long Y = (uae_u16)m68k_dreg(regs, 1);
        !          1316:     long W = (uae_u16)m68k_dreg(regs, 2);
        !          1317:     long H = (uae_u16)m68k_dreg(regs, 3);
        !          1318:     uae_u8 Mask = (uae_u8)m68k_dreg(regs, 4);
        !          1319:     uae_u32 RGBFmt = m68k_dreg(regs, 7);
        !          1320: 
        !          1321:     uae_u8 Bpp = GetBytesPerPixel(RGBFmt);
        !          1322:     int inversion = 0;
        !          1323:     struct RenderInfo ri;
        !          1324:     struct Pattern pattern;
        !          1325:     uae_u16 rows;
        !          1326:     uae_u32 fgpen, bgpen, value;
        !          1327:     uae_u8 *uae_mem, *frame_buffer_UAM;
        !          1328:     unsigned long ysize_mask;
        !          1329:     int xshift;
        !          1330: 
        !          1331:     wgfx_flushline ();
        !          1332: 
        !          1333:     if (!CopyRenderInfoStructureA2U(rinf, &ri) || !CopyPatternStructureA2U(pinf, &pattern))
        !          1334:        return 0;
        !          1335: 
        !          1336:     Bpp = GetBytesPerPixel(ri.RGBFormat);
        !          1337:     uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset with address */
        !          1338: 
        !          1339:     if (pattern.DrawMode & INVERS)
        !          1340:        inversion = 1;
        !          1341: 
        !          1342:     pattern.DrawMode &= 0x03;
        !          1343:     if (Mask != 0xFF) {
        !          1344:        if (Bpp > 1)
        !          1345:            MyOutputDebugString ("ERROR - not obeying BlitPattern() mask 0x%x properly with Bpp %d.\n", Mask, Bpp);
        !          1346:        else if (pattern.DrawMode == COMP) {
        !          1347:            MyOutputDebugString ("ERROR - Unsupported Mask value 0x%x with COMP Draw in BlitPattern(), using fallback method.\n", Mask);
        !          1348:            return 0;
        !          1349:        }
        !          1350:     }
        !          1351: 
        !          1352:     /*MyOutputDebugString ("BlitPattern() xy(%d,%d), wh(%d,%d) draw 0x%x, off(%d,%d), ph %d\n",
        !          1353:                          X, Y, W, H, pattern.DrawMode, pattern.XOffset, pattern.YOffset, 1<<pattern.Size); */
        !          1354: #ifdef _DEBUG
        !          1355:     DumpPattern(&pattern);
        !          1356: #endif
        !          1357:     ysize_mask = (1 << pattern.Size) - 1;
        !          1358:     xshift = pattern.XOffset & 15;
        !          1359: 
        !          1360:     for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow) {
        !          1361:        int prow = (rows + pattern.YOffset) & ysize_mask;
        !          1362:        unsigned int d = do_get_mem_word (((uae_u16 *)pattern.Memory) + prow);
        !          1363:        uae_u8 *uae_mem2 = uae_mem;
        !          1364:        long cols;
        !          1365: 
        !          1366:        if (xshift != 0)
        !          1367:            d = (d << xshift) | (d >> (16 - xshift));
        !          1368: 
        !          1369:        for (cols = 0; cols < W; cols += 16, uae_mem2 += Bpp << 4) {
        !          1370:            long bits;
        !          1371:            long max = W - cols;
        !          1372:            unsigned int data = d;
        !          1373: 
        !          1374:            if (max > 16)
        !          1375:                max = 16;
        !          1376:     
        !          1377:            for (bits = 0; bits < max; bits++) {
        !          1378:                int bit_set = data & 0x8000;
        !          1379:                data <<= 1;
        !          1380:                switch (pattern.DrawMode) {
        !          1381:                 case JAM1:
        !          1382:                    if (inversion)
        !          1383:                        bit_set = !bit_set;
        !          1384:                    if (bit_set)
        !          1385:                        PixelWrite(uae_mem2, bits, pattern.FgPen, Bpp, Mask);
        !          1386:                    break;
        !          1387:                 case JAM2:
        !          1388:                    if (inversion)
        !          1389:                        bit_set = !bit_set;
        !          1390:                    if (bit_set)
        !          1391:                        PixelWrite(uae_mem2, bits, pattern.FgPen, Bpp, Mask);
        !          1392:                    else
        !          1393:                        PixelWrite(uae_mem2, bits, pattern.BgPen, Bpp, Mask);
        !          1394:                    break;
        !          1395:                 case COMP:
        !          1396:                    if (bit_set) {
        !          1397:                        fgpen = pattern.FgPen;
        !          1398: 
        !          1399:                        switch (Bpp) {
        !          1400:                         case 1:
        !          1401:                            {
        !          1402:                                uae_u8 *addr = uae_mem2 + bits;
        !          1403:                                do_put_mem_byte (addr, do_get_mem_byte (addr) ^ fgpen);
        !          1404:                            }
        !          1405:                            break;
        !          1406:                         case 2:
        !          1407:                            {
        !          1408:                                uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
        !          1409:                                do_put_mem_word (addr, do_get_mem_word (addr) ^ fgpen);
        !          1410:                            }
        !          1411:                            break;
        !          1412:                         case 3:
        !          1413:                            {
        !          1414:                                uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
        !          1415:                                do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
        !          1416:                            }
        !          1417:                            break;
        !          1418:                         case 4:
        !          1419:                            {
        !          1420:                                uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
        !          1421:                                do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
        !          1422:                            }
        !          1423:                            break;
        !          1424:                        }
        !          1425:                    }
        !          1426:                    break;
        !          1427:                }
        !          1428:            }
        !          1429:        }
        !          1430:     }
        !          1431: 
        !          1432:     frame_buffer_UAM = ri.Memory + X*picasso96_state.BytesPerPixel + Y*ri.BytesPerRow;
        !          1433:     if (renderinfo_is_current_screen (&ri))
        !          1434:        do_blit (frame_buffer_UAM, ri.BytesPerRow, 0, 0, X, Y, W, H, 0);
        !          1435: 
        !          1436:     return 1;
        !          1437: }
        !          1438: 
        !          1439: /*************************************************
        !          1440: BlitTemplate:
        !          1441: **************************************************
        !          1442: * Synopsis: BlitTemplate(bi, ri, template, X, Y, Width, Height, Mask, RGBFormat);
        !          1443: * a0: struct BoardInfo *bi
        !          1444: * a1: struct RenderInfo *ri
        !          1445: * a2: struct Template *template
        !          1446: * d0.w: X
        !          1447: * d1.w: Y
        !          1448: * d2.w: Width
        !          1449: * d3.w: Height
        !          1450: * d4.w: Mask
        !          1451: * d7.l: RGBFormat
        !          1452: *
        !          1453: * This function is used to paint a template on the board memory using the blitter.
        !          1454: * It is called by BltPattern and BltTemplate. The template consists of a b/w image
        !          1455: * using a single plane of image data which will be expanded to the destination RGBFormat
        !          1456: * using ForeGround and BackGround pens as well as draw modes.
        !          1457: ***********************************************************************************/
        !          1458: uae_u32 picasso_BlitTemplate (void)
        !          1459: {
        !          1460:     uae_u8 inversion = 0;
        !          1461:     uaecptr rinf = m68k_areg(regs, 1);
        !          1462:     uaecptr tmpl = m68k_areg(regs, 2);
        !          1463:     uae_u16 X = m68k_dreg(regs, 0);
        !          1464:     uae_u16 Y = m68k_dreg(regs, 1);
        !          1465:     uae_u16 W = m68k_dreg(regs, 2);
        !          1466:     uae_u16 H = m68k_dreg(regs, 3);
        !          1467:     uae_u16 Mask = m68k_dreg(regs, 4);
        !          1468:     uae_u32 Fmt = m68k_dreg(regs, 7);
        !          1469:     struct Template tmp;
        !          1470:     struct RenderInfo ri;
        !          1471:     long rows;
        !          1472:     int bitoffset;
        !          1473:     uae_u32 fgpen, bgpen, value;
        !          1474:     uae_u8 *uae_mem, *uae_mem2, Bpp, *frame_buffer_UAM;
        !          1475:     uae_u8 *tmpl_base;
        !          1476: 
        !          1477:     wgfx_flushline ();
        !          1478: 
        !          1479:     if (!CopyRenderInfoStructureA2U(rinf, &ri) || !CopyTemplateStructureA2U(tmpl, &tmp))
        !          1480:        return 0;
        !          1481: 
        !          1482:     Bpp = GetBytesPerPixel(ri.RGBFormat);
        !          1483:     uae_mem = ri.Memory + Y*ri.BytesPerRow + X*Bpp; /* offset into address */
        !          1484: 
        !          1485:     if (tmp.DrawMode & INVERS)
        !          1486:        inversion = 1;
        !          1487: 
        !          1488:     tmp.DrawMode &= 0x03;
        !          1489:     if (Mask != 0xFF) {
        !          1490:        if (Bpp > 1)
        !          1491:            MyOutputDebugString ("ERROR - not obeying BlitTemplate() mask 0x%x properly with Bpp %d.\n", Mask, Bpp);
        !          1492:        else if (tmp.DrawMode == COMP) {
        !          1493:            MyOutputDebugString ("ERROR - Unsupported Mask value 0x%x with COMP Draw in BlitTemplate(), using fallback method.\n", Mask);
        !          1494:            return 0;
        !          1495:        }
        !          1496:     }
        !          1497: 
        !          1498:     /*MyOutputDebugString ("BlitTemplate() xy(%d,%d), wh(%d,%d) draw 0x%x fg 0x%x bg 0x%x \n",
        !          1499:                          X, Y, W, H, tmp.DrawMode, tmp.FgPen, tmp.BgPen); */
        !          1500: 
        !          1501:     bitoffset = tmp.XOffset % 8;
        !          1502: 
        !          1503: #ifdef _DEBUG
        !          1504:     DumpTemplate(&tmp, W, H);
        !          1505: #endif
        !          1506: 
        !          1507:     tmpl_base = tmp.Memory + tmp.XOffset/8;
        !          1508: 
        !          1509:     for (rows = 0; rows < H; rows++, uae_mem += ri.BytesPerRow, tmpl_base += tmp.BytesPerRow) {
        !          1510:        long cols;
        !          1511:        uae_u8 *tmpl_mem = tmpl_base;
        !          1512:        uae_u8 *uae_mem2 = uae_mem;
        !          1513:        unsigned int data = *tmpl_mem;
        !          1514: 
        !          1515:        for (cols = 0; cols < W; cols += 8, uae_mem2 += Bpp << 3) {
        !          1516:            unsigned int byte;
        !          1517:            long bits;
        !          1518:            long max = W - cols;
        !          1519: 
        !          1520:            if (max > 8)
        !          1521:                max = 8;
        !          1522: 
        !          1523:            data <<= 8;
        !          1524:            data |= *++tmpl_mem;
        !          1525: 
        !          1526:            byte = data >> (8 - bitoffset);
        !          1527: 
        !          1528:            for (bits = 0; bits < max; bits++) {
        !          1529:                int bit_set = (byte & 0x80);
        !          1530:                byte <<= 1;
        !          1531:                switch (tmp.DrawMode) {
        !          1532:                 case JAM1:
        !          1533:                    if (inversion)
        !          1534:                        bit_set = !bit_set;
        !          1535:                    if (bit_set) {
        !          1536:                        fgpen = tmp.FgPen;
        !          1537:                        PixelWrite(uae_mem2, bits, fgpen, Bpp, Mask);
        !          1538:                    }
        !          1539:                    break;
        !          1540:                 case JAM2:
        !          1541:                    if (inversion)
        !          1542:                        bit_set = !bit_set;
        !          1543:                    fgpen = tmp.BgPen;
        !          1544:                    if (bit_set)
        !          1545:                        fgpen = tmp.FgPen;
        !          1546: 
        !          1547:                    PixelWrite(uae_mem2, bits, fgpen, Bpp, Mask);
        !          1548:                    break;
        !          1549:                 case COMP:
        !          1550:                    if (bit_set) {
        !          1551:                        fgpen = tmp.FgPen;
        !          1552: 
        !          1553:                        switch (Bpp) {
        !          1554:                         case 1:
        !          1555:                            {
        !          1556:                                uae_u8 *addr = uae_mem2 + bits;
        !          1557:                                do_put_mem_byte (addr, do_get_mem_byte (addr) ^ fgpen);
        !          1558:                            }
        !          1559:                            break;
        !          1560:                         case 2:
        !          1561:                            {
        !          1562:                                uae_u16 *addr = ((uae_u16 *)uae_mem2) + bits;
        !          1563:                                do_put_mem_word (addr, do_get_mem_word (addr) ^ fgpen);
        !          1564:                            }
        !          1565:                            break;
        !          1566:                         case 3:
        !          1567:                            {
        !          1568:                                uae_u32 *addr = (uae_u32 *)(uae_mem2 + bits * 3);
        !          1569:                                do_put_mem_long (addr, do_get_mem_long (addr) ^ (fgpen & 0x00FFFFFF));
        !          1570:                            }
        !          1571:                            break;
        !          1572:                         case 4:
        !          1573:                            {
        !          1574:                                uae_u32 *addr = ((uae_u32 *)uae_mem2) + bits;
        !          1575:                                do_put_mem_long (addr, do_get_mem_long (addr) ^ fgpen);
        !          1576:                            }
        !          1577:                            break;
        !          1578:                        }
        !          1579:                    }
        !          1580:                    break;
        !          1581:                }
        !          1582:            }
        !          1583:        }
        !          1584:     }
        !          1585: 
        !          1586:     frame_buffer_UAM = ri.Memory + X*picasso96_state.BytesPerPixel + Y*ri.BytesPerRow;
        !          1587:     if (renderinfo_is_current_screen (&ri))
        !          1588:        do_blit (frame_buffer_UAM, ri.BytesPerRow, 0, 0, X, Y, W, H, 0);
        !          1589: 
        !          1590:     return 1;
        !          1591: }
        !          1592: 
        !          1593: /*
        !          1594:  * CalculateBytesPerRow:
        !          1595:  * a0:         struct BoardInfo
        !          1596:  * d0:         uae_u16 Width
        !          1597:  * d7: RGBFTYPE RGBFormat
        !          1598:  * This function calculates the amount of bytes needed for a line of
        !          1599:  * "Width" pixels in the given RGBFormat.
        !          1600:  */
        !          1601: uae_u32 picasso_CalculateBytesPerRow (void)
        !          1602: {
        !          1603:     uae_u16 width = m68k_dreg(regs, 0);
        !          1604:     uae_u32 type = m68k_dreg(regs, 7);
        !          1605: 
        !          1606:     width = GetBytesPerPixel(type)*width;
        !          1607:     /*MyOutputDebugString ("CalculateBytesPerRow() = %d\n",width); */
        !          1608: 
        !          1609:     return width;
        !          1610: }
        !          1611: 
        !          1612: /*
        !          1613:  * SetDisplay:
        !          1614:  * a0: struct BoardInfo
        !          1615:  * d0: BOOL state
        !          1616:  * This function enables and disables the video display.
        !          1617:  * 
        !          1618:  * NOTE: return the opposite of the state
        !          1619:  */
        !          1620: uae_u32 picasso_SetDisplay (void)
        !          1621: {
        !          1622:     uae_u32 state = m68k_dreg(regs, 0);
        !          1623:     /*MyOutputDebugString ("SetDisplay(%d)\n", state);*/
        !          1624:     return !state;
        !          1625: }
        !          1626: 
        !          1627: /*
        !          1628:  * WaitVerticalSync:
        !          1629:  * a0: struct BoardInfo
        !          1630:  * This function waits for the next horizontal retrace.
        !          1631:  */
        !          1632: uae_u32 picasso_WaitVerticalSync (void)
        !          1633: {
        !          1634:     /*MyOutputDebugString ("WaitVerticalSync()\n");*/
        !          1635:     return 1;
        !          1636: }
        !          1637: 
        !          1638: /* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
        !          1639: static void PlanarToChunky(struct RenderInfo *ri, struct BitMap *bm, long srcx, long srcy,
        !          1640:                           long dstx, long dsty, long width, long height, uae_u8 mask)
        !          1641: {
        !          1642:     int j, bits;
        !          1643: 
        !          1644:     uae_u8 *PLANAR[8], *image = ri->Memory + dstx * GetBytesPerPixel (ri->RGBFormat) + dsty*ri->BytesPerRow;
        !          1645:     int Depth = bm->Depth;
        !          1646:     uae_u16 rows, total_bits, value, bitoffset = srcx & 7;
        !          1647:     long eol_offset;
        !          1648: 
        !          1649:     /* if (mask != 0xFF) 
        !          1650:        MyOutputDebugString ("P2C - pixel-width = %d, bit-offset = %d\n", width, bitoffset); */
        !          1651:     
        !          1652:     /* Set up our bm->Planes[] pointers to the right horizontal offset */
        !          1653:     for (j = 0; j < Depth; j++) {
        !          1654:        uae_u8 *p = bm->Planes[j];
        !          1655:        if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
        !          1656:            p += srcx/8 + srcy*bm->BytesPerRow;
        !          1657:        PLANAR[j] = p;
        !          1658:        if ((mask & (1 << j)) == 0)
        !          1659:            PLANAR[j] = &all_zeros_bitmap;
        !          1660:     }
        !          1661:     eol_offset = (long)bm->BytesPerRow - ((width + 7) >> 3);
        !          1662:     for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
        !          1663:        long cols;
        !          1664: 
        !          1665:        for (cols = 0; cols < width; cols += 8) {
        !          1666:            int k;
        !          1667:            uae_u32 a = 0, b = 0;
        !          1668:            unsigned int msk = 0xFF;
        !          1669:            long tmp = cols + 8 - width;
        !          1670:            if (tmp > 0) {
        !          1671:                msk <<= tmp;
        !          1672:                b = do_get_mem_long ((uae_u32 *)(image + cols + 4));
        !          1673:                if (tmp < 4)
        !          1674:                    b &= 0xFFFFFFFF >> (32 - tmp * 8);
        !          1675:                else if (tmp > 4) {
        !          1676:                    a = do_get_mem_long ((uae_u32 *)(image + cols));
        !          1677:                    a &= 0xFFFFFFFF >> (64 - tmp * 8);
        !          1678:                }
        !          1679:            }
        !          1680:            for (k = 0; k < Depth; k++) {
        !          1681:                unsigned int data;
        !          1682:                if (PLANAR[k] == &all_zeros_bitmap)
        !          1683:                    data = 0;
        !          1684:                else if (PLANAR[k] == &all_ones_bitmap)
        !          1685:                    data = 0xFF;
        !          1686:                else {
        !          1687:                    data = (uae_u8)(do_get_mem_word ((uae_u16 *)PLANAR[k]) >> (8 - bitoffset));
        !          1688:                    PLANAR[k]++;
        !          1689:                }
        !          1690:                data &= msk;
        !          1691:                a |= p2ctab[data][0] << k;
        !          1692:                b |= p2ctab[data][1] << k;
        !          1693:            }
        !          1694:            do_put_mem_long ((uae_u32 *)(image + cols), a);
        !          1695:            do_put_mem_long ((uae_u32 *)(image + cols + 4), b);
        !          1696:        }
        !          1697:        for (j = 0; j < Depth; j++) {
        !          1698:            if (PLANAR[j] != &all_zeros_bitmap && PLANAR[j] != &all_ones_bitmap) {
        !          1699:                PLANAR[j] += eol_offset;
        !          1700:            }
        !          1701:        }
        !          1702:     }
        !          1703: }
        !          1704: 
        !          1705: /*
        !          1706:  * BlitPlanar2Chunky:
        !          1707:  * a0: struct BoardInfo *bi
        !          1708:  * a1: struct BitMap *bm - source containing planar information and assorted details
        !          1709:  * a2: struct RenderInfo *ri - dest area and its details
        !          1710:  * d0.w: SrcX
        !          1711:  * d1.w: SrcY
        !          1712:  * d2.w: DstX
        !          1713:  * d3.w: DstY
        !          1714:  * d4.w: SizeX
        !          1715:  * d5.w: SizeY
        !          1716:  * d6.b: MinTerm - uh oh!
        !          1717:  * d7.b: Mask - uh oh!
        !          1718:  *
        !          1719:  * This function is currently used to blit from planar bitmaps within system memory to chunky bitmaps
        !          1720:  * on the board. Watch out for plane pointers that are 0x00000000 (represents a plane with all bits "0")
        !          1721:  * or 0xffffffff (represents a plane with all bits "1").
        !          1722:  */
        !          1723: uae_u32 picasso_BlitPlanar2Chunky (void)
        !          1724: {
        !          1725:     uaecptr bi = m68k_areg(regs, 0);
        !          1726:     uaecptr bm = m68k_areg(regs, 1);
        !          1727:     uaecptr ri = m68k_areg(regs, 2);
        !          1728:     uae_u16 srcx = m68k_dreg(regs, 0) & 0xFFFF;
        !          1729:     uae_u16 srcy = m68k_dreg(regs, 1) & 0xFFFF;
        !          1730:     uae_u16 dstx = m68k_dreg(regs, 2) & 0xFFFF;
        !          1731:     uae_u16 dsty = m68k_dreg(regs, 3) & 0xFFFF;
        !          1732:     uae_u16 width = m68k_dreg(regs, 4) & 0xFFFF;
        !          1733:     uae_u16 height = m68k_dreg(regs, 5) & 0xFFFF;
        !          1734:     uae_u8 minterm = m68k_dreg(regs, 6) & 0xFF;
        !          1735:     uae_u8 mask = m68k_dreg(regs, 7) & 0xFF;
        !          1736:     int i;
        !          1737:     struct RenderInfo local_ri;
        !          1738:     uae_u8 *uaebm = NULL;
        !          1739:     struct BitMap local_bm;
        !          1740: 
        !          1741:     wgfx_flushline ();
        !          1742: 
        !          1743:     if (minterm != 0x0C) {
        !          1744:        MyOutputDebugString ("ERROR - BlitPlanar2Chunky() has minterm 0x%x, which I don't handle. Using fall-back routine.\n",
        !          1745:                             minterm);
        !          1746:        return 0;
        !          1747:     }
        !          1748:     if (!CopyRenderInfoStructureA2U(ri, &local_ri) || !CopyBitMapStructureA2U(bm, &local_bm))
        !          1749:        return 0;
        !          1750: 
        !          1751:     /*MyOutputDebugString ("BlitPlanar2Chunky(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
        !          1752:                          srcx, srcy, dstx, dsty, width, height, minterm, mask, local_bm.Depth);
        !          1753:     MyOutputDebugString ("P2C - BitMap has %d BPR, %d rows\n", local_bm.BytesPerRow, local_bm.Rows); */
        !          1754:     PlanarToChunky(&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, mask);
        !          1755:     if (renderinfo_is_current_screen (&local_ri))
        !          1756:        do_blit (local_ri.Memory + dstx * GetBytesPerPixel (local_ri.RGBFormat) + dsty * local_ri.BytesPerRow,
        !          1757:                 local_ri.BytesPerRow,
        !          1758:                 0, 0, dstx, dsty, width, height, 0);
        !          1759: 
        !          1760:     return m68k_dreg(regs, 0);
        !          1761: }
        !          1762: 
        !          1763: /* NOTE: Watch for those planeptrs of 0x00000000 and 0xFFFFFFFF for all zero / all one bitmaps !!!! */
        !          1764: static void PlanarToDirect(struct RenderInfo *ri, struct BitMap *bm,
        !          1765:                           long srcx, long srcy, long dstx, long dsty,
        !          1766:                           long width, long height, uae_u8 mask,
        !          1767:                           struct ColorIndexMapping *cim)
        !          1768: {
        !          1769:     int j;
        !          1770:     int bpp = GetBytesPerPixel(ri->RGBFormat);
        !          1771:     uae_u8 *PLANAR[8];
        !          1772:     uae_u8 *image = ri->Memory + dstx * bpp + dsty * ri->BytesPerRow;
        !          1773:     int Depth = bm->Depth;
        !          1774:     long rows;
        !          1775:     long eol_offset;
        !          1776: 
        !          1777:     /* Set up our bm->Planes[] pointers to the right horizontal offset */
        !          1778:     for (j = 0; j < Depth; j++) {
        !          1779:        uae_u8 *p = bm->Planes[j];
        !          1780:        if (p != &all_zeros_bitmap && p != &all_ones_bitmap)
        !          1781:            p += srcx/8 + srcy*bm->BytesPerRow;
        !          1782:        PLANAR[j] = p;
        !          1783:        if ((mask & (1 << j)) == 0)
        !          1784:            PLANAR[j] = &all_zeros_bitmap;
        !          1785:     }
        !          1786: 
        !          1787:     eol_offset = (long)bm->BytesPerRow - ((width + (srcx & 7)) >> 3);
        !          1788:     for (rows = 0; rows < height; rows++, image += ri->BytesPerRow) {
        !          1789:        long cols;
        !          1790:        uae_u8 *image2 = image;
        !          1791:        unsigned int bitoffs = 7 - (srcx & 7);
        !          1792:        int i;
        !          1793: 
        !          1794:        for (cols = 0; cols < width; cols ++) {
        !          1795:            int v = 0, k;
        !          1796:            for (k = 0; k < Depth; k++) {
        !          1797:                if (PLANAR[k] == &all_ones_bitmap)
        !          1798:                    v |= 1 << k;
        !          1799:                else if (PLANAR[k] != &all_zeros_bitmap) {
        !          1800:                    v |= ((*PLANAR[k] >> bitoffs) & 1) << k;
        !          1801:                }
        !          1802:            }
        !          1803: 
        !          1804:            switch (bpp) {
        !          1805:             case 2:
        !          1806:                do_put_mem_word ((uae_u16 *)image2, cim->Colors[v]);
        !          1807:                image2 += 2;
        !          1808:                break;
        !          1809:             case 3:
        !          1810:                do_put_mem_byte (image2++, cim->Colors[v] & 0x000000FF);
        !          1811:                do_put_mem_word ((uae_u16 *)image2, (cim->Colors[v] & 0x00FFFF00) >> 8);
        !          1812:                image2 += 2;
        !          1813:                break;
        !          1814:             case 4:
        !          1815:                do_put_mem_long ((uae_u32 *)image2, cim->Colors[v]);
        !          1816:                image2 += 4;
        !          1817:                break;
        !          1818:            }
        !          1819:            bitoffs--;
        !          1820:            bitoffs &= 7;
        !          1821:            if (bitoffs == 7) {
        !          1822:                int k;
        !          1823:                for (k = 0; k < Depth; k++) {
        !          1824:                    if (PLANAR[k] != &all_zeros_bitmap && PLANAR[k] != &all_ones_bitmap) {
        !          1825:                        PLANAR[k]++;
        !          1826:                    }
        !          1827:                }
        !          1828:            }
        !          1829:        }
        !          1830: 
        !          1831:        for (i = 0; i < Depth; i++) {
        !          1832:            if (PLANAR[i] != &all_zeros_bitmap && PLANAR[i] != &all_ones_bitmap) {
        !          1833:                PLANAR[i] += eol_offset;
        !          1834:            }
        !          1835:        }
        !          1836:     }
        !          1837: }
        !          1838: 
        !          1839: /*
        !          1840:  * BlitPlanar2Direct: 
        !          1841:  * 
        !          1842:  * Synopsis:
        !          1843:  * BlitPlanar2Direct(bi, bm, ri, cim, SrcX, SrcY, DstX, DstY, SizeX, SizeY, MinTerm, Mask);
        !          1844:  * Inputs:
        !          1845:  * a0:struct BoardInfo *bi
        !          1846:  * a1:struct BitMap *bm
        !          1847:  * a2:struct RenderInfo *ri
        !          1848:  * a3:struct ColorIndexMapping *cmi
        !          1849:  * d0.w:SrcX
        !          1850:  * d1.w:SrcY
        !          1851:  * d2.w:DstX
        !          1852:  * d3.w:DstY
        !          1853:  * d4.w:SizeX
        !          1854:  * d5.w:SizeY
        !          1855:  * d6.b:MinTerm
        !          1856:  * d7.b:Mask
        !          1857:  * 
        !          1858:  * This function is currently used to blit from planar bitmaps within system memory to direct color
        !          1859:  * bitmaps (15, 16, 24 or 32 bit) on the board. Watch out for plane pointers that are 0x00000000 (represents
        !          1860:  * a plane with all bits "0") or 0xffffffff (represents a plane with all bits "1"). The ColorIndexMapping is
        !          1861:  * used to map the color index of each pixel formed by the bits in the bitmap's planes to a direct color value
        !          1862:  * which is written to the destination RenderInfo. The color mask and all colors within the mapping are words,
        !          1863:  * triple bytes or longwords respectively similar to the color values used in FillRect(), BlitPattern() or
        !          1864:  * BlitTemplate(). 
        !          1865:  */
        !          1866: uae_u32 picasso_BlitPlanar2Direct (void)
        !          1867: {
        !          1868:     uaecptr bi = m68k_areg(regs, 0);
        !          1869:     uaecptr bm = m68k_areg(regs, 1);
        !          1870:     uaecptr ri = m68k_areg(regs, 2);
        !          1871:     uaecptr cim = m68k_areg(regs, 3);
        !          1872:     uae_u16 srcx = m68k_dreg(regs, 0);
        !          1873:     uae_u16 srcy = m68k_dreg(regs, 1);
        !          1874:     uae_u16 dstx = m68k_dreg(regs, 2);
        !          1875:     uae_u16 dsty = m68k_dreg(regs, 3);
        !          1876:     uae_u16 width = m68k_dreg(regs, 4);
        !          1877:     uae_u16 height = m68k_dreg(regs, 5);
        !          1878:     uae_u8 minterm = m68k_dreg(regs, 6);
        !          1879:     uae_u8 Mask = m68k_dreg(regs, 7);
        !          1880:     struct RenderInfo local_ri;
        !          1881:     uae_u8 *uaebm = NULL;
        !          1882:     struct BitMap local_bm;
        !          1883:     struct ColorIndexMapping local_cim;
        !          1884: 
        !          1885:     wgfx_flushline ();
        !          1886: 
        !          1887:     if (minterm != 0x0C) {
        !          1888:        MyOutputDebugString ("ERROR - BlitPlanar2Direct() has op-code 0x%x, which I don't handle. Using fall-back routine.\n",
        !          1889:                             minterm);
        !          1890:        return 0;
        !          1891:     }
        !          1892:     if (Mask != 0xFF) {
        !          1893:        MyOutputDebugString ("ERROR - Unsupported Mask value 0x%x in BlitPlanar2Direct(), using fallback method.\n", Mask);
        !          1894:        return 0;
        !          1895:     }
        !          1896:     if (!CopyRenderInfoStructureA2U (ri, &local_ri) || !CopyBitMapStructureA2U (bm, &local_bm))
        !          1897:        return 0;
        !          1898: 
        !          1899:     CopyColorIndexMappingA2U (cim, &local_cim);
        !          1900:     /* MyOutputDebugString ("BlitPlanar2Direct(%d, %d, %d, %d, %d, %d) Minterm 0x%x, Mask 0x%x, Depth %d\n",
        !          1901:                            srcx, srcy, dstx, dsty, width, height, minterm, Mask, local_bm.Depth); */
        !          1902:     PlanarToDirect(&local_ri, &local_bm, srcx, srcy, dstx, dsty, width, height, Mask, &local_cim);
        !          1903:     if (renderinfo_is_current_screen (&local_ri))
        !          1904:        do_blit (local_ri.Memory + dstx * GetBytesPerPixel (local_ri.RGBFormat) + dsty * local_ri.BytesPerRow,
        !          1905:                 local_ri.BytesPerRow,
        !          1906:                 0, 0, dstx, dsty, width, height, 0);
        !          1907:     return 1;
        !          1908: }
        !          1909: 
        !          1910: /* @@@ - Work to be done here!
        !          1911:  *
        !          1912:  * The address is the offset into our Picasso96 frame-buffer (pointed to by gfxmem_start)
        !          1913:  * where the value was put.
        !          1914:  *
        !          1915:  * Porting work: on some machines you may not need these functions, ie. if the memory for the
        !          1916:  * Picasso96 frame-buffer is directly viewable or directly blittable.  On Win32 with DirectX,
        !          1917:  * this is not the case.  So I provide some write-through functions (as per Mathias' orders!)
        !          1918:  */
        !          1919: static void write_gfx_long (uaecptr addr, uae_u32 value)
        !          1920: {
        !          1921:     uaecptr oldaddr = addr;
        !          1922:     int x, xbytes, y;
        !          1923:     uae_u8 *dst;
        !          1924: 
        !          1925:     if (!picasso_on)
        !          1926:        return;
        !          1927: 
        !          1928:     /*
        !          1929:      * Several writes to successive memory locations are a common access pattern.
        !          1930:      * Try to optimize it.
        !          1931:      */
        !          1932:     if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
        !          1933:        if (addr < wgfx_min)
        !          1934:            wgfx_min = addr;
        !          1935:        if (addr + 4 > wgfx_max)
        !          1936:            wgfx_max = addr + 4;
        !          1937:        return;
        !          1938:     } else
        !          1939:        wgfx_flushline ();
        !          1940: 
        !          1941:     addr += gfxmem_start;
        !          1942:     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
        !          1943:     if (addr < picasso96_state.Address || addr + 4 > picasso96_state.Extent)
        !          1944:        return;
        !          1945: 
        !          1946:     addr -= picasso96_state.Address;
        !          1947:     y = addr / picasso96_state.BytesPerRow;
        !          1948: 
        !          1949: #if 0
        !          1950:     DX_Invalidate (y, y);
        !          1951:     if (! picasso_vidinfo.extra_mem)
        !          1952:        return;
        !          1953: 
        !          1954:     xbytes = addr - y * picasso96_state.BytesPerRow;
        !          1955:     x = xbytes / picasso96_state.BytesPerPixel;
        !          1956: 
        !          1957:     if (x < picasso96_state.Width && y < picasso96_state.Height) {
        !          1958:        dst = lockscr();
        !          1959:        if (dst) {
        !          1960:            do_put_mem_long ((uae_u32 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value);
        !          1961:            unlockscr();
        !          1962:        }
        !          1963:     }
        !          1964: #else
        !          1965:     if (y >= picasso96_state.Height)
        !          1966:        return;
        !          1967:     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
        !          1968:     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
        !          1969:     wgfx_y = y;
        !          1970:     wgfx_min = oldaddr;
        !          1971:     wgfx_max = oldaddr + 4;
        !          1972: #endif
        !          1973: }
        !          1974: 
        !          1975: static void write_gfx_word (uaecptr addr, uae_u16 value)
        !          1976: {
        !          1977:     uaecptr oldaddr = addr;
        !          1978:     int x, xbytes, y;
        !          1979:     uae_u8 *dst;
        !          1980: 
        !          1981:     if (!picasso_on)
        !          1982:        return;
        !          1983: 
        !          1984:     /*
        !          1985:      * Several writes to successive memory locations are a common access pattern.
        !          1986:      * Try to optimize it.
        !          1987:      */
        !          1988:     if (addr >= wgfx_linestart && addr + 2 <= wgfx_lineend) {
        !          1989:        if (addr < wgfx_min)
        !          1990:            wgfx_min = addr;
        !          1991:        if (addr + 2 > wgfx_max)
        !          1992:            wgfx_max = addr + 2;
        !          1993:        return;
        !          1994:     } else
        !          1995:        wgfx_flushline ();
        !          1996: 
        !          1997:     addr += gfxmem_start;
        !          1998:     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
        !          1999:     if (addr < picasso96_state.Address || addr + 2 > picasso96_state.Extent)
        !          2000:        return;
        !          2001: 
        !          2002:     addr -= picasso96_state.Address;
        !          2003:     y = addr / picasso96_state.BytesPerRow;
        !          2004: 
        !          2005: #if 0
        !          2006:     DX_Invalidate (y, y);
        !          2007:     if (! picasso_vidinfo.extra_mem)
        !          2008:        return;
        !          2009: 
        !          2010:     xbytes = addr - y * picasso96_state.BytesPerRow;
        !          2011:     x = xbytes / picasso96_state.BytesPerPixel;
        !          2012: 
        !          2013:     if (x < picasso96_state.Width && y < picasso96_state.Height) {
        !          2014:        dst = lockscr();
        !          2015:        if (dst) {
        !          2016:            do_put_mem_word ((uae_u16 *)(dst + y * picasso_vidinfo.rowbytes + xbytes), value);
        !          2017:            unlockscr();
        !          2018:        }
        !          2019:     }
        !          2020: #else
        !          2021:     if (y >= picasso96_state.Height)
        !          2022:        return;
        !          2023:     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
        !          2024:     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
        !          2025:     wgfx_y = y;
        !          2026:     wgfx_min = oldaddr;
        !          2027:     wgfx_max = oldaddr + 2;
        !          2028: #endif
        !          2029: }
        !          2030: 
        !          2031: static void write_gfx_byte (uaecptr addr, uae_u8 value)
        !          2032: {
        !          2033:     uaecptr oldaddr = addr;
        !          2034:     int x, xbytes, y;
        !          2035:     uae_u8 *dst;
        !          2036: 
        !          2037:     if (!picasso_on)
        !          2038:        return;
        !          2039: 
        !          2040:     /*
        !          2041:      * Several writes to successive memory locations are a common access pattern.
        !          2042:      * Try to optimize it.
        !          2043:      */
        !          2044:     if (addr >= wgfx_linestart && addr + 4 <= wgfx_lineend) {
        !          2045:        if (addr < wgfx_min)
        !          2046:            wgfx_min = addr;
        !          2047:        if (addr + 1 > wgfx_max)
        !          2048:            wgfx_max = addr + 1;
        !          2049:        return;
        !          2050:     } else
        !          2051:        wgfx_flushline ();
        !          2052: 
        !          2053:     addr += gfxmem_start;
        !          2054:     /* Check to see if this needs to be written through to the display, or was it an "offscreen" area? */
        !          2055:     if (addr < picasso96_state.Address || addr + 1 > picasso96_state.Extent)
        !          2056:        return;
        !          2057: 
        !          2058:     addr -= picasso96_state.Address;
        !          2059:     y = addr / picasso96_state.BytesPerRow;
        !          2060: 
        !          2061: #if 0
        !          2062:     DX_Invalidate (y, y);
        !          2063:     if (! picasso_vidinfo.extra_mem)
        !          2064:        return;
        !          2065: 
        !          2066:     xbytes = addr - y * picasso96_state.BytesPerRow;
        !          2067:     x = xbytes / picasso96_state.BytesPerPixel;
        !          2068: 
        !          2069:     if (x < picasso96_state.Width && y < picasso96_state.Height) {
        !          2070:        dst = lockscr();
        !          2071:        if (dst) {
        !          2072:            *(uae_u8 *)(dst + y * picasso_vidinfo.rowbytes + xbytes) = value;
        !          2073:            unlockscr();
        !          2074:        }
        !          2075:     }
        !          2076: #else
        !          2077:     if (y >= picasso96_state.Height)
        !          2078:        return;
        !          2079:     wgfx_linestart = picasso96_state.Address - gfxmem_start + y * picasso96_state.BytesPerRow;
        !          2080:     wgfx_lineend = wgfx_linestart + picasso96_state.BytesPerRow;
        !          2081:     wgfx_y = y;
        !          2082:     wgfx_min = oldaddr;
        !          2083:     wgfx_max = oldaddr + 1;
        !          2084: #endif
        !          2085: }
        !          2086: 
        !          2087: static uae_u32 REGPARAM2 gfxmem_lget (uaecptr addr)
        !          2088: {
        !          2089:     uae_u32 *m;
        !          2090:     addr -= gfxmem_start & gfxmem_mask;
        !          2091:     addr &= gfxmem_mask;
        !          2092:     m = (uae_u32 *)(gfxmemory + addr);
        !          2093:     return do_get_mem_long(m);
        !          2094: }
        !          2095: 
        !          2096: static uae_u32 REGPARAM2 gfxmem_wget (uaecptr addr)
        !          2097: {
        !          2098:     uae_u16 *m;
        !          2099:     addr -= gfxmem_start & gfxmem_mask;
        !          2100:     addr &= gfxmem_mask;
        !          2101:     m = (uae_u16 *)(gfxmemory + addr);
        !          2102:     return do_get_mem_word(m);
        !          2103: }
        !          2104: 
        !          2105: static uae_u32 REGPARAM2 gfxmem_bget (uaecptr addr)
        !          2106: {
        !          2107:     addr -= gfxmem_start & gfxmem_mask;
        !          2108:     addr &= gfxmem_mask;
        !          2109:     return gfxmemory[addr];
        !          2110: }
        !          2111: 
        !          2112: static void REGPARAM2 gfxmem_lput (uaecptr addr, uae_u32 l)
        !          2113: {
        !          2114:     uae_u32 *m;
        !          2115:     addr -= gfxmem_start & gfxmem_mask;
        !          2116:     addr &= gfxmem_mask;
        !          2117:     m = (uae_u32 *)(gfxmemory + addr);
        !          2118:     do_put_mem_long(m, l);
        !          2119: 
        !          2120:     /* write the long-word to our displayable memory */
        !          2121:     write_gfx_long(addr, l);
        !          2122: }
        !          2123: 
        !          2124: static void REGPARAM2 gfxmem_wput (uaecptr addr, uae_u32 w)
        !          2125: {
        !          2126:     uae_u16 *m;
        !          2127:     addr -= gfxmem_start & gfxmem_mask;
        !          2128:     addr &= gfxmem_mask;
        !          2129:     m = (uae_u16 *)(gfxmemory + addr);
        !          2130:     do_put_mem_word(m, (uae_u16)w);
        !          2131: 
        !          2132:     /* write the word to our displayable memory */
        !          2133:     write_gfx_word(addr, (uae_u16)w);
        !          2134: }
        !          2135: 
        !          2136: static void REGPARAM2 gfxmem_bput (uaecptr addr, uae_u32 b)
        !          2137: {
        !          2138:     addr -= gfxmem_start & gfxmem_mask;
        !          2139:     addr &= gfxmem_mask;
        !          2140:     gfxmemory[addr] = b;
        !          2141: 
        !          2142:     /* write the byte to our displayable memory */
        !          2143:     write_gfx_byte(addr, (uae_u8)b);
        !          2144: }
        !          2145: 
        !          2146: static int REGPARAM2 gfxmem_check (uaecptr addr, uae_u32 size)
        !          2147: {
        !          2148:     addr -= gfxmem_start & gfxmem_mask;
        !          2149:     addr &= gfxmem_mask;
        !          2150:     return (addr + size) < gfxmem_size;
        !          2151: }
        !          2152: 
        !          2153: static uae_u8 REGPARAM2 *gfxmem_xlate (uaecptr addr)
        !          2154: {
        !          2155:     addr -= gfxmem_start & gfxmem_mask;
        !          2156:     addr &= gfxmem_mask;
        !          2157:     return gfxmemory + addr;
        !          2158: }
        !          2159: 
        !          2160: addrbank gfxmem_bank = {
        !          2161:     gfxmem_lget, gfxmem_wget, gfxmem_bget,
        !          2162:     gfxmem_lput, gfxmem_wput, gfxmem_bput,
        !          2163:     gfxmem_xlate, gfxmem_check
        !          2164: };
        !          2165: 
        !          2166: static int resolution_compare (const void *a, const void *b)
        !          2167: {
        !          2168:     struct PicassoResolution *ma = (struct PicassoResolution *)a;
        !          2169:     struct PicassoResolution *mb = (struct PicassoResolution *)b;
        !          2170:     if (ma->res.width > mb->res.width)
        !          2171:        return -1;
        !          2172:     if (ma->res.width < mb->res.width)
        !          2173:        return 1;
        !          2174:     if (ma->res.height > mb->res.height)
        !          2175:        return -1;
        !          2176:     if (ma->res.height < mb->res.height)
        !          2177:        return 1;
        !          2178:     return ma->depth - mb->depth;
        !          2179: }
        !          2180: /* Call this function first, near the beginning of code flow
        !          2181:  * NOTE: Don't stuff it in InitGraphics() which seems reasonable...
        !          2182:  * Instead, put it in customreset() for safe-keeping.  */
        !          2183: void InitPicasso96 (void)
        !          2184: {
        !          2185:     static int first_time = 1;
        !          2186: 
        !          2187:     if (first_time) {
        !          2188:        int i;
        !          2189: 
        !          2190:        for (i = 0; i < 256; i++) {
        !          2191:            p2ctab[i][0] = (((i & 128) ? 0x01000000 : 0)
        !          2192:                            | ((i & 64) ? 0x010000 : 0)
        !          2193:                            | ((i & 32) ? 0x0100 : 0)
        !          2194:                            | ((i & 16) ? 0x01 : 0));
        !          2195:            p2ctab[i][1] = (((i & 8) ? 0x01000000 : 0)
        !          2196:                            | ((i & 4) ? 0x010000 : 0)
        !          2197:                            | ((i & 2) ? 0x0100 : 0)
        !          2198:                            | ((i & 1) ? 0x01 : 0));
        !          2199:        }
        !          2200: #if 0
        !          2201:        /* If we have some gfxmem settings, then we want Picasso96 support */
        !          2202:        if (gfxmem_size > 0) {
        !          2203:            gfxmem_mask = gfxmem_size - 1;
        !          2204:            gfxmemory = (uae_u8 *)xmalloc (gfxmem_size);
        !          2205:            map_banks(&gfxmem_bank, 0x800, gfxmem_size >> 16);
        !          2206:        }
        !          2207: #endif
        !          2208:        memset(&picasso96_state, 0, sizeof(struct picasso96_state_struct));
        !          2209:        mode_count = DX_FillResolutions (&picasso96_pixel_format);
        !          2210:        qsort (DisplayModes, mode_count, sizeof (struct PicassoResolution),
        !          2211:               resolution_compare);
        !          2212: 
        !          2213:        for (i = 0; i < mode_count; i++) {
        !          2214:            sprintf(DisplayModes[i].name, "%dx%d, %d-bit, %d Hz",
        !          2215:                    DisplayModes[i].res.width, DisplayModes[i].res.height,
        !          2216:                    DisplayModes[i].depth * 8, DisplayModes[i].refresh);
        !          2217:            switch (DisplayModes[i].depth) {
        !          2218:             case 1:
        !          2219:                if (DisplayModes[i].res.width > chunky.width)
        !          2220:                    chunky.width = DisplayModes[i].res.width;
        !          2221:                if (DisplayModes[i].res.height > chunky.height)
        !          2222:                    chunky.height = DisplayModes[i].res.height;
        !          2223:                break;
        !          2224:             case 2:
        !          2225:                if (DisplayModes[i].res.width > hicolour.width)
        !          2226:                    hicolour.width = DisplayModes[i].res.width;
        !          2227:                if (DisplayModes[i].res.height > hicolour.height)
        !          2228:                    hicolour.height = DisplayModes[i].res.height;
        !          2229:                break;
        !          2230:             case 3:
        !          2231:                if (DisplayModes[i].res.width > truecolour.width)
        !          2232:                    truecolour.width = DisplayModes[i].res.width;
        !          2233:                if (DisplayModes[i].res.height > truecolour.height)
        !          2234:                    truecolour.height = DisplayModes[i].res.height;
        !          2235:                break;
        !          2236:             case 4:
        !          2237:                if (DisplayModes[i].res.width > alphacolour.width)
        !          2238:                    alphacolour.width = DisplayModes[i].res.width;
        !          2239:                if (DisplayModes[i].res.height > alphacolour.height)
        !          2240:                    alphacolour.height = DisplayModes[i].res.height;
        !          2241:                break;
        !          2242:            }
        !          2243:        }
        !          2244:        ShowSupportedResolutions();
        !          2245: 
        !          2246:        first_time = 0;
        !          2247:     }
        !          2248: 
        !          2249:     if (gfxmem_size > 0) {
        !          2250:        memset(&picasso96_state, 0, sizeof(struct picasso96_state_struct));
        !          2251:     }
        !          2252: }
        !          2253: 
        !          2254: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.