1/*****
2 * SPC7110 emulator - version 0.03 (2008-08-10)
3 * Copyright (c) 2008, byuu and neviksti
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * The software is provided "as is" and the author disclaims all warranties
10 * with regard to this software including all implied warranties of
11 * merchantibility and fitness, in no event shall the author be liable for
12 * any special, direct, indirect, or consequential damages or any damages
13 * whatsoever resulting from loss of use, data or profits, whether in an
14 * action of contract, negligence or other tortious action, arising out of
15 * or in connection with the use or performance of this software.
16 *****/
17
18
19#ifdef _SPC7110EMU_CPP_
20
21uint8 SPC7110Decomp::read() {
22 if(decomp_buffer_length == 0) {
23 //decompress at least (decomp_buffer_size / 2) bytes to the buffer
24 switch(decomp_mode) {
25 case 0: mode0(false); break;
26 case 1: mode1(false); break;
27 case 2: mode2(false); break;
28 default: return 0x00;
29 }
30 }
31
32 uint8 data = decomp_buffer[decomp_buffer_rdoffset++];
33 decomp_buffer_rdoffset &= decomp_buffer_size - 1;
34 decomp_buffer_length--;
35 return data;
36}
37
38void SPC7110Decomp::write(uint8 data) {
39 decomp_buffer[decomp_buffer_wroffset++] = data;
40 decomp_buffer_wroffset &= decomp_buffer_size - 1;
41 decomp_buffer_length++;
42}
43
44uint8 SPC7110Decomp::dataread() {
45 unsigned size = memory_cartrom_size() > 0x500000 ? memory_cartrom_size() - 0x200000 : memory_cartrom_size() - 0x100000;
46 while(decomp_offset >= size) decomp_offset -= size;
47 return memory_cartrom_read(0x100000 + decomp_offset++);
48}
49
50void SPC7110Decomp::init(unsigned mode, unsigned offset, unsigned index) {
51 decomp_mode = mode;
52 decomp_offset = offset;
53
54 decomp_buffer_rdoffset = 0;
55 decomp_buffer_wroffset = 0;
56 decomp_buffer_length = 0;
57
58 //reset context states
59 for(unsigned i = 0; i < 32; i++) {
60 context[i].index = 0;
61 context[i].invert = 0;
62 }
63
64 switch(decomp_mode) {
65 case 0: mode0(true); break;
66 case 1: mode1(true); break;
67 case 2: mode2(true); break;
68 }
69
70 //decompress up to requested output data index
71 while(index--) read();
72}
73
74//
75
76void SPC7110Decomp::mode0(bool init) {
77 static uint8 val, in, span;
78 static int out, inverts, lps, in_count;
79
80 if(init == true) {
81 out = inverts = lps = 0;
82 span = 0xff;
83 val = dataread();
84 in = dataread();
85 in_count = 8;
86 return;
87 }
88
89 while(decomp_buffer_length < (decomp_buffer_size >> 1)) {
90 for(unsigned bit = 0; bit < 8; bit++) {
91 //get context
92 uint8 mask = (1 << (bit & 3)) - 1;
93 uint8 con = mask + ((inverts & mask) ^ (lps & mask));
94 if(bit > 3) con += 15;
95
96 //get prob and mps
97 unsigned prob = probability(con);
98 unsigned mps = (((out >> 15) & 1) ^ context[con].invert);
99
100 //get bit
101 unsigned flag_lps;
102 if(val <= span - prob) { //mps
103 span = span - prob;
104 out = (out << 1) + mps;
105 flag_lps = 0;
106 } else { //lps
107 val = val - (span - (prob - 1));
108 span = prob - 1;
109 out = (out << 1) + 1 - mps;
110 flag_lps = 1;
111 }
112
113 //renormalize
114 unsigned shift = 0;
115 while(span < 0x7f) {
116 shift++;
117
118 span = (span << 1) + 1;
119 val = (val << 1) + (in >> 7);
120
121 in <<= 1;
122 if(--in_count == 0) {
123 in = dataread();
124 in_count = 8;
125 }
126 }
127
128 //update processing info
129 lps = (lps << 1) + flag_lps;
130 inverts = (inverts << 1) + context[con].invert;
131
132 //update context state
133 if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;
134 if(flag_lps) context[con].index = next_lps(con);
135 else if(shift) context[con].index = next_mps(con);
136 }
137
138 //save byte
139 write(out);
140 }
141}
142
143void SPC7110Decomp::mode1(bool init) {
144 static unsigned pixelorder[4], realorder[4];
145 static uint8 in, val, span;
146 static int out, inverts, lps, in_count;
147
148 if(init == true) {
149 for(unsigned i = 0; i < 4; i++) pixelorder[i] = i;
150 out = inverts = lps = 0;
151 span = 0xff;
152 val = dataread();
153 in = dataread();
154 in_count = 8;
155 return;
156 }
157
158 while(decomp_buffer_length < (decomp_buffer_size >> 1)) {
159 for(unsigned pixel = 0; pixel < 8; pixel++) {
160 //get first symbol context
161 unsigned a = ((out >> (1 * 2)) & 3);
162 unsigned b = ((out >> (7 * 2)) & 3);
163 unsigned c = ((out >> (8 * 2)) & 3);
164 unsigned con = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
165
166 //update pixel order
167 unsigned m, n;
168 for(m = 0; m < 4; m++) if(pixelorder[m] == a) break;
169 for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1];
170 pixelorder[0] = a;
171
172 //calculate the real pixel order
173 for(m = 0; m < 4; m++) realorder[m] = pixelorder[m];
174
175 //rotate reference pixel c value to top
176 for(m = 0; m < 4; m++) if(realorder[m] == c) break;
177 for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
178 realorder[0] = c;
179
180 //rotate reference pixel b value to top
181 for(m = 0; m < 4; m++) if(realorder[m] == b) break;
182 for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
183 realorder[0] = b;
184
185 //rotate reference pixel a value to top
186 for(m = 0; m < 4; m++) if(realorder[m] == a) break;
187 for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
188 realorder[0] = a;
189
190 //get 2 symbols
191 for(unsigned bit = 0; bit < 2; bit++) {
192 //get prob
193 unsigned prob = probability(con);
194
195 //get symbol
196 unsigned flag_lps;
197 if(val <= span - prob) { //mps
198 span = span - prob;
199 flag_lps = 0;
200 } else { //lps
201 val = val - (span - (prob - 1));
202 span = prob - 1;
203 flag_lps = 1;
204 }
205
206 //renormalize
207 unsigned shift = 0;
208 while(span < 0x7f) {
209 shift++;
210
211 span = (span << 1) + 1;
212 val = (val << 1) + (in >> 7);
213
214 in <<= 1;
215 if(--in_count == 0) {
216 in = dataread();
217 in_count = 8;
218 }
219 }
220
221 //update processing info
222 lps = (lps << 1) + flag_lps;
223 inverts = (inverts << 1) + context[con].invert;
224
225 //update context state
226 if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;
227 if(flag_lps) context[con].index = next_lps(con);
228 else if(shift) context[con].index = next_mps(con);
229
230 //get next context
231 con = 5 + (con << 1) + ((lps ^ inverts) & 1);
232 }
233
234 //get pixel
235 b = realorder[(lps ^ inverts) & 3];
236 out = (out << 2) + b;
237 }
238
239 //turn pixel data into bitplanes
240 unsigned data = morton_2x8(out);
241 write(data >> 8);
242 write(data >> 0);
243 }
244}
245
246void SPC7110Decomp::mode2(bool init) {
247 static unsigned pixelorder[16], realorder[16];
248 static uint8 bitplanebuffer[16], buffer_index;
249 static uint8 in, val, span;
250 static int out0, out1, inverts, lps, in_count;
251
252 if(init == true) {
253 for(unsigned i = 0; i < 16; i++) pixelorder[i] = i;
254 buffer_index = 0;
255 out0 = out1 = inverts = lps = 0;
256 span = 0xff;
257 val = dataread();
258 in = dataread();
259 in_count = 8;
260 return;
261 }
262
263 while(decomp_buffer_length < (decomp_buffer_size >> 1)) {
264 for(unsigned pixel = 0; pixel < 8; pixel++) {
265 //get first symbol context
266 unsigned a = ((out0 >> (0 * 4)) & 15);
267 unsigned b = ((out0 >> (7 * 4)) & 15);
268 unsigned c = ((out1 >> (0 * 4)) & 15);
269 unsigned con = 0;
270 unsigned refcon = (a == b) ? (b != c) : (b == c) ? 2 : 4 - (a == c);
271
272 //update pixel order
273 unsigned m, n;
274 for(m = 0; m < 16; m++) if(pixelorder[m] == a) break;
275 for(n = m; n > 0; n--) pixelorder[n] = pixelorder[n - 1];
276 pixelorder[0] = a;
277
278 //calculate the real pixel order
279 for(m = 0; m < 16; m++) realorder[m] = pixelorder[m];
280
281 //rotate reference pixel c value to top
282 for(m = 0; m < 16; m++) if(realorder[m] == c) break;
283 for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
284 realorder[0] = c;
285
286 //rotate reference pixel b value to top
287 for(m = 0; m < 16; m++) if(realorder[m] == b) break;
288 for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
289 realorder[0] = b;
290
291 //rotate reference pixel a value to top
292 for(m = 0; m < 16; m++) if(realorder[m] == a) break;
293 for(n = m; n > 0; n--) realorder[n] = realorder[n - 1];
294 realorder[0] = a;
295
296 //get 4 symbols
297 for(unsigned bit = 0; bit < 4; bit++) {
298 //get prob
299 unsigned prob = probability(con);
300
301 //get symbol
302 unsigned flag_lps;
303 if(val <= span - prob) { //mps
304 span = span - prob;
305 flag_lps = 0;
306 } else { //lps
307 val = val - (span - (prob - 1));
308 span = prob - 1;
309 flag_lps = 1;
310 }
311
312 //renormalize
313 unsigned shift = 0;
314 while(span < 0x7f) {
315 shift++;
316
317 span = (span << 1) + 1;
318 val = (val << 1) + (in >> 7);
319
320 in <<= 1;
321 if(--in_count == 0) {
322 in = dataread();
323 in_count = 8;
324 }
325 }
326
327 //update processing info
328 lps = (lps << 1) + flag_lps;
329 unsigned invertbit = context[con].invert;
330 inverts = (inverts << 1) + invertbit;
331
332 //update context state
333 if(flag_lps & toggle_invert(con)) context[con].invert ^= 1;
334 if(flag_lps) context[con].index = next_lps(con);
335 else if(shift) context[con].index = next_mps(con);
336
337 //get next context
338 con = mode2_context_table[con][flag_lps ^ invertbit] + (con == 1 ? refcon : 0);
339 }
340
341 //get pixel
342 b = realorder[(lps ^ inverts) & 0x0f];
343 out1 = (out1 << 4) + ((out0 >> 28) & 0x0f);
344 out0 = (out0 << 4) + b;
345 }
346
347 //convert pixel data into bitplanes
348 unsigned data = morton_4x8(out0);
349 write(data >> 24);
350 write(data >> 16);
351 bitplanebuffer[buffer_index++] = data >> 8;
352 bitplanebuffer[buffer_index++] = data >> 0;
353
354 if(buffer_index == 16) {
355 for(unsigned i = 0; i < 16; i++) write(bitplanebuffer[i]);
356 buffer_index = 0;
357 }
358 }
359}
360
361//
362
363const uint8 SPC7110Decomp::evolution_table[53][4] = {
364//{ prob, nextlps, nextmps, toggle invert },
365
366 { 0x5a, 1, 1, 1 },
367 { 0x25, 6, 2, 0 },
368 { 0x11, 8, 3, 0 },
369 { 0x08, 10, 4, 0 },
370 { 0x03, 12, 5, 0 },
371 { 0x01, 15, 5, 0 },
372
373 { 0x5a, 7, 7, 1 },
374 { 0x3f, 19, 8, 0 },
375 { 0x2c, 21, 9, 0 },
376 { 0x20, 22, 10, 0 },
377 { 0x17, 23, 11, 0 },
378 { 0x11, 25, 12, 0 },
379 { 0x0c, 26, 13, 0 },
380 { 0x09, 28, 14, 0 },
381 { 0x07, 29, 15, 0 },
382 { 0x05, 31, 16, 0 },
383 { 0x04, 32, 17, 0 },
384 { 0x03, 34, 18, 0 },
385 { 0x02, 35, 5, 0 },
386
387 { 0x5a, 20, 20, 1 },
388 { 0x48, 39, 21, 0 },
389 { 0x3a, 40, 22, 0 },
390 { 0x2e, 42, 23, 0 },
391 { 0x26, 44, 24, 0 },
392 { 0x1f, 45, 25, 0 },
393 { 0x19, 46, 26, 0 },
394 { 0x15, 25, 27, 0 },
395 { 0x11, 26, 28, 0 },
396 { 0x0e, 26, 29, 0 },
397 { 0x0b, 27, 30, 0 },
398 { 0x09, 28, 31, 0 },
399 { 0x08, 29, 32, 0 },
400 { 0x07, 30, 33, 0 },
401 { 0x05, 31, 34, 0 },
402 { 0x04, 33, 35, 0 },
403 { 0x04, 33, 36, 0 },
404 { 0x03, 34, 37, 0 },
405 { 0x02, 35, 38, 0 },
406 { 0x02, 36, 5, 0 },
407
408 { 0x58, 39, 40, 1 },
409 { 0x4d, 47, 41, 0 },
410 { 0x43, 48, 42, 0 },
411 { 0x3b, 49, 43, 0 },
412 { 0x34, 50, 44, 0 },
413 { 0x2e, 51, 45, 0 },
414 { 0x29, 44, 46, 0 },
415 { 0x25, 45, 24, 0 },
416
417 { 0x56, 47, 48, 1 },
418 { 0x4f, 47, 49, 0 },
419 { 0x47, 48, 50, 0 },
420 { 0x41, 49, 51, 0 },
421 { 0x3c, 50, 52, 0 },
422 { 0x37, 51, 43, 0 },
423};
424
425const uint8 SPC7110Decomp::mode2_context_table[32][2] = {
426//{ next 0, next 1 },
427
428 { 1, 2 },
429
430 { 3, 8 },
431 { 13, 14 },
432
433 { 15, 16 },
434 { 17, 18 },
435 { 19, 20 },
436 { 21, 22 },
437 { 23, 24 },
438 { 25, 26 },
439 { 25, 26 },
440 { 25, 26 },
441 { 25, 26 },
442 { 25, 26 },
443 { 27, 28 },
444 { 29, 30 },
445
446 { 31, 31 },
447 { 31, 31 },
448 { 31, 31 },
449 { 31, 31 },
450 { 31, 31 },
451 { 31, 31 },
452 { 31, 31 },
453 { 31, 31 },
454 { 31, 31 },
455 { 31, 31 },
456 { 31, 31 },
457 { 31, 31 },
458 { 31, 31 },
459 { 31, 31 },
460 { 31, 31 },
461 { 31, 31 },
462
463 { 31, 31 },
464};
465
466uint8 SPC7110Decomp::probability (unsigned n) { return evolution_table[context[n].index][0]; }
467uint8 SPC7110Decomp::next_lps (unsigned n) { return evolution_table[context[n].index][1]; }
468uint8 SPC7110Decomp::next_mps (unsigned n) { return evolution_table[context[n].index][2]; }
469uint8 SPC7110Decomp::toggle_invert(unsigned n) { return evolution_table[context[n].index][3]; }
470
471unsigned SPC7110Decomp::morton_2x8(unsigned data) {
472 //reverse morton lookup: de-interleave two 8-bit values
473 //15, 13, 11, 9, 7, 5, 3, 1 -> 15- 8
474 //14, 12, 10, 8, 6, 4, 2, 0 -> 7- 0
475 return morton16[0][(data >> 0) & 255] + morton16[1][(data >> 8) & 255];
476}
477
478unsigned SPC7110Decomp::morton_4x8(unsigned data) {
479 //reverse morton lookup: de-interleave four 8-bit values
480 //31, 27, 23, 19, 15, 11, 7, 3 -> 31-24
481 //30, 26, 22, 18, 14, 10, 6, 2 -> 23-16
482 //29, 25, 21, 17, 13, 9, 5, 1 -> 15- 8
483 //28, 24, 20, 16, 12, 8, 4, 0 -> 7- 0
484 return morton32[0][(data >> 0) & 255] + morton32[1][(data >> 8) & 255]
485 + morton32[2][(data >> 16) & 255] + morton32[3][(data >> 24) & 255];
486}
487
488//
489
490void SPC7110Decomp::reset() {
491 //mode 3 is invalid; this is treated as a special case to always return 0x00
492 //set to mode 3 so that reading decomp port before starting first decomp will return 0x00
493 decomp_mode = 3;
494
495 decomp_buffer_rdoffset = 0;
496 decomp_buffer_wroffset = 0;
497 decomp_buffer_length = 0;
498}
499
500SPC7110Decomp::SPC7110Decomp() {
501 decomp_buffer = new uint8[decomp_buffer_size];
502 reset();
503
504 //initialize reverse morton lookup tables
505 for(unsigned i = 0; i < 256; i++) {
506 #define map(x, y) (((i >> x) & 1) << y)
507 //2x8-bit
508 morton16[1][i] = map(7, 15) + map(6, 7) + map(5, 14) + map(4, 6)
509 + map(3, 13) + map(2, 5) + map(1, 12) + map(0, 4);
510 morton16[0][i] = map(7, 11) + map(6, 3) + map(5, 10) + map(4, 2)
511 + map(3, 9) + map(2, 1) + map(1, 8) + map(0, 0);
512 //4x8-bit
513 morton32[3][i] = map(7, 31) + map(6, 23) + map(5, 15) + map(4, 7)
514 + map(3, 30) + map(2, 22) + map(1, 14) + map(0, 6);
515 morton32[2][i] = map(7, 29) + map(6, 21) + map(5, 13) + map(4, 5)
516 + map(3, 28) + map(2, 20) + map(1, 12) + map(0, 4);
517 morton32[1][i] = map(7, 27) + map(6, 19) + map(5, 11) + map(4, 3)
518 + map(3, 26) + map(2, 18) + map(1, 10) + map(0, 2);
519 morton32[0][i] = map(7, 25) + map(6, 17) + map(5, 9) + map(4, 1)
520 + map(3, 24) + map(2, 16) + map(1, 8) + map(0, 0);
521 #undef map
522 }
523}
524
525SPC7110Decomp::~SPC7110Decomp() {
526 delete[] decomp_buffer;
527}
528
529#endif
530