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