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 "snes9x.h"
8#include "memmap.h"
9
10static void DSP2_Op01 (void);
11static void DSP2_Op03 (void);
12static void DSP2_Op05 (void);
13static void DSP2_Op06 (void);
14static void DSP2_Op09 (void);
15static void DSP2_Op0D (void);
16
17
18// convert bitmap to bitplane tile
19static void DSP2_Op01 (void)
20{
21 // Op01 size is always 32 bytes input and output
22 // The hardware does strange things if you vary the size
23
24 uint8 c0, c1, c2, c3;
25 uint8 *p1 = DSP2.parameters;
26 uint8 *p2a = DSP2.output;
27 uint8 *p2b = DSP2.output + 16; // halfway
28
29 // Process 8 blocks of 4 bytes each
30
31 for (int j = 0; j < 8; j++)
32 {
33 c0 = *p1++;
34 c1 = *p1++;
35 c2 = *p1++;
36 c3 = *p1++;
37
38 *p2a++ = (c0 & 0x10) << 3 |
39 (c0 & 0x01) << 6 |
40 (c1 & 0x10) << 1 |
41 (c1 & 0x01) << 4 |
42 (c2 & 0x10) >> 1 |
43 (c2 & 0x01) << 2 |
44 (c3 & 0x10) >> 3 |
45 (c3 & 0x01);
46
47 *p2a++ = (c0 & 0x20) << 2 |
48 (c0 & 0x02) << 5 |
49 (c1 & 0x20) |
50 (c1 & 0x02) << 3 |
51 (c2 & 0x20) >> 2 |
52 (c2 & 0x02) << 1 |
53 (c3 & 0x20) >> 4 |
54 (c3 & 0x02) >> 1;
55
56 *p2b++ = (c0 & 0x40) << 1 |
57 (c0 & 0x04) << 4 |
58 (c1 & 0x40) >> 1 |
59 (c1 & 0x04) << 2 |
60 (c2 & 0x40) >> 3 |
61 (c2 & 0x04) |
62 (c3 & 0x40) >> 5 |
63 (c3 & 0x04) >> 2;
64
65 *p2b++ = (c0 & 0x80) |
66 (c0 & 0x08) << 3 |
67 (c1 & 0x80) >> 2 |
68 (c1 & 0x08) << 1 |
69 (c2 & 0x80) >> 4 |
70 (c2 & 0x08) >> 1 |
71 (c3 & 0x80) >> 6 |
72 (c3 & 0x08) >> 3;
73 }
74}
75
76// set transparent color
77static void DSP2_Op03 (void)
78{
79 DSP2.Op05Transparent = DSP2.parameters[0];
80}
81
82// replace bitmap using transparent color
83static void DSP2_Op05 (void)
84{
85 // Overlay bitmap with transparency.
86 // Input:
87 //
88 // Bitmap 1: i[0] <=> i[size-1]
89 // Bitmap 2: i[size] <=> i[2*size-1]
90 //
91 // Output:
92 //
93 // Bitmap 3: o[0] <=> o[size-1]
94 //
95 // Processing:
96 //
97 // Process all 4-bit pixels (nibbles) in the bitmap
98 //
99 // if ( BM2_pixel == transparent_color )
100 // pixelout = BM1_pixel
101 // else
102 // pixelout = BM2_pixel
103
104 // The max size bitmap is limited to 255 because the size parameter is a byte
105 // I think size=0 is an error. The behavior of the chip on size=0 is to
106 // return the last value written to DR if you read DR on Op05 with
107 // size = 0. I don't think it's worth implementing this quirk unless it's
108 // proven necessary.
109
110 uint8 color;
111 uint8 c1, c2;
112 uint8 *p1 = DSP2.parameters;
113 uint8 *p2 = DSP2.parameters + DSP2.Op05Len;
114 uint8 *p3 = DSP2.output;
115
116 color = DSP2.Op05Transparent & 0x0f;
117
118 for (int32 n = 0; n < DSP2.Op05Len; n++)
119 {
120 c1 = *p1++;
121 c2 = *p2++;
122 *p3++ = (((c2 >> 4) == color) ? c1 & 0xf0: c2 & 0xf0) | (((c2 & 0x0f) == color) ? c1 & 0x0f: c2 & 0x0f);
123 }
124}
125
126// reverse bitmap
127static void DSP2_Op06 (void)
128{
129 // Input:
130 // size
131 // bitmap
132
133 for (int32 i = 0, j = DSP2.Op06Len - 1; i < DSP2.Op06Len; i++, j--)
134 DSP2.output[j] = (DSP2.parameters[i] << 4) | (DSP2.parameters[i] >> 4);
135}
136
137// multiply
138static void DSP2_Op09 (void)
139{
140 DSP2.Op09Word1 = DSP2.parameters[0] | (DSP2.parameters[1] << 8);
141 DSP2.Op09Word2 = DSP2.parameters[2] | (DSP2.parameters[3] << 8);
142
143 uint32 temp = DSP2.Op09Word1 * DSP2.Op09Word2;
144 DSP2.output[0] = temp & 0xFF;
145 DSP2.output[1] = (temp >> 8) & 0xFF;
146 DSP2.output[2] = (temp >> 16) & 0xFF;
147 DSP2.output[3] = (temp >> 24) & 0xFF;
148}
149
150// scale bitmap
151static void DSP2_Op0D (void)
152{
153 // Bit accurate hardware algorithm - uses fixed point math
154 // This should match the DSP2 Op0D output exactly
155 // I wouldn't recommend using this unless you're doing hardware debug.
156 // In some situations it has small visual artifacts that
157 // are not readily apparent on a TV screen but show up clearly
158 // on a monitor. Use Overload's scaling instead.
159 // This is for hardware verification testing.
160 //
161 // One note: the HW can do odd byte scaling but since we divide
162 // by two to get the count of bytes this won't work well for
163 // odd byte scaling (in any of the current algorithm implementations).
164 // So far I haven't seen Dungeon Master use it.
165 // If it does we can adjust the parameters and code to work with it
166
167 uint32 multiplier; // Any size int >= 32-bits
168 uint32 pixloc; // match size of multiplier
169 uint8 pixelarray[512];
170
171 if (DSP2.Op0DInLen <= DSP2.Op0DOutLen)
172 multiplier = 0x10000; // In our self defined fixed point 0x10000 == 1
173 else
174 multiplier = (DSP2.Op0DInLen << 17) / ((DSP2.Op0DOutLen << 1) + 1);
175
176 pixloc = 0;
177
178 for (int32 i = 0; i < DSP2.Op0DOutLen * 2; i++)
179 {
180 int32 j = pixloc >> 16;
181
182 if (j & 1)
183 pixelarray[i] = DSP2.parameters[j >> 1] & 0x0f;
184 else
185 pixelarray[i] = (DSP2.parameters[j >> 1] & 0xf0) >> 4;
186
187 pixloc += multiplier;
188 }
189
190 for (int32 i = 0; i < DSP2.Op0DOutLen; i++)
191 DSP2.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1];
192}
193
194/*
195static void DSP2_Op0D (void)
196{
197 // Overload's algorithm - use this unless doing hardware testing
198
199 // One note: the HW can do odd byte scaling but since we divide
200 // by two to get the count of bytes this won't work well for
201 // odd byte scaling (in any of the current algorithm implementations).
202 // So far I haven't seen Dungeon Master use it.
203 // If it does we can adjust the parameters and code to work with it
204
205 int32 pixel_offset;
206 uint8 pixelarray[512];
207
208 for (int32 i = 0; i < DSP2.Op0DOutLen * 2; i++)
209 {
210 pixel_offset = (i * DSP2.Op0DInLen) / DSP2.Op0DOutLen;
211
212 if ((pixel_offset & 1) == 0)
213 pixelarray[i] = DSP2.parameters[pixel_offset >> 1] >> 4;
214 else
215 pixelarray[i] = DSP2.parameters[pixel_offset >> 1] & 0x0f;
216 }
217
218 for (int32 i = 0; i < DSP2.Op0DOutLen; i++)
219 DSP2.output[i] = (pixelarray[i << 1] << 4) | pixelarray[(i << 1) + 1];
220}
221*/
222
223void DSP2SetByte (uint8 byte, uint16 address)
224{
225 if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000))
226 {
227 if (DSP2.waiting4command)
228 {
229 DSP2.command = byte;
230 DSP2.in_index = 0;
231 DSP2.waiting4command = FALSE;
232
233 switch (byte)
234 {
235 case 0x01: DSP2.in_count = 32; break;
236 case 0x03: DSP2.in_count = 1; break;
237 case 0x05: DSP2.in_count = 1; break;
238 case 0x06: DSP2.in_count = 1; break;
239 case 0x09: DSP2.in_count = 4; break;
240 case 0x0D: DSP2.in_count = 2; break;
241 default:
242 #ifdef DEBUGGER
243 //printf("Op%02X\n", byte);
244 #endif
245 case 0x0f: DSP2.in_count = 0; break;
246 }
247 }
248 else
249 {
250 DSP2.parameters[DSP2.in_index] = byte;
251 DSP2.in_index++;
252 }
253
254 if (DSP2.in_count == DSP2.in_index)
255 {
256 DSP2.waiting4command = TRUE;
257 DSP2.out_index = 0;
258
259 switch (DSP2.command)
260 {
261 case 0x01:
262 DSP2.out_count = 32;
263 DSP2_Op01();
264 break;
265
266 case 0x03:
267 DSP2_Op03();
268 break;
269
270 case 0x05:
271 if (DSP2.Op05HasLen)
272 {
273 DSP2.Op05HasLen = FALSE;
274 DSP2.out_count = DSP2.Op05Len;
275 DSP2_Op05();
276 }
277 else
278 {
279 DSP2.Op05Len = DSP2.parameters[0];
280 DSP2.in_index = 0;
281 DSP2.in_count = 2 * DSP2.Op05Len;
282 DSP2.Op05HasLen = TRUE;
283 if (byte)
284 DSP2.waiting4command = FALSE;
285 }
286
287 break;
288
289 case 0x06:
290 if (DSP2.Op06HasLen)
291 {
292 DSP2.Op06HasLen = FALSE;
293 DSP2.out_count = DSP2.Op06Len;
294 DSP2_Op06();
295 }
296 else
297 {
298 DSP2.Op06Len = DSP2.parameters[0];
299 DSP2.in_index = 0;
300 DSP2.in_count = DSP2.Op06Len;
301 DSP2.Op06HasLen = TRUE;
302 if (byte)
303 DSP2.waiting4command = FALSE;
304 }
305
306 break;
307
308 case 0x09:
309 DSP2.out_count = 4;
310 DSP2_Op09();
311 break;
312
313 case 0x0D:
314 if (DSP2.Op0DHasLen)
315 {
316 DSP2.Op0DHasLen = FALSE;
317 DSP2.out_count = DSP2.Op0DOutLen;
318 DSP2_Op0D();
319 }
320 else
321 {
322 DSP2.Op0DInLen = DSP2.parameters[0];
323 DSP2.Op0DOutLen = DSP2.parameters[1];
324 DSP2.in_index = 0;
325 DSP2.in_count = (DSP2.Op0DInLen + 1) >> 1;
326 DSP2.Op0DHasLen = TRUE;
327 if (byte)
328 DSP2.waiting4command = FALSE;
329 }
330
331 break;
332
333 case 0x0f:
334 default:
335 break;
336 }
337 }
338 }
339}
340
341uint8 DSP2GetByte (uint16 address)
342{
343 uint8 t;
344
345 if ((address & 0xf000) == 0x6000 || (address >= 0x8000 && address < 0xc000))
346 {
347 if (DSP2.out_count)
348 {
349 t = (uint8) DSP2.output[DSP2.out_index];
350 DSP2.out_index++;
351 if (DSP2.out_count == DSP2.out_index)
352 DSP2.out_count = 0;
353 }
354 else
355 t = 0xff;
356 }
357 else
358 t = 0x80;
359
360 return (t);
361}
362