Annotation of generator/src/vdp.c, revision 1.1.1.2

1.1.1.2 ! 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 */
1.1       root       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"
1.1.1.2 ! root       21: #include "event.h"
1.1       root       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;
1.1.1.2 ! root       32: unsigned int vdp_visstartline;
        !            33: unsigned int vdp_visendline;
1.1       root       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 */
1.1.1.2 ! root       44: unsigned int vdp_dmabusy = 0;    /* dma busy flag */
1.1       root       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;
1.1.1.2 ! root       65: signed int vdp_nextevent = 0;
        !            66: sint32 vdp_dmabytes = 0;            /* bytes left in DMA - must be fixed size */
1.1       root       67: signed int vdp_hskip_countdown = 0; /* actual countdown */
1.1.1.2 ! root       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 */
1.1       root       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);
1.1.1.2 ! root       86: void vdp_dma_vramcopy(void);
        !            87: void vdp_dma_fill(uint8 data);
1.1       root       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,
1.1.1.2 ! root       92:                      uint8 *fielddata, unsigned int lineoffset);
1.1       root       93: inline void vdp_plotcell(uint8 *patloc, uint8 palette, uint8 flags,
1.1.1.2 ! root       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);
1.1       root       99: int vdp_sprite_simple(unsigned int priority, uint8 *framedata,
1.1.1.2 ! root      100:                      unsigned int lineoffset, unsigned int number,
        !           101:                      uint8 *spritelist, uint8 *sprite);
1.1       root      102: void vdp_sprites_simple(unsigned int priority, uint8 *framedata,
1.1.1.2 ! root      103:                         unsigned int lineoffset);
1.1       root      104: void vdp_shadow_simple(uint8 *framedata, unsigned int lineoffset);
                    105: void vdp_window(unsigned int line, unsigned int priority, uint8 *linedata);
1.1.1.2 ! root      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
1.1       root      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: {
1.1.1.2 ! root      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: 
1.1       root      131:   vdp_clock = vdp_pal ? 53200000 : 53693100; /* What speed is the PAL clock? */
                    132:   vdp_68kclock = vdp_clock / 7;
1.1.1.2 ! root      133:   vdp_vislines = v30 ? 240 : 224;
        !           134:   vdp_visstartline = v30 ? 46 : (vdp_pal ? 54 : 19);
        !           135:   vdp_visendline = vdp_visstartline + vdp_vislines;
1.1       root      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: 
1.1.1.2 ! root      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: 
1.1       root      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 ?
1.1.1.2 ! root      187:                "PAL" : "NTSC"));
1.1       root      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
1.1.1.2 ! root      205:    * 10-15 are next word on bus, i.e. next word in ROM - CM
1.1       root      206:    */
1.1.1.2 ! root      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;
1.1       root      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;
1.1.1.2 ! root      217:   vdp_ctrlflag = 0; /* Charles MacDonald - so he claims ;) */
1.1       root      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) {
1.1.1.2 ! root      235:         LOG_NORMAL(("%08X [VDP] Invalid register (%d)", regs.pc,
        !           236:                      ((data>>8) & 31)));
        !           237:         return;
1.1       root      238:       }
                    239:       vdp_reg[reg] = regdata;
1.1.1.2 ! root      240:       vdp_code = 0;
1.1       root      241: #ifdef DEBUG_VDP
                    242:       LOG_VERBOSE(("%08X [VDP] Register %d set to %04X", regs.pc,
1.1.1.2 ! root      243:                   reg, regdata));
1.1       root      244: #endif
                    245:       return;
                    246:     } else {
                    247:       vdp_ctrlflag = 1;
1.1.1.2 ! root      248:       vdp_first = data;
1.1       root      249:       return;
                    250:     }
                    251:   } else {
1.1.1.2 ! root      252:     vdp_second = data;
1.1       root      253:     vdp_ctrlflag = 0;
1.1.1.2 ! root      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;
1.1       root      291:       }
                    292:     }
                    293:   }
                    294: }
                    295: 
1.1.1.2 ! root      296: void vdp_ramcopy_vram_obsolete(int type)
1.1       root      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 "
1.1.1.2 ! root      318:                 "vdpaddr=%08X length=%d",
        !           319:                 regs.pc, srcoffset*2, type, vdp_address, length));
1.1       root      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 "
1.1.1.2 ! root      326:                 "vdpaddr=%08X length=%d",
        !           327:                 regs.pc, srcbank*0x20000+srcoffset*2, type, vdp_address,
        !           328:                 length));
1.1       root      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;
1.1.1.2 ! root      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:     }      
1.1       root      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: 
1.1.1.2 ! root      382: void vdp_ramcopy_vram(int type)
1.1       root      383: {
                    384:   uint16 length = vdp_reg[19] | vdp_reg[20]<<8;
1.1.1.2 ! root      385:   uint8 srcbank = vdp_reg[23];
        !           386:   uint16 srcoffset = vdp_reg[21] | vdp_reg[22]<<8;
1.1       root      387:   uint8 increment = vdp_reg[15];
1.1.1.2 ! root      388:   uint16 *srcmemory;
        !           389:   uint16 srcmask;
        !           390:   uint16 data;
        !           391:   unsigned int i;
1.1       root      392: 
1.1.1.2 ! root      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));
1.1       root      397: #endif
1.1.1.2 ! root      398: 
        !           399:   if (srcbank & 1<<6) {
        !           400:     srcmemory = (uint16 *)cpu68k_ram;
        !           401:     srcmask = 0x7fff; /* 32k words = 64k */
1.1       root      402:   } else {
1.1.1.2 ! root      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;
1.1       root      424:     }
1.1.1.2 ! root      425:     srcoffset+=1;
        !           426:     vdp_address+= increment;
1.1       root      427:   }
1.1.1.2 ! root      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);
1.1       root      434: }
                    435: 
1.1.1.2 ! root      436: void vdp_dma_vramcopy()
1.1       root      437: {
1.1.1.2 ! root      438:   uint32 length = vdp_reg[19] | vdp_reg[20]<<8;
1.1       root      439:   uint8 increment = vdp_reg[15];
1.1.1.2 ! root      440:   uint16 srcaddr = vdp_reg[21] | vdp_reg[22]<<8;
        !           441:   unsigned int i;
1.1       root      442: 
1.1.1.2 ! root      443:   if (length == 0) {
        !           444:     LOG_NORMAL(("%08X [VDP] Warning - length of 0 used in vram copy"));
        !           445:     length = 0x10000; /* could be 0xffff */
1.1       root      446:   }
1.1.1.2 ! root      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;
1.1       root      457:   }
1.1.1.2 ! root      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) */
1.1       root      464: }
                    465: 
1.1.1.2 ! root      466: void vdp_dma_fill(uint8 data)
1.1       root      467: {
1.1.1.2 ! root      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) */
1.1       root      483: }
                    484: 
1.1.1.2 ! root      485: uint16 vdp_fetchdata_obsolete(void)
1.1       root      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,
1.1.1.2 ! root      495:                 vdp_address));
1.1       root      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",
1.1.1.2 ! root      503:                 regs.pc, vdp_address));
1.1       root      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,
1.1.1.2 ! root      511:                 vdp_address));
1.1       root      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,
1.1.1.2 ! root      518:                  vdp_code));
1.1       root      519:     return 0;
                    520:   }
                    521:   if (vdp_address>=size) {
                    522:     LOG_VERBOSE(("%08X [VDP] Address (%08X) out of bounds (%08X)",
1.1.1.2 ! root      523:                 regs.pc, vdp_address, size));
1.1       root      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,
1.1.1.2 ! root      528:                vdp_address & ~1));
1.1       root      529: #endif
                    530:   vdp_address+= vdp_reg[15];
1.1.1.2 ! root      531:   vdp_ctrlflag = 0;
1.1       root      532:   return data;
                    533: }
                    534: 
1.1.1.2 ! root      535: void vdp_storedata(uint16 data)
1.1       root      536: {
1.1.1.2 ! root      537:   uint16 address;
        !           538:   uint16 sdata;
        !           539: 
1.1       root      540:   if (vdp_ctrlflag) {
1.1.1.2 ! root      541:     LOG_NORMAL(("%08X [VDP] Unterminated ctrl setting %04X/%04X", regs.pc,
        !           542:                vdp_first, vdp_second));
        !           543:     vdp_storectrl(vdp_second);
1.1       root      544:   }
1.1.1.2 ! root      545: 
1.1       root      546:   switch(vdp_code) {
                    547:   case cd_vram_store:
1.1.1.2 ! root      548:     sdata = (vdp_address & 1) ? SWAP16(data) : data; /* only for VRAM */
        !           549:     *(uint16 *)(vdp_vram+(vdp_address & 0xfffe)) = LOCENDIAN16(sdata);
        !           550:     break;
1.1       root      551:   case cd_cram_store:
1.1.1.2 ! root      552:     address = vdp_address & 0x7e; /* address lines used */
        !           553:     *(uint16 *)(vdp_cram+address) = LOCENDIAN16(data);
        !           554:     vdp_cramf[address>>1] = 1;
        !           555:     break;
1.1       root      556:   case cd_vsram_store:
1.1.1.2 ! root      557:     address = vdp_address & 0x7e; /* address lines used */
        !           558:     if (address < LEN_VSRAM)
        !           559:       *(uint16 *)(vdp_vsram+address) = LOCENDIAN16(data);
        !           560:     break;
1.1       root      561:   default: /* undefined */
1.1.1.2 ! root      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);
1.1       root      573:   }
                    574: }
                    575: 
1.1.1.2 ! root      576: uint16 vdp_fetchdata(void)
1.1       root      577: {
1.1.1.2 ! root      578:   uint16 address;
        !           579:   uint16 data;
        !           580: 
1.1       root      581:   if (vdp_ctrlflag) {
1.1.1.2 ! root      582:     LOG_NORMAL(("%08X [VDP] Unterminated ctrl setting %04X/%04X", regs.pc,
        !           583:                vdp_first, vdp_second));
        !           584:     vdp_storectrl(vdp_second);
1.1       root      585:   }
1.1.1.2 ! root      586: 
1.1       root      587:   switch(vdp_code) {
1.1.1.2 ! root      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;
1.1       root      603:   default: /* undefined */
1.1.1.2 ! root      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;
1.1       root      609:   }
1.1.1.2 ! root      610:   vdp_address+= vdp_reg[15]; /* 16 bit wrap */
        !           611:   return data;
1.1       root      612: }
                    613: 
1.1.1.2 ! root      614: #define LINEDATA(offset, value, palette, priority) \
1.1       root      615: if (value) { \
1.1.1.2 ! root      616:   linedata[offset] = (palette)*16 + value; \
1.1       root      617: } else if (priority) { \
                    618:   linedata[offset] = (linedata[offset] & 63); \
                    619: }
                    620: 
1.1.1.2 ! root      621: #define LINEDATASPR(offset, value, palette, priority) \
1.1       root      622: if (value) { \
1.1.1.2 ! root      623:   if (outdata[offset] < 62) \
1.1       root      624:     vdp_collision = 1; \
1.1.1.2 ! root      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;
1.1       root      639: 
1.1.1.2 ! root      640: void vdp_sprites(unsigned int line, uint8 *pridata, uint8 *outdata)
1.1       root      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) {
1.1.1.2 ! root      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:         }
1.1       root      702:       } else {
1.1.1.2 ! root      703:         /* higest priority sprite, so mask */
        !           704:         plotter = 0;
1.1       root      705:       }
                    706:       si[i].hplot = 0;
                    707:     }
1.1.1.2 ! root      708:     if (si[i].hpos == -127) {
        !           709:       LOG_VERBOSE(("Warning: Use of hpos = 1 in plotter"));
        !           710:       plotter = 1;
        !           711:     }
