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