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