1.1       root      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;
1.1.1.2 ! root      730:     uint8 priority;
1.1       root      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;
1.1.1.2 ! root      745:       priority = (cellinfo >> 15) & 1;
1.1       root      746: 
1.1.1.2 ! root      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;
1.1       root      814:       }
                    815:     }
                    816:   }
                    817: }
                    818: 
1.1.1.2 ! root      819: inline void vdp_spritelayer(unsigned int line, uint8 *spritedata,
        !           820:                            uint8 *pridata, uint8 *linedata,
        !           821:                            unsigned int priority)
1.1       root      822: {
                    823:   int i;
                    824:   
1.1.1.2 ! root      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:         }
1.1       root      837:       }
                    838:     }
1.1.1.2 ! root      839:   } else {
        !           840:     for (i = 0; i < 320; i++) {
        !           841:       if (pridata[i] == priority) {
        !           842:         if (spritedata[i]) {
        !           843:           linedata[i] = spritedata[i];
        !           844:         }
1.1       root      845:       }
                    846:     }
1.1.1.2 ! root      847:   }
1.1       root      848: }
                    849: 
                    850: /* layer 0 = A (top), layer 1 = B (bottom) */
                    851: 
1.1.1.2 ! root      852: void vdp_newlayer(unsigned int line, uint8 *pridata, uint8 *outdata,
        !           853:                  unsigned int layer)
1.1       root      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) :
1.1.1.2 ! root      861:                       ((vdp_reg[2] & (7<<3)) << 10));
1.1       root      862:   uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset);
                    863:   uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10)
1.1.1.2 ! root      864:                                   + vdp_vram + layer*2);
1.1       root      865:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
1.1.1.2 ! root      866:   uint16 hwidth, vwidth, vmask, hoffset, voffset;
1.1       root      867:   uint16 cellinfo;
                    868:   uint8 *pattern;
                    869:   uint32 data;
                    870:   uint8 palette;
                    871:   uint8 pixel;
                    872:   uint8 topbottom, leftright, winhpos, winvpos;
1.1.1.2 ! root      873:   uint8 priority;
        !           874:   int interlace = (vdp_reg[12] >> 1) & 3;
        !           875:   int realline = interlace ? line >> 1 : line;
        !           876: 
        !           877:   /* do window vertical check */
1.1       root      878: 
                    879:   if (layer == 0) {
                    880:     /* turn off A when window is on */
                    881:     topbottom = vdp_reg[18] & 0x80;
                    882:     leftright = vdp_reg[17] & 0x80;
                    883:     winhpos = vdp_reg[17] & 0x1f;
                    884:     winvpos = vdp_reg[18] & 0x1f;
                    885:     /* Battle Tank sets winvpos to 1F and expects layer A to be off */
                    886:     if (topbottom && winvpos != 0x1F) {
1.1.1.2 ! root      887:       if ((realline >> 3) >= winvpos)
        !           888:         return;
1.1       root      889:     } else {
1.1.1.2 ! root      890:       if ((realline >> 3) < winvpos)
        !           891:         return;
1.1       root      892:     }
                    893:   }
                    894: 
1.1.1.2 ! root      895:   /* isn't this bug fixed now? */
1.1       root      896:   /* BUG: layer A is still displayed left/right when window is on,
                    897:      only apparent with high-priority layer A and low-priority window */
                    898: 
1.1.1.2 ! root      899:   /* select horizontal scrolling offset based on mode */
        !           900: 
1.1       root      901:   switch(hmode) {
                    902:   case 0: /* full screen */
                    903:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF;
                    904:     break;
                    905:   case 2: /* cell scroll */
1.1.1.2 ! root      906:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(realline & ~7)])) & 0x3FF;
1.1       root      907:     break;
                    908:   case 3: /* line scroll */
1.1.1.2 ! root      909:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*realline])) & 0x3FF;
1.1       root      910:     break;
                    911:   default:
                    912:     LOG_NORMAL(("prohibited HSCR/LSCR"));
                    913:     hoffset = 0;
                    914:     break;
                    915:   }
1.1.1.2 ! root      916:   hwidth = (hsize+1) << 5;
        !           917:   vwidth = ((vsize+1) << 5) * (interlace ? 2 : 1);
        !           918:   vmask = (vwidth << 3) - 1; /* to put offsets into range */
        !           919:   hoffset&= (hwidth << 3)-1; /* put offset in range */
        !           920:   voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & vmask;
        !           921:   cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+
        !           922:                          hwidth*((voffset>>3)>>(interlace ? 1 : 0))]);
        !           923:   /* 32 bytes per pattern or 64 in interlace mode */
        !           924:   pattern = vdp_vram + (((cellinfo & 2047)<<5) << (interlace ? 1 : 0));
        !           925:   /* now get correct line from pattern data */
        !           926:   switch (interlace) {
        !           927:   case 0: /* no interlace */
        !           928:   case 1: /* ?? */
        !           929:   case 2: /* ?? */
1.1       root      930:     if (cellinfo & 1<<12) {
                    931:       /* vertical flip */
                    932:       pattern+= 4*(7-(voffset & 7));
                    933:     } else {
                    934:       /* no vertical flip */
                    935:       pattern+= 4*(voffset & 7);
                    936:     }
1.1.1.2 ! root      937:     break;
        !           938:   case 3: /* interlace with double height cells */
        !           939:     if (cellinfo & 1<<12) {
        !           940:       /* vertical flip */
        !           941:       pattern+= 4*(15-(voffset & 15));
1.1       root      942:     } else {
1.1.1.2 ! root      943:       /* no vertical flip */
        !           944:       pattern+= 4*(voffset & 15);
1.1       root      945:     }
1.1.1.2 ! root      946:     break;
1.1       root      947:   }
1.1.1.2 ! root      948:   priority = (cellinfo >> 15) & 1;
        !           949:   palette = (cellinfo >> 13) & 3;
        !           950:   data = LOCENDIAN32(*(uint32 *)pattern);
        !           951:   if (cellinfo & 1<<11) {
        !           952:     /* horizontal flip */
        !           953:     data>>= (hoffset & 7)*4; /* get first pixel in bottom 4 bits */
        !           954:     for (i = 0; i < 8-(hoffset & 7); i++) {
        !           955:       pixel = data & 15;
        !           956:       LINEDATALAYER(i, pixel, palette, priority);
        !           957:       data>>= 4;
        !           958:     }
        !           959:   } else {
        !           960:     data<<= (hoffset & 7)*4; /* get first pixel in top 4 bits */
        !           961:     for (i = 0; i < 8-(hoffset & 7); i++) {
        !           962:       pixel = (data>>28) & 15;
        !           963:       LINEDATALAYER(i, pixel, palette, priority);
        !           964:       data<<= 4;
        !           965:     }
        !           966:   }
        !           967:   outdata+= 8-(hoffset & 7);
        !           968:   pridata+= 8-(hoffset & 7);
1.1       root      969:   hoffset+= 8;
                    970:   hoffset&= (hwidth*8)-1; /* put offset in range */
                    971:   for (j = 1; j < screencells; j++) {
                    972:     if (vmode) {
                    973:       /* 2-cell scroll */
                    974:       /* DEBUG DEBUG DEBUG awooga awooga */
                    975:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
1.1.1.2 ! root      976:           [(j&~1)+layer] )) & vmask;
1.1       root      977:     } else {
                    978:       /* full screen */
1.1.1.2 ! root      979:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & vmask;
1.1       root      980:     }
1.1.1.2 ! root      981:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+
        !           982:                            hwidth*((voffset>>3)>>(interlace ? 1 : 0))]);
        !           983:     priority = (cellinfo >> 15) & 1;
1.1       root      984:     /* printf("hoff: %04X voff: %04X hwid: %04X cell: %08X info: %04X\n",
1.1.1.2 ! root      985:            hoffset, voffset, hwidth, (hoffset>>3)+hwidth*(voffset>>3),
        !           986:            cellinfo); */
1.1       root      987:     /* printf("loc %08X cellinfo %08X\n",
1.1.1.2 ! root      988:            (hoffset>>3)+hwidth*(voffset>>3),
        !           989:            cellinfo); */
        !           990:     palette = (cellinfo >> 13) & 3;
        !           991:     /* 32 bytes per pattern or 64 in interlace mode */
        !           992:     pattern = vdp_vram + (((cellinfo & 2047)<<5) << (interlace ? 1 : 0));
        !           993:     /* now get correct line from pattern data */
        !           994:     switch (interlace) {
        !           995:     case 0: /* no interlace */
        !           996:     case 1: /* ?? */
        !           997:     case 2: /* ?? */
1.1       root      998:       if (cellinfo & 1<<12) {
1.1.1.2 ! root      999:         /* vertical flip */
        !          1000:         pattern+= 4*(7-(voffset & 7));
1.1       root     1001:       } else {
1.1.1.2 ! root     1002:         /* no vertical flip */
        !          1003:         pattern+= 4*(voffset & 7);
1.1       root     1004:       }
1.1.1.2 ! root     1005:       break;
        !          1006:     case 3: /* interlace with double height cells */
        !          1007:       if (cellinfo & 1<<12) {
        !          1008:         /* vertical flip */
        !          1009:         pattern+= 4*(15-(voffset & 15));
1.1       root     1010:       } else {
1.1.1.2 ! root     1011:         /* no vertical flip */
        !          1012:         pattern+= 4*(voffset & 15);
1.1       root     1013:       }
1.1.1.2 ! root     1014:       break;
1.1       root     1015:     }
1.1.1.2 ! root     1016:     data = LOCENDIAN32(*(uint32 *)pattern);
        !          1017:     if (cellinfo & 1<<11) {
        !          1018:       /* horizontal flip */
        !          1019:       for (i = 0; i < 8; i++) {
        !          1020:         pixel = data & 15;
        !          1021:         LINEDATALAYER(i, pixel, palette, priority);
        !          1022:         data>>= 4;
        !          1023:       }
        !          1024:     } else {
        !          1025:       for (i = 0; i < 8; i++) {
        !          1026:         pixel = (data>>28) & 15;
        !          1027:         LINEDATALAYER(i, pixel, palette, priority);
        !          1028:         data<<= 4;
        !          1029:       }
        !          1030:     }
        !          1031:     outdata+= 8;
        !          1032:     pridata+= 8;
