|
|
1.1.1.2 ! 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 */ 1.1 root 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" 1.1.1.2 ! root 21: #include "event.h" 1.1 root 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; 1.1.1.2 ! root 32: unsigned int vdp_visstartline; ! 33: unsigned int vdp_visendline; 1.1 root 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 */ 1.1.1.2 ! root 44: unsigned int vdp_dmabusy = 0; /* dma busy flag */ 1.1 root 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; 1.1.1.2 ! root 65: signed int vdp_nextevent = 0; ! 66: sint32 vdp_dmabytes = 0; /* bytes left in DMA - must be fixed size */ 1.1 root 67: signed int vdp_hskip_countdown = 0; /* actual countdown */ 1.1.1.2 ! root 68: uint16 vdp_address; /* address for data/dma transfers */ ! 69: t_code vdp_code; /* code number for data/dma transfers CD3-CD0 */ ! 70: unsigned int vdp_ctrlflag; /* set inbetween ctrl writes */ ! 71: uint16 vdp_first; /* first word of address set */ ! 72: uint16 vdp_second; /* second word of address set */ 1.1 root 73: 74: /*** global variables ***/ 75: 76: uint8 vdp_reg[25]; 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); 1.1.1.2 ! root 86: void vdp_dma_vramcopy(void); ! 87: void vdp_dma_fill(uint8 data); 1.1 root 88: void vdp_showregs(void); 89: void vdp_describe(void); 90: void vdp_eventinit(void); 91: void vdp_layer_simple(unsigned int layer, unsigned int priority, 1.1.1.2 ! root 92: uint8 *fielddata, unsigned int lineoffset); 1.1 root 93: inline void vdp_plotcell(uint8 *patloc, uint8 palette, uint8 flags, 1.1.1.2 ! root 94: uint8 *cellloc, unsigned int lineoffset); ! 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); 1.1 root 99: int vdp_sprite_simple(unsigned int priority, uint8 *framedata, 1.1.1.2 ! root 100: unsigned int lineoffset, unsigned int number, ! 101: uint8 *spritelist, uint8 *sprite); 1.1 root 102: void vdp_sprites_simple(unsigned int priority, uint8 *framedata, 1.1.1.2 ! root 103: unsigned int lineoffset); 1.1 root 104: void vdp_shadow_simple(uint8 *framedata, unsigned int lineoffset); 105: void vdp_window(unsigned int line, unsigned int priority, uint8 *linedata); 1.1.1.2 ! root 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 1.1 root 113: 114: /*** vdp_init - initialise this sub-unit ***/ 115: 116: int vdp_init(void) 117: { 118: vdp_reset(); 119: return 0; 120: } 121: 122: /*** vdp_setupvideo - setup parameters dependant on vdp_pal ***/ 123: 124: void vdp_setupvideo(void) 125: { 1.1.1.2 ! root 126: int v30 = (vdp_reg[1] & 1<<3) ? 1 : 0; ! 127: ! 128: if (!vdp_pal && v30) ! 129: ui_err("Impossible VDP mode - vertical 30 cell NTSC"); ! 130: 1.1 root 131: vdp_clock = vdp_pal ? 53200000 : 53693100; /* What speed is the PAL clock? */ 132: vdp_68kclock = vdp_clock / 7; 1.1.1.2 ! root 133: vdp_vislines = v30 ? 240 : 224; ! 134: vdp_visstartline = v30 ? 46 : (vdp_pal ? 54 : 19); ! 135: vdp_visendline = vdp_visstartline + vdp_vislines; 1.1 root 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: 1.1.1.2 ! root 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: 1.1 root 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 ? 1.1.1.2 ! root 187: "PAL" : "NTSC")); 1.1 root 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 1.1.1.2 ! root 205: * 10-15 are next word on bus, i.e. next word in ROM - CM 1.1 root 206: */ 1.1.1.2 ! root 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; 1.1 root 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; 1.1.1.2 ! root 217: vdp_ctrlflag = 0; /* Charles MacDonald - so he claims ;) */ 1.1 root 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) { 1.1.1.2 ! root 235: LOG_NORMAL(("%08X [VDP] Invalid register (%d)", regs.pc, ! 236: ((data>>8) & 31))); ! 237: return; 1.1 root 238: } 239: vdp_reg[reg] = regdata; 1.1.1.2 ! root 240: vdp_code = 0; 1.1 root 241: #ifdef DEBUG_VDP 242: LOG_VERBOSE(("%08X [VDP] Register %d set to %04X", regs.pc, 1.1.1.2 ! root 243: reg, regdata)); 1.1 root 244: #endif 245: return; 246: } else { 247: vdp_ctrlflag = 1; 1.1.1.2 ! root 248: vdp_first = data; 1.1 root 249: return; 250: } 251: } else { 1.1.1.2 ! root 252: vdp_second = data; 1.1 root 253: vdp_ctrlflag = 0; 1.1.1.2 ! root 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; 1.1 root 291: } 292: } 293: } 294: } 295: 1.1.1.2 ! root 296: void vdp_ramcopy_vram_obsolete(int type) 1.1 root 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 " 1.1.1.2 ! root 318: "vdpaddr=%08X length=%d", ! 319: regs.pc, srcoffset*2, type, vdp_address, length)); 1.1 root 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 " 1.1.1.2 ! root 326: "vdpaddr=%08X length=%d", ! 327: regs.pc, srcbank*0x20000+srcoffset*2, type, vdp_address, ! 328: length)); 1.1 root 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; 1.1.1.2 ! root 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: } 1.1 root 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: 1.1.1.2 ! root 382: void vdp_ramcopy_vram(int type) 1.1 root 383: { 384: uint16 length = vdp_reg[19] | vdp_reg[20]<<8; 1.1.1.2 ! root 385: uint8 srcbank = vdp_reg[23]; ! 386: uint16 srcoffset = vdp_reg[21] | vdp_reg[22]<<8; 1.1 root 387: uint8 increment = vdp_reg[15]; 1.1.1.2 ! root 388: uint16 *srcmemory; ! 389: uint16 srcmask; ! 390: uint16 data; ! 391: unsigned int i; 1.1 root 392: 1.1.1.2 ! root 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)); 1.1 root 397: #endif 1.1.1.2 ! root 398: ! 399: if (srcbank & 1<<6) { ! 400: srcmemory = (uint16 *)cpu68k_ram; ! 401: srcmask = 0x7fff; /* 32k words = 64k */ 1.1 root 402: } else { 1.1.1.2 ! root 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; 1.1 root 424: } 1.1.1.2 ! root 425: srcoffset+=1; ! 426: vdp_address+= increment; 1.1 root 427: } 1.1.1.2 ! root 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); 1.1 root 434: } 435: 1.1.1.2 ! root 436: void vdp_dma_vramcopy() 1.1 root 437: { 1.1.1.2 ! root 438: uint32 length = vdp_reg[19] | vdp_reg[20]<<8; 1.1 root 439: uint8 increment = vdp_reg[15]; 1.1.1.2 ! root 440: uint16 srcaddr = vdp_reg[21] | vdp_reg[22]<<8; ! 441: unsigned int i; 1.1 root 442: 1.1.1.2 ! root 443: if (length == 0) { ! 444: LOG_NORMAL(("%08X [VDP] Warning - length of 0 used in vram copy")); ! 445: length = 0x10000; /* could be 0xffff */ 1.1 root 446: } 1.1.1.2 ! root 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; 1.1 root 457: } 1.1.1.2 ! root 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) */ 1.1 root 464: } 465: 1.1.1.2 ! root 466: void vdp_dma_fill(uint8 data) 1.1 root 467: { 1.1.1.2 ! root 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) */ 1.1 root 483: } 484: 1.1.1.2 ! root 485: uint16 vdp_fetchdata_obsolete(void) 1.1 root 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, 1.1.1.2 ! root 495: vdp_address)); 1.1 root 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", 1.1.1.2 ! root 503: regs.pc, vdp_address)); 1.1 root 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, 1.1.1.2 ! root 511: vdp_address)); 1.1 root 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, 1.1.1.2 ! root 518: vdp_code)); 1.1 root 519: return 0; 520: } 521: if (vdp_address>=size) { 522: LOG_VERBOSE(("%08X [VDP] Address (%08X) out of bounds (%08X)", 1.1.1.2 ! root 523: regs.pc, vdp_address, size)); 1.1 root 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, 1.1.1.2 ! root 528: vdp_address & ~1)); 1.1 root 529: #endif 530: vdp_address+= vdp_reg[15]; 1.1.1.2 ! root 531: vdp_ctrlflag = 0; 1.1 root 532: return data; 533: } 534: 1.1.1.2 ! root 535: void vdp_storedata(uint16 data) 1.1 root 536: { 1.1.1.2 ! root 537: uint16 address; ! 538: uint16 sdata; ! 539: 1.1 root 540: if (vdp_ctrlflag) { 1.1.1.2 ! root 541: LOG_NORMAL(("%08X [VDP] Unterminated ctrl setting %04X/%04X", regs.pc, ! 542: vdp_first, vdp_second)); ! 543: vdp_storectrl(vdp_second); 1.1 root 544: } 1.1.1.2 ! root 545: 1.1 root 546: switch(vdp_code) { 547: case cd_vram_store: 1.1.1.2 ! root 548: sdata = (vdp_address & 1) ? SWAP16(data) : data; /* only for VRAM */ ! 549: *(uint16 *)(vdp_vram+(vdp_address & 0xfffe)) = LOCENDIAN16(sdata); ! 550: break; 1.1 root 551: case cd_cram_store: 1.1.1.2 ! root 552: address = vdp_address & 0x7e; /* address lines used */ ! 553: *(uint16 *)(vdp_cram+address) = LOCENDIAN16(data); ! 554: vdp_cramf[address>>1] = 1; ! 555: break; 1.1 root 556: case cd_vsram_store: 1.1.1.2 ! root 557: address = vdp_address & 0x7e; /* address lines used */ ! 558: if (address < LEN_VSRAM) ! 559: *(uint16 *)(vdp_vsram+address) = LOCENDIAN16(data); ! 560: break; 1.1 root 561: default: /* undefined */ 1.1.1.2 ! root 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); 1.1 root 573: } 574: } 575: 1.1.1.2 ! root 576: uint16 vdp_fetchdata(void) 1.1 root 577: { 1.1.1.2 ! root 578: uint16 address; ! 579: uint16 data; ! 580: 1.1 root 581: if (vdp_ctrlflag) { 1.1.1.2 ! root 582: LOG_NORMAL(("%08X [VDP] Unterminated ctrl setting %04X/%04X", regs.pc, ! 583: vdp_first, vdp_second)); ! 584: vdp_storectrl(vdp_second); 1.1 root 585: } 1.1.1.2 ! root 586: 1.1 root 587: switch(vdp_code) { 1.1.1.2 ! root 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; 1.1 root 603: default: /* undefined */ 1.1.1.2 ! root 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; 1.1 root 609: } 1.1.1.2 ! root 610: vdp_address+= vdp_reg[15]; /* 16 bit wrap */ ! 611: return data; 1.1 root 612: } 613: 1.1.1.2 ! root 614: #define LINEDATA(offset, value, palette, priority) \ 1.1 root 615: if (value) { \ 1.1.1.2 ! root 616: linedata[offset] = (palette)*16 + value; \ 1.1 root 617: } else if (priority) { \ 618: linedata[offset] = (linedata[offset] & 63); \ 619: } 620: 1.1.1.2 ! root 621: #define LINEDATASPR(offset, value, palette, priority) \ 1.1 root 622: if (value) { \ 1.1.1.2 ! root 623: if (outdata[offset] < 62) \ 1.1 root 624: vdp_collision = 1; \ 1.1.1.2 ! root 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; 1.1 root 639: 1.1.1.2 ! root 640: void vdp_sprites(unsigned int line, uint8 *pridata, uint8 *outdata) 1.1 root 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) { 1.1.1.2 ! root 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: } 1.1 root 702: } else { 1.1.1.2 ! root 703: /* higest priority sprite, so mask */ ! 704: plotter = 0; 1.1 root 705: } 706: si[i].hplot = 0; 707: } 1.1.1.2 ! root 708: if (si[i].hpos == -127) { ! 709: LOG_VERBOSE(("Warning: Use of hpos = 1 in plotter")); ! 710: plotter = 1; ! 711: } 1.1 root 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; 1.1.1.2 ! root 730: uint8 priority; 1.1 root 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; 1.1.1.2 ! root 745: priority = (cellinfo >> 15) & 1; 1.1 root 746: 1.1.1.2 ! root 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; 1.1 root 814: } 815: } 816: } 817: } 818: 1.1.1.2 ! root 819: inline void vdp_spritelayer(unsigned int line, uint8 *spritedata, ! 820: uint8 *pridata, uint8 *linedata, ! 821: unsigned int priority) 1.1 root 822: { 823: int i; 824: 1.1.1.2 ! root 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: } 1.1 root 837: } 838: } 1.1.1.2 ! root 839: } else { ! 840: for (i = 0; i < 320; i++) { ! 841: if (pridata[i] == priority) { ! 842: if (spritedata[i]) { ! 843: linedata[i] = spritedata[i]; ! 844: } 1.1 root 845: } 846: } 1.1.1.2 ! root 847: } 1.1 root 848: } 849: 850: /* layer 0 = A (top), layer 1 = B (bottom) */ 851: 1.1.1.2 ! root 852: void vdp_newlayer(unsigned int line, uint8 *pridata, uint8 *outdata, ! 853: unsigned int layer) 1.1 root 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) : 1.1.1.2 ! root 861: ((vdp_reg[2] & (7<<3)) << 10)); 1.1 root 862: uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset); 863: uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10) 1.1.1.2 ! root 864: + vdp_vram + layer*2); 1.1 root 865: uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32; 1.1.1.2 ! root 866: uint16 hwidth, vwidth, vmask, hoffset, voffset; 1.1 root 867: uint16 cellinfo; 868: uint8 *pattern; 869: uint32 data; 870: uint8 palette; 871: uint8 pixel; 872: uint8 topbottom, leftright, winhpos, winvpos; 1.1.1.2 ! root 873: uint8 priority; ! 874: int interlace = (vdp_reg[12] >> 1) & 3; ! 875: int realline = interlace ? line >> 1 : line; ! 876: ! 877: /* do window vertical check */ 1.1 root 878: 879: if (layer == 0) { 880: /* turn off A when window is on */ 881: topbottom = vdp_reg[18] & 0x80; 882: leftright = vdp_reg[17] & 0x80; 883: winhpos = vdp_reg[17] & 0x1f; 884: winvpos = vdp_reg[18] & 0x1f; 885: /* Battle Tank sets winvpos to 1F and expects layer A to be off */ 886: if (topbottom && winvpos != 0x1F) { 1.1.1.2 ! root 887: if ((realline >> 3) >= winvpos) ! 888: return; 1.1 root 889: } else { 1.1.1.2 ! root 890: if ((realline >> 3) < winvpos) ! 891: return; 1.1 root 892: } 893: } 894: 1.1.1.2 ! root 895: /* isn't this bug fixed now? */ 1.1 root 896: /* BUG: layer A is still displayed left/right when window is on, 897: only apparent with high-priority layer A and low-priority window */ 898: 1.1.1.2 ! root 899: /* select horizontal scrolling offset based on mode */ ! 900: 1.1 root 901: switch(hmode) { 902: case 0: /* full screen */ 903: hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF; 904: break; 905: case 2: /* cell scroll */ 1.1.1.2 ! root 906: hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(realline & ~7)])) & 0x3FF; 1.1 root 907: break; 908: case 3: /* line scroll */ 1.1.1.2 ! root 909: hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*realline])) & 0x3FF; 1.1 root 910: break; 911: default: 912: LOG_NORMAL(("prohibited HSCR/LSCR")); 913: hoffset = 0; 914: break; 915: } 1.1.1.2 ! root 916: hwidth = (hsize+1) << 5; ! 917: vwidth = ((vsize+1) << 5) * (interlace ? 2 : 1); ! 918: vmask = (vwidth << 3) - 1; /* to put offsets into range */ ! 919: hoffset&= (hwidth << 3)-1; /* put offset in range */ ! 920: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & vmask; ! 921: cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+ ! 922: hwidth*((voffset>>3)>>(interlace ? 1 : 0))]); ! 923: /* 32 bytes per pattern or 64 in interlace mode */ ! 924: pattern = vdp_vram + (((cellinfo & 2047)<<5) << (interlace ? 1 : 0)); ! 925: /* now get correct line from pattern data */ ! 926: switch (interlace) { ! 927: case 0: /* no interlace */ ! 928: case 1: /* ?? */ ! 929: case 2: /* ?? */ 1.1 root 930: if (cellinfo & 1<<12) { 931: /* vertical flip */ 932: pattern+= 4*(7-(voffset & 7)); 933: } else { 934: /* no vertical flip */ 935: pattern+= 4*(voffset & 7); 936: } 1.1.1.2 ! root 937: break; ! 938: case 3: /* interlace with double height cells */ ! 939: if (cellinfo & 1<<12) { ! 940: /* vertical flip */ ! 941: pattern+= 4*(15-(voffset & 15)); 1.1 root 942: } else { 1.1.1.2 ! root 943: /* no vertical flip */ ! 944: pattern+= 4*(voffset & 15); 1.1 root 945: } 1.1.1.2 ! root 946: break; 1.1 root 947: } 1.1.1.2 ! root 948: priority = (cellinfo >> 15) & 1; ! 949: palette = (cellinfo >> 13) & 3; ! 950: data = LOCENDIAN32(*(uint32 *)pattern); ! 951: if (cellinfo & 1<<11) { ! 952: /* horizontal flip */ ! 953: data>>= (hoffset & 7)*4; /* get first pixel in bottom 4 bits */ ! 954: for (i = 0; i < 8-(hoffset & 7); i++) { ! 955: pixel = data & 15; ! 956: LINEDATALAYER(i, pixel, palette, priority); ! 957: data>>= 4; ! 958: } ! 959: } else { ! 960: data<<= (hoffset & 7)*4; /* get first pixel in top 4 bits */ ! 961: for (i = 0; i < 8-(hoffset & 7); i++) { ! 962: pixel = (data>>28) & 15; ! 963: LINEDATALAYER(i, pixel, palette, priority); ! 964: data<<= 4; ! 965: } ! 966: } ! 967: outdata+= 8-(hoffset & 7); ! 968: pridata+= 8-(hoffset & 7); 1.1 root 969: hoffset+= 8; 970: hoffset&= (hwidth*8)-1; /* put offset in range */ 971: for (j = 1; j < screencells; j++) { 972: if (vmode) { 973: /* 2-cell scroll */ 974: /* DEBUG DEBUG DEBUG awooga awooga */ 975: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram) 1.1.1.2 ! root 976: [(j&~1)+layer] )) & vmask; 1.1 root 977: } else { 978: /* full screen */ 1.1.1.2 ! root 979: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & vmask; 1.1 root 980: } 1.1.1.2 ! root 981: cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+ ! 982: hwidth*((voffset>>3)>>(interlace ? 1 : 0))]); ! 983: priority = (cellinfo >> 15) & 1; 1.1 root 984: /* printf("hoff: %04X voff: %04X hwid: %04X cell: %08X info: %04X\n", 1.1.1.2 ! root 985: hoffset, voffset, hwidth, (hoffset>>3)+hwidth*(voffset>>3), ! 986: cellinfo); */ 1.1 root 987: /* printf("loc %08X cellinfo %08X\n", 1.1.1.2 ! root 988: (hoffset>>3)+hwidth*(voffset>>3), ! 989: cellinfo); */ ! 990: palette = (cellinfo >> 13) & 3; ! 991: /* 32 bytes per pattern or 64 in interlace mode */ ! 992: pattern = vdp_vram + (((cellinfo & 2047)<<5) << (interlace ? 1 : 0)); ! 993: /* now get correct line from pattern data */ ! 994: switch (interlace) { ! 995: case 0: /* no interlace */ ! 996: case 1: /* ?? */ ! 997: case 2: /* ?? */ 1.1 root 998: if (cellinfo & 1<<12) { 1.1.1.2 ! root 999: /* vertical flip */ ! 1000: pattern+= 4*(7-(voffset & 7)); 1.1 root 1001: } else { 1.1.1.2 ! root 1002: /* no vertical flip */ ! 1003: pattern+= 4*(voffset & 7); 1.1 root 1004: } 1.1.1.2 ! root 1005: break; ! 1006: case 3: /* interlace with double height cells */ ! 1007: if (cellinfo & 1<<12) { ! 1008: /* vertical flip */ ! 1009: pattern+= 4*(15-(voffset & 15)); 1.1 root 1010: } else { 1.1.1.2 ! root 1011: /* no vertical flip */ ! 1012: pattern+= 4*(voffset & 15); 1.1 root 1013: } 1.1.1.2 ! root 1014: break; 1.1 root 1015: } 1.1.1.2 ! root 1016: data = LOCENDIAN32(*(uint32 *)pattern); ! 1017: if (cellinfo & 1<<11) { ! 1018: /* horizontal flip */ ! 1019: for (i = 0; i < 8; i++) { ! 1020: pixel = data & 15; ! 1021: LINEDATALAYER(i, pixel, palette, priority); ! 1022: data>>= 4; ! 1023: } ! 1024: } else { ! 1025: for (i = 0; i < 8; i++) { ! 1026: pixel = (data>>28) & 15; ! 1027: LINEDATALAYER(i, pixel, palette, priority); ! 1028: data<<= 4; ! 1029: } ! 1030: } ! 1031: outdata+= 8; ! 1032: pridata+= 8; 1.1 root 1033: hoffset+= 8; 1034: hoffset&= (hwidth*8)-1; /* put offset in range */ 1035: } 1036: if (hoffset & 7) { 1037: if (vmode) { 1038: /* 2-cell scroll - note use last offset, not next */ 1039: /* DEBUG DEBUG DEBUG awooga awooga */ 1040: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram) 1.1.1.2 ! root 1041: [(screencells-2)+layer] )) & vmask; 1.1 root 1042: } else { 1043: /* full screen */ 1.1.1.2 ! root 1044: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & vmask; ! 1045: } ! 1046: cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+ ! 1047: hwidth*((voffset>>3)>>(interlace ? 1 : 0))]); ! 1048: priority = (cellinfo >> 15) & 1; ! 1049: palette = (cellinfo >> 13) & 3; ! 1050: /* 32 bytes per pattern or 64 in interlace mode */ ! 1051: pattern = vdp_vram + (((cellinfo & 2047)<<5) << (interlace ? 1 : 0)); ! 1052: /* now get correct line from pattern data */ ! 1053: switch (interlace) { ! 1054: case 0: /* no interlace */ ! 1055: case 1: /* ?? */ ! 1056: case 2: /* ?? */ ! 1057: if (cellinfo & 1<<12) { ! 1058: /* vertical flip */ ! 1059: pattern+= 4*(7-(voffset & 7)); ! 1060: } else { ! 1061: /* no vertical flip */ ! 1062: pattern+= 4*(voffset & 7); ! 1063: } ! 1064: break; ! 1065: case 3: /* interlace with double height cells */ ! 1066: if (cellinfo & 1<<12) { ! 1067: /* vertical flip */ ! 1068: pattern+= 4*(15-(voffset & 15)); ! 1069: } else { ! 1070: /* no vertical flip */ ! 1071: pattern+= 4*(voffset & 15); ! 1072: } ! 1073: break; ! 1074: } ! 1075: data = LOCENDIAN32(*(uint32 *)pattern); ! 1076: if (cellinfo & 1<<11) { ! 1077: /* horizontal flip */ ! 1078: for (i = 0; i < (hoffset & 7); i++) { ! 1079: pixel = data & 15; ! 1080: LINEDATALAYER(i, pixel, palette, priority); ! 1081: data>>= 4; ! 1082: } ! 1083: } else { ! 1084: for (i = 0; i < (hoffset & 7); i++) { ! 1085: pixel = (data>>28) & 15; ! 1086: LINEDATALAYER(i, pixel, palette, priority); ! 1087: data<<= 4; ! 1088: } ! 1089: } ! 1090: } ! 1091: } ! 1092: ! 1093: /* this function updates outdata/pridata which came from the layerA generation ! 1094: routines */ ! 1095: ! 1096: void vdp_newwindow(unsigned int line, uint8 *pridata, uint8 *outdata) ! 1097: { ! 1098: uint16 *patterndata = (uint16 *)(vdp_vram + ((vdp_reg[3] & 0x3e) << 10)); ! 1099: uint8 winhpos = vdp_reg[17] & 0x1f; ! 1100: uint8 winvpos = vdp_reg[18] & 0x1f; ! 1101: uint8 vcell = line / 8; ! 1102: uint8 hcell; ! 1103: uint8 voffset = line & 7; ! 1104: uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32; ! 1105: uint8 topbottom = vdp_reg[18] & 0x80; ! 1106: uint8 leftright = vdp_reg[17] & 0x80; ! 1107: uint8 patternshift = (vdp_reg[12] & 1) ? 6 : 5; ! 1108: uint16 cellinfo; ! 1109: uint8 *pattern; ! 1110: uint32 data; ! 1111: uint8 palette; ! 1112: uint8 pixel; ! 1113: unsigned int i; ! 1114: unsigned int wholeline = 0; ! 1115: uint8 priority; ! 1116: int layer = 0; /* for LINEDATALAYER macro */ ! 1117: ! 1118: if (vdp_reg[17] == 0 && vdp_reg[18] == 0) ! 1119: return; /* window is off */ ! 1120: ! 1121: /* Battle Tank sets winvpos to 0x80+0x1F and expects layer A to be off */ ! 1122: ! 1123: /* this section below is repeated in the main renderline code, so that ! 1124: layerA is not unnecessarily calculated */ ! 1125: if (topbottom ? (vcell >= winvpos) : (vcell < winvpos)) ! 1126: wholeline = 1; ! 1127: if (topbottom && winvpos == 0x1f) ! 1128: wholeline = 1; ! 1129: ! 1130: if (!wholeline) { ! 1131: if (winhpos >= 20) ! 1132: winhpos = 20; /* 0x1F might be special? */ ! 1133: if (leftright) { ! 1134: /* clear out priority bits on right of line (winhpos units of 16 pix */ ! 1135: for (i = winhpos*4; i < 320/4; i++) /* winhpos units of 16 pix */ ! 1136: ((uint32 *)pridata)[i]&= (0xffffffff - (0x01010101<<PRIBIT_LAYERA)); ! 1137: memset(outdata+winhpos*16, 0, 320-(winhpos*16)); ! 1138: } else { ! 1139: /* clear out priority bits on left of line (winhpos units of 16 pix) */ ! 1140: for (i = 0; i < (unsigned int)(winhpos/4); i++) ! 1141: ((uint32 *)pridata)[i]&= (0xffffffff - (0x01010101<<PRIBIT_LAYERA)); ! 1142: memset(outdata, 0, winhpos*16); ! 1143: } ! 1144: } ! 1145: for (hcell = 0; hcell < screencells; hcell++, outdata+=8, pridata+=8) { ! 1146: if (!wholeline) { ! 1147: if (leftright) { ! 1148: if ((hcell>>1) < winhpos) ! 1149: continue; ! 1150: } else { ! 1151: if ((hcell>>1) >= winhpos) ! 1152: continue; ! 1153: } ! 1154: } ! 1155: cellinfo = LOCENDIAN16(patterndata[vcell<<patternshift | hcell]); ! 1156: priority = (cellinfo >> 15) & 1; ! 1157: palette = (cellinfo >> 13) & 3; ! 1158: /* 32 bytes per pattern */ ! 1159: pattern = vdp_vram + ((cellinfo & 2047)<<5); /* fix for interlace */ ! 1160: if (cellinfo & 1<<12) { ! 1161: /* vertical flip */ ! 1162: pattern+= 4*(7-(voffset & 7)); ! 1163: } else { ! 1164: /* no vertical flip */ ! 1165: pattern+= 4*(voffset & 7); ! 1166: } ! 1167: data = LOCENDIAN32(*(uint32 *)pattern); ! 1168: if (cellinfo & 1<<11) { ! 1169: /* horizontal flip */ ! 1170: for (i = 0; i < 8; i++) { ! 1171: pixel = data & 15; ! 1172: LINEDATALAYER(i, pixel, palette, priority); ! 1173: data>>= 4; ! 1174: } ! 1175: } else { ! 1176: for (i = 0; i < 8; i++) { ! 1177: pixel = (data>>28) & 15; ! 1178: LINEDATALAYER(i, pixel, palette, priority); ! 1179: data<<= 4; ! 1180: } ! 1181: } ! 1182: } /* hcell */ ! 1183: } ! 1184: ! 1185: inline void vdp_shadow(unsigned int line, uint8 *linedata) ! 1186: { ! 1187: int i; ! 1188: ! 1189: /* this could be done 4 bytes at a time */ ! 1190: for (i = 0; i < 320; i++) ! 1191: linedata[i] = (linedata[i] & 63) + 128; ! 1192: } ! 1193: ! 1194: void vdp_window(unsigned int line, unsigned int priority, uint8 *linedata) ! 1195: { ! 1196: uint16 *patterndata = (uint16 *)(vdp_vram + ((vdp_reg[3] & 0x3e) << 10)); ! 1197: uint8 winhpos = vdp_reg[17] & 0x1f; ! 1198: uint8 winvpos = vdp_reg[18] & 0x1f; ! 1199: uint8 vcell = line / 8; ! 1200: uint8 hcell; ! 1201: uint8 voffset = line & 7; ! 1202: uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32; ! 1203: uint8 topbottom = vdp_reg[18] & 0x80; ! 1204: uint8 leftright = vdp_reg[17] & 0x80; ! 1205: uint8 patternshift = (vdp_reg[12] & 1) ? 6 : 5; ! 1206: uint16 cellinfo; ! 1207: uint8 *pattern; ! 1208: uint32 data; ! 1209: uint8 palette; ! 1210: uint8 pixel; ! 1211: unsigned int i; ! 1212: unsigned int wholeline = 0; ! 1213: ! 1214: if (topbottom) { ! 1215: /* bottom part */ ! 1216: /* Battle Tank sets winvpos to 0x1F and expects layer A to be off */ ! 1217: if (winvpos == 0x1F || vcell >= winvpos) ! 1218: wholeline = 1; ! 1219: } else { ! 1220: /* top part */ ! 1221: if (vcell < winvpos) ! 1222: wholeline = 1; ! 1223: } ! 1224: for (hcell = 0; hcell < screencells; hcell++, linedata+=8) { ! 1225: if (!wholeline) { ! 1226: if (leftright) { ! 1227: if ((hcell>>1) < winhpos) ! 1228: continue; ! 1229: } else { ! 1230: if ((hcell>>1) >= winhpos) ! 1231: continue; ! 1232: } 1.1 root 1233: } 1.1.1.2 ! root 1234: cellinfo = LOCENDIAN16(patterndata[vcell<<patternshift | hcell]); 1.1 root 1235: if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) { 1236: palette = (cellinfo >> 13) & 3; 1237: pattern = vdp_vram + ((cellinfo & 2047)<<5); /* 32 bytes per pattern */ 1238: if (cellinfo & 1<<12) { 1.1.1.2 ! root 1239: /* vertical flip */ ! 1240: pattern+= 4*(7-(voffset & 7)); 1.1 root 1241: } else { 1.1.1.2 ! root 1242: /* no vertical flip */ ! 1243: pattern+= 4*(voffset & 7); 1.1 root 1244: } 1245: data = LOCENDIAN32(*(uint32 *)pattern); 1246: if (cellinfo & 1<<11) { 1.1.1.2 ! root 1247: /* horizontal flip */ ! 1248: for (i = 0; i < 8; i++) { ! 1249: pixel = data & 15; ! 1250: LINEDATA(i, pixel, palette, priority); ! 1251: data>>= 4; ! 1252: } 1.1 root 1253: } else { 1.1.1.2 ! root 1254: for (i = 0; i < 8; i++) { ! 1255: pixel = (data>>28) & 15; ! 1256: LINEDATA(i, pixel, palette, priority); ! 1257: data<<= 4; ! 1258: } 1.1 root 1259: } 1260: } 1.1.1.2 ! root 1261: } /* hcell */ 1.1 root 1262: } 1263: 1264: void vdp_layer_interlace(unsigned int line, unsigned int layer, 1.1.1.2 ! root 1265: unsigned int priority, uint8 *linedata) 1.1 root 1266: { 1267: int i, j; 1268: uint8 hsize = vdp_reg[16] & 3; 1269: uint8 vsize = (vdp_reg[16] >> 4) & 3; 1270: uint8 hmode = vdp_reg[11] & 3; 1271: uint8 vmode = (vdp_reg[11] >> 2) & 1; 1272: uint16 vramoffset = (layer ? ((vdp_reg[4] & 7) << 13) : 1.1.1.2 ! root 1273: ((vdp_reg[2] & (7<<3)) << 10)); 1.1 root 1274: uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset); 1275: uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10) 1.1.1.2 ! root 1276: + vdp_vram + layer*2); 1.1 root 1277: uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32; 1278: uint16 hwidth, vwidth, hoffset, voffset; 1279: uint16 cellinfo; 1280: uint8 *pattern; 1281: uint32 data; 1282: uint8 palette; 1283: uint8 pixel; 1284: uint8 topbottom, leftright, winhpos, winvpos; 1285: 1286: if (layer == 0) { 1287: /* turn off A when window is on */ 1288: topbottom = vdp_reg[18] & 0x80; 1289: leftright = vdp_reg[17] & 0x80; 1290: winhpos = vdp_reg[17] & 0x1f; 1291: winvpos = vdp_reg[18] & 0x1f; 1292: if (topbottom) { 1293: if ((line>>4) >= winvpos) 1.1.1.2 ! root 1294: return; 1.1 root 1295: } else { 1296: if ((line>>4) < winvpos) 1.1.1.2 ! root 1297: return; 1.1 root 1298: } 1299: } 1300: 1301: /* BUG: layer A is still displayed left/right when window is on, 1302: only apparent with high-priority layer A and low-priority window */ 1303: 1304: switch(hmode) { 1305: case 0: /* full screen */ 1306: hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF; 1307: break; 1308: case 2: /* cell scroll */ 1309: /* interlace we use the actual line for the hscroll */ 1310: hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*((line>>1) & ~7)])) & 0x3FF; 1311: break; 1312: case 3: /* line scroll */ 1313: /* interlace we use the actual line for the hscroll */ 1314: hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(line>>1)])) & 0x3FF; 1315: break; 1316: default: 1317: LOG_NORMAL(("prohibited HSCR/LSCR")); 1318: hoffset = 0; 1319: break; 1320: } 1321: hwidth = 32+hsize*32; 1322: vwidth = 32+vsize*32; 1323: hoffset&= (hwidth*8)-1; /* put offset in range */ 1324: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF; 1325: voffset&= (vwidth*16)-1; /* put offset in range */ 1326: 1327: cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]); 1328: if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) { 1329: palette = (cellinfo >> 13) & 3; 1330: pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */ 1331: if (cellinfo & 1<<12) { 1332: /* vertical flip */ 1333: pattern+= 4*(15-(voffset & 15)); 1334: } else { 1335: /* no vertical flip */ 1336: pattern+= 4*(voffset & 15); 1337: } 1338: data = LOCENDIAN32(*(uint32 *)pattern); 1339: if (cellinfo & 1<<11) { 1340: /* horizontal flip */ 1341: data>>= (hoffset & 7)*4; /* get first pixel in bottom 4 bits */ 1342: for (i = 0; i < 8-(hoffset & 7); i++) { 1.1.1.2 ! root 1343: pixel = data & 15; ! 1344: LINEDATA(i, pixel, palette, priority); ! 1345: data>>= 4; 1.1 root 1346: } 1347: } else { 1348: data<<= (hoffset & 7)*4; /* get first pixel in top 4 bits */ 1349: for (i = 0; i < 8-(hoffset & 7); i++) { 1.1.1.2 ! root 1350: pixel = (data>>28) & 15; ! 1351: LINEDATA(i, pixel, palette, priority); ! 1352: data<<= 4; 1.1 root 1353: } 1354: } 1355: } 1356: linedata+= 8-(hoffset & 7); 1357: hoffset+= 8; 1358: hoffset&= (hwidth*8)-1; /* put offset in range */ 1359: for (j = 0; j < screencells-1; j++) { 1360: if (vmode) { 1361: /* 2-cell scroll */ 1362: /* DEBUG DEBUG DEBUG awooga awooga */ 1363: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram) 1.1.1.2 ! root 1364: [2*(j>>1)+layer] )) & 0x7FF; 1.1 root 1365: } else { 1366: /* full screen */ 1367: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF; 1368: } 1369: voffset&= (vwidth*16)-1; /* put offset in range */ 1370: cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]); 1371: /* printf("hoff: %04X voff: %04X hwid: %04X cell: %08X info: %04X\n", 1.1.1.2 ! root 1372: hoffset, voffset, hwidth, (hoffset>>3)+hwidth*(voffset>>4), ! 1373: cellinfo); */ 1.1 root 1374: /* printf("loc %08X cellinfo %08X\n", 1.1.1.2 ! root 1375: (hoffset>>3)+hwidth*(voffset>>4), ! 1376: cellinfo); */ 1.1 root 1377: if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) { 1378: palette = (cellinfo >> 13) & 3; 1379: pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */ 1380: if (cellinfo & 1<<12) { 1.1.1.2 ! root 1381: /* vertical flip */ ! 1382: pattern+= 4*(15-(voffset & 15)); 1.1 root 1383: } else { 1.1.1.2 ! root 1384: /* no vertical flip */ ! 1385: pattern+= 4*(voffset & 15); 1.1 root 1386: } 1387: data = LOCENDIAN32(*(uint32 *)pattern); 1388: if (cellinfo & 1<<11) { 1.1.1.2 ! root 1389: /* horizontal flip */ ! 1390: for (i = 0; i < 8; i++) { ! 1391: pixel = data & 15; ! 1392: LINEDATA(i, pixel, palette, priority); ! 1393: data>>= 4; ! 1394: } 1.1 root 1395: } else { 1.1.1.2 ! root 1396: for (i = 0; i < 8; i++) { ! 1397: pixel = (data>>28) & 15; ! 1398: LINEDATA(i, pixel, palette, priority); ! 1399: data<<= 4; ! 1400: } 1.1 root 1401: } 1402: } 1403: linedata+= 8; 1404: hoffset+= 8; 1405: hoffset&= (hwidth*8)-1; /* put offset in range */ 1406: } 1407: if (hoffset & 7) { 1408: if (vmode) { 1409: /* 2-cell scroll - note use last offset, not next */ 1410: /* DEBUG DEBUG DEBUG awooga awooga */ 1411: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram) 1.1.1.2 ! root 1412: [2*(j>>1)+layer] )) & 0x7FF; 1.1 root 1413: } else { 1414: /* full screen */ 1415: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x7FF; 1416: } 1417: voffset&= (vwidth*16)-1; /* put offset in range */ 1418: cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>4)]); 1419: if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) { 1420: palette = (cellinfo >> 13) & 3; 1421: pattern = vdp_vram + ((cellinfo & 2047)<<6); /* 64 bytes per pattern */ 1422: if (cellinfo & 1<<12) { 1.1.1.2 ! root 1423: /* vertical flip */ ! 1424: pattern+= 4*(15-(voffset & 15)); 1.1 root 1425: } else { 1.1.1.2 ! root 1426: /* no vertical flip */ ! 1427: pattern+= 4*(voffset & 15); 1.1 root 1428: } 1429: data = LOCENDIAN32(*(uint32 *)pattern); 1430: if (cellinfo & 1<<11) { 1.1.1.2 ! root 1431: /* horizontal flip */ ! 1432: for (i = 0; i < (hoffset & 7); i++) { ! 1433: pixel = data & 15; ! 1434: LINEDATA(i, pixel, palette, priority); ! 1435: data>>= 4; ! 1436: } 1.1 root 1437: } else { 1.1.1.2 ! root 1438: for (i = 0; i < (hoffset & 7); i++) { ! 1439: pixel = (data>>28) & 15; ! 1440: LINEDATA(i, pixel, palette, priority); ! 1441: data<<= 4; ! 1442: } 1.1 root 1443: } 1444: } 1445: linedata+= 8; 1446: } 1447: } 1448: 1.1.1.2 ! root 1449: void vdp_renderline(unsigned int line, uint8 *linedata, unsigned int odd) 1.1 root 1450: { 1451: int i; 1.1.1.2 ! root 1452: uint8 datablock[320*4]; ! 1453: uint8 *data_sprite = datablock; ! 1454: uint8 *data_layerA = datablock + 320; ! 1455: uint8 *data_layerB = datablock + 320*2; ! 1456: uint8 *priorities = datablock + 320*3; ! 1457: uint8 bg = vdp_reg[7] & 63; ! 1458: unsigned int winvpos = vdp_reg[18] & 0x1f; ! 1459: int windowall; ! 1460: unsigned int interlace = (vdp_reg[12] >> 1) & 3; 1.1 root 1461: 1.1.1.2 ! root 1462: windowall = ((vdp_reg[18] & 0x80) ? (winvpos == 0x1f || (line/8) >= winvpos) ! 1463: : (line/8 < winvpos)); 1.1 root 1464: 1.1.1.2 ! root 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: } 1.1 root 1473: 1.1.1.2 ! root 1474: if (vdp_layerS || vdp_layerSp) ! 1475: vdp_sprites(interlace ? (line*2+odd) : line, priorities, data_sprite); ! 1476: if (vdp_layerA || vdp_layerAp) { ! 1477: if (!windowall) ! 1478: vdp_newlayer(interlace ? (line*2+odd) : line, priorities, data_layerA, 0); ! 1479: if (vdp_layerW || vdp_layerWp) ! 1480: vdp_newwindow(line, priorities, data_layerA); ! 1481: } ! 1482: if (vdp_layerB || vdp_layerBp) ! 1483: vdp_newlayer(interlace ? (line*2+odd) : line, priorities, data_layerB, 1); ! 1484: ! 1485: for (i = 0; i < 320; i++) { ! 1486: switch(priorities[i] | (vdp_reg[12] & 1<<3)) { ! 1487: case 0: /* s/ten=0, B=0, A=0, S=0 */ ! 1488: if (data_sprite[i]) ! 1489: linedata[i] = data_sprite[i]; ! 1490: else if (data_layerA[i]) ! 1491: linedata[i] = data_layerA[i]; ! 1492: else if (data_layerB[i]) ! 1493: linedata[i] = data_layerB[i]; ! 1494: else ! 1495: linedata[i] = bg; ! 1496: break; ! 1497: case 1: /* s/ten=0, B=1, A=0, S=0 */ ! 1498: if (data_layerB[i]) ! 1499: linedata[i] = data_layerB[i]; ! 1500: else if (data_sprite[i]) ! 1501: linedata[i] = data_sprite[i]; ! 1502: else if (data_layerA[i]) ! 1503: linedata[i] = data_layerA[i]; ! 1504: else ! 1505: linedata[i] = bg; ! 1506: break; ! 1507: case 2: /* s/ten=0, B=0, A=1, S=0 */ ! 1508: if (data_layerA[i]) ! 1509: linedata[i] = data_layerA[i]; ! 1510: else if (data_sprite[i]) ! 1511: linedata[i] = data_sprite[i]; ! 1512: else if (data_layerB[i]) ! 1513: linedata[i] = data_layerB[i]; ! 1514: else ! 1515: linedata[i] = bg; ! 1516: break; ! 1517: case 3: /* s/ten=0, B=1, A=1, S=0 */ ! 1518: if (data_layerA[i]) ! 1519: linedata[i] = data_layerA[i]; ! 1520: else if (data_layerB[i]) ! 1521: linedata[i] = data_layerB[i]; ! 1522: else if (data_sprite[i]) ! 1523: linedata[i] = data_sprite[i]; ! 1524: else ! 1525: linedata[i] = bg; ! 1526: break; ! 1527: case 4: /* s/ten=0, B=0, A=0, S=1 */ ! 1528: if (data_sprite[i]) ! 1529: linedata[i] = data_sprite[i]; ! 1530: else if (data_layerA[i]) ! 1531: linedata[i] = data_layerA[i]; ! 1532: else if (data_layerB[i]) ! 1533: linedata[i] = data_layerB[i]; ! 1534: else ! 1535: linedata[i] = bg; ! 1536: break; ! 1537: case 5: /* s/ten=0, B=1, A=0, S=1 */ ! 1538: if (data_sprite[i]) ! 1539: linedata[i] = data_sprite[i]; ! 1540: else if (data_layerB[i]) ! 1541: linedata[i] = data_layerB[i]; ! 1542: else if (data_layerA[i]) ! 1543: linedata[i] = data_layerA[i]; ! 1544: else ! 1545: linedata[i] = bg; ! 1546: break; ! 1547: case 6: /* s/ten=0, B=0, A=1, S=1 */ ! 1548: if (data_sprite[i]) ! 1549: linedata[i] = data_sprite[i]; ! 1550: else if (data_layerA[i]) ! 1551: linedata[i] = data_layerA[i]; ! 1552: else if (data_layerB[i]) ! 1553: linedata[i] = data_layerB[i]; ! 1554: else ! 1555: linedata[i] = bg; ! 1556: break; ! 1557: case 7: /* s/ten=0, B=1, A=1, S=1 */ ! 1558: if (data_sprite[i]) ! 1559: linedata[i] = data_sprite[i]; ! 1560: else if (data_layerA[i]) ! 1561: linedata[i] = data_layerA[i]; ! 1562: else if (data_layerB[i]) ! 1563: linedata[i] = data_layerB[i]; ! 1564: else ! 1565: linedata[i] = bg; ! 1566: break; ! 1567: case 8: /* s/ten=1, B=0, A=0, S=0 */ ! 1568: if (data_sprite[i]) { ! 1569: if (data_sprite[i] == 63) { /* shadow operator */ ! 1570: if (data_layerA[i]) ! 1571: linedata[i] = data_layerA[i] | 128; /* shadow */ ! 1572: else if (data_layerB[i]) ! 1573: linedata[i] = data_layerB[i] | 128; /* shadow */ ! 1574: else ! 1575: linedata[i] = bg | 128; /* shadow */ ! 1576: } else if (data_sprite[i] == 62) { /* highlight operator */ ! 1577: if (data_layerA[i]) ! 1578: linedata[i] = data_layerA[i]; /* normal */ ! 1579: else if (data_layerB[i]) ! 1580: linedata[i] = data_layerB[i]; /* normal */ ! 1581: else ! 1582: linedata[i] = bg; /* normal */ ! 1583: } else { ! 1584: linedata[i] = data_sprite[i] | 128; /* shadow */ ! 1585: } ! 1586: } else { ! 1587: if (data_layerA[i]) ! 1588: linedata[i] = data_layerA[i] | 128; /* shadow */ ! 1589: else if (data_layerB[i]) ! 1590: linedata[i] = data_layerB[i] | 128; /* shadow */ ! 1591: else ! 1592: linedata[i] = bg | 128; /* shadow */ ! 1593: } ! 1594: break; ! 1595: case 9: /* s/ten=1, B=1, A=0, S=0 */ ! 1596: if (data_layerB[i]) { ! 1597: linedata[i] = data_layerB[i]; /* normal */ ! 1598: } else { ! 1599: if (data_sprite[i]) { ! 1600: if (data_sprite[i] == 63) { /* shadow operator */ ! 1601: if (data_layerA[i]) ! 1602: linedata[i] = data_layerA[i] | 128; /* shadow */ ! 1603: else ! 1604: linedata[i] = bg | 128; /* shadow */ ! 1605: } else if (data_sprite[i] == 62) { /* highlight operator */ ! 1606: if (data_layerA[i]) ! 1607: linedata[i] = data_layerA[i] | 64; /* highlight */ ! 1608: else ! 1609: linedata[i] = bg | 64; /* highlight */ ! 1610: } else { ! 1611: linedata[i] = data_sprite[i]; /* normal */ ! 1612: } ! 1613: } else { ! 1614: if (data_layerA[i]) ! 1615: linedata[i] = data_layerA[i]; /* normal */ ! 1616: else ! 1617: linedata[i] = bg; /* normal */ ! 1618: } ! 1619: } ! 1620: break; ! 1621: case 10: /* s/ten=1, B=0, A=1, S=0 */ ! 1622: if (data_layerA[i]) { ! 1623: linedata[i] = data_layerA[i]; /* normal */ ! 1624: } else { ! 1625: if (data_sprite[i]) { ! 1626: if (data_sprite[i] == 63) { /* shadow operator */ ! 1627: if (data_layerB[i]) ! 1628: linedata[i] = data_layerB[i] | 128; /* shadow */ ! 1629: else ! 1630: linedata[i] = bg | 128; /* shadow */ ! 1631: } else if (data_sprite[i] == 62) { /* highlight operator */ ! 1632: if (data_layerB[i]) ! 1633: linedata[i] = data_layerB[i] | 64; /* highlight */ ! 1634: else ! 1635: linedata[i] = bg | 64; /* highlight */ ! 1636: } else { ! 1637: linedata[i] = data_sprite[i]; /* normal */ ! 1638: } ! 1639: } else { ! 1640: if (data_layerB[i]) ! 1641: linedata[i] = data_layerB[i]; /* normal */ ! 1642: else ! 1643: linedata[i] = bg; /* normal */ ! 1644: } ! 1645: } ! 1646: break; ! 1647: case 11: /* s/ten=1, B=1, A=1, S=0 */ ! 1648: if (data_layerA[i]) { ! 1649: linedata[i] = data_layerA[i]; /* normal */ ! 1650: } else if (data_layerB[i]) { ! 1651: linedata[i] = data_layerB[i]; /* normal */ ! 1652: } else if (data_sprite[i]) { ! 1653: if (data_sprite[i] == 63) /* shadow operator */ ! 1654: linedata[i] = bg | 128; /* shadow */ ! 1655: else if (data_sprite[i] == 62) /* highlight operator */ ! 1656: linedata[i] = bg | 64; /* highlight */ ! 1657: else ! 1658: linedata[i] = data_sprite[i]; /* normal */ ! 1659: } else { ! 1660: linedata[i] = bg; /* normal */ ! 1661: } ! 1662: break; ! 1663: case 12: /* s/ten=0, B=0, A=0, S=1 */ ! 1664: if (data_sprite[i]) { ! 1665: if (data_sprite[i] == 63) { /* shadow operator */ ! 1666: if (data_layerA[i]) ! 1667: linedata[i] = data_layerA[i] | 128; /* shadow */ ! 1668: else if (data_layerB[i]) ! 1669: linedata[i] = data_layerB[i] | 128; /* shadow */ ! 1670: else ! 1671: linedata[i] = bg | 128; /* shadow */ ! 1672: } else if (data_sprite[i] == 62) { /* highlight operator */ ! 1673: if (data_layerA[i]) ! 1674: linedata[i] = data_layerA[i]; /* normal */ ! 1675: else if (data_layerB[i]) ! 1676: linedata[i] = data_layerB[i]; /* normal */ ! 1677: else ! 1678: linedata[i] = bg; /* normal */ ! 1679: } else { ! 1680: linedata[i] = data_sprite[i]; /* normal */ ! 1681: } ! 1682: } else if (data_layerA[i]) { ! 1683: linedata[i] = data_layerA[i] | 128; /* shadow */ ! 1684: } else if (data_layerB[i]) { ! 1685: linedata[i] = data_layerB[i] | 128; /* shadow */ ! 1686: } else { ! 1687: linedata[i] = bg | 128; /* shadow */ ! 1688: } ! 1689: break; ! 1690: case 13: /* s/ten=1, B=1, A=0, S=1 */ ! 1691: if (data_sprite[i]) { ! 1692: if (data_sprite[i] == 63) { /* shadow operator */ ! 1693: if (data_layerB[i]) ! 1694: linedata[i] = data_layerB[i] | 128; /* shadow */ ! 1695: else if (data_layerA[i]) ! 1696: linedata[i] = data_layerA[i] | 128; /* shadow */ ! 1697: else ! 1698: linedata[i] = bg | 128; /* shadow */ ! 1699: } else if (data_sprite[i] == 62) { /* highlight operator */ ! 1700: if (data_layerB[i]) ! 1701: linedata[i] = data_layerB[i] | 64; /* highlight */ ! 1702: else if (data_layerA[i]) ! 1703: linedata[i] = data_layerA[i] | 64; /* highlight */ ! 1704: else ! 1705: linedata[i] = bg | 64; /* highlight */ ! 1706: } else { ! 1707: linedata[i] = data_sprite[i]; /* normal */ ! 1708: } ! 1709: } else if (data_layerB[i]) { ! 1710: linedata[i] = data_layerB[i]; /* normal */ ! 1711: } else if (data_layerA[i]) { ! 1712: linedata[i] = data_layerA[i]; /* normal */ ! 1713: } ! 1714: break; ! 1715: case 14: /* s/ten=1, B=0, A=1, S=1 */ ! 1716: if (data_sprite[i]) { ! 1717: if (data_sprite[i] == 63) { /* shadow operator */ ! 1718: if (data_layerA[i]) ! 1719: linedata[i] = data_layerA[i] | 128; /* shadow */ ! 1720: else if (data_layerB[i]) ! 1721: linedata[i] = data_layerB[i] | 128; /* shadow */ ! 1722: else ! 1723: linedata[i] = bg | 128; /* shadow */ ! 1724: } else if (data_sprite[i] == 62) { /* highlight operator */ ! 1725: if (data_layerA[i]) ! 1726: linedata[i] = data_layerA[i] | 64; /* highlight */ ! 1727: else if (data_layerB[i]) ! 1728: linedata[i] = data_layerB[i] | 64; /* highlight */ ! 1729: else ! 1730: linedata[i] = bg | 64; /* highlight */ ! 1731: } else { ! 1732: linedata[i] = data_sprite[i]; /* normal */ ! 1733: } ! 1734: } else if (data_layerA[i]) { ! 1735: linedata[i] = data_layerA[i]; /* normal */ ! 1736: } else if (data_layerB[i]) { ! 1737: linedata[i] = data_layerB[i]; /* normal */ ! 1738: } ! 1739: break; ! 1740: case 15: /* s/ten=1, B=1, A=1, S=1 */ ! 1741: if (data_sprite[i]) { ! 1742: if (data_sprite[i] == 63) { /* shadow operator */ ! 1743: if (data_layerA[i]) ! 1744: linedata[i] = data_layerA[i] | 128; /* shadow */ ! 1745: else if (data_layerB[i]) ! 1746: linedata[i] = data_layerB[i] | 128; /* shadow */ ! 1747: else ! 1748: linedata[i] = bg | 128; /* shadow */ ! 1749: } else if (data_sprite[i] == 62) { /* highlight operator */ ! 1750: if (data_layerA[i]) ! 1751: linedata[i] = data_layerA[i] | 64; /* highlight */ ! 1752: else if (data_layerB[i]) ! 1753: linedata[i] = data_layerB[i] | 64; /* highlight */ ! 1754: else ! 1755: linedata[i] = bg | 64; /* highlight */ ! 1756: } else { ! 1757: linedata[i] = data_sprite[i]; /* normal */ ! 1758: } ! 1759: } else if (data_layerA[i]) { ! 1760: linedata[i] = data_layerA[i]; /* normal */ ! 1761: } else if (data_layerB[i]) { ! 1762: linedata[i] = data_layerB[i]; /* normal */ ! 1763: } ! 1764: break; ! 1765: } 1.1 root 1766: } 1767: } 1768: 1769: void vdp_renderline_interlace2(unsigned int line, uint8 *linedata) 1770: { 1771: int i; 1.1.1.2 ! root 1772: uint8 pridata[640]; ! 1773: uint8 *spritedata = pridata + 320; 1.1 root 1774: 1.1.1.2 ! root 1775: memset(pridata, 0, 640); ! 1776: memset(linedata, vdp_reg[7] & 63, 320); 1.1 root 1777: 1778: if (vdp_reg[1] & 1<<6) { 1.1.1.2 ! root 1779: vdp_sprites(line, pridata, spritedata); ! 1780: ; 1.1 root 1781: if (vdp_layerB) 1782: vdp_layer_interlace(line, 1, 0, linedata); 1783: if (vdp_layerA) 1784: vdp_layer_interlace(line, 0, 0, linedata); 1785: /* 1786: if (vdp_layerW) 1787: vdp_window(line, 0, linedata); 1788: */ 1789: if (vdp_layerH && (vdp_reg[12] & 1<<3)) 1790: vdp_shadow(line, linedata); 1.1.1.2 ! root 1791: if (vdp_layerS) ! 1792: vdp_spritelayer(line, spritedata, pridata, linedata, 0); 1.1 root 1793: if (vdp_layerBp) 1794: vdp_layer_interlace(line, 1, 1, linedata); 1795: if (vdp_layerAp) 1796: vdp_layer_interlace(line, 0, 1, linedata); 1797: /* 1798: if (vdp_layerWp) 1799: vdp_window(line, 1, linedata); 1800: */ 1801: if (vdp_layerSp) 1.1.1.2 ! root 1802: vdp_spritelayer(line, spritedata, pridata, linedata, 1); 1.1 root 1803: } 1804: } 1805: 1806: void vdp_renderframe(uint8 *framedata, unsigned int lineoffset) 1807: { 1808: unsigned int i, line; 1809: uint32 background; 1810: unsigned int vertcells = vdp_reg[1] & 1<<3 ? 30 : 28; 1811: uint8 *linedata; 1812: 1813: /* fill in background */ 1814: 1815: background = vdp_reg[7] & 63; 1816: background|= background<<8; 1817: background|= background<<16; 1818: 1819: for (line = 0; line < vertcells*8; line++) { 1820: linedata = framedata + line*lineoffset; 1821: for (i = 0; i < (320 / 4); i++) { 1822: ((uint32 *)linedata)[i] = background; 1823: } 1824: } 1825: 1826: if (vdp_reg[1] & 1<<6) { 1827: if (vdp_layerB) 1828: vdp_layer_simple(1, 0, framedata, lineoffset); 1829: if (vdp_layerA) 1830: vdp_layer_simple(0, 0, framedata, lineoffset); 1831: if (vdp_layerH && (vdp_reg[12] & 1<<3)) 1832: vdp_shadow_simple(framedata, lineoffset); 1.1.1.2 ! root 1833: if (vdp_layerS) ! 1834: vdp_sprites_simple(0, framedata, lineoffset); 1.1 root 1835: if (vdp_layerBp) 1836: vdp_layer_simple(1, 1, framedata, lineoffset); 1837: if (vdp_layerAp) 1838: vdp_layer_simple(0, 1, framedata, lineoffset); 1839: if (vdp_layerSp) 1840: vdp_sprites_simple(1, framedata, lineoffset); 1841: } 1842: } 1843: 1844: void vdp_showregs(void) 1845: { 1846: int i; 1847: 1848: for (i = 0; i < 25; i++) { 1849: printf("[%02d] %02X: ", i, vdp_reg[i]); 1850: switch(i) { 1851: case 0: 1852: printf("%s ", vdp_reg[0] & 1<<1 ? "HV-stop" : "HV-enable"); 1853: printf("%s ", vdp_reg[0] & 1<<4 ? "HInt-enable" : "HInt-disable"); 1854: break; 1855: case 1: 1856: printf("%s ", vdp_reg[1] & 1<<3 ? "30-cell" : "28-cell"); 1857: printf("%s ", vdp_reg[1] & 1<<4 ? "DMA-enable" : "DMA-disable"); 1858: printf("%s ", vdp_reg[1] & 1<<5 ? "VInt-enable" : "VInt-disable"); 1859: printf("%s ", vdp_reg[1] & 1<<6 ? "Disp-enable" : "Disp-disable"); 1860: break; 1861: case 2: 1862: printf("Scroll A @ %04X", (vdp_reg[2] & 0x38)<<10); 1863: break; 1864: case 3: 1865: printf("Window @ %04X", (vdp_reg[3] & 0x3E)<<10); 1866: break; 1867: case 4: 1868: printf("Scroll B @ %04X", (vdp_reg[4] & 7)<<13); 1869: break; 1870: case 5: 1871: printf("Sprites @ %04X", (vdp_reg[5] & 0x7F)<<9); 1872: break; 1873: case 7: 1874: printf("bgpal %d col %d", (vdp_reg[7]>>4 & 3), (vdp_reg[7] & 15)); 1875: break; 1876: case 10: 1877: printf("hintreg %04X", vdp_reg[10]); 1878: break; 1879: case 11: 1880: printf("V-mode %d H-mode %d ", (vdp_reg[11]>>2) & 1, (vdp_reg[11] & 3)); 1881: printf("%s", (vdp_reg[11] & 1<<3) ? "ExtInt-enable" : "ExtInt-disable"); 1882: break; 1883: case 12: 1884: printf("Interlace %d ", (vdp_reg[12]>>1) & 3); 1885: printf("%s ", (vdp_reg[12] & 1<<0) ? "40-cell" : "32-cell"); 1886: printf("%s ", (vdp_reg[12] & 1<<3) ? "Shadow-enable" : "Shadow-disable"); 1887: break; 1888: case 13: 1889: printf("Scroll A @ %04X", (vdp_reg[13] & 0x3F)<<10); 1890: break; 1891: case 15: 1892: printf("Autoinc %d", vdp_reg[15]); 1893: break; 1894: case 16: 1895: printf("Vsize %d Hsize %d", (vdp_reg[16]>>4) & 3, (vdp_reg[16] & 3)); 1896: break; 1897: case 17: 1898: printf("Window H %s ", (vdp_reg[17] & 1<<7) ? "right" : "left"); 1899: printf("%d", vdp_reg[17] & 0x1F); 1900: break; 1901: case 18: 1902: printf("Window V %s ", (vdp_reg[18] & 1<<7) ? "lower" : "upper"); 1903: printf("%d", vdp_reg[18] & 0x1F); 1904: break; 1905: case 19: 1906: printf("DMA-length-low %02X", vdp_reg[19]); 1907: break; 1908: case 20: 1909: printf("DMA-length-high %02X", vdp_reg[20]); 1910: break; 1911: case 21: 1912: printf("DMA-source-low %02X", vdp_reg[21]); 1913: break; 1914: case 22: 1915: printf("DMA-source-mid %02X", vdp_reg[22]); 1916: break; 1917: case 23: 1918: printf("DMA-source-high %02X", vdp_reg[23]); 1919: break; 1920: } 1921: printf("\n"); 1922: } 1923: } 1924: 1925: void vdp_spritelist(void) 1926: { 1927: uint8 *spritelist = vdp_vram + ((vdp_reg[5] & 0x7F)<<9); 1928: uint8 *sprite; 1929: uint8 link = 0; 1930: uint16 pattern; 1931: uint8 palette; 1932: uint16 cellinfo; 1933: sint16 vpos, hpos, vmax; 1934: uint8 vsize, hsize; 1935: 1936: LOG_REQUEST(("SPRITE DUMP: (base=vram+%X)", 1.1.1.2 ! root 1937: (vdp_reg[5] & 0x7f)<<9)); 1.1 root 1938: do { 1939: sprite = spritelist + (link<<3); 1940: hpos = (LOCENDIAN16(*(uint16 *)(sprite+6)) & 0x1FF) - 0x80; 1941: vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x3FF) - 0x80; 1942: vsize = 1+(sprite[2] & 3); 1943: hsize = 1+((sprite[2]>>2) & 3); 1944: cellinfo = LOCENDIAN16(*(uint16 *)(sprite+4)); 1945: pattern = cellinfo & 0x7FF; 1946: palette = (cellinfo >> 13) & 3; 1947: vmax = vpos + vsize*8; 1948: 1949: LOG_REQUEST(("Sprite %d @ %X", link, 1.1.1.2 ! root 1950: (link<<3) | (vdp_reg[5] & 0x7f)<<9)); 1.1 root 1951: LOG_REQUEST((" Pos: %d,%d", hpos, vpos)); 1952: LOG_REQUEST((" Size: %d,%d", hsize, vsize)); 1953: LOG_REQUEST((" Pri: %d, Pal: %d, Vflip: %d, Hflip: %d", 1.1.1.2 ! root 1954: (cellinfo>>15 & 1), (cellinfo>>13 & 3), (cellinfo>>12 & 1), ! 1955: (cellinfo>>11 & 1))); ! 1956: LOG_REQUEST((" Pattern: %d (%x) @ vram+%X (%X if interlaced)", ! 1957: (cellinfo & 0x7FF), (cellinfo & 0x7FF), ! 1958: (cellinfo & 0x7FF)*32, (cellinfo & 0x7FF)*32)); 1.1 root 1959: link = sprite[3] & 0x7F; 1960: } while (link); 1961: } 1962: 1963: void vdp_describe(void) 1964: { 1965: int layer; 1966: unsigned int line; 1967: uint32 o_patterndata, o_hscrolldata; 1968: uint16 *patterndata, *hscrolldata; 1969: uint8 hsize = vdp_reg[16] & 3; 1970: uint8 vsize = (vdp_reg[16] >> 4) & 3; 1971: uint8 hmode = vdp_reg[11] & 3; 1972: uint8 vmode = (vdp_reg[11] >> 2) & 1; 1973: uint16 hwidth, vwidth, hoffset, voffset, raw_hoffset; 1974: 1975: hwidth = 32+hsize*32; 1976: vwidth = 32+vsize*32; 1977: LOG_REQUEST(("VDP description:")); 1978: LOG_REQUEST((" hsize = %d (ie. width=%d)", hsize, hwidth)); 1979: LOG_REQUEST((" vsize = %d (ie. width=%d)", vsize, vwidth)); 1980: LOG_REQUEST((" hmode = %d (0=full, 2=cell, 3=line)", hmode)); 1981: LOG_REQUEST((" vmode = %d (0=full, 1=2cell", vmode)); 1982: 1983: for (layer = 0; layer < 2; layer++) { 1984: LOG_REQUEST((" Layer %s:", layer == 0 ? "A" : "B")); 1985: o_patterndata = (layer == 0 ? ((vdp_reg[2] & 0x38)<<10) : 1.1.1.2 ! root 1986: ((vdp_reg[4] & 7)<<13)); 1.1 root 1987: o_hscrolldata = layer*2 + ((vdp_reg[13] & 63)<<10); 1988: LOG_REQUEST((" Pattern data @ vram+%08X", o_patterndata)); 1989: LOG_REQUEST((" Hscroll data @ vram+%08X", o_hscrolldata)); 1990: patterndata = (uint16 *)(vdp_vram + o_patterndata); 1991: hscrolldata = (uint16 *)(vdp_vram + o_hscrolldata); 1992: for (line = 0; line < vdp_vislines; line++) { 1993: switch(hmode) { 1994: case 0: /* full screen */ 1.1.1.2 ! root 1995: hoffset = (0x400 - LOCENDIAN16(hscrolldata[0])) & 0x3FF; ! 1996: break; 1.1 root 1997: case 2: /* cell scroll */ 1.1.1.2 ! root 1998: hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*(line & ~7)])) & 0x3FF; ! 1999: break; 1.1 root 2000: case 3: /* line scroll */ 1.1.1.2 ! root 2001: hoffset = (0x400 - LOCENDIAN16(hscrolldata[2*line])) & 0x3FF; ! 2002: break; 1.1 root 2003: default: 1.1.1.2 ! root 2004: LOG_REQUEST(("prohibited HSCR/LSCR on line %d", line)); ! 2005: hoffset = 0; ! 2006: break; 1.1 root 2007: } 2008: raw_hoffset = hoffset; 2009: hoffset&= (hwidth*8)-1; /* put offset in range */ 2010: voffset = (line + LOCENDIAN16( ((uint16 *)vdp_vsram)[layer] )) & 0x3FF; 2011: voffset&= (vwidth*8)-1; /* put offset in range */ 2012: LOG_REQUEST((" line %d: hoffset=%d=%d, voffset=%d, " 1.1.1.2 ! root 2013: "firstcell=vram+%08X", line, raw_hoffset, hoffset, voffset, ! 2014: o_patterndata+2*((hoffset>>3)+hwidth*(voffset>>3)))); 1.1 root 2015: } 2016: } 2017: } 2018: 2019: void vdp_eventinit(void) 2020: { 2021: /* Facts from documentation: 2022: H-Blank is 73.7 clock cycles long. 2023: The VDP settings are aquired 36 clocks after start of H-Blank. 2024: The display period is 413.3 clocks in duration. 2025: V-Int occurs 14.7us after H-Int (which is 112 clock cycles) 2026: Facts from clock data: 2027: One line takes 488 clocks (vdp_clksperline_68k) 1.1.1.2 ! root 2028: Assumptions: (not sure if these are true anymore) 1.1 root 2029: We 'approximate' and make H-Int occur at the same time as H-Blank. 2030: V-Blank starts at V-Int and ends at the start of line 0. 2031: 2032: vdp_event_start = start of line, end of v-blank 2033: vdp_event_vint = v-int time on line 224 (or 240) 2034: (112 clocks after h-int) 2035: vdp_event_hint = h-int time at end of each line 2036: vdp_event_hdisplay = settings are aquired and current line displayed 2037: vdp_event_end = end of line, end of h-blank 2038: 2039: Note that if the program stays in H-Int 224 longer than 112 clocks, V-Int 2040: is not supposed to occur due to the processor acknowledging the wrong 2041: interrupt from the VDP, thus programs disable H-Ints on 223 to prevent 2042: this problem. We don't worry about this. 2043: */ 2044: vdp_event = 0; 2045: vdp_event_start = 0; 2046: vdp_event_vint = 112-74; 2047: vdp_event_hint = vdp_clksperline_68k-74; 2048: vdp_event_hdisplay = vdp_event_hint+36; 2049: vdp_event_end = vdp_clksperline_68k; 1.1.1.2 ! root 2050: vdp_nextevent = 0; 1.1 root 2051: } 2052: 2053: void vdp_endfield(void) 2054: { 2055: vdp_line = 0; 2056: vdp_eventinit(); 2057: vdp_oddframe^= 1; /* toggle */ 2058: /* printf("(%d,%d,%d,%d,%d)\n", vdp_event_type, 2059: vdp_event_startline, vdp_event_hint, vdp_event_vdpplot, 2060: vdp_event_endline); */ 2061: } 2062: 2063: inline void vdp_plotcell(uint8 *patloc, uint8 palette, uint8 flags, 1.1.1.2 ! root 2064: uint8 *cellloc, unsigned int lineoffset) 1.1 root 2065: { 2066: int y, x; 2067: uint8 value; 2068: uint32 data; 2069: 2070: switch(flags) { 2071: case 0: 2072: /* normal tile - no s/ten */ 2073: for (y = 0; y < 8; y++, cellloc+= lineoffset) { 2074: data = LOCENDIAN32(((uint32 *)patloc)[y]); 2075: for (x = 0; x < 8; x++, data<<= 4) { 1.1.1.2 ! root 2076: value = data>>28; ! 2077: if (value) ! 2078: cellloc[x] = palette*16 + value; 1.1 root 2079: } 2080: } 2081: break; 2082: case 1: 2083: /* h flipped tile - no s/ten */ 2084: for (y = 0; y < 8; y++, cellloc+= lineoffset) { 2085: data = LOCENDIAN32(((uint32 *)patloc)[y]); 2086: for (x = 0; x < 8; x++, data>>= 4) { 1.1.1.2 ! root 2087: value = data & 15; ! 2088: if (value) ! 2089: cellloc[x] = palette*16 + value; 1.1 root 2090: } 2091: } 2092: break; 2093: case 2: 2094: /* v flipped tile - no s/ten */ 2095: for (y = 0; y < 8; y++, cellloc+= lineoffset) { 2096: data = LOCENDIAN32(((uint32 *)patloc)[7-y]); 2097: for (x = 0; x < 8; x++, data<<= 4) { 1.1.1.2 ! root 2098: value = data>>28; ! 2099: if (value) ! 2100: cellloc[x] = palette*16 + value; 1.1 root 2101: } 2102: } 2103: break; 2104: case 3: 2105: /* h and v flipped tile - no s/ten */ 2106: for (y = 0; y < 8; y++, cellloc+= lineoffset) { 2107: data = LOCENDIAN32(((uint32 *)patloc)[7-y]); 2108: for (x = 0; x < 8; x++, data>>= 4) { 1.1.1.2 ! root 2109: value = data & 15; ! 2110: if (value) ! 2111: cellloc[x] = palette*16 + value; 1.1 root 2112: } 2113: } 2114: break; 2115: case 4: 2116: /* normal tile - s/ten enabled */ 2117: for (y = 0; y < 8; y++, cellloc+= lineoffset) { 2118: data = LOCENDIAN32(((uint32 *)patloc)[y]); 2119: for (x = 0; x < 8; x++, data<<= 4) { 1.1.1.2 ! root 2120: value = data>>28; ! 2121: if (value) { ! 2122: if (palette == 3 && value == 14) { ! 2123: cellloc[x] = (cellloc[x] & 63) + 64; ! 2124: } else if (palette == 3 && value == 15) { ! 2125: cellloc[x] = (cellloc[x] & 63) + 128; ! 2126: } else { ! 2127: cellloc[x] = palette*16 + value; ! 2128: } ! 2129: } 1.1 root 2130: } 2131: } 2132: break; 2133: case 5: 2134: /* h flipped tile - s/ten */ 2135: for (y = 0; y < 8; y++, cellloc+= lineoffset) { 2136: data = LOCENDIAN32(((uint32 *)patloc)[y]); 2137: for (x = 0; x < 8; x++, data>>= 4) { 1.1.1.2 ! root 2138: value = data & 15; ! 2139: if (value) { ! 2140: if (palette == 3 && value == 14) { ! 2141: cellloc[x] = (cellloc[x] & 63) + 64; ! 2142: } else if (palette == 3 && value == 15) { ! 2143: cellloc[x] = (cellloc[x] & 63) + 128; ! 2144: } else { ! 2145: cellloc[x] = palette*16 + value; ! 2146: } ! 2147: } 1.1 root 2148: } 2149: } 2150: break; 2151: case 6: 2152: /* v flipped tile - s/ten enabled */ 2153: for (y = 0; y < 8; y++, cellloc+= lineoffset) { 2154: data = LOCENDIAN32(((uint32 *)patloc)[7-y]); 2155: for (x = 0; x < 8; x++, data<<= 4) { 1.1.1.2 ! root 2156: value = data>>28; ! 2157: if (value) { ! 2158: if (palette == 3 && value == 14) { ! 2159: cellloc[x] = (cellloc[x] & 63) + 64; ! 2160: } else if (palette == 3 && value == 15) { ! 2161: cellloc[x] = (cellloc[x] & 63) + 128; ! 2162: } else { ! 2163: cellloc[x] = palette*16 + value; ! 2164: } ! 2165: } 1.1 root 2166: } 2167: } 2168: break; 2169: case 7: 2170: /* h and v flipped tile - s/ten enabled */ 2171: for (y = 0; y < 8; y++, cellloc+= lineoffset) { 2172: data = LOCENDIAN32(((uint32 *)patloc)[7-y]); 2173: for (x = 0; x < 8; x++, data>>= 4) { 1.1.1.2 ! root 2174: value = data & 15; ! 2175: if (value) { ! 2176: if (palette == 3 && value == 14) { ! 2177: cellloc[x] = (cellloc[x] & 63) + 64; ! 2178: } else if (palette == 3 && value == 15) { ! 2179: cellloc[x] = (cellloc[x] & 63) + 128; ! 2180: } else { ! 2181: cellloc[x] = palette*16 + value; ! 2182: } ! 2183: } 1.1 root 2184: } 2185: } 2186: break; 2187: default: 2188: ui_err("Unknown plotcell flags"); 2189: } 2190: } 2191: 2192: /* must be 8*lineoffset bytes scrap before and after fielddata and also 2193: 8 bytes before each line and 8 bytes after each line */ 2194: 2195: void vdp_layer_simple(unsigned int layer, unsigned int priority, 1.1.1.2 ! root 2196: uint8 *framedata, unsigned int lineoffset) 1.1 root 2197: { 2198: int i, j; 2199: uint8 hsize = vdp_reg[16] & 3; 2200: uint8 vsize = (vdp_reg[16] >> 4) & 3; 2201: uint8 hmode = vdp_reg[11] & 3; 2202: uint8 vmode = (vdp_reg[11] >> 2) & 1; 2203: uint16 vramoffset = (layer ? ((vdp_reg[4] & 7) << 13) : 1.1.1.2 ! root 2204: ((vdp_reg[2] & (7<<3)) << 10)); 1.1 root 2205: uint16 *patterndata = (uint16 *)(vdp_vram + vramoffset); 2206: uint16 *hscrolldata = (uint16 *)(((vdp_reg[13] & 63) << 10) 1.1.1.2 ! root 2207: + vdp_vram + layer*2); 1.1 root 2208: uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32; 2209: uint16 hwidth = 32+hsize*32; 2210: uint16 vwidth = 32+vsize*32; 2211: uint16 hoffset, voffset; 2212: uint16 cellinfo; 2213: uint8 *pattern; 2214: uint32 data; 2215: uint8 palette; 2216: uint8 value; 2217: unsigned int xcell, ycell; 2218: unsigned int pos; 2219: uint8 *toploc, *cellloc; 2220: uint8 flags; 2221: uint32 hscroll, vscroll; 2222: unsigned int x, y; 2223: 2224: for (xcell = 0; xcell <= screencells; xcell++) { 2225: if (vmode) { 2226: /* 2-cell scroll */ 2227: vscroll = ((xcell >= screencells ? xcell-2 : xcell) & ~1) + layer; 2228: } else { 2229: /* full screen */ 2230: vscroll = layer; 2231: } 2232: voffset = LOCENDIAN16( ((uint16 *)vdp_vsram)[vscroll] ) & 0x3FF; 2233: toploc = framedata - lineoffset*(voffset & 7); 2234: for (ycell = 0; ycell <= 28; ycell++, voffset+=8, toploc+=lineoffset*8) { 2235: switch(hmode) { 2236: case 0: /* full screen */ 1.1.1.2 ! root 2237: hscroll = 0; ! 2238: break; 1.1 root 2239: case 2: /* cell scroll */ 1.1.1.2 ! root 2240: hscroll = 2 * (ycell >= 28 ? ycell-2 : ycell) * 8; ! 2241: break; 1.1 root 2242: case 3: /* line scroll - approximation */ 1.1.1.2 ! root 2243: hscroll = 2 * (ycell >= 28 ? ycell-2 : ycell) * 8; ! 2244: vdp_complex = 1; ! 2245: break; 1.1 root 2246: default: 1.1.1.2 ! root 2247: LOG_NORMAL(("prohibited HSCR/LSCR")); ! 2248: hscroll = 0; ! 2249: break; 1.1 root 2250: } 2251: voffset &= (vwidth*8)-1; 2252: hoffset = (0x400 - LOCENDIAN16(hscrolldata[hscroll])) & 0x3FF; 2253: hoffset = (hoffset+xcell*8) & ((hwidth*8)-1); 2254: cellinfo = LOCENDIAN16(patterndata[(hoffset>>3)+hwidth*(voffset>>3)]); 2255: if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) == priority) { 1.1.1.2 ! root 2256: /* plot cell */ ! 2257: palette = (cellinfo >> 13) & 3; ! 2258: pattern = vdp_vram + ((cellinfo & 2047)<<5); ! 2259: flags = (cellinfo>>11) & 3; /* bit0=H flip, bit1=V flip */ 1.1 root 2260: cellloc = toploc - (hoffset&7) + xcell*8; 1.1.1.2 ! root 2261: vdp_plotcell(pattern, palette, flags, cellloc, lineoffset); 1.1 root 2262: } 2263: } /* ycell */ 2264: } /* xcell */ 2265: } 2266: 2267: void vdp_shadow_simple(uint8 *framedata, unsigned int lineoffset) 2268: { 2269: unsigned int vertcells = vdp_reg[1] & 1<<3 ? 30 : 28; 2270: uint8 *linedata; 2271: unsigned int line; 2272: int i; 2273: 2274: for (line = 0; line < vertcells*8; line++) { 2275: linedata = framedata + line*lineoffset; 2276: /* this could be done 4 bytes at a time */ 2277: for (i = 0; i < 320; i++) 2278: linedata[i] = (linedata[i] & 63) + 128; 2279: } 2280: } 2281: 2282: void vdp_sprites_simple(unsigned int priority, uint8 *framedata, 1.1.1.2 ! root 2283: unsigned int lineoffset) 1.1 root 2284: { 2285: uint8 *spritelist = vdp_vram + ((vdp_reg[5] & 0x7F)<<9); 2286: 2287: vdp_sprite_simple(priority, framedata, lineoffset, 1, 1.1.1.2 ! root 2288: spritelist, spritelist); 1.1 root 2289: } 2290: 2291: int vdp_sprite_simple(unsigned int priority, uint8 *framedata, 1.1.1.2 ! root 2292: unsigned int lineoffset, unsigned int number, ! 2293: uint8 *spritelist, uint8 *sprite) 1.1 root 2294: { 2295: int i, j; 2296: int plotted = 1; 2297: uint8 screencells = (vdp_reg[12] & 1) ? 40 : 32; 2298: uint8 link; 2299: uint16 pattern; 2300: uint32 data; 2301: uint8 palette; 2302: uint16 cellinfo; 2303: sint16 vpos, hpos, vmax; 2304: uint16 xcell, ycell; 2305: uint8 vsize, hsize; 2306: uint8 *cellloc; 2307: uint8 flags; 2308: uint8 *patloc; 2309: 2310: if (number > 80) { 2311: LOG_VERBOSE(("%08X [VDP] Maximum of 80 sprites exceeded", regs.pc)); 2312: return 0; 2313: } 2314: 2315: link = sprite[3] & 0x7F; 2316: hpos = (LOCENDIAN16(*(uint16 *)(sprite+6)) & 0x1FF) - 0x80; 2317: vpos = (LOCENDIAN16(*(uint16 *)(sprite)) & 0x3FF) - 0x80; 2318: vsize = 1+(sprite[2] & 3); 2319: hsize = 1+((sprite[2]>>2) & 3); 2320: cellinfo = LOCENDIAN16(*(uint16 *)(sprite+4)); 2321: pattern = cellinfo & 0x7FF; 2322: palette = (cellinfo >> 13) & 3; 2323: vmax = vpos + vsize*8; 2324: 2325: if (link) { 2326: if (hpos == -128) 2327: /* we do not support 'masking' in simple mode */ 2328: vdp_complex = 1; 2329: plotted = vdp_sprite_simple(priority, framedata, lineoffset, number+1, 1.1.1.2 ! root 2330: spritelist, spritelist + (link<<3)); 1.1 root 2331: plotted++; 2332: } 2333: 2334: if (((uint8)((cellinfo & 1<<15) ? 1 : 0)) != priority) 2335: return plotted; 2336: if (vpos >= 240 || hpos >= 320 || vpos+vsize*8 <= 0 || hpos+hsize*8 <= 0) 2337: /* sprite is not on screen */ 2338: return plotted; 2339: flags = (cellinfo>>11) & 3; /* bit0=H flip, bit1=V flip */ 1.1.1.2 ! root 2340: if (vdp_reg[12] & 1<<3) /* s/ten enabled? */ ! 2341: flags|= 1<<2; 1.1 root 2342: switch(flags) { 2343: case 0: 2344: case 4: 2345: /* normal orientation */ 2346: for (ycell = 0; ycell < vsize; ycell++) { 2347: if (ycell*8+vpos < -7 || ycell*8+vpos >= 240) 1.1.1.2 ! root 2348: /* cell out of plotting area (remember scrap area) */ ! 2349: continue; 1.1 root 2350: patloc = vdp_vram + (pattern<<5) + ycell*32; 2351: for (xcell = 0; xcell < hsize; xcell++, patloc+= vsize*32) { 1.1.1.2 ! root 2352: if (xcell*8+hpos < -7 || xcell*8+hpos >= 320) ! 2353: /* cell out of plotting area */ ! 2354: continue; ! 2355: cellloc = framedata + ((vpos+ycell*8)*lineoffset + ! 2356: (hpos+xcell*8)); ! 2357: vdp_plotcell(patloc, palette, flags, cellloc, lineoffset); 1.1 root 2358: } 2359: } 2360: break; 2361: case 1: 2362: case 5: 2363: /* H flip */ 2364: for (ycell = 0; ycell < vsize; ycell++) { 2365: if (ycell*8+vpos < -7 || ycell*8+vpos >= 240) 1.1.1.2 ! root 2366: /* cell out of plotting area (remember scrap area) */ ! 2367: continue; 1.1 root 2368: patloc = vdp_vram + (pattern<<5) + ycell*32 + vsize*32*(hsize-1); 2369: for (xcell = 0; xcell < hsize; xcell++, patloc-= vsize*32) { 1.1.1.2 ! root 2370: if (xcell*8+hpos < -7 || xcell*8+hpos >= 320) ! 2371: /* cell out of plotting area */ ! 2372: continue; ! 2373: cellloc = framedata + ((vpos+ycell*8)*lineoffset + ! 2374: (hpos+xcell*8)); ! 2375: vdp_plotcell(patloc, palette, flags, cellloc, lineoffset); 1.1 root 2376: } 2377: } 2378: break; 2379: case 2: 2380: case 6: 2381: /* V flip */ 2382: for (ycell = 0; ycell < vsize; ycell++) { 2383: if (ycell*8+vpos < -7 || ycell*8+vpos >= 240) 1.1.1.2 ! root 2384: /* cell out of plotting area (remember scrap area) */ ! 2385: continue; 1.1 root 2386: patloc = vdp_vram + (pattern<<5) + (vsize-ycell-1)*32; 2387: for (xcell = 0; xcell < hsize; xcell++, patloc+= vsize*32) { 1.1.1.2 ! root 2388: if (xcell*8+hpos < -7 || xcell*8+hpos >= 320) ! 2389: /* cell out of plotting area */ ! 2390: continue; ! 2391: cellloc = framedata + ((vpos+ycell*8)*lineoffset + ! 2392: (hpos+xcell*8)); ! 2393: vdp_plotcell(patloc, palette, flags, cellloc, lineoffset); 1.1 root 2394: } 2395: } 2396: break; 2397: case 3: 2398: case 7: 2399: /* H and V flip */ 2400: for (ycell = 0; ycell < vsize; ycell++) { 2401: if (ycell*8+vpos < -7 || ycell*8+vpos >= 240) 1.1.1.2 ! root 2402: /* cell out of plotting area (remember scrap area) */ ! 2403: continue; 1.1 root 2404: patloc = vdp_vram + (pattern<<5) + ((vsize-ycell-1)*32 + 1.1.1.2 ! root 2405: vsize*32*(hsize-1)); 1.1 root 2406: for (xcell = 0; xcell < hsize; xcell++, patloc-= vsize*32) { 1.1.1.2 ! root 2407: if (xcell*8+hpos < -7 || xcell*8+hpos >= 320) ! 2408: /* cell out of plotting area */ ! 2409: continue; ! 2410: cellloc = framedata + ((vpos+ycell*8)*lineoffset + ! 2411: (hpos+xcell*8)); ! 2412: vdp_plotcell(patloc, palette, flags, cellloc, lineoffset); 1.1 root 2413: } 2414: } 2415: break; 2416: } 2417: return plotted; 2418: } 2419: 2420: uint8 vdp_gethpos(void) { 1.1.1.2 ! root 2421: float percent; ! 2422: 1.1 root 2423: /* vdp_event = 0/1/2 -> beginning of line until 74 clocks before end 2424: 3 -> between hint and hdisplay (36 clocks) 2425: 4 -> between hdisplay and end (38 clocks) 2426: This routine goes from 0 to the maximum number allowed not within 2427: H-blank, and then goes slightly beyond up to hdisplay. Then 2428: between hdisplay and end we go negative. I'm not sure how negative 2429: it is supposed to be, this goes from -38 to 0. 2430: 1.1.1.2 ! root 2431: 40 horizontal cells, H goes from $00 to $B6, $E4 to $FF ! 2432: 32 horizontal cells, H goes from $00 to $93, $E8 to $FF ! 2433: 1.1 root 2434: this is such a bodge - any changes, check '3 Ninjas kick back' 2435: */ 2436: LOG_DEBUG1(("gethpos %X: clocks=%X : startofline=%X : hint=%X : " 1.1.1.2 ! root 2437: "end=%X", vdp_event, cpu68k_clocks, ! 2438: vdp_event_start, ! 2439: vdp_event_hint, vdp_event_end)); ! 2440: if (vdp_event < 3) { ! 2441: percent = ((float)(cpu68k_clocks-vdp_event_start)/ ! 2442: (float)(vdp_event_hint-vdp_event_start)); ! 2443: if (vdp_reg[12] & 1) ! 2444: return (cpu68k_clocks > vdp_event_hint) ? 0xE4 : percent*0xB6; ! 2445: else ! 2446: return (cpu68k_clocks > vdp_event_hint) ? 0xE8 : percent*0x93; ! 2447: } else { ! 2448: percent = ((float)(cpu68k_clocks-vdp_event_hint)/ ! 2449: (float)(vdp_event_end-vdp_event_hint)); ! 2450: if (vdp_reg[12] & 1) ! 2451: return ((cpu68k_clocks > vdp_event_end) ? 0 : ! 2452: ((0xE4+(uint8)percent*28) & 0xff)); ! 2453: else ! 2454: return ((cpu68k_clocks > vdp_event_end) ? 0 : ! 2455: ((0xE8+(uint8)percent*24) & 0xff)); ! 2456: } 1.1 root 2457: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.