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

1.1     ! root        1: /*****************************************************************************/
        !             2: /*     Generator - Sega Genesis emulation - (c) James Ponder 1997-1998       */
        !             3: /*****************************************************************************/
        !             4: /*                                                                           */
        !             5: /* vdp.c - Video Display Processor                                           */
        !             6: /*                                                                           */
        !             7: /*****************************************************************************/
        !             8: 
        !             9: #include <stdlib.h>
        !            10: #include <stdio.h>
        !            11: #include <string.h>
        !            12: 
        !            13: #include "generator.h"
        !            14: #include "vdp.h"
        !            15: #include "cpu68k.h"
        !            16: #include "ui.h"
        !            17: 
        !            18: #undef DEBUG_VDP
        !            19: #undef DEBUG_VDPDMA
        !            20: #undef DEBUG_VDPDATA
        !            21: #undef DEBUG_VDPCRAM
        !            22: 
        !            23: #define DEBUG_VDP
        !            24: #define DEBUG_VDPCRAM
        !            25: #define DEBUG_VDPDATA
        !            26: #define DEBUG_VDPDMA
        !            27: 
        !            28: typedef enum {
        !            29:   cd_vram_fetch, cd_vram_store,
        !            30:   cd_2, cd_cram_store,
        !            31:   cd_vsram_fetch, cd_vsram_store,
        !            32:   cd_6, cd_7,
        !            33:   cd_cram_fetch, cd_9,
        !            34:   cd_10, cd_11,
        !            35:   cd_12, cd_13,
        !            36:   cd_14, cd_15,
        !            37:   cd_16, cd_17,
        !            38:   cd_18, cd_19,
        !            39:   cd_20, cd_21,
        !            40:   cd_22, cd_23,
        !            41:   cd_24, cd_25,
        !            42:   cd_26, cd_27,
        !            43:   cd_28, cd_29,
        !            44:   cd_30, cd_31,
        !            45:   cd_32, cd_vram_fill,
        !            46:   cd_invalid
        !            47: } t_code;
        !            48: 
        !            49: /*** variables externed ***/
        !            50: 
        !            51: unsigned int vdp_event;
        !            52: unsigned int vdp_vislines;
        !            53: unsigned int vdp_totlines;
        !            54: unsigned int vdp_framerate;
        !            55: unsigned int vdp_clock;
        !            56: unsigned int vdp_68kclock;
        !            57: unsigned int vdp_clksperline_68k;
        !            58: unsigned int vdp_oddframe = 0;   /* odd/even frame */
        !            59: unsigned int vdp_vblank = 0;     /* set during vertical blanking */
        !            60: unsigned int vdp_hblank = 0;     /* set during horizontal blanking */
        !            61: unsigned int vdp_interlace = 0;  /* set in interlace mode */
        !            62: unsigned int vdp_line = 0;       /* current line number */
        !            63: unsigned int vdp_vsync = 0;      /* a vsync just happened */
        !            64: unsigned int vdp_pal = 0;        /* set for pal mode */
        !            65: unsigned int vdp_overseas = 1;   /* set for overseas model */
        !            66: unsigned int vdp_layerB  = 1;    /* flag */
        !            67: unsigned int vdp_layerBp = 1;    /* flag */
        !            68: unsigned int vdp_layerA  = 1;    /* flag */
        !            69: unsigned int vdp_layerAp = 1;    /* flag */
        !            70: unsigned int vdp_layerW  = 1;    /* flag */
        !            71: unsigned int vdp_layerWp = 1;    /* flag */
        !            72: unsigned int vdp_layerH  = 1;    /* flag */
        !            73: unsigned int vdp_layerS  = 1;    /* flag */
        !            74: unsigned int vdp_layerSp = 1;    /* flag */
        !            75: uint8 vdp_cram[LEN_CRAM];
        !            76: uint8 vdp_vsram[LEN_VSRAM];
        !            77: uint8 vdp_vram[LEN_VRAM];
        !            78: uint8 vdp_cramf[LEN_CRAM/2];
        !            79: unsigned int vdp_event_start;
        !            80: unsigned int vdp_event_vint;
        !            81: unsigned int vdp_event_hint;
        !            82: unsigned int vdp_event_hdisplay;
        !            83: unsigned int vdp_event_end;
        !            84: unsigned int vdp_event_startofcurrentline;
        !            85: signed int vdp_hskip_countdown = 0; /* actual countdown */
        !            86: 
        !            87: /*** global variables ***/
        !            88: 
        !            89: uint8 vdp_reg[25];
        !            90: static int vdp_collision;  /* set during a sprite collision */
        !            91: static int vdp_overflow;   /* set when too many sprites in one line */
        !            92: static int vdp_fifofull;   /* set when write fifo full */
        !            93: static int vdp_fifoempty;  /* set when write fifo empty */
        !            94: static uint16 vdp_address; /* address for data/dma transfers */
        !            95: static t_code vdp_code;    /* code number for data/dma transfers */
        !            96: static int vdp_complex;    /* set when simple routines can't cope */
        !            97: static unsigned int vdp_ctrlflag; /* set inbetween ctrl writes */
        !            98: 
        !            99: /*** forward references ***/
        !           100: 
        !           101: void vdp_ramcopy_vram(int type);
        !           102: void vdp_vramcopy(void);
        !           103: void vdp_showregs(void);
        !           104: void vdp_describe(void);
        !           105: void vdp_eventinit(void);
        !           106: void vdp_layer_simple(unsigned int layer, unsigned int priority,
        !           107:                      uint8 *fielddata, unsigned int lineoffset);
        !           108: inline void vdp_plotcell(uint8 *patloc, uint8 palette, uint8 flags,
        !           109:                         uint8 *cellloc, unsigned int lineoffset);
        !           110: int vdp_sprite(unsigned int line, unsigned int priority, uint8 *linedata,
        !           111:               uint8 *linemask, unsigned int number, uint8 *spritelist,
        !           112:               uint8 *sprite);
        !           113: void vdp_sprites(unsigned int line, unsigned int priority, uint8 *linedata);
        !           114: int vdp_sprite_simple(unsigned int priority, uint8 *framedata,
        !           115:                      unsigned int lineoffset, unsigned int number,
        !           116:                      uint8 *spritelist, uint8 *sprite);
        !           117: void vdp_sprites_simple(unsigned int priority, uint8 *framedata,
        !           118:                        unsigned int lineoffset);
        !           119: void vdp_shadow_simple(uint8 *framedata, unsigned int lineoffset);
        !           120: void vdp_window(unsigned int line, unsigned int priority, uint8 *linedata);
        !           121: 
        !           122: /*** vdp_init - initialise this sub-unit ***/
        !           123: 
        !           124: int vdp_init(void)
        !           125: {
        !           126:   vdp_reset();
        !           127:   return 0;
        !           128: }
        !           129: 
        !           130: /*** vdp_setupvideo - setup parameters dependant on vdp_pal ***/
        !           131: 
        !           132: void vdp_setupvideo(void)
        !           133: {
        !           134:   vdp_clock = vdp_pal ? 53200000 : 53693100; /* What speed is the PAL clock? */
        !           135:   vdp_68kclock = vdp_clock / 7;
        !           136:   vdp_vislines = 0 ? 240 : 224;
        !           137:   vdp_totlines = vdp_pal ? 312 : 262;
        !           138:   vdp_framerate = vdp_pal ? 50 : 60;
        !           139:   vdp_clksperline_68k = (vdp_68kclock/vdp_framerate/vdp_totlines);
        !           140: }
        !           141: 
        !           142: /*** vdp_reset - reset vdp sub-unit ***/
        !           143: 
        !           144: void vdp_reset(void)
        !           145: {
        !           146:   int i;
        !           147: 
        !           148:   /* clear registers */
        !           149: 
        !           150:   for (i = 0; i < 25; i++)
        !           151:     vdp_reg[i] = 0;
        !           152: 
        !           153:   /* set PAL/NTSC variables */
        !           154: 
        !           155:   vdp_setupvideo();
        !           156:   vdp_vblank = 0;
        !           157:   vdp_hblank = 0;
        !           158:   vdp_oddframe = 0;
        !           159:   vdp_collision = 0;
        !           160:   vdp_overflow = 0;
        !           161:   vdp_vsync = 0;
        !           162:   vdp_fifofull = 0;
        !           163:   vdp_fifoempty = 0;
        !           164:   vdp_ctrlflag = 0;
        !           165: 
        !           166:   memset(vdp_cram, 0, LEN_CRAM);
        !           167:   memset(vdp_vsram, 0, LEN_VSRAM);
        !           168:   memset(vdp_vram, 0, LEN_VRAM);
        !           169: 
        !           170:   /* clear CRAM */
        !           171: 
        !           172:   for (i = 0; i < 64; i++) {
        !           173:     (vdp_cram+i*2)[0] = (i & 7)<<1;
        !           174:     (vdp_cram+i*2)[1] = (i & 7)<<5 | (i & 7)<<1;
        !           175:     vdp_cramf[i] = 1;
        !           176:   }
        !           177:   vdp_eventinit();
        !           178:   LOG_VERBOSE(("VDP: totlines = %d (%s)", vdp_totlines, vdp_pal ?
        !           179:               "PAL" : "NTSC"));
        !           180: }
        !           181: 
        !           182: uint16 vdp_status(void)
        !           183: {
        !           184:   uint16 ret;
        !           185: 
        !           186:   /* bit      meaning (when set)
        !           187:    * 0        0:ntsc 1:pal
        !           188:    * 1        dma busy
        !           189:    * 2        during h blanking
        !           190:    * 3        during v blanking
        !           191:    * 4        frame in interlace mode - 0:even 1:odd
        !           192:    * 5        collision happened between non-zero pixels in two sprites
        !           193:    * 6        too many sprites in one line
        !           194:    * 7        v interrupt has happened
        !           195:    * 8        write fifo full
        !           196:    * 9        write fifo empty
        !           197:    */
        !           198: 
        !           199:   ret = vdp_pal | vdp_hblank<<2 | vdp_vblank<<3 | vdp_oddframe<<4 |
        !           200:     vdp_collision<<5 | vdp_overflow<<6 | vdp_vsync<<7 | vdp_fifofull<<8 |
        !           201:     vdp_fifoempty<<9;
        !           202: 
        !           203: #ifdef DEBUG_VDP
        !           204:   if (vdp_collision)
        !           205:     LOG_VERBOSE(("%08X Collision read", vdp_collision));
        !           206: #endif
        !           207: 
        !           208:   vdp_vsync = vdp_collision = vdp_overflow = 0;
        !           209: 
        !           210:   LOG_DEBUG1(("%08X STATUS READ %02X", regs.pc, ret));
        !           211: 
        !           212:   return (ret);
        !           213: }
        !           214: 
        !           215: void vdp_storectrl(uint16 data)
        !           216: {
        !           217:   static uint16 first;
        !           218:   uint8 reg;
        !           219:   uint8 regdata;
        !           220: 
        !           221:   if (!vdp_ctrlflag) {
        !           222:     if ((data & 0xE000) == 0x8000) {
        !           223:       /* register set */
        !           224:       reg = (data>>8) & 31;
        !           225:       regdata = data & 255;
        !           226:       if (reg > 24) {
        !           227:        LOG_NORMAL(("%08X [VDP] Invalid register (%d)", regs.pc,
        !           228:                      ((data>>8) & 31)));
        !           229:        return;
        !           230:       }
        !           231:       vdp_reg[reg] = regdata;
        !           232: #ifdef DEBUG_VDP
        !           233:       LOG_VERBOSE(("%08X [VDP] Register %d set to %04X", regs.pc,
        !           234:                   reg, regdata));
        !           235: #endif
        !           236:       return;
        !           237:     } else {
        !           238:       vdp_ctrlflag = 1;
        !           239:       first = data;
        !           240:       return;
        !           241:     }
        !           242:   } else {
        !           243:     vdp_ctrlflag = 0;
        !           244:     vdp_code = ((first>>14) & 3) | ((data>>2) & (15<<2));
        !           245:     vdp_address = (first & 0x3FFF) | (data<<14 & 0xC000);
        !           246:     switch(vdp_code) {
        !           247:     case 0: /* vram read */
        !           248: #ifdef DEBUG_VDP
        !           249:       LOG_VERBOSE(("%08X [VDP] start of vram read to address %X",
        !           250:                   regs.pc, vdp_address));
        !           251: #endif
        !           252:       break;
        !           253:     case 1: /* vram write */
        !           254: #ifdef DEBUG_VDP
        !           255:       LOG_VERBOSE(("%08X [VDP] start of vram write to address %X",
        !           256:                   regs.pc, vdp_address));
        !           257: #endif
        !           258:       break;
        !           259:     case 2: /* undefined */
        !           260: #ifdef DEBUG_VDP
        !           261:       LOG_VERBOSE(("%08X [VDP] start of bad transfer to address %X",
        !           262:                   regs.pc, vdp_address));
        !           263: #endif
        !           264:       break;
        !           265:     case 3: /* cram write */
        !           266: #ifdef DEBUG_VDP
        !           267:       LOG_VERBOSE(("%08X [VDP] start of cram write to address %X",
        !           268:                   regs.pc, vdp_address));
        !           269: #endif
        !           270:       break;
        !           271:     case 4: /* vsram read */
        !           272: #ifdef DEBUG_VDP
        !           273:       LOG_VERBOSE(("%08X [VDP] start of vsram read to address %X",
        !           274:                   regs.pc, vdp_address));
        !           275: #endif
        !           276:       break;
        !           277:     case 5: /* vsram write */
        !           278: #ifdef DEBUG_VDP
        !           279:       LOG_VERBOSE(("%08X [VDP] start of vsram read to address %X",
        !           280:                   regs.pc, vdp_address));
        !           281: #endif
        !           282:       break;
        !           283:     case 6: /* undefined */
        !           284:     case 7: /* undefined */
        !           285:       LOG_NORMAL(("%08X [VDP] start of type %d to address %X",
        !           286:                    regs.pc, vdp_code, vdp_address));
        !           287:       break;
        !           288:     case 8: /* cram read */
        !           289: #ifdef DEBUG_VDP
        !           290:       LOG_VERBOSE(("%08X [VDP] start of cram read to address %X",
        !           291:                   regs.pc, vdp_address));
        !           292: #endif
        !           293:       break;
        !           294:     case 33: /* ram copy to vram/vram fill */
        !           295: #ifdef DEBUG_VDP
        !           296:       LOG_VERBOSE(("%08X [VDP] start of vram copy/fill to address %X",
        !           297:                   regs.pc, vdp_address));
        !           298: #endif
        !           299:       if (!(vdp_reg[23] & 1<<7)) {
        !           300:        vdp_ramcopy_vram(0);
        !           301:        vdp_code = cd_invalid;
        !           302:       }
        !           303:       break;
        !           304:     case 35: /* ram copy to cram */
        !           305: #ifdef DEBUG_VDPCRAM
        !           306:       LOG_VERBOSE(("%08X [VDP] ram copy to cram address %X",
        !           307:                   regs.pc, vdp_address));
        !           308: #endif
        !           309:       vdp_ramcopy_vram(1);
        !           310:       vdp_code = cd_invalid;
        !           311:       break;
        !           312:     case 37: /* ram copy to vsram */
        !           313: #ifdef DEBUG_VDP
        !           314:       LOG_VERBOSE(("%08X [VDP] ram copy to vsram address %X", regs.pc,
        !           315:                   vdp_address));
        !           316: #endif
        !           317:       vdp_ramcopy_vram(2);
        !           318:       vdp_code = cd_invalid;
        !           319:       break;
        !           320:     case 48: /* vram copy */
        !           321: #ifdef DEBUG_VDP
        !           322:       LOG_VERBOSE(("%08X [VDP] vram copy to %X", regs.pc,
        !           323:                   vdp_address));
        !           324: #endif
        !           325:       vdp_vramcopy();
        !           326:       vdp_code = cd_invalid;
        !           327:       break;
        !           328:     default: /* undefined */
        !           329:       LOG_NORMAL(("%08X [VDP] start of type %d to address %X",
        !           330:                    regs.pc, vdp_code, vdp_address));
        !           331:       break;
        !           332:     }
        !           333:   }
        !           334: }
        !           335: 
        !           336: void vdp_ramcopy_vram(int type)
        !           337: {
        !           338:   uint16 length = vdp_reg[19] | vdp_reg[20]<<8;
        !           339:   uint8 srcbank = vdp_reg[23];
        !           340:   uint16 srcoffset = vdp_reg[21] | vdp_reg[22]<<8;
        !           341:   uint8 increment = vdp_reg[15];
        !           342:   uint16 *srcmemory;
        !           343:   uint16 data;
        !           344:   uint8 *memory;
        !           345:   uint16 length_t;
        !           346:   uint16 vdp_address_t;
        !           347:   uint32 vdp_address_mask;
        !           348: 
        !           349:   /* VRAM (type 0): reads are word-wide, writes are byte-wide */
        !           350:   /* CRAM (type 1) WSRAM (type 2): reads are word-wide, writes are byte-wide */
        !           351: 
        !           352:   if (srcbank & 1<<6) {
        !           353:     /* this is a ram source - note altered beast uses E00000 upwards */
        !           354:     srcmemory = (uint16 *)cpu68k_ram;
        !           355:     srcoffset&= 0x7fff;
        !           356: #ifdef DEBUG_VDP
        !           357:     LOG_VERBOSE(("%08X [VDP] ramcopy from RAM offset %08X type=%d "
        !           358:                 "vdpaddr=%08X length=%d",
        !           359:                 regs.pc, srcoffset*2, type, vdp_address, length));
        !           360: #endif
        !           361:   } else {
        !           362:     /* this is a rom source - each bank is 128k, srcoffset is in words */
        !           363:     srcmemory = (uint16 *)(cpu68k_rom + srcbank*0x20000);
        !           364: #ifdef DEBUG_VDP
        !           365:     LOG_VERBOSE(("%08X [VDP] ramcopy from ROM offset %08X type=%d "
        !           366:                 "vdpaddr=%08X length=%d",
        !           367:                 regs.pc, srcbank*0x20000+srcoffset*2, type, vdp_address,
        !           368:                 length));
        !           369: #endif
        !           370:   }
        !           371: 
        !           372:   switch(type) {
        !           373:   case 0:
        !           374:     memory = vdp_vram;
        !           375:     vdp_address_mask = LEN_VRAM-1;
        !           376:     break;
        !           377:   case 1:
        !           378:     length&= 0xff; /* maybe this or maybe we just stop at the end */
        !           379:     memory = vdp_cram;
        !           380:     vdp_address_mask = LEN_CRAM-1;
        !           381:     length_t = length;
        !           382:     vdp_address_t = vdp_address & vdp_address_mask;
        !           383:     for(; length_t; length_t--) {
        !           384:       vdp_cramf[vdp_address_t>>1] = 1;
        !           385:       vdp_address_t+= increment;
        !           386:       vdp_address_t&= vdp_address_mask;
        !           387:     }
        !           388:     break;
        !           389:   case 2:
        !           390:     length&= 0xff; /* maybe this or maybe we just stop at the end */
        !           391:     memory = vdp_vsram;
        !           392:     vdp_address_mask = LEN_VSRAM-1;
        !           393:     break;
        !           394:   default:
        !           395:     LOG_NORMAL(("%08X [VDP] Bad type %d", regs.pc, type));
        !           396:     return;
        !           397:   }
        !           398:   vdp_address_t = vdp_address & vdp_address_mask;
        !           399:   for(; length; length--) {
        !           400:     data = LOCENDIAN16(srcmemory[srcoffset]);
        !           401: #ifdef DEBUG_VDPDMA
        !           402:     /*
        !           403:       LOG_VERBOSE(("%08X [VDP] data %04X (ram/rom+2*%04X) -> %04X",
        !           404:       regs.pc, data, srcoffset, vdp_address_t));
        !           405:     */
        !           406: #endif
        !           407:     memory[vdp_address_t] = data>>8;
        !           408:     memory[vdp_address_t+1] = data & 0xff;
        !           409:     srcoffset+= 1;
        !           410:     vdp_address_t+= increment;
        !           411:     vdp_address_t&= vdp_address_mask;
        !           412:   }
        !           413:   /* don't think about writing vdp_address_t into registers - T2 is a good
        !           414:      example of something that doesn't like that */
        !           415: }
        !           416: 
        !           417: void vdp_vramcopy()
        !           418: {
        !           419:   uint16 length = vdp_reg[19] | vdp_reg[20]<<8;
        !           420:   uint8 increment = vdp_reg[15];
        !           421:   uint32 dstaddr = vdp_address;
        !           422:   uint32 srcaddr = vdp_reg[21] | vdp_reg[22]<<8;
        !           423: 
        !           424: #ifdef DEBUG_VDPDMA
        !           425:   LOG_VERBOSE(("%08X [VDP] COPY length %04X dstaddr %08X inc %02X "
        !           426:               "srcaddr %04X", regs.pc, length, dstaddr, increment, srcaddr));
        !           427: #endif
        !           428:   /* is this faster, is the question */
        !           429:   if (increment == 1 && (dstaddr+increment*length) <= LEN_VRAM &&
        !           430:       (srcaddr+increment <= LEN_VRAM) &&
        !           431:       (srcaddr < dstaddr ? srcaddr+increment <= dstaddr :
        !           432:                            dstaddr+increment*length <= srcaddr)) {
        !           433:     memcpy(vdp_vram+dstaddr, vdp_vram+srcaddr, length);
        !           434:   } else {
        !           435:     while(length--) {
        !           436:       if (dstaddr < LEN_VRAM && srcaddr < LEN_VRAM)
        !           437:        vdp_vram[dstaddr] = vdp_vram[srcaddr];
        !           438:       dstaddr++;
        !           439:       srcaddr+= increment;
        !           440:     }
        !           441:   }
        !           442:   LOG_NORMAL(("VRAM copy is untested"));
        !           443: }
        !           444: 
        !           445: void vdp_fill(uint16 data)
        !           446: {
        !           447:   uint16 length = vdp_reg[19] | vdp_reg[20]<<8;
        !           448:   uint8 increment = vdp_reg[15];
        !           449:   uint8 low = data & 0xff;
        !           450:   uint8 high = (data>>8) & 0xff;
        !           451:   uint32 addr = vdp_address;
        !           452: 
        !           453: #ifdef DEBUG_VDP
        !           454:   LOG_DEBUG1(("%08X [VDP] FILL length %04X data %04X addr %08X "
        !           455:              "inc %02X", regs.pc, length, data, addr, increment));
        !           456: #endif
        !           457:   if (addr + length * increment > LEN_VRAM) {
        !           458:     LOG_VERBOSE(("%08X [VDP] Bound check failed for vdp_fill: "
        !           459:                 "addr=%08X to addr=%08X (len=%d,inc=%d)", regs.pc, addr,
        !           460:                 addr+length*increment, length, increment));
        !           461:   }
        !           462:   switch(increment) {
        !           463:   case 1:
        !           464:     if (vdp_address & 1) {
        !           465:       vdp_vram[addr-1] = high;
        !           466:       if (--length) {
        !           467:        vdp_vram[addr] = low;
        !           468:        length--;
        !           469:       }
        !           470:       addr++;
        !           471:     } else {
        !           472:       vdp_vram[addr] = low;
        !           473:       if (--length && (addr+1) < LEN_VRAM) {
        !           474:        vdp_vram[addr+1] = high;
        !           475:        if (--length)
        !           476:          length--;
        !           477:       }
        !           478:       addr+= 2;
        !           479:     }      
        !           480:     for (; addr < LEN_VRAM && length; length--) {
        !           481:       vdp_vram[addr++] = high;
        !           482:     }
        !           483:     break;
        !           484:   case 2:
        !           485:     if (vdp_address & 1) {
        !           486:       vdp_vram[addr-1] = high;
        !           487:       vdp_vram[addr] = low;
        !           488:       length--;
        !           489:       addr+= 2;
        !           490:       for (; length && addr < LEN_VRAM; length--) {
        !           491:        /* changed in 0.14 */
        !           492:        vdp_vram[addr] = high;
        !           493:        addr+= 2;
        !           494:       }
        !           495:     } else {
        !           496:       vdp_vram[addr] = low;
        !           497:       vdp_vram[addr+1] = high;
        !           498:       length--;
        !           499:       addr+= 2;
        !           500:       for (; length && addr < LEN_VRAM; length--) {
        !           501:        /* changed in 0.14 */
        !           502:        vdp_vram[addr] = high;
        !           503:        addr+= 2;
        !           504:       }
        !           505:     }
        !           506:     break;
        !           507:   default:
        !           508:     LOG_NORMAL(("%08X [VDP] Unimplemented fill increment of %d",
        !           509:                  regs.pc, increment));
        !           510:   }
        !           511:   /* vdp_address = addr; this can't be right, removed in 0.14 DEBUG DEBUG */
        !           512: }
        !           513: 
        !           514: uint8 vdp_fetchdata_byte(void)
        !           515: {
        !           516:   LOG_NORMAL(("%08X [VDP] Byte fetch from %08X of type %d",
        !           517:                regs.pc, vdp_address, vdp_code));
        !           518:   return 0;
        !           519: }
        !           520: 
        !           521: uint16 vdp_fetchdata_word(void)
        !           522: {
        !           523:   uint8 *memory;
        !           524:   uint32 size;
        !           525:   uint16 data;
        !           526: 
        !           527:   switch(vdp_code) {
        !           528:   case cd_vram_fetch:
        !           529: #ifdef DEBUG_VDPDATA
        !           530:     LOG_VERBOSE(("%08X [VDP] VRAM fetch from address %X", regs.pc,
        !           531:                 vdp_address));
        !           532: #endif
        !           533:     memory = vdp_vram;
        !           534:     size = LEN_VRAM;
        !           535:     break;
        !           536:   case cd_vsram_fetch:
        !           537: #ifdef DEBUG_VDPDATA
        !           538:     LOG_VERBOSE(("%08X [VDP] VSRAM fetch from address %X",
        !           539:                 regs.pc, vdp_address));
        !           540: #endif
        !           541:     memory = vdp_vsram;
        !           542:     size = LEN_VSRAM;
        !           543:     break;
        !           544:   case cd_cram_fetch:
        !           545: #ifdef DEBUG_VDPDATA
        !           546:     LOG_VERBOSE(("%08X [VDP] CRAM fetch from address %X", regs.pc,
        !           547:                 vdp_address));
        !           548: #endif
        !           549:     memory = vdp_cram;
        !           550:     size = LEN_CRAM;
        !           551:     break;
        !           552:   default:
        !           553:     LOG_NORMAL(("%08X [VDP] Fetch in invalid mode %d", regs.pc,
        !           554:                  vdp_code));
        !           555:     return 0;
        !           556:   }
        !           557:   if (vdp_address>=size) {
        !           558:     LOG_VERBOSE(("%08X [VDP] Address (%08X) out of bounds (%08X)",
        !           559:                 regs.pc, vdp_address, size));
        !           560:   }
        !           561:   data = LOCENDIAN16(*(uint16 *)(memory+(vdp_address & ~1)));
        !           562: #ifdef DEBUG_VDPDATA
        !           563:   LOG_VERBOSE(("%08X [VDP] Fetch %04X from %08X", regs.pc, data,
        !           564:               vdp_address & ~1));
        !           565: #endif
        !           566:   vdp_address+= vdp_reg[15];
        !           567:   return data;
        !           568: }
        !           569: 
        !           570: void vdp_storedata_byte(uint8 data)
        !           571: {
        !           572:   LOG_DEBUG2(("%08X [VDP] Store data byte of %02X", regs.pc, data));
        !           573:   if (vdp_ctrlflag) {
        !           574:     LOG_NORMAL(("%08X [VDP] Unterminated ctrl setting", regs.pc));
        !           575:     vdp_storectrl(0);
        !           576:   }
        !           577:   switch(vdp_code) {
        !           578:   case cd_vram_store:
        !           579:     if (vdp_address >= LEN_VRAM) {
        !           580:       LOG_VERBOSE(("%08X [VDP] VRAM address %08X out of bounds",
        !           581:                   regs.pc, vdp_address));
        !           582:       return;
        !           583:     }
        !           584: #ifdef DEBUG_VDPDATA
        !           585:     LOG_VERBOSE(("%08X [VDP] vram byte store %02X in %08X", regs.pc,
        !           586:                 data, vdp_address ^ 1));
        !           587: #endif
        !           588:     *(uint8 *)(vdp_vram+vdp_address) = data;
        !           589:     vdp_address+= vdp_reg[15];
        !           590:     return;
        !           591:   case cd_cram_store:
        !           592:     if (vdp_address>=LEN_CRAM) {
        !           593:       LOG_VERBOSE(("%08X [VDP] CRAM address (%08X) out of bounds",
        !           594:                   regs.pc, vdp_address));
        !           595:       return;
        !           596:     }
        !           597: #ifdef DEBUG_VDPCRAM
        !           598:     LOG_VERBOSE(("%08X [VDP] CRAM byte store %04X in %08X", regs.pc,
        !           599:                 data, vdp_address));
        !           600: #endif
        !           601:     *(uint8 *)(vdp_cram+vdp_address) = data;
        !           602:     vdp_cramf[vdp_address>>1] = 1;
        !           603:     vdp_address+= vdp_reg[15];
        !           604:     return;
        !           605:   case cd_vsram_store:
        !           606:     if (vdp_address>=LEN_VSRAM) {
        !           607:       LOG_VERBOSE(("%08X [VDP] VSRAM address (%08X) out of bounds",
        !           608:                   regs.pc, vdp_address));
        !           609:       return;
        !           610:     }
        !           611: #ifdef DEBUG_VDPDATA
        !           612:     LOG_VERBOSE(("%08X [VDP] VSRAM byte store %04X in %08X",
        !           613:                regs.pc, data, vdp_address & ~1));
        !           614: #endif
        !           615:     *(uint8 *)(vdp_vsram+vdp_address) = data;
        !           616:     vdp_address+= vdp_reg[15];
        !           617:     return;
        !           618:   case cd_vram_fill:
        !           619: #ifdef DEBUG_VDPDATA
        !           620:     LOG_VERBOSE(("%08X [VDP] VRAM byte fill with %04X to %08X",
        !           621:                 regs.pc, data, vdp_address));
        !           622: #endif
        !           623:     vdp_fill(data | (data<<8));
        !           624:     return;
        !           625:   default: /* undefined */
        !           626:     LOG_NORMAL(("%08X [VDP] Byte store to %08X of type %d",
        !           627:                  regs.pc, vdp_address, vdp_code));
        !           628:     return;
        !           629:   }
        !           630: }
        !           631: 
        !           632: void vdp_storedata_word(uint16 data)
        !           633: {
        !           634:   if (vdp_ctrlflag) {
        !           635:     LOG_NORMAL(("%08X [VDP] Unterminated ctrl setting", regs.pc));
        !           636:     vdp_storectrl(0);
        !           637:   }
        !           638:   switch(vdp_code) {
        !           639:   case cd_vram_store:
        !           640:     if (vdp_address>=LEN_VRAM) {
        !           641:       LOG_VERBOSE(("%08X [VDP] VRAM address (%08X) out of bounds",
        !           642:                   regs.pc, vdp_address));
        !           643:       return;
        !           644:     }
        !           645:     if (vdp_address & 1)
        !           646:       data = SWAP16(data);
        !           647: #ifdef DEBUG_VDPDATA
        !           648:     LOG_VERBOSE(("%08X [VDP] VRAM store %04X in %08X", regs.pc, data,
        !           649:                 vdp_address & ~1));
        !           650: #endif
        !           651:     *(uint16 *)(vdp_vram+(vdp_address & ~1)) = LOCENDIAN16(data);
        !           652:     vdp_address+= vdp_reg[15];
        !           653:     return;
        !           654:   case cd_cram_store:
        !           655:     if (vdp_address>=LEN_CRAM) {
        !           656:       LOG_VERBOSE(("%08X [VDP] CRAM address (%08X) out of bounds",
        !           657:                   regs.pc, vdp_address));
        !           658:       return;
        !           659:     }
        !           660: #ifdef DEBUG_VDPCRAM
        !           661:     LOG_VERBOSE(("%08X [VDP] CRAM store %04X in %08X", regs.pc, data,
        !           662:                 vdp_address & ~1));
        !           663: #endif
        !           664:     *(uint16 *)(vdp_cram+(vdp_address & ~1)) = LOCENDIAN16(data);
        !           665:     vdp_cramf[vdp_address>>1] = 1;
        !           666:     vdp_address+= vdp_reg[15];
        !           667:     return;
        !           668:   case cd_vsram_store:
        !           669:     if (vdp_address>=LEN_VSRAM) {
        !           670:       LOG_VERBOSE(("%08X [VDP] VSRAM address (%08X) out of bounds",
        !           671:                   regs.pc, vdp_address));
        !           672:       return;
        !           673:     }
        !           674: #ifdef DEBUG_VDPDATA
        !           675:     LOG_VERBOSE(("%08X [VDP] VSRAM store %04X in %08X", regs.pc, data,
        !           676:                 vdp_address & ~1));
        !           677: #endif
        !           678:     *(uint16 *)(vdp_vsram+(vdp_address & ~1)) = LOCENDIAN16(data);
        !           679:     vdp_address+= vdp_reg[15];
        !           680:     return;
        !           681:   case cd_vram_fill:
        !           682: #ifdef DEBUG_VDPDATA
        !           683:     LOG_VERBOSE(("%08X [VDP] VRAM fill with %04X to %08X", regs.pc,
        !           684:                 data, vdp_address));
        !           685: #endif
        !           686:     vdp_fill(data);
        !           687:     return;
        !           688:   default: /* undefined */
        !           689:     LOG_NORMAL(("%08X [VDP] Word store to %08X of type %d data = %04X",
        !           690:                  regs.pc, vdp_address, vdp_code, data,vdp_address));
        !           691:     return;
        !           692:   }
        !           693: }
        !           694: 
        !           695: #define LINEDATA(offset, value, priority) \
        !           696: if (value) { \
        !           697:   linedata[offset] = palette*16 + value; \
        !           698: } else if (priority) { \
        !           699:   linedata[offset] = (linedata[offset] & 63); \
        !           700: }
        !           701: 
        !           702: #define LINEDATASPR(offset, value) \
        !           703: if (value) { \
        !           704:   if (linemask[offset]) \
        !           705:     vdp_collision = 1; \
        !           706:   linemask[offset] = 1; \
        !           707:   if ((vdp_reg[12] & 1<<3) && palette == 3 && value == 14) { \
        !           708:     linedata[offset] = (linedata[offset] & 63) + 64; \
        !           709:   } else if ((vdp_reg[12] & 1<<3) && palette == 3 && value == 15) { \
        !           710:     linedata[offset] = (linedata[offset] & 63) + 128; \
        !           711:   } else { \
        !           712:     linedata[offset] = palette*16 + value; \
        !           713:   } \
        !           714: }
        !           715: 
        !           716: void vdp_sprites(unsigned int line, unsigned int priority, uint8 *linedata)
        !           717: {
        !           718:   uint8 interlace = (vdp_reg[12]>>1) & 3;
        !           719:   uint8 *spritelist = vdp_vram + ((vdp_reg[5] & 0x7F)<<9);
        !           720:   uint8 linemask[320];
        !           721:   t_spriteinfo si[128]; /* 128 - max sprites supported per line */
        !           722:   unsigned int sprites;
        !           723:   unsigned int idx;
        !           724:   int i;
        !           725:   uint8 link;
        !           726:   uint8 *sprite = spritelist;
        !           727:   int plotter; /* flag */
        !           728:   unsigned int screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !           729:   unsigned int maxspl = (vdp_reg[12] & 1) ? 20 : 16; /* max sprs/line */
        !           730:   unsigned int cells;
        !           731:   uint8 loops = 0;
        !           732: 
        !           733:   for (idx = 0; loops < 255 && idx < maxspl; loops++) {
        !           734:     link = sprite[3] & 0x7F;
        !           735:     si[idx].sprite = sprite;
        !           736:     if (interlace == 3)
        !           737:       si[idx].vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x3FF) - 0x100;
        !           738:     else
        !           739:       si[idx].vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x1FF) - 0x080;
        !           740:     if ((signed int)line < si[idx].vpos)
        !           741:       goto next;
        !           742:     si[idx].vsize = 1+(sprite[2] & 3);
        !           743:     if (interlace == 3)
        !           744:       si[idx].vsize<<= 1;
        !           745:     si[idx].vmax = si[idx].vpos + si[idx].vsize*8;
        !           746:     if ((signed int)line >= si[idx].vmax)
        !           747:       goto next;
        !           748:     si[idx].hpos = (LOCENDIAN16(*(uint16 *)(sprite+6)) & 0x1FF) - 0x80;
        !           749:     si[idx].hsize = 1+((sprite[2]>>2) & 3);
        !           750:     si[idx].hplot = si[idx].hsize;
        !           751:     si[idx].hmax = si[idx].hpos + si[idx].hsize*8;
        !           752:     idx++;
        !           753:   next:
        !           754:     if (!link)
        !           755:       break;
        !           756:     sprite = spritelist + (link<<3);
        !           757: 
        !           758:   }
        !           759:   if (idx < 1)
        !           760:     return;
        !           761:   sprites = idx;
        !           762:   memset(linemask, 0, 320); /* initialise mask */
        !           763:   plotter = 1;
        !           764:   cells = (vdp_reg[12] & 1) ? 40 : 32; /* 320 or 256 pixels */
        !           765:   /* loop masking */
        !           766:   for (i = 0; i < (signed int)sprites; i++) {
        !           767:     if (plotter == 0) {
        !           768:       sprites = i;
        !           769:       break;
        !           770:     }
        !           771:     if (si[i].hpos == -128) {
        !           772:       /* mask sprite - but does it? */
        !           773:       if (i > 0) {
        !           774:        /* is there a higher priority sprite? */
        !           775:        if (si[i-1].vpos <= (signed int)line &&
        !           776:            si[i-1].vmax > (signed int)line) {
        !           777:          /* match, mask time */
        !           778:          plotter = 0;
        !           779:        }
        !           780:       } else {
        !           781:        /* higest priority sprite, so mask */
        !           782:        plotter = 0;
        !           783:       }
        !           784:       si[i].hplot = 0;
        !           785:     }
        !           786:     if (cells >= si[i].hplot) {
        !           787:       cells-= si[i].hplot;
        !           788:     } else {
        !           789:       si[i].hplot = cells; /* only room for this many */
        !           790:       cells = 0;
        !           791:     }
        !           792:   }    
        !           793: 
        !           794:   {
        !           795:     sint16 hpos, vpos;
        !           796:     uint16 hsize, vsize, hplot;
        !           797:     sint16 hmax, vmax;
        !           798:     uint16 cellinfo;
        !           799:     uint16 pattern;
        !           800:     uint8 palette;
        !           801:     uint8 *cellline;
        !           802:     uint32 data;
        !           803:     uint8 pixel;
        !           804:     int j, k;
        !           805: 
        !           806:     /* loop around sprites until end of list marker or no more */
        !           807:     for (i = sprites-1; i >= 0; i--) {
        !           808:       hpos = si[i].hpos;
        !           809:       vpos = si[i].vpos;
        !           810:       vsize = si[i].vsize; /* doubled when in interlace mode */
        !           811:       hsize = si[i].hsize;
        !           812:       hmax = si[i].hmax;
        !           813:       vmax = si[i].vmax;
        !           814:       hplot = si[i].hplot; /* number of cells to plot for this sprite */
        !           815:       cellinfo = LOCENDIAN16(*(uint16 *)(si[i].sprite+4));
        !           816:       pattern = cellinfo & 0x7FF;
        !           817:       palette = (cellinfo >> 13) & 3;
        !           818: 
        !           819:       if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !           820:        cellline = vdp_vram + ((interlace == 3) ? (pattern<<6) : (pattern<<5));
        !           821:        if (cellinfo & 1<<12) /* vertical flip */
        !           822:          cellline+= (vmax-line-1)*4;
        !           823:        else
        !           824:          cellline+= (line-vpos)*4;
        !           825:        for (k = 0; k < hsize && hplot--; k++) {
        !           826:          if (hpos > -8 && hpos < 0) {
        !           827:            if (cellinfo & 1<<11) {
        !           828:              /* horizontal flip */
        !           829:              data = LOCENDIAN32(*(uint32 *)(cellline+
        !           830:                                             (hsize-k*2-1)*(vsize<<5)));
        !           831:              data>>= (-hpos)*4; /* get first pixel in bottom 4 bits */
        !           832:              for (j = 0; j < 8+hpos; j++) {
        !           833:                pixel = data & 15;
        !           834:                LINEDATASPR(j, pixel);
        !           835:                data>>= 4;
        !           836:              }
        !           837:            } else {
        !           838:              data = LOCENDIAN32(*(uint32 *)cellline);
        !           839:              data<<= (-hpos)*4; /* get first pixel in top 4 bits */
        !           840:              for (j = 0; j < 8+hpos; j++) {
        !           841:                pixel = (data>>28) & 15;
        !           842:                LINEDATASPR(j, pixel);
        !           843:                data<<= 4;
        !           844:              }
        !           845:            }
        !           846:          } else if (hpos >= 0 && hpos <= (signed int)(screencells-1)*8) {
        !           847:            if (cellinfo & 1<<11) {
        !           848:              /* horizontal flip */
        !           849:              data = LOCENDIAN32(*(uint32 *)(cellline+
        !           850:                                             (hsize-k*2-1)*(vsize<<5)));
        !           851:              for (j = 0; j < 8; j++) {
        !           852:                pixel = data & 15;
        !           853:                LINEDATASPR(hpos+j, pixel);
        !           854:                data>>= 4;
        !           855:              }
        !           856:            } else {
        !           857:              data = LOCENDIAN32(*(uint32 *)cellline);
        !           858:              for (j = 0; j < 8; j++) {
        !           859:                pixel = (data>>28) & 15;
        !           860:                LINEDATASPR(hpos+j, pixel);
        !           861:                data<<= 4;
        !           862:              }
        !           863:            }
        !           864:          } else if (hpos > (signed int)(screencells-1)*8 &&
        !           865:                     hpos < (signed int)screencells*8) {
        !           866:            if (cellinfo & 1<<11) {
        !           867:              /* horizontal flip */
        !           868:              data = LOCENDIAN32(*(uint32 *)(cellline+
        !           869:                                             (hsize-k*2-1)*(vsize<<5)));
        !           870:              for (j = 0; j < (signed int)(screencells*8 - hpos); j++) {
        !           871:                pixel = data & 15;
        !           872:                LINEDATASPR(hpos+j, pixel);
        !           873:                data>>= 4;
        !           874:              }
        !           875:            } else {
        !           876:              data = LOCENDIAN32(*(uint32 *)cellline);
        !           877:              for (j = 0; j < (signed int)(screencells*8 - hpos); j++) {
        !           878:                pixel = (data>>28) & 15;
        !           879:                LINEDATASPR(hpos+j, pixel);
        !           880:                data<<= 4;
        !           881:              }
        !           882:            }
        !           883:          }
        !           884:          cellline+= vsize<<5; /* 32 bytes per cell (note vsize is doubled
        !           885:                                  when interlaced) */
        !           886:          hpos+= 8;
        !           887:        }
        !           888:       }
        !           889:     }
        !           890:   }
        !           891: }
        !           892: 
        !           893: void vdp_shadow(unsigned int line, uint8 *linedata)
        !           894: {
        !           895:   int i;
        !           896:   
        !           897:   /* this could be done 4 bytes at a time */
        !           898:   for (i = 0; i < 320; i++)
        !           899:     linedata[i] = (linedata[i] & 63) + 128;
        !           900: }
        !           901: 
        !           902: void vdp_window(unsigned int line, unsigned int priority, uint8 *linedata)
        !           903: {
        !           904:   uint16 *patterndata = (uint16 *)(vdp_vram + ((vdp_reg[3] & 0x3e) << 10));
        !           905:   uint8 winhpos = vdp_reg[17] & 0x1f;
        !           906:   uint8 winvpos = vdp_reg[18] & 0x1f;
        !           907:   uint8 vcell = line / 8;
        !           908:   uint8 hcell;
        !           909:   uint8 voffset = line & 7;
        !           910:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !           911:   uint8 topbottom = vdp_reg[18] & 0x80;
        !           912:   uint8 leftright = vdp_reg[17] & 0x80;
        !           913:   uint8 patternshift = (vdp_reg[12] & 1) ? 6 : 5;
        !           914:   uint16 cellinfo;
        !           915:   uint8 *pattern;
        !           916:   uint32 data;
        !           917:   uint8 palette;
        !           918:   uint8 pixel;
        !           919:   unsigned int i;
        !           920:   unsigned int wholeline = 0;
        !           921: 
        !           922:   if (topbottom) {
        !           923:     /* bottom part */
        !           924:     /* Battle Tank sets winvpos to 0x1F and expects layer A to be off */
        !           925:     if (winvpos == 0x1F || vcell >= winvpos)
        !           926:       wholeline = 1;
        !           927:   } else {
        !           928:     /* top part */
        !           929:     if (vcell < winvpos)
        !           930:       wholeline = 1;
        !           931:   }
        !           932:   for (hcell = 0; hcell < screencells; hcell++, linedata+=8) {
        !           933:     if (!wholeline) {
        !           934:       if (leftright) {
        !           935:        if ((hcell>>1) < winhpos)
        !           936:          continue;
        !           937:       } else {
        !           938:        if ((hcell>>1) >= winhpos)
        !           939:          continue;
        !           940:       }
        !           941:     }
        !           942:     cellinfo = LOCENDIAN16(patterndata[vcell<<patternshift | hcell]);
        !           943:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !           944:       palette = (cellinfo >> 13) & 3;
        !           945:       pattern = vdp_vram + ((cellinfo & 2047)<<5); /* 32 bytes per pattern */
        !           946:       if (cellinfo & 1<<12) {
        !           947:        /* vertical flip */
        !           948:        pattern+= 4*(7-(voffset & 7));
        !           949:       } else {
        !           950:        /* no vertical flip */
        !           951:        pattern+= 4*(voffset & 7);
        !           952:       }
        !           953:       data = LOCENDIAN32(*(uint32 *)pattern);
        !           954:       if (cellinfo & 1<<11) {
        !           955:        /* horizontal flip */
        !           956:        for (i = 0; i < 8; i++) {
        !           957:          pixel = data & 15;
        !           958:          LINEDATA(i, pixel, priority);
        !           959:          data>>= 4;
        !           960:        }
        !           961:       } else {
        !           962:        for (i = 0; i < 8; i++) {
        !           963:          pixel = (data>>28) & 15;
        !           964:          LINEDATA(i, pixel, priority);
        !           965:          data<<= 4;
        !           966:        }
        !           967:       }
        !           968:     }
        !           969:   } /* hcell */
        !           970: }
        !           971: 
        !           972: /* layer 0 = A (top), layer 1 = B (bottom) */
        !           973: 
        !           974: void vdp_layer(unsigned int line, unsigned int layer, unsigned int priority,
        !           975:               uint8 *linedata)
        !           976: {
        !           977:   int i, j;
        !           978:   uint8 hsize = vdp_reg[16] & 3;
        !           979:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
        !           980:   uint8 hmode = vdp_reg[11] & 3;
        !           981:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
        !           982:   uint16 vramoffset = (layer ? ((vdp_reg[4] & 7) << 13) :
        !           983:                       ((vdp_reg[2] & (7<<3)) << 10));
        !           984:   uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset);
        !           985:   uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10)
        !           986:                                   + vdp_vram + layer*2);
        !           987:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !           988:   uint16 hwidth, vwidth, hoffset, voffset;
        !           989:   uint16 cellinfo;
        !           990:   uint8 *pattern;
        !           991:   uint32 data;
        !           992:   uint8 palette;
        !           993:   uint8 pixel;
        !           994:   uint8 topbottom, leftright, winhpos, winvpos;
        !           995: 
        !           996:   if (layer == 0) {
        !           997:     /* turn off A when window is on */
        !           998:     topbottom = vdp_reg[18] & 0x80;
        !           999:     leftright = vdp_reg[17] & 0x80;
        !          1000:     winhpos = vdp_reg[17] & 0x1f;
        !          1001:     winvpos = vdp_reg[18] & 0x1f;
        !          1002:     /* Battle Tank sets winvpos to 1F and expects layer A to be off */
        !          1003:     if (topbottom && winvpos != 0x1F) {
        !          1004:       if ((line>>3) >= winvpos)
        !          1005:        return;
        !          1006:     } else {
        !          1007:       if ((line>>3) < winvpos)
        !          1008:        return;
        !          1009:     }
        !          1010:   }
        !          1011: 
        !          1012:   /* BUG: layer A is still displayed left/right when window is on,
        !          1013:      only apparent with high-priority layer A and low-priority window */
        !          1014: 
        !          1015:   switch(hmode) {
        !          1016:   case 0: /* full screen */
        !          1017:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF;
        !          1018:     break;
        !          1019:   case 2: /* cell scroll */
        !          1020:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(line & ~7)])) & 0x3FF;
        !          1021:     break;
        !          1022:   case 3: /* line scroll */
        !          1023:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*line])) & 0x3FF;
        !          1024:     break;
        !          1025:   default:
        !          1026:     LOG_NORMAL(("prohibited HSCR/LSCR"));
        !          1027:     hoffset = 0;
        !          1028:     break;
        !          1029:   }
        !          1030:   hwidth = 32+hsize*32;
        !          1031:   vwidth = 32+vsize*32;
        !          1032:   hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1033:   voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x3FF;
        !          1034:   voffset&= (vwidth*8)-1; /* put offset in range */
        !          1035:   cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>3)]);
        !          1036:   if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1037:     palette = (cellinfo >> 13) & 3;
        !          1038:     pattern = vdp_vram + ((cellinfo & 2047)<<5); /* 32 bytes per pattern */
        !          1039:     if (cellinfo & 1<<12) {
        !          1040:       /* vertical flip */
        !          1041:       pattern+= 4*(7-(voffset & 7));
        !          1042:     } else {
        !          1043:       /* no vertical flip */
        !          1044:       pattern+= 4*(voffset & 7);
        !          1045:     }
        !          1046:     data = LOCENDIAN32(*(uint32 *)pattern);
        !          1047:     if (cellinfo & 1<<11) {
        !          1048:       /* horizontal flip */
        !          1049:       data>>= (hoffset & 7)*4; /* get first pixel in bottom 4 bits */
        !          1050:       for (i = 0; i < 8-(hoffset & 7); i++) {
        !          1051:        pixel = data & 15;
        !          1052:        LINEDATA(i, pixel, priority);
        !          1053:        data>>= 4;
        !          1054:       }
        !          1055:     } else {
        !          1056:       data<<= (hoffset & 7)*4; /* get first pixel in top 4 bits */
        !          1057:       for (i = 0; i < 8-(hoffset & 7); i++) {
        !          1058:        pixel = (data>>28) & 15;
        !          1059:        LINEDATA(i, pixel, priority);
        !          1060:        data<<= 4;
        !          1061:       }
        !          1062:     }
        !          1063:   }
        !          1064:   linedata+= 8-(hoffset & 7);
        !          1065:   hoffset+= 8;
        !          1066:   hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1067:   for (j = 1; j < screencells; j++) {
        !          1068:     if (vmode) {
        !          1069:       /* 2-cell scroll */
        !          1070:       /* DEBUG DEBUG DEBUG awooga awooga */
        !          1071:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
        !          1072:                                     [(j&~1)+layer] )) & 0x3FF;
        !          1073:     } else {
        !          1074:       /* full screen */
        !          1075:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x3FF;
        !          1076:     }
        !          1077:     voffset&= (vwidth*8)-1; /* put offset in range */
        !          1078:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>3)]);
        !          1079:     /* printf("hoff: %04X voff: %04X hwid: %04X cell: %08X info: %04X\n",
        !          1080:           hoffset, voffset, hwidth, (hoffset>>3)+hwidth*(voffset>>3),
        !          1081:           cellinfo); */
        !          1082:     /* printf("loc %08X cellinfo %08X\n",
        !          1083:           (hoffset>>3)+hwidth*(voffset>>3),
        !          1084:           cellinfo); */
        !          1085:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1086:       palette = (cellinfo >> 13) & 3;
        !          1087:       pattern = vdp_vram + ((cellinfo & 2047)<<5); /* 32 bytes per pattern */
        !          1088:       if (cellinfo & 1<<12) {
        !          1089:        /* vertical flip */
        !          1090:        pattern+= 4*(7-(voffset & 7));
        !          1091:       } else {
        !          1092:        /* no vertical flip */
        !          1093:        pattern+= 4*(voffset & 7);
        !          1094:       }
        !          1095:       data = LOCENDIAN32(*(uint32 *)pattern);
        !          1096:       if (cellinfo & 1<<11) {
        !          1097:        /* horizontal flip */
        !          1098:        for (i = 0; i < 8; i++) {
        !          1099:          pixel = data & 15;
        !          1100:          LINEDATA(i, pixel, priority);
        !          1101:          data>>= 4;
        !          1102:        }
        !          1103:       } else {
        !          1104:        for (i = 0; i < 8; i++) {
        !          1105:          pixel = (data>>28) & 15;
        !          1106:          LINEDATA(i, pixel, priority);
        !          1107:          data<<= 4;
        !          1108:        }
        !          1109:       }
        !          1110:     }
        !          1111:     linedata+= 8;
        !          1112:     hoffset+= 8;
        !          1113:     hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1114:   }
        !          1115:   if (hoffset & 7) {
        !          1116:     if (vmode) {
        !          1117:       /* 2-cell scroll - note use last offset, not next */
        !          1118:       /* DEBUG DEBUG DEBUG awooga awooga */
        !          1119:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
        !          1120:                                     [(j&~1)+layer] )) & 0x3FF;
        !          1121:     } else {
        !          1122:       /* full screen */
        !          1123:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x3FF;
        !          1124:     }
        !          1125:     voffset&= (vwidth*8)-1; /* put offset in range */
        !          1126:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>3)]);
        !          1127:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1128:       palette = (cellinfo >> 13) & 3;
        !          1129:       pattern = vdp_vram + ((cellinfo & 2047)<<5); /* 32 bytes per pattern */
        !          1130:       if (cellinfo & 1<<12) {
        !          1131:        /* vertical flip */
        !          1132:        pattern+= 4*(7-(voffset & 7));
        !          1133:       } else {
        !          1134:        /* no vertical flip */
        !          1135:        pattern+= 4*(voffset & 7);
        !          1136:       }
        !          1137:       data = LOCENDIAN32(*(uint32 *)pattern);
        !          1138:       if (cellinfo & 1<<11) {
        !          1139:        /* horizontal flip */
        !          1140:        for (i = 0; i < (hoffset & 7); i++) {
        !          1141:          pixel = data & 15;
        !          1142:          LINEDATA(i, pixel, priority);
        !          1143:          data>>= 4;
        !          1144:        }
        !          1145:       } else {
        !          1146:        for (i = 0; i < (hoffset & 7); i++) {
        !          1147:          pixel = (data>>28) & 15;
        !          1148:          LINEDATA(i, pixel, priority);
        !          1149:          data<<= 4;
        !          1150:        }
        !          1151:       }
        !          1152:     }
        !          1153:     linedata+= 8;
        !          1154:   }
        !          1155: }
        !          1156: 
        !          1157: void vdp_layer_interlace(unsigned int line, unsigned int layer,
        !          1158:                         unsigned int priority, uint8 *linedata)
        !          1159: {
        !          1160:   int i, j;
        !          1161:   uint8 hsize = vdp_reg[16] & 3;
        !          1162:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
        !          1163:   uint8 hmode = vdp_reg[11] & 3;
        !          1164:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
        !          1165:   uint16 vramoffset = (layer ? ((vdp_reg[4] & 7) << 13) :
        !          1166:                       ((vdp_reg[2] & (7<<3)) << 10));
        !          1167:   uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset);
        !          1168:   uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10)
        !          1169:                                   + vdp_vram + layer*2);
        !          1170:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !          1171:   uint16 hwidth, vwidth, hoffset, voffset;
        !          1172:   uint16 cellinfo;
        !          1173:   uint8 *pattern;
        !          1174:   uint32 data;
        !          1175:   uint8 palette;
        !          1176:   uint8 pixel;
        !          1177:   uint8 topbottom, leftright, winhpos, winvpos;
        !          1178: 
        !          1179:   if (layer == 0) {
        !          1180:     /* turn off A when window is on */
        !          1181:     topbottom = vdp_reg[18] & 0x80;
        !          1182:     leftright = vdp_reg[17] & 0x80;
        !          1183:     winhpos = vdp_reg[17] & 0x1f;
        !          1184:     winvpos = vdp_reg[18] & 0x1f;
        !          1185:     if (topbottom) {
        !          1186:       if ((line>>4) >= winvpos)
        !          1187:        return;
        !          1188:     } else {
        !          1189:       if ((line>>4) < winvpos)
        !          1190:        return;
        !          1191:     }
        !          1192:   }
        !          1193: 
        !          1194:   /* BUG: layer A is still displayed left/right when window is on,
        !          1195:      only apparent with high-priority layer A and low-priority window */
        !          1196: 
        !          1197:   switch(hmode) {
        !          1198:   case 0: /* full screen */
        !          1199:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF;
        !          1200:     break;
        !          1201:   case 2: /* cell scroll */
        !          1202:     /* interlace we use the actual line for the hscroll */
        !          1203:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*((line>>1) & ~7)])) & 0x3FF;
        !          1204:     break;
        !          1205:   case 3: /* line scroll */
        !          1206:     /* interlace we use the actual line for the hscroll */
        !          1207:     hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(line>>1)])) & 0x3FF;
        !          1208:     break;
        !          1209:   default:
        !          1210:     LOG_NORMAL(("prohibited HSCR/LSCR"));
        !          1211:     hoffset = 0;
        !          1212:     break;
        !          1213:   }
        !          1214:   hwidth = 32+hsize*32;
        !          1215:   vwidth = 32+vsize*32;
        !          1216:   hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1217:   voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF;
        !          1218:   voffset&= (vwidth*16)-1; /* put offset in range */
        !          1219: 
        !          1220:   cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]);
        !          1221:   if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1222:     palette = (cellinfo >> 13) & 3;
        !          1223:     pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */
        !          1224:     if (cellinfo & 1<<12) {
        !          1225:       /* vertical flip */
        !          1226:       pattern+= 4*(15-(voffset & 15));
        !          1227:     } else {
        !          1228:       /* no vertical flip */
        !          1229:       pattern+= 4*(voffset & 15);
        !          1230:     }
        !          1231:     data = LOCENDIAN32(*(uint32 *)pattern);
        !          1232:     if (cellinfo & 1<<11) {
        !          1233:       /* horizontal flip */
        !          1234:       data>>= (hoffset & 7)*4; /* get first pixel in bottom 4 bits */
        !          1235:       for (i = 0; i < 8-(hoffset & 7); i++) {
        !          1236:        pixel = data & 15;
        !          1237:        LINEDATA(i, pixel, priority);
        !          1238:        data>>= 4;
        !          1239:       }
        !          1240:     } else {
        !          1241:       data<<= (hoffset & 7)*4; /* get first pixel in top 4 bits */
        !          1242:       for (i = 0; i < 8-(hoffset & 7); i++) {
        !          1243:        pixel = (data>>28) & 15;
        !          1244:        LINEDATA(i, pixel, priority);
        !          1245:        data<<= 4;
        !          1246:       }
        !          1247:     }
        !          1248:   }
        !          1249:   linedata+= 8-(hoffset & 7);
        !          1250:   hoffset+= 8;
        !          1251:   hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1252:   for (j = 0; j < screencells-1; j++) {
        !          1253:     if (vmode) {
        !          1254:       /* 2-cell scroll */
        !          1255:       /* DEBUG DEBUG DEBUG awooga awooga */
        !          1256:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
        !          1257:                                     [2*(j>>1)+layer] )) & 0x7FF;
        !          1258:     } else {
        !          1259:       /* full screen */
        !          1260:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF;
        !          1261:     }
        !          1262:     voffset&= (vwidth*16)-1; /* put offset in range */
        !          1263:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]);
        !          1264:     /* printf("hoff: %04X voff: %04X hwid: %04X cell: %08X info: %04X\n",
        !          1265:           hoffset, voffset, hwidth, (hoffset>>3)+hwidth*(voffset>>4),
        !          1266:           cellinfo); */
        !          1267:     /* printf("loc %08X cellinfo %08X\n",
        !          1268:           (hoffset>>3)+hwidth*(voffset>>4),
        !          1269:           cellinfo); */
        !          1270:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1271:       palette = (cellinfo >> 13) & 3;
        !          1272:       pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */
        !          1273:       if (cellinfo & 1<<12) {
        !          1274:        /* vertical flip */
        !          1275:        pattern+= 4*(15-(voffset & 15));
        !          1276:       } else {
        !          1277:        /* no vertical flip */
        !          1278:        pattern+= 4*(voffset & 15);
        !          1279:       }
        !          1280:       data = LOCENDIAN32(*(uint32 *)pattern);
        !          1281:       if (cellinfo & 1<<11) {
        !          1282:        /* horizontal flip */
        !          1283:        for (i = 0; i < 8; i++) {
        !          1284:          pixel = data & 15;
        !          1285:          LINEDATA(i, pixel, priority);
        !          1286:          data>>= 4;
        !          1287:        }
        !          1288:       } else {
        !          1289:        for (i = 0; i < 8; i++) {
        !          1290:          pixel = (data>>28) & 15;
        !          1291:          LINEDATA(i, pixel, priority);
        !          1292:          data<<= 4;
        !          1293:        }
        !          1294:       }
        !          1295:     }
        !          1296:     linedata+= 8;
        !          1297:     hoffset+= 8;
        !          1298:     hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1299:   }
        !          1300:   if (hoffset & 7) {
        !          1301:     if (vmode) {
        !          1302:       /* 2-cell scroll - note use last offset, not next */
        !          1303:       /* DEBUG DEBUG DEBUG awooga awooga */
        !          1304:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)
        !          1305:                                     [2*(j>>1)+layer] )) & 0x7FF;
        !          1306:     } else {
        !          1307:       /* full screen */
        !          1308:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF;
        !          1309:     }
        !          1310:     voffset&= (vwidth*16)-1; /* put offset in range */
        !          1311:     cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]);
        !          1312:     if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1313:       palette = (cellinfo >> 13) & 3;
        !          1314:       pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */
        !          1315:       if (cellinfo & 1<<12) {
        !          1316:        /* vertical flip */
        !          1317:        pattern+= 4*(15-(voffset & 15));
        !          1318:       } else {
        !          1319:        /* no vertical flip */
        !          1320:        pattern+= 4*(voffset & 15);
        !          1321:       }
        !          1322:       data = LOCENDIAN32(*(uint32 *)pattern);
        !          1323:       if (cellinfo & 1<<11) {
        !          1324:        /* horizontal flip */
        !          1325:        for (i = 0; i < (hoffset & 7); i++) {
        !          1326:          pixel = data & 15;
        !          1327:          LINEDATA(i, pixel, priority);
        !          1328:          data>>= 4;
        !          1329:        }
        !          1330:       } else {
        !          1331:        for (i = 0; i < (hoffset & 7); i++) {
        !          1332:          pixel = (data>>28) & 15;
        !          1333:          LINEDATA(i, pixel, priority);
        !          1334:          data<<= 4;
        !          1335:        }
        !          1336:       }
        !          1337:     }
        !          1338:     linedata+= 8;
        !          1339:   }
        !          1340: }
        !          1341: 
        !          1342: void vdp_renderline(unsigned int line, uint8 *linedata)
        !          1343: {
        !          1344:   int i;
        !          1345:   uint32 background;
        !          1346: 
        !          1347:   /* fill in background */
        !          1348:   background = vdp_reg[7] & 63;
        !          1349:   background|= background<<8;
        !          1350:   background|= background<<16;
        !          1351: 
        !          1352:   for (i = 0; i < (320 / 4); i++)
        !          1353:     ((uint32 *)linedata)[i] = background;
        !          1354: 
        !          1355:   if (vdp_reg[1] & 1<<6) {
        !          1356:     if (vdp_layerB)
        !          1357:       vdp_layer(line, 1, 0, linedata);
        !          1358:     if (vdp_layerA)
        !          1359:       vdp_layer(line, 0, 0, linedata);
        !          1360:     if (vdp_layerW)
        !          1361:       vdp_window(line, 0, linedata);
        !          1362:     if (vdp_layerS)
        !          1363:       vdp_sprites(line,  0, linedata);
        !          1364:     if (vdp_layerH && (vdp_reg[12] & 1<<3))
        !          1365:       vdp_shadow(line, linedata);
        !          1366:     if (vdp_layerBp)
        !          1367:       vdp_layer(line, 1, 1, linedata);
        !          1368:     if (vdp_layerAp)
        !          1369:       vdp_layer(line, 0, 1, linedata);
        !          1370:     if (vdp_layerWp)
        !          1371:       vdp_window(line, 1, linedata);
        !          1372:     if (vdp_layerSp)
        !          1373:       vdp_sprites(line,  1, linedata);
        !          1374:   }
        !          1375: }
        !          1376: 
        !          1377: void vdp_renderline_interlace2(unsigned int line, uint8 *linedata)
        !          1378: {
        !          1379:   int i;
        !          1380:   uint32 background;
        !          1381: 
        !          1382:   /* fill in background */
        !          1383:   background = vdp_reg[7] & 63;
        !          1384:   background|= background<<8;
        !          1385:   background|= background<<16;
        !          1386: 
        !          1387:   for (i = 0; i < (320 / 4); i++)
        !          1388:     ((uint32 *)linedata)[i] = background;
        !          1389: 
        !          1390:   if (vdp_reg[1] & 1<<6) {
        !          1391:     if (vdp_layerB)
        !          1392:       vdp_layer_interlace(line, 1, 0, linedata);
        !          1393:     if (vdp_layerA)
        !          1394:       vdp_layer_interlace(line, 0, 0, linedata);
        !          1395:     /*
        !          1396:       if (vdp_layerW)
        !          1397:       vdp_window(line, 0, linedata);
        !          1398:     */
        !          1399:     if (vdp_layerS)
        !          1400:       vdp_sprites(line,  0, linedata);
        !          1401:     if (vdp_layerH && (vdp_reg[12] & 1<<3))
        !          1402:       vdp_shadow(line, linedata);
        !          1403:     if (vdp_layerBp)
        !          1404:       vdp_layer_interlace(line, 1, 1, linedata);
        !          1405:     if (vdp_layerAp)
        !          1406:       vdp_layer_interlace(line, 0, 1, linedata);
        !          1407:     /*
        !          1408:       if (vdp_layerWp)
        !          1409:       vdp_window(line, 1, linedata);
        !          1410:     */
        !          1411:     if (vdp_layerSp)
        !          1412:       vdp_sprites(line,  1, linedata);
        !          1413:   }
        !          1414: }
        !          1415: 
        !          1416: void vdp_renderframe(uint8 *framedata, unsigned int lineoffset)
        !          1417: {
        !          1418:   unsigned int i, line;
        !          1419:   uint32 background;
        !          1420:   unsigned int vertcells = vdp_reg[1] & 1<<3 ? 30 : 28;
        !          1421:   uint8 *linedata;
        !          1422: 
        !          1423:   /* fill in background */
        !          1424: 
        !          1425:   background = vdp_reg[7] & 63;
        !          1426:   background|= background<<8;
        !          1427:   background|= background<<16;
        !          1428: 
        !          1429:   for (line = 0; line < vertcells*8; line++) {
        !          1430:     linedata = framedata + line*lineoffset;
        !          1431:     for (i = 0; i < (320 / 4); i++) {
        !          1432:       ((uint32 *)linedata)[i] = background;
        !          1433:     }
        !          1434:   }
        !          1435: 
        !          1436:   if (vdp_reg[1] & 1<<6) {
        !          1437:     if (vdp_layerB)
        !          1438:       vdp_layer_simple(1, 0, framedata, lineoffset);
        !          1439:     if (vdp_layerA)
        !          1440:       vdp_layer_simple(0, 0, framedata, lineoffset);
        !          1441:     if (vdp_layerS)
        !          1442:       vdp_sprites_simple(0, framedata, lineoffset);
        !          1443:     if (vdp_layerH && (vdp_reg[12] & 1<<3))
        !          1444:       vdp_shadow_simple(framedata, lineoffset);
        !          1445:     if (vdp_layerBp)
        !          1446:       vdp_layer_simple(1, 1, framedata, lineoffset);
        !          1447:     if (vdp_layerAp)
        !          1448:       vdp_layer_simple(0, 1, framedata, lineoffset);
        !          1449:     if (vdp_layerSp)
        !          1450:       vdp_sprites_simple(1, framedata, lineoffset);
        !          1451:   }
        !          1452: }
        !          1453: 
        !          1454: void vdp_showregs(void)
        !          1455: {
        !          1456:   int i;
        !          1457: 
        !          1458:   for (i = 0; i < 25; i++) {
        !          1459:     printf("[%02d] %02X: ", i, vdp_reg[i]);
        !          1460:     switch(i) {
        !          1461:     case 0:
        !          1462:       printf("%s ", vdp_reg[0] & 1<<1 ? "HV-stop" : "HV-enable");
        !          1463:       printf("%s ", vdp_reg[0] & 1<<4 ? "HInt-enable" : "HInt-disable");
        !          1464:       break;
        !          1465:     case 1:
        !          1466:       printf("%s ", vdp_reg[1] & 1<<3 ? "30-cell" : "28-cell");
        !          1467:       printf("%s ", vdp_reg[1] & 1<<4 ? "DMA-enable" : "DMA-disable");
        !          1468:       printf("%s ", vdp_reg[1] & 1<<5 ? "VInt-enable" : "VInt-disable");
        !          1469:       printf("%s ", vdp_reg[1] & 1<<6 ? "Disp-enable" : "Disp-disable");
        !          1470:       break;
        !          1471:     case 2:
        !          1472:       printf("Scroll A @ %04X", (vdp_reg[2] & 0x38)<<10);
        !          1473:       break;
        !          1474:     case 3:
        !          1475:       printf("Window @ %04X", (vdp_reg[3] & 0x3E)<<10);
        !          1476:       break;
        !          1477:     case 4:
        !          1478:       printf("Scroll B @ %04X", (vdp_reg[4] & 7)<<13);
        !          1479:       break;
        !          1480:     case 5:
        !          1481:       printf("Sprites @ %04X", (vdp_reg[5] & 0x7F)<<9);
        !          1482:       break;
        !          1483:     case 7:
        !          1484:       printf("bgpal %d col %d", (vdp_reg[7]>>4 & 3), (vdp_reg[7] & 15));
        !          1485:       break;
        !          1486:     case 10:
        !          1487:       printf("hintreg %04X", vdp_reg[10]);
        !          1488:       break;
        !          1489:     case 11:
        !          1490:       printf("V-mode %d H-mode %d ", (vdp_reg[11]>>2) & 1, (vdp_reg[11] & 3));
        !          1491:       printf("%s", (vdp_reg[11] & 1<<3) ? "ExtInt-enable" : "ExtInt-disable");
        !          1492:       break;
        !          1493:     case 12:
        !          1494:       printf("Interlace %d ", (vdp_reg[12]>>1) & 3);
        !          1495:       printf("%s ", (vdp_reg[12] & 1<<0) ? "40-cell" : "32-cell");
        !          1496:       printf("%s ", (vdp_reg[12] & 1<<3) ? "Shadow-enable" : "Shadow-disable");
        !          1497:       break;
        !          1498:     case 13:
        !          1499:       printf("Scroll A @ %04X", (vdp_reg[13] & 0x3F)<<10);
        !          1500:       break;
        !          1501:     case 15:
        !          1502:       printf("Autoinc %d", vdp_reg[15]);
        !          1503:       break;
        !          1504:     case 16:
        !          1505:       printf("Vsize %d Hsize %d", (vdp_reg[16]>>4) & 3, (vdp_reg[16] & 3));
        !          1506:       break;
        !          1507:     case 17:
        !          1508:       printf("Window H %s ", (vdp_reg[17] & 1<<7) ? "right" : "left");
        !          1509:       printf("%d", vdp_reg[17] & 0x1F);
        !          1510:       break;
        !          1511:     case 18:
        !          1512:       printf("Window V %s ", (vdp_reg[18] & 1<<7) ? "lower" : "upper");
        !          1513:       printf("%d", vdp_reg[18] & 0x1F);
        !          1514:       break;
        !          1515:     case 19:
        !          1516:       printf("DMA-length-low %02X", vdp_reg[19]);
        !          1517:       break;
        !          1518:     case 20:
        !          1519:       printf("DMA-length-high %02X", vdp_reg[20]);
        !          1520:       break;
        !          1521:     case 21:
        !          1522:       printf("DMA-source-low %02X", vdp_reg[21]);
        !          1523:       break;
        !          1524:     case 22:
        !          1525:       printf("DMA-source-mid %02X", vdp_reg[22]);
        !          1526:       break;
        !          1527:     case 23:
        !          1528:       printf("DMA-source-high %02X", vdp_reg[23]);
        !          1529:       break;
        !          1530:     }
        !          1531:     printf("\n");
        !          1532:   }
        !          1533: }
        !          1534: 
        !          1535: void vdp_spritelist(void)
        !          1536: {
        !          1537:   uint8 *spritelist = vdp_vram + ((vdp_reg[5] & 0x7F)<<9);
        !          1538:   uint8 *sprite;
        !          1539:   uint8 link = 0;
        !          1540:   uint16 pattern;
        !          1541:   uint8 palette;
        !          1542:   uint16 cellinfo;
        !          1543:   sint16 vpos, hpos, vmax;
        !          1544:   uint8 vsize, hsize;
        !          1545: 
        !          1546:   LOG_REQUEST(("SPRITE DUMP: (base=vram+%X)",
        !          1547:               (vdp_reg[5] & 0x7f)<<9));
        !          1548:   do {
        !          1549:     sprite = spritelist + (link<<3);
        !          1550:     hpos = (LOCENDIAN16(*(uint16 *)(sprite+6)) & 0x1FF) - 0x80;
        !          1551:     vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x3FF) - 0x80;
        !          1552:     vsize = 1+(sprite[2] & 3);
        !          1553:     hsize = 1+((sprite[2]>>2) & 3);
        !          1554:     cellinfo = LOCENDIAN16(*(uint16 *)(sprite+4));
        !          1555:     pattern = cellinfo & 0x7FF;
        !          1556:     palette = (cellinfo >> 13) & 3;
        !          1557:     vmax = vpos + vsize*8;
        !          1558: 
        !          1559:     LOG_REQUEST(("Sprite %d @ %X", link,
        !          1560:                 (link<<3) | (vdp_reg[5] & 0x7f)<<9));
        !          1561:     LOG_REQUEST(("  Pos:  %d,%d", hpos, vpos));
        !          1562:     LOG_REQUEST(("  Size: %d,%d", hsize, vsize));
        !          1563:     LOG_REQUEST(("  Pri: %d, Pal: %d, Vflip: %d, Hflip: %d",
        !          1564:                 (cellinfo>>15 & 1), (cellinfo>>13 & 3), (cellinfo>>12 & 1),
        !          1565:                 (cellinfo>>11 & 1)));
        !          1566:     LOG_REQUEST(("  Pattern: %d @ vram+%X", (cellinfo & 0x7FF),
        !          1567:                 (cellinfo & 0x7FF)));
        !          1568:     link = sprite[3] & 0x7F;
        !          1569:   } while (link);
        !          1570: }
        !          1571: 
        !          1572: void vdp_describe(void)
        !          1573: {
        !          1574:   int layer;
        !          1575:   unsigned int line;
        !          1576:   uint32 o_patterndata, o_hscrolldata;
        !          1577:   uint16 *patterndata, *hscrolldata;
        !          1578:   uint8 hsize = vdp_reg[16] & 3;
        !          1579:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
        !          1580:   uint8 hmode = vdp_reg[11] & 3;
        !          1581:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
        !          1582:   uint16 hwidth, vwidth, hoffset, voffset, raw_hoffset;
        !          1583: 
        !          1584:   hwidth = 32+hsize*32;
        !          1585:   vwidth = 32+vsize*32;
        !          1586:   LOG_REQUEST(("VDP description:"));
        !          1587:   LOG_REQUEST(("  hsize = %d (ie. width=%d)", hsize, hwidth));
        !          1588:   LOG_REQUEST(("  vsize = %d (ie. width=%d)", vsize, vwidth));
        !          1589:   LOG_REQUEST(("  hmode = %d (0=full, 2=cell, 3=line)", hmode));
        !          1590:   LOG_REQUEST(("  vmode = %d (0=full, 1=2cell", vmode));
        !          1591: 
        !          1592:   for (layer = 0; layer < 2; layer++) {
        !          1593:     LOG_REQUEST(("  Layer %s:", layer == 0 ? "A" : "B"));
        !          1594:     o_patterndata = (layer == 0 ? ((vdp_reg[2] & 0x38)<<10) :
        !          1595:                     ((vdp_reg[4] & 7)<<13));
        !          1596:     o_hscrolldata = layer*2 + ((vdp_reg[13] & 63)<<10);
        !          1597:     LOG_REQUEST(("    Pattern data @ vram+%08X", o_patterndata));
        !          1598:     LOG_REQUEST(("    Hscroll data @ vram+%08X", o_hscrolldata));
        !          1599:     patterndata = (uint16 *)(vdp_vram + o_patterndata);
        !          1600:     hscrolldata = (uint16 *)(vdp_vram + o_hscrolldata);
        !          1601:     for (line = 0; line < vdp_vislines; line++) {
        !          1602:       switch(hmode) {
        !          1603:       case 0: /* full screen */
        !          1604:        hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF;
        !          1605:        break;
        !          1606:       case 2: /* cell scroll */
        !          1607:        hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(line & ~7)])) & 0x3FF;
        !          1608:        break;
        !          1609:       case 3: /* line scroll */
        !          1610:        hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*line])) & 0x3FF;
        !          1611:        break;
        !          1612:       default:
        !          1613:        LOG_REQUEST(("prohibited HSCR/LSCR on line %d", line));
        !          1614:        hoffset = 0;
        !          1615:        break;
        !          1616:       }
        !          1617:       raw_hoffset = hoffset;
        !          1618:       hoffset&= (hwidth*8)-1; /* put offset in range */
        !          1619:       voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x3FF;
        !          1620:       voffset&= (vwidth*8)-1; /* put offset in range */
        !          1621:       LOG_REQUEST(("     line %d: hoffset=%d=%d, voffset=%d, "
        !          1622:                   "firstcell=vram+%08X", line, raw_hoffset, hoffset, voffset,
        !          1623:                   o_patterndata+2*((hoffset>>3)+hwidth*(voffset>>3))));
        !          1624:     }
        !          1625:   }
        !          1626: }
        !          1627: 
        !          1628: void vdp_eventinit(void)
        !          1629: {
        !          1630:   /* Facts from documentation:
        !          1631:        H-Blank is 73.7 clock cycles long.
        !          1632:        The VDP settings are aquired 36 clocks after start of H-Blank.
        !          1633:        The display period is 413.3 clocks in duration.
        !          1634:        V-Int occurs 14.7us after H-Int (which is 112 clock cycles)
        !          1635:      Facts from clock data:
        !          1636:        One line takes 488 clocks (vdp_clksperline_68k)
        !          1637:      Assumptions:
        !          1638:        We 'approximate' and make H-Int occur at the same time as H-Blank.
        !          1639:        V-Blank starts at V-Int and ends at the start of line 0.
        !          1640: 
        !          1641:      vdp_event_start    = start of line, end of v-blank
        !          1642:      vdp_event_vint     = v-int time on line 224 (or 240)
        !          1643:                                 (112 clocks after h-int)
        !          1644:      vdp_event_hint     = h-int time at end of each line
        !          1645:      vdp_event_hdisplay = settings are aquired and current line displayed
        !          1646:      vdp_event_end      = end of line, end of h-blank
        !          1647: 
        !          1648:      Note that if the program stays in H-Int 224 longer than 112 clocks, V-Int
        !          1649:      is not supposed to occur due to the processor acknowledging the wrong
        !          1650:      interrupt from the VDP, thus programs disable H-Ints on 223 to prevent
        !          1651:      this problem.  We don't worry about this.
        !          1652:   */
        !          1653:   vdp_event = 0;
        !          1654:   vdp_event_start = 0;
        !          1655:   vdp_event_vint = 112-74;
        !          1656:   vdp_event_hint = vdp_clksperline_68k-74;
        !          1657:   vdp_event_hdisplay = vdp_event_hint+36;
        !          1658:   vdp_event_end = vdp_clksperline_68k;
        !          1659: }
        !          1660: 
        !          1661: void vdp_endfield(void)
        !          1662: {
        !          1663:   vdp_line = 0;
        !          1664:   vdp_eventinit();
        !          1665:   vdp_oddframe^= 1; /* toggle */
        !          1666:   /* printf("(%d,%d,%d,%d,%d)\n", vdp_event_type,
        !          1667:      vdp_event_startline, vdp_event_hint, vdp_event_vdpplot,
        !          1668:      vdp_event_endline); */
        !          1669: }
        !          1670: 
        !          1671: inline void vdp_plotcell(uint8 *patloc, uint8 palette, uint8 flags,
        !          1672:                         uint8 *cellloc, unsigned int lineoffset)
        !          1673: {
        !          1674:   int y, x;
        !          1675:   uint8 value;
        !          1676:   uint32 data;
        !          1677: 
        !          1678:   switch(flags) {
        !          1679:   case 0:
        !          1680:     /* normal tile - no s/ten */
        !          1681:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          1682:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
        !          1683:       for (x = 0; x < 8; x++, data<<= 4) {
        !          1684:        value = data>>28;
        !          1685:        if (value)
        !          1686:          cellloc[x] = palette*16 + value;
        !          1687:       }
        !          1688:     }
        !          1689:     break;
        !          1690:   case 1:
        !          1691:     /* h flipped tile - no s/ten */
        !          1692:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          1693:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
        !          1694:       for (x = 0; x < 8; x++, data>>= 4) {
        !          1695:        value = data & 15;
        !          1696:        if (value)
        !          1697:          cellloc[x] = palette*16 + value;
        !          1698:       }
        !          1699:     }
        !          1700:     break;
        !          1701:   case 2:
        !          1702:     /* v flipped tile - no s/ten */
        !          1703:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          1704:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
        !          1705:       for (x = 0; x < 8; x++, data<<= 4) {
        !          1706:        value = data>>28;
        !          1707:        if (value)
        !          1708:          cellloc[x] = palette*16 + value;
        !          1709:       }
        !          1710:     }
        !          1711:     break;
        !          1712:   case 3:
        !          1713:     /* h and v flipped tile - no s/ten */
        !          1714:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          1715:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
        !          1716:       for (x = 0; x < 8; x++, data>>= 4) {
        !          1717:        value = data & 15;
        !          1718:        if (value)
        !          1719:          cellloc[x] = palette*16 + value;
        !          1720:       }
        !          1721:     }
        !          1722:     break;
        !          1723:   case 4:
        !          1724:     /* normal tile - s/ten enabled */
        !          1725:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          1726:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
        !          1727:       for (x = 0; x < 8; x++, data<<= 4) {
        !          1728:        value = data>>28;
        !          1729:        if (value) {
        !          1730:          if (palette == 3 && value == 14) {
        !          1731:            cellloc[x] = (cellloc[x] & 63) + 64;
        !          1732:          } else if (palette == 3 && value == 15) {
        !          1733:            cellloc[x] = (cellloc[x] & 63) + 128;
        !          1734:          } else {
        !          1735:            cellloc[x] = palette*16 + value;
        !          1736:          }
        !          1737:        }
        !          1738:       }
        !          1739:     }
        !          1740:     break;
        !          1741:   case 5:
        !          1742:     /* h flipped tile - s/ten */
        !          1743:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          1744:       data = LOCENDIAN32(((uint32 *)patloc)[y]);
        !          1745:       for (x = 0; x < 8; x++, data>>= 4) {
        !          1746:        value = data & 15;
        !          1747:        if (value) {
        !          1748:          if (palette == 3 && value == 14) {
        !          1749:            cellloc[x] = (cellloc[x] & 63) + 64;
        !          1750:          } else if (palette == 3 && value == 15) {
        !          1751:            cellloc[x] = (cellloc[x] & 63) + 128;
        !          1752:          } else {
        !          1753:            cellloc[x] = palette*16 + value;
        !          1754:          }
        !          1755:        }
        !          1756:       }
        !          1757:     }
        !          1758:     break;
        !          1759:   case 6:
        !          1760:     /* v flipped tile - s/ten enabled */
        !          1761:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          1762:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
        !          1763:       for (x = 0; x < 8; x++, data<<= 4) {
        !          1764:        value = data>>28;
        !          1765:        if (value) {
        !          1766:          if (palette == 3 && value == 14) {
        !          1767:            cellloc[x] = (cellloc[x] & 63) + 64;
        !          1768:          } else if (palette == 3 && value == 15) {
        !          1769:            cellloc[x] = (cellloc[x] & 63) + 128;
        !          1770:          } else {
        !          1771:            cellloc[x] = palette*16 + value;
        !          1772:          }
        !          1773:        }
        !          1774:       }
        !          1775:     }
        !          1776:     break;
        !          1777:   case 7:
        !          1778:     /* h and v flipped tile - s/ten enabled */
        !          1779:     for (y = 0; y < 8; y++, cellloc+= lineoffset) {
        !          1780:       data = LOCENDIAN32(((uint32 *)patloc)[7-y]);
        !          1781:       for (x = 0; x < 8; x++, data>>= 4) {
        !          1782:        value = data & 15;
        !          1783:        if (value) {
        !          1784:          if (palette == 3 && value == 14) {
        !          1785:            cellloc[x] = (cellloc[x] & 63) + 64;
        !          1786:          } else if (palette == 3 && value == 15) {
        !          1787:            cellloc[x] = (cellloc[x] & 63) + 128;
        !          1788:          } else {
        !          1789:            cellloc[x] = palette*16 + value;
        !          1790:          }
        !          1791:        }
        !          1792:       }
        !          1793:     }
        !          1794:     break;
        !          1795:   default:
        !          1796:     ui_err("Unknown plotcell flags");
        !          1797:   }
        !          1798: }
        !          1799: 
        !          1800: /* must be 8*lineoffset bytes scrap before and after fielddata and also
        !          1801:    8 bytes before each line and 8 bytes after each line */
        !          1802: 
        !          1803: void vdp_layer_simple(unsigned int layer, unsigned int priority,
        !          1804:                      uint8 *framedata, unsigned int lineoffset)
        !          1805: {
        !          1806:   int i, j;
        !          1807:   uint8 hsize = vdp_reg[16] & 3;
        !          1808:   uint8 vsize = (vdp_reg[16] >> 4) & 3;
        !          1809:   uint8 hmode = vdp_reg[11] & 3;
        !          1810:   uint8 vmode = (vdp_reg[11] >> 2) & 1;
        !          1811:   uint16 vramoffset = (layer ? ((vdp_reg[4] & 7) << 13) :
        !          1812:                       ((vdp_reg[2] & (7<<3)) << 10));
        !          1813:   uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset);
        !          1814:   uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10)
        !          1815:                                   + vdp_vram + layer*2);
        !          1816:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !          1817:   uint16 hwidth = 32+hsize*32;
        !          1818:   uint16 vwidth = 32+vsize*32;
        !          1819:   uint16 hoffset, voffset;
        !          1820:   uint16 cellinfo;
        !          1821:   uint8 *pattern;
        !          1822:   uint32 data;
        !          1823:   uint8 palette;
        !          1824:   uint8 value;
        !          1825:   unsigned int xcell, ycell;
        !          1826:   unsigned int pos;
        !          1827:   uint8 *toploc, *cellloc;
        !          1828:   uint8 flags;
        !          1829:   uint32 hscroll, vscroll;
        !          1830:   unsigned int x, y;
        !          1831: 
        !          1832:   for (xcell = 0; xcell <= screencells; xcell++) {
        !          1833:     if (vmode) {
        !          1834:       /* 2-cell scroll */
        !          1835:       vscroll = ((xcell >= screencells ? xcell-2 : xcell) & ~1) + layer;
        !          1836:     } else {
        !          1837:       /* full screen */
        !          1838:       vscroll = layer;
        !          1839:     }
        !          1840:     voffset = LOCENDIAN16( ((uint16 *)vdp_vsram)[vscroll] ) & 0x3FF;
        !          1841:     toploc = framedata - lineoffset*(voffset & 7);
        !          1842:     for (ycell = 0; ycell <= 28; ycell++, voffset+=8, toploc+=lineoffset*8) {
        !          1843:       switch(hmode) {
        !          1844:       case 0: /* full screen */
        !          1845:        hscroll = 0;
        !          1846:        break;
        !          1847:       case 2: /* cell scroll */
        !          1848:        hscroll = 2 * (ycell >= 28 ? ycell-2 : ycell) * 8;
        !          1849:        break;
        !          1850:       case 3: /* line scroll - approximation */
        !          1851:        hscroll = 2 * (ycell >= 28 ? ycell-2 : ycell) * 8;
        !          1852:        vdp_complex = 1;
        !          1853:        break;
        !          1854:       default:
        !          1855:        LOG_NORMAL(("prohibited HSCR/LSCR"));
        !          1856:        hscroll = 0;
        !          1857:        break;
        !          1858:       }
        !          1859:       voffset &= (vwidth*8)-1;
        !          1860:       hoffset = (0x400 - LOCENDIAN16(hscrolldata[hscroll])) & 0x3FF;
        !          1861:       hoffset = (hoffset+xcell*8) & ((hwidth*8)-1);
        !          1862:       cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>3)]);
        !          1863:       if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) {
        !          1864:        /* plot cell */
        !          1865:        palette = (cellinfo >> 13) & 3;
        !          1866:        pattern = vdp_vram + ((cellinfo & 2047)<<5);
        !          1867:        flags = (cellinfo>>11) & 3; /* bit0=H flip, bit1=V flip */
        !          1868:         cellloc = toploc - (hoffset&7) + xcell*8;
        !          1869:        vdp_plotcell(pattern, palette, flags, cellloc, lineoffset);
        !          1870:       }
        !          1871:     } /* ycell */
        !          1872:   } /* xcell */
        !          1873: }
        !          1874: 
        !          1875: void vdp_shadow_simple(uint8 *framedata, unsigned int lineoffset)
        !          1876: {
        !          1877:   unsigned int vertcells = vdp_reg[1] & 1<<3 ? 30 : 28;
        !          1878:   uint8 *linedata;
        !          1879:   unsigned int line;
        !          1880:   int i;
        !          1881: 
        !          1882:   for (line = 0; line < vertcells*8; line++) {
        !          1883:     linedata = framedata + line*lineoffset;
        !          1884:     /* this could be done 4 bytes at a time */
        !          1885:     for (i = 0; i < 320; i++)
        !          1886:       linedata[i] = (linedata[i] & 63) + 128;
        !          1887:   }
        !          1888: }
        !          1889: 
        !          1890: void vdp_sprites_simple(unsigned int priority, uint8 *framedata,
        !          1891:                        unsigned int lineoffset)
        !          1892: {
        !          1893:   uint8 *spritelist = vdp_vram + ((vdp_reg[5] & 0x7F)<<9);
        !          1894: 
        !          1895:   vdp_sprite_simple(priority, framedata, lineoffset, 1,
        !          1896:                    spritelist, spritelist);
        !          1897: }
        !          1898: 
        !          1899: int vdp_sprite_simple(unsigned int priority, uint8 *framedata,
        !          1900:                      unsigned int lineoffset, unsigned int number,
        !          1901:                      uint8 *spritelist, uint8 *sprite)
        !          1902: {
        !          1903:   int i, j;
        !          1904:   int plotted = 1;
        !          1905:   uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32;
        !          1906:   uint8 link;
        !          1907:   uint16 pattern;
        !          1908:   uint32 data;
        !          1909:   uint8 palette;
        !          1910:   uint16 cellinfo;
        !          1911:   sint16 vpos, hpos, vmax;
        !          1912:   uint16 xcell, ycell;
        !          1913:   uint8 vsize, hsize;
        !          1914:   uint8 *cellloc;
        !          1915:   uint8 flags;
        !          1916:   uint8 *patloc;
        !          1917: 
        !          1918:   if (number > 80) {
        !          1919:     LOG_VERBOSE(("%08X [VDP] Maximum of 80 sprites exceeded", regs.pc));
        !          1920:     return 0;
        !          1921:   }
        !          1922: 
        !          1923:   link = sprite[3] & 0x7F;
        !          1924:   hpos = (LOCENDIAN16(*(uint16 *)(sprite+6)) & 0x1FF) - 0x80;
        !          1925:   vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x3FF) - 0x80;
        !          1926:   vsize = 1+(sprite[2] & 3);
        !          1927:   hsize = 1+((sprite[2]>>2) & 3);
        !          1928:   cellinfo = LOCENDIAN16(*(uint16 *)(sprite+4));
        !          1929:   pattern = cellinfo & 0x7FF;
        !          1930:   palette = (cellinfo >> 13) & 3;
        !          1931:   vmax = vpos + vsize*8;
        !          1932:   
        !          1933:   if (link) {
        !          1934:     if (hpos == -128)
        !          1935:       /* we do not support 'masking' in simple mode */
        !          1936:       vdp_complex = 1;
        !          1937:     plotted = vdp_sprite_simple(priority, framedata, lineoffset, number+1,
        !          1938:                                spritelist, spritelist + (link<<3));
        !          1939:     plotted++;
        !          1940:   }
        !          1941: 
        !          1942:   if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) != priority)
        !          1943:     return plotted;
        !          1944:   if (vpos >= 240 || hpos >= 320 || vpos+vsize*8 <= 0 || hpos+hsize*8 <= 0)
        !          1945:     /* sprite is not on screen */
        !          1946:     return plotted;
        !          1947:   flags = (cellinfo>>11) & 3; /* bit0=H flip, bit1=V flip */
        !          1948:   flags|= 1<<2 ; /* s/ten enable */
        !          1949:   switch(flags) {
        !          1950:   case 0:
        !          1951:   case 4:
        !          1952:     /* normal orientation */
        !          1953:     for (ycell = 0; ycell < vsize; ycell++) {
        !          1954:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
        !          1955:        /* cell out of plotting area (remember scrap area) */
        !          1956:        continue;
        !          1957:       patloc = vdp_vram + (pattern<<5) + ycell*32;
        !          1958:       for (xcell = 0; xcell < hsize; xcell++, patloc+= vsize*32) {
        !          1959:        if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          1960:          /* cell out of plotting area */
        !          1961:          continue;
        !          1962:        cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          1963:                               (hpos+xcell*8));
        !          1964:        vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
        !          1965:       }
        !          1966:     }
        !          1967:     break;
        !          1968:   case 1:
        !          1969:   case 5:
        !          1970:     /* H flip */
        !          1971:     for (ycell = 0; ycell < vsize; ycell++) {
        !          1972:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
        !          1973:        /* cell out of plotting area (remember scrap area) */
        !          1974:        continue;
        !          1975:       patloc = vdp_vram + (pattern<<5) + ycell*32 + vsize*32*(hsize-1);
        !          1976:       for (xcell = 0; xcell < hsize; xcell++, patloc-= vsize*32) {
        !          1977:        if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          1978:          /* cell out of plotting area */
        !          1979:          continue;
        !          1980:        cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          1981:                               (hpos+xcell*8));
        !          1982:        vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
        !          1983:       }
        !          1984:     }
        !          1985:     break;
        !          1986:   case 2:
        !          1987:   case 6:
        !          1988:     /* V flip */
        !          1989:     for (ycell = 0; ycell < vsize; ycell++) {
        !          1990:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
        !          1991:        /* cell out of plotting area (remember scrap area) */
        !          1992:        continue;
        !          1993:       patloc = vdp_vram + (pattern<<5) + (vsize-ycell-1)*32;
        !          1994:       for (xcell = 0; xcell < hsize; xcell++, patloc+= vsize*32) {
        !          1995:        if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          1996:          /* cell out of plotting area */
        !          1997:          continue;
        !          1998:        cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          1999:                               (hpos+xcell*8));
        !          2000:        vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
        !          2001:       }
        !          2002:     }
        !          2003:     break;
        !          2004:   case 3:
        !          2005:   case 7:
        !          2006:     /* H and V flip */
        !          2007:     for (ycell = 0; ycell < vsize; ycell++) {
        !          2008:       if (ycell*8+vpos < -7 || ycell*8+vpos >= 240)
        !          2009:        /* cell out of plotting area (remember scrap area) */
        !          2010:        continue;
        !          2011:       patloc = vdp_vram + (pattern<<5) + ((vsize-ycell-1)*32 +
        !          2012:                                          vsize*32*(hsize-1));
        !          2013:       for (xcell = 0; xcell < hsize; xcell++, patloc-= vsize*32) {
        !          2014:        if (xcell*8+hpos < -7 || xcell*8+hpos >= 320)
        !          2015:          /* cell out of plotting area */
        !          2016:          continue;
        !          2017:        cellloc = framedata + ((vpos+ycell*8)*lineoffset +
        !          2018:                               (hpos+xcell*8));
        !          2019:        vdp_plotcell(patloc, palette, flags, cellloc, lineoffset);
        !          2020:       }
        !          2021:     }
        !          2022:     break;
        !          2023:   }
        !          2024:   return plotted;
        !          2025: }
        !          2026: 
        !          2027: uint8 vdp_gethpos(void) {
        !          2028:   /* vdp_event = 0/1/2 -> beginning of line until 74 clocks before end
        !          2029:                  3     -> between hint and hdisplay (36 clocks)
        !          2030:                  4     -> between hdisplay and end  (38 clocks)
        !          2031:      This routine goes from 0 to the maximum number allowed not within
        !          2032:      H-blank, and then goes slightly beyond up to hdisplay.  Then
        !          2033:      between hdisplay and end we go negative.  I'm not sure how negative
        !          2034:      it is supposed to be, this goes from -38 to 0.
        !          2035: 
        !          2036:      this is such a bodge - any changes, check '3 Ninjas kick back'
        !          2037:   */
        !          2038:   LOG_DEBUG1(("gethpos %X: clocks=%X : startofline=%X : hint=%X : "
        !          2039:              "end=%X", vdp_event, cpu68k_clocks, vdp_event_startofcurrentline,
        !          2040:              vdp_event_hint, vdp_event_end));
        !          2041:   if (vdp_event == 1 || vdp_event == 2) {
        !          2042:     if (cpu68k_clocks > vdp_event_hint)
        !          2043:       return (vdp_reg[12] & 1) ? 0x9f : 0x7f;
        !          2044:     return (((vdp_reg[12] & 1) ? 0x9f : 0x7f)*
        !          2045:            ((float)(cpu68k_clocks-vdp_event_startofcurrentline)/
        !          2046:             (float)(vdp_event_hint-vdp_event_startofcurrentline)));
        !          2047:   }
        !          2048:   LOG_DEBUG1(("gethpos %d %d %02X", vdp_event_end, cpu68k_clocks,
        !          2049:              vdp_event_end-cpu68k_clocks));
        !          2050:   if (cpu68k_clocks > vdp_event_end)
        !          2051:     return 0xff;
        !          2052:   return -(vdp_event_end-cpu68k_clocks);
        !          2053: }

unix.superglobalmegacorp.com

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