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