1.1       root     1033:     hoffset+= 8;
                   1034:     hoffset&= (hwidth*8)-1; /* put offset in range */
                   1035:   }
                   1036:   if (hoffset & 7) {
                   1037:     if (vmode) {
                   1038:       /* 2-cell scroll - note use last offset, not next */
                   1039:       /* DEBUG DEBUG DEBUG awooga awooga */
                   1040:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
1.1.1.2 ! root     1041:           [(screencells-2)+layer] )) & vmask;
1.1       root     1042:     } else {
                   1043:       /* full screen */
1.1.1.2 ! root     1044:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & vmask;
        !          1045:     }
        !          1046:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+
        !          1047:                            hwidth*((voffset>>3)>>(interlace ? 1 : 0))]);
        !          1048:     priority = (cellinfo >> 15) & 1;
        !          1049:     palette = (cellinfo >> 13) & 3;
        !          1050:     /* 32 bytes per pattern or 64 in interlace mode */
        !          1051:     pattern = vdp_vram + (((cellinfo & 2047)<<5) << (interlace ? 1 : 0));
        !          1052:     /* now get correct line from pattern data */
        !          1053:     switch (interlace) {
        !          1054:     case 0: /* no interlace */
        !          1055:     case 1: /* ?? */
        !          1056:     case 2: /* ?? */
        !          1057:       if (cellinfo & 1<<12) {
        !          1058:         /* vertical flip */
        !          1059:         pattern+= 4*(7-(voffset & 7));
        !          1060:       } else {
        !          1061:         /* no vertical flip */
        !          1062:         pattern+= 4*(voffset & 7);
        !          1063:       }
        !          1064:       break;
        !          1065:     case 3: /* interlace with double height cells */
        !          1066:       if (cellinfo & 1<<12) {
        !          1067:         /* vertical flip */
        !          1068:         pattern+= 4*(15-(voffset & 15));
        !          1069:       } else {
        !          1070:         /* no vertical flip */
        !          1071:         pattern+= 4*(voffset & 15);
        !          1072:       }
        !          1073:       break;
        !          1074:     }
        !          1075:     data = LOCENDIAN32(*(uint32 *)pattern);
        !          1076:     if (cellinfo & 1<<11) {
        !          1077:       /* horizontal flip */
        !          1078:       for (i = 0; i < (hoffset & 7); i++) {
        !          1079:         pixel = data & 15;
        !          1080:         LINEDATALAYER(i, pixel, palette, priority);
        !          1081:         data>>= 4;
        !          1082:       }
        !          1083:     } else {
        !          1084:       for (i = 0; i < (hoffset & 7); i++) {
        !          1085:         pixel = (data>>28) & 15;
        !          1086:         LINEDATALAYER(i, pixel, palette, priority);
        !          1087:         data<<= 4;
        !          1088:       }
        !          1089:     }
        !          1090:   }
        !          1091: }
        !          1092: 
        !          1093: /* this function updates outdata/pridata which came from the layerA generation
        !          1094:    routines */
        !          1095: 
        !          1096: void vdp_newwindow(unsigned int line, uint8 *pridata, uint8 *outdata)
        !          1097: {
        !          1098:   uint16 *patterndata = (uint16 *)(vdp_vram + ((vdp_reg[3] & 0x3e) << 10));
        !          1099:   uint8 winhpos = vdp_reg[17] & 0x1f;
        !          1100:   uint8 winvpos = vdp_reg[18] & 0x1f;
        !          1101:   uint8 vcell = line / 8;
        !          1102:   uint8 hcell;
        !          1103:   uint8 voffset = line & 7;
        !          1104:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !          1105:   uint8 topbottom = vdp_reg[18] & 0x80;
        !          1106:   uint8 leftright = vdp_reg[17] & 0x80;
        !          1107:   uint8 patternshift = (vdp_reg[12] & 1) ? 6 : 5;
        !          1108:   uint16 cellinfo;
        !          1109:   uint8 *pattern;
        !          1110:   uint32 data;
        !          1111:   uint8 palette;
        !          1112:   uint8 pixel;
        !          1113:   unsigned int i;
        !          1114:   unsigned int wholeline = 0;
        !          1115:   uint8 priority;
        !          1116:   int layer = 0; /* for LINEDATALAYER macro */
        !          1117: 
        !          1118:   if (vdp_reg[17] == 0 && vdp_reg[18] == 0)
        !          1119:     return; /* window is off */
        !          1120: 
        !          1121:   /* Battle Tank sets winvpos to 0x80+0x1F and expects layer A to be off */
        !          1122: 
        !          1123:   /* this section below is repeated in the main renderline code, so that
        !          1124:      layerA is not unnecessarily calculated */
        !          1125:   if (topbottom ? (vcell >= winvpos) : (vcell < winvpos))
        !          1126:     wholeline = 1;
        !          1127:   if (topbottom && winvpos == 0x1f)
        !          1128:     wholeline = 1;
        !          1129: 
        !          1130:   if (!wholeline) {
        !          1131:     if (winhpos >= 20)
        !          1132:       winhpos = 20; /* 0x1F might be special? */
        !          1133:     if (leftright) {
        !          1134:       /* clear out priority bits on right of line (winhpos units of 16 pix */
        !          1135:       for (i = winhpos*4; i < 320/4; i++) /* winhpos units of 16 pix */
        !          1136:         ((uint32 *)pridata)[i]&= (0xffffffff - (0x01010101<<PRIBIT_LAYERA));
        !          1137:       memset(outdata+winhpos*16, 0, 320-(winhpos*16));
        !          1138:     } else {
        !          1139:       /* clear out priority bits on left of line (winhpos units of 16 pix) */
        !          1140:       for (i = 0; i < (unsigned int)(winhpos/4); i++)
        !          1141:         ((uint32 *)pridata)[i]&= (0xffffffff - (0x01010101<<PRIBIT_LAYERA));
        !          1142:       memset(outdata, 0, winhpos*16);
        !          1143:     }
        !          1144:   }
        !          1145:   for (hcell = 0; hcell < screencells; hcell++, outdata+=8, pridata+=8) {
        !          1146:     if (!wholeline) {
        !          1147:       if (leftright) {
        !          1148:         if ((hcell>>1) < winhpos)
        !          1149:           continue;
        !          1150:       } else {
        !          1151:         if ((hcell>>1) >= winhpos)
        !          1152:           continue;
        !          1153:       }
        !          1154:     }
        !          1155:     cellinfo = LOCENDIAN16(patterndata[vcell<<patternshift | hcell]);
        !          1156:     priority = (cellinfo >> 15) & 1;
        !          1157:     palette = (cellinfo >> 13) & 3;
        !          1158:     /* 32 bytes per pattern */
        !          1159:     pattern = vdp_vram + ((cellinfo & 2047)<<5); /* fix for interlace */
        !          1160:     if (cellinfo & 1<<12) {
        !          1161:       /* vertical flip */
        !          1162:       pattern+= 4*(7-(voffset & 7));
        !          1163:     } else {
        !          1164:       /* no vertical flip */
        !          1165:       pattern+= 4*(voffset & 7);
        !          1166:     }
        !          1167:     data = LOCENDIAN32(*(uint32 *)pattern);
        !          1168:     if (cellinfo & 1<<11) {
        !          1169:       /* horizontal flip */
        !          1170:       for (i = 0; i < 8; i++) {
        !          1171:         pixel = data & 15;
        !          1172:         LINEDATALAYER(i, pixel, palette, priority);
        !          1173:         data>>= 4;
        !          1174:       }
        !          1175:     } else {
        !          1176:       for (i = 0; i < 8; i++) {
        !          1177:         pixel = (data>>28) & 15;
        !          1178:         LINEDATALAYER(i, pixel, palette, priority);
        !          1179:         data<<= 4;
        !          1180:       }
        !          1181:     }
        !          1182:   } /* hcell */
        !          1183: }
        !          1184: 
        !          1185: inline void vdp_shadow(unsigned int line, uint8 *linedata)
        !          1186: {
        !          1187:   int i;
        !          1188:   
        !          1189:   /* this could be done 4 bytes at a time */
        !          1190:   for (i = 0; i < 320; i++)
        !          1191:     linedata[i] = (linedata[i] & 63) + 128;
        !          1192: }
        !          1193: 
        !          1194: void vdp_window(unsigned int line, unsigned int priority, uint8 *linedata)
        !          1195: {
        !          1196:   uint16 *patterndata = (uint16 *)(vdp_vram + ((vdp_reg[3] & 0x3e) << 10));
        !          1197:   uint8 winhpos = vdp_reg[17] & 0x1f;
        !          1198:   uint8 winvpos = vdp_reg[18] & 0x1f;
        !          1199:   uint8 vcell = line / 8;
        !          1200:   uint8 hcell;
        !          1201:   uint8 voffset = line & 7;
        !          1202:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !          1203:   uint8 topbottom = vdp_reg[18] & 0x80;
        !          1204:   uint8 leftright = vdp_reg[17] & 0x80;
        !          1205:   uint8 patternshift = (vdp_reg[12] & 1) ? 6 : 5;
        !          1206:   uint16 cellinfo;
        !          1207:   uint8 *pattern;
        !          1208:   uint32 data;
        !          1209:   uint8 palette;
        !          1210:   uint8 pixel;
        !          1211:   unsigned int i;
        !          1212:   unsigned int wholeline = 0;
        !          1213: 
        !          1214:   if (topbottom) {
        !          1215:     /* bottom part */
        !          1216:     /* Battle Tank sets winvpos to 0x1F and expects layer A to be off */
        !          1217:     if (winvpos == 0x1F || vcell >= winvpos)
        !          1218:       wholeline = 1;
        !          1219:   } else {
        !          1220:     /* top part */
        !          1221:     if (vcell < winvpos)
        !          1222:       wholeline = 1;
        !          1223:   }
        !          1224:   for (hcell = 0; hcell < screencells; hcell++, linedata+=8) {
        !          1225:     if (!wholeline) {
        !          1226:       if (leftright) {
        !          1227:         if ((hcell>>1) < winhpos)
        !          1228:           continue;
        !          1229:       } else {
        !          1230:         if ((hcell>>1) >= winhpos)
        !          1231:           continue;
        !          1232:       }
1.1       root     1233:     }
1.1.1.2 ! root     1234:     cellinfo = LOCENDIAN16(patterndata[vcell<<patternshift | hcell]);
1.1       root     1235:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
                   1236:       palette = (cellinfo >> 13) & 3;
                   1237:       pattern = vdp_vram + ((cellinfo & 2047)<<5); /* 32 bytes per pattern */
                   1238:       if (cellinfo & 1<<12) {
1.1.1.2 ! root     1239:         /* vertical flip */
        !          1240:         pattern+= 4*(7-(voffset & 7));
1.1       root     1241:       } else {
1.1.1.2 ! root     1242:         /* no vertical flip */
        !          1243:         pattern+= 4*(voffset & 7);
1.1       root     1244:       }
                   1245:       data = LOCENDIAN32(*(uint32 *)pattern);
                   1246:       if (cellinfo & 1<<11) {
1.1.1.2 ! root     1247:         /* horizontal flip */
        !          1248:         for (i = 0; i < 8; i++) {
        !          1249:           pixel = data & 15;
        !          1250:           LINEDATA(i, pixel, palette, priority);
        !          1251:           data>>= 4;
        !          1252:         }
1.1       root     1253:       } else {
1.1.1.2 ! root     1254:         for (i = 0; i < 8; i++) {
        !          1255:           pixel = (data>>28) & 15;
        !          1256:           LINEDATA(i, pixel, palette, priority);
        !          1257:           data<<= 4;
        !          1258:         }
1.1       root     1259:       }
                   1260:     }
1.1.1.2 ! root     1261:   } /* hcell */
1.1       root     1262: }
                   1263: 
                   1264: void vdp_layer_interlace(unsigned int line, unsigned int layer,
1.1.1.2 ! root     1265:                         unsigned int priority, uint8 *linedata)
1.1       root     1266: {
                   1267:   int i, j;
                   1268:   uint8 hsize = vdp_reg[16] & 3;
                   1269:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
                   1270:   uint8 hmode = vdp_reg[11] & 3;
                   1271:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
                   1272:   uint16 vramoffset = (layer ? ((vdp_reg[4] & 7) << 13) :
1.1.1.2 ! root     1273:                       ((vdp_reg[2] & (7<<3)) << 10));
1.1       root     1274:   uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset);
                   1275:   uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10)
