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