1/*****************************************************************************\
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 This file is licensed under the Snes9x License.
4 For further information, consult the LICENSE file in the root directory.
5\*****************************************************************************/
6
7#include <math.h>
8#include "snes9x.h"
9#include "memmap.h"
10#include "sar.h"
11
12static int16 C4SinTable[512] =
13{
14 0, 402, 804, 1206, 1607, 2009, 2410, 2811,
15 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
16 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
17 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
18 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
19 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
20 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
21 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
22 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
23 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
24 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
25 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
26 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
27 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
28 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
29 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765,
30 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
31 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
32 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
33 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
34 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
35 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
36 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
37 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
38 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
39 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
40 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
41 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
42 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
43 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
44 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
45 3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
46 0, -402, -804, -1206, -1607, -2009, -2410, -2811,
47 -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
48 -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
49 -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
50 -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
51 -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
52 -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
53 -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
54 -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
55 -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
56 -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
57 -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
58 -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
59 -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
60 -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
61 -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
62 -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
63 -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
64 -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
65 -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
66 -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
67 -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
68 -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
69 -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
70 -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
71 -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
72 -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
73 -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
74 -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
75 -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
76 -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
77 -3211, -2811, -2410, -2009, -1607, -1206, -804, -402
78};
79
80static int16 C4CosTable[512] =
81{
82 32767, 32765, 32758, 32745, 32728, 32706, 32679, 32647,
83 32610, 32568, 32521, 32469, 32413, 32351, 32285, 32214,
84 32138, 32057, 31971, 31881, 31785, 31685, 31581, 31471,
85 31357, 31237, 31114, 30985, 30852, 30714, 30572, 30425,
86 30273, 30117, 29956, 29791, 29621, 29447, 29269, 29086,
87 28898, 28707, 28511, 28310, 28106, 27897, 27684, 27466,
88 27245, 27020, 26790, 26557, 26319, 26077, 25832, 25583,
89 25330, 25073, 24812, 24547, 24279, 24007, 23732, 23453,
90 23170, 22884, 22594, 22301, 22005, 21706, 21403, 21097,
91 20787, 20475, 20159, 19841, 19519, 19195, 18868, 18537,
92 18204, 17869, 17530, 17189, 16846, 16499, 16151, 15800,
93 15446, 15090, 14732, 14372, 14010, 13645, 13278, 12910,
94 12539, 12167, 11793, 11416, 11039, 10659, 10278, 9896,
95 9512, 9126, 8739, 8351, 7961, 7571, 7179, 6786,
96 6392, 5997, 5602, 5205, 4808, 4409, 4011, 3611,
97 3211, 2811, 2410, 2009, 1607, 1206, 804, 402,
98 0, -402, -804, -1206, -1607, -2009, -2410, -2811,
99 -3211, -3611, -4011, -4409, -4808, -5205, -5602, -5997,
100 -6392, -6786, -7179, -7571, -7961, -8351, -8739, -9126,
101 -9512, -9896, -10278, -10659, -11039, -11416, -11793, -12167,
102 -12539, -12910, -13278, -13645, -14010, -14372, -14732, -15090,
103 -15446, -15800, -16151, -16499, -16846, -17189, -17530, -17869,
104 -18204, -18537, -18868, -19195, -19519, -19841, -20159, -20475,
105 -20787, -21097, -21403, -21706, -22005, -22301, -22594, -22884,
106 -23170, -23453, -23732, -24007, -24279, -24547, -24812, -25073,
107 -25330, -25583, -25832, -26077, -26319, -26557, -26790, -27020,
108 -27245, -27466, -27684, -27897, -28106, -28310, -28511, -28707,
109 -28898, -29086, -29269, -29447, -29621, -29791, -29956, -30117,
110 -30273, -30425, -30572, -30714, -30852, -30985, -31114, -31237,
111 -31357, -31471, -31581, -31685, -31785, -31881, -31971, -32057,
112 -32138, -32214, -32285, -32351, -32413, -32469, -32521, -32568,
113 -32610, -32647, -32679, -32706, -32728, -32745, -32758, -32765,
114 -32767, -32765, -32758, -32745, -32728, -32706, -32679, -32647,
115 -32610, -32568, -32521, -32469, -32413, -32351, -32285, -32214,
116 -32138, -32057, -31971, -31881, -31785, -31685, -31581, -31471,
117 -31357, -31237, -31114, -30985, -30852, -30714, -30572, -30425,
118 -30273, -30117, -29956, -29791, -29621, -29447, -29269, -29086,
119 -28898, -28707, -28511, -28310, -28106, -27897, -27684, -27466,
120 -27245, -27020, -26790, -26557, -26319, -26077, -25832, -25583,
121 -25330, -25073, -24812, -24547, -24279, -24007, -23732, -23453,
122 -23170, -22884, -22594, -22301, -22005, -21706, -21403, -21097,
123 -20787, -20475, -20159, -19841, -19519, -19195, -18868, -18537,
124 -18204, -17869, -17530, -17189, -16846, -16499, -16151, -15800,
125 -15446, -15090, -14732, -14372, -14010, -13645, -13278, -12910,
126 -12539, -12167, -11793, -11416, -11039, -10659, -10278, -9896,
127 -9512, -9126, -8739, -8351, -7961, -7571, -7179, -6786,
128 -6392, -5997, -5602, -5205, -4808, -4409, -4011, -3611,
129 -3211, -2811, -2410, -2009, -1607, -1206, -804, -402,
130 0, 402, 804, 1206, 1607, 2009, 2410, 2811,
131 3211, 3611, 4011, 4409, 4808, 5205, 5602, 5997,
132 6392, 6786, 7179, 7571, 7961, 8351, 8739, 9126,
133 9512, 9896, 10278, 10659, 11039, 11416, 11793, 12167,
134 12539, 12910, 13278, 13645, 14010, 14372, 14732, 15090,
135 15446, 15800, 16151, 16499, 16846, 17189, 17530, 17869,
136 18204, 18537, 18868, 19195, 19519, 19841, 20159, 20475,
137 20787, 21097, 21403, 21706, 22005, 22301, 22594, 22884,
138 23170, 23453, 23732, 24007, 24279, 24547, 24812, 25073,
139 25330, 25583, 25832, 26077, 26319, 26557, 26790, 27020,
140 27245, 27466, 27684, 27897, 28106, 28310, 28511, 28707,
141 28898, 29086, 29269, 29447, 29621, 29791, 29956, 30117,
142 30273, 30425, 30572, 30714, 30852, 30985, 31114, 31237,
143 31357, 31471, 31581, 31685, 31785, 31881, 31971, 32057,
144 32138, 32214, 32285, 32351, 32413, 32469, 32521, 32568,
145 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
146};
147
148static uint8 C4TestPattern[12 * 4] =
149{
150 0x00, 0x00, 0x00, 0xff,
151 0xff, 0xff, 0x00, 0xff,
152 0x00, 0x00, 0x00, 0xff,
153 0xff, 0xff, 0x00, 0x00,
154 0xff, 0xff, 0x00, 0x00,
155 0x80, 0xff, 0xff, 0x7f,
156 0x00, 0x80, 0x00, 0xff,
157 0x7f, 0x00, 0xff, 0x7f,
158 0xff, 0x7f, 0xff, 0xff,
159 0x00, 0x00, 0x01, 0xff,
160 0xff, 0xfe, 0x00, 0x01,
161 0x00, 0xff, 0xfe, 0x00
162};
163
164static void C4ConvOAM (void);
165static void C4DoScaleRotate (int);
166static void C4DrawLine (int32, int32, int16, int32, int32, int16, uint8);
167static void C4DrawWireFrame (void);
168static void C4TransformLines (void);
169static void C4BitPlaneWave (void);
170static void C4SprDisintegrate (void);
171static void C4ProcessSprites (void);
172
173
174static void C4ConvOAM (void)
175{
176 uint8 *OAMptr = Memory.C4RAM + (Memory.C4RAM[0x626] << 2);
177 for (uint8 *i = Memory.C4RAM + 0x1fd; i > OAMptr; i -= 4)
178 *i = 0xe0; // Clear OAM-to-be
179
180 uint8 *OAMptr2;
181 uint16 globalX, globalY;
182 int16 SprX, SprY;
183 uint8 SprName, SprAttr;
184 uint8 SprCount;
185
186 globalX = READ_WORD(Memory.C4RAM + 0x0621);
187 globalY = READ_WORD(Memory.C4RAM + 0x0623);
188 OAMptr2 = Memory.C4RAM + 0x200 + (Memory.C4RAM[0x626] >> 2);
189
190#ifdef DEBUGGER
191 if (Memory.C4RAM[0x625] != 0)
192 printf("$6625=%02x, expected 00\n", Memory.C4RAM[0x625]);
193 if ((Memory.C4RAM[0x626] >> 2) != Memory.C4RAM[0x629])
194 printf("$6629=%02x, expected %02x\n", Memory.C4RAM[0x629], (Memory.C4RAM[0x626] >> 2));
195 if (((uint16) Memory.C4RAM[0x626] << 2) != READ_WORD(Memory.C4RAM + 0x627))
196 printf("$6627=%04x, expected %04x\n", READ_WORD(Memory.C4RAM + 0x627), ((uint16) Memory.C4RAM[0x626] << 2));
197#endif
198
199 if (Memory.C4RAM[0x0620] != 0)
200 {
201 SprCount = 128 - Memory.C4RAM[0x626];
202
203 uint8 offset = (Memory.C4RAM[0x626] & 3) * 2;
204 uint8 *srcptr = Memory.C4RAM + 0x220;
205
206 for (int i = Memory.C4RAM[0x0620]; i > 0 && SprCount > 0; i--, srcptr += 16)
207 {
208 SprX = READ_WORD(srcptr) - globalX;
209 SprY = READ_WORD(srcptr + 2) - globalY;
210 SprName = srcptr[5];
211 SprAttr = srcptr[4] | srcptr[0x06]; // XXX: mask bits?
212
213 uint8 *sprptr = C4GetMemPointer(READ_3WORD(srcptr + 7));
214 if (*sprptr != 0)
215 {
216 int16 X, Y;
217
218 for (int SprCnt = *sprptr++; SprCnt > 0 && SprCount > 0; SprCnt--, sprptr += 4)
219 {
220 X = (int8) sprptr[1];
221 if (SprAttr & 0x40)
222 X = -X - ((sprptr[0] & 0x20) ? 16 : 8); // flip X
223 X += SprX;
224
225 if (X >= -16 && X <= 272)
226 {
227 Y = (int8) sprptr[2];
228 if (SprAttr & 0x80)
229 Y = -Y - ((sprptr[0] & 0x20) ? 16 : 8);
230 Y += SprY;
231
232 if (Y >= -16 && Y <= 224)
233 {
234 OAMptr[0] = X & 0xff;
235 OAMptr[1] = (uint8) Y;
236 OAMptr[2] = SprName + sprptr[3];
237 OAMptr[3] = SprAttr ^ (sprptr[0] & 0xc0); // XXX: Carry from SprName addition?
238
239 *OAMptr2 &= ~(3 << offset);
240 if (X & 0x100)
241 *OAMptr2 |= 1 << offset;
242 if (sprptr[0] & 0x20)
243 *OAMptr2 |= 2 << offset;
244
245 OAMptr += 4;
246 SprCount--;
247
248 offset = (offset + 2) & 6;
249 if (offset == 0)
250 OAMptr2++;
251 }
252 }
253 }
254 }
255 else
256 if (SprCount > 0)
257 {
258 // XXX: Should we be testing -16<=SprX<=272 and -16<=SprY<=224?
259 OAMptr[0] = (uint8) SprX;
260 OAMptr[1] = (uint8) SprY;
261 OAMptr[2] = SprName;
262 OAMptr[3] = SprAttr;
263
264 *OAMptr2 &= ~(3 << offset);
265 if (SprX & 0x100)
266 *OAMptr2 |= 3 << offset;
267 else
268 *OAMptr2 |= 2 << offset;
269
270 OAMptr += 4;
271 SprCount--;
272
273 offset = (offset + 2) & 6;
274 if (offset == 0)
275 OAMptr2++;
276 }
277 }
278 }
279}
280
281static void C4DoScaleRotate (int row_padding)
282{
283 int16 A, B, C, D;
284
285 // Calculate matrix
286 int32 XScale = READ_WORD(Memory.C4RAM + 0x1f8f);
287 if (XScale & 0x8000)
288 XScale = 0x7fff;
289
290 int32 YScale = READ_WORD(Memory.C4RAM + 0x1f92);
291 if (YScale & 0x8000)
292 YScale = 0x7fff;
293
294 if (READ_WORD(Memory.C4RAM + 0x1f80) == 0) // no rotation
295 {
296 // XXX: only do this for C and D?
297 // XXX: and then only when YScale is 0x1000?
298 A = (int16) XScale;
299 B = 0;
300 C = 0;
301 D = (int16) YScale;
302 }
303 else
304 if (READ_WORD(Memory.C4RAM + 0x1f80) == 128) // 90 degree rotation
305 {
306 // XXX: Really do this?
307 A = 0;
308 B = (int16) (-YScale);
309 C = (int16) XScale;
310 D = 0;
311 }
312 else
313 if (READ_WORD(Memory.C4RAM + 0x1f80) == 256) // 180 degree rotation
314 {
315 // XXX: Really do this?
316 A = (int16) (-XScale);
317 B = 0;
318 C = 0;
319 D = (int16) (-YScale);
320 }
321 else
322 if (READ_WORD(Memory.C4RAM + 0x1f80) == 384) // 270 degree rotation
323 {
324 // XXX: Really do this?
325 A = 0;
326 B = (int16) YScale;
327 C = (int16) (-XScale);
328 D = 0;
329 }
330 else
331 {
332 A = (int16) SAR(C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * XScale, 15);
333 B = (int16) (-SAR(C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * YScale, 15));
334 C = (int16) SAR(C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * XScale, 15);
335 D = (int16) SAR(C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * YScale, 15);
336 }
337
338 // Calculate Pixel Resolution
339 uint8 w = Memory.C4RAM[0x1f89] & ~7;
340 uint8 h = Memory.C4RAM[0x1f8c] & ~7;
341
342 //printf("%dx%d XScale=%04x YScale=%04x angle=%03x\n", w, h, XScale, YScale, READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff);
343 //printf("Matrix: [%10g %10g] [%04x %04x]\n", A / 4096.0, B / 4096.0, A & 0xffff, B & 0xffff);
344 //printf(" [%10g %10g] [%04x %04x]\n", C / 4096.0, D / 4096.0, C & 0xffff, D & 0xffff);
345
346 // Clear the output RAM
347 memset(Memory.C4RAM, 0, (w + row_padding / 4) * h / 2);
348
349 int32 Cx = (int16) READ_WORD(Memory.C4RAM + 0x1f83);
350 int32 Cy = (int16) READ_WORD(Memory.C4RAM + 0x1f86);
351
352#ifdef DEBUGGER
353 if (Memory.C4RAM[0x1f97] != 0)
354 printf("$7f97=%02x, expected 00\n", Memory.C4RAM[0x1f97]);
355 if ((Cx & ~1) != w / 2 || (Cy & ~1) != h / 2)
356 printf("Center is not middle of image! (%d, %d) != (%d, %d)\n", Cx, Cy, w / 2, h / 2);
357#endif
358
359 // Calculate start position (i.e. (Ox, Oy) = (0, 0))
360 // The low 12 bits are fractional, so (Cx<<12) gives us the Cx we want in the function.
361 // We do Cx*A etc normally because the matrix parameters already have the fractional parts.
362 int32 LineX = (Cx << 12) - Cx * A - Cx * B;
363 int32 LineY = (Cy << 12) - Cy * C - Cy * D;
364
365 // Start loop
366 uint32 X, Y;
367 uint8 byte;
368 int outidx = 0;
369 uint8 bit = 0x80;
370
371 for (int y = 0; y < h; y++)
372 {
373 X = LineX;
374 Y = LineY;
375
376 for (int x = 0; x < w; x++)
377 {
378 if ((X >> 12) >= w || (Y >> 12) >= h)
379 byte = 0;
380 else
381 {
382 uint32 addr = (Y >> 12) * w + (X >> 12);
383 byte = Memory.C4RAM[0x600 + (addr >> 1)];
384 if (addr & 1)
385 byte >>= 4;
386 }
387
388 // De-bitplanify
389 if (byte & 1)
390 Memory.C4RAM[outidx] |= bit;
391 if (byte & 2)
392 Memory.C4RAM[outidx + 1] |= bit;
393 if (byte & 4)
394 Memory.C4RAM[outidx + 16] |= bit;
395 if (byte & 8)
396 Memory.C4RAM[outidx + 17] |= bit;
397
398 bit >>= 1;
399 if (bit == 0)
400 {
401 bit = 0x80;
402 outidx += 32;
403 }
404
405 X += A; // Add 1 to output x => add an A and a C
406 Y += C;
407 }
408
409 outidx += 2 + row_padding;
410 if (outidx & 0x10)
411 outidx &= ~0x10;
412 else
413 outidx -= w * 4 + row_padding;
414
415 LineX += B; // Add 1 to output y => add a B and a D
416 LineY += D;
417 }
418}
419
420static void C4DrawLine (int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2, uint8 Color)
421{
422 // Transform coordinates
423 C4WFXVal = (int16) X1;
424 C4WFYVal = (int16) Y1;
425 C4WFZVal = Z1;
426 C4WFScale = Memory.C4RAM[0x1f90];
427 C4WFX2Val = Memory.C4RAM[0x1f86];
428 C4WFY2Val = Memory.C4RAM[0x1f87];
429 C4WFDist = Memory.C4RAM[0x1f88];
430 C4TransfWireFrame2();
431 X1 = (C4WFXVal + 48) << 8;
432 Y1 = (C4WFYVal + 48) << 8;
433
434 C4WFXVal = (int16) X2;
435 C4WFYVal = (int16) Y2;
436 C4WFZVal = Z2;
437 C4TransfWireFrame2();
438 X2 = (C4WFXVal + 48) << 8;
439 Y2 = (C4WFYVal + 48) << 8;
440
441 // Get line info
442 C4WFXVal = (int16) (X1 >> 8);
443 C4WFYVal = (int16) (Y1 >> 8);
444 C4WFX2Val = (int16) (X2 >> 8);
445 C4WFY2Val = (int16) (Y2 >> 8);
446 C4CalcWireFrame();
447 X2 = (int16) C4WFXVal;
448 Y2 = (int16) C4WFYVal;
449
450 // Render line
451 for (int i = C4WFDist ? C4WFDist : 1; i > 0; i--)
452 {
453 if (X1 > 0xff && Y1 > 0xff && X1 < 0x6000 && Y1 < 0x6000)
454 {
455 uint16 addr = (((Y1 >> 8) >> 3) << 8) - (((Y1 >> 8) >> 3) << 6) + (((X1 >> 8) >> 3) << 4) + ((Y1 >> 8) & 7) * 2;
456 uint8 bit = 0x80 >> ((X1 >> 8) & 7);
457
458 Memory.C4RAM[addr + 0x300] &= ~bit;
459 Memory.C4RAM[addr + 0x301] &= ~bit;
460 if (Color & 1)
461 Memory.C4RAM[addr + 0x300] |= bit;
462 if (Color & 2)
463 Memory.C4RAM[addr + 0x301] |= bit;
464 }
465
466 X1 += X2;
467 Y1 += Y2;
468 }
469}
470
471static void C4DrawWireFrame (void)
472{
473 uint8 *line = C4GetMemPointer(READ_3WORD(Memory.C4RAM + 0x1f80));
474 uint8 *point1, *point2;
475 int16 X1, Y1, Z1;
476 int16 X2, Y2, Z2;
477 uint8 Color;
478
479#ifdef DEBUGGER
480 if (READ_3WORD(Memory.C4RAM + 0x1f8f) & 0xff00ff)
481 printf("wireframe: Unexpected value in $7f8f: %06x\n", READ_3WORD(Memory.C4RAM + 0x1f8f));
482 if (READ_3WORD(Memory.C4RAM + 0x1fa4) != 0x001000)
483 printf("wireframe: Unexpected value in $7fa4: %06x\n", READ_3WORD(Memory.C4RAM + 0x1fa4));
484#endif
485
486 for (int i = Memory.C4RAM[0x0295]; i > 0; i--, line += 5)
487 {
488 if (line[0] == 0xff && line[1] == 0xff)
489 {
490 uint8 *tmp = line - 5;
491 while (tmp[2] == 0xff && tmp[3] == 0xff)
492 tmp -= 5;
493 point1 = C4GetMemPointer((Memory.C4RAM[0x1f82] << 16) | (tmp[2] << 8) | tmp[3]);
494 }
495 else
496 point1 = C4GetMemPointer((Memory.C4RAM[0x1f82] << 16) | (line[0] << 8) | line[1]);
497
498 point2 = C4GetMemPointer((Memory.C4RAM[0x1f82] << 16) | (line[2] << 8) | line[3]);
499
500 X1 = (point1[0] << 8) | point1[1];
501 Y1 = (point1[2] << 8) | point1[3];
502 Z1 = (point1[4] << 8) | point1[5];
503 X2 = (point2[0] << 8) | point2[1];
504 Y2 = (point2[2] << 8) | point2[3];
505 Z2 = (point2[4] << 8) | point2[5];
506
507 Color = line[4];
508
509 C4DrawLine(X1, Y1, Z1, X2, Y2, Z2, Color);
510 }
511}
512
513static void C4TransformLines (void)
514{
515 C4WFX2Val = Memory.C4RAM[0x1f83];
516 C4WFY2Val = Memory.C4RAM[0x1f86];
517 C4WFDist = Memory.C4RAM[0x1f89];
518 C4WFScale = Memory.C4RAM[0x1f8c];
519
520#ifdef DEBUGGER
521 if (Memory.C4RAM[0x1f8a] != 0x90)
522 printf("lines: $7f8a = %02x, expected 90\n", READ_WORD(Memory.C4RAM + 0x1f8a));
523#endif
524
525 // Transform vertices
526 uint8 *ptr = Memory.C4RAM;
527
528 for (int i = READ_WORD(Memory.C4RAM + 0x1f80); i > 0; i--, ptr += 0x10)
529 {
530 C4WFXVal = READ_WORD(ptr + 1);
531 C4WFYVal = READ_WORD(ptr + 5);
532 C4WFZVal = READ_WORD(ptr + 9);
533 C4TransfWireFrame();
534
535 // Displace
536 WRITE_WORD(ptr + 1, C4WFXVal + 0x80);
537 WRITE_WORD(ptr + 5, C4WFYVal + 0x50);
538 }
539
540 WRITE_WORD(Memory.C4RAM + 0x600, 23);
541 WRITE_WORD(Memory.C4RAM + 0x602, 0x60);
542 WRITE_WORD(Memory.C4RAM + 0x605, 0x40);
543 WRITE_WORD(Memory.C4RAM + 0x600 + 8, 23);
544 WRITE_WORD(Memory.C4RAM + 0x602 + 8, 0x60);
545 WRITE_WORD(Memory.C4RAM + 0x605 + 8, 0x40);
546
547 ptr = Memory.C4RAM + 0xb02;
548 uint8 *ptr2 = Memory.C4RAM;
549
550 for (int i = READ_WORD(Memory.C4RAM + 0xb00); i > 0; i--, ptr += 2, ptr2 += 8)
551 {
552 C4WFXVal = READ_WORD(Memory.C4RAM + (ptr[0] << 4) + 1);
553 C4WFYVal = READ_WORD(Memory.C4RAM + (ptr[0] << 4) + 5);
554 C4WFX2Val = READ_WORD(Memory.C4RAM + (ptr[1] << 4) + 1);
555 C4WFY2Val = READ_WORD(Memory.C4RAM + (ptr[1] << 4) + 5);
556 C4CalcWireFrame();
557
558 WRITE_WORD(ptr2 + 0x600, C4WFDist ? C4WFDist : 1);
559 WRITE_WORD(ptr2 + 0x602, C4WFXVal);
560 WRITE_WORD(ptr2 + 0x605, C4WFYVal);
561 }
562}
563
564static void C4BitPlaneWave (void)
565{
566 static uint16 bmpdata[] =
567 {
568 0x0000, 0x0002, 0x0004, 0x0006, 0x0008, 0x000A, 0x000C, 0x000E,
569 0x0200, 0x0202, 0x0204, 0x0206, 0x0208, 0x020A, 0x020C, 0x020E,
570 0x0400, 0x0402, 0x0404, 0x0406, 0x0408, 0x040A, 0x040C, 0x040E,
571 0x0600, 0x0602, 0x0604, 0x0606, 0x0608, 0x060A, 0x060C, 0x060E,
572 0x0800, 0x0802, 0x0804, 0x0806, 0x0808, 0x080A, 0x080C, 0x080E
573 };
574
575 uint8 *dst = Memory.C4RAM;
576 uint32 waveptr = Memory.C4RAM[0x1f83];
577 uint16 mask1 = 0xc0c0;
578 uint16 mask2 = 0x3f3f;
579
580#ifdef DEBUGGER
581 if (READ_3WORD(Memory.C4RAM + 0x1f80) != Memory.C4RAM[waveptr + 0xb00])
582 printf("$7f80=%06x, expected %02x\n", READ_3WORD(Memory.C4RAM + 0x1f80), Memory.C4RAM[waveptr + 0xb00]);
583#endif
584
585 for (int j = 0; j < 0x10; j++)
586 {
587 do
588 {
589 int16 height = -((int8) Memory.C4RAM[waveptr + 0xb00]) - 16;
590
591 for (int i = 0; i < 40; i++)
592 {
593 uint16 tmp = READ_WORD(dst + bmpdata[i]) & mask2;
594 if (height >= 0)
595 {
596 if (height < 8)
597 tmp |= mask1 & READ_WORD(Memory.C4RAM + 0xa00 + height * 2);
598 else
599 tmp |= mask1 & 0xff00;
600 }
601
602 WRITE_WORD(dst + bmpdata[i], tmp);
603
604 height++;
605 }
606
607 waveptr = (waveptr + 1) & 0x7f;
608 mask1 = (mask1 >> 2) | (mask1 << 6);
609 mask2 = (mask2 >> 2) | (mask2 << 6);
610 }
611 while (mask1 != 0xc0c0);
612
613 dst += 16;
614
615 do
616 {
617 int16 height = -((int8) Memory.C4RAM[waveptr + 0xb00]) - 16;
618
619 for (int i = 0; i < 40; i++)
620 {
621 uint16 tmp = READ_WORD(dst + bmpdata[i]) & mask2;
622 if (height >= 0)
623 {
624 if (height < 8)
625 tmp |= mask1 & READ_WORD(Memory.C4RAM + 0xa10 + height * 2);
626 else
627 tmp |= mask1 & 0xff00;
628 }
629
630 WRITE_WORD(dst + bmpdata[i], tmp);
631
632 height++;
633 }
634
635 waveptr = (waveptr + 1) & 0x7f;
636 mask1 = (mask1 >> 2) | (mask1 << 6);
637 mask2 = (mask2 >> 2) | (mask2 << 6);
638 }
639 while (mask1 != 0xc0c0);
640
641 dst += 16;
642 }
643}
644
645static void C4SprDisintegrate (void)
646{
647 uint8 *src;
648 uint8 width, height;
649 uint32 StartX, StartY;
650 int32 scaleX, scaleY;
651 int32 Cx, Cy;
652
653 width = Memory.C4RAM[0x1f89];
654 height = Memory.C4RAM[0x1f8c];
655 Cx = (int16) READ_WORD(Memory.C4RAM + 0x1f80);
656 Cy = (int16) READ_WORD(Memory.C4RAM + 0x1f83);
657
658#ifdef DEBUGGER
659 if ((Cx & ~1) != width / 2 || (Cy & ~1) != height / 2)
660 printf("Center is not middle of image for disintegrate! (%d, %d) != (%d, %d)\n", Cx, Cy, width / 2, height / 2);
661#endif
662
663 scaleX = (int16) READ_WORD(Memory.C4RAM + 0x1f86);
664 scaleY = (int16) READ_WORD(Memory.C4RAM + 0x1f8f);
665 StartX = -Cx * scaleX + (Cx << 8);
666 StartY = -Cy * scaleY + (Cy << 8);
667
668 src = Memory.C4RAM + 0x600;
669
670 memset(Memory.C4RAM, 0, width * height / 2);
671
672 for (uint32 y = StartY, i = 0; i < height; i++, y += scaleY)
673 {
674 for (uint32 x = StartX, j = 0; j < width; j++, x += scaleX)
675 {
676 if ((x >> 8) < width && (y >> 8) < height && (y >> 8) * width + (x >> 8) < 0x2000)
677 {
678 uint8 pixel = (j & 1) ? (*src >> 4) : *src;
679 int idx = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
680 uint8 mask = 0x80 >> ((x >> 8) & 7);
681
682 if (pixel & 1)
683 Memory.C4RAM[idx] |= mask;
684 if (pixel & 2)
685 Memory.C4RAM[idx + 1] |= mask;
686 if (pixel & 4)
687 Memory.C4RAM[idx + 16] |= mask;
688 if (pixel & 8)
689 Memory.C4RAM[idx + 17] |= mask;
690 }
691
692 if (j & 1)
693 src++;
694 }
695 }
696}
697
698static void C4ProcessSprites (void)
699{
700 switch (Memory.C4RAM[0x1f4d])
701 {
702 case 0x00: // Build OAM
703 #ifdef DEBUGGER
704 //printf("00 00 Build OAM!\n");
705 #endif
706 C4ConvOAM();
707 break;
708
709 case 0x03: // Scale/Rotate
710 #ifdef DEBUGGER
711 //printf("00 03 Scale/Rotate!\n");
712 #endif
713 C4DoScaleRotate(0);
714 break;
715
716 case 0x05: // Transform Lines
717 #ifdef DEBUGGER
718 //printf("00 05 Transform Lines!\n");
719 #endif
720 C4TransformLines();
721 break;
722
723 case 0x07: // Scale/Rotate
724 #ifdef DEBUGGER
725 //printf("00 07 Scale/Rotate!\n");
726 #endif
727 C4DoScaleRotate(64);
728 break;
729
730 case 0x08: // Draw wireframe
731 #ifdef DEBUGGER
732 //printf("00 08 Draw wireframe!\n");
733 #endif
734 C4DrawWireFrame();
735 break;
736
737 case 0x0b: // Disintegrate
738 #ifdef DEBUGGER
739 //printf("00 0b Disintegrate!\n");
740 #endif
741 C4SprDisintegrate();
742 break;
743
744 case 0x0c: // Wave
745 #ifdef DEBUGGER
746 //printf("00 0b Wave!\n");
747 #endif
748 C4BitPlaneWave();
749 break;
750
751 default:
752 #ifdef DEBUGGER
753 printf("Unknown C4 sprite command (%02x)\n", Memory.C4RAM[0x1f4d]);
754 #endif
755 break;
756 }
757}
758
759void S9xInitC4 (void)
760{
761 // Stupid zsnes code, we can't do the logical thing without breaking savestates
762 // Memory.C4RAM = &Memory.FillRAM [0x6000];
763 memset(Memory.C4RAM, 0, 0x2000);
764}
765
766uint8 S9xGetC4 (uint16 Address)
767{
768 if (Address == 0x7f5e)
769 return (0);
770
771 return (Memory.C4RAM[Address - 0x6000]);
772}
773
774void S9xSetC4 (uint8 byte, uint16 Address)
775{
776 Memory.C4RAM[Address - 0x6000] = byte;
777
778 if (Address == 0x7f4f)
779 {
780 if (Memory.C4RAM[0x1f4d] == 0x0e && byte < 0x40 && (byte & 3) == 0)
781 {
782 #ifdef DEBUGGER
783 printf("Test command %02x 0e used!\n", byte);
784 #endif
785 Memory.C4RAM[0x1f80] = byte >> 2;
786 }
787 else
788 {
789 switch (byte)
790 {
791 case 0x00: // Sprite
792 #ifdef DEBUGGER
793 //printf("00 Sprite!\n");
794 #endif
795 C4ProcessSprites();
796 break;
797
798 case 0x01: // Draw wireframe
799 #ifdef DEBUGGER
800 //printf("01 Draw wireframe!\n");
801 if (Memory.C4RAM[0x1f4d] != 8)
802 printf("$7f4d=%02x, expected 08 for command 01 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
803 #endif
804 memset(Memory.C4RAM + 0x300, 0, 16 * 12 * 3 * 4);
805 C4DrawWireFrame();
806 break;
807
808 case 0x05: // Propulsion (?)
809 {
810 #ifdef DEBUGGER
811 //printf("05 Propulsion (?)!\n");
812 if (Memory.C4RAM[0x1f4d] != 2)
813 printf("$7f4d=%02x, expected 02 for command 05 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
814 #endif
815 int32 tmp = 0x10000;
816 if (READ_WORD(Memory.C4RAM + 0x1f83))
817 tmp = SAR((tmp / READ_WORD(Memory.C4RAM + 0x1f83)) * READ_WORD(Memory.C4RAM + 0x1f81), 8);
818
819 WRITE_WORD(Memory.C4RAM + 0x1f80, (uint16) tmp);
820 break;
821 }
822
823 case 0x0d: // Set vector length
824 #ifdef DEBUGGER
825 //printf("0d Set vector length!\n");
826 if (Memory.C4RAM[0x1f4d] != 2)
827 printf("$7f4d=%02x, expected 02 for command 0d %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
828 #endif
829 C41FXVal = READ_WORD(Memory.C4RAM + 0x1f80);
830 C41FYVal = READ_WORD(Memory.C4RAM + 0x1f83);
831 C41FDistVal = READ_WORD(Memory.C4RAM + 0x1f86);
832 C4Op0D();
833 WRITE_WORD(Memory.C4RAM + 0x1f89, C41FXVal);
834 WRITE_WORD(Memory.C4RAM + 0x1f8c, C41FYVal);
835 break;
836
837 case 0x10: // Polar to rectangluar
838 {
839 #ifdef DEBUGGER
840 //printf("10 Polar->Rect!\n");
841 if (Memory.C4RAM[0x1f4d] != 2)
842 printf("$7f4d=%02x, expected 02 for command 10 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
843 #endif
844 int32 tmp;
845 int32 r1;
846 r1 = READ_WORD(Memory.C4RAM + 0x1f83);
847 if (r1 & 0x8000)
848 r1 |= ~0x7fff;
849 else
850 r1 &= 0x7fff;
851
852 tmp = SAR(r1 * C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 16);
853 WRITE_3WORD(Memory.C4RAM + 0x1f86, tmp);
854 tmp = SAR(r1 * C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 16);
855 WRITE_3WORD(Memory.C4RAM + 0x1f89, (tmp - SAR(tmp, 6)));
856 break;
857 }
858
859 case 0x13: // Polar to rectangluar
860 {
861 #ifdef DEBUGGER
862 //printf("13 Polar->Rect!\n");
863 if (Memory.C4RAM[0x1f4d] != 2)
864 printf("$7f4d=%02x, expected 02 for command 13 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
865 #endif
866 int32 tmp;
867 tmp = SAR((int32) READ_WORD(Memory.C4RAM + 0x1f83) * C4CosTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 8);
868 WRITE_3WORD(Memory.C4RAM + 0x1f86, tmp);
869 tmp = SAR((int32) READ_WORD(Memory.C4RAM + 0x1f83) * C4SinTable[READ_WORD(Memory.C4RAM + 0x1f80) & 0x1ff] * 2, 8);
870 WRITE_3WORD(Memory.C4RAM + 0x1f89, tmp);
871 break;
872 }
873
874 case 0x15: // Pythagorean
875 #ifdef DEBUGGER
876 //printf("15 Pythagorean!\n");
877 if (Memory.C4RAM[0x1f4d] != 2)
878 printf("$7f4d=%02x, expected 02 for command 15 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
879 #endif
880 C41FXVal = READ_WORD(Memory.C4RAM + 0x1f80);
881 C41FYVal = READ_WORD(Memory.C4RAM + 0x1f83);
882 //C4Op15(); // optimized to:
883 C41FDist = (int16) sqrt((double) C41FXVal * C41FXVal + (double) C41FYVal * C41FYVal);
884 WRITE_WORD(Memory.C4RAM + 0x1f80, C41FDist);
885 break;
886
887 case 0x1f: // atan
888 #ifdef DEBUGGER
889 //printf("1f atan!\n");
890 if (Memory.C4RAM[0x1f4d] != 2)
891 printf("$7f4d=%02x, expected 02 for command 1f %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
892 #endif
893 C41FXVal = READ_WORD(Memory.C4RAM + 0x1f80);
894 C41FYVal = READ_WORD(Memory.C4RAM + 0x1f83);
895 C4Op1F();
896 WRITE_WORD(Memory.C4RAM + 0x1f86, C41FAngleRes);
897 break;
898
899 case 0x22: // Trapezoid
900 {
901 #ifdef DEBUGGER
902 //printf("22 Trapezoid!\n");
903 if (Memory.C4RAM[0x1f4d] != 2)
904 printf("$7f4d=%02x, expected 02 for command 22 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
905 #endif
906 int16 angle1 = READ_WORD(Memory.C4RAM + 0x1f8c) & 0x1ff;
907 int16 angle2 = READ_WORD(Memory.C4RAM + 0x1f8f) & 0x1ff;
908
909 #ifdef DEBUGGER
910 if (C4CosTable[angle1] == 0)
911 fprintf(stderr, "22 Trapezoid: Invalid tangent! angle1=%d\n", angle1);
912 if (C4CosTable[angle2] == 0)
913 fprintf(stderr, "22 Trapezoid: Invalid tangent! angle2=%d\n", angle2);
914 #endif
915
916 int32 tan1 = (C4CosTable[angle1] != 0) ? ((((int32) C4SinTable[angle1]) << 16) / C4CosTable[angle1]) : 0x80000000;
917 int32 tan2 = (C4CosTable[angle2] != 0) ? ((((int32) C4SinTable[angle2]) << 16) / C4CosTable[angle2]) : 0x80000000;
918
919 int16 y = READ_WORD(Memory.C4RAM + 0x1f83) - READ_WORD(Memory.C4RAM + 0x1f89);
920 int16 left, right;
921
922 for (int j = 0; j < 225; j++)
923 {
924 if (y >= 0)
925 {
926 left = SAR((int32) tan1 * y, 16) - READ_WORD(Memory.C4RAM + 0x1f80) + READ_WORD(Memory.C4RAM + 0x1f86);
927 right = SAR((int32) tan2 * y, 16) - READ_WORD(Memory.C4RAM + 0x1f80) + READ_WORD(Memory.C4RAM + 0x1f86) + READ_WORD(Memory.C4RAM + 0x1f93);
928
929 if (left < 0 && right < 0)
930 {
931 left = 1;
932 right = 0;
933 }
934 else
935 if (left < 0)
936 left = 0;
937 else
938 if (right < 0)
939 right = 0;
940
941 if (left > 255 && right > 255)
942 {
943 left = 255;
944 right = 254;
945 }
946 else
947 if (left > 255)
948 left = 255;
949 else
950 if (right > 255)
951 right = 255;
952 }
953 else
954 {
955 left = 1;
956 right = 0;
957 }
958
959 Memory.C4RAM[j + 0x800] = (uint8) left;
960 Memory.C4RAM[j + 0x900] = (uint8) right;
961
962 y++;
963 }
964
965 break;
966 }
967
968 case 0x25: // Multiply
969 {
970 #ifdef DEBUGGER
971 //printf("25 Multiply!\n");
972 if (Memory.C4RAM[0x1f4d] != 2)
973 printf("$7f4d=%02x, expected 02 for command 25 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
974 #endif
975 int32 foo = READ_3WORD(Memory.C4RAM + 0x1f80);
976 int32 bar = READ_3WORD(Memory.C4RAM + 0x1f83);
977 foo *= bar;
978 WRITE_3WORD(Memory.C4RAM + 0x1f80, foo);
979 break;
980 }
981
982 case 0x2d: // Transform Coords
983 #ifdef DEBUGGER
984 //printf("2d Transform Coords!\n");
985 if (Memory.C4RAM[0x1f4d] != 2)
986 printf("$7f4d=%02x, expected 02 for command 2d %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
987 if (READ_3WORD(Memory.C4RAM + 0x1f8f) & 0xff00ff)
988 printf("2d transform coords: Unexpected value in $7f8f: %06x\n", READ_3WORD(Memory.C4RAM + 0x1f8f));
989 if (READ_3WORD(Memory.C4RAM + 0x1f8c) != 0x001000)
990 printf("0d transform coords: Unexpected value in $7f8c: %06x\n", READ_3WORD(Memory.C4RAM + 0x1f8c));
991 #endif
992 C4WFXVal = READ_WORD(Memory.C4RAM + 0x1f81);
993 C4WFYVal = READ_WORD(Memory.C4RAM + 0x1f84);
994 C4WFZVal = READ_WORD(Memory.C4RAM + 0x1f87);
995 C4WFX2Val = Memory.C4RAM[0x1f89];
996 C4WFY2Val = Memory.C4RAM[0x1f8a];
997 C4WFDist = Memory.C4RAM[0x1f8b];
998 C4WFScale = READ_WORD(Memory.C4RAM + 0x1f90);
999 C4TransfWireFrame2();
1000 WRITE_WORD(Memory.C4RAM + 0x1f80, C4WFXVal);
1001 WRITE_WORD(Memory.C4RAM + 0x1f83, C4WFYVal);
1002 break;
1003
1004 case 0x40: // Sum
1005 {
1006 #ifdef DEBUGGER
1007 //printf("40 Sum!\n");
1008 if (Memory.C4RAM[0x1f4d] != 0x0e)
1009 printf("$7f4d=%02x, expected 0e for command 40 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
1010 #endif
1011 uint16 sum = 0;
1012 for (int i = 0; i < 0x800; sum += Memory.C4RAM[i++]) ;
1013 WRITE_WORD(Memory.C4RAM + 0x1f80, sum);
1014 break;
1015 }
1016
1017 case 0x54: // Square
1018 {
1019 #ifdef DEBUGGER
1020 //printf("54 Square!\n");
1021 if (Memory.C4RAM[0x1f4d] != 0x0e)
1022 printf("$7f4d=%02x, expected 0e for command 54 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
1023 #endif
1024 int64 a = (int64)READ_3WORD(Memory.C4RAM + 0x1f80);
1025 a |= 0xffffffffff000000 * ((a >> 23) & 1);
1026 //printf("%08X%08X\n", (uint32) (a>>32), (uint32) (a&0xFFFFFFFF));
1027 a *= a;
1028 //printf("%08X%08X\n", (uint32) (a>>32), (uint32) (a&0xFFFFFFFF));
1029 WRITE_3WORD(Memory.C4RAM + 0x1f83, a);
1030 WRITE_3WORD(Memory.C4RAM + 0x1f86, (a >> 24));
1031 break;
1032 }
1033
1034 case 0x5c: // Immediate Reg
1035 #ifdef DEBUGGER
1036 //printf("5c Immediate Reg!\n");
1037 if (Memory.C4RAM[0x1f4d] != 0x0e)
1038 printf("$7f4d=%02x, expected 0e for command 5c %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
1039 #endif
1040 for (int i = 0; i < 12 * 4; i++)
1041 Memory.C4RAM[i] = C4TestPattern[i];
1042 break;
1043
1044 case 0x89: // Immediate ROM
1045 #ifdef DEBUGGER
1046 //printf("89 Immediate ROM!\n");
1047 if (Memory.C4RAM[0x1f4d] != 0x0e)
1048 printf("$7f4d=%02x, expected 0e for command 89 %02x\n", Memory.C4RAM[0x1f4d], Memory.C4RAM[0x1f4d]);
1049 #endif
1050 Memory.C4RAM[0x1f80] = 0x36;
1051 Memory.C4RAM[0x1f81] = 0x43;
1052 Memory.C4RAM[0x1f82] = 0x05;
1053 break;
1054
1055 default:
1056 #ifdef DEBUGGER
1057 printf("Unknown C4 command (%02x)\n", byte);
1058 #endif
1059 break;
1060 }
1061 }
1062 }
1063 else
1064 if (Address == 0x7f47)
1065 {
1066 #ifdef DEBUGGER
1067 //printf("C4 load memory %06x => %04x, %04x bytes\n", READ_3WORD(Memory.C4RAM + 0x1f40), READ_WORD(Memory.C4RAM + 0x1f45), READ_WORD(Memory.C4RAM + 0x1f43));
1068 if (byte != 0)
1069 printf("C4 load: non-0 written to $7f47! Wrote %02x\n", byte);
1070 if (READ_WORD(Memory.C4RAM + 0x1f45) < 0x6000 || (READ_WORD(Memory.C4RAM + 0x1f45) + READ_WORD(Memory.C4RAM + 0x1f43)) > 0x6c00)
1071 printf("C4 load: Dest unusual! It's %04x\n", READ_WORD(Memory.C4RAM + 0x1f45));
1072 #endif
1073 memmove(Memory.C4RAM + (READ_WORD(Memory.C4RAM + 0x1f45) & 0x1fff), C4GetMemPointer(READ_3WORD(Memory.C4RAM + 0x1f40)), READ_WORD(Memory.C4RAM + 0x1f43));
1074 }
1075}
1076