BizHawk/libmeteor/source/bios.cpp

920 lines
21 KiB
C++

// Meteor - A Nintendo Gameboy Advance emulator
// Copyright (C) 2009-2011 Philippe Daouadi
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "ameteor/bios.hpp"
#include "ameteor/cpu.hpp"
#include "ameteor/memory.hpp"
#include "globals.hpp"
#include "debug.hpp"
#include <cmath>
namespace AMeteor
{
namespace Bios
{
static const int16_t sineTable[256] = {
(int16_t)0x0000, (int16_t)0x0192, (int16_t)0x0323, (int16_t)0x04B5,
(int16_t)0x0645, (int16_t)0x07D5, (int16_t)0x0964, (int16_t)0x0AF1,
(int16_t)0x0C7C, (int16_t)0x0E05, (int16_t)0x0F8C, (int16_t)0x1111,
(int16_t)0x1294, (int16_t)0x1413, (int16_t)0x158F, (int16_t)0x1708,
(int16_t)0x187D, (int16_t)0x19EF, (int16_t)0x1B5D, (int16_t)0x1CC6,
(int16_t)0x1E2B, (int16_t)0x1F8B, (int16_t)0x20E7, (int16_t)0x223D,
(int16_t)0x238E, (int16_t)0x24DA, (int16_t)0x261F, (int16_t)0x275F,
(int16_t)0x2899, (int16_t)0x29CD, (int16_t)0x2AFA, (int16_t)0x2C21,
(int16_t)0x2D41, (int16_t)0x2E5A, (int16_t)0x2F6B, (int16_t)0x3076,
(int16_t)0x3179, (int16_t)0x3274, (int16_t)0x3367, (int16_t)0x3453,
(int16_t)0x3536, (int16_t)0x3612, (int16_t)0x36E5, (int16_t)0x37AF,
(int16_t)0x3871, (int16_t)0x392A, (int16_t)0x39DA, (int16_t)0x3A82,
(int16_t)0x3B20, (int16_t)0x3BB6, (int16_t)0x3C42, (int16_t)0x3CC5,
(int16_t)0x3D3E, (int16_t)0x3DAE, (int16_t)0x3E14, (int16_t)0x3E71,
(int16_t)0x3EC5, (int16_t)0x3F0E, (int16_t)0x3F4E, (int16_t)0x3F84,
(int16_t)0x3FB1, (int16_t)0x3FD3, (int16_t)0x3FEC, (int16_t)0x3FFB,
(int16_t)0x4000, (int16_t)0x3FFB, (int16_t)0x3FEC, (int16_t)0x3FD3,
(int16_t)0x3FB1, (int16_t)0x3F84, (int16_t)0x3F4E, (int16_t)0x3F0E,
(int16_t)0x3EC5, (int16_t)0x3E71, (int16_t)0x3E14, (int16_t)0x3DAE,
(int16_t)0x3D3E, (int16_t)0x3CC5, (int16_t)0x3C42, (int16_t)0x3BB6,
(int16_t)0x3B20, (int16_t)0x3A82, (int16_t)0x39DA, (int16_t)0x392A,
(int16_t)0x3871, (int16_t)0x37AF, (int16_t)0x36E5, (int16_t)0x3612,
(int16_t)0x3536, (int16_t)0x3453, (int16_t)0x3367, (int16_t)0x3274,
(int16_t)0x3179, (int16_t)0x3076, (int16_t)0x2F6B, (int16_t)0x2E5A,
(int16_t)0x2D41, (int16_t)0x2C21, (int16_t)0x2AFA, (int16_t)0x29CD,
(int16_t)0x2899, (int16_t)0x275F, (int16_t)0x261F, (int16_t)0x24DA,
(int16_t)0x238E, (int16_t)0x223D, (int16_t)0x20E7, (int16_t)0x1F8B,
(int16_t)0x1E2B, (int16_t)0x1CC6, (int16_t)0x1B5D, (int16_t)0x19EF,
(int16_t)0x187D, (int16_t)0x1708, (int16_t)0x158F, (int16_t)0x1413,
(int16_t)0x1294, (int16_t)0x1111, (int16_t)0x0F8C, (int16_t)0x0E05,
(int16_t)0x0C7C, (int16_t)0x0AF1, (int16_t)0x0964, (int16_t)0x07D5,
(int16_t)0x0645, (int16_t)0x04B5, (int16_t)0x0323, (int16_t)0x0192,
(int16_t)0x0000, (int16_t)0xFE6E, (int16_t)0xFCDD, (int16_t)0xFB4B,
(int16_t)0xF9BB, (int16_t)0xF82B, (int16_t)0xF69C, (int16_t)0xF50F,
(int16_t)0xF384, (int16_t)0xF1FB, (int16_t)0xF074, (int16_t)0xEEEF,
(int16_t)0xED6C, (int16_t)0xEBED, (int16_t)0xEA71, (int16_t)0xE8F8,
(int16_t)0xE783, (int16_t)0xE611, (int16_t)0xE4A3, (int16_t)0xE33A,
(int16_t)0xE1D5, (int16_t)0xE075, (int16_t)0xDF19, (int16_t)0xDDC3,
(int16_t)0xDC72, (int16_t)0xDB26, (int16_t)0xD9E1, (int16_t)0xD8A1,
(int16_t)0xD767, (int16_t)0xD633, (int16_t)0xD506, (int16_t)0xD3DF,
(int16_t)0xD2BF, (int16_t)0xD1A6, (int16_t)0xD095, (int16_t)0xCF8A,
(int16_t)0xCE87, (int16_t)0xCD8C, (int16_t)0xCC99, (int16_t)0xCBAD,
(int16_t)0xCACA, (int16_t)0xC9EE, (int16_t)0xC91B, (int16_t)0xC851,
(int16_t)0xC78F, (int16_t)0xC6D6, (int16_t)0xC626, (int16_t)0xC57E,
(int16_t)0xC4E0, (int16_t)0xC44A, (int16_t)0xC3BE, (int16_t)0xC33B,
(int16_t)0xC2C2, (int16_t)0xC252, (int16_t)0xC1EC, (int16_t)0xC18F,
(int16_t)0xC13B, (int16_t)0xC0F2, (int16_t)0xC0B2, (int16_t)0xC07C,
(int16_t)0xC04F, (int16_t)0xC02D, (int16_t)0xC014, (int16_t)0xC005,
(int16_t)0xC000, (int16_t)0xC005, (int16_t)0xC014, (int16_t)0xC02D,
(int16_t)0xC04F, (int16_t)0xC07C, (int16_t)0xC0B2, (int16_t)0xC0F2,
(int16_t)0xC13B, (int16_t)0xC18F, (int16_t)0xC1EC, (int16_t)0xC252,
(int16_t)0xC2C2, (int16_t)0xC33B, (int16_t)0xC3BE, (int16_t)0xC44A,
(int16_t)0xC4E0, (int16_t)0xC57E, (int16_t)0xC626, (int16_t)0xC6D6,
(int16_t)0xC78F, (int16_t)0xC851, (int16_t)0xC91B, (int16_t)0xC9EE,
(int16_t)0xCACA, (int16_t)0xCBAD, (int16_t)0xCC99, (int16_t)0xCD8C,
(int16_t)0xCE87, (int16_t)0xCF8A, (int16_t)0xD095, (int16_t)0xD1A6,
(int16_t)0xD2BF, (int16_t)0xD3DF, (int16_t)0xD506, (int16_t)0xD633,
(int16_t)0xD767, (int16_t)0xD8A1, (int16_t)0xD9E1, (int16_t)0xDB26,
(int16_t)0xDC72, (int16_t)0xDDC3, (int16_t)0xDF19, (int16_t)0xE075,
(int16_t)0xE1D5, (int16_t)0xE33A, (int16_t)0xE4A3, (int16_t)0xE611,
(int16_t)0xE783, (int16_t)0xE8F8, (int16_t)0xEA71, (int16_t)0xEBED,
(int16_t)0xED6C, (int16_t)0xEEEF, (int16_t)0xF074, (int16_t)0xF1FB,
(int16_t)0xF384, (int16_t)0xF50F, (int16_t)0xF69C, (int16_t)0xF82B,
(int16_t)0xF9BB, (int16_t)0xFB4B, (int16_t)0xFCDD, (int16_t)0xFE6E
};
void Bios000h ()
{
debug("Bios entry point");
R(13) = 0x03007FE0;
R(15) = 0x08000004;
CPU.SwitchToMode(Cpu::M_IRQ);
R(13) = 0x03007FA0;
CPU.SwitchToMode(Cpu::M_SYS);
R(13) = 0x03007F00;
ICPSR.irq_d = false;
IO.Write8(Io::POSTFLG, 0x01);
}
void Bios008h ()
{
// if we are here, we should be in SVC mode (0x13)
// store the spsr, r11, r12 and r14 on the stack
uint32_t baseadd = R(13) - (4*4), add = (baseadd & 0xFFFFFFFC);
MEM.Write32(add , SPSR);
MEM.Write32(add += 4, R(11));
MEM.Write32(add += 4, R(12));
MEM.Write32(add + 4, R(14));
R(13) = baseadd;
uint8_t swiComment = MEM.Read8(R(14) - 2);
// put 0x1F in cpsr but don't touch to the irq disable bit
CPU.SwitchToMode(0x1F);
CPSR = 0x0000001F | (CPSR & (0x1 << 7));
CPU.UpdateICpsr();
// store r11 and r14 (of the user mode) on the stack
baseadd = R(13) - (2*4); add = (baseadd & 0xFFFFFFFC);
MEM.Write32(add , R(11));
MEM.Write32(add + 4, R(14));
R(13) = baseadd;
R(14) = 0x168;
debug("Software IRQ start");
switch (swiComment)
{
case 0x04:
IntrWait();
break;
case 0x05:
VBlankIntrWait();
break;
default:
met_abort("not implemented : " << (int)swiComment);
break;
}
}
void Bios168h ()
{
uint32_t add = R(13) & 0xFFFFFFFC;
R( 2) = MEM.Read32(add );
R(14) = MEM.Read32(add += 4);
R(13) += 2*4;
// SVC with fiq and irq disabled
CPU.SwitchToMode(0x13); // SVC
CPSR = 0x000000D3;
CPU.UpdateICpsr();
add = R(13) & 0xFFFFFFFC;
SPSR = MEM.Read32(add);
R(11) = MEM.Read32(add += 4);
R(12) = MEM.Read32(add += 4);
R(14) = MEM.Read32(add + 4);
R(13) += 4*4;
// FIXME this works (for thumb) ?
if (CPU.Spsr().b.thumb)
R(15) = R(14) + 2;
else
R(15) = R(14) + 4;
debug("Software IRQ end");
CPU.SwitchModeBack();
}
void Bios018h ()
{
debug("IRQ start");
// stmfd r13!,r0-r3,r12,r14
uint32_t baseadd = R(13) - (6*4), add = (baseadd & 0xFFFFFFFC);
MEM.Write32(add , R( 0));
MEM.Write32(add += 4, R( 1));
MEM.Write32(add += 4, R( 2));
MEM.Write32(add += 4, R( 3));
MEM.Write32(add += 4, R(12));
MEM.Write32(add + 4, R(14));
R(13) = baseadd;
// add r14,r15,0h
R(14) = 0x00000130;
R(15) = MEM.Read32(0x03007FFC) + 4;
}
void Bios130h ()
{
debug("IRQ end");
// ldmfd r13!,r0-r3,r12,r14
uint32_t add = R(13) & 0xFFFFFFFC;
R( 0) = MEM.Read32(add );
R( 1) = MEM.Read32(add += 4);
R( 2) = MEM.Read32(add += 4);
R( 3) = MEM.Read32(add += 4);
R(12) = MEM.Read32(add += 4);
R(14) = MEM.Read32(add + 4);
R(13) += 6*4;
// subs r15,r14,4h
R(15) = R(14);
if (CPU.Spsr().b.thumb)
R(15) -= 2;
CPU.SwitchModeBack();
// XXX FIXME, usefull ? test on breath of fire !
/*if (FLAG_T)
R(15) &= 0xFFFFFFFE;
else
R(15) &= 0xFFFFFFFC;*/
}
void SoftReset ()
{
CPU.SoftReset ();
if (MEM.Read8(0x03007FFA))
R(15) = 0x02000004;
else
R(15) = 0x08000004;
MEM.SoftReset ();
}
void RegisterRamReset ()
{
IO.Write16(Io::DISPCNT, 0x0080);
uint8_t flagRes = R(0);
if (flagRes & (0x1 ))
MEM.ClearWbram();
if (flagRes & (0x1 << 1))
MEM.ClearWcram();
if (flagRes & (0x1 << 2))
MEM.ClearPalette();
if (flagRes & (0x1 << 3))
MEM.ClearVram();
if (flagRes & (0x1 << 4))
MEM.ClearOam();
if (flagRes & (0x1 << 5))
IO.ClearSio ();
if (flagRes & (0x1 << 6))
IO.ClearSound ();
if (flagRes & (0x1 << 7))
IO.ClearOthers ();
}
void Halt ()
{
IO.Write8(Io::HALTCNT, 0);
}
void IntrWait ()
{
// FIXME ugly
R(13) -= 8;
MEM.Write32(R(13) & 0xFFFFFFFC, R(4));
MEM.Write32((R(13)+4) & 0xFFFFFFFC, R(14));
uint16_t& intFlags = *(uint16_t*)MEM.GetRealAddress(0x03007FF8);
if (R(0))
{
if (intFlags & R(1))
intFlags = (intFlags & R(1)) ^ intFlags;
else
FLAG_Z = 1;
IO.Write16(Io::IME, 1);
}
IO.Write8(Io::HALTCNT, 0);
// return address (after IRQ)
R(15) = 0x33C;
debug("IntrWait start");
}
void Bios338h ()
{
uint16_t& intFlags = *(uint16_t*)MEM.GetRealAddress(0x03007FF8);
if (!(intFlags & R(1)))
{
IO.Write16(Io::IME, 1);
IO.Write8(Io::HALTCNT, 0);
}
else
{
intFlags = (intFlags & R(1)) ^ intFlags;
IO.Write16(Io::IME, 1);
// FIXME ugly
R(4) = MEM.Read32(R(13) & 0xFFFFFFFC);
R(14) = MEM.Read32((R(13)+4) & 0xFFFFFFFC);
R(13) += 8;
// should lead to 0x168
R(15) = R(14)+4;
}
debug("IntWait end");
}
void VBlankIntrWait ()
{
R(0) = 1;
R(1) = 1;
IntrWait();
}
void Div ()
{
if (!R(1))
met_abort("Div by 0");
int32_t number = R(0), denom = R(1);
int32_t div = number / denom;
R(0) = div;
R(1) = number % denom;
R(3) = div < 0 ? -div : div;
}
void DivArm ()
{
uint32_t tmp = R(0);
R(0) = R(1);
R(1) = tmp;
Div();
}
void Sqrt ()
{
R(0) = (uint16_t)sqrt((float)R(0));
}
void ArcTan ()
{
int32_t a = -(((int32_t)R(0) * R(0)) >> 14);
int32_t b = 0xA9;
b = ((a * b) >> 14) + 0x0390;
b = ((a * b) >> 14) + 0x091C;
b = ((a * b) >> 14) + 0x0FB6;
b = ((a * b) >> 14) + 0X16AA;
b = ((a * b) >> 14) + 0X2081;
b = ((a * b) >> 14) + 0X3651;
b = ((a * b) >> 14) + 0XA2F9;
R(0) = (R(0) * b) >> 16;
}
void ArcTan2 ()
{
int16_t x = R(0), y = R(1);
if (y)
if (x)
if (abs(x) < abs(y))
{
R(0) <<= 14;
Div();
ArcTan();
R(0) = 0x4000 - R(0);
if (y < 0)
R(0) += 0x8000;
}
else
{
uint32_t r1 = R(1);
R(1) = R(0);
R(0) = r1 << 14;
Div();
ArcTan();
if (x < 0)
R(0) += 0x8000;
else if (y < 0)
R(0) += 0x10000;
}
else
if (y < 0)
R(0) = 0xc000;
else
R(0) = 0x4000;
else
if (x < 0)
R(0) = 0x8000;
else
R(0) = 0x0000;
}
void CpuSet ()
{
if (R(2) & (0x1 << 26)) // 32 bits
{
if (R(2) & (0x1 << 24)) // fixed source address
{
uint32_t source = MEM.Read32(R(0) & 0xFFFFFFFC);
uint32_t address = R(1) & 0xFFFFFFFC;
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
{
MEM.Write32(address, source);
address += 4;
}
}
else // copy
{
uint32_t src = R(0) & 0xFFFFFFFC;
uint32_t dest = R(1) & 0xFFFFFFFC;
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
{
MEM.Write32(dest, MEM.Read32(src));
src += 4;
dest += 4;
}
}
}
else // 16 bits
{
if (R(2) & (0x1 << 24)) // fixed source address
{
uint16_t source = MEM.Read16(R(0));
uint32_t address = R(1);
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
{
MEM.Write16(address, source);
address += 2;
}
}
else // copy
{
uint32_t src = R(0);
uint32_t dest = R(1);
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
{
MEM.Write16(dest, MEM.Read16(src));
src += 2;
dest += 2;
}
}
}
}
void CpuFastSet ()
{
if (R(2) & (0x1 << 24)) // fixed source address
{
uint32_t source = MEM.Read32(R(0));
uint32_t address = R(1);
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
{
MEM.Write32(address, source);
address += 4;
}
}
else // copy
{
uint32_t src = R(0);
uint32_t dest = R(1);
for (uint32_t count = (R(2) & 0x001FFFFF); count; --count)
{
MEM.Write32(dest, MEM.Read32(src));
src += 4;
dest += 4;
}
}
}
void BgAffineSet ()
{
uint32_t src = R(0);
uint32_t dest = R(1);
uint32_t num = R(2);
int32_t cx, cy;
int16_t dix, diy, rx, ry;
uint16_t alpha;
int32_t cos, sin;
int16_t dx, dmx, dy, dmy;
while (num--)
{
cx = MEM.Read32(src);
src += 4;
cy = MEM.Read32(src);
src += 4;
dix = MEM.Read16(src);
src += 2;
diy = MEM.Read16(src);
src += 2;
rx = MEM.Read16(src);
src += 2;
ry = MEM.Read16(src);
src += 2;
alpha = MEM.Read16(src) >> 8;
src += 2;
sin = sineTable[alpha];
cos = sineTable[(alpha + 0x40) & 0xFF];
dx = (rx * cos) >> 14;
dmx = -((rx * sin) >> 14);
dy = (ry * sin) >> 14;
dmy = (ry * cos) >> 14;
MEM.Write16(dest, dx);
dest += 2;
MEM.Write16(dest, dmx);
dest += 2;
MEM.Write16(dest, dy);
dest += 2;
MEM.Write16(dest, dmy);
dest += 2;
MEM.Write32(dest, cx - dx * dix - dmx * diy);
dest += 4;
MEM.Write32(dest, cy - dy * dix - dmy * diy);
dest += 4;
}
}
void ObjAffineSet ()
{
uint32_t src = R(0);
uint32_t dest = R(1);
uint32_t num = R(2);
uint32_t off = R(3);
int16_t rx, ry;
uint16_t alpha;
int32_t cos, sin;
int16_t dx, dmx, dy, dmy;
while (num--)
{
rx = MEM.Read16(src);
src += 2;
ry = MEM.Read16(src);
src += 2;
alpha = MEM.Read16(src) >> 8;
src += 4;
sin = sineTable[alpha];
cos = sineTable[(alpha + 0x40) & 0xFF];
dx = (rx * cos) >> 14;
dmx = -((rx * sin) >> 14);
dy = (ry * sin) >> 14;
dmy = (ry * cos) >> 14;
MEM.Write16(dest, dx);
dest += off;
MEM.Write16(dest, dmx);
dest += off;
MEM.Write16(dest, dy);
dest += off;
MEM.Write16(dest, dmy);
dest += off;
}
}
void LZ77UnCompWram ()
{
uint32_t src = R(0);
uint32_t header = MEM.Read32(src);
src += 4;
if (((header >> 4) & 0xF) != 1)
met_abort("This is not LZ77 data");
uint32_t size = header >> 8;
debug("LZ77UnCompWram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
uint32_t dest = R(1);
uint8_t flags;
uint16_t block;
uint8_t blocklen;
uint32_t realaddr;
// for each block of a flags byte + 8 blocks
while (true)
{
flags = MEM.Read8(src++);
for (uint8_t i = 0; i < 8; ++i)
{
// compressed block of 2 bytes
if (flags & 0x80)
{
block = MEM.Read8(src) << 8 | MEM.Read8(src+1);
src += 2;
blocklen = (block >> 12) + 3;
realaddr = dest - (block & 0x0FFF) - 1;
for(uint16_t j = 0; j < blocklen; ++j)
{
MEM.Write8(dest++, MEM.Read8(realaddr++));
--size;
if(size == 0)
{
size = header >> 8;
return;
}
}
}
// uncompressed block of 1 byte
else
{
MEM.Write8(dest++, MEM.Read8(src++));
--size;
if (size == 0)
{
size = header >> 8;
return;
}
}
flags <<= 1;
}
}
}
void LZ77UnCompVram ()
{
uint32_t src = R(0);
uint32_t header = MEM.Read32(src);
src += 4;
if (((header >> 4) & 0xF) != 1)
met_abort("This is not LZ77 data");
uint32_t size = header >> 8;
debug("LZ77UnCompVram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
uint32_t dest = R(1);
uint8_t flags;
uint16_t out = 0;
uint8_t shift = 0;
uint16_t block;
uint8_t blocklen;
uint32_t realaddr;
// for each block of a flags byte + 8 blocks
while (true)
{
flags = MEM.Read8(src++);
for (uint8_t i = 0; i < 8; ++i)
{
// compressed block of 2 bytes
if (flags & 0x80)
{
block = MEM.Read8(src) << 8 | MEM.Read8(src+1);
src += 2;
blocklen = (block >> 12) + 3;
realaddr = dest + (shift/8) - (block & 0x0FFF) - 1;
for(uint16_t j = 0; j < blocklen; ++j) {
out |= MEM.Read8(realaddr++) << shift;
shift += 8;
if(shift == 16) {
MEM.Write16(dest, out);
dest += 2;
out = 0;
shift = 0;
}
--size;
if(size == 0)
{
size = header >> 8;
return;
}
}
}
// uncompressed block of 1 byte
else
{
out |= MEM.Read8(src++) << shift;
shift += 8;
if (shift == 16)
{
MEM.Write16(dest, out);
dest += 2;
shift = 0;
out = 0;
}
--size;
if (size == 0)
{
size = header >> 8;
return;
}
}
flags <<= 1;
}
}
}
void HuffUnComp ()
{
uint32_t src = R(0) & 0xFFFFFFFC;
uint32_t dest = R(1);
uint32_t header = MEM.Read32(src);
src += 4;
if (((header >> 4) & 0xF) != 2)
met_abort("This is not Huffman data");
uint8_t blockLen = header & 0xF;
uint32_t size = header >> 8;
if (size % 4)
met_abort("Size not multiple of 4 in HuffUnComp");
uint32_t treeStart = src + 1;
src += 2 + MEM.Read8(src) * 2;
uint32_t cData = MEM.Read32(src);
src += 4;
uint32_t mask = 0x80000000;
uint32_t treePos = treeStart;
uint8_t node = MEM.Read8(treePos);
bool endNode = false;
uint32_t oData = 0;
uint8_t oShift = 0;
while (size)
{
treePos = (treePos & 0xFFFFFFFE) + (node & 0x3F) * 2 + 2;
if (cData & mask)
{
++treePos;
if (node & (0x1 << 6))
endNode = true;
}
else
{
if (node & (0x1 << 7))
endNode = true;
}
node = MEM.Read8(treePos);
if (endNode)
{
oData |= ((uint32_t)node) << oShift;
oShift += blockLen;
if (oShift >= 32)
{
MEM.Write32(dest, oData);
dest += 4;
size -= 4;
oShift -= 32;
if (oShift)
oData = node >> (8 - oShift);
else
oData = 0;
}
endNode = false;
treePos = treeStart;
node = MEM.Read8(treePos);
}
mask >>= 1;
if (!mask)
{
cData = MEM.Read32(src);
src += 4;
mask = 0x80000000;
}
}
}
void RLUnCompWram ()
{
uint32_t src = R(0);
uint32_t header = MEM.Read32(src);
src += 4;
if (((header >> 4) & 0xF) != 3)
met_abort("This is not RL data");
uint32_t size = header >> 8;
debug("RLUnCompWram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
uint32_t dest = R(1);
uint8_t flags;
uint8_t block;
uint8_t blocklen;
// for each block
while (true)
{
flags = MEM.Read8(src++);
blocklen = flags & 0x7F;
// compressed block
if (flags & 0x80)
{
blocklen += 3;
block = MEM.Read8(src++);
for(uint8_t i = 0; i < blocklen; ++i) {
MEM.Write8(dest++, block);
--size;
if(size == 0)
{
size = header >> 8;
return;
}
}
}
// uncompressed block
else
{
blocklen += 1;
for (uint8_t i = 0; i < blocklen; ++i)
{
MEM.Write8(dest++, MEM.Read8(src++));
--size;
if (size == 0)
{
size = header >> 8;
return;
}
}
}
}
}
void RLUnCompVram ()
{
uint32_t src = R(0);
uint32_t header = MEM.Read32(src);
src += 4;
if (((header >> 4) & 0xF) != 3)
met_abort("This is not RL data");
uint32_t size = header >> 8;
debug("RLUnCompVram from " << IOS_ADD << R(0) << " to " << IOS_ADD << R(1) << ", len : " << size);
uint32_t dest = R(1);
uint8_t flags;
uint16_t out = 0;
uint8_t shift = 0;
uint8_t block;
uint8_t blocklen;
// for each block
while (true)
{
flags = MEM.Read8(src++);
blocklen = flags & 0x7F;
// compressed block
if (flags & 0x80)
{
blocklen += 3;
block = MEM.Read8(src++);
for(uint8_t i = 0; i < blocklen; ++i) {
out |= block << shift;
shift += 8;
if(shift == 16) {
MEM.Write16(dest, out);
dest += 2;
out = 0;
shift = 0;
}
--size;
if(size == 0)
{
size = header >> 8;
return;
}
}
}
// uncompressed block
else
{
blocklen += 1;
for (uint8_t i = 0; i < blocklen; ++i)
{
out |= MEM.Read8(src++) << shift;
shift += 8;
if (shift == 16)
{
MEM.Write16(dest, out);
dest += 2;
shift = 0;
out = 0;
}
--size;
if (size == 0)
{
size = header >> 8;
return;
}
}
}
}
}
}
}