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

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

unix.superglobalmegacorp.com

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