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

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

unix.superglobalmegacorp.com

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