1.1.1.2 ! root     1276:                                   + vdp_vram + layer*2);
1.1       root     1277:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
                   1278:   uint16 hwidth, vwidth, hoffset, voffset;
                   1279:   uint16 cellinfo;
                   1280:   uint8 *pattern;
                   1281:   uint32 data;
                   1282:   uint8 palette;
                   1283:   uint8 pixel;
                   1284:   uint8 topbottom, leftright, winhpos, winvpos;
                   1285: 
                   1286:   if (layer == 0) {
                   1287:     /* turn off A when window is on */
                   1288:     topbottom = vdp_reg[18] & 0x80;
                   1289:     leftright = vdp_reg[17] & 0x80;
                   1290:     winhpos = vdp_reg[17] & 0x1f;
                   1291:     winvpos = vdp_reg[18] & 0x1f;
                   1292:     if (topbottom) {
                   1293:       if ((line>>4) >= winvpos)
1.1.1.2 ! root     1294:         return;
1.1       root     1295:     } else {
                   1296:       if ((line>>4) < winvpos)
1.1.1.2 ! root     1297:         return;
1.1       root     1298:     }
                   1299:   }
                   1300: 
                   1301:   /* BUG: layer A is still displayed left/right when window is on,
                   1302:      only apparent with high-priority layer A and low-priority window */
                   1303: 
                   1304:   switch(hmode) {
                   1305:   case 0: /* full screen */
                   1306:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF;
                   1307:     break;
                   1308:   case 2: /* cell scroll */
                   1309:     /* interlace we use the actual line for the hscroll */
                   1310:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*((line>>1) & ~7)])) & 0x3FF;
                   1311:     break;
                   1312:   case 3: /* line scroll */
                   1313:     /* interlace we use the actual line for the hscroll */
                   1314:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(line>>1)])) & 0x3FF;
                   1315:     break;
                   1316:   default:
                   1317:     LOG_NORMAL(("prohibited HSCR/LSCR"));
                   1318:     hoffset = 0;
                   1319:     break;
                   1320:   }
                   1321:   hwidth = 32+hsize*32;
                   1322:   vwidth = 32+vsize*32;
                   1323:   hoffset&= (hwidth*8)-1; /* put offset in range */
                   1324:   voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF;
                   1325:   voffset&= (vwidth*16)-1; /* put offset in range */
                   1326: 
                   1327:   cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]);
                   1328:   if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
                   1329:     palette = (cellinfo >> 13) & 3;
                   1330:     pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */
                   1331:     if (cellinfo & 1<<12) {
                   1332:       /* vertical flip */
                   1333:       pattern+= 4*(15-(voffset & 15));
                   1334:     } else {
                   1335:       /* no vertical flip */
                   1336:       pattern+= 4*(voffset & 15);
                   1337:     }
                   1338:     data = LOCENDIAN32(*(uint32 *)pattern);
                   1339:     if (cellinfo & 1<<11) {
                   1340:       /* horizontal flip */
                   1341:       data>>= (hoffset & 7)*4; /* get first pixel in bottom 4 bits */
                   1342:       for (i = 0; i < 8-(hoffset & 7); i++) {
1.1.1.2 ! root     1343:         pixel = data & 15;
        !          1344:         LINEDATA(i, pixel, palette, priority);
        !          1345:         data>>= 4;
1.1       root     1346:       }
                   1347:     } else {
                   1348:       data<<= (hoffset & 7)*4; /* get first pixel in top 4 bits */
                   1349:       for (i = 0; i < 8-(hoffset & 7); i++) {
1.1.1.2 ! root     1350:         pixel = (data>>28) & 15;
        !          1351:         LINEDATA(i, pixel, palette, priority);
        !          1352:         data<<= 4;
1.1       root     1353:       }
                   1354:     }
                   1355:   }
                   1356:   linedata+= 8-(hoffset & 7);
                   1357:   hoffset+= 8;
                   1358:   hoffset&= (hwidth*8)-1; /* put offset in range */
                   1359:   for (j = 0; j < screencells-1; j++) {
                   1360:     if (vmode) {
                   1361:       /* 2-cell scroll */
                   1362:       /* DEBUG DEBUG DEBUG awooga awooga */
                   1363:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
1.1.1.2 ! root     1364:                                     [2*(j>>1)+layer] )) & 0x7FF;
1.1       root     1365:     } else {
                   1366:       /* full screen */
                   1367:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF;
                   1368:     }
                   1369:     voffset&= (vwidth*16)-1; /* put offset in range */
                   1370:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]);
                   1371:     /* printf("hoff: %04X voff: %04X hwid: %04X cell: %08X info: %04X\n",
1.1.1.2 ! root     1372:            hoffset, voffset, hwidth, (hoffset>>3)+hwidth*(voffset>>4),
        !          1373:            cellinfo); */
1.1       root     1374:     /* printf("loc %08X cellinfo %08X\n",
1.1.1.2 ! root     1375:            (hoffset>>3)+hwidth*(voffset>>4),
        !          1376:            cellinfo); */
1.1       root     1377:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
                   1378:       palette = (cellinfo >> 13) & 3;
                   1379:       pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */
                   1380:       if (cellinfo & 1<<12) {
1.1.1.2 ! root     1381:         /* vertical flip */
        !          1382:         pattern+= 4*(15-(voffset & 15));
1.1       root     1383:       } else {
1.1.1.2 ! root     1384:         /* no vertical flip */
        !          1385:         pattern+= 4*(voffset & 15);
1.1       root     1386:       }
                   1387:       data = LOCENDIAN32(*(uint32 *)pattern);
                   1388:       if (cellinfo & 1<<11) {
1.1.1.2 ! root     1389:         /* horizontal flip */
        !          1390:         for (i = 0; i < 8; i++) {
        !          1391:           pixel = data & 15;
        !          1392:           LINEDATA(i, pixel, palette, priority);
        !          1393:           data>>= 4;
        !          1394:         }
1.1       root     1395:       } else {
1.1.1.2 ! root     1396:         for (i = 0; i < 8; i++) {
        !          1397:           pixel = (data>>28) & 15;
        !          1398:           LINEDATA(i, pixel, palette, priority);
        !          1399:           data<<= 4;
        !          1400:         }
1.1       root     1401:       }
                   1402:     }
                   1403:     linedata+= 8;
                   1404:     hoffset+= 8;
                   1405:     hoffset&= (hwidth*8)-1; /* put offset in range */
                   1406:   }
                   1407:   if (hoffset & 7) {
                   1408:     if (vmode) {
                   1409:       /* 2-cell scroll - note use last offset, not next */
                   1410:       /* DEBUG DEBUG DEBUG awooga awooga */
                   1411:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
1.1.1.2 ! root     1412:                                     [2*(j>>1)+layer] )) & 0x7FF;
1.1       root     1413:     } else {
                   1414:       /* full screen */
                   1415:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF;
                   1416:     }
                   1417:     voffset&= (vwidth*16)-1; /* put offset in range */
                   1418:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]);
                   1419:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
                   1420:       palette = (cellinfo >> 13) & 3;
                   1421:       pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */
                   1422:       if (cellinfo & 1<<12) {
1.1.1.2 ! root     1423:         /* vertical flip */
        !          1424:         pattern+= 4*(15-(voffset & 15));
1.1       root     1425:       } else {
1.1.1.2 ! root     1426:         /* no vertical flip */
        !          1427:         pattern+= 4*(voffset & 15);
1.1       root     1428:       }
                   1429:       data = LOCENDIAN32(*(uint32 *)pattern);
                   1430:       if (cellinfo & 1<<11) {
1.1.1.2 ! root     1431:         /* horizontal flip */
        !          1432:         for (i = 0; i < (hoffset & 7); i++) {
        !          1433:           pixel = data & 15;
        !          1434:           LINEDATA(i, pixel, palette, priority);
        !          1435:           data>>= 4;
        !          1436:         }
1.1       root     1437:       } else {
1.1.1.2 ! root     1438:         for (i = 0; i < (hoffset & 7); i++) {
        !          1439:           pixel = (data>>28) & 15;
        !          1440:           LINEDATA(i, pixel, palette, priority);
        !          1441:           data<<= 4;
        !          1442:         }
1.1       root     1443:       }
                   1444:     }
                   1445:     linedata+= 8;
                   1446:   }
                   1447: }
                   1448: 
