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