Annotation of generator/src/vdp.c, revision 1.1.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.