1.1.1.2 ! root     1449: void vdp_renderline(unsigned int line, uint8 *linedata, unsigned int odd)
1.1       root     1450: {
                   1451:   int i;
1.1.1.2 ! root     1452:   uint8 datablock[320*4];
        !          1453:   uint8 *data_sprite = datablock;
        !          1454:   uint8 *data_layerA = datablock + 320;
        !          1455:   uint8 *data_layerB = datablock + 320*2;
        !          1456:   uint8 *priorities = datablock + 320*3;
        !          1457:   uint8 bg = vdp_reg[7] & 63;
        !          1458:   unsigned int winvpos = vdp_reg[18] & 0x1f;
        !          1459:   int windowall;
        !          1460:   unsigned int interlace = (vdp_reg[12] >> 1) & 3;
1.1       root     1461: 
1.1.1.2 ! root     1462:   windowall = ((vdp_reg[18] & 0x80) ? (winvpos == 0x1f || (line/8) >= winvpos)
        !          1463:                : (line/8 < winvpos));
1.1       root     1464: 
1.1.1.2 ! root     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:   }
1.1       root     1473: 
1.1.1.2 ! root     1474:   if (vdp_layerS || vdp_layerSp)
        !          1475:     vdp_sprites(interlace ? (line*2+odd) : line, priorities, data_sprite);
        !          1476:   if (vdp_layerA || vdp_layerAp) {
        !          1477:     if (!windowall)
        !          1478:       vdp_newlayer(interlace ? (line*2+odd) : line, priorities, data_layerA, 0);
        !          1479:     if (vdp_layerW || vdp_layerWp)
        !          1480:       vdp_newwindow(line, priorities, data_layerA);
        !          1481:   }
        !          1482:   if (vdp_layerB || vdp_layerBp)
        !          1483:     vdp_newlayer(interlace ? (line*2+odd) : line, priorities, data_layerB, 1);
        !          1484: 
        !          1485:   for (i = 0; i < 320; i++) {
        !          1486:     switch(priorities[i] | (vdp_reg[12] & 1<<3)) {
        !          1487:     case 0:                                        /* s/ten=0, B=0, A=0, S=0 */
        !          1488:       if (data_sprite[i])
        !          1489:         linedata[i] = data_sprite[i];
        !          1490:       else if (data_layerA[i])
        !          1491:         linedata[i] = data_layerA[i];
        !          1492:       else if (data_layerB[i])
        !          1493:         linedata[i] = data_layerB[i];
        !          1494:       else
        !          1495:         linedata[i] = bg;
        !          1496:       break;
        !          1497:     case 1:                                        /* s/ten=0, B=1, A=0, S=0 */
        !          1498:       if (data_layerB[i])
        !          1499:         linedata[i] = data_layerB[i];
        !          1500:       else if (data_sprite[i])
        !          1501:         linedata[i] = data_sprite[i];
        !          1502:       else if (data_layerA[i])
        !          1503:         linedata[i] = data_layerA[i];
        !          1504:       else
        !          1505:         linedata[i] = bg;
        !          1506:       break;
        !          1507:     case 2:                                        /* s/ten=0, B=0, A=1, S=0 */
        !          1508:       if (data_layerA[i])
        !          1509:         linedata[i] = data_layerA[i];
        !          1510:       else if (data_sprite[i])
        !          1511:         linedata[i] = data_sprite[i];
        !          1512:       else if (data_layerB[i])
        !          1513:         linedata[i] = data_layerB[i];
        !          1514:       else
        !          1515:         linedata[i] = bg;
        !          1516:       break;
        !          1517:     case 3:                                        /* s/ten=0, B=1, A=1, S=0 */
        !          1518:       if (data_layerA[i])
        !          1519:         linedata[i] = data_layerA[i];
        !          1520:       else if (data_layerB[i])
        !          1521:         linedata[i] = data_layerB[i];
        !          1522:       else if (data_sprite[i])
        !          1523:         linedata[i] = data_sprite[i];
        !          1524:       else
        !          1525:         linedata[i] = bg;
        !          1526:       break;
        !          1527:     case 4:                                        /* s/ten=0, B=0, A=0, S=1 */
        !          1528:       if (data_sprite[i])
        !          1529:         linedata[i] = data_sprite[i];
        !          1530:       else if (data_layerA[i])
        !          1531:         linedata[i] = data_layerA[i];
        !          1532:       else if (data_layerB[i])
        !          1533:         linedata[i] = data_layerB[i];
        !          1534:       else
        !          1535:         linedata[i] = bg;
        !          1536:       break;
        !          1537:     case 5:                                        /* s/ten=0, B=1, A=0, S=1 */
        !          1538:       if (data_sprite[i])
        !          1539:         linedata[i] = data_sprite[i];
        !          1540:       else if (data_layerB[i])
        !          1541:         linedata[i] = data_layerB[i];
        !          1542:       else if (data_layerA[i])
        !          1543:         linedata[i] = data_layerA[i];
        !          1544:       else
        !          1545:         linedata[i] = bg;
        !          1546:       break;
        !          1547:     case 6:                                        /* s/ten=0, B=0, A=1, S=1 */
        !          1548:       if (data_sprite[i])
        !          1549:         linedata[i] = data_sprite[i];
        !          1550:       else if (data_layerA[i])
        !          1551:         linedata[i] = data_layerA[i];
        !          1552:       else if (data_layerB[i])
        !          1553:         linedata[i] = data_layerB[i];
        !          1554:       else
        !          1555:         linedata[i] = bg;
        !          1556:       break;
        !          1557:     case 7:                                        /* s/ten=0, B=1, A=1, S=1 */
        !          1558:       if (data_sprite[i])
        !          1559:         linedata[i] = data_sprite[i];
        !          1560:       else if (data_layerA[i])
        !          1561:         linedata[i] = data_layerA[i];
        !          1562:       else if (data_layerB[i])
        !          1563:         linedata[i] = data_layerB[i];
        !          1564:       else
        !          1565:         linedata[i] = bg;
        !          1566:       break;
        !          1567:     case 8:                                        /* s/ten=1, B=0, A=0, S=0 */
        !          1568:       if (data_sprite[i]) {
        !          1569:         if (data_sprite[i] == 63) {                /* shadow operator */
        !          1570:           if (data_layerA[i])
        !          1571:             linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1572:           else if (data_layerB[i])
        !          1573:             linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1574:           else
        !          1575:             linedata[i] = bg | 128; /* shadow */
        !          1576:         } else if (data_sprite[i] == 62) {         /* highlight operator */
        !          1577:           if (data_layerA[i])
        !          1578:             linedata[i] = data_layerA[i]; /* normal */
        !          1579:           else if (data_layerB[i])
        !          1580:             linedata[i] = data_layerB[i]; /* normal */
        !          1581:           else
        !          1582:             linedata[i] = bg; /* normal */
        !          1583:         } else {
        !          1584:           linedata[i] = data_sprite[i] | 128; /* shadow */
        !          1585:         }
        !          1586:       } else {
        !          1587:         if (data_layerA[i])
        !          1588:           linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1589:         else if (data_layerB[i])
        !          1590:           linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1591:         else
        !          1592:           linedata[i] = bg | 128; /* shadow */
        !          1593:       }
        !          1594:       break;
        !          1595:     case 9:                                        /* s/ten=1, B=1, A=0, S=0 */
        !          1596:       if (data_layerB[i]) {
        !          1597:         linedata[i] = data_layerB[i]; /* normal */
        !          1598:       } else {
        !          1599:         if (data_sprite[i]) {
        !          1600:           if (data_sprite[i] == 63) {              /* shadow operator */
        !          1601:             if (data_layerA[i])
        !          1602:               linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1603:             else
        !          1604:               linedata[i] = bg | 128; /* shadow */
        !          1605:           } else if (data_sprite[i] == 62) {       /* highlight operator */
        !          1606:             if (data_layerA[i])
        !          1607:               linedata[i] = data_layerA[i] | 64; /* highlight */
        !          1608:             else
        !          1609:               linedata[i] = bg | 64; /* highlight */
        !          1610:           } else {
        !          1611:             linedata[i] = data_sprite[i]; /* normal */
        !          1612:           }
        !          1613:         } else {
        !          1614:           if (data_layerA[i])
        !          1615:             linedata[i] = data_layerA[i]; /* normal */
        !          1616:           else
        !          1617:             linedata[i] = bg; /* normal */
        !          1618:         }
        !          1619:       }
        !          1620:       break;
        !          1621:     case 10:                                       /* s/ten=1, B=0, A=1, S=0 */
        !          1622:       if (data_layerA[i]) {
        !          1623:         linedata[i] = data_layerA[i]; /* normal */
        !          1624:       } else {
        !          1625:         if (data_sprite[i]) {
        !          1626:           if (data_sprite[i] == 63) {              /* shadow operator */
        !          1627:             if (data_layerB[i])
        !          1628:               linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1629:             else
        !          1630:               linedata[i] = bg | 128; /* shadow */
        !          1631:           } else if (data_sprite[i] == 62) {       /* highlight operator */
        !          1632:             if (data_layerB[i])
        !          1633:               linedata[i] = data_layerB[i] | 64; /* highlight */
        !          1634:             else
        !          1635:               linedata[i] = bg | 64; /* highlight */
        !          1636:           } else {
        !          1637:             linedata[i] = data_sprite[i]; /* normal */
        !          1638:           }
        !          1639:         } else {
        !          1640:           if (data_layerB[i])
        !          1641:             linedata[i] = data_layerB[i]; /* normal */
        !          1642:           else
        !          1643:             linedata[i] = bg; /* normal */
        !          1644:         }
        !          1645:       }
        !          1646:       break;
        !          1647:     case 11:                                       /* s/ten=1, B=1, A=1, S=0 */
        !          1648:       if (data_layerA[i]) {
        !          1649:         linedata[i] = data_layerA[i]; /* normal */
        !          1650:       } else if (data_layerB[i]) {
        !          1651:         linedata[i] = data_layerB[i]; /* normal */
        !          1652:       } else if (data_sprite[i]) {
        !          1653:         if (data_sprite[i] == 63)                  /* shadow operator */
        !          1654:           linedata[i] = bg | 128; /* shadow */
        !          1655:         else if (data_sprite[i] == 62)             /* highlight operator */
        !          1656:           linedata[i] = bg | 64; /* highlight */
        !          1657:         else
        !          1658:           linedata[i] = data_sprite[i]; /* normal */
        !          1659:       } else {
        !          1660:         linedata[i] = bg; /* normal */
        !          1661:       }
        !          1662:       break;
        !          1663:     case 12:                                       /* s/ten=0, B=0, A=0, S=1 */
        !          1664:       if (data_sprite[i]) {
        !          1665:         if (data_sprite[i] == 63) {                /* shadow operator */
        !          1666:           if (data_layerA[i])
        !          1667:             linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1668:           else if (data_layerB[i])
        !          1669:             linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1670:           else
        !          1671:             linedata[i] = bg | 128; /* shadow */
        !          1672:         } else if (data_sprite[i] == 62) {         /* highlight operator */
        !          1673:           if (data_layerA[i])
        !          1674:             linedata[i] = data_layerA[i]; /* normal */
        !          1675:           else if (data_layerB[i])
        !          1676:             linedata[i] = data_layerB[i]; /* normal */
        !          1677:           else
        !          1678:             linedata[i] = bg; /* normal */
        !          1679:         } else {
        !          1680:           linedata[i] = data_sprite[i]; /* normal */
        !          1681:         }
        !          1682:       } else if (data_layerA[i]) {
        !          1683:         linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1684:       } else if (data_layerB[i]) {
        !          1685:         linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1686:       } else {
        !          1687:         linedata[i] = bg | 128; /* shadow */
        !          1688:       }
        !          1689:       break;
        !          1690:     case 13:                                       /* s/ten=1, B=1, A=0, S=1 */
        !          1691:       if (data_sprite[i]) {
        !          1692:         if (data_sprite[i] == 63) {                /* shadow operator */
        !          1693:           if (data_layerB[i])
        !          1694:             linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1695:           else if (data_layerA[i])
        !          1696:             linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1697:           else
        !          1698:             linedata[i] = bg | 128; /* shadow */
        !          1699:         } else if (data_sprite[i] == 62) {         /* highlight operator */
        !          1700:           if (data_layerB[i])
        !          1701:             linedata[i] = data_layerB[i] | 64; /* highlight */
        !          1702:           else if (data_layerA[i])
        !          1703:             linedata[i] = data_layerA[i] | 64; /* highlight */
        !          1704:           else
        !          1705:             linedata[i] = bg | 64; /* highlight */
        !          1706:         } else {
        !          1707:           linedata[i] = data_sprite[i]; /* normal */
        !          1708:         }
        !          1709:       } else if (data_layerB[i]) {
        !          1710:         linedata[i] = data_layerB[i]; /* normal */
        !          1711:       } else if (data_layerA[i]) {
        !          1712:         linedata[i] = data_layerA[i]; /* normal */
        !          1713:       }
        !          1714:       break;
        !          1715:     case 14:                                       /* s/ten=1, B=0, A=1, S=1 */
        !          1716:       if (data_sprite[i]) {
        !          1717:         if (data_sprite[i] == 63) {                /* shadow operator */
        !          1718:           if (data_layerA[i])
        !          1719:             linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1720:           else if (data_layerB[i])
        !          1721:             linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1722:           else
        !          1723:             linedata[i] = bg | 128; /* shadow */
        !          1724:         } else if (data_sprite[i] == 62) {         /* highlight operator */
        !          1725:           if (data_layerA[i])
        !          1726:             linedata[i] = data_layerA[i] | 64; /* highlight */
        !          1727:           else if (data_layerB[i])
        !          1728:             linedata[i] = data_layerB[i] | 64; /* highlight */
        !          1729:           else
        !          1730:             linedata[i] = bg | 64; /* highlight */
        !          1731:         } else {
        !          1732:           linedata[i] = data_sprite[i]; /* normal */
        !          1733:         }
        !          1734:       } else if (data_layerA[i]) {
        !          1735:         linedata[i] = data_layerA[i]; /* normal */
        !          1736:       } else if (data_layerB[i]) {
        !          1737:         linedata[i] = data_layerB[i]; /* normal */
        !          1738:       }
        !          1739:       break;
        !          1740:     case 15:                                       /* s/ten=1, B=1, A=1, S=1 */
        !          1741:       if (data_sprite[i]) {
        !          1742:         if (data_sprite[i] == 63) {                /* shadow operator */
        !          1743:           if (data_layerA[i])
        !          1744:             linedata[i] = data_layerA[i] | 128; /* shadow */
        !          1745:           else if (data_layerB[i])
        !          1746:             linedata[i] = data_layerB[i] | 128; /* shadow */
        !          1747:           else
        !          1748:             linedata[i] = bg | 128; /* shadow */
        !          1749:         } else if (data_sprite[i] == 62) {         /* highlight operator */
        !          1750:           if (data_layerA[i])
        !          1751:             linedata[i] = data_layerA[i] | 64; /* highlight */
        !          1752:           else if (data_layerB[i])
        !          1753:             linedata[i] = data_layerB[i] | 64; /* highlight */
        !          1754:           else
        !          1755:             linedata[i] = bg | 64; /* highlight */
        !          1756:         } else {
        !          1757:           linedata[i] = data_sprite[i]; /* normal */
        !          1758:         }
        !          1759:       } else if (data_layerA[i]) {
        !          1760:         linedata[i] = data_layerA[i]; /* normal */
        !          1761:       } else if (data_layerB[i]) {
        !          1762:         linedata[i] = data_layerB[i]; /* normal */
        !          1763:       }
        !          1764:       break;
        !          1765:     }
1.1       root     1766:   }
                   1767: }
                   1768: 
                   1769: void vdp_renderline_interlace2(unsigned int line, uint8 *linedata)
                   1770: {
                   1771:   int i;
1.1.1.2 ! root     1772:   uint8 pridata[640];
        !          1773:   uint8 *spritedata = pridata + 320;
1.1       root     1774: 
1.1.1.2 ! root     1775:   memset(pridata, 0, 640);
        !          1776:   memset(linedata, vdp_reg[7] & 63, 320);
1.1       root     1777: 
                   1778:   if (vdp_reg[1] & 1<<6) {
1.1.1.2 ! root     1779:     vdp_sprites(line, pridata, spritedata);
        !          1780:     ;
1.1       root     1781:     if (vdp_layerB)
                   1782:       vdp_layer_interlace(line, 1, 0, linedata);
                   1783:     if (vdp_layerA)
                   1784:       vdp_layer_interlace(line, 0, 0, linedata);
                   1785:     /*
                   1786:       if (vdp_layerW)
                   1787:       vdp_window(line, 0, linedata);
                   1788:     */
                   1789:     if (vdp_layerH && (vdp_reg[12] & 1<<3))
                   1790:       vdp_shadow(line, linedata);
1.1.1.2 ! root     1791:     if (vdp_layerS)
        !          1792:       vdp_spritelayer(line, spritedata, pridata, linedata, 0);
1.1       root     1793:     if (vdp_layerBp)
                   1794:       vdp_layer_interlace(line, 1, 1, linedata);
                   1795:     if (vdp_layerAp)
                   1796:       vdp_layer_interlace(line, 0, 1, linedata);
                   1797:     /*
                   1798:       if (vdp_layerWp)
                   1799:       vdp_window(line, 1, linedata);
                   1800:     */
                   1801:     if (vdp_layerSp)
1.1.1.2 ! root     1802:       vdp_spritelayer(line, spritedata, pridata, linedata, 1);
1.1       root     1803:   }
                   1804: }
                   1805: 
                   1806: void vdp_renderframe(uint8 *framedata, unsigned int lineoffset)
                   1807: {
                   1808:   unsigned int i, line;
                   1809:   uint32 background;
                   1810:   unsigned int vertcells = vdp_reg[1] & 1<<3 ? 30 : 28;
                   1811:   uint8 *linedata;
                   1812: 
                   1813:   /* fill in background */
                   1814: 
                   1815:   background = vdp_reg[7] & 63;
                   1816:   background|= background<<8;
                   1817:   background|= background<<16;
                   1818: 
                   1819:   for (line = 0; line < vertcells*8; line++) {
                   1820:     linedata = framedata + line*lineoffset;
                   1821:     for (i = 0; i < (320 / 4); i++) {
                   1822:       ((uint32 *)linedata)[i] = background;
                   1823:     }
                   1824:   }
                   1825: 
                   1826:   if (vdp_reg[1] & 1<<6) {
                   1827:     if (vdp_layerB)
                   1828:       vdp_layer_simple(1, 0, framedata, lineoffset);
                   1829:     if (vdp_layerA)
                   1830:       vdp_layer_simple(0, 0, framedata, lineoffset);
                   1831:     if (vdp_layerH && (vdp_reg[12] & 1<<3))
                   1832:       vdp_shadow_simple(framedata, lineoffset);
1.1.1.2 ! root     1833:     if (vdp_layerS)
        !          1834:       vdp_sprites_simple(0, framedata, lineoffset);
1.1       root     1835:     if (vdp_layerBp)
                   1836:       vdp_layer_simple(1, 1, framedata, lineoffset);
                   1837:     if (vdp_layerAp)
                   1838:       vdp_layer_simple(0, 1, framedata, lineoffset);
                   1839:     if (vdp_layerSp)
                   1840:       vdp_sprites_simple(1, framedata, lineoffset);
                   1841:   }
                   1842: }
                   1843: 
                   1844: void vdp_showregs(void)
                   1845: {
                   1846:   int i;
                   1847: 
                   1848:   for (i = 0; i < 25; i++) {
                   1849:     printf("[%02d] %02X: ", i, vdp_reg[i]);
                   1850:     switch(i) {
                   1851:     case 0:
                   1852:       printf("%s ", vdp_reg[0] & 1<<1 ? "HV-stop" : "HV-enable");
                   1853:       printf("%s ", vdp_reg[0] & 1<<4 ? "HInt-enable" : "HInt-disable");
                   1854:       break;
                   1855:     case 1:
                   1856:       printf("%s ", vdp_reg[1] & 1<<3 ? "30-cell" : "28-cell");
                   1857:       printf("%s ", vdp_reg[1] & 1<<4 ? "DMA-enable" : "DMA-disable");
                   1858:       printf("%s ", vdp_reg[1] & 1<<5 ? "VInt-enable" : "VInt-disable");
                   1859:       printf("%s ", vdp_reg[1] & 1<<6 ? "Disp-enable" : "Disp-disable");
                   1860:       break;
                   1861:     case 2:
                   1862:       printf("Scroll A @ %04X", (vdp_reg[2] & 0x38)<<10);
                   1863:       break;
                   1864:     case 3:
                   1865:       printf("Window @ %04X", (vdp_reg[3] & 0x3E)<<10);
                   1866:       break;
                   1867:     case 4:
                   1868:       printf("Scroll B @ %04X", (vdp_reg[4] & 7)<<13);
                   1869:       break;
                   1870:     case 5:
                   1871:       printf("Sprites @ %04X", (vdp_reg[5] & 0x7F)<<9);
                   1872:       break;
                   1873:     case 7:
                   1874:       printf("bgpal %d col %d", (vdp_reg[7]>>4 & 3), (vdp_reg[7] & 15));
                   1875:       break;
                   1876:     case 10:
                   1877:       printf("hintreg %04X", vdp_reg[10]);
                   1878:       break;
                   1879:     case 11:
                   1880:       printf("V-mode %d H-mode %d ", (vdp_reg[11]>>2) & 1, (vdp_reg[11] & 3));
                   1881:       printf("%s", (vdp_reg[11] & 1<<3) ? "ExtInt-enable" : "ExtInt-disable");
                   1882:       break;
                   1883:     case 12:
                   1884:       printf("Interlace %d ", (vdp_reg[12]>>1) & 3);
                   1885:       printf("%s ", (vdp_reg[12] & 1<<0) ? "40-cell" : "32-cell");
                   1886:       printf("%s ", (vdp_reg[12] & 1<<3) ? "Shadow-enable" : "Shadow-disable");
                   1887:       break;
                   1888:     case 13:
                   1889:       printf("Scroll A @ %04X", (vdp_reg[13] & 0x3F)<<10);
                   1890:       break;
                   1891:     case 15:
                   1892:       printf("Autoinc %d", vdp_reg[15]);
                   1893:       break;
                   1894:     case 16:
                   1895:       printf("Vsize %d Hsize %d", (vdp_reg[16]>>4) & 3, (vdp_reg[16] & 3));
                   1896:       break;
                   1897:     case 17:
                   1898:       printf("Window H %s ", (vdp_reg[17] & 1<<7) ? "right" : "left");
                   1899:       printf("%d", vdp_reg[17] & 0x1F);
                   1900:       break;
                   1901:     case 18:
                   1902:       printf("Window V %s ", (vdp_reg[18] & 1<<7) ? "lower" : "upper");
                   1903:       printf("%d", vdp_reg[18] & 0x1F);
                   1904:       break;
                   1905:     case 19:
                   1906:       printf("DMA-length-low %02X", vdp_reg[19]);
                   1907:       break;
                   1908:     case 20:
                   1909:       printf("DMA-length-high %02X", vdp_reg[20]);
                   1910:       break;
                   1911:     case 21:
                   1912:       printf("DMA-source-low %02X", vdp_reg[21]);
                   1913:       break;
                   1914:     case 22:
                   1915:       printf("DMA-source-mid %02X", vdp_reg[22]);
                   1916:       break;
                   1917:     case 23:
                   1918:       printf("DMA-source-high %02X", vdp_reg[23]);
                   1919:       break;
                   1920:     }
                   1921:     printf("\n");
                   1922:   }
                   1923: }
                   1924: 
                   1925: void vdp_spritelist(void)
                   1926: {
                   1927:   uint8 *spritelist = vdp_vram + ((vdp_reg[5] & 0x7F)<<9);
                   1928:   uint8 *sprite;
                   1929:   uint8 link = 0;
                   1930:   uint16 pattern;
                   1931:   uint8 palette;
                   1932:   uint16 cellinfo;
                   1933:   sint16 vpos, hpos, vmax;
                   1934:   uint8 vsize, hsize;
                   1935: 
                   1936:   LOG_REQUEST(("SPRITE DUMP: (base=vram+%X)",
1.1.1.2 ! root     1937:                (vdp_reg[5] & 0x7f)<<9));
1.1       root     1938:   do {
                   1939:     sprite = spritelist + (link<<3);
                   1940:     hpos = (LOCENDIAN16(*(uint16 *)(sprite+6)) & 0x1FF) - 0x80;
                   1941:     vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x3FF) - 0x80;
                   1942:     vsize = 1+(sprite[2] & 3);
                   1943:     hsize = 1+((sprite[2]>>2) & 3);
                   1944:     cellinfo = LOCENDIAN16(*(uint16 *)(sprite+4));
                   1945:     pattern = cellinfo & 0x7FF;
                   1946:     palette = (cellinfo >> 13) & 3;
                   1947:     vmax = vpos + vsize*8;
                   1948: 
                   1949:     LOG_REQUEST(("Sprite %d @ %X", link,
1.1.1.2 ! root     1950:                 (link<<3) | (vdp_reg[5] & 0x7f)<<9));
1.1       root     1951:     LOG_REQUEST(("  Pos:  %d,%d", hpos, vpos));
                   1952:     LOG_REQUEST(("  Size: %d,%d", hsize, vsize));
                   1953:     LOG_REQUEST(("  Pri: %d, Pal: %d, Vflip: %d, Hflip: %d",
1.1.1.2 ! root     1954:                 (cellinfo>>15 & 1), (cellinfo>>13 & 3), (cellinfo>>12 & 1),
        !          1955:                 (cellinfo>>11 & 1)));
        !          1956:     LOG_REQUEST(("  Pattern: %d (%x) @ vram+%X (%X if interlaced)",
        !          1957:                 (cellinfo & 0x7FF), (cellinfo & 0x7FF),
        !          1958:                (cellinfo & 0x7FF)*32, (cellinfo & 0x7FF)*32));
1.1       root     1959:     link = sprite[3] & 0x7F;
                   1960:   } while (link);
                   1961: }
                   1962: 
                   1963: void vdp_describe(void)
                   1964: {
                   1965:   int layer;
                   1966:   unsigned int line;
                   1967:   uint32 o_patterndata, o_hscrolldata;
                   1968:   uint16 *patterndata, *hscrolldata;
                   1969:   uint8 hsize = vdp_reg[16] & 3;
                   1970:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
                   1971:   uint8 hmode = vdp_reg[11] & 3;
                   1972:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
                   1973:   uint16 hwidth, vwidth, hoffset, voffset, raw_hoffset;
                   1974: 
                   1975:   hwidth = 32+hsize*32;
                   1976:   vwidth = 32+vsize*32;
                   1977:   LOG_REQUEST(("VDP description:"));
                   1978:   LOG_REQUEST(("  hsize = %d (ie. width=%d)", hsize, hwidth));
                   1979:   LOG_REQUEST(("  vsize = %d (ie. width=%d)", vsize, vwidth));
                   1980:   LOG_REQUEST(("  hmode = %d (0=full, 2=cell, 3=line)", hmode));
                   1981:   LOG_REQUEST(("  vmode = %d (0=full, 1=2cell", vmode));
                   1982: 
                   1983:   for (layer = 0; layer < 2; layer++) {
                   1984:     LOG_REQUEST(("  Layer %s:", layer == 0 ? "A" : "B"));
                   1985:     o_patterndata = (layer == 0 ? ((vdp_reg[2] & 0x38)<<10) :
1.1.1.2 ! root     1986:                     ((vdp_reg[4] & 7)<<13));
1.1       root     1987:     o_hscrolldata = layer*2 + ((vdp_reg[13] & 63)<<10);
                   1988:     LOG_REQUEST(("    Pattern data @ vram+%08X", o_patterndata));
                   1989:     LOG_REQUEST(("    Hscroll data @ vram+%08X", o_hscrolldata));
                   1990:     patterndata = (uint16 *)(vdp_vram + o_patterndata);
                   1991:     hscrolldata = (uint16 *)(vdp_vram + o_hscrolldata);
                   1992:     for (line = 0; line < vdp_vislines; line++) {
                   1993:       switch(hmode) {
                   1994:       case 0: /* full screen */
1.1.1.2 ! root     1995:         hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF;
        !          1996:         break;
1.1       root     1997:       case 2: /* cell scroll */
1.1.1.2 ! root     1998:         hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(line & ~7)])) & 0x3FF;
        !          1999:         break;
1.1       root     2000:       case 3: /* line scroll */
1.1.1.2 ! root     2001:         hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*line])) & 0x3FF;
        !          2002:         break;
