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

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

unix.superglobalmegacorp.com

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