Annotation of generator/main/vdp.c, revision 1.1

1.1     ! root        1: /* Generator is (c) James Ponder, 1997-2001 http://www.squish.net/generator/ */
        !             2: 
        !             3: /* video display processor emulation */
        !             4: 
        !             5: /* for dma 'bytes per line' stuff we use 'memory to vram' figures as a baseline
        !             6:    and double the number of real bytes for 'vram copy' in order to adjust to
        !             7:    our model; also there is a subtraction of one for vram fill to compensate
        !             8:    there too - probably being far too picky and it isn't exactly perfect
        !             9:    anyway */
        !            10: 
        !            11: /* to do: fix F flag in status register */
        !            12: 
        !            13: #include <stdlib.h>
        !            14: #include <stdio.h>
        !            15: #include <string.h>
        !            16: 
        !            17: #include "generator.h"
        !            18: #include "vdp.h"
        !            19: #include "cpu68k.h"
        !            20: #include "ui.h"
        !            21: #include "event.h"
        !            22: 
        !            23: #undef DEBUG_VDP
        !            24: #undef DEBUG_VDPDMA
        !            25: #undef DEBUG_VDPDATA
        !            26: #undef DEBUG_VDPCRAM
        !            27: 
        !            28: /*** variables externed ***/
        !            29: 
        !            30: unsigned int vdp_event;
        !            31: unsigned int vdp_vislines;
        !            32: unsigned int vdp_visstartline;
        !            33: unsigned int vdp_visendline;
        !            34: unsigned int vdp_totlines;
        !            35: unsigned int vdp_framerate;
        !            36: unsigned int vdp_clock;
        !            37: unsigned int vdp_68kclock;
        !            38: unsigned int vdp_clksperline_68k;
        !            39: unsigned int vdp_oddframe = 0;   /* odd/even frame */
        !            40: unsigned int vdp_vblank = 0;     /* set during vertical blanking */
        !            41: unsigned int vdp_hblank = 0;     /* set during horizontal blanking */
        !            42: unsigned int vdp_line = 0;       /* current line number */
        !            43: unsigned int vdp_vsync = 0;      /* a vsync just happened */
        !            44: unsigned int vdp_dmabusy = 0;    /* dma busy flag */
        !            45: unsigned int vdp_pal = 0;        /* set for pal mode */
        !            46: unsigned int vdp_overseas = 1;   /* set for overseas model */
        !            47: unsigned int vdp_layerB  = 1;    /* flag */
        !            48: unsigned int vdp_layerBp = 1;    /* flag */
        !            49: unsigned int vdp_layerA  = 1;    /* flag */
        !            50: unsigned int vdp_layerAp = 1;    /* flag */
        !            51: unsigned int vdp_layerW  = 1;    /* flag */
        !            52: unsigned int vdp_layerWp = 1;    /* flag */
        !            53: unsigned int vdp_layerH  = 1;    /* flag */
        !            54: unsigned int vdp_layerS  = 1;    /* flag */
        !            55: unsigned int vdp_layerSp = 1;    /* flag */
        !            56: uint8 vdp_cram[LEN_CRAM];
        !            57: uint8 vdp_vsram[LEN_VSRAM];
        !            58: uint8 vdp_vram[LEN_VRAM];
        !            59: uint8 vdp_cramf[LEN_CRAM/2];
        !            60: unsigned int vdp_event_start;
        !            61: unsigned int vdp_event_vint;
        !            62: unsigned int vdp_event_hint;
        !            63: unsigned int vdp_event_hdisplay;
        !            64: unsigned int vdp_event_end;
        !            65: signed int vdp_nextevent = 0;
        !            66: sint32 vdp_dmabytes = 0;            /* bytes left in DMA - must be fixed size */
        !            67: signed int vdp_hskip_countdown = 0; /* actual countdown */
        !            68: uint16 vdp_address; /* address for data/dma transfers */
        !            69: t_code vdp_code;    /* code number for data/dma transfers CD3-CD0 */
        !            70: unsigned int vdp_ctrlflag; /* set inbetween ctrl writes */
        !            71: uint16 vdp_first;   /* first word of address set */
        !            72: uint16 vdp_second;  /* second word of address set */
        !            73: 
        !            74: /*** global variables ***/
        !            75: 
        !            76: uint8 vdp_reg[25];
        !            77: static int vdp_collision;  /* set during a sprite collision */
        !            78: static int vdp_overflow;   /* set when too many sprites in one line */
        !            79: static int vdp_fifofull;   /* set when write fifo full */
        !            80: static int vdp_fifoempty;  /* set when write fifo empty */
        !            81: static int vdp_complex;    /* set when simple routines can't cope */
        !            82: 
        !            83: /*** forward references ***/
        !            84: 
        !            85: void vdp_ramcopy_vram(int type);
        !            86: void vdp_dma_vramcopy(void);
        !            87: void vdp_dma_fill(uint8 data);
        !            88: void vdp_showregs(void);
        !            89: void vdp_describe(void);
        !            90: void vdp_eventinit(void);
        !            91: void vdp_layer_simple(unsigned int layer, unsigned int priority,
        !            92:                      uint8 *fielddata, unsigned int lineoffset);
        !            93: inline void vdp_plotcell(uint8 *patloc, uint8 palette, uint8 flags,
        !            94:                         uint8 *cellloc, unsigned int lineoffset);
        !            95: void vdp_sprites(unsigned int line, uint8 *pridata, uint8 *outdata);
        !            96: inline void vdp_spritelayer(unsigned int line, uint8 *spritedata,
        !            97:                            uint8 *pridata, uint8 *linedata,
        !            98:                            unsigned int priority);
        !            99: int vdp_sprite_simple(unsigned int priority, uint8 *framedata,
        !           100:                      unsigned int lineoffset, unsigned int number,
        !           101:                      uint8 *spritelist, uint8 *sprite);
        !           102: void vdp_sprites_simple(unsigned int priority, uint8 *framedata,
        !           103:                         unsigned int lineoffset);
        !           104: void vdp_shadow_simple(uint8 *framedata, unsigned int lineoffset);
        !           105: void vdp_window(unsigned int line, unsigned int priority, uint8 *linedata);
        !           106: void vdp_newlayer(unsigned int line, uint8 *pridata, uint8 *outdata,
        !           107:                   unsigned int layer);
        !           108: void vdp_newwindow(unsigned int line, uint8 *pridata, uint8 *outdata);
        !           109: 
        !           110: #define PRIBIT_LAYERB 0
        !           111: #define PRIBIT_LAYERA 1
        !           112: #define PRIBIT_SPRITE 2
        !           113: 
        !           114: /*** vdp_init - initialise this sub-unit ***/
        !           115: 
        !           116: int vdp_init(void)
        !           117: {
        !           118:   vdp_reset();
        !           119:   return 0;
        !           120: }
        !           121: 
        !           122: /*** vdp_setupvideo - setup parameters dependant on vdp_pal ***/
        !           123: 
        !           124: void vdp_setupvideo(void)
        !           125: {
        !           126:   int v30 = (vdp_reg[1] & 1<<3) ? 1 : 0;
        !           127: 
        !           128:   if (!vdp_pal && v30)
        !           129:     ui_err("Impossible VDP mode - vertical 30 cell NTSC");
        !           130: 
        !           131:   vdp_clock = vdp_pal ? 53200000 : 53693100; /* What speed is the PAL clock? */
        !           132:   vdp_68kclock = vdp_clock / 7;
        !           133:   vdp_vislines = v30 ? 240 : 224;
        !           134:   vdp_visstartline = v30 ? 46 : (vdp_pal ? 54 : 19);
        !           135:   vdp_visendline = vdp_visstartline + vdp_vislines;
        !           136:   vdp_totlines = vdp_pal ? 312 : 262;
        !           137:   vdp_framerate = vdp_pal ? 50 : 60;
        !           138:   vdp_clksperline_68k = (vdp_68kclock/vdp_framerate/vdp_totlines);
        !           139: }
        !           140: 
        !           141: /*** vdp_softreset - soft reset ***/
        !           142: 
        !           143: void vdp_softreset(void)
        !           144: {
        !           145:   /* a soft reset involves resetting the cpu so we need to reset the
        !           146:      vdp event timers */
        !           147:   vdp_eventinit();
        !           148: }
        !           149: 
        !           150: /*** vdp_reset - reset vdp sub-unit ***/
        !           151: 
        !           152: void vdp_reset(void)
        !           153: {
        !           154:   int i;
        !           155: 
        !           156:   /* clear registers */
        !           157: 
        !           158:   for (i = 0; i < 25; i++)
        !           159:     vdp_reg[i] = 0;
        !           160: 
        !           161:   /* set PAL/NTSC variables */
        !           162: 
        !           163:   vdp_setupvideo();
        !           164:   vdp_vblank = 0;
        !           165:   vdp_hblank = 0;
        !           166:   vdp_oddframe = 0;
        !           167:   vdp_collision = 0;
        !           168:   vdp_overflow = 0;
        !           169:   vdp_vsync = 0;
        !           170:   vdp_fifofull = 0;
        !           171:   vdp_fifoempty = 0;
        !           172:   vdp_ctrlflag = 0;
        !           173: 
        !           174:   memset(vdp_cram, 0, LEN_CRAM);
        !           175:   memset(vdp_vsram, 0, LEN_VSRAM);
        !           176:   memset(vdp_vram, 0, LEN_VRAM);
        !           177: 
        !           178:   /* clear CRAM */
        !           179: 
        !           180:   for (i = 0; i < 64; i++) {
        !           181:     (vdp_cram+i*2)[0] = (i & 7)<<1;
        !           182:     (vdp_cram+i*2)[1] = (i & 7)<<5 | (i & 7)<<1;
        !           183:     vdp_cramf[i] = 1;
        !           184:   }
        !           185:   vdp_eventinit();
        !           186:   LOG_VERBOSE(("VDP: totlines = %d (%s)", vdp_totlines, vdp_pal ?
        !           187:                "PAL" : "NTSC"));
        !           188: }
        !           189: 
        !           190: uint16 vdp_status(void)
        !           191: {
        !           192:   uint16 ret;
        !           193: 
        !           194:   /* bit      meaning (when set)
        !           195:    * 0        0:ntsc 1:pal
        !           196:    * 1        dma busy
        !           197:    * 2        during h blanking
        !           198:    * 3        during v blanking
        !           199:    * 4        frame in interlace mode - 0:even 1:odd
        !           200:    * 5        collision happened between non-zero pixels in two sprites
        !           201:    * 6        too many sprites in one line
        !           202:    * 7        v interrupt has happened
        !           203:    * 8        write fifo full
        !           204:    * 9        write fifo empty
        !           205:    * 10-15 are next word on bus, i.e. next word in ROM - CM
        !           206:    */
        !           207:   ret = vdp_pal | vdp_dmabusy<<1 | vdp_hblank<<2 | vdp_vblank<<3 |
        !           208:     vdp_oddframe<<4 | vdp_collision<<5 | vdp_overflow<<6 | vdp_vsync<<7 |
        !           209:     vdp_fifofull<<8 | vdp_fifoempty<<9;
        !           210: 
        !           211: #ifdef DEBUG_VDP
        !           212:   if (vdp_collision)
        !           213:     LOG_VERBOSE(("%08X Collision read", vdp_collision));
        !           214: #endif
        !           215: 
        !           216:   vdp_vsync = vdp_collision = vdp_overflow = 0;
        !           217:   vdp_ctrlflag = 0; /* Charles MacDonald - so he claims ;) */
        !           218: 
        !           219:   LOG_DEBUG1(("%08X STATUS READ %02X", regs.pc, ret));
        !           220: 
        !           221:   return (ret);
        !           222: }
        !           223: 
        !           224: void vdp_storectrl(uint16 data)
        !           225: {
        !           226:   uint8 reg;
        !           227:   uint8 regdata;
        !           228: 
        !           229:   if (!vdp_ctrlflag) {
        !           230:     if ((data & 0xE000) == 0x8000) {
        !           231:       /* register set */
        !           232:       reg = (data>>8) & 31;
        !           233:       regdata = data & 255;
        !           234:       if (reg > 24) {
        !           235:         LOG_NORMAL(("%08X [VDP] Invalid register (%d)", regs.pc,
        !           236:                      ((data>>8) & 31)));
        !           237:         return;
        !           238:       }
        !           239:       vdp_reg[reg] = regdata;
        !           240:       vdp_code = 0;
        !           241: #ifdef DEBUG_VDP
        !           242:       LOG_VERBOSE(("%08X [VDP] Register %d set to %04X", regs.pc,
        !           243:                   reg, regdata));
        !           244: #endif
        !           245:       return;
        !           246:     } else {
        !           247:       vdp_ctrlflag = 1;
        !           248:       vdp_first = data;
        !           249:       return;
        !           250:     }
        !           251:   } else {
        !           252:     vdp_second = data;
        !           253:     vdp_ctrlflag = 0;
        !           254:     vdp_code = ((vdp_first>>14) & 3) | ((data>>2) & (3<<2));
        !           255:     vdp_address = (vdp_first & 0x3FFF) | (data<<14 & 0xC000);
        !           256: 
        !           257:     if ((data & 1<<7) && (vdp_reg[1] & 1<<4)) { /* CD5 - DMA ? */
        !           258:       if (vdp_dmabusy) {
        !           259:         vdp_dmabusy = 1; /* null statement to avoid gcc warnings */
        !           260:         LOG_DEBUG1(("DMA initiation during DMA!"));
        !           261:       }
        !           262:       /* CD4 - not read - need to verify */
        !           263:       vdp_dmabusy = 1;
        !           264:       switch((vdp_reg[23] >> 6) & 3) {
        !           265:       case 0:
        !           266:       case 1: /* ram to vram */
        !           267:         switch (vdp_code) {
        !           268:         case 1: /* ram copy to vram */
        !           269:           vdp_ramcopy_vram(0);
        !           270:           break;
        !           271:         case 3: /* ram copy to cram */
        !           272:           vdp_ramcopy_vram(1);
        !           273:           break;
        !           274:         case 5: /* ram copy to vsram */
        !           275:           vdp_ramcopy_vram(2);
        !           276:           break;
        !           277:         default: /* undefined */
        !           278:           LOG_NORMAL(("%08X [VDP] start of type %d to address %X",
        !           279:                      regs.pc, vdp_code, vdp_address));
        !           280:           break;
        !           281:         }
        !           282:         vdp_dmabusy = 0; /* 68k was frozen */
        !           283:         break;
        !           284:       case 2: /* VRAM fill */
        !           285:         /* later folks */
        !           286:         break;
        !           287:       case 3: /* VRAM copy */
        !           288:         vdp_dma_vramcopy();
        !           289:         /* vdp_dmabusy is cleared when vdp_dmabytes is empty */
        !           290:         break;
        !           291:       }
        !           292:     }
        !           293:   }
        !           294: }
        !           295: 
        !           296: void vdp_ramcopy_vram_obsolete(int type)
        !           297: {
        !           298:   uint16 length = vdp_reg[19] | vdp_reg[20]<<8;
        !           299:   uint8 srcbank = vdp_reg[23];
        !           300:   uint16 srcoffset = vdp_reg[21] | vdp_reg[22]<<8;
        !           301:   uint8 increment = vdp_reg[15];
        !           302:   uint16 *srcmemory;
        !           303:   uint16 data;
        !           304:   uint8 *memory;
        !           305:   uint16 length_t;
        !           306:   uint16 vdp_address_t;
        !           307:   uint32 vdp_address_mask;
        !           308: 
        !           309:   /* VRAM (type 0): reads are word-wide, writes are byte-wide */
        !           310:   /* CRAM (type 1) WSRAM (type 2): reads are word-wide, writes are byte-wide */
        !           311: 
        !           312:   if (srcbank & 1<<6) {
        !           313:     /* this is a ram source - note altered beast uses E00000 upwards */
        !           314:     srcmemory = (uint16 *)cpu68k_ram;
        !           315:     srcoffset&= 0x7fff;
        !           316: #ifdef DEBUG_VDP
        !           317:     LOG_VERBOSE(("%08X [VDP] ramcopy from RAM offset %08X type=%d "
        !           318:                 "vdpaddr=%08X length=%d",
        !           319:                 regs.pc, srcoffset*2, type, vdp_address, length));
        !           320: #endif
        !           321:   } else {
        !           322:     /* this is a rom source - each bank is 128k, srcoffset is in words */
        !           323:     srcmemory = (uint16 *)(cpu68k_rom + srcbank*0x20000);
        !           324: #ifdef DEBUG_VDP
        !           325:     LOG_VERBOSE(("%08X [VDP] ramcopy from ROM offset %08X type=%d "
        !           326:                 "vdpaddr=%08X length=%d",
        !           327:                 regs.pc, srcbank*0x20000+srcoffset*2, type, vdp_address,
        !           328:                 length));
        !           329: #endif
        !           330:   }
        !           331: 
        !           332:   switch(type) {
        !           333:   case 0:
        !           334:     memory = vdp_vram;
        !           335:     vdp_address_mask = LEN_VRAM-1;
        !           336:     break;
        !           337:   case 1:
        !           338:     length&= 0xff; /* maybe this or maybe we just stop at the end */
        !           339:     memory = vdp_cram;
        !           340:     vdp_address_mask = LEN_CRAM-1;
        !           341:     length_t = length;
        !           342:     vdp_address_t = vdp_address & vdp_address_mask;
        !           343:     for(; length_t; length_t--) {
        !           344:       vdp_cramf[vdp_address_t>>1] = 1;
        !           345:       vdp_address_t+= increment;
        !           346:       vdp_address_t&= vdp_address_mask;
        !           347:     }
        !           348:     break;
        !           349:   case 2:
        !           350:     length&= 0xff; /* maybe this or maybe we just stop at the end */
        !           351:     memory = vdp_vsram;
        !           352:     vdp_address_mask = 255;
        !           353:     if (vdp_address + (length * increment) > LEN_VSRAM) {
        !           354:       LOG_CRITICAL(("%08X [VDP] write to out of bounds vsram addr=$%X "
        !           355:                    "len=$%X inc=$%X end=$%X", regs.pc, vdp_address,
        !           356:                    length, increment, LEN_VSRAM));
        !           357:     }      
        !           358:     break;
        !           359:   default:
        !           360:     LOG_NORMAL(("%08X [VDP] Bad type %d", regs.pc, type));
        !           361:     return;
        !           362:   }
        !           363:   vdp_address_t = vdp_address & vdp_address_mask;
        !           364:   for(; length; length--) {
        !           365:     data = LOCENDIAN16(srcmemory[srcoffset]);
        !           366: #ifdef DEBUG_VDPDMA
        !           367:     /*
        !           368:       LOG_VERBOSE(("%08X [VDP] data %04X (ram/rom+2*%04X) -> %04X",
        !           369:       regs.pc, data, srcoffset, vdp_address_t));
        !           370:     */
        !           371: #endif
        !           372:     memory[vdp_address_t] = data>>8;
        !           373:     memory[vdp_address_t+1] = data & 0xff;
        !           374:     srcoffset+= 1;
        !           375:     vdp_address_t+= increment;
        !           376:     vdp_address_t&= vdp_address_mask;
        !           377:   }
        !           378:   /* don't think about writing vdp_address_t into registers - T2 is a good
        !           379:      example of something that doesn't like that */
        !           380: }
        !           381: 
        !           382: void vdp_ramcopy_vram(int type)
        !           383: {
        !           384:   uint16 length = vdp_reg[19] | vdp_reg[20]<<8;
        !           385:   uint8 srcbank = vdp_reg[23];
        !           386:   uint16 srcoffset = vdp_reg[21] | vdp_reg[22]<<8;
        !           387:   uint8 increment = vdp_reg[15];
        !           388:   uint16 *srcmemory;
        !           389:   uint16 srcmask;
        !           390:   uint16 data;
        !           391:   unsigned int i;
        !           392: 
        !           393: #ifdef DEBUG_VDP
        !           394:   LOG_VERBOSE(("%08X [VDP] VRAM copy from source %08X "
        !           395:                "vdpaddr=%08X length=%d",
        !           396:                regs.pc, (srcbank*0x10000+srcoffset)*2, vdp_address, length));
        !           397: #endif
        !           398: 
        !           399:   if (srcbank & 1<<6) {
        !           400:     srcmemory = (uint16 *)cpu68k_ram;
        !           401:     srcmask = 0x7fff; /* 32k words = 64k */
        !           402:   } else {
        !           403:     srcmemory = (uint16 *)(cpu68k_rom + srcbank*0x20000);
        !           404:     srcmask = 0xffff; /* 64k words = 128k */
        !           405:   }
        !           406:   for (i = 0; i < length; i++) {
        !           407:     data = LOCENDIAN16(srcmemory[srcoffset & srcmask]);
        !           408:     switch (type) {
        !           409:     case 0: /* VRAM */
        !           410:       vdp_vram[vdp_address] = data>>8;
        !           411:       vdp_vram[vdp_address ^ 1] = data & 0xff;
        !           412:       break;
        !           413:     case 1: /* CRAM */
        !           414:       vdp_cram[vdp_address & 0x7e] = data>>8;
        !           415:       vdp_cram[(vdp_address & 0x7e) | 1] = data & 0xff;
        !           416:       vdp_cramf[vdp_address>>1] = 1;
        !           417:       break;
        !           418:     case 2: /* VSRAM */
        !           419:       if ((vdp_address & 0x7e) < LEN_VSRAM) {
        !           420:         vdp_vsram[vdp_address & 0x7e] = data>>8;
        !           421:         vdp_vsram[(vdp_address & 0x7e) | 1] = data & 0xff;
        !           422:       }
        !           423:       break;
        !           424:     }
        !           425:     srcoffset+=1;
        !           426:     vdp_address+= increment;
        !           427:   }
        !           428:   vdp_reg[19] = 0;
        !           429:   vdp_reg[20] = 0;
        !           430:   vdp_reg[22] = (srcoffset >> 8) & 0xff;
        !           431:   vdp_reg[21] = srcoffset & 0xff;
        !           432:   /* vram sends bytes, cram/vsram send words so are twice as efficient */
        !           433:   event_freeze(type == 0 ? length*2 : length);
        !           434: }
        !           435: 
        !           436: void vdp_dma_vramcopy()
        !           437: {
        !           438:   uint32 length = vdp_reg[19] | vdp_reg[20]<<8;
        !           439:   uint8 increment = vdp_reg[15];
        !           440:   uint16 srcaddr = vdp_reg[21] | vdp_reg[22]<<8;
        !           441:   unsigned int i;
        !           442: 
        !           443:   if (length == 0) {
        !           444:     LOG_NORMAL(("%08X [VDP] Warning - length of 0 used in vram copy"));
        !           445:     length = 0x10000; /* could be 0xffff */
        !           446:   }
        !           447: 
        !           448: #ifdef DEBUG_VDPDMA
        !           449:   LOG_VERBOSE(("%08X [VDP] COPY length %04X dstaddr %08X inc %02X "
        !           450:                "srcaddr %04X", regs.pc, length, vdp_address, increment,
        !           451:                srcaddr));
        !           452: #endif
        !           453: 
        !           454:   for (i = 0; i < length; i++) {
        !           455:     vdp_vram[vdp_address] = vdp_vram[srcaddr++];
        !           456:     vdp_address+= increment;
        !           457:   }
        !           458: 
        !           459:   vdp_reg[19] = 0;
        !           460:   vdp_reg[20] = 0;
        !           461:   vdp_reg[22] = (srcaddr >> 8) & 0xff;
        !           462:   vdp_reg[21] = srcaddr & 0xff;
        !           463:   vdp_dmabytes = length*2; /* factor of 2 vram copy to vram fill (p36) */
        !           464: }
        !           465: 
        !           466: void vdp_dma_fill(uint8 data)
        !           467: {
        !           468:   uint16 length = vdp_reg[19] | vdp_reg[20]<<8;
        !           469:   uint8 increment = vdp_reg[15];
        !           470:   unsigned int screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !           471:   unsigned int i;
        !           472: 
        !           473:   if (increment != 1 && increment != 2)
        !           474:     LOG_NORMAL(("VDP fill used with strange increment %d", increment));
        !           475: 
        !           476:   for (i = 0; i < length; i++) {
        !           477:     vdp_vram[vdp_address] = data;
        !           478:     vdp_address+= increment; /* 16 bit wrap */
        !           479:   }
        !           480:   vdp_reg[19] = 0;
        !           481:   vdp_reg[20] = 0;
        !           482:   vdp_dmabytes = length+1; /* extra byte used (see p36) */
        !           483: }
        !           484: 
        !           485: uint16 vdp_fetchdata_obsolete(void)
        !           486: {
        !           487:   uint8 *memory;
        !           488:   uint32 size;
        !           489:   uint16 data;
        !           490: 
        !           491:   switch(vdp_code) {
        !           492:   case cd_vram_fetch:
        !           493: #ifdef DEBUG_VDPDATA
        !           494:     LOG_VERBOSE(("%08X [VDP] VRAM fetch from address %X", regs.pc,
        !           495:                 vdp_address));
        !           496: #endif
        !           497:     memory = vdp_vram;
        !           498:     size = LEN_VRAM;
        !           499:     break;
        !           500:   case cd_vsram_fetch:
        !           501: #ifdef DEBUG_VDPDATA
        !           502:     LOG_VERBOSE(("%08X [VDP] VSRAM fetch from address %X",
        !           503:                 regs.pc, vdp_address));
        !           504: #endif
        !           505:     memory = vdp_vsram;
        !           506:     size = LEN_VSRAM;
        !           507:     break;
        !           508:   case cd_cram_fetch:
        !           509: #ifdef DEBUG_VDPDATA
        !           510:     LOG_VERBOSE(("%08X [VDP] CRAM fetch from address %X", regs.pc,
        !           511:                 vdp_address));
        !           512: #endif
        !           513:     memory = vdp_cram;
        !           514:     size = LEN_CRAM;
        !           515:     break;
        !           516:   default:
        !           517:     LOG_NORMAL(("%08X [VDP] Fetch in invalid mode %d", regs.pc,
        !           518:                  vdp_code));
        !           519:     return 0;
        !           520:   }
        !           521:   if (vdp_address>=size) {
        !           522:     LOG_VERBOSE(("%08X [VDP] Address (%08X) out of bounds (%08X)",
        !           523:                 regs.pc, vdp_address, size));
        !           524:   }
        !           525:   data = LOCENDIAN16(*(uint16 *)(memory+(vdp_address & ~1)));
        !           526: #ifdef DEBUG_VDPDATA
        !           527:   LOG_VERBOSE(("%08X [VDP] Fetch %04X from %08X", regs.pc, data,
        !           528:                vdp_address & ~1));
        !           529: #endif
        !           530:   vdp_address+= vdp_reg[15];
        !           531:   vdp_ctrlflag = 0;
        !           532:   return data;
        !           533: }
        !           534: 
        !           535: void vdp_storedata(uint16 data)
        !           536: {
        !           537:   uint16 address;
        !           538:   uint16 sdata;
        !           539: 
        !           540:   if (vdp_ctrlflag) {
        !           541:     LOG_NORMAL(("%08X [VDP] Unterminated ctrl setting %04X/%04X", regs.pc,
        !           542:                vdp_first, vdp_second));
        !           543:     vdp_storectrl(vdp_second);
        !           544:   }
        !           545: 
        !           546:   switch(vdp_code) {
        !           547:   case cd_vram_store:
        !           548:     sdata = (vdp_address & 1) ? SWAP16(data) : data; /* only for VRAM */
        !           549:     *(uint16 *)(vdp_vram+(vdp_address & 0xfffe)) = LOCENDIAN16(sdata);
        !           550:     break;
        !           551:   case cd_cram_store:
        !           552:     address = vdp_address & 0x7e; /* address lines used */
        !           553:     *(uint16 *)(vdp_cram+address) = LOCENDIAN16(data);
        !           554:     vdp_cramf[address>>1] = 1;
        !           555:     break;
        !           556:   case cd_vsram_store:
        !           557:     address = vdp_address & 0x7e; /* address lines used */
        !           558:     if (address < LEN_VSRAM)
        !           559:       *(uint16 *)(vdp_vsram+address) = LOCENDIAN16(data);
        !           560:     break;
        !           561:   default: /* undefined */
        !           562:     LOG_NORMAL(("%08X [VDP] Bad word store to %08X of type %d data = %04X",
        !           563:                regs.pc, vdp_address, vdp_code, data));
        !           564:     break;
        !           565:   }
        !           566:   vdp_address+= vdp_reg[15]; /* 16 bit wrap */
        !           567: 
        !           568:   if (vdp_dmabusy) {
        !           569:     if (vdp_code == 1)
        !           570:       /* other vdp_codes consume time but don't result in fills */
        !           571:       /* vdp_dmabusy is cleared when vdp_dmabytes is empty */
        !           572:       vdp_dma_fill((data >> 8) & 0xff);
        !           573:   }
        !           574: }
        !           575: 
        !           576: uint16 vdp_fetchdata(void)
        !           577: {
        !           578:   uint16 address;
        !           579:   uint16 data;
        !           580: 
        !           581:   if (vdp_ctrlflag) {
        !           582:     LOG_NORMAL(("%08X [VDP] Unterminated ctrl setting %04X/%04X", regs.pc,
        !           583:                vdp_first, vdp_second));
        !           584:     vdp_storectrl(vdp_second);
        !           585:   }
        !           586: 
        !           587:   switch(vdp_code) {
        !           588:   case cd_vram_fetch:
        !           589:     data = LOCENDIAN16(*(uint16 *)(vdp_vram+(vdp_address & 0xfffe)));
        !           590:     break;
        !           591:   case cd_cram_fetch:
        !           592:     address = vdp_address & 0x7e; /* address lines used */
        !           593:     data = LOCENDIAN16(*(uint16 *)(vdp_cram+address));
        !           594:     break;
        !           595:   case cd_vsram_fetch:
        !           596:     address = vdp_address & 0x7e; /* address lines used */
        !           597:     if (address < LEN_VSRAM)
        !           598:       data = LOCENDIAN16(*(uint16 *)(vdp_vsram+address));
        !           599:     else
        !           600:       data = 0; /* tests show this range appears random (although I'm sure it
        !           601:                   isn't) */
        !           602:     break;
        !           603:   default: /* undefined */
        !           604:     /* reading in write mode suspends 68000 on a real machine */
        !           605:     LOG_NORMAL(("%08X [VDP] Bad word fetch of %08X of type %d",
        !           606:                regs.pc, vdp_address, vdp_code));
        !           607:     data = 0;
        !           608:     break;
        !           609:   }
        !           610:   vdp_address+= vdp_reg[15]; /* 16 bit wrap */
        !           611:   return data;
        !           612: }
        !           613: 
        !           614: #define LINEDATA(offset, value, palette, priority) \
        !           615: if (value) { \
        !           616:   linedata[offset] = (palette)*16 + value; \
        !           617: } else if (priority) { \
        !           618:   linedata[offset] = (linedata[offset] & 63); \
        !           619: }
        !           620: 
        !           621: #define LINEDATASPR(offset, value, palette, priority) \
        !           622: if (value) { \
        !           623:   if (outdata[offset] < 62) \
        !           624:     vdp_collision = 1; \
        !           625:   if (priority) \
        !           626:     pridata[offset]|= 1<<PRIBIT_SPRITE; \
        !           627:   else \
        !           628:     pridata[offset]&= ~(1<<PRIBIT_SPRITE); \
        !           629:   outdata[offset] = (palette)*16 + value; \
        !           630: }
        !           631: 
        !           632: #define LINEDATALAYER(offset, value, palette, priority) \
        !           633:   if (priority) \
        !           634:     pridata[offset]|= layer ? 1<<PRIBIT_LAYERB : 1<<PRIBIT_LAYERA; \
        !           635:   if (value) \
        !           636:     outdata[offset] = (palette)*16 + value; \
        !           637:   else \
        !           638:     outdata[offset] = 0;
        !           639: 
        !           640: void vdp_sprites(unsigned int line, uint8 *pridata, uint8 *outdata)
        !           641: {
        !           642:   uint8 interlace = (vdp_reg[12]>>1) & 3;
        !           643:   uint8 *spritelist = vdp_vram + ((vdp_reg[5] & 0x7F)<<9);
        !           644:   t_spriteinfo si[128]; /* 128 - max sprites supported per line */
        !           645:   unsigned int sprites;
        !           646:   unsigned int idx;
        !           647:   int i;
        !           648:   uint8 link;
        !           649:   uint8 *sprite = spritelist;
        !           650:   int plotter; /* flag */
        !           651:   unsigned int screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !           652:   unsigned int maxspl = (vdp_reg[12] & 1) ? 20 : 16; /* max sprs/line */
        !           653:   unsigned int cells;
        !           654:   uint8 loops = 0;
        !           655: 
        !           656:   for (idx = 0; loops < 255 && idx < maxspl; loops++) {
        !           657:     link = sprite[3] & 0x7F;
        !           658:     si[idx].sprite = sprite;
        !           659:     if (interlace == 3)
        !           660:       si[idx].vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x3FF) - 0x100;
        !           661:     else
        !           662:       si[idx].vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x1FF) - 0x080;
        !           663:     if ((signed int)line < si[idx].vpos)
        !           664:       goto next;
        !           665:     si[idx].vsize = 1+(sprite[2] & 3);
        !           666:     if (interlace == 3)
        !           667:       si[idx].vsize<<= 1;
        !           668:     si[idx].vmax = si[idx].vpos + si[idx].vsize*8;
        !           669:     if ((signed int)line >= si[idx].vmax)
        !           670:       goto next;
        !           671:     si[idx].hpos = (LOCENDIAN16(*(uint16 *)(sprite+6)) & 0x1FF) - 0x80;
        !           672:     si[idx].hsize = 1+((sprite[2]>>2) & 3);
        !           673:     si[idx].hplot = si[idx].hsize;
        !           674:     si[idx].hmax = si[idx].hpos + si[idx].hsize*8;
        !           675:     idx++;
        !           676:   next:
        !           677:     if (!link)
        !           678:       break;
        !           679:     sprite = spritelist + (link<<3);
        !           680: 
        !           681:   }
        !           682:   if (idx < 1)
        !           683:     return;
        !           684:   sprites = idx;
        !           685:   plotter = 1;
        !           686:   cells = (vdp_reg[12] & 1) ? 40 : 32; /* 320 or 256 pixels */
        !           687:   /* loop masking */
        !           688:   for (i = 0; i < (signed int)sprites; i++) {
        !           689:     if (plotter == 0) {
        !           690:       sprites = i;
        !           691:       break;
        !           692:     }
        !           693:     if (si[i].hpos == -128) {
        !           694:       /* mask sprite - but does it? */
        !           695:       if (i > 0) {
        !           696:         /* is there a higher priority sprite? */
        !           697:         if (si[i-1].vpos <= (signed int)line &&
        !           698:             si[i-1].vmax > (signed int)line) {
        !           699:           /* match, mask time */
        !           700:           plotter = 0;
        !           701:         }
        !           702:       } else {
        !           703:         /* higest priority sprite, so mask */
        !           704:         plotter = 0;
        !           705:       }
        !           706:       si[i].hplot = 0;
        !           707:     }
        !           708:     if (si[i].hpos == -127) {
        !           709:       LOG_VERBOSE(("Warning: Use of hpos = 1 in plotter"));
        !           710:       plotter = 1;
        !           711:     }
        !           712:     if (cells >= si[i].hplot) {
        !           713:       cells-= si[i].hplot;
        !           714:     } else {
        !           715:       si[i].hplot = cells; /* only room for this many */
        !           716:       cells = 0;
        !           717:     }
        !           718:   }    
        !           719: 
        !           720:   {
        !           721:     sint16 hpos, vpos;
        !           722:     uint16 hsize, vsize, hplot;
        !           723:     sint16 hmax, vmax;
        !           724:     uint16 cellinfo;
        !           725:     uint16 pattern;
        !           726:     uint8 palette;
        !           727:     uint8 *cellline;
        !           728:     uint32 data;
        !           729:     uint8 pixel;
        !           730:     uint8 priority;
        !           731:     int j, k;
        !           732: 
        !           733:     /* loop around sprites until end of list marker or no more */
        !           734:     for (i = sprites-1; i >= 0; i--) {
        !           735:       hpos = si[i].hpos;
        !           736:       vpos = si[i].vpos;
        !           737:       vsize = si[i].vsize; /* doubled when in interlace mode */
        !           738:       hsize = si[i].hsize;
        !           739:       hmax = si[i].hmax;
        !           740:       vmax = si[i].vmax;
        !           741:       hplot = si[i].hplot; /* number of cells to plot for this sprite */
        !           742:       cellinfo = LOCENDIAN16(*(uint16 *)(si[i].sprite+4));
        !           743:       pattern = cellinfo & 0x7FF;
        !           744:       palette = (cellinfo >> 13) & 3;
        !           745:       priority = (cellinfo >> 15) & 1;
        !           746: 
        !           747:       cellline = vdp_vram + ((interlace == 3) ? (pattern<<6) : (pattern<<5));
        !           748:       if (cellinfo & 1<<12) /* vertical flip */
        !           749:         cellline+= (vmax-line-1)*4;
        !           750:       else
        !           751:         cellline+= (line-vpos)*4;
        !           752:       for (k = 0; k < hsize && hplot--; k++) {
        !           753:         if (hpos > -8 && hpos < 0) {
        !           754:           if (cellinfo & 1<<11) {
        !           755:             /* horizontal flip */
        !           756:             data = LOCENDIAN32(*(uint32 *)(cellline+
        !           757:                                           (hsize-k*2-1)*(vsize<<5)));
        !           758:             data>>= (-hpos)*4; /* get first pixel in bottom 4 bits */
        !           759:             for (j = 0; j < 8+hpos; j++) {
        !           760:               pixel = data & 15;
        !           761:               LINEDATASPR(j, pixel, palette, priority);
        !           762:               data>>= 4;
        !           763:             }
        !           764:           } else {
        !           765:             data = LOCENDIAN32(*(uint32 *)cellline);
        !           766:             data<<= (-hpos)*4; /* get first pixel in top 4 bits */
        !           767:             for (j = 0; j < 8+hpos; j++) {
        !           768:               pixel = (data>>28) & 15;
        !           769:               LINEDATASPR(j, pixel, palette, priority);
        !           770:               data<<= 4;
        !           771:             }
        !           772:           }
        !           773:         } else if (hpos >= 0 && hpos <= (signed int)(screencells-1)*8) {
        !           774:           if (cellinfo & 1<<11) {
        !           775:             /* horizontal flip */
        !           776:             data = LOCENDIAN32(*(uint32 *)(cellline+
        !           777:                                           (hsize-k*2-1)*(vsize<<5)));
        !           778:             for (j = 0; j < 8; j++) {
        !           779:               pixel = data & 15;
        !           780:               LINEDATASPR(hpos+j, pixel, palette, priority);
        !           781:               data>>= 4;
        !           782:             }
        !           783:           } else {
        !           784:             data = LOCENDIAN32(*(uint32 *)cellline);
        !           785:             for (j = 0; j < 8; j++) {
        !           786:               pixel = (data>>28) & 15;
        !           787:               LINEDATASPR(hpos+j, pixel, palette, priority);
        !           788:               data<<= 4;
        !           789:             }
        !           790:           }
        !           791:         } else if (hpos > (signed int)(screencells-1)*8 &&
        !           792:                   hpos < (signed int)screencells*8) {
        !           793:           if (cellinfo & 1<<11) {
        !           794:             /* horizontal flip */
        !           795:             data = LOCENDIAN32(*(uint32 *)(cellline+
        !           796:                                           (hsize-k*2-1)*(vsize<<5)));
        !           797:             for (j = 0; j < (signed int)(screencells*8 - hpos); j++) {
        !           798:               pixel = data & 15;
        !           799:               LINEDATASPR(hpos+j, pixel, palette, priority);
        !           800:               data>>= 4;
        !           801:             }
        !           802:           } else {
        !           803:             data = LOCENDIAN32(*(uint32 *)cellline);
        !           804:             for (j = 0; j < (signed int)(screencells*8 - hpos); j++) {
        !           805:               pixel = (data>>28) & 15;
        !           806:               LINEDATASPR(hpos+j, pixel, palette, priority);
        !           807:               data<<= 4;
        !           808:             }
        !           809:           }
        !           810:         }
        !           811:         cellline+= vsize<<5; /* 32 bytes per cell (note vsize is doubled
        !           812:                                when interlaced) */
        !           813:         hpos+= 8;
        !           814:       }
        !           815:     }
        !           816:   }
        !           817: }
        !           818: 
        !           819: inline void vdp_spritelayer(unsigned int line, uint8 *spritedata,
        !           820:                            uint8 *pridata, uint8 *linedata,
        !           821:                            unsigned int priority)
        !           822: {
        !           823:   int i;
        !           824:   
        !           825:   if (vdp_reg[12] & 1<<3) { /* s/ten = 1 */
        !           826:     for (i = 0; i < 320; i++) {
        !           827:       if (pridata[i] == priority) {
        !           828:         if (spritedata[i]) {
        !           829:           if (spritedata[i] == 62) { /* pal=3, val=14 */
        !           830:             linedata[i] = (linedata[i] & 63) + 64;
        !           831:           } else if (spritedata[i] == 63) { /* pal=3, val=15 */
        !           832:             linedata[i] = (linedata[i] & 63) + 128;
        !           833:           } else {
        !           834:             linedata[i] = spritedata[i];
        !           835:           }
        !           836:         }
        !           837:       }
        !           838:     }
        !           839:   } else {
        !           840:     for (i = 0; i < 320; i++) {
        !           841:       if (pridata[i] == priority) {
        !           842:         if (spritedata[i]) {
        !           843:           linedata[i] = spritedata[i];
        !           844:         }
        !           845:       }
        !           846:     }
        !           847:   }
        !           848: }
        !           849: 
        !           850: /* layer 0 = A (top), layer 1 = B (bottom) */
        !           851: 
        !           852: void vdp_newlayer(unsigned int line, uint8 *pridata, uint8 *outdata,
        !           853:                  unsigned int layer)
        !           854: {
        !           855:   int i, j;
        !           856:   uint8 hsize = vdp_reg[16] & 3;
        !           857:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
        !           858:   uint8 hmode = vdp_reg[11] & 3;
        !           859:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
        !           860:   uint16 vramoffset = (layer ? ((vdp_reg[4] & 7) << 13) :
        !           861:                       ((vdp_reg[2] & (7<<3)) << 10));
        !           862:   uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset);
        !           863:   uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10)
        !           864:                                   + vdp_vram + layer*2);
        !           865:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !           866:   uint16 hwidth, vwidth, vmask, hoffset, voffset;
        !           867:   uint16 cellinfo;
        !           868:   uint8 *pattern;
        !           869:   uint32 data;
        !           870:   uint8 palette;
        !           871:   uint8 pixel;
        !           872:   uint8 winvpos;
        !           873:   uint8 priority;
        !           874:   int interlace = (vdp_reg[12] >> 1) & 3;
        !           875:   int realline = interlace ? line >> 1 : line;
        !           876: 
        !           877:   if (layer == 0) {
        !           878:     int vcell = realline >> 3;
        !           879:     int topbottom = vdp_reg[18] & 0x80;
        !           880:     int winvpos = vdp_reg[18] & 0x1f;
        !           881:     int leftright = vdp_reg[17] & 0x80;
        !           882:     int winhpos = vdp_reg[17] & 0x1f;
        !           883: 
        !           884:     /* sometimes the window covers the whole line, so we skip layer A for
        !           885:        that bit - for lines where layer A appears even for just one cell we
        !           886:        plot the entire line - would it be worth improving this? */
        !           887: 
        !           888:     if (topbottom ? (vcell >= winvpos) : (vcell < winvpos))
        !           889:       return; /* window is on the whole line */
        !           890: 
        !           891:     /* it could be that the vdp is in such a state that there is no whole line
        !           892:        part to the window, but reg[17] is either 00 or 1F, meaning that
        !           893:        infact there is (this is one way of turning on/off window) in which
        !           894:        case we really should optimise this case otherwise we could be
        !           895:        drawing layer A pointlessly as window will just clobber all our work) */
        !           896:        
        !           897:     if (leftright ? (winhpos == 0) : (winhpos >= (screencells<<1)))
        !           898:       return; /* window is on the whole line */
        !           899:   }
        !           900: 
        !           901:   /* isn't this bug fixed now? */
        !           902:   /* BUG: layer A is still displayed left/right when window is on,
        !           903:      only apparent with high-priority layer A and low-priority window */
        !           904: 
        !           905:   /* select horizontal scrolling offset based on mode */
        !           906: 
        !           907:   switch(hmode) {
        !           908:   case 0: /* full screen */
        !           909:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF;
        !           910:     break;
        !           911:   case 2: /* cell scroll */
        !           912:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(realline & ~7)])) & 0x3FF;
        !           913:     break;
        !           914:   case 3: /* line scroll */
        !           915:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*realline])) & 0x3FF;
        !           916:     break;
        !           917:   default:
        !           918:     LOG_NORMAL(("prohibited HSCR/LSCR"));
        !           919:     hoffset = 0;
        !           920:     break;
        !           921:   }
        !           922:   hwidth = (hsize+1) << 5;
        !           923:   vwidth = ((vsize+1) << 5) * (interlace ? 2 : 1);
        !           924:   vmask = (vwidth << 3) - 1; /* to put offsets into range */
        !           925:   hoffset&= (hwidth << 3)-1; /* put offset in range */
        !           926:   voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & vmask;
        !           927:   cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+
        !           928:                          hwidth*((voffset>>3)>>(interlace ? 1 : 0))]);
        !           929:   /* 32 bytes per pattern or 64 in interlace mode */
        !           930:   pattern = vdp_vram + (((cellinfo & 2047)<<5) << (interlace ? 1 : 0));
        !           931:   /* now get correct line from pattern data */
        !           932:   switch (interlace) {
        !           933:   case 0: /* no interlace */
        !           934:   case 1: /* ?? */
        !           935:   case 2: /* ?? */
        !           936:     if (cellinfo & 1<<12) {
        !           937:       /* vertical flip */
        !           938:       pattern+= 4*(7-(voffset & 7));
        !           939:     } else {
        !           940:       /* no vertical flip */
        !           941:       pattern+= 4*(voffset & 7);
        !           942:     }
        !           943:     break;
        !           944:   case 3: /* interlace with double height cells */
        !           945:     if (cellinfo & 1<<12) {
        !           946:       /* vertical flip */
        !           947:       pattern+= 4*(15-(voffset & 15));
        !           948:     } else {
        !           949:       /* no vertical flip */
        !           950:       pattern+= 4*(voffset & 15);
        !           951:     }
        !           952:     break;
        !           953:   }
        !           954:   priority = (cellinfo >> 15) & 1;
        !           955:   palette = (cellinfo >> 13) & 3;
        !           956:   data = LOCENDIAN32(*(uint32 *)pattern);
        !           957:   if (cellinfo & 1<<11) {
        !           958:     /* horizontal flip */
        !           959:     data>>= (hoffset & 7)*4; /* get first pixel in bottom 4 bits */
        !           960:     for (i = 0; i < 8-(hoffset & 7); i++) {
        !           961:       pixel = data & 15;
        !           962:       LINEDATALAYER(i, pixel, palette, priority);
        !           963:       data>>= 4;
        !           964:     }
        !           965:   } else {
        !           966:     data<<= (hoffset & 7)*4; /* get first pixel in top 4 bits */
        !           967:     for (i = 0; i < 8-(hoffset & 7); i++) {
        !           968:       pixel = (data>>28) & 15;
        !           969:       LINEDATALAYER(i, pixel, palette, priority);
        !           970:       data<<= 4;
        !           971:     }
        !           972:   }
        !           973:   outdata+= 8-(hoffset & 7);
        !           974:   pridata+= 8-(hoffset & 7);
        !           975:   hoffset+= 8;
        !           976:   hoffset&= (hwidth*8)-1; /* put offset in range */
        !           977:   for (j = 1; j < screencells; j++) {
        !           978:     if (vmode) {
        !           979:       /* 2-cell scroll */
        !           980:       /* DEBUG DEBUG DEBUG awooga awooga */
        !           981:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
        !           982:           [(j&~1)+layer] )) & vmask;
        !           983:     } else {
        !           984:       /* full screen */
        !           985:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & vmask;
        !           986:     }
        !           987:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+
        !           988:                            hwidth*((voffset>>3)>>(interlace ? 1 : 0))]);
        !           989:     priority = (cellinfo >> 15) & 1;
        !           990:     /* printf("hoff: %04X voff: %04X hwid: %04X cell: %08X info: %04X\n",
        !           991:            hoffset, voffset, hwidth, (hoffset>>3)+hwidth*(voffset>>3),
        !           992:            cellinfo); */
        !           993:     /* printf("loc %08X cellinfo %08X\n",
        !           994:            (hoffset>>3)+hwidth*(voffset>>3),
        !           995:            cellinfo); */
        !           996:     palette = (cellinfo >> 13) & 3;
        !           997:     /* 32 bytes per pattern or 64 in interlace mode */
        !           998:     pattern = vdp_vram + (((cellinfo & 2047)<<5) << (interlace ? 1 : 0));
        !           999:     /* now get correct line from pattern data */
        !          1000:     switch (interlace) {
        !          1001:     case 0: /* no interlace */
        !          1002:     case 1: /* ?? */
        !          1003:     case 2: /* ?? */
        !          1004:       if (cellinfo & 1<<12) {
        !          1005:         /* vertical flip */
        !          1006:         pattern+= 4*(7-(voffset & 7));
        !          1007:       } else {
        !          1008:         /* no vertical flip */
        !          1009:         pattern+= 4*(voffset & 7);
        !          1010:       }
        !          1011:       break;
        !          1012:     case 3: /* interlace with double height cells */
        !          1013:       if (cellinfo & 1<<12) {
        !          1014:         /* vertical flip */
        !          1015:         pattern+= 4*(15-(voffset & 15));
        !          1016:       } else {
        !          1017:         /* no vertical flip */
        !          1018:         pattern+= 4*(voffset & 15);
        !          1019:       }
        !          1020:       break;
        !          1021:     }
        !          1022:     data = LOCENDIAN32(*(uint32 *)pattern);
        !          1023:     if (cellinfo & 1<<11) {
        !          1024:       /* horizontal flip */
        !          1025:       for (i = 0; i < 8; i++) {
        !          1026:         pixel = data & 15;
        !          1027:         LINEDATALAYER(i, pixel, palette, priority);
        !          1028:         data>>= 4;
        !          1029:       }
        !          1030:     } else {
        !          1031:       for (i = 0; i < 8; i++) {
        !          1032:         pixel = (data>>28) & 15;
        !          1033:         LINEDATALAYER(i, pixel, palette, priority);
        !          1034:         data<<= 4;
        !          1035:       }
        !          1036:     }
        !          1037:     outdata+= 8;
        !          1038:     pridata+= 8;
        !          1039:     hoffset+= 8;
        !          1040:     hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1041:   }
        !          1042:   if (hoffset & 7) {
        !          1043:     if (vmode) {
        !          1044:       /* 2-cell scroll - note use last offset, not next */
        !          1045:       /* DEBUG DEBUG DEBUG awooga awooga */
        !          1046:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
        !          1047:           [(screencells-2)+layer] )) & vmask;
        !          1048:     } else {
        !          1049:       /* full screen */
        !          1050:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & vmask;
        !          1051:     }
        !          1052:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+
        !          1053:                            hwidth*((voffset>>3)>>(interlace ? 1 : 0))]);
        !          1054:     priority = (cellinfo >> 15) & 1;
        !          1055:     palette = (cellinfo >> 13) & 3;
        !          1056:     /* 32 bytes per pattern or 64 in interlace mode */
        !          1057:     pattern = vdp_vram + (((cellinfo & 2047)<<5) << (interlace ? 1 : 0));
        !          1058:     /* now get correct line from pattern data */
        !          1059:     switch (interlace) {
        !          1060:     case 0: /* no interlace */
        !          1061:     case 1: /* ?? */
        !          1062:     case 2: /* ?? */
        !          1063:       if (cellinfo & 1<<12) {
        !          1064:         /* vertical flip */
        !          1065:         pattern+= 4*(7-(voffset & 7));
        !          1066:       } else {
        !          1067:         /* no vertical flip */
        !          1068:         pattern+= 4*(voffset & 7);
        !          1069:       }
        !          1070:       break;
        !          1071:     case 3: /* interlace with double height cells */
        !          1072:       if (cellinfo & 1<<12) {
        !          1073:         /* vertical flip */
        !          1074:         pattern+= 4*(15-(voffset & 15));
        !          1075:       } else {
        !          1076:         /* no vertical flip */
        !          1077:         pattern+= 4*(voffset & 15);
        !          1078:       }
        !          1079:       break;
        !          1080:     }
        !          1081:     data = LOCENDIAN32(*(uint32 *)pattern);
        !          1082:     if (cellinfo & 1<<11) {
        !          1083:       /* horizontal flip */
        !          1084:       for (i = 0; i < (hoffset & 7); i++) {
        !          1085:         pixel = data & 15;
        !          1086:         LINEDATALAYER(i, pixel, palette, priority);
        !          1087:         data>>= 4;
        !          1088:       }
        !          1089:     } else {
        !          1090:       for (i = 0; i < (hoffset & 7); i++) {
        !          1091:         pixel = (data>>28) & 15;
        !          1092:         LINEDATALAYER(i, pixel, palette, priority);
        !          1093:         data<<= 4;
        !          1094:       }
        !          1095:     }
        !          1096:   }
        !          1097: }
        !          1098: 
        !          1099: /* this function updates outdata/pridata which came from the layerA generation
        !          1100:    routines */
        !          1101: 
        !          1102: void vdp_newwindow(unsigned int line, uint8 *pridata, uint8 *outdata)
        !          1103: {
        !          1104:   uint16 *patterndata = (uint16 *)(vdp_vram + ((vdp_reg[3] & 0x3e) << 10));
        !          1105:   uint8 winhpos = vdp_reg[17] & 0x1f;
        !          1106:   uint8 winvpos = vdp_reg[18] & 0x1f;
        !          1107:   uint8 vcell = line / 8;
        !          1108:   uint8 hcell;
        !          1109:   uint8 voffset = line & 7;
        !          1110:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !          1111:   uint8 topbottom = vdp_reg[18] & 0x80;
        !          1112:   uint8 leftright = vdp_reg[17] & 0x80;
        !          1113:   uint8 patternshift = (vdp_reg[12] & 1) ? 6 : 5;
        !          1114:   uint16 cellinfo;
        !          1115:   uint8 *pattern;
        !          1116:   uint32 data;
        !          1117:   uint8 palette;
        !          1118:   uint8 pixel;
        !          1119:   unsigned int i;
        !          1120:   unsigned int wholeline = 0;
        !          1121:   uint8 priority;
        !          1122:   int layer = 0; /* for LINEDATALAYER macro */
        !          1123: 
        !          1124:   /* if topbottom is set then the wholeline part of the window is to the
        !          1125:      bottom, if it is clear then it is to the top
        !          1126:      in the other part of the window, if leftright is set then the window
        !          1127:      is on the right in this part of the screen
        !          1128:      this section below is repeated in the main renderline code, so that
        !          1129:      layerA is not unnecessarily calculated */
        !          1130: 
        !          1131:   if (topbottom ? (vcell >= winvpos) : (vcell < winvpos))
        !          1132:     wholeline = 1;
        !          1133: 
        !          1134:   if (!wholeline) {
        !          1135:     if (winhpos >= 20)
        !          1136:       winhpos = 20; /* 0x1F might be special? */
        !          1137:     if (leftright) {
        !          1138:       /* clear out priority bits on right of line (winhpos units of 16 pix */
        !          1139:       for (i = winhpos*4; i < 320/4; i++) /* winhpos units of 16 pix */
        !          1140:         ((uint32 *)pridata)[i]&= (0xffffffff - (0x01010101<<PRIBIT_LAYERA));
        !          1141:       memset(outdata+winhpos*16, 0, 320-(winhpos*16));
        !          1142:     } else {
        !          1143:       /* clear out priority bits on left of line (winhpos units of 16 pix) */
        !          1144:       for (i = 0; i < (unsigned int)(winhpos/4); i++)
        !          1145:         ((uint32 *)pridata)[i]&= (0xffffffff - (0x01010101<<PRIBIT_LAYERA));
        !          1146:       memset(outdata, 0, winhpos*16);
        !          1147:     }
        !          1148:   }
        !          1149:   for (hcell = 0; hcell < screencells; hcell++, outdata+=8, pridata+=8) {
        !          1150:     if (!wholeline) {
        !          1151:       if (leftright) {
        !          1152:         if ((hcell>>1) < winhpos)
        !          1153:           continue;
        !          1154:       } else {
        !          1155:         if ((hcell>>1) >= winhpos)
        !          1156:           continue;
        !          1157:       }
        !          1158:     }
        !          1159:     cellinfo = LOCENDIAN16(patterndata[vcell<<patternshift | hcell]);
        !          1160:     priority = (cellinfo >> 15) & 1;
        !          1161:     palette = (cellinfo >> 13) & 3;
        !          1162:     /* 32 bytes per pattern */
        !          1163:     pattern = vdp_vram + ((cellinfo & 2047)<<5); /* fix for interlace */
        !          1164:     if (cellinfo & 1<<12) {
        !          1165:       /* vertical flip */
        !          1166:       pattern+= 4*(7-(voffset & 7));
        !          1167:     } else {
        !          1168:       /* no vertical flip */
        !          1169:       pattern+= 4*(voffset & 7);
        !          1170:     }
        !          1171:     data = LOCENDIAN32(*(uint32 *)pattern);
        !          1172:     if (cellinfo & 1<<11) {
        !          1173:       /* horizontal flip */
        !          1174:       for (i = 0; i < 8; i++) {
        !          1175:         pixel = data & 15;
        !          1176:         LINEDATALAYER(i, pixel, palette, priority);
        !          1177:         data>>= 4;
        !          1178:       }
        !          1179:     } else {
        !          1180:       for (i = 0; i < 8; i++) {
        !          1181:         pixel = (data>>28) & 15;
        !          1182:         LINEDATALAYER(i, pixel, palette, priority);
        !          1183:         data<<= 4;
        !          1184:       }
        !          1185:     }
        !          1186:   } /* hcell */
        !          1187: }
        !          1188: 
        !          1189: inline void vdp_shadow(unsigned int line, uint8 *linedata)
        !          1190: {
        !          1191:   int i;
        !          1192:   
        !          1193:   /* this could be done 4 bytes at a time */
        !          1194:   for (i = 0; i < 320; i++)
        !          1195:     linedata[i] = (linedata[i] & 63) + 128;
        !          1196: }
        !          1197: 
        !          1198: void vdp_window(unsigned int line, unsigned int priority, uint8 *linedata)
        !          1199: {
        !          1200:   uint16 *patterndata = (uint16 *)(vdp_vram + ((vdp_reg[3] & 0x3e) << 10));
        !          1201:   uint8 winhpos = vdp_reg[17] & 0x1f;
        !          1202:   uint8 winvpos = vdp_reg[18] & 0x1f;
        !          1203:   uint8 vcell = line / 8;
        !          1204:   uint8 hcell;
        !          1205:   uint8 voffset = line & 7;
        !          1206:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !          1207:   uint8 topbottom = vdp_reg[18] & 0x80;
        !          1208:   uint8 leftright = vdp_reg[17] & 0x80;
        !          1209:   uint8 patternshift = (vdp_reg[12] & 1) ? 6 : 5;
        !          1210:   uint16 cellinfo;
        !          1211:   uint8 *pattern;
        !          1212:   uint32 data;
        !          1213:   uint8 palette;
        !          1214:   uint8 pixel;
        !          1215:   unsigned int i;
        !          1216:   unsigned int wholeline = 0;
        !          1217: 
        !          1218:   if (topbottom) {
        !          1219:     /* bottom part */
        !          1220:     /* Battle Tank sets winvpos to 0x1F and expects layer A to be off */
        !          1221:     if (winvpos == 0x1F || vcell >= winvpos)
        !          1222:       wholeline = 1;
        !          1223:   } else {
        !          1224:     /* top part */
        !          1225:     if (vcell < winvpos)
        !          1226:       wholeline = 1;
        !          1227:   }
        !          1228:   for (hcell = 0; hcell < screencells; hcell++, linedata+=8) {
        !          1229:     if (!wholeline) {
        !          1230:       if (leftright) {
        !          1231:         if ((hcell>>1) < winhpos)
        !          1232:           continue;
        !          1233:       } else {
        !          1234:         if ((hcell>>1) >= winhpos)
        !          1235:           continue;
        !          1236:       }
        !          1237:     }
        !          1238:     cellinfo = LOCENDIAN16(patterndata[vcell<<patternshift | hcell]);
        !          1239:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1240:       palette = (cellinfo >> 13) & 3;
        !          1241:       pattern = vdp_vram + ((cellinfo & 2047)<<5); /* 32 bytes per pattern */
        !          1242:       if (cellinfo & 1<<12) {
        !          1243:         /* vertical flip */
        !          1244:         pattern+= 4*(7-(voffset & 7));
        !          1245:       } else {
        !          1246:         /* no vertical flip */
        !          1247:         pattern+= 4*(voffset & 7);
        !          1248:       }
        !          1249:       data = LOCENDIAN32(*(uint32 *)pattern);
        !          1250:       if (cellinfo & 1<<11) {
        !          1251:         /* horizontal flip */
        !          1252:         for (i = 0; i < 8; i++) {
        !          1253:           pixel = data & 15;
        !          1254:           LINEDATA(i, pixel, palette, priority);
        !          1255:           data>>= 4;
        !          1256:         }
        !          1257:       } else {
        !          1258:         for (i = 0; i < 8; i++) {
        !          1259:           pixel = (data>>28) & 15;
        !          1260:           LINEDATA(i, pixel, palette, priority);
        !          1261:           data<<= 4;
        !          1262:         }
        !          1263:       }
        !          1264:     }
        !          1265:   } /* hcell */
        !          1266: }
        !          1267: 
        !          1268: void vdp_layer_interlace(unsigned int line, unsigned int layer,
        !          1269:                         unsigned int priority, uint8 *linedata)
        !          1270: {
        !          1271:   int i, j;
        !          1272:   uint8 hsize = vdp_reg[16] & 3;
        !          1273:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
        !          1274:   uint8 hmode = vdp_reg[11] & 3;
        !          1275:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
        !          1276:   uint16 vramoffset = (layer ? ((vdp_reg[4] & 7) << 13) :
        !          1277:                       ((vdp_reg[2] & (7<<3)) << 10));
        !          1278:   uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset);
        !          1279:   uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10)
        !          1280:                                   + vdp_vram + layer*2);
        !          1281:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !          1282:   uint16 hwidth, vwidth, hoffset, voffset;
        !          1283:   uint16 cellinfo;
        !          1284:   uint8 *pattern;
        !          1285:   uint32 data;
        !          1286:   uint8 palette;
        !          1287:   uint8 pixel;
        !          1288:   uint8 topbottom, leftright, winhpos, winvpos;
        !          1289: 
        !          1290:   if (layer == 0) {
        !          1291:     /* turn off A when window is on */
        !          1292:     topbottom = vdp_reg[18] & 0x80;
        !          1293:     leftright = vdp_reg[17] & 0x80;
        !          1294:     winhpos = vdp_reg[17] & 0x1f;
        !          1295:     winvpos = vdp_reg[18] & 0x1f;
        !          1296:     if (topbottom) {
        !          1297:       if ((line>>4) >= winvpos)
        !          1298:         return;
        !          1299:     } else {
        !          1300:       if ((line>>4) < winvpos)
        !          1301:         return;
        !          1302:     }
        !          1303:   }
        !          1304: 
        !          1305:   /* BUG: layer A is still displayed left/right when window is on,
        !          1306:      only apparent with high-priority layer A and low-priority window */
        !          1307: 
        !          1308:   switch(hmode) {
        !          1309:   case 0: /* full screen */
        !          1310:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF;
        !          1311:     break;
        !          1312:   case 2: /* cell scroll */
        !          1313:     /* interlace we use the actual line for the hscroll */
        !          1314:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*((line>>1) & ~7)])) & 0x3FF;
        !          1315:     break;
        !          1316:   case 3: /* line scroll */
        !          1317:     /* interlace we use the actual line for the hscroll */
        !          1318:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(line>>1)])) & 0x3FF;
        !          1319:     break;
        !          1320:   default:
        !          1321:     LOG_NORMAL(("prohibited HSCR/LSCR"));
        !          1322:     hoffset = 0;
        !          1323:     break;
        !          1324:   }
        !          1325:   hwidth = 32+hsize*32;
        !          1326:   vwidth = 32+vsize*32;
        !          1327:   hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1328:   voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF;
        !          1329:   voffset&= (vwidth*16)-1; /* put offset in range */
        !          1330: 
        !          1331:   cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]);
        !          1332:   if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1333:     palette = (cellinfo >> 13) & 3;
        !          1334:     pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */
        !          1335:     if (cellinfo & 1<<12) {
        !          1336:       /* vertical flip */
        !          1337:       pattern+= 4*(15-(voffset & 15));
        !          1338:     } else {
        !          1339:       /* no vertical flip */
        !          1340:       pattern+= 4*(voffset & 15);
        !          1341:     }
        !          1342:     data = LOCENDIAN32(*(uint32 *)pattern);
        !          1343:     if (cellinfo & 1<<11) {
        !          1344:       /* horizontal flip */
        !          1345:       data>>= (hoffset & 7)*4; /* get first pixel in bottom 4 bits */
        !          1346:       for (i = 0; i < 8-(hoffset & 7); i++) {
        !          1347:         pixel = data & 15;
        !          1348:         LINEDATA(i, pixel, palette, priority);
        !          1349:         data>>= 4;
        !          1350:       }
        !          1351:     } else {
        !          1352:       data<<= (hoffset & 7)*4; /* get first pixel in top 4 bits */
        !          1353:       for (i = 0; i < 8-(hoffset & 7); i++) {
        !          1354:         pixel = (data>>28) & 15;
        !          1355:         LINEDATA(i, pixel, palette, priority);
        !          1356:         data<<= 4;
        !          1357:       }
        !          1358:     }
        !          1359:   }
        !          1360:   linedata+= 8-(hoffset & 7);
        !          1361:   hoffset+= 8;
        !          1362:   hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1363:   for (j = 0; j < screencells-1; j++) {
        !          1364:     if (vmode) {
        !          1365:       /* 2-cell scroll */
        !          1366:       /* DEBUG DEBUG DEBUG awooga awooga */
        !          1367:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
        !          1368:                                     [2*(j>>1)+layer] )) & 0x7FF;
        !          1369:     } else {
        !          1370:       /* full screen */
        !          1371:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF;
        !          1372:     }
        !          1373:     voffset&= (vwidth*16)-1; /* put offset in range */
        !          1374:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]);
        !          1375:     /* printf("hoff: %04X voff: %04X hwid: %04X cell: %08X info: %04X\n",
        !          1376:            hoffset, voffset, hwidth, (hoffset>>3)+hwidth*(voffset>>4),
        !          1377:            cellinfo); */
        !          1378:     /* printf("loc %08X cellinfo %08X\n",
        !          1379:            (hoffset>>3)+hwidth*(voffset>>4),
        !          1380:            cellinfo); */
        !          1381:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1382:       palette = (cellinfo >> 13) & 3;
        !          1383:       pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */
        !          1384:       if (cellinfo & 1<<12) {
        !          1385:         /* vertical flip */
        !          1386:         pattern+= 4*(15-(voffset & 15));
        !          1387:       } else {
        !          1388:         /* no vertical flip */
        !          1389:         pattern+= 4*(voffset & 15);
        !          1390:       }
        !          1391:       data = LOCENDIAN32(*(uint32 *)pattern);
        !          1392:       if (cellinfo & 1<<11) {
        !          1393:         /* horizontal flip */
        !          1394:         for (i = 0; i < 8; i++) {
        !          1395:           pixel = data & 15;
        !          1396:           LINEDATA(i, pixel, palette, priority);
        !          1397:           data>>= 4;
        !          1398:         }
        !          1399:       } else {
        !          1400:         for (i = 0; i < 8; i++) {
        !          1401:           pixel = (data>>28) & 15;
        !          1402:           LINEDATA(i, pixel, palette, priority);
        !          1403:           data<<= 4;
        !          1404:         }
        !          1405:       }
        !          1406:     }
        !          1407:     linedata+= 8;
        !          1408:     hoffset+= 8;
        !          1409:     hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1410:   }
        !          1411:   if (hoffset & 7) {
        !          1412:     if (vmode) {
        !          1413:       /* 2-cell scroll - note use last offset, not next */
        !          1414:       /* DEBUG DEBUG DEBUG awooga awooga */
        !          1415:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
        !          1416:                                     [2*(j>>1)+layer] )) & 0x7FF;
        !          1417:     } else {
        !          1418:       /* full screen */
        !          1419:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF;
        !          1420:     }
        !          1421:     voffset&= (vwidth*16)-1; /* put offset in range */
        !          1422:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]);
        !          1423:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1424:       palette = (cellinfo >> 13) & 3;
        !          1425:       pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */
        !          1426:       if (cellinfo & 1<<12) {
        !          1427:         /* vertical flip */
        !          1428:         pattern+= 4*(15-(voffset & 15));
        !          1429:       } else {
        !          1430:         /* no vertical flip */
        !          1431:         pattern+= 4*(voffset & 15);
        !          1432:       }
        !          1433:       data = LOCENDIAN32(*(uint32 *)pattern);
        !          1434:       if (cellinfo & 1<<11) {
        !          1435:         /* horizontal flip */
        !          1436:         for (i = 0; i < (hoffset & 7); i++) {
        !          1437:           pixel = data & 15;
        !          1438:           LINEDATA(i, pixel, palette, priority);
        !          1439:           data>>= 4;
        !          1440:         }
        !          1441:       } else {
        !          1442:         for (i = 0; i < (hoffset & 7); i++) {
        !          1443:           pixel = (data>>28) & 15;
        !          1444:           LINEDATA(i, pixel, palette, priority);
        !          1445:           data<<= 4;
        !          1446:         }
        !          1447:       }
        !          1448:     }
        !          1449:     linedata+= 8;
        !          1450:   }
        !          1451: }
        !          1452: 
        !          1453: void vdp_renderline(unsigned int line, uint8 *linedata, unsigned int odd)
        !          1454: {
        !          1455:   int i;
        !          1456:   uint8 datablock[320*4];
        !          1457:   uint8 *data_sprite = datablock;
        !          1458:   uint8 *data_layerA = datablock + 320;
        !          1459:   uint8 *data_layerB = datablock + 320*2;
        !          1460:   uint8 *priorities = datablock + 320*3;
        !          1461:   uint8 bg = vdp_reg[7] & 63;
        !          1462:   unsigned int winvpos = vdp_reg[18] & 0x1f;
        !          1463:   unsigned int interlace = (vdp_reg[12] >> 1) & 3;
        !          1464: 
        !          1465:   memset(datablock, 0, sizeof(datablock));
        !          1466:   
        !          1467:   if ((vdp_reg[1] & 1<<6) == 0) {
        !          1468:     /* screen is disabled */
        !          1469:     for (i = 0; i < 320; i++)
        !          1470:       linedata[i] = bg;
        !          1471:     return;
        !          1472:   }
        !          1473: 
        !          1474:   if (vdp_layerS || vdp_layerSp)
        !          1475:     vdp_sprites(interlace ? (line*2+odd) : line, priorities, data_sprite);
        !          1476:   if (vdp_layerA || vdp_layerAp) {
        !          1477:     vdp_newlayer(interlace ? (line*2+odd) : line, priorities, data_layerA, 0);
        !          1478:     if (vdp_layerW || vdp_layerWp)
        !          1479:       vdp_newwindow(line, priorities, data_layerA);
        !          1480:   }
        !          1481:   if (vdp_layerB || vdp_layerBp)
        !          1482:     vdp_newlayer(interlace ? (line*2+odd) : line, priorities, data_layerB, 1);
        !          1483: 
        !          1484:   for (i = 0; i < 320; i++) {
        !          1485:     switch(priorities[i] | (vdp_reg[12] & 1<<3)) {
        !          1486:     case 0:                                        /* s/ten=0, B=0, A=0, S=0 */
        !          1487:       if (data_sprite[i])
        !          1488:         linedata[i] = data_sprite[i];
        !          1489:       else if (data_layerA[i])
        !          1490:         linedata[i] = data_layerA[i];
        !          1491:       else if (data_layerB[i])
        !          1492:         linedata[i] = data_layerB[i];
        !          1493:       else
        !          1494:         linedata[i] = bg;
        !          1495:       break;
        !          1496:     case 1:                                        /* s/ten=0, B=1, A=0, S=0 */
        !          1497:       if (data_layerB[i])
        !          1498:         linedata[i] = data_layerB[i];
        !          1499:       else if (data_sprite[i])
        !          1500:         linedata[i] = data_sprite[i];
        !          1501:       else if (data_layerA[i])
        !          1502:         linedata[i] = data_layerA[i];
        !          1503:       else
        !          1504:         linedata[i] = bg;
        !          1505:       break;
        !          1506:     case 2:                                        /* s/ten=0, B=0, A=1, S=0 */
        !          1507:       if (data_layerA[i])
        !          1508:         linedata[i] = data_layerA[i];
        !          1509:       else if (data_sprite[i])
        !          1510:         linedata[i] = data_sprite[i];
        !          1511:       else if (data_layerB[i])
        !          1512:         linedata[i] = data_layerB[i];
        !          1513:       else
        !          1514:         linedata[i] = bg;
        !          1515:       break;
        !          1516:     case 3:                                        /* s/ten=0, B=1, A=1, S=0 */
        !          1517:       if (data_layerA[i])
        !          1518:         linedata[i] = data_layerA[i];
        !          1519:       else if (data_layerB[i])
        !          1520:         linedata[i] = data_layerB[i];
        !          1521:       else if (data_sprite[i])
        !          1522:         linedata[i] = data_sprite[i];
        !          1523:       else
        !          1524:         linedata[i] = bg;
        !          1525:       break;
        !          1526:     case 4:                                        /* s/ten=0, B=0, A=0, S=1 */
        !          1527:       if (data_sprite[i])
        !          1528:         linedata[i] = data_sprite[i];
        !          1529:       else if (data_layerA[i])
        !          1530:         linedata[i] = data_layerA[i];
        !          1531:       else if (data_layerB[i])
        !          1532:         linedata[i] = data_layerB[i];
        !          1533:       else
        !          1534:         linedata[i] = bg;
        !          1535:       break;
        !          1536:     case 5:                                        /* s/ten=0, B=1, A=0, S=1 */
        !          1537:       if (data_sprite[i])
        !          1538:         linedata[i] = data_sprite[i];
        !          1539:       else if (data_layerB[i])
        !          1540:         linedata[i] = data_layerB[i];
        !          1541:       else if (data_layerA[i])
        !          1542:         linedata[i] = data_layerA[i];
        !          1543:       else
        !          1544:         linedata[i] = bg;
        !          1545:       break;
        !          1546:     case 6:                                        /* s/ten=0, B=0, A=1, S=1 */
        !          1547:       if (data_sprite[i])
        !          1548:         linedata[i] = data_sprite[i];
        !          1549:       else if (data_layerA[i])
        !          1550:         linedata[i] = data_layerA[i];
        !          1551:       else if (data_layerB[i])
        !          1552:         linedata[i] = data_layerB[i];
        !          1553:       else
        !          1554:         linedata[i] = bg;
        !          1555:       break;
        !          1556:     case 7:                                        /* s/ten=0, B=1, A=1, S=1 */
        !          1557:       if (data_sprite[i])
        !          1558:         linedata[i] = data_sprite[i];
        !          1559:       else if (data_layerA[i])
        !          1560:         linedata[i] = data_layerA[i];
        !          1561:       else if (data_layerB[i])
        !          1562:         linedata[i] = data_layerB[i];
        !          1563:       else
        !          1564:         linedata[i] = bg;
        !          1565:       break;
        !          1566:     case 8:                                        /* s/ten=1, B=0, A=0, S=0 */
        !          1567:       if (data_sprite[i]) {
        !          1568:         if (data_sprite[i] == 63) {                /* shadow operator */
        !          1569:           if (data_layerA[i])
        !          1570:             linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1571:           else if (data_layerB[i])
        !          1572:             linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1573:           else
        !          1574:             linedata[i] = bg | 128; /* shadow */
        !          1575:         } else if (data_sprite[i] == 62) {         /* highlight operator */
        !          1576:           if (data_layerA[i])
        !          1577:             linedata[i] = data_layerA[i]; /* normal */
        !          1578:           else if (data_layerB[i])
        !          1579:             linedata[i] = data_layerB[i]; /* normal */
        !          1580:           else
        !          1581:             linedata[i] = bg; /* normal */
        !          1582:         } else {
        !          1583:           linedata[i] = data_sprite[i] | 128; /* shadow */
        !          1584:         }
        !          1585:       } else {
        !          1586:         if (data_layerA[i])
        !          1587:           linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1588:         else if (data_layerB[i])
        !          1589:           linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1590:         else
        !          1591:           linedata[i] = bg | 128; /* shadow */
        !          1592:       }
        !          1593:       break;
        !          1594:     case 9:                                        /* s/ten=1, B=1, A=0, S=0 */
        !          1595:       if (data_layerB[i]) {
        !          1596:         linedata[i] = data_layerB[i]; /* normal */
        !          1597:       } else {
        !          1598:         if (data_sprite[i]) {
        !          1599:           if (data_sprite[i] == 63) {              /* shadow operator */
        !          1600:             if (data_layerA[i])
        !          1601:               linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1602:             else
        !          1603:               linedata[i] = bg | 128; /* shadow */
        !          1604:           } else if (data_sprite[i] == 62) {       /* highlight operator */
        !          1605:             if (data_layerA[i])
        !          1606:               linedata[i] = data_layerA[i] | 64; /* highlight */
        !          1607:             else
        !          1608:               linedata[i] = bg | 64; /* highlight */
        !          1609:           } else {
        !          1610:             linedata[i] = data_sprite[i]; /* normal */
        !          1611:           }
        !          1612:         } else {
        !          1613:           if (data_layerA[i])
        !          1614:             linedata[i] = data_layerA[i]; /* normal */
        !          1615:           else
        !          1616:             linedata[i] = bg; /* normal */
        !          1617:         }
        !          1618:       }
        !          1619:       break;
        !          1620:     case 10:                                       /* s/ten=1, B=0, A=1, S=0 */
        !          1621:       if (data_layerA[i]) {
        !          1622:         linedata[i] = data_layerA[i]; /* normal */
        !          1623:       } else {
        !          1624:         if (data_sprite[i]) {
        !          1625:           if (data_sprite[i] == 63) {              /* shadow operator */
        !          1626:             if (data_layerB[i])
        !          1627:               linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1628:             else
        !          1629:               linedata[i] = bg | 128; /* shadow */
        !          1630:           } else if (data_sprite[i] == 62) {       /* highlight operator */
        !          1631:             if (data_layerB[i])
        !          1632:               linedata[i] = data_layerB[i] | 64; /* highlight */
        !          1633:             else
        !          1634:               linedata[i] = bg | 64; /* highlight */
        !          1635:           } else {
        !          1636:             linedata[i] = data_sprite[i]; /* normal */
        !          1637:           }
        !          1638:         } else {
        !          1639:           if (data_layerB[i])
        !          1640:             linedata[i] = data_layerB[i]; /* normal */
        !          1641:           else
        !          1642:             linedata[i] = bg; /* normal */
        !          1643:         }
        !          1644:       }
        !          1645:       break;
        !          1646:     case 11:                                       /* s/ten=1, B=1, A=1, S=0 */
        !          1647:       if (data_layerA[i]) {
        !          1648:         linedata[i] = data_layerA[i]; /* normal */
        !          1649:       } else if (data_layerB[i]) {
        !          1650:         linedata[i] = data_layerB[i]; /* normal */
        !          1651:       } else if (data_sprite[i]) {
        !          1652:         if (data_sprite[i] == 63)                  /* shadow operator */
        !          1653:           linedata[i] = bg | 128; /* shadow */
        !          1654:         else if (data_sprite[i] == 62)             /* highlight operator */
        !          1655:           linedata[i] = bg | 64; /* highlight */
        !          1656:         else
        !          1657:           linedata[i] = data_sprite[i]; /* normal */
        !          1658:       } else {
        !          1659:         linedata[i] = bg; /* normal */
        !          1660:       }
        !          1661:       break;
        !          1662:     case 12:                                       /* s/ten=0, B=0, A=0, S=1 */
        !          1663:       if (data_sprite[i]) {
        !          1664:         if (data_sprite[i] == 63) {                /* shadow operator */
        !          1665:           if (data_layerA[i])
        !          1666:             linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1667:           else if (data_layerB[i])
        !          1668:             linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1669:           else
        !          1670:             linedata[i] = bg | 128; /* shadow */
        !          1671:         } else if (data_sprite[i] == 62) {         /* highlight operator */
        !          1672:           if (data_layerA[i])
        !          1673:             linedata[i] = data_layerA[i]; /* normal */
        !          1674:           else if (data_layerB[i])
        !          1675:             linedata[i] = data_layerB[i]; /* normal */
        !          1676:           else
        !          1677:             linedata[i] = bg; /* normal */
        !          1678:         } else {
        !          1679:           linedata[i] = data_sprite[i]; /* normal */
        !          1680:         }
        !          1681:       } else if (data_layerA[i]) {
        !          1682:         linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1683:       } else if (data_layerB[i]) {
        !          1684:         linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1685:       } else {
        !          1686:         linedata[i] = bg | 128; /* shadow */
        !          1687:       }
        !          1688:       break;
        !          1689:     case 13:                                       /* s/ten=1, B=1, A=0, S=1 */
        !          1690:       if (data_sprite[i]) {
        !          1691:         if (data_sprite[i] == 63) {                /* shadow operator */
        !          1692:           if (data_layerB[i])
        !          1693:             linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1694:           else if (data_layerA[i])
        !          1695:             linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1696:           else
        !          1697:             linedata[i] = bg | 128; /* shadow */
        !          1698:         } else if (data_sprite[i] == 62) {         /* highlight operator */
        !          1699:           if (data_layerB[i])
        !          1700:             linedata[i] = data_layerB[i] | 64; /* highlight */
        !          1701:           else if (data_layerA[i])
        !          1702:             linedata[i] = data_layerA[i] | 64; /* highlight */
        !          1703:           else
        !          1704:             linedata[i] = bg | 64; /* highlight */
        !          1705:         } else {
        !          1706:           linedata[i] = data_sprite[i]; /* normal */
        !          1707:         }
        !          1708:       } else if (data_layerB[i]) {
        !          1709:         linedata[i] = data_layerB[i]; /* normal */
        !          1710:       } else if (data_layerA[i]) {
        !          1711:         linedata[i] = data_layerA[i]; /* normal */
        !          1712:       }
        !          1713:       break;
        !          1714:     case 14:                                       /* s/ten=1, B=0, A=1, S=1 */
        !          1715:       if (data_sprite[i]) {
        !          1716:         if (data_sprite[i] == 63) {                /* shadow operator */
        !          1717:           if (data_layerA[i])
        !          1718:             linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1719:           else if (data_layerB[i])
        !          1720:             linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1721:           else
        !          1722:             linedata[i] = bg | 128; /* shadow */
        !          1723:         } else if (data_sprite[i] == 62) {         /* highlight operator */
        !          1724:           if (data_layerA[i])
        !          1725:             linedata[i] = data_layerA[i] | 64; /* highlight */
        !          1726:           else if (data_layerB[i])
        !          1727:             linedata[i] = data_layerB[i] | 64; /* highlight */
        !          1728:           else
        !          1729:             linedata[i] = bg | 64; /* highlight */
        !          1730:         } else {
        !          1731:           linedata[i] = data_sprite[i]; /* normal */
        !          1732:         }
        !          1733:       } else if (data_layerA[i]) {
        !          1734:         linedata[i] = data_layerA[i]; /* normal */
        !          1735:       } else if (data_layerB[i]) {
        !          1736:         linedata[i] = data_layerB[i]; /* normal */
        !          1737:       }
        !          1738:       break;
        !          1739:     case 15:                                       /* s/ten=1, B=1, A=1, S=1 */
        !          1740:       if (data_sprite[i]) {
        !          1741:         if (data_sprite[i] == 63) {                /* shadow operator */
        !          1742:           if (data_layerA[i])
        !          1743:             linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1744:           else if (data_layerB[i])
        !          1745:             linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1746:           else
        !          1747:             linedata[i] = bg | 128; /* shadow */
        !          1748:         } else if (data_sprite[i] == 62) {         /* highlight operator */
        !          1749:           if (data_layerA[i])
        !          1750:             linedata[i] = data_layerA[i] | 64; /* highlight */
        !          1751:           else if (data_layerB[i])
        !          1752:             linedata[i] = data_layerB[i] | 64; /* highlight */
        !          1753:           else
        !          1754:             linedata[i] = bg | 64; /* highlight */
        !          1755:         } else {
        !          1756:           linedata[i] = data_sprite[i]; /* normal */
        !          1757:         }
        !          1758:       } else if (data_layerA[i]) {
        !          1759:         linedata[i] = data_layerA[i]; /* normal */
        !          1760:       } else if (data_layerB[i]) {
        !          1761:         linedata[i] = data_layerB[i]; /* normal */
        !          1762:       }
        !          1763:       break;
        !          1764:     }
        !          1765:   }
        !          1766: }
        !          1767: 
        !          1768: void vdp_renderline_interlace2(unsigned int line, uint8 *linedata)
        !          1769: {
        !          1770:   int i;
        !          1771:   uint8 pridata[640];
        !          1772:   uint8 *spritedata = pridata + 320;
        !          1773: 
        !          1774:   memset(pridata, 0, 640);
        !          1775:   memset(linedata, vdp_reg[7] & 63, 320);
        !          1776: 
        !          1777:   if (vdp_reg[1] & 1<<6) {
        !          1778:     vdp_sprites(line, pridata, spritedata);
        !          1779:     ;
        !          1780:     if (vdp_layerB)
        !          1781:       vdp_layer_interlace(line, 1, 0, linedata);
        !          1782:     if (vdp_layerA)
        !          1783:       vdp_layer_interlace(line, 0, 0, linedata);
        !          1784:     /*
        !          1785:       if (vdp_layerW)
        !          1786:       vdp_window(line, 0, linedata);
        !          1787:     */
        !          1788:     if (vdp_layerH && (vdp_reg[12] & 1<<3))
        !          1789:       vdp_shadow(line, linedata);
        !          1790:     if (vdp_layerS)
        !          1791:       vdp_spritelayer(line, spritedata, pridata, linedata, 0);
        !          1792:     if (vdp_layerBp)
        !          1793:       vdp_layer_interlace(line, 1, 1, linedata);
        !          1794:     if (vdp_layerAp)
        !          1795:       vdp_layer_interlace(line, 0, 1, linedata);
        !          1796:     /*
        !          1797:       if (vdp_layerWp)
        !          1798:       vdp_window(line, 1, linedata);
        !          1799:     */
        !          1800:     if (vdp_layerSp)
        !          1801:       vdp_spritelayer(line, spritedata, pridata, linedata, 1);
        !          1802:   }
        !          1803: }
        !          1804: 
        !          1805: void vdp_renderframe(uint8 *framedata, unsigned int lineoffset)
        !          1806: {
        !          1807:   unsigned int i, line;
        !          1808:   uint32 background;
        !          1809:   unsigned int vertcells = vdp_reg[1] & 1<<3 ? 30 : 28;
        !          1810:   uint8 *linedata;
        !          1811: 
        !          1812:   /* fill in background */
        !          1813: 
        !          1814:   background = vdp_reg[7] & 63;
        !          1815:   background|= background<<8;
        !          1816:   background|= background<<16;
        !          1817: 
        !          1818:   for (line = 0; line < vertcells*8; line++) {
        !          1819:     linedata = framedata + line*lineoffset;
        !          1820:     for (i = 0; i < (320 / 4); i++) {
        !          1821:       ((uint32 *)linedata)[i] = background;
        !          1822:     }
        !          1823:   }
        !          1824: 
        !          1825:   if (vdp_reg[1] & 1<<6) {
        !          1826:     if (vdp_layerB)
        !          1827:       vdp_layer_simple(1, 0, framedata, lineoffset);
        !          1828:     if (vdp_layerA)
        !          1829:       vdp_layer_simple(0, 0, framedata, lineoffset);
        !          1830:     if (vdp_layerH && (vdp_reg[12] & 1<<3))
        !          1831:       vdp_shadow_simple(framedata, lineoffset);
        !          1832:     if (vdp_layerS)
        !          1833:       vdp_sprites_simple(0, framedata, lineoffset);
        !          1834:     if (vdp_layerBp)
        !          1835:       vdp_layer_simple(1, 1, framedata, lineoffset);
        !          1836:     if (vdp_layerAp)
        !          1837:       vdp_layer_simple(0, 1, framedata, lineoffset);
        !          1838:     if (vdp_layerSp)
        !          1839:       vdp_sprites_simple(1, framedata, lineoffset);
        !          1840:   }
        !          1841: }
        !          1842: 
        !          1843: void vdp_showregs(void)
        !          1844: {
        !          1845:   int i;
        !          1846: 
        !          1847:   for (i = 0; i < 25; i++) {
        !          1848:     printf("[%02d] %02X: ", i, vdp_reg[i]);
        !          1849:     switch(i) {
        !          1850:     case 0:
        !          1851:       printf("%s ", vdp_reg[0] & 1<<1 ? "HV-stop" : "HV-enable");
        !          1852:       printf("%s ", vdp_reg[0] & 1<<4 ? "HInt-enable" : "HInt-disable");
        !          1853:       break;
        !          1854:     case 1:
        !          1855:       printf("%s ", vdp_reg[1] & 1<<3 ? "30-cell" : "28-cell");
        !          1856:       printf("%s ", vdp_reg[1] & 1<<4 ? "DMA-enable" : "DMA-disable");
        !          1857:       printf("%s ", vdp_reg[1] & 1<<5 ? "VInt-enable" : "VInt-disable");
        !          1858:       printf("%s ", vdp_reg[1] & 1<<6 ? "Disp-enable" : "Disp-disable");
        !          1859:       break;
        !          1860:     case 2:
        !          1861:       printf("Scroll A @ %04X", (vdp_reg[2] & 0x38)<<10);
        !          1862:       break;
        !          1863:     case 3:
        !          1864:       printf("Window @ %04X", (vdp_reg[3] & 0x3E)<<10);
        !          1865:       break;
        !          1866:     case 4:
        !          1867:       printf("Scroll B @ %04X", (vdp_reg[4] & 7)<<13);
        !          1868:       break;
        !          1869:     case 5:
        !          1870:       printf("Sprites @ %04X", (vdp_reg[5] & 0x7F)<<9);
        !          1871:       break;
        !          1872:     case 7:
        !          1873:       printf("bgpal %d col %d", (vdp_reg[7]>>4 & 3), (vdp_reg[7] & 15));
        !          1874:       break;
        !          1875:     case 10:
        !          1876:       printf("hintreg %04X", vdp_reg[10]);
        !          1877:       break;
        !          1878:     case 11:
        !          1879:       printf("V-mode %d H-mode %d ", (vdp_reg[11]>>2) & 1, (vdp_reg[11] & 3));
        !          1880:       printf("%s", (vdp_reg[11] & 1<<3) ? "ExtInt-enable" : "ExtInt-disable");
        !          1881:       break;
        !          1882:     case 12:
        !          1883:       printf("Interlace %d ", (vdp_reg[12]>>1) & 3);
        !          1884:       printf("%s ", (vdp_reg[12] & 1<<0) ? "40-cell" : "32-cell");
        !          1885:       printf("%s ", (vdp_reg[12] & 1<<3) ? "Shadow-enable" : "Shadow-disable");
        !          1886:       break;
        !          1887:     case 13:
        !          1888:       printf("Scroll A @ %04X", (vdp_reg[13] & 0x3F)<<10);
        !          1889:       break;
        !          1890:     case 15:
        !          1891:       printf("Autoinc %d", vdp_reg[15]);
        !          1892:       break;
        !          1893:     case 16:
        !          1894:       printf("Vsize %d Hsize %d", (vdp_reg[16]>>4) & 3, (vdp_reg[16] & 3));
        !          1895:       break;
        !          1896:     case 17:
        !          1897:       printf("Window H %s ", (vdp_reg[17] & 1<<7) ? "right" : "left");
        !          1898:       printf("%d", vdp_reg[17] & 0x1F);
        !          1899:       break;
        !          1900:     case 18:
        !          1901:       printf("Window V %s ", (vdp_reg[18] & 1<<7) ? "lower" : "upper");
        !          1902:       printf("%d", vdp_reg[18] & 0x1F);
        !          1903:       break;
        !          1904:     case 19:
        !          1905:       printf("DMA-length-low %02X", vdp_reg[19]);
        !          1906:       break;
        !          1907:     case 20:
        !          1908:       printf("DMA-length-high %02X", vdp_reg[20]);
        !          1909:       break;
        !          1910:     case 21:
        !          1911:       printf("DMA-source-low %02X", vdp_reg[21]);
        !          1912:       break;
        !          1913:     case 22:
        !          1914:       printf("DMA-source-mid %02X", vdp_reg[22]);
        !          1915:       break;
        !          1916:     case 23:
        !          1917:       printf("DMA-source-high %02X", vdp_reg[23]);
        !          1918:       break;
        !          1919:     }
        !          1920:     printf("\n");
        !          1921:   }
        !          1922: }
        !          1923: 
        !          1924: void vdp_spritelist(void)
        !          1925: {
        !          1926:   uint8 *spritelist = vdp_vram + ((vdp_reg[5] & 0x7F)<<9);
        !          1927:   uint8 *sprite;
        !          1928:   uint8 link = 0;
        !          1929:   uint16 pattern;
        !          1930:   uint8 palette;
        !          1931:   uint16 cellinfo;
        !          1932:   sint16 vpos, hpos, vmax;
        !          1933:   uint8 vsize, hsize;
        !          1934: 
        !          1935:   LOG_REQUEST(("SPRITE DUMP: (base=vram+%X)",
        !          1936:                (vdp_reg[5] & 0x7f)<<9));
        !          1937:   do {
        !          1938:     sprite = spritelist + (link<<3);
        !          1939:     hpos = (LOCENDIAN16(*(uint16 *)(sprite+6)) & 0x1FF) - 0x80;
        !          1940:     vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x3FF) - 0x80;
        !          1941:     vsize = 1+(sprite[2] & 3);
        !          1942:     hsize = 1+((sprite[2]>>2) & 3);
        !          1943:     cellinfo = LOCENDIAN16(*(uint16 *)(sprite+4));
        !          1944:     pattern = cellinfo & 0x7FF;
        !          1945:     palette = (cellinfo >> 13) & 3;
        !          1946:     vmax = vpos + vsize*8;
        !          1947: 
        !          1948:     LOG_REQUEST(("Sprite %d @ %X", link,
        !          1949:                 (link<<3) | (vdp_reg[5] & 0x7f)<<9));
        !          1950:     LOG_REQUEST(("  Pos:  %d,%d", hpos, vpos));
        !          1951:     LOG_REQUEST(("  Size: %d,%d", hsize, vsize));
        !          1952:     LOG_REQUEST(("  Pri: %d, Pal: %d, Vflip: %d, Hflip: %d",
        !          1953:                 (cellinfo>>15 & 1), (cellinfo>>13 & 3), (cellinfo>>12 & 1),
        !          1954:                 (cellinfo>>11 & 1)));
        !          1955:     LOG_REQUEST(("  Pattern: %d (%x) @ vram+%X (%X if interlaced)",
        !          1956:                 (cellinfo & 0x7FF), (cellinfo & 0x7FF),
        !          1957:                (cellinfo & 0x7FF)*32, (cellinfo & 0x7FF)*32));
        !          1958:     link = sprite[3] & 0x7F;
        !          1959:   } while (link);
        !          1960: }
        !          1961: 
        !          1962: void vdp_describe(void)
        !          1963: {
        !          1964:   int layer;
        !          1965:   unsigned int line;
        !          1966:   uint32 o_patterndata, o_hscrolldata;
        !          1967:   uint16 *patterndata, *hscrolldata;
        !          1968:   uint8 hsize = vdp_reg[16] & 3;
        !          1969:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
        !          1970:   uint8 hmode = vdp_reg[11] & 3;
        !          1971:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
        !          1972:   uint16 hwidth, vwidth, hoffset, voffset, raw_hoffset;
        !          1973: 
        !          1974:   hwidth = 32+hsize*32;
        !          1975:   vwidth = 32+vsize*32;
        !          1976:   LOG_REQUEST(("VDP description:"));
        !          1977:   LOG_REQUEST(("  hsize = %d (ie. width=%d)", hsize, hwidth));
        !          1978:   LOG_REQUEST(("  vsize = %d (ie. width=%d)", vsize, vwidth));
        !          1979:   LOG_REQUEST(("  hmode = %d (0=full, 2=cell, 3=line)", hmode));
        !          1980:   LOG_REQUEST(("  vmode = %d (0=full, 1=2cell", vmode));
        !          1981: 
        !          1982:   for (layer = 0; layer < 2; layer++) {
        !          1983:     LOG_REQUEST(("  Layer %s:", layer == 0 ? "A" : "B"));
        !          1984:     o_patterndata = (layer == 0 ? ((vdp_reg[2] & 0x38)<<10) :
        !          1985:                     ((vdp_reg[4] & 7)<<13));
        !          1986:     o_hscrolldata = layer*2 + ((vdp_reg[13] & 63)<<10);
        !          1987:     LOG_REQUEST(("    Pattern data @ vram+%08X", o_patterndata));
        !          1988:     LOG_REQUEST(("    Hscroll data @ vram+%08X", o_hscrolldata));
        !          1989:     patterndata = (uint16 *)(vdp_vram + o_patterndata);
        !          1990:     hscrolldata = (uint16 *)(vdp_vram + o_hscrolldata);
        !          1991:     for (line = 0; line < vdp_vislines; line++) {
        !          1992:       switch(hmode) {
        !          1993:       case 0: /* full screen */
        !          1994:         hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF;
        !          1995:         break;
        !          1996:       case 2: /* cell scroll */
        !          1997:         hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(line & ~7)])) & 0x3FF;
        !          1998:         break;
        !          1999:       case 3: /* line scroll */
        !          2000:         hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*line])) & 0x3FF;
        !          2001:         break;
        !          2002:       default:
        !          2003:         LOG_REQUEST(("prohibited HSCR/LSCR on line %d", line));
        !          2004:         hoffset = 0;
        !          2005:         break;
        !          2006:       }
        !          2007:       raw_hoffset = hoffset;
        !          2008:       hoffset&= (hwidth*8)-1; /* put offset in range */
        !          2009:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x3FF;
        !          2010:       voffset&= (vwidth*8)-1; /* put offset in range */
        !          2011:       LOG_REQUEST(("     line %d: hoffset=%d=%d, voffset=%d, "
        !          2012:                   "firstcell=vram+%08X", line, raw_hoffset, hoffset, voffset,
        !          2013:                   o_patterndata+2*((hoffset>>3)+hwidth*(voffset>>3))));
        !          2014:     }
        !          2015:   }
        !          2016: }
        !          2017: 
        !          2018: void vdp_eventinit(void)
        !          2019: {
        !          2020:   /* Facts from documentation:
        !          2021:        H-Blank is 73.7 clock cycles long.
        !          2022:        The VDP settings are aquired 36 clocks after start of H-Blank.
        !          2023:        The display period is 413.3 clocks in duration.
        !          2024:        V-Int occurs 14.7us after H-Int (which is 112 clock cycles)
        !          2025:      Facts from clock data:
        !          2026:        One line takes 488 clocks (vdp_clksperline_68k)
        !          2027:      Assumptions: (not sure if these are true anymore)
        !          2028:        We 'approximate' and make H-Int occur at the same time as H-Blank.
        !          2029:        V-Blank starts at V-Int and ends at the start of line 0.
        !          2030: 
        !          2031:      vdp_event_start    = start of line, end of v-blank
        !          2032:      vdp_event_vint     = v-int time on line 224 (or 240)
        !          2033:                                 (112 clocks after h-int)
        !          2034:      vdp_event_hint     = h-int time at end of each line
        !          2035:      vdp_event_hdisplay = settings are aquired and current line displayed
        !          2036:      vdp_event_end      = end of line, end of h-blank
        !          2037: 
        !          2038:      Note that if the program stays in H-Int 224 longer than 112 clocks, V-Int
        !          2039:      is not supposed to occur due to the processor acknowledging the wrong
        !          2040:      interrupt from the VDP, thus programs disable H-Ints on 223 to prevent
        !          2041:      this problem.  We don't worry about this.
        !          2042:   */
        !          2043:   vdp_event = 0;
        !          2044:   vdp_event_start = 0;
        !          2045:   vdp_event_vint = 112-74;
        !          2046:   vdp_event_hint = vdp_clksperline_68k-74;
        !          2047:   vdp_event_hdisplay = vdp_event_hint+36;
        !          2048:   vdp_event_end = vdp_clksperline_68k;
        !          2049:   vdp_nextevent = 0;
        !          2050: }
        !          2051: 
        !          2052: void vdp_endfield(void)
        !          2053: {
        !          2054:   vdp_line = 0;
        !          2055:   vdp_eventinit();
        !          2056:   vdp_oddframe^= 1; /* toggle */
        !          2057:   /* printf("(%d,%d,%d,%d,%d)\n", vdp_event_type,
        !          2058:      vdp_event_startline, vdp_event_hint, vdp_event_vdpplot,
        !          2059:      vdp_event_endline); */
        !          2060: }
        !          2061: 
        !          2062: inline void vdp_plotcell(uint8 *patloc, uint8 palette, uint8 flags,
        !          2063:                         uint8 *cellloc, unsigned int lineoffset)
        !          2064: {
        !          2065:   int y, x;
        !          2066:   uint8 value;
        !          2067:   uint32 data;
        !          2068: 
        !          2069:   switch(flags) {
        !          2070:   case 0:
        !          2071:     /* normal tile - no s/ten */
        !          2072:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          2073:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
        !          2074:       for (x = 0; x < 8; x++, data<<= 4) {
        !          2075:         value = data>>28;
        !          2076:         if (value)
        !          2077:           cellloc[x] = palette*16 + value;
        !          2078:       }
        !          2079:     }
        !          2080:     break;
        !          2081:   case 1:
        !          2082:     /* h flipped tile - no s/ten */
        !          2083:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          2084:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
        !          2085:       for (x = 0; x < 8; x++, data>>= 4) {
        !          2086:         value = data & 15;
        !          2087:         if (value)
        !          2088:           cellloc[x] = palette*16 + value;
        !          2089:       }
        !          2090:     }
        !          2091:     break;
        !          2092:   case 2:
        !          2093:     /* v flipped tile - no s/ten */
        !          2094:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          2095:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
        !          2096:       for (x = 0; x < 8; x++, data<<= 4) {
        !          2097:         value = data>>28;
        !          2098:         if (value)
        !          2099:           cellloc[x] = palette*16 + value;
        !          2100:       }
        !          2101:     }
        !          2102:     break;
        !          2103:   case 3:
        !          2104:     /* h and v flipped tile - no s/ten */
        !          2105:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          2106:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
        !          2107:       for (x = 0; x < 8; x++, data>>= 4) {
        !          2108:         value = data & 15;
        !          2109:         if (value)
        !          2110:           cellloc[x] = palette*16 + value;
        !          2111:       }
        !          2112:     }
        !          2113:     break;
        !          2114:   case 4:
        !          2115:     /* normal tile - s/ten enabled */
        !          2116:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          2117:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
        !          2118:       for (x = 0; x < 8; x++, data<<= 4) {
        !          2119:         value = data>>28;
        !          2120:         if (value) {
        !          2121:           if (palette == 3 && value == 14) {
        !          2122:             cellloc[x] = (cellloc[x] & 63) + 64;
        !          2123:           } else if (palette == 3 && value == 15) {
        !          2124:             cellloc[x] = (cellloc[x] & 63) + 128;
        !          2125:           } else {
        !          2126:             cellloc[x] = palette*16 + value;
        !          2127:           }
        !          2128:         }
        !          2129:       }
        !          2130:     }
        !          2131:     break;
        !          2132:   case 5:
        !          2133:     /* h flipped tile - s/ten */
        !          2134:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          2135:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
        !          2136:       for (x = 0; x < 8; x++, data>>= 4) {
        !          2137:         value = data & 15;
        !          2138:         if (value) {
        !          2139:           if (palette == 3 && value == 14) {
        !          2140:             cellloc[x] = (cellloc[x] & 63) + 64;
        !          2141:           } else if (palette == 3 && value == 15) {
        !          2142:             cellloc[x] = (cellloc[x] & 63) + 128;
        !          2143:           } else {
        !          2144:             cellloc[x] = palette*16 + value;
        !          2145:           }
        !          2146:         }
        !          2147:       }
        !          2148:     }
        !          2149:     break;
        !          2150:   case 6:
        !          2151:     /* v flipped tile - s/ten enabled */
        !          2152:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          2153:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
        !          2154:       for (x = 0; x < 8; x++, data<<= 4) {
        !          2155:         value = data>>28;
        !          2156:         if (value) {
        !          2157:           if (palette == 3 && value == 14) {
        !          2158:             cellloc[x] = (cellloc[x] & 63) + 64;
        !          2159:           } else if (palette == 3 && value == 15) {
        !          2160:             cellloc[x] = (cellloc[x] & 63) + 128;
        !          2161:           } else {
        !          2162:             cellloc[x] = palette*16 + value;
        !          2163:           }
        !          2164:         }
        !          2165:       }
        !          2166:     }
        !          2167:     break;
        !          2168:   case 7:
        !          2169:     /* h and v flipped tile - s/ten enabled */
        !          2170:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          2171:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
        !          2172:       for (x = 0; x < 8; x++, data>>= 4) {
        !          2173:         value = data & 15;
        !          2174:         if (value) {
        !          2175:           if (palette == 3 && value == 14) {
        !          2176:             cellloc[x] = (cellloc[x] & 63) + 64;
        !          2177:           } else if (palette == 3 && value == 15) {
        !          2178:             cellloc[x] = (cellloc[x] & 63) + 128;
        !          2179:           } else {
        !          2180:             cellloc[x] = palette*16 + value;
        !          2181:           }
        !          2182:         }
        !          2183:       }
        !          2184:     }
        !          2185:     break;
        !          2186:   default:
        !          2187:     ui_err("Unknown plotcell flags");
        !          2188:   }
        !          2189: }
        !          2190: 
        !          2191: /* must be 8*lineoffset bytes scrap before and after fielddata and also
        !          2192:    8 bytes before each line and 8 bytes after each line */
        !          2193: 
        !          2194: void vdp_layer_simple(unsigned int layer, unsigned int priority,
        !          2195:                      uint8 *framedata, unsigned int lineoffset)
        !          2196: {
        !          2197:   int i, j;
        !          2198:   uint8 hsize = vdp_reg[16] & 3;
        !          2199:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
        !          2200:   uint8 hmode = vdp_reg[11] & 3;
        !          2201:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
        !          2202:   uint16 vramoffset = (layer ? ((vdp_reg[4] & 7) << 13) :
        !          2203:                       ((vdp_reg[2] & (7<<3)) << 10));
        !          2204:   uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset);
        !          2205:   uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10)
        !          2206:                                   + vdp_vram + layer*2);
        !          2207:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !          2208:   uint16 hwidth = 32+hsize*32;
        !          2209:   uint16 vwidth = 32+vsize*32;
        !          2210:   uint16 hoffset, voffset;
        !          2211:   uint16 cellinfo;
        !          2212:   uint8 *pattern;
        !          2213:   uint32 data;
        !          2214:   uint8 palette;
        !          2215:   uint8 value;
        !          2216:   unsigned int xcell, ycell;
        !          2217:   unsigned int pos;
        !          2218:   uint8 *toploc, *cellloc;
        !          2219:   uint8 flags;
        !          2220:   uint32 hscroll, vscroll;
        !          2221:   unsigned int x, y;
        !          2222:   int topbottom = vdp_reg[18] & 0x80;
        !          2223:   int winvpos = vdp_reg[18] & 0x1f;
        !          2224:   int leftright = vdp_reg[17] & 0x80;
        !          2225:   int winhpos = vdp_reg[17] & 0x1f;
        !          2226: 
        !          2227:   if (layer == 0 &&
        !          2228:       ((vdp_reg[18] == 0x9F && vdp_reg[17] == 0x9F) ||
        !          2229:        (vdp_reg[18] == 0x9F && vdp_reg[17] == 0x80) ||
        !          2230:        (vdp_reg[18] == 0x80) ||
        !          2231:        (vdp_reg[18] == 0x00 && vdp_reg[17] > (screencells << 1))))
        !          2232:     /* quick hack to remove layer A when it definitely shouldn't be plotted */
        !          2233:     return;
        !          2234: 
        !          2235:   for (xcell = 0; xcell <= screencells; xcell++) {
        !          2236:     if (vmode) {
        !          2237:       /* 2-cell scroll */
        !          2238:       vscroll = ((xcell >= screencells ? xcell-2 : xcell) & ~1) + layer;
        !          2239:     } else {
        !          2240:       /* full screen */
        !          2241:       vscroll = layer;
        !          2242:     }
        !          2243:     voffset = LOCENDIAN16( ((uint16 *)vdp_vsram)[vscroll] ) & 0x3FF;
        !          2244:     toploc = framedata - lineoffset*(voffset & 7);
        !          2245:     for (ycell = 0; ycell <= 28; ycell++, voffset+=8, toploc+=lineoffset*8) {
        !          2246:       switch(hmode) {
        !          2247:       case 0: /* full screen */
        !          2248:         hscroll = 0;
        !          2249:         break;
        !          2250:       case 2: /* cell scroll */
        !          2251:         hscroll = 2 * (ycell >= 28 ? ycell-2 : ycell) * 8;
        !          2252:         break;
        !          2253:       case 3: /* line scroll - approximation */
        !          2254:         hscroll = 2 * (ycell >= 28 ? ycell-2 : ycell) * 8;
        !          2255:         vdp_complex = 1;
        !          2256:         break;
        !          2257:       default:
        !          2258:         LOG_NORMAL(("prohibited HSCR/LSCR"));
        !          2259:         hscroll = 0;
        !          2260:         break;
        !          2261:       }
        !          2262:       voffset &= (vwidth*8)-1;
        !          2263:       hoffset = (0x400 - LOCENDIAN16(hscrolldata[hscroll])) & 0x3FF;
        !          2264:       hoffset = (hoffset+xcell*8) & ((hwidth*8)-1);
        !          2265:       cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>3)]);
        !          2266:       if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          2267:         /* plot cell */
        !          2268:         palette = (cellinfo >> 13) & 3;
        !          2269:         pattern = vdp_vram + ((cellinfo & 2047)<<5);
        !          2270:         flags = (cellinfo>>11) & 3; /* bit0=H flip, bit1=V flip */
        !          2271:         cellloc = toploc - (hoffset&7) + xcell*8;
        !          2272:         vdp_plotcell(pattern, palette, flags, cellloc, lineoffset);
        !          2273:       }
        !          2274:     } /* ycell */
        !          2275:   } /* xcell */
        !          2276: }
        !          2277: 
        !          2278: void vdp_shadow_simple(uint8 *framedata, unsigned int lineoffset)
        !          2279: {
        !          2280:   unsigned int vertcells = vdp_reg[1] & 1<<3 ? 30 : 28;
        !          2281:   uint8 *linedata;
        !          2282:   unsigned int line;
        !          2283:   int i;
        !          2284: 
        !          2285:   for (line = 0; line < vertcells*8; line++) {
        !          2286:     linedata = framedata + line*lineoffset;
        !          2287:     /* this could be done 4 bytes at a time */
        !          2288:     for (i = 0; i < 320; i++)
        !          2289:       linedata[i] = (linedata[i] & 63) + 128;
        !          2290:   }
        !          2291: }
        !          2292: 
        !          2293: void vdp_sprites_simple(unsigned int priority, uint8 *framedata,
        !          2294:                        unsigned int lineoffset)
        !          2295: {
        !          2296:   uint8 *spritelist = vdp_vram + ((vdp_reg[5] & 0x7F)<<9);
        !          2297: 
        !          2298:   vdp_sprite_simple(priority, framedata, lineoffset, 1,
        !          2299:                    spritelist, spritelist);
        !          2300: }
        !          2301: 
        !          2302: int vdp_sprite_simple(unsigned int priority, uint8 *framedata,
        !          2303:                      unsigned int lineoffset, unsigned int number,
        !          2304:                      uint8 *spritelist, uint8 *sprite)
        !          2305: {
        !          2306:   int i, j;
        !          2307:   int plotted = 1;
        !          2308:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !          2309:   uint8 link;
        !          2310:   uint16 pattern;
        !          2311:   uint32 data;
        !          2312:   uint8 palette;
        !          2313:   uint16 cellinfo;
        !          2314:   sint16 vpos, hpos, vmax;
        !          2315:   uint16 xcell, ycell;
        !          2316:   uint8 vsize, hsize;
        !          2317:   uint8 *cellloc;
        !          2318:   uint8 flags;
        !          2319:   uint8 *patloc;
        !          2320: 
        !          2321:   if (number > 80) {
        !          2322:     LOG_VERBOSE(("%08X [VDP] Maximum of 80 sprites exceeded", regs.pc));
        !          2323:     return 0;
        !          2324:   }
        !          2325: 
        !          2326:   link = sprite[3] & 0x7F;
        !          2327:   hpos = (LOCENDIAN16(*(uint16 *)(sprite+6)) & 0x1FF) - 0x80;
        !          2328:   vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x3FF) - 0x80;
        !          2329:   vsize = 1+(sprite[2] & 3);
        !          2330:   hsize = 1+((sprite[2]>>2) & 3);
        !          2331:   cellinfo = LOCENDIAN16(*(uint16 *)(sprite+4));
        !          2332:   pattern = cellinfo & 0x7FF;
        !          2333:   palette = (cellinfo >> 13) & 3;
        !          2334:   vmax = vpos + vsize*8;
        !          2335:   
        !          2336:   if (link) {
        !          2337:     if (hpos == -128)
        !          2338:       /* we do not support 'masking' in simple mode */
        !          2339:       vdp_complex = 1;
        !          2340:     plotted = vdp_sprite_simple(priority, framedata, lineoffset, number+1,
        !          2341:                                spritelist, spritelist + (link<<3));
        !          2342:     plotted++;
        !          2343:   }
        !          2344: 
        !          2345:   if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) != priority)
        !          2346:     return plotted;
        !          2347:   if (vpos >= 240 || hpos >= 320 || vpos+vsize*8 <= 0 || hpos+hsize*8 <= 0)
        !          2348:     /* sprite is not on screen */
        !          2349:     return plotted;
        !          2350:   flags = (cellinfo>>11) & 3; /* bit0=H flip, bit1=V flip */
        !          2351:   if (vdp_reg[12] & 1<<3) /* s/ten enabled? */
        !          2352:     flags|= 1<<2;
        !          2353:   switch(flags) {
        !          2354:   case 0:
        !          2355:   case 4:
        !          2356:     /* normal orientation */
        !          2357:     for (ycell = 0; ycell < vsize; ycell++) {
        !          2358:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
        !          2359:         /* cell out of plotting area (remember scrap area) */
        !          2360:         continue;
        !          2361:       patloc = vdp_vram + (pattern<<5) + ycell*32;
        !          2362:       for (xcell = 0; xcell < hsize; xcell++, patloc+= vsize*32) {
        !          2363:         if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          2364:           /* cell out of plotting area */
        !          2365:           continue;
        !          2366:         cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          2367:                               (hpos+xcell*8));
        !          2368:         vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
        !          2369:       }
        !          2370:     }
        !          2371:     break;
        !          2372:   case 1:
        !          2373:   case 5:
        !          2374:     /* H flip */
        !          2375:     for (ycell = 0; ycell < vsize; ycell++) {
        !          2376:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
        !          2377:         /* cell out of plotting area (remember scrap area) */
        !          2378:         continue;
        !          2379:       patloc = vdp_vram + (pattern<<5) + ycell*32 + vsize*32*(hsize-1);
        !          2380:       for (xcell = 0; xcell < hsize; xcell++, patloc-= vsize*32) {
        !          2381:         if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          2382:           /* cell out of plotting area */
        !          2383:           continue;
        !          2384:         cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          2385:                               (hpos+xcell*8));
        !          2386:         vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
        !          2387:       }
        !          2388:     }
        !          2389:     break;
        !          2390:   case 2:
        !          2391:   case 6:
        !          2392:     /* V flip */
        !          2393:     for (ycell = 0; ycell < vsize; ycell++) {
        !          2394:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
        !          2395:         /* cell out of plotting area (remember scrap area) */
        !          2396:         continue;
        !          2397:       patloc = vdp_vram + (pattern<<5) + (vsize-ycell-1)*32;
        !          2398:       for (xcell = 0; xcell < hsize; xcell++, patloc+= vsize*32) {
        !          2399:         if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          2400:           /* cell out of plotting area */
        !          2401:           continue;
        !          2402:         cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          2403:                               (hpos+xcell*8));
        !          2404:         vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
        !          2405:       }
        !          2406:     }
        !          2407:     break;
        !          2408:   case 3:
        !          2409:   case 7:
        !          2410:     /* H and V flip */
        !          2411:     for (ycell = 0; ycell < vsize; ycell++) {
        !          2412:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
        !          2413:         /* cell out of plotting area (remember scrap area) */
        !          2414:         continue;
        !          2415:       patloc = vdp_vram + (pattern<<5) + ((vsize-ycell-1)*32 +
        !          2416:                                          vsize*32*(hsize-1));
        !          2417:       for (xcell = 0; xcell < hsize; xcell++, patloc-= vsize*32) {
        !          2418:         if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          2419:           /* cell out of plotting area */
        !          2420:           continue;
        !          2421:         cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          2422:                               (hpos+xcell*8));
        !          2423:         vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
        !          2424:       }
        !          2425:     }
        !          2426:     break;
        !          2427:   }
        !          2428:   return plotted;
        !          2429: }
        !          2430: 
        !          2431: uint8 vdp_gethpos(void) {
        !          2432:   float percent;
        !          2433: 
        !          2434:   /* vdp_event = 0/1/2 -> beginning of line until 74 clocks before end
        !          2435:                  3     -> between hint and hdisplay (36 clocks)
        !          2436:                  4     -> between hdisplay and end  (38 clocks)
        !          2437:      This routine goes from 0 to the maximum number allowed not within
        !          2438:      H-blank, and then goes slightly beyond up to hdisplay.  Then
        !          2439:      between hdisplay and end we go negative.  I'm not sure how negative
        !          2440:      it is supposed to be, this goes from -38 to 0.
        !          2441: 
        !          2442:      40 horizontal cells, H goes from $00 to $B6, $E4 to $FF
        !          2443:      32 horizontal cells, H goes from $00 to $93, $E8 to $FF
        !          2444: 
        !          2445:      this is such a bodge - any changes, check '3 Ninjas kick back'
        !          2446:   */
        !          2447:   LOG_DEBUG1(("gethpos %X: clocks=%X : startofline=%X : hint=%X : "
        !          2448:               "end=%X", vdp_event, cpu68k_clocks,
        !          2449:               vdp_event_start,
        !          2450:               vdp_event_hint, vdp_event_end));
        !          2451:   if (vdp_event < 3) {
        !          2452:     percent = ((float)(cpu68k_clocks-vdp_event_start)/
        !          2453:                (float)(vdp_event_hint-vdp_event_start));
        !          2454:     if (vdp_reg[12] & 1)
        !          2455:       return (cpu68k_clocks > vdp_event_hint) ? 0xE4 : percent*0xB6;
        !          2456:     else
        !          2457:       return (cpu68k_clocks > vdp_event_hint) ? 0xE8 : percent*0x93;
        !          2458:   } else {
        !          2459:     percent = ((float)(cpu68k_clocks-vdp_event_hint)/
        !          2460:                (float)(vdp_event_end-vdp_event_hint));
        !          2461:     if (vdp_reg[12] & 1)
        !          2462:       return ((cpu68k_clocks > vdp_event_end) ? 0 :
        !          2463:               ((0xE4+(uint8)percent*28) & 0xff));
        !          2464:     else
        !          2465:       return ((cpu68k_clocks > vdp_event_end) ? 0 :
        !          2466:               ((0xE8+(uint8)percent*24) & 0xff));
        !          2467:   }
        !          2468: }

unix.superglobalmegacorp.com

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