1.1       root     2003:       default:
1.1.1.2 ! root     2004:         LOG_REQUEST(("prohibited HSCR/LSCR on line %d", line));
        !          2005:         hoffset = 0;
        !          2006:         break;
1.1       root     2007:       }
                   2008:       raw_hoffset = hoffset;
                   2009:       hoffset&= (hwidth*8)-1; /* put offset in range */
                   2010:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x3FF;
                   2011:       voffset&= (vwidth*8)-1; /* put offset in range */
                   2012:       LOG_REQUEST(("     line %d: hoffset=%d=%d, voffset=%d, "
1.1.1.2 ! root     2013:                   "firstcell=vram+%08X", line, raw_hoffset, hoffset, voffset,
        !          2014:                   o_patterndata+2*((hoffset>>3)+hwidth*(voffset>>3))));
1.1       root     2015:     }
                   2016:   }
                   2017: }
                   2018: 
                   2019: void vdp_eventinit(void)
                   2020: {
                   2021:   /* Facts from documentation:
                   2022:        H-Blank is 73.7 clock cycles long.
                   2023:        The VDP settings are aquired 36 clocks after start of H-Blank.
                   2024:        The display period is 413.3 clocks in duration.
                   2025:        V-Int occurs 14.7us after H-Int (which is 112 clock cycles)
                   2026:      Facts from clock data:
                   2027:        One line takes 488 clocks (vdp_clksperline_68k)
1.1.1.2 ! root     2028:      Assumptions: (not sure if these are true anymore)
1.1       root     2029:        We 'approximate' and make H-Int occur at the same time as H-Blank.
                   2030:        V-Blank starts at V-Int and ends at the start of line 0.
                   2031: 
                   2032:      vdp_event_start    = start of line, end of v-blank
                   2033:      vdp_event_vint     = v-int time on line 224 (or 240)
                   2034:                                 (112 clocks after h-int)
                   2035:      vdp_event_hint     = h-int time at end of each line
                   2036:      vdp_event_hdisplay = settings are aquired and current line displayed
                   2037:      vdp_event_end      = end of line, end of h-blank
                   2038: 
                   2039:      Note that if the program stays in H-Int 224 longer than 112 clocks, V-Int
                   2040:      is not supposed to occur due to the processor acknowledging the wrong
                   2041:      interrupt from the VDP, thus programs disable H-Ints on 223 to prevent
                   2042:      this problem.  We don't worry about this.
                   2043:   */
                   2044:   vdp_event = 0;
                   2045:   vdp_event_start = 0;
                   2046:   vdp_event_vint = 112-74;
                   2047:   vdp_event_hint = vdp_clksperline_68k-74;
                   2048:   vdp_event_hdisplay = vdp_event_hint+36;
                   2049:   vdp_event_end = vdp_clksperline_68k;
1.1.1.2 ! root     2050:   vdp_nextevent = 0;
1.1       root     2051: }
                   2052: 
                   2053: void vdp_endfield(void)
                   2054: {
                   2055:   vdp_line = 0;
                   2056:   vdp_eventinit();
                   2057:   vdp_oddframe^= 1; /* toggle */
                   2058:   /* printf("(%d,%d,%d,%d,%d)\n", vdp_event_type,
                   2059:      vdp_event_startline, vdp_event_hint, vdp_event_vdpplot,
                   2060:      vdp_event_endline); */
                   2061: }
                   2062: 
                   2063: inline void vdp_plotcell(uint8 *patloc, uint8 palette, uint8 flags,
1.1.1.2 ! root     2064:                         uint8 *cellloc, unsigned int lineoffset)
1.1       root     2065: {
                   2066:   int y, x;
                   2067:   uint8 value;
                   2068:   uint32 data;
                   2069: 
                   2070:   switch(flags) {
                   2071:   case 0:
                   2072:     /* normal tile - no s/ten */
                   2073:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
                   2074:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
                   2075:       for (x = 0; x < 8; x++, data<<= 4) {
1.1.1.2 ! root     2076:         value = data>>28;
        !          2077:         if (value)
        !          2078:           cellloc[x] = palette*16 + value;
1.1       root     2079:       }
                   2080:     }
                   2081:     break;
                   2082:   case 1:
                   2083:     /* h flipped tile - no s/ten */
                   2084:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
                   2085:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
                   2086:       for (x = 0; x < 8; x++, data>>= 4) {
1.1.1.2 ! root     2087:         value = data & 15;
        !          2088:         if (value)
        !          2089:           cellloc[x] = palette*16 + value;
1.1       root     2090:       }
                   2091:     }
                   2092:     break;
                   2093:   case 2:
                   2094:     /* v flipped tile - no s/ten */
                   2095:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
                   2096:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
                   2097:       for (x = 0; x < 8; x++, data<<= 4) {
1.1.1.2 ! root     2098:         value = data>>28;
        !          2099:         if (value)
        !          2100:           cellloc[x] = palette*16 + value;
1.1       root     2101:       }
                   2102:     }
                   2103:     break;
                   2104:   case 3:
                   2105:     /* h and v flipped tile - no s/ten */
                   2106:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
                   2107:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
                   2108:       for (x = 0; x < 8; x++, data>>= 4) {
1.1.1.2 ! root     2109:         value = data & 15;
        !          2110:         if (value)
        !          2111:           cellloc[x] = palette*16 + value;
1.1       root     2112:       }
                   2113:     }
                   2114:     break;
                   2115:   case 4:
                   2116:     /* normal tile - s/ten enabled */
                   2117:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
                   2118:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
                   2119:       for (x = 0; x < 8; x++, data<<= 4) {
1.1.1.2 ! root     2120:         value = data>>28;
        !          2121:         if (value) {
        !          2122:           if (palette == 3 && value == 14) {
        !          2123:             cellloc[x] = (cellloc[x] & 63) + 64;
        !          2124:           } else if (palette == 3 && value == 15) {
        !          2125:             cellloc[x] = (cellloc[x] & 63) + 128;
        !          2126:           } else {
        !          2127:             cellloc[x] = palette*16 + value;
        !          2128:           }
        !          2129:         }
1.1       root     2130:       }
                   2131:     }
                   2132:     break;
                   2133:   case 5:
                   2134:     /* h flipped tile - s/ten */
                   2135:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
                   2136:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
                   2137:       for (x = 0; x < 8; x++, data>>= 4) {
1.1.1.2 ! root     2138:         value = data & 15;
        !          2139:         if (value) {
        !          2140:           if (palette == 3 && value == 14) {
        !          2141:             cellloc[x] = (cellloc[x] & 63) + 64;
        !          2142:           } else if (palette == 3 && value == 15) {
        !          2143:             cellloc[x] = (cellloc[x] & 63) + 128;
        !          2144:           } else {
        !          2145:             cellloc[x] = palette*16 + value;
        !          2146:           }
        !          2147:         }
1.1       root     2148:       }
                   2149:     }
                   2150:     break;
                   2151:   case 6:
                   2152:     /* v flipped tile - s/ten enabled */
                   2153:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
                   2154:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
                   2155:       for (x = 0; x < 8; x++, data<<= 4) {
1.1.1.2 ! root     2156:         value = data>>28;
        !          2157:         if (value) {
        !          2158:           if (palette == 3 && value == 14) {
        !          2159:             cellloc[x] = (cellloc[x] & 63) + 64;
        !          2160:           } else if (palette == 3 && value == 15) {
        !          2161:             cellloc[x] = (cellloc[x] & 63) + 128;
        !          2162:           } else {
        !          2163:             cellloc[x] = palette*16 + value;
        !          2164:           }
        !          2165:         }
1.1       root     2166:       }
                   2167:     }
                   2168:     break;
                   2169:   case 7:
                   2170:     /* h and v flipped tile - s/ten enabled */
                   2171:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
                   2172:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
                   2173:       for (x = 0; x < 8; x++, data>>= 4) {
1.1.1.2 ! root     2174:         value = data & 15;
        !          2175:         if (value) {
        !          2176:           if (palette == 3 && value == 14) {
        !          2177:             cellloc[x] = (cellloc[x] & 63) + 64;
        !          2178:           } else if (palette == 3 && value == 15) {
        !          2179:             cellloc[x] = (cellloc[x] & 63) + 128;
        !          2180:           } else {
        !          2181:             cellloc[x] = palette*16 + value;
        !          2182:           }
        !          2183:         }
1.1       root     2184:       }
                   2185:     }
                   2186:     break;
                   2187:   default:
                   2188:     ui_err("Unknown plotcell flags");
                   2189:   }
                   2190: }
                   2191: 
                   2192: /* must be 8*lineoffset bytes scrap before and after fielddata and also
                   2193:    8 bytes before each line and 8 bytes after each line */
                   2194: 
                   2195: void vdp_layer_simple(unsigned int layer, unsigned int priority,
1.1.1.2 ! root     2196:                      uint8 *framedata, unsigned int lineoffset)
1.1       root     2197: {
                   2198:   int i, j;
                   2199:   uint8 hsize = vdp_reg[16] & 3;
                   2200:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
                   2201:   uint8 hmode = vdp_reg[11] & 3;
                   2202:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
                   2203:   uint16 vramoffset = (layer ? ((vdp_reg[4] & 7) << 13) :
1.1.1.2 ! root     2204:                       ((vdp_reg[2] & (7<<3)) << 10));
1.1       root     2205:   uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset);
                   2206:   uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10)
