Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmeteor/source/bios.cpp
2 views
1
// Meteor - A Nintendo Gameboy Advance emulator
2
// Copyright (C) 2009-2011 Philippe Daouadi
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
#include "ameteor/bios.hpp"
18
#include "ameteor/cpu.hpp"
19
#include "ameteor/memory.hpp"
20
21
#include "globals.hpp"
22
23
#include "debug.hpp"
24
25
#include <cmath>
26
27
namespace AMeteor
28
{
29
namespace Bios
30
{
31
static const int16_t sineTable[256] = {
32
(int16_t)0x0000, (int16_t)0x0192, (int16_t)0x0323, (int16_t)0x04B5,
33
(int16_t)0x0645, (int16_t)0x07D5, (int16_t)0x0964, (int16_t)0x0AF1,
34
(int16_t)0x0C7C, (int16_t)0x0E05, (int16_t)0x0F8C, (int16_t)0x1111,
35
(int16_t)0x1294, (int16_t)0x1413, (int16_t)0x158F, (int16_t)0x1708,
36
(int16_t)0x187D, (int16_t)0x19EF, (int16_t)0x1B5D, (int16_t)0x1CC6,
37
(int16_t)0x1E2B, (int16_t)0x1F8B, (int16_t)0x20E7, (int16_t)0x223D,
38
(int16_t)0x238E, (int16_t)0x24DA, (int16_t)0x261F, (int16_t)0x275F,
39
(int16_t)0x2899, (int16_t)0x29CD, (int16_t)0x2AFA, (int16_t)0x2C21,
40
(int16_t)0x2D41, (int16_t)0x2E5A, (int16_t)0x2F6B, (int16_t)0x3076,
41
(int16_t)0x3179, (int16_t)0x3274, (int16_t)0x3367, (int16_t)0x3453,
42
(int16_t)0x3536, (int16_t)0x3612, (int16_t)0x36E5, (int16_t)0x37AF,
43
(int16_t)0x3871, (int16_t)0x392A, (int16_t)0x39DA, (int16_t)0x3A82,
44
(int16_t)0x3B20, (int16_t)0x3BB6, (int16_t)0x3C42, (int16_t)0x3CC5,
45
(int16_t)0x3D3E, (int16_t)0x3DAE, (int16_t)0x3E14, (int16_t)0x3E71,
46
(int16_t)0x3EC5, (int16_t)0x3F0E, (int16_t)0x3F4E, (int16_t)0x3F84,
47
(int16_t)0x3FB1, (int16_t)0x3FD3, (int16_t)0x3FEC, (int16_t)0x3FFB,
48
(int16_t)0x4000, (int16_t)0x3FFB, (int16_t)0x3FEC, (int16_t)0x3FD3,
49
(int16_t)0x3FB1, (int16_t)0x3F84, (int16_t)0x3F4E, (int16_t)0x3F0E,
50
(int16_t)0x3EC5, (int16_t)0x3E71, (int16_t)0x3E14, (int16_t)0x3DAE,
51
(int16_t)0x3D3E, (int16_t)0x3CC5, (int16_t)0x3C42, (int16_t)0x3BB6,
52
(int16_t)0x3B20, (int16_t)0x3A82, (int16_t)0x39DA, (int16_t)0x392A,
53
(int16_t)0x3871, (int16_t)0x37AF, (int16_t)0x36E5, (int16_t)0x3612,
54
(int16_t)0x3536, (int16_t)0x3453, (int16_t)0x3367, (int16_t)0x3274,
55
(int16_t)0x3179, (int16_t)0x3076, (int16_t)0x2F6B, (int16_t)0x2E5A,
56
(int16_t)0x2D41, (int16_t)0x2C21, (int16_t)0x2AFA, (int16_t)0x29CD,
57
(int16_t)0x2899, (int16_t)0x275F, (int16_t)0x261F, (int16_t)0x24DA,
58
(int16_t)0x238E, (int16_t)0x223D, (int16_t)0x20E7, (int16_t)0x1F8B,
59
(int16_t)0x1E2B, (int16_t)0x1CC6, (int16_t)0x1B5D, (int16_t)0x19EF,
60
(int16_t)0x187D, (int16_t)0x1708, (int16_t)0x158F, (int16_t)0x1413,
61
(int16_t)0x1294, (int16_t)0x1111, (int16_t)0x0F8C, (int16_t)0x0E05,
62
(int16_t)0x0C7C, (int16_t)0x0AF1, (int16_t)0x0964, (int16_t)0x07D5,
63
(int16_t)0x0645, (int16_t)0x04B5, (int16_t)0x0323, (int16_t)0x0192,
64
(int16_t)0x0000, (int16_t)0xFE6E, (int16_t)0xFCDD, (int16_t)0xFB4B,
65
(int16_t)0xF9BB, (int16_t)0xF82B, (int16_t)0xF69C, (int16_t)0xF50F,
66
(int16_t)0xF384, (int16_t)0xF1FB, (int16_t)0xF074, (int16_t)0xEEEF,
67
(int16_t)0xED6C, (int16_t)0xEBED, (int16_t)0xEA71, (int16_t)0xE8F8,
68
(int16_t)0xE783, (int16_t)0xE611, (int16_t)0xE4A3, (int16_t)0xE33A,
69
(int16_t)0xE1D5, (int16_t)0xE075, (int16_t)0xDF19, (int16_t)0xDDC3,
70
(int16_t)0xDC72, (int16_t)0xDB26, (int16_t)0xD9E1, (int16_t)0xD8A1,
71
(int16_t)0xD767, (int16_t)0xD633, (int16_t)0xD506, (int16_t)0xD3DF,
72
(int16_t)0xD2BF, (int16_t)0xD1A6, (int16_t)0xD095, (int16_t)0xCF8A,
73
(int16_t)0xCE87, (int16_t)0xCD8C, (int16_t)0xCC99, (int16_t)0xCBAD,
74
(int16_t)0xCACA, (int16_t)0xC9EE, (int16_t)0xC91B, (int16_t)0xC851,
75
(int16_t)0xC78F, (int16_t)0xC6D6, (int16_t)0xC626, (int16_t)0xC57E,
76
(int16_t)0xC4E0, (int16_t)0xC44A, (int16_t)0xC3BE, (int16_t)0xC33B,
77
(int16_t)0xC2C2, (int16_t)0xC252, (int16_t)0xC1EC, (int16_t)0xC18F,
78
(int16_t)0xC13B, (int16_t)0xC0F2, (int16_t)0xC0B2, (int16_t)0xC07C,
79
(int16_t)0xC04F, (int16_t)0xC02D, (int16_t)0xC014, (int16_t)0xC005,
80
(int16_t)0xC000, (int16_t)0xC005, (int16_t)0xC014, (int16_t)0xC02D,
81
(int16_t)0xC04F, (int16_t)0xC07C, (int16_t)0xC0B2, (int16_t)0xC0F2,
82
(int16_t)0xC13B, (int16_t)0xC18F, (int16_t)0xC1EC, (int16_t)0xC252,
83
(int16_t)0xC2C2, (int16_t)0xC33B, (int16_t)0xC3BE, (int16_t)0xC44A,
84
(int16_t)0xC4E0, (int16_t)0xC57E, (int16_t)0xC626, (int16_t)0xC6D6,
85
(int16_t)0xC78F, (int16_t)0xC851, (int16_t)0xC91B, (int16_t)0xC9EE,
86
(int16_t)0xCACA, (int16_t)0xCBAD, (int16_t)0xCC99, (int16_t)0xCD8C,
87
(int16_t)0xCE87, (int16_t)0xCF8A, (int16_t)0xD095, (int16_t)0xD1A6,
88
(int16_t)0xD2BF, (int16_t)0xD3DF, (int16_t)0xD506, (int16_t)0xD633,
89
(int16_t)0xD767, (int16_t)0xD8A1, (int16_t)0xD9E1, (int16_t)0xDB26,
90
(int16_t)0xDC72, (int16_t)0xDDC3, (int16_t)0xDF19, (int16_t)0xE075,
91
(int16_t)0xE1D5, (int16_t)0xE33A, (int16_t)0xE4A3, (int16_t)0xE611,
92
(int16_t)0xE783, (int16_t)0xE8F8, (int16_t)0xEA71, (int16_t)0xEBED,
93
(int16_t)0xED6C, (int16_t)0xEEEF, (int16_t)0xF074, (int16_t)0xF1FB,
94
(int16_t)0xF384, (int16_t)0xF50F, (int16_t)0xF69C, (int16_t)0xF82B,
95
(int16_t)0xF9BB, (int16_t)0xFB4B, (int16_t)0xFCDD, (int16_t)0xFE6E
96
};
97
98
void Bios000h ()
99
{
100
debug("Bios entry point");
101
R(13) = 0x03007FE0;
102
R(15) = 0x08000004;
103
CPU.SwitchToMode(Cpu::M_IRQ);
104
R(13) = 0x03007FA0;
105
CPU.SwitchToMode(Cpu::M_SYS);
106
R(13) = 0x03007F00;
107
ICPSR.irq_d = false;
108
IO.Write8(Io::POSTFLG, 0x01);
109
}
110
111
void Bios008h ()
112
{
113
// if we are here, we should be in SVC mode (0x13)
114
// store the spsr, r11, r12 and r14 on the stack
115
uint32_t baseadd = R(13) - (4*4), add = (baseadd & 0xFFFFFFFC);
116
MEM.Write32(add , SPSR);
117
MEM.Write32(add += 4, R(11));
118
MEM.Write32(add += 4, R(12));
119
MEM.Write32(add + 4, R(14));
120
R(13) = baseadd;
121
122
uint8_t swiComment = MEM.Read8(R(14) - 2);
123
124
// put 0x1F in cpsr but don't touch to the irq disable bit
125
CPU.SwitchToMode(0x1F);
126
CPSR = 0x0000001F | (CPSR & (0x1 << 7));
127
CPU.UpdateICpsr();
128
129
// store r11 and r14 (of the user mode) on the stack
130
baseadd = R(13) - (2*4); add = (baseadd & 0xFFFFFFFC);
131
MEM.Write32(add , R(11));
132
MEM.Write32(add + 4, R(14));
133
R(13) = baseadd;
134
135
R(14) = 0x168;
136
137
debug("Software IRQ start");
138
switch (swiComment)
139
{
140
case 0x04:
141
IntrWait();
142
break;
143
case 0x05:
144
VBlankIntrWait();
145
break;
146
default:
147
met_abort("not implemented : " << (int)swiComment);
148
break;
149
}
150
}
151
152
void Bios168h ()
153
{
154
uint32_t add = R(13) & 0xFFFFFFFC;
155
R( 2) = MEM.Read32(add );
156
R(14) = MEM.Read32(add += 4);
157
R(13) += 2*4;
158
159
// SVC with fiq and irq disabled
160
CPU.SwitchToMode(0x13); // SVC
161
CPSR = 0x000000D3;
162
CPU.UpdateICpsr();
163
add = R(13) & 0xFFFFFFFC;
164
165
SPSR = MEM.Read32(add);
166
167
R(11) = MEM.Read32(add += 4);
168
R(12) = MEM.Read32(add += 4);
169
R(14) = MEM.Read32(add + 4);
170
R(13) += 4*4;
171
172
// FIXME this works (for thumb) ?
173
if (CPU.Spsr().b.thumb)
174
R(15) = R(14) + 2;
175
else
176
R(15) = R(14) + 4;
177
178
debug("Software IRQ end");
179
CPU.SwitchModeBack();
180
}
181
182
void Bios018h ()
183
{
184
debug("IRQ start");
185
// stmfd r13!,r0-r3,r12,r14
186
uint32_t baseadd = R(13) - (6*4), add = (baseadd & 0xFFFFFFFC);
187
MEM.Write32(add , R( 0));
188
MEM.Write32(add += 4, R( 1));
189
MEM.Write32(add += 4, R( 2));
190
MEM.Write32(add += 4, R( 3));
191
MEM.Write32(add += 4, R(12));
192
MEM.Write32(add + 4, R(14));
193
194
R(13) = baseadd;
195
196
// add r14,r15,0h
197
R(14) = 0x00000130;
198
199
R(15) = MEM.Read32(0x03007FFC) + 4;
200
}
201
202
void Bios130h ()
203
{
204
debug("IRQ end");
205
// ldmfd r13!,r0-r3,r12,r14
206
uint32_t add = R(13) & 0xFFFFFFFC;
207
R( 0) = MEM.Read32(add );
208
R( 1) = MEM.Read32(add += 4);
209
R( 2) = MEM.Read32(add += 4);
210
R( 3) = MEM.Read32(add += 4);
211
R(12) = MEM.Read32(add += 4);
212
R(14) = MEM.Read32(add + 4);
213
214
R(13) += 6*4;
215
216
// subs r15,r14,4h
217
R(15) = R(14);
218
if (CPU.Spsr().b.thumb)
219
R(15) -= 2;
220
221
CPU.SwitchModeBack();
222
223
// XXX FIXME, usefull ? test on breath of fire !
224
/*if (FLAG_T)
225
R(15) &= 0xFFFFFFFE;
226
else
227
R(15) &= 0xFFFFFFFC;*/
228
}
229
230
void SoftReset ()
231
{
232
CPU.SoftReset ();
233
if (MEM.Read8(0x03007FFA))
234
R(15) = 0x02000004;
235
else
236
R(15) = 0x08000004;
237
238
MEM.SoftReset ();
239
}
240
241
void RegisterRamReset ()
242
{
243
IO.Write16(Io::DISPCNT, 0x0080);
244
uint8_t flagRes = R(0);
245
if (flagRes & (0x1 ))
246
MEM.ClearWbram();
247
if (flagRes & (0x1 << 1))
248
MEM.ClearWcram();
249
if (flagRes & (0x1 << 2))
250
MEM.ClearPalette();
251
if (flagRes & (0x1 << 3))
252
MEM.ClearVram();
253
if (flagRes & (0x1 << 4))
254
MEM.ClearOam();
255
if (flagRes & (0x1 << 5))
256
IO.ClearSio ();
257
if (flagRes & (0x1 << 6))
258
IO.ClearSound ();
259
if (flagRes & (0x1 << 7))
260
IO.ClearOthers ();
261
}
262
263
void Halt ()
264
{
265
IO.Write8(Io::HALTCNT, 0);
266
}
267
268
void IntrWait ()
269
{
270
// FIXME ugly
271
R(13) -= 8;
272
MEM.Write32(R(13) & 0xFFFFFFFC, R(4));
273
MEM.Write32((R(13)+4) & 0xFFFFFFFC, R(14));
274
275
uint16_t& intFlags = *(uint16_t*)MEM.GetRealAddress(0x03007FF8);
276
277
if (R(0))
278
{
279
if (intFlags & R(1))
280
intFlags = (intFlags & R(1)) ^ intFlags;
281
else
282
FLAG_Z = 1;
283
IO.Write16(Io::IME, 1);
284
}
285
286
IO.Write8(Io::HALTCNT, 0);
287
288
// return address (after IRQ)
289
R(15) = 0x33C;
290
291
debug("IntrWait start");
292
}
293
294
void Bios338h ()
295
{
296
uint16_t& intFlags = *(uint16_t*)MEM.GetRealAddress(0x03007FF8);
297
298
if (!(intFlags & R(1)))
299
{
300
IO.Write16(Io::IME, 1);
301
IO.Write8(Io::HALTCNT, 0);
302
}
303
else
304
{
305
intFlags = (intFlags & R(1)) ^ intFlags;
306
IO.Write16(Io::IME, 1);
307
308
// FIXME ugly
309
R(4) = MEM.Read32(R(13) & 0xFFFFFFFC);
310
R(14) = MEM.Read32((R(13)+4) & 0xFFFFFFFC);
311
R(13) += 8;
312
313
// should lead to 0x168
314
R(15) = R(14)+4;
315
}
316
317
debug("IntWait end");
318
}
319
320
void VBlankIntrWait ()
321
{
322
R(0) = 1;
323
R(1) = 1;
324
IntrWait();
325
}
326
327
void Div ()
328
{
329
if (!R(1))
330
met_abort("Div by 0");
331
332
int32_t number = R(0), denom = R(1);
333
334
int32_t div = number / denom;
335
R(0) = div;
336
R(1) = number % denom;
337
R(3) = div < 0 ? -div : div;
338
}
339
340
void DivArm ()
341
{
342
uint32_t tmp = R(0);
343
R(0) = R(1);
344
R(1) = tmp;
345
Div();
346
}
347
348
void Sqrt ()
349
{
350
R(0) = (uint16_t)sqrt((float)R(0));
351
}
352
353
void ArcTan ()
354
{
355
int32_t a = -(((int32_t)R(0) * R(0)) >> 14);
356
int32_t b = 0xA9;
357
b = ((a * b) >> 14) + 0x0390;
358
b = ((a * b) >> 14) + 0x091C;
359
b = ((a * b) >> 14) + 0x0FB6;
360
b = ((a * b) >> 14) + 0X16AA;
361
b = ((a * b) >> 14) + 0X2081;
362
b = ((a * b) >> 14) + 0X3651;
363
b = ((a * b) >> 14) + 0XA2F9;
364
365
R(0) = (R(0) * b) >> 16;
366
}
367
368
void ArcTan2 ()
369
{
370
int16_t x = R(0), y = R(1);
371
if (y)
372
if (x)
373
if (abs(x) < abs(y))
374
{
375
R(0) <<= 14;
376
Div();
377
ArcTan();
378
R(0) = 0x4000 - R(0);
379
if (y < 0)
380
R(0) += 0x8000;
381
}
382
else
383
{
384
uint32_t r1 = R(1);
385
R(1) = R(0);
386
R(0) = r1 << 14;
387
Div();
388
ArcTan();
389
if (x < 0)
390
R(0) += 0x8000;
391
else if (y < 0)
392
R(0) += 0x10000;
393
}
394
else
395
if (y < 0)
396
R(0) = 0xc000;
397
else
398
R(0) = 0x4000;
399
else
400
if (x < 0)
401
R(0) = 0x8000;
402
else
403
R(0) = 0x0000;
404
}
405
406
void CpuSet ()
407
{
408
if (R(2) & (0x1 << 26)) // 32 bits
409
{
410
if (R(2) & (0x1 << 24)) // fixed source address
411
{
412
uint32_t source = MEM.Read32(R(0) & 0xFFFFFFFC);
413
uint32_t address = R(1) & 0xFFFFFFFC;
414
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
415
{
416
MEM.Write32(address, source);
417
address += 4;
418
}
419
}
420
else // copy
421
{
422
uint32_t src = R(0) & 0xFFFFFFFC;
423
uint32_t dest = R(1) & 0xFFFFFFFC;
424
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
425
{
426
MEM.Write32(dest, MEM.Read32(src));
427
src += 4;
428
dest += 4;
429
}
430
}
431
}
432
else // 16 bits
433
{
434
if (R(2) & (0x1 << 24)) // fixed source address
435
{
436
uint16_t source = MEM.Read16(R(0));
437
uint32_t address = R(1);
438
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
439
{
440
MEM.Write16(address, source);
441
address += 2;
442
}
443
}
444
else // copy
445
{
446
uint32_t src = R(0);
447
uint32_t dest = R(1);
448
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
449
{
450
MEM.Write16(dest, MEM.Read16(src));
451
src += 2;
452
dest += 2;
453
}
454
}
455
}
456
}
457
458
void CpuFastSet ()
459
{
460
if (R(2) & (0x1 << 24)) // fixed source address
461
{
462
uint32_t source = MEM.Read32(R(0));
463
uint32_t address = R(1);
464
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
465
{
466
MEM.Write32(address, source);
467
address += 4;
468
}
469
}
470
else // copy
471
{
472
uint32_t src = R(0);
473
uint32_t dest = R(1);
474
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
475
{
476
MEM.Write32(dest, MEM.Read32(src));
477
src += 4;
478
dest += 4;
479
}
480
}
481
}
482
483
void BgAffineSet ()
484
{
485
uint32_t src = R(0);
486
uint32_t dest = R(1);
487
uint32_t num = R(2);
488
489
int32_t cx, cy;
490
int16_t dix, diy, rx, ry;
491
uint16_t alpha;
492
493
int32_t cos, sin;
494
int16_t dx, dmx, dy, dmy;
495
496
while (num--)
497
{
498
cx = MEM.Read32(src);
499
src += 4;
500
cy = MEM.Read32(src);
501
src += 4;
502
dix = MEM.Read16(src);
503
src += 2;
504
diy = MEM.Read16(src);
505
src += 2;
506
rx = MEM.Read16(src);
507
src += 2;
508
ry = MEM.Read16(src);
509
src += 2;
510
alpha = MEM.Read16(src) >> 8;
511
src += 2;
512
513
sin = sineTable[alpha];
514
cos = sineTable[(alpha + 0x40) & 0xFF];
515
516
dx = (rx * cos) >> 14;
517
dmx = -((rx * sin) >> 14);
518
dy = (ry * sin) >> 14;
519
dmy = (ry * cos) >> 14;
520
521
MEM.Write16(dest, dx);
522
dest += 2;
523
MEM.Write16(dest, dmx);
524
dest += 2;
525
MEM.Write16(dest, dy);
526
dest += 2;
527
MEM.Write16(dest, dmy);
528
dest += 2;
529
530
MEM.Write32(dest, cx - dx * dix - dmx * diy);
531
dest += 4;
532
MEM.Write32(dest, cy - dy * dix - dmy * diy);
533
dest += 4;
534
}
535
}
536
537
void ObjAffineSet ()
538
{
539
uint32_t src = R(0);
540
uint32_t dest = R(1);
541
uint32_t num = R(2);
542
uint32_t off = R(3);
543
544
int16_t rx, ry;
545
uint16_t alpha;
546
547
int32_t cos, sin;
548
int16_t dx, dmx, dy, dmy;
549
550
while (num--)
551
{
552
rx = MEM.Read16(src);
553
src += 2;
554
ry = MEM.Read16(src);
555
src += 2;
556
alpha = MEM.Read16(src) >> 8;
557
src += 4;
558
559
sin = sineTable[alpha];
560
cos = sineTable[(alpha + 0x40) & 0xFF];
561
562
dx = (rx * cos) >> 14;
563
dmx = -((rx * sin) >> 14);
564
dy = (ry * sin) >> 14;
565
dmy = (ry * cos) >> 14;
566
567
MEM.Write16(dest, dx);
568
dest += off;
569
MEM.Write16(dest, dmx);
570
dest += off;
571
MEM.Write16(dest, dy);
572
dest += off;
573
MEM.Write16(dest, dmy);
574
dest += off;
575
}
576
}
577
578
void LZ77UnCompWram ()
579
{
580
uint32_t src = R(0);
581
uint32_t header = MEM.Read32(src);
582
src += 4;
583
if (((header >> 4) & 0xF) != 1)
584
met_abort("This is not LZ77 data");
585
uint32_t size = header >> 8;
586
debug("LZ77UnCompWram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
587
uint32_t dest = R(1);
588
uint8_t flags;
589
uint16_t block;
590
uint8_t blocklen;
591
uint32_t realaddr;
592
593
// for each block of a flags byte + 8 blocks
594
while (true)
595
{
596
flags = MEM.Read8(src++);
597
598
for (uint8_t i = 0; i < 8; ++i)
599
{
600
// compressed block of 2 bytes
601
if (flags & 0x80)
602
{
603
block = MEM.Read8(src) << 8 | MEM.Read8(src+1);
604
src += 2;
605
blocklen = (block >> 12) + 3;
606
realaddr = dest - (block & 0x0FFF) - 1;
607
for(uint16_t j = 0; j < blocklen; ++j)
608
{
609
MEM.Write8(dest++, MEM.Read8(realaddr++));
610
611
--size;
612
if(size == 0)
613
{
614
size = header >> 8;
615
return;
616
}
617
}
618
}
619
// uncompressed block of 1 byte
620
else
621
{
622
MEM.Write8(dest++, MEM.Read8(src++));
623
624
--size;
625
if (size == 0)
626
{
627
size = header >> 8;
628
return;
629
}
630
}
631
632
flags <<= 1;
633
}
634
}
635
}
636
637
void LZ77UnCompVram ()
638
{
639
uint32_t src = R(0);
640
uint32_t header = MEM.Read32(src);
641
src += 4;
642
if (((header >> 4) & 0xF) != 1)
643
met_abort("This is not LZ77 data");
644
uint32_t size = header >> 8;
645
debug("LZ77UnCompVram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
646
uint32_t dest = R(1);
647
uint8_t flags;
648
uint16_t out = 0;
649
uint8_t shift = 0;
650
uint16_t block;
651
uint8_t blocklen;
652
uint32_t realaddr;
653
654
// for each block of a flags byte + 8 blocks
655
while (true)
656
{
657
flags = MEM.Read8(src++);
658
659
for (uint8_t i = 0; i < 8; ++i)
660
{
661
// compressed block of 2 bytes
662
if (flags & 0x80)
663
{
664
block = MEM.Read8(src) << 8 | MEM.Read8(src+1);
665
src += 2;
666
blocklen = (block >> 12) + 3;
667
realaddr = dest + (shift/8) - (block & 0x0FFF) - 1;
668
for(uint16_t j = 0; j < blocklen; ++j) {
669
out |= MEM.Read8(realaddr++) << shift;
670
shift += 8;
671
672
if(shift == 16) {
673
MEM.Write16(dest, out);
674
dest += 2;
675
out = 0;
676
shift = 0;
677
}
678
679
--size;
680
if(size == 0)
681
{
682
size = header >> 8;
683
return;
684
}
685
}
686
}
687
// uncompressed block of 1 byte
688
else
689
{
690
out |= MEM.Read8(src++) << shift;
691
shift += 8;
692
693
if (shift == 16)
694
{
695
MEM.Write16(dest, out);
696
dest += 2;
697
shift = 0;
698
out = 0;
699
}
700
701
--size;
702
if (size == 0)
703
{
704
size = header >> 8;
705
return;
706
}
707
}
708
709
flags <<= 1;
710
}
711
}
712
}
713
714
void HuffUnComp ()
715
{
716
uint32_t src = R(0) & 0xFFFFFFFC;
717
uint32_t dest = R(1);
718
uint32_t header = MEM.Read32(src);
719
src += 4;
720
if (((header >> 4) & 0xF) != 2)
721
met_abort("This is not Huffman data");
722
uint8_t blockLen = header & 0xF;
723
uint32_t size = header >> 8;
724
if (size % 4)
725
met_abort("Size not multiple of 4 in HuffUnComp");
726
uint32_t treeStart = src + 1;
727
src += 2 + MEM.Read8(src) * 2;
728
729
uint32_t cData = MEM.Read32(src);
730
src += 4;
731
uint32_t mask = 0x80000000;
732
uint32_t treePos = treeStart;
733
uint8_t node = MEM.Read8(treePos);
734
bool endNode = false;
735
uint32_t oData = 0;
736
uint8_t oShift = 0;
737
738
while (size)
739
{
740
treePos = (treePos & 0xFFFFFFFE) + (node & 0x3F) * 2 + 2;
741
if (cData & mask)
742
{
743
++treePos;
744
if (node & (0x1 << 6))
745
endNode = true;
746
}
747
else
748
{
749
if (node & (0x1 << 7))
750
endNode = true;
751
}
752
node = MEM.Read8(treePos);
753
754
if (endNode)
755
{
756
oData |= ((uint32_t)node) << oShift;
757
oShift += blockLen;
758
759
if (oShift >= 32)
760
{
761
MEM.Write32(dest, oData);
762
dest += 4;
763
size -= 4;
764
765
oShift -= 32;
766
if (oShift)
767
oData = node >> (8 - oShift);
768
else
769
oData = 0;
770
}
771
endNode = false;
772
treePos = treeStart;
773
node = MEM.Read8(treePos);
774
}
775
776
mask >>= 1;
777
if (!mask)
778
{
779
cData = MEM.Read32(src);
780
src += 4;
781
mask = 0x80000000;
782
}
783
}
784
}
785
786
void RLUnCompWram ()
787
{
788
uint32_t src = R(0);
789
uint32_t header = MEM.Read32(src);
790
src += 4;
791
if (((header >> 4) & 0xF) != 3)
792
met_abort("This is not RL data");
793
uint32_t size = header >> 8;
794
debug("RLUnCompWram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
795
uint32_t dest = R(1);
796
uint8_t flags;
797
uint8_t block;
798
uint8_t blocklen;
799
800
// for each block
801
while (true)
802
{
803
flags = MEM.Read8(src++);
804
blocklen = flags & 0x7F;
805
806
// compressed block
807
if (flags & 0x80)
808
{
809
blocklen += 3;
810
block = MEM.Read8(src++);
811
812
for(uint8_t i = 0; i < blocklen; ++i) {
813
MEM.Write8(dest++, block);
814
815
--size;
816
if(size == 0)
817
{
818
size = header >> 8;
819
return;
820
}
821
}
822
}
823
// uncompressed block
824
else
825
{
826
blocklen += 1;
827
828
for (uint8_t i = 0; i < blocklen; ++i)
829
{
830
MEM.Write8(dest++, MEM.Read8(src++));
831
832
--size;
833
if (size == 0)
834
{
835
size = header >> 8;
836
return;
837
}
838
}
839
}
840
}
841
}
842
843
void RLUnCompVram ()
844
{
845
uint32_t src = R(0);
846
uint32_t header = MEM.Read32(src);
847
src += 4;
848
if (((header >> 4) & 0xF) != 3)
849
met_abort("This is not RL data");
850
uint32_t size = header >> 8;
851
debug("RLUnCompVram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
852
uint32_t dest = R(1);
853
uint8_t flags;
854
uint16_t out = 0;
855
uint8_t shift = 0;
856
uint8_t block;
857
uint8_t blocklen;
858
859
// for each block
860
while (true)
861
{
862
flags = MEM.Read8(src++);
863
blocklen = flags & 0x7F;
864
865
// compressed block
866
if (flags & 0x80)
867
{
868
blocklen += 3;
869
block = MEM.Read8(src++);
870
871
for(uint8_t i = 0; i < blocklen; ++i) {
872
out |= block << shift;
873
shift += 8;
874
875
if(shift == 16) {
876
MEM.Write16(dest, out);
877
dest += 2;
878
out = 0;
879
shift = 0;
880
}
881
882
--size;
883
if(size == 0)
884
{
885
size = header >> 8;
886
return;
887
}
888
}
889
}
890
// uncompressed block
891
else
892
{
893
blocklen += 1;
894
895
for (uint8_t i = 0; i < blocklen; ++i)
896
{
897
out |= MEM.Read8(src++) << shift;
898
shift += 8;
899
900
if (shift == 16)
901
{
902
MEM.Write16(dest, out);
903
dest += 2;
904
shift = 0;
905
out = 0;
906
}
907
908
--size;
909
if (size == 0)
910
{
911
size = header >> 8;
912
return;
913
}
914
}
915
}
916
}
917
}
918
}
919
}
920
921