1 /*******************************************************************************
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
4 (c) Copyright 1996 - 2003 Gary Henderson (gary.henderson@ntlworld.com) and
5 Jerremy Koot (jkoot@snes9x.com)
7 (c) Copyright 2002 - 2003 Matthew Kendora and
8 Brad Jorsch (anomie@users.sourceforge.net)
12 C4 x86 assembler and some C emulation code
13 (c) Copyright 2000 - 2003 zsKnight (zsknight@zsnes.com),
14 _Demo_ (_demo_@zsnes.com), and
15 Nach (n-a-c-h@users.sourceforge.net)
18 (c) Copyright 2003 Brad Jorsch
21 (c) Copyright 1998 - 2003 Ivar (ivar@snes9x.com), _Demo_, Gary Henderson,
22 John Weidman (jweidman@slip.net),
23 neviksti (neviksti@hotmail.com), and
24 Kris Bleakley (stinkfish@bigpond.com)
27 (c) Copyright 2003 Kris Bleakley, John Weidman, neviksti, Matthew Kendora, and
28 Lord Nightmare (lord_nightmare@users.sourceforge.net
31 (c) Copyright 2001 - 2003 zsKnight, pagefault (pagefault@zsnes.com)
32 Ported from x86 assembler to C by sanmaiwashi
34 SPC7110 and RTC C++ emulator code
35 (c) Copyright 2002 Matthew Kendora with research by
36 zsKnight, John Weidman, and Dark Force
39 (c) Copyright 2001 John Weidman
41 Super FX x86 assembler emulator code
42 (c) Copyright 1998 - 2003 zsKnight, _Demo_, and pagefault
44 Super FX C emulator code
45 (c) Copyright 1997 - 1999 Ivar and Gary Henderson.
50 Specific ports contains the works of other authors. See headers in
53 Snes9x homepage: http://www.snes9x.com
55 Permission to use, copy, modify and distribute Snes9x in both binary and
56 source form, for non-commercial purposes, is hereby granted without fee,
57 providing that this license information and copyright notice appear with
58 all copies and any derived work.
60 This software is provided 'as-is', without any express or implied
61 warranty. In no event shall the authors be held liable for any damages
62 arising from the use of this software.
64 Snes9x is freeware for PERSONAL USE only. Commercial users should
65 seek permission of the copyright holders first. Commercial use includes
66 charging money for Snes9x or software derived from Snes9x.
68 The copyright holders request that bug fixes and improvements to the code
69 should be forwarded to them so everyone can benefit from the modifications
72 Super NES and Super Nintendo Entertainment System are trademarks of
73 Nintendo Co., Limited and its subsidiary companies.
74 *******************************************************************************/
91 // Stupid zsnes code, we can't do the logical thing without breaking
93 // Memory.C4RAM = &Memory.FillRAM [0x6000];
94 memset(Memory.C4RAM, 0, 0x2000);
97 uint8 S9xGetC4 (uint16 Address)
100 if(Settings.BGLayering) printf("%02x from %04x\n", Memory.C4RAM[Address-0x6000], Address);
102 if(Address==0x7f5e) return 0;
103 return (Memory.C4RAM [Address-0x6000]);
106 static uint8 C4TestPattern [12 * 4] =
108 0x00, 0x00, 0x00, 0xff,
109 0xff, 0xff, 0x00, 0xff,
110 0x00, 0x00, 0x00, 0xff,
111 0xff, 0xff, 0x00, 0x00,
112 0xff, 0xff, 0x00, 0x00,
113 0x80, 0xff, 0xff, 0x7f,
114 0x00, 0x80, 0x00, 0xff,
115 0x7f, 0x00, 0xff, 0x7f,
116 0xff, 0x7f, 0xff, 0xff,
117 0x00, 0x00, 0x01, 0xff,
118 0xff, 0xfe, 0x00, 0x01,
119 0x00, 0xff, 0xfe, 0x00
123 static void C4ConvOAM(void){
124 uint8 *OAMptr=Memory.C4RAM+(Memory.C4RAM[0x626]<<2);
125 for(uint8 *i=Memory.C4RAM+0x1fd; i>OAMptr; i-=4){
130 uint16 globalX, globalY;
133 uint8 SprName, SprAttr;
136 globalX=READ_WORD(Memory.C4RAM+0x0621);
137 globalY=READ_WORD(Memory.C4RAM+0x0623);
138 OAMptr2=Memory.C4RAM+0x200+(Memory.C4RAM[0x626]>>2);
141 if(Memory.C4RAM[0x625]!=0) printf("$6625=%02x, expected 00\n", Memory.C4RAM[0x625]);
142 if((Memory.C4RAM[0x626]>>2)!=Memory.C4RAM[0x629]) printf("$6629=%02x, expected %02x\n", Memory.C4RAM[0x629], (Memory.C4RAM[0x626]>>2));
143 if(((uint16)Memory.C4RAM[0x626]<<2)!=READ_WORD(Memory.C4RAM+0x627)) printf("$6627=%04x, expected %04x\n", READ_WORD(Memory.C4RAM+0x627), ((uint16)Memory.C4RAM[0x626]<<2));
146 if(Memory.C4RAM[0x0620]!=0){
147 SprCount=128-Memory.C4RAM[0x626];
148 uint8 offset=(Memory.C4RAM[0x626]&3)*2;
149 uint8 *srcptr=Memory.C4RAM+0x220;
150 for(int i=Memory.C4RAM[0x0620]; i>0 && SprCount>0; i--, srcptr+=16){
151 SprX=READ_WORD(srcptr)-globalX;
152 SprY=READ_WORD(srcptr+2)-globalY;
154 SprAttr=srcptr[4] | srcptr[0x06]; // XXX: mask bits?
156 uint8 *sprptr=S9xGetMemPointer(READ_3WORD(srcptr+7));
159 for(int SprCnt=*sprptr++; SprCnt>0 && SprCount>0; SprCnt--, sprptr+=4){
161 if(SprAttr&0x40){ // flip X
162 X=-X-((sprptr[0]&0x20)?16:8);
165 if(X>=-16 && X<=272){
168 Y=-Y-((sprptr[0]&0x20)?16:8);
171 if(Y>=-16 && Y<=224){
174 OAMptr[2]=SprName+sprptr[3];
175 OAMptr[3]=SprAttr^(sprptr[0]&0xc0); // XXX: Carry from SprName addition?
176 *OAMptr2 &= ~(3<<offset);
177 if(X&0x100) *OAMptr2 |= 1<<offset;
178 if(sprptr[0]&0x20) *OAMptr2 |= 2<<offset;
182 if(offset==0) OAMptr2++;
186 } else if(SprCount>0){
187 OAMptr[0]=(uint8)SprX;
188 OAMptr[1]=(uint8)SprY;
191 *OAMptr2 &= ~(3<<offset);
192 if(SprX&0x100) *OAMptr2 |= 3<<offset;
193 else *OAMptr2 |= 2<<offset;
197 if(offset==0) OAMptr2++;
201 // XXX: Copy to OAM? I doubt it.
204 static void C4DoScaleRotate(int row_padding){
208 int32 XScale=READ_WORD(Memory.C4RAM+0x1f8f);
209 if(XScale&0x8000) XScale=0x7fff;
210 int32 YScale=READ_WORD(Memory.C4RAM+0x1f92);
211 if(YScale&0x8000) YScale=0x7fff;
213 if(READ_WORD(Memory.C4RAM+0x1f80)==0)
215 // XXX: only do this for C and D?
216 // XXX: and then only when YScale is 0x1000?
222 else if(READ_WORD(Memory.C4RAM+0x1f80)==128){ // 90 degree rotation
223 // XXX: Really do this?
228 } else if(READ_WORD(Memory.C4RAM+0x1f80)==256){ // 180 degree rotation
229 // XXX: Really do this?
234 } else if(READ_WORD(Memory.C4RAM+0x1f80)==384){ // 270 degree rotation
235 // XXX: Really do this?
241 A=(int16)SAR(C4CosTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*XScale, 15);
242 B=(int16)(-SAR(C4SinTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*YScale, 15));
243 C=(int16)SAR(C4SinTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*XScale, 15);
244 D=(int16)SAR(C4CosTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*YScale, 15);
247 // Calculate Pixel Resolution
248 uint8 w=Memory.C4RAM[0x1f89]&~7;
249 uint8 h=Memory.C4RAM[0x1f8c]&~7;
251 // printf("%dx%d XScale=%04x YScale=%04x angle=%03x\n", w, h, XScale, YScale, READ_WORD(Memory.C4RAM+0x1f80)&0x1ff);
252 // printf("Matrix: [%10g %10g] [%04x %04x]\n", A/4096.0, B/4096.0, A&0xffff, B&0xffff);
253 // printf(" [%10g %10g] [%04x %04x]\n", C/4096.0, D/4096.0, C&0xffff, D&0xffff);
255 // Clear the output RAM
256 memset(Memory.C4RAM, 0, (w+row_padding/4)*h/2);
258 int32 Cx=(int16)READ_WORD(Memory.C4RAM+0x1f83);
259 int32 Cy=(int16)READ_WORD(Memory.C4RAM+0x1f86);
262 if(Memory.C4RAM[0x1f97]!=0) printf("$7f97=%02x, expected 00\n", Memory.C4RAM[0x1f97]);
263 if((Cx&~1)!=w/2 || (Cy&~1)!=h/2) printf("Center is not middle of image! (%d, %d) != (%d, %d)\n", Cx, Cy, w/2, h/2);
266 // Calculate start position (i.e. (Ox, Oy) = (0, 0))
267 // The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in
268 // the function. We do Cx*A etc normally because the matrix parameters
269 // already have the fractional parts.
270 int32 LineX=(Cx<<12) - Cx*A - Cx*B;
271 int32 LineY=(Cy<<12) - Cy*C - Cy*D;
278 for(int y=0; y<h; y++){
281 for(int x=0; x<w; x++){
282 if((X>>12)>=w || (Y>>12)>=h){
285 uint32 addr=(Y>>12)*w+(X>>12);
286 byte=Memory.C4RAM[0x600+(addr>>1)];
291 if(byte&1) Memory.C4RAM[outidx]|=bit;
292 if(byte&2) Memory.C4RAM[outidx+1]|=bit;
293 if(byte&4) Memory.C4RAM[outidx+16]|=bit;
294 if(byte&8) Memory.C4RAM[outidx+17]|=bit;
302 X+=A; // Add 1 to output x => add an A and a C
305 outidx+=2+row_padding;
309 outidx-=w*4+row_padding;
311 LineX+=B; // Add 1 to output y => add a B and a D
316 static void C4DrawLine(int32 X1, int32 Y1, int16 Z1,
317 int32 X2, int32 Y2, int16 Z2, uint8 Color){
318 // Transform coordinates
322 C4WFScale=Memory.C4RAM[0x1f90];
323 C4WFX2Val=Memory.C4RAM[0x1f86];
324 C4WFY2Val=Memory.C4RAM[0x1f87];
325 C4WFDist=Memory.C4RAM[0x1f88];
326 C4TransfWireFrame2();
333 C4TransfWireFrame2();
338 C4WFXVal=(short)(X1>>8);
339 C4WFYVal=(short)(Y1>>8);
340 C4WFX2Val=(short)(X2>>8);
341 C4WFY2Val=(short)(Y2>>8);
347 for(int i=C4WFDist?C4WFDist:1; i>0; i--)
349 if(X1>0xff && Y1>0xff && X1<0x6000 && Y1<0x6000)
351 uint16 addr=((X1&~0x7ff) + (Y1&~0x7ff)*12 + (Y1&0x700))>>7;
352 addr=(((Y1>>8)>>3)<<8)-(((Y1>>8)>>3)<<6)+(((X1>>8)>>3)<<4)+((Y1>>8)&7)*2;
353 uint8 bit=0x80>>((X1>>8)&7);
354 Memory.C4RAM[addr+0x300]&=~bit;
355 Memory.C4RAM[addr+0x301]&=~bit;
356 if(Color&1) Memory.C4RAM[addr+0x300]|=bit;
357 if(Color&2) Memory.C4RAM[addr+0x301]|=bit;
364 static void C4DrawWireFrame(void)
366 uint8 *line=S9xGetMemPointer(READ_3WORD(Memory.C4RAM+0x1f80));
367 uint8 *point1, *point2;
373 if(READ_3WORD(Memory.C4RAM+0x1f8f)&0xff00ff) printf("wireframe: Unexpected value in $7f8f: %06x\n", READ_3WORD(Memory.C4RAM+0x1f8f));
374 if(READ_3WORD(Memory.C4RAM+0x1fa4)!=0x001000) printf("wireframe: Unexpected value in $7fa4: %06x\n", READ_3WORD(Memory.C4RAM+0x1fa4));
377 for(int i=Memory.C4RAM[0x0295]; i>0; i--, line+=5){
378 if(line[0]==0xff && line[1]==0xff){
380 while(line[2]==0xff && line[3]==0xff) tmp-=5;
381 point1=S9xGetMemPointer((Memory.C4RAM[0x1f82]<<16) | (tmp[2]<<8) | tmp[3]);
383 point1=S9xGetMemPointer((Memory.C4RAM[0x1f82]<<16) | (line[0]<<8) | line[1]);
385 point2=S9xGetMemPointer((Memory.C4RAM[0x1f82]<<16) | (line[2]<<8) | line[3]);
387 X1=(point1[0]<<8) | point1[1];
388 Y1=(point1[2]<<8) | point1[3];
389 Z1=(point1[4]<<8) | point1[5];
390 X2=(point2[0]<<8) | point2[1];
391 Y2=(point2[2]<<8) | point2[3];
392 Z2=(point2[4]<<8) | point2[5];
394 C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
398 static void C4TransformLines(void){
399 C4WFX2Val=Memory.C4RAM[0x1f83];
400 C4WFY2Val=Memory.C4RAM[0x1f86];
401 C4WFDist=Memory.C4RAM[0x1f89];
402 C4WFScale=Memory.C4RAM[0x1f8c];
405 if(Memory.C4RAM[0x1f8a]!=0x90) printf("lines: $7f8a = %02x, expected 90\n", READ_WORD(Memory.C4RAM+0x1f8a));
408 // transform vertices
409 uint8 *ptr=Memory.C4RAM;
411 for(int i=READ_WORD(Memory.C4RAM+0x1f80); i>0; i--, ptr+=0x10)
413 C4WFXVal=READ_WORD(ptr+1);
414 C4WFYVal=READ_WORD(ptr+5);
415 C4WFZVal=READ_WORD(ptr+9);
419 WRITE_WORD(ptr+1, C4WFXVal+0x80);
420 WRITE_WORD(ptr+5, C4WFYVal+0x50);
423 WRITE_WORD(Memory.C4RAM+0x600, 23);
424 WRITE_WORD(Memory.C4RAM+0x602, 0x60);
425 WRITE_WORD(Memory.C4RAM+0x605, 0x40);
426 WRITE_WORD(Memory.C4RAM+0x600+8, 23);
427 WRITE_WORD(Memory.C4RAM+0x602+8, 0x60);
428 WRITE_WORD(Memory.C4RAM+0x605+8, 0x40);
430 ptr=Memory.C4RAM+0xb02;
431 uint8 *ptr2=Memory.C4RAM;
433 for(int i=READ_WORD(Memory.C4RAM+0xb00); i>0; i--, ptr+=2, ptr2+=8)
435 C4WFXVal=READ_WORD(Memory.C4RAM+(ptr[0]<<4)+1);
436 C4WFYVal=READ_WORD(Memory.C4RAM+(ptr[0]<<4)+5);
437 C4WFX2Val=READ_WORD(Memory.C4RAM+(ptr[1]<<4)+1);
438 C4WFY2Val=READ_WORD(Memory.C4RAM+(ptr[1]<<4)+5);
440 WRITE_WORD(ptr2+0x600, C4WFDist?C4WFDist:1);
441 WRITE_WORD(ptr2+0x602, C4WFXVal);
442 WRITE_WORD(ptr2+0x605, C4WFYVal);
446 static void C4BitPlaneWave(){
447 static uint16 bmpdata[]={
448 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, 0x000E,
449 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020A, 0x020C, 0x020E,
450 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, 0x040E,
451 0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060A, 0x060C, 0x060E,
452 0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080A, 0x080C, 0x080E
455 uint8 *dst=Memory.C4RAM;
456 uint32 waveptr=Memory.C4RAM[0x1f83];
461 if(READ_3WORD(Memory.C4RAM+0x1f80) != Memory.C4RAM[waveptr+0xb00]) printf("$7f80=%06x, expected %02x\n", READ_3WORD(Memory.C4RAM+0x1f80), Memory.C4RAM[waveptr+0xb00]);
464 for(int j=0; j<0x10; j++){
466 int16 height=-((int8)Memory.C4RAM[waveptr+0xb00])-16;
467 for(int i=0; i<40; i++){
468 uint16 tmp=READ_WORD(dst+bmpdata[i]) & mask2;
471 tmp|=mask1&READ_WORD(Memory.C4RAM+0xa00+height*2);
476 WRITE_WORD(dst+bmpdata[i], tmp);
479 waveptr=(waveptr+1)&0x7f;
480 mask1=(mask1>>2)|(mask1<<6);
481 mask2=(mask2>>2)|(mask2<<6);
482 } while(mask1!=0xc0c0);
486 int16 height=-((int8)Memory.C4RAM[waveptr+0xb00])-16;
487 for(int i=0; i<40; i++){
488 uint16 tmp=READ_WORD(dst+bmpdata[i]) & mask2;
491 tmp|=mask1&READ_WORD(Memory.C4RAM+0xa10+height*2);
496 WRITE_WORD(dst+bmpdata[i], tmp);
499 waveptr=(waveptr+1)&0x7f;
500 mask1=(mask1>>2)|(mask1<<6);
501 mask2=(mask2>>2)|(mask2<<6);
502 } while(mask1!=0xc0c0);
507 static void C4SprDisintegrate()
510 uint32 StartX, StartY;
512 int32 scaleX, scaleY;
515 width=Memory.C4RAM[0x1f89];
516 height=Memory.C4RAM[0x1f8c];
517 Cx=(int16)READ_WORD(Memory.C4RAM+0x1f80);
518 Cy=(int16)READ_WORD(Memory.C4RAM+0x1f83);
521 if((Cx&~1)!=width/2 || (Cy&~1)!=height/2) printf("Center is not middle of image for disintegrate! (%d, %d) != (%d, %d)\n", Cx, Cy, width/2, height/2);
524 scaleX=(int16)READ_WORD(Memory.C4RAM+0x1f86);
525 scaleY=(int16)READ_WORD(Memory.C4RAM+0x1f8f);
526 StartX=-Cx*scaleX+(Cx<<8);
527 StartY=-Cy*scaleY+(Cy<<8);
528 src=Memory.C4RAM+0x600;
530 memset(Memory.C4RAM, 0, width*height/2);
532 for(uint32 y=StartY, i=0; i<height; i++, y+=scaleY)
534 for(uint32 x=StartX, j=0; j<width; j++, x+=scaleX)
536 if((x>>8)<width && (y>>8)<height && (y>>8)*width+(x>>8)<0x2000)
538 uint8 pixel=(j&1)?(*src>>4):*src;
539 int idx=(y>>11)*width*4+(x>>11)*32+((y>>8)&7)*2;
540 uint8 mask=0x80>>((x>>8)&7);
541 if(pixel&1) Memory.C4RAM[idx]|=mask;
542 if(pixel&2) Memory.C4RAM[idx+1]|=mask;
543 if(pixel&4) Memory.C4RAM[idx+16]|=mask;
544 if(pixel&8) Memory.C4RAM[idx+17]|=mask;
551 static void S9xC4ProcessSprites()
553 switch(Memory.C4RAM[0x1f4d])
555 case 0x00: // Build OAM
557 // printf("00 00 Build OAM!\n");
562 case 0x03: // Scale/Rotate
564 // printf("00 03 Scale/Rotate!\n");
569 case 0x05: // Transform Lines
571 // printf("00 05 Transform Lines!\n");
576 case 0x07: // Scale/Rotate
578 // printf("00 07 Scale/Rotate!\n");
583 case 0x08: // Draw wireframe
585 // printf("00 08 Draw wireframe!\n");
590 case 0x0b: // Disintegrate
592 printf("00 0b Disintegrate!\n");
599 // printf("00 0b Wave!\n");
606 printf ("Unknown C4 sprite command (%02x)\n", Memory.C4RAM [0x1f4d]);
612 void S9xSetC4 (uint8 byte, uint16 Address)
617 if(Settings.BGLayering) printf("%02x to %04x\n", byte, Address);
619 Memory.C4RAM [Address-0x6000] = byte;
620 if (Address == 0x7f4f)
622 if(Memory.C4RAM[0x1f4d]==0x0e && byte<0x40 && (byte&3)==0)
625 printf("Test command %02x 0e used!\n", byte);
627 Memory.C4RAM[0x1f80]=byte>>2;
634 S9xC4ProcessSprites();
637 case 0x01: // Draw wireframe
639 //printf("01 Draw wireframe used!\n");
640 if(Memory.C4RAM[0x1f4d]!=8) printf("$7f4d=%02x, expected 08 for command 01 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
642 memset(Memory.C4RAM+0x300, 0, 16*12*3*4);
646 case 0x05: // Propulsion (?)
648 printf("05 Propulsion (?)!\n");
649 if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 05 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
653 if(READ_WORD(Memory.C4RAM+0x1f83)){
654 tmp=SAR((tmp/READ_WORD(Memory.C4RAM+0x1f83))*READ_WORD(Memory.C4RAM+0x1f81), 8);
656 WRITE_WORD(Memory.C4RAM+0x1f80, (uint16)tmp);
660 case 0x0d: // Set vector length
662 printf("0d Set vector length!\n");
663 if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 0d %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
665 C41FXVal=READ_WORD(Memory.C4RAM+0x1f80);
666 C41FYVal=READ_WORD(Memory.C4RAM+0x1f83);
667 C41FDistVal=READ_WORD(Memory.C4RAM+0x1f86);
669 WRITE_WORD(Memory.C4RAM+0x1f89, C41FXVal);
670 WRITE_WORD(Memory.C4RAM+0x1f8c, C41FYVal);
673 case 0x10: // Polar to rectangluar
675 // printf("10 Polar->Rect!\n");
676 if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 10 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
679 int32 tmp=SAR((int32)READ_WORD(Memory.C4RAM+0x1f83)*C4CosTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*2, 16);
680 WRITE_3WORD(Memory.C4RAM+0x1f86, tmp);
681 tmp=SAR((int32)READ_WORD(Memory.C4RAM+0x1f83)*C4SinTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*2, 16);
682 WRITE_3WORD(Memory.C4RAM+0x1f89, (tmp-SAR(tmp, 6)));
686 case 0x13: // Polar to rectangluar
688 // printf("13 Polar->Rect!\n");
689 if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 13 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
692 int32 tmp=SAR((int32)READ_WORD(Memory.C4RAM+0x1f83)*C4CosTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*2, 8);
693 WRITE_3WORD(Memory.C4RAM+0x1f86, tmp);
694 tmp=SAR((int32)READ_WORD(Memory.C4RAM+0x1f83)*C4SinTable[READ_WORD(Memory.C4RAM+0x1f80)&0x1ff]*2, 8);
695 WRITE_3WORD(Memory.C4RAM+0x1f89, tmp);
699 case 0x15: // Pythagorean
701 printf("15 Pythagorean!\n");
702 if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 15 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
704 C41FXVal=READ_WORD(Memory.C4RAM+0x1f80);
705 C41FYVal=READ_WORD(Memory.C4RAM+0x1f83);
706 C41FDist=(int16)sqrt((double)C41FXVal*C41FXVal + (double)C41FYVal*C41FYVal);
707 WRITE_WORD(Memory.C4RAM+0x1f80, C41FDist);
712 // printf("1f atan!\n");
713 if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 1f %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
715 C41FXVal=READ_WORD(Memory.C4RAM+0x1f80);
716 C41FYVal=READ_WORD(Memory.C4RAM+0x1f83);
718 WRITE_WORD(Memory.C4RAM+0x1f86, C41FAngleRes);
721 case 0x22: // Trapezoid
724 // printf("22 Trapezoid!\n");
725 if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 22 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
727 int16 angle1=READ_WORD(Memory.C4RAM+0x1f8c)&0x1ff;
728 int16 angle2=READ_WORD(Memory.C4RAM+0x1f8f)&0x1ff;
730 if(C4CosTable[angle1]==0) fprintf(stderr, "22 Trapezoid: Invalid tangent! angle1=%d\n", angle1);
731 if(C4CosTable[angle2]==0) fprintf(stderr, "22 Trapezoid: Invalid tangent! angle2=%d\n", angle2);
733 int32 tan1=(C4CosTable[angle1]!=0)?((((int32)C4SinTable[angle1])<<16)/C4CosTable[angle1]):0x80000000;
734 int32 tan2=(C4CosTable[angle2]!=0)?((((int32)C4SinTable[angle2])<<16)/C4CosTable[angle2]):0x80000000;
735 int16 y = READ_WORD(Memory.C4RAM+0x1f83) - READ_WORD(Memory.C4RAM+0x1f89);
737 for(int j=0; j<225; j++)
741 left = SAR((int32)tan1*y, 16) -
742 READ_WORD(Memory.C4RAM+0x1f80) +
743 READ_WORD(Memory.C4RAM+0x1f86);
744 right = SAR((int32)tan2*y, 16) -
745 READ_WORD(Memory.C4RAM+0x1f80) +
746 READ_WORD(Memory.C4RAM+0x1f86) +
747 READ_WORD(Memory.C4RAM+0x1f93);
749 if(left<0 && right<0){
757 if(left>255 && right>255){
762 } else if(right>255){
771 Memory.C4RAM[j+0x800] = (uint8)left;
772 Memory.C4RAM[j+0x900] = (uint8)right;
778 case 0x25: // Multiply
780 printf("25 Multiply!\n");
781 if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 25 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
784 int32 foo=READ_3WORD(Memory.C4RAM+0x1f80);
785 int32 bar=READ_3WORD(Memory.C4RAM+0x1f83);
787 WRITE_3WORD(Memory.C4RAM+0x1f80, foo);
791 case 0x2d: // Transform Coords
793 // printf("2d Transform Coords!\n");
794 if(Memory.C4RAM[0x1f4d]!=2) printf("$7f4d=%02x, expected 02 for command 2d %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
795 if(READ_3WORD(Memory.C4RAM+0x1f8f)&0xff00ff) printf("2d transform coords: Unexpected value in $7f8f: %06x\n", READ_3WORD(Memory.C4RAM+0x1f8f));
796 if(READ_3WORD(Memory.C4RAM+0x1f8c)!=0x001000) printf("0d transform coords: Unexpected value in $7f8c: %06x\n", READ_3WORD(Memory.C4RAM+0x1f8c));
798 C4WFXVal=READ_WORD(Memory.C4RAM+0x1f81);
799 C4WFYVal=READ_WORD(Memory.C4RAM+0x1f84);
800 C4WFZVal=READ_WORD(Memory.C4RAM+0x1f87);
801 C4WFX2Val=Memory.C4RAM[0x1f89];
802 C4WFY2Val=Memory.C4RAM[0x1f8a];
803 C4WFDist=Memory.C4RAM[0x1f8b];
804 C4WFScale=READ_WORD(Memory.C4RAM+0x1f90);
805 C4TransfWireFrame2();
806 WRITE_WORD(Memory.C4RAM+0x1f80, C4WFXVal);
807 WRITE_WORD(Memory.C4RAM+0x1f83, C4WFYVal);
813 if(Memory.C4RAM[0x1f4d]!=0x0e) printf("$7f4d=%02x, expected 0e for command 40 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
817 for(int i=0; i<0x800; sum+=Memory.C4RAM[i++]);
818 WRITE_WORD(Memory.C4RAM+0x1f80, sum);
824 printf("54 Square!\n");
825 if(Memory.C4RAM[0x1f4d]!=0x0e) printf("$7f4d=%02x, expected 0e for command 54 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
828 int64 a=SAR((int64)READ_3WORD(Memory.C4RAM+0x1f80)<<40, 40);
829 // printf("%08X%08X\n", (uint32)(a>>32), (uint32)(a&0xFFFFFFFF));
831 // printf("%08X%08X\n", (uint32)(a>>32), (uint32)(a&0xFFFFFFFF));
832 WRITE_3WORD(Memory.C4RAM+0x1f83, a);
833 WRITE_3WORD(Memory.C4RAM+0x1f86, (a>>24));
837 case 0x5c: // Immediate Reg
839 printf("5c Immediate Reg!\n");
840 if(Memory.C4RAM[0x1f4d]!=0x0e) printf("$7f4d=%02x, expected 0e for command 5c %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
842 for (i = 0; i < 12 * 4; i++)
843 Memory.C4RAM [i] = C4TestPattern [i];
846 case 0x89: // Immediate ROM
848 printf("89 Immediate ROM!\n");
849 if(Memory.C4RAM[0x1f4d]!=0x0e) printf("$7f4d=%02x, expected 0e for command 89 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
851 Memory.C4RAM [0x1f80] = 0x36;
852 Memory.C4RAM [0x1f81] = 0x43;
853 Memory.C4RAM [0x1f82] = 0x05;
858 printf ("Unknown C4 command (%02x)\n", byte);
863 } else if (Address == 0x7f47) {
865 // printf("C4 load memory %06x => %04x, %04x bytes\n", READ_3WORD(Memory.C4RAM+0x1f40), READ_WORD(Memory.C4RAM+0x1f45), READ_WORD(Memory.C4RAM+0x1f43));
866 if(byte != 0) printf("C4 load: non-0 written to $7f47! Wrote %02x\n", byte);
867 if(READ_WORD(Memory.C4RAM+0x1f45) < 0x6000 || (READ_WORD(Memory.C4RAM+0x1f45) + READ_WORD(Memory.C4RAM+0x1f43)) > 0x6c00) printf("C4 load: Dest unusual! It's %04x\n", READ_WORD(Memory.C4RAM+0x1f45));
869 memmove(Memory.C4RAM+(READ_WORD(Memory.C4RAM+0x1f45)&0x1fff),
870 S9xGetMemPointer(READ_3WORD(Memory.C4RAM+0x1f40)),
871 READ_WORD(Memory.C4RAM+0x1f43));
875 int16 C4SinTable[512] = {
876 0, 402, 804, 1206, 1607, 2009, 2410, 2811,
877 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
878 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
879 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
880 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
881 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
882 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
883 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
884 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
885 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
886 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
887 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
888 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
889 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
890 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
891 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
892 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
893 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
894 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
895 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
896 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
897 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
898 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
899 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
900 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
901 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
902 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
903 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
904 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
905 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
906 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
907 3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
908 0, -402, -804, -1206, -1607, -2009, -2410, -2811,
909 -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
910 -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
911 -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
912 -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
913 -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
914 -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
915 -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
916 -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
917 -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
918 -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
919 -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
920 -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
921 -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
922 -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
923 -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
924 -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
925 -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
926 -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
927 -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
928 -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
929 -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
930 -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
931 -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
932 -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
933 -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
934 -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
935 -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
936 -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
937 -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
938 -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
939 -3211, -2811, -2410, -2009, -1607, -1206, -804, -402
942 int16 C4CosTable[512] = {
943 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
944 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
945 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
946 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
947 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
948 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
949 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
950 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
951 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
952 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
953 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
954 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
955 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
956 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
957 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
958 3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
959 0, -402, -804, -1206, -1607, -2009, -2410, -2811,
960 -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
961 -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
962 -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
963 -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
964 -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
965 -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
966 -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
967 -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
968 -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
969 -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
970 -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
971 -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
972 -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
973 -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
974 -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
975 -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
976 -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
977 -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
978 -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
979 -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
980 -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
981 -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
982 -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
983 -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
984 -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
985 -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
986 -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
987 -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
988 -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
989 -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
990 -3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
991 0, 402, 804, 1206, 1607, 2009, 2410, 2811,
992 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
993 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
994 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
995 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
996 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
997 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
998 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
999 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
1000 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
1001 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
1002 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
1003 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
1004 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
1005 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
1006 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765