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