1.1.1.2 ! root     2207:                                   + vdp_vram + layer*2);
1.1       root     2208:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
                   2209:   uint16 hwidth = 32+hsize*32;
                   2210:   uint16 vwidth = 32+vsize*32;
                   2211:   uint16 hoffset, voffset;
                   2212:   uint16 cellinfo;
                   2213:   uint8 *pattern;
                   2214:   uint32 data;
                   2215:   uint8 palette;
                   2216:   uint8 value;
                   2217:   unsigned int xcell, ycell;
                   2218:   unsigned int pos;
                   2219:   uint8 *toploc, *cellloc;
                   2220:   uint8 flags;
                   2221:   uint32 hscroll, vscroll;
                   2222:   unsigned int x, y;
                   2223: 
                   2224:   for (xcell = 0; xcell <= screencells; xcell++) {
                   2225:     if (vmode) {
                   2226:       /* 2-cell scroll */
                   2227:       vscroll = ((xcell >= screencells ? xcell-2 : xcell) & ~1) + layer;
                   2228:     } else {
                   2229:       /* full screen */
                   2230:       vscroll = layer;
                   2231:     }
                   2232:     voffset = LOCENDIAN16( ((uint16 *)vdp_vsram)[vscroll] ) & 0x3FF;
                   2233:     toploc = framedata - lineoffset*(voffset & 7);
                   2234:     for (ycell = 0; ycell <= 28; ycell++, voffset+=8, toploc+=lineoffset*8) {
                   2235:       switch(hmode) {
                   2236:       case 0: /* full screen */
1.1.1.2 ! root     2237:         hscroll = 0;
        !          2238:         break;
1.1       root     2239:       case 2: /* cell scroll */
1.1.1.2 ! root     2240:         hscroll = 2 * (ycell >= 28 ? ycell-2 : ycell) * 8;
        !          2241:         break;
1.1       root     2242:       case 3: /* line scroll - approximation */
1.1.1.2 ! root     2243:         hscroll = 2 * (ycell >= 28 ? ycell-2 : ycell) * 8;
        !          2244:         vdp_complex = 1;
        !          2245:         break;
1.1       root     2246:       default:
1.1.1.2 ! root     2247:         LOG_NORMAL(("prohibited HSCR/LSCR"));
        !          2248:         hscroll = 0;
        !          2249:         break;
1.1       root     2250:       }
                   2251:       voffset &= (vwidth*8)-1;
                   2252:       hoffset = (0x400 - LOCENDIAN16(hscrolldata[hscroll])) & 0x3FF;
                   2253:       hoffset = (hoffset+xcell*8) & ((hwidth*8)-1);
                   2254:       cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>3)]);
                   2255:       if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
1.1.1.2 ! root     2256:         /* plot cell */
        !          2257:         palette = (cellinfo >> 13) & 3;
        !          2258:         pattern = vdp_vram + ((cellinfo & 2047)<<5);
        !          2259:         flags = (cellinfo>>11) & 3; /* bit0=H flip, bit1=V flip */
1.1       root     2260:         cellloc = toploc - (hoffset&7) + xcell*8;
1.1.1.2 ! root     2261:         vdp_plotcell(pattern, palette, flags, cellloc, lineoffset);
1.1       root     2262:       }
                   2263:     } /* ycell */
                   2264:   } /* xcell */
                   2265: }
                   2266: 
                   2267: void vdp_shadow_simple(uint8 *framedata, unsigned int lineoffset)
                   2268: {
                   2269:   unsigned int vertcells = vdp_reg[1] & 1<<3 ? 30 : 28;
                   2270:   uint8 *linedata;
                   2271:   unsigned int line;
                   2272:   int i;
                   2273: 
                   2274:   for (line = 0; line < vertcells*8; line++) {
                   2275:     linedata = framedata + line*lineoffset;
                   2276:     /* this could be done 4 bytes at a time */
                   2277:     for (i = 0; i < 320; i++)
                   2278:       linedata[i] = (linedata[i] & 63) + 128;
                   2279:   }
                   2280: }
                   2281: 
                   2282: void vdp_sprites_simple(unsigned int priority, uint8 *framedata,
1.1.1.2 ! root     2283:                        unsigned int lineoffset)
1.1       root     2284: {
                   2285:   uint8 *spritelist = vdp_vram + ((vdp_reg[5] & 0x7F)<<9);
                   2286: 
                   2287:   vdp_sprite_simple(priority, framedata, lineoffset, 1,
1.1.1.2 ! root     2288:                    spritelist, spritelist);
1.1       root     2289: }
                   2290: 
                   2291: int vdp_sprite_simple(unsigned int priority, uint8 *framedata,
1.1.1.2 ! root     2292:                      unsigned int lineoffset, unsigned int number,
        !          2293:                      uint8 *spritelist, uint8 *sprite)
1.1       root     2294: {
                   2295:   int i, j;
                   2296:   int plotted = 1;
                   2297:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
                   2298:   uint8 link;
                   2299:   uint16 pattern;
                   2300:   uint32 data;
                   2301:   uint8 palette;
                   2302:   uint16 cellinfo;
                   2303:   sint16 vpos, hpos, vmax;
                   2304:   uint16 xcell, ycell;
                   2305:   uint8 vsize, hsize;
                   2306:   uint8 *cellloc;
                   2307:   uint8 flags;
                   2308:   uint8 *patloc;
                   2309: 
                   2310:   if (number > 80) {
                   2311:     LOG_VERBOSE(("%08X [VDP] Maximum of 80 sprites exceeded", regs.pc));
                   2312:     return 0;
                   2313:   }
                   2314: 
                   2315:   link = sprite[3] & 0x7F;
                   2316:   hpos = (LOCENDIAN16(*(uint16 *)(sprite+6)) & 0x1FF) - 0x80;
                   2317:   vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x3FF) - 0x80;
                   2318:   vsize = 1+(sprite[2] & 3);
                   2319:   hsize = 1+((sprite[2]>>2) & 3);
                   2320:   cellinfo = LOCENDIAN16(*(uint16 *)(sprite+4));
                   2321:   pattern = cellinfo & 0x7FF;
                   2322:   palette = (cellinfo >> 13) & 3;
                   2323:   vmax = vpos + vsize*8;
                   2324:   
                   2325:   if (link) {
                   2326:     if (hpos == -128)
                   2327:       /* we do not support 'masking' in simple mode */
                   2328:       vdp_complex = 1;
                   2329:     plotted = vdp_sprite_simple(priority, framedata, lineoffset, number+1,
1.1.1.2 ! root     2330:                                spritelist, spritelist + (link<<3));
1.1       root     2331:     plotted++;
                   2332:   }
                   2333: 
                   2334:   if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) != priority)
                   2335:     return plotted;
                   2336:   if (vpos >= 240 || hpos >= 320 || vpos+vsize*8 <= 0 || hpos+hsize*8 <= 0)
                   2337:     /* sprite is not on screen */
                   2338:     return plotted;
                   2339:   flags = (cellinfo>>11) & 3; /* bit0=H flip, bit1=V flip */
1.1.1.2 ! root     2340:   if (vdp_reg[12] & 1<<3) /* s/ten enabled? */
        !          2341:     flags|= 1<<2;
1.1       root     2342:   switch(flags) {
                   2343:   case 0:
                   2344:   case 4:
                   2345:     /* normal orientation */
                   2346:     for (ycell = 0; ycell < vsize; ycell++) {
                   2347:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
1.1.1.2 ! root     2348:         /* cell out of plotting area (remember scrap area) */
        !          2349:         continue;
1.1       root     2350:       patloc = vdp_vram + (pattern<<5) + ycell*32;
                   2351:       for (xcell = 0; xcell < hsize; xcell++, patloc+= vsize*32) {
1.1.1.2 ! root     2352:         if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          2353:           /* cell out of plotting area */
        !          2354:           continue;
        !          2355:         cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          2356:                               (hpos+xcell*8));
        !          2357:         vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
1.1       root     2358:       }
                   2359:     }
                   2360:     break;
                   2361:   case 1:
                   2362:   case 5:
                   2363:     /* H flip */
                   2364:     for (ycell = 0; ycell < vsize; ycell++) {
                   2365:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
1.1.1.2 ! root     2366:         /* cell out of plotting area (remember scrap area) */
        !          2367:         continue;
1.1       root     2368:       patloc = vdp_vram + (pattern<<5) + ycell*32 + vsize*32*(hsize-1);
                   2369:       for (xcell = 0; xcell < hsize; xcell++, patloc-= vsize*32) {
1.1.1.2 ! root     2370:         if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          2371:           /* cell out of plotting area */
        !          2372:           continue;
        !          2373:         cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          2374:                               (hpos+xcell*8));
        !          2375:         vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
1.1       root     2376:       }
                   2377:     }
                   2378:     break;
                   2379:   case 2:
                   2380:   case 6:
                   2381:     /* V flip */
                   2382:     for (ycell = 0; ycell < vsize; ycell++) {
                   2383:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
1.1.1.2 ! root     2384:         /* cell out of plotting area (remember scrap area) */
        !          2385:         continue;
1.1       root     2386:       patloc = vdp_vram + (pattern<<5) + (vsize-ycell-1)*32;
                   2387:       for (xcell = 0; xcell < hsize; xcell++, patloc+= vsize*32) {
1.1.1.2 ! root     2388:         if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          2389:           /* cell out of plotting area */
        !          2390:           continue;
        !          2391:         cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          2392:                               (hpos+xcell*8));
        !          2393:         vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
1.1       root     2394:       }
                   2395:     }
                   2396:     break;
                   2397:   case 3:
                   2398:   case 7:
                   2399:     /* H and V flip */
                   2400:     for (ycell = 0; ycell < vsize; ycell++) {
                   2401:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
1.1.1.2 ! root     2402:         /* cell out of plotting area (remember scrap area) */
        !          2403:         continue;
1.1       root     2404:       patloc = vdp_vram + (pattern<<5) + ((vsize-ycell-1)*32 +
1.1.1.2 ! root     2405:                                          vsize*32*(hsize-1));
1.1       root     2406:       for (xcell = 0; xcell < hsize; xcell++, patloc-= vsize*32) {
1.1.1.2 ! root     2407:         if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          2408:           /* cell out of plotting area */
        !          2409:           continue;
        !          2410:         cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          2411:                               (hpos+xcell*8));
        !          2412:         vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
1.1       root     2413:       }
                   2414:     }
                   2415:     break;
                   2416:   }
                   2417:   return plotted;
                   2418: }
                   2419: 
                   2420: uint8 vdp_gethpos(void) {
1.1.1.2 ! root     2421:   float percent;
        !          2422: 
1.1       root     2423:   /* vdp_event = 0/1/2 -> beginning of line until 74 clocks before end
                   2424:                  3     -> between hint and hdisplay (36 clocks)
                   2425:                  4     -> between hdisplay and end  (38 clocks)
                   2426:      This routine goes from 0 to the maximum number allowed not within
                   2427:      H-blank, and then goes slightly beyond up to hdisplay.  Then
                   2428:      between hdisplay and end we go negative.  I'm not sure how negative
                   2429:      it is supposed to be, this goes from -38 to 0.
                   2430: 
1.1.1.2 ! root     2431:      40 horizontal cells, H goes from $00 to $B6, $E4 to $FF
        !          2432:      32 horizontal cells, H goes from $00 to $93, $E8 to $FF
        !          2433: 
1.1       root     2434:      this is such a bodge - any changes, check '3 Ninjas kick back'
                   2435:   */
                   2436:   LOG_DEBUG1(("gethpos %X: clocks=%X : startofline=%X : hint=%X : "
1.1.1.2 ! root     2437:               "end=%X", vdp_event, cpu68k_clocks,
        !          2438:               vdp_event_start,
        !          2439:               vdp_event_hint, vdp_event_end));
        !          2440:   if (vdp_event < 3) {
        !          2441:     percent = ((float)(cpu68k_clocks-vdp_event_start)/
        !          2442:                (float)(vdp_event_hint-vdp_event_start));
        !          2443:     if (vdp_reg[12] & 1)
        !          2444:       return (cpu68k_clocks > vdp_event_hint) ? 0xE4 : percent*0xB6;
        !          2445:     else
        !          2446:       return (cpu68k_clocks > vdp_event_hint) ? 0xE8 : percent*0x93;
        !          2447:   } else {
        !          2448:     percent = ((float)(cpu68k_clocks-vdp_event_hint)/
        !          2449:                (float)(vdp_event_end-vdp_event_hint));
        !          2450:     if (vdp_reg[12] & 1)
        !          2451:       return ((cpu68k_clocks > vdp_event_end) ? 0 :
        !          2452:               ((0xE4+(uint8)percent*28) & 0xff));
        !          2453:     else
        !          2454:       return ((cpu68k_clocks > vdp_event_end) ? 0 :
        !          2455:               ((0xE8+(uint8)percent*24) & 0xff));
        !          2456:   }
1.1       root     2457: }

unix.superglobalmegacorp.com

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