mirror of
https://github.com/XorTroll/EveryFileExplorer.git
synced 2024-12-04 08:53:15 +00:00
Totally herstructured the ARM9 stuff
This commit is contained in:
parent
fec7c83b09
commit
6bd41cb3f7
433
NDS/CPU/ARM9.cs
433
NDS/CPU/ARM9.cs
@ -1,433 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using LibEveryFileExplorer.IO;
|
||||
|
||||
namespace NDS.CPU
|
||||
{
|
||||
public class ARM9
|
||||
{
|
||||
public static byte[] Decompress(byte[] Compressed, uint RamAddress, uint EntryAddress, uint AutoloadDone)
|
||||
{
|
||||
ARM9Context c = new ARM9Context();
|
||||
c.Registers[15] = EntryAddress;
|
||||
Array.Copy(Compressed, 0, c.Memory, RamAddress, Compressed.Length);
|
||||
uint stopaddress;
|
||||
while (true)
|
||||
{
|
||||
ExecuteInstruction(c);
|
||||
if (c.Registers[15] == AutoloadDone)
|
||||
{
|
||||
//Now we know the address of do_autoload + 4, which is MIi_UncompressBackward + 8
|
||||
stopaddress = c.Registers[14] - 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
c = new ARM9Context();
|
||||
c.Registers[15] = EntryAddress;
|
||||
Array.Copy(Compressed, 0, c.Memory, RamAddress, Compressed.Length);
|
||||
uint length = 0;
|
||||
uint compoffsaddr = 0;
|
||||
while (true)
|
||||
{
|
||||
ExecuteInstruction(c);
|
||||
if (c.Registers[15] == stopaddress - 4)
|
||||
{
|
||||
//look if the file is compressed (R0 = 0 means the data is not compressed!)
|
||||
if (c.Registers[0] == 0) return Compressed;
|
||||
length = c.Registers[0] + IOUtil.ReadU32LE(c.Memory, (int)c.Registers[0] - 4) - RamAddress;
|
||||
compoffsaddr = c.Registers[1] + 0x14 - RamAddress;
|
||||
}
|
||||
//we're done decompressing!
|
||||
if (c.Registers[15] == stopaddress) break;
|
||||
}
|
||||
byte[] result = new byte[length];
|
||||
Array.Copy(c.Memory, RamAddress, result, 0, length);
|
||||
IOUtil.WriteU32LE(result, (int)compoffsaddr, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
private class ARM9Context
|
||||
{
|
||||
public uint[] Registers = new uint[16];
|
||||
public byte[] Memory = new byte[0x8000000];
|
||||
public bool C;
|
||||
public bool N;
|
||||
public bool V;
|
||||
public bool Z;
|
||||
}
|
||||
|
||||
private static void ExecuteInstruction(ARM9Context c)
|
||||
{
|
||||
uint inst = IOUtil.ReadU32LE(c.Memory, (int)c.Registers[15]);
|
||||
uint condition = inst >> 28;
|
||||
if (EvaluateCondition(c, condition))
|
||||
{
|
||||
switch ((inst >> 25) & 7)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
DataProc(c, inst);
|
||||
c.Registers[15] += 4;
|
||||
break;
|
||||
case 0x2:
|
||||
case 0x3:
|
||||
SingleDataTrans(c, inst);
|
||||
c.Registers[15] += 4;
|
||||
break;
|
||||
case 0x4:
|
||||
BlockDataTrans(c, inst);
|
||||
c.Registers[15] += 4;
|
||||
break;
|
||||
case 0x5://101
|
||||
Branch(c, inst);
|
||||
break;
|
||||
case 0x7:
|
||||
c.Registers[15] += 4;
|
||||
break;//ignore mcr, mrc and that kind of crap
|
||||
default:
|
||||
c.Registers[15] += 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else c.Registers[15] += 4;
|
||||
}
|
||||
|
||||
private static UInt32 Shift(UInt32 ShiftType, UInt32 Value, UInt32 NrBits, ref bool Carry)
|
||||
{
|
||||
switch (ShiftType)
|
||||
{
|
||||
case 0:
|
||||
if (NrBits > 0) Carry = ((Value >> (32 - (int)NrBits)) & 1) == 1;
|
||||
return Value << (int)NrBits;
|
||||
case 1:
|
||||
if (NrBits > 0) Carry = ((Value >> ((int)NrBits - 1)) & 1) == 1;
|
||||
else Carry = ((Value >> 31) & 1) == 1;
|
||||
return Value >> (int)NrBits;
|
||||
case 2:
|
||||
if (NrBits > 0)
|
||||
{
|
||||
Carry = ((Value >> ((int)NrBits - 1)) & 1) == 1;
|
||||
return (uint)(((int)Value) >> (int)NrBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
Carry = ((Value >> 31) & 1) == 1;
|
||||
return ((Value >> 31) & 1) * 0xFFFFFFFF;
|
||||
}
|
||||
case 3:
|
||||
if (NrBits > 0)
|
||||
{
|
||||
Carry = ((Value >> ((int)NrBits - 1)) & 1) == 1;
|
||||
return (Value >> (int)NrBits) | (Value << (32 - (int)NrBits));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint tmp = ((Carry ? 1u : 0u) << 31) | (Value >> 1);
|
||||
Carry = (Value & 1) == 1;
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
private static void DataProc(ARM9Context c, uint Instruction)
|
||||
{
|
||||
uint result = 0;
|
||||
uint Rn;
|
||||
if ((Instruction & 0x0FFFFF00) == 0x12FFF00)//bx, blx
|
||||
{
|
||||
uint op = (Instruction >> 4) & 0xF;
|
||||
Rn = Instruction & 0xF;
|
||||
if (op == 1)
|
||||
{
|
||||
c.Registers[15] = c.Registers[Rn] - 4;
|
||||
}
|
||||
else if (op == 3)
|
||||
{
|
||||
c.Registers[14] = c.Registers[15] + 4;
|
||||
c.Registers[15] = c.Registers[Rn] - 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
//shouldn't happen!
|
||||
}
|
||||
return;
|
||||
}
|
||||
bool Shift_C = c.C;
|
||||
|
||||
bool I = ((Instruction >> 25) & 1) == 1;
|
||||
uint Opcode = (Instruction >> 21) & 0xF;
|
||||
bool S = ((Instruction >> 20) & 1) == 1;
|
||||
Rn = (Instruction >> 16) & 0xF;
|
||||
uint Rd = (Instruction >> 12) & 0xF;
|
||||
uint Op2 = 0;
|
||||
if (I)
|
||||
{
|
||||
uint Is = (Instruction >> 8) & 0xF;
|
||||
uint nn = Instruction & 0xFF;
|
||||
|
||||
Op2 = (nn >> (int)(Is * 2)) | (nn << (32 - (int)(Is * 2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
uint ShiftType = (Instruction >> 5) & 0x3;
|
||||
bool R = ((Instruction >> 4) & 1) == 1;
|
||||
uint Rm = Instruction & 0xF;
|
||||
|
||||
if (!R)
|
||||
{
|
||||
uint Is = (Instruction >> 7) & 0x1F;
|
||||
Op2 = Shift(ShiftType, c.Registers[Rm], Is, ref Shift_C);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint Rs = (Instruction >> 8) & 0xF;
|
||||
uint Reserved = (Instruction >> 7) & 1;
|
||||
Op2 = Shift(ShiftType, c.Registers[Rm], c.Registers[Rs] & 0xFF, ref Shift_C);
|
||||
}
|
||||
}
|
||||
|
||||
switch (Opcode)
|
||||
{
|
||||
case 0x2://sub
|
||||
result = c.Registers[Rd] = c.Registers[Rn] - Op2;
|
||||
break;
|
||||
case 0x4://add
|
||||
result = c.Registers[Rd] = c.Registers[Rn] + Op2;
|
||||
break;
|
||||
case 0x8:
|
||||
if (S == false)//MRS
|
||||
{
|
||||
break;
|
||||
}
|
||||
else//TST
|
||||
{
|
||||
result = c.Registers[Rn] & Op2;
|
||||
}
|
||||
break;
|
||||
case 0x9:
|
||||
if (S == false)//MSR
|
||||
{
|
||||
break;
|
||||
}
|
||||
else//TEQ
|
||||
{
|
||||
result = c.Registers[Rn] ^ Op2;
|
||||
}
|
||||
break;
|
||||
case 0xA://compare
|
||||
result = c.Registers[Rn] - Op2;
|
||||
break;
|
||||
case 0xC://OR logical
|
||||
result = c.Registers[Rd] = c.Registers[Rn] | Op2;
|
||||
break;
|
||||
case 0xD://move
|
||||
result = c.Registers[Rd] = Op2;
|
||||
break;
|
||||
case 0xE://bit clear
|
||||
result = c.Registers[Rd] = c.Registers[Rn] & ~Op2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (S)
|
||||
{
|
||||
bool V = c.V;//tmp
|
||||
bool C = c.C;//tmp
|
||||
bool Z = result == 0;
|
||||
bool N = (result >> 31) == 1;
|
||||
if (Rd != 15)
|
||||
{
|
||||
switch (Opcode)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 8:
|
||||
case 9:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
C = Shift_C;
|
||||
break;
|
||||
//case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
//case 10:
|
||||
case 11:
|
||||
C = !(Op2 > c.Registers[Rn]);
|
||||
break;
|
||||
case 0x2:
|
||||
case 0xA:
|
||||
C = !(Op2 > c.Registers[Rn]);
|
||||
V = ((c.Registers[Rn] < 0 && Op2 >= 0) || (c.Registers[Rn] >= 0 && Op2 < 0)) && ((c.Registers[Rn] < 0 && result >= 0) || (c.Registers[Rn] >= 0 && result < 0));
|
||||
break;
|
||||
}
|
||||
c.C = C;
|
||||
c.N = N;
|
||||
c.V = V;
|
||||
c.Z = Z;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void SingleDataTrans(ARM9Context c, UInt32 Instruction)
|
||||
{
|
||||
bool I = ((Instruction >> 25) & 1) == 1;
|
||||
bool P = ((Instruction >> 24) & 1) == 1;
|
||||
bool U = ((Instruction >> 23) & 1) == 1;
|
||||
bool B = ((Instruction >> 22) & 1) == 1;
|
||||
|
||||
bool T = false;
|
||||
bool W = false;
|
||||
|
||||
if (P) W = ((Instruction >> 21) & 1) == 1;
|
||||
else T = ((Instruction >> 21) & 1) == 1;
|
||||
|
||||
bool L = ((Instruction >> 20) & 1) == 1;
|
||||
|
||||
uint Rn = (Instruction >> 16) & 0xF;
|
||||
uint Rd = (Instruction >> 12) & 0xF;
|
||||
|
||||
uint Offset;
|
||||
if (I)
|
||||
{
|
||||
uint Is = (Instruction >> 7) & 0x1F;
|
||||
uint ShiftType = (Instruction >> 5) & 0x3;
|
||||
uint Reserved = (Instruction >> 4) & 1;
|
||||
uint Rm = Instruction & 0xF;
|
||||
bool Shift_C = c.C;
|
||||
Offset = Shift(ShiftType, c.Registers[Rm], Is, ref Shift_C);
|
||||
}
|
||||
else
|
||||
{
|
||||
Offset = Instruction & 0xFFF;
|
||||
}
|
||||
|
||||
uint MemoryOffset = c.Registers[Rn];
|
||||
if (Rn == 15) MemoryOffset += 8;
|
||||
if (P)
|
||||
{
|
||||
if (U) MemoryOffset += Offset;
|
||||
else MemoryOffset -= Offset;
|
||||
if (W) c.Registers[Rn] = MemoryOffset;
|
||||
}
|
||||
if (L)
|
||||
{
|
||||
if (B)
|
||||
{
|
||||
try
|
||||
{
|
||||
c.Registers[Rd] = c.Memory[MemoryOffset];
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
else c.Registers[Rd] = IOUtil.ReadU32LE(c.Memory, (int)MemoryOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Rd == 15)
|
||||
{
|
||||
if (B) c.Memory[MemoryOffset] = (byte)((c.Registers[Rd] + 12) & 0xFF);
|
||||
else Array.Copy(BitConverter.GetBytes(c.Registers[Rd] + 12), 0, c.Memory, MemoryOffset, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (B) c.Memory[MemoryOffset] = (byte)(c.Registers[Rd] & 0xFF);
|
||||
else Array.Copy(BitConverter.GetBytes(c.Registers[Rd]), 0, c.Memory, MemoryOffset, 4);
|
||||
}
|
||||
}
|
||||
if (!P)
|
||||
{
|
||||
if (U) MemoryOffset += Offset;
|
||||
else MemoryOffset -= Offset;
|
||||
c.Registers[Rn] = MemoryOffset;
|
||||
}
|
||||
}
|
||||
|
||||
private static void BlockDataTrans(ARM9Context c, UInt32 Instruction)
|
||||
{
|
||||
bool P = ((Instruction >> 24) & 1) == 1;
|
||||
bool U = ((Instruction >> 23) & 1) == 1;
|
||||
bool S = ((Instruction >> 22) & 1) == 1;
|
||||
bool W = ((Instruction >> 21) & 1) == 1;
|
||||
bool L = ((Instruction >> 20) & 1) == 1;
|
||||
uint Rn = (Instruction >> 16) & 0xF;
|
||||
uint RList = Instruction & 0xFFFF;
|
||||
|
||||
if (!U && ((RList >> 15) & 1) == 1)
|
||||
{
|
||||
//TODO!
|
||||
}
|
||||
|
||||
uint offs = c.Registers[Rn];
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
int reg;
|
||||
if (U) reg = i;
|
||||
else reg = 14 - i;
|
||||
if (((RList >> reg) & 1) == 1)
|
||||
{
|
||||
if (P)
|
||||
{
|
||||
if (U) offs += 4;
|
||||
else offs -= 4;
|
||||
}
|
||||
if (L) c.Registers[reg] = IOUtil.ReadU32LE(c.Memory, (int)offs);
|
||||
else IOUtil.WriteU32LE(c.Memory, (int)offs, c.Registers[reg]);
|
||||
if (!P)
|
||||
{
|
||||
if (U) offs += 4;
|
||||
else offs -= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (U && ((RList >> 15) & 1) == 1)
|
||||
{
|
||||
//TODO!
|
||||
}
|
||||
if (W) c.Registers[Rn] = offs;
|
||||
}
|
||||
|
||||
private static void Branch(ARM9Context c, UInt32 Instruction)
|
||||
{
|
||||
uint Opcode = (Instruction >> 24) & 1;
|
||||
int nn = (int)((Instruction & 0xFFFFFF) << 8) >> 8;
|
||||
if (Opcode == 1)
|
||||
c.Registers[14] = c.Registers[15] + 4;
|
||||
c.Registers[15] = (uint)((int)c.Registers[15] + 8 + nn * 4);
|
||||
}
|
||||
|
||||
private static bool EvaluateCondition(ARM9Context c, uint condition)
|
||||
{
|
||||
switch (condition)
|
||||
{
|
||||
case 0x0: return c.Z == true;
|
||||
case 0x1: return c.Z == false;
|
||||
case 0x2: return c.C == true;
|
||||
case 0x3: return c.C == false;
|
||||
case 0x4: return c.N == true;
|
||||
case 0x5: return c.N == false;
|
||||
case 0x6: return c.V == true;
|
||||
case 0x7: return c.V == false;
|
||||
case 0x8: return c.C == true && c.Z == false;
|
||||
case 0x9: return c.C == false || c.Z == true;
|
||||
case 0xA: return c.N == c.V;
|
||||
case 0xB: return c.N != c.V;
|
||||
case 0xC: return c.Z == false && c.N == c.V;
|
||||
case 0xD: return c.Z == true || c.N != c.V;
|
||||
case 0xE: return true;
|
||||
case 0xF: return false;
|
||||
}
|
||||
//shouldn't happen!
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using System.IO;
|
||||
|
||||
namespace NDS.CPU
|
||||
{
|
||||
[Serializable]
|
||||
[XmlRoot("ASMHack")]
|
||||
public class ASMHackInfo
|
||||
{
|
||||
public ASMHackInfo() { }
|
||||
public ASMHackInfo(NDS Rom, UInt32 AreaLo)
|
||||
{
|
||||
AddressInfo.RamAddress = Rom.Header.MainRamAddress;
|
||||
AddressInfo.EntryAddress = Rom.Header.MainEntryAddress;
|
||||
AddressInfo.AutoloadDoneAddress = Rom.Header.MainAutoloadDone;
|
||||
AddressInfo.ArenaLo = AreaLo;
|
||||
//Default:
|
||||
InPath = "arm9.bin";
|
||||
OutPath = "arm9_new.bin";
|
||||
}
|
||||
|
||||
[XmlElement("Addresses")]
|
||||
public Addresses AddressInfo = new Addresses();
|
||||
public class Addresses : IXmlSerializable
|
||||
{
|
||||
public UInt32 RamAddress;
|
||||
public UInt32 EntryAddress;
|
||||
public UInt32 AutoloadDoneAddress;
|
||||
public UInt32 ArenaLo;
|
||||
|
||||
public System.Xml.Schema.XmlSchema GetSchema()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ReadXml(System.Xml.XmlReader reader)
|
||||
{
|
||||
reader.ReadStartElement("RamAddress");
|
||||
{
|
||||
RamAddress = uint.Parse(reader.ReadString().Replace("0x", ""), System.Globalization.NumberStyles.HexNumber);
|
||||
}
|
||||
reader.ReadEndElement();
|
||||
reader.ReadStartElement("EntryAddress");
|
||||
{
|
||||
EntryAddress = uint.Parse(reader.ReadString().Replace("0x", ""), System.Globalization.NumberStyles.HexNumber);
|
||||
}
|
||||
reader.ReadEndElement();
|
||||
reader.ReadStartElement("AutoloadDoneAddress");
|
||||
{
|
||||
AutoloadDoneAddress = uint.Parse(reader.ReadString().Replace("0x", ""), System.Globalization.NumberStyles.HexNumber);
|
||||
}
|
||||
reader.ReadEndElement();
|
||||
reader.ReadStartElement("ArenaLo");
|
||||
{
|
||||
ArenaLo = uint.Parse(reader.ReadString().Replace("0x", ""), System.Globalization.NumberStyles.HexNumber);
|
||||
}
|
||||
reader.ReadEndElement();
|
||||
}
|
||||
|
||||
public void WriteXml(System.Xml.XmlWriter writer)
|
||||
{
|
||||
writer.WriteStartElement("RamAddress");
|
||||
{
|
||||
writer.WriteString("0x" + RamAddress.ToString("X8"));
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
writer.WriteStartElement("EntryAddress");
|
||||
{
|
||||
writer.WriteString("0x" + EntryAddress.ToString("X8"));
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
writer.WriteStartElement("AutoloadDoneAddress");
|
||||
{
|
||||
writer.WriteString("0x" + AutoloadDoneAddress.ToString("X8"));
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
writer.WriteStartElement("ArenaLo");
|
||||
{
|
||||
writer.WriteString("0x" + ArenaLo.ToString("X8"));
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
public String InPath;
|
||||
public String OutPath;
|
||||
|
||||
public static ASMHackInfo FromByteArray(byte[] Data)
|
||||
{
|
||||
XmlSerializer s = new XmlSerializer(typeof(ASMHackInfo));
|
||||
return (ASMHackInfo)s.Deserialize(new MemoryStream(Data));
|
||||
}
|
||||
|
||||
public byte[] Write()
|
||||
{
|
||||
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
|
||||
ns.Add("", "");
|
||||
XmlSerializer s = new XmlSerializer(typeof(ASMHackInfo));
|
||||
MemoryStream m = new MemoryStream();
|
||||
s.Serialize(m, this, ns);
|
||||
byte[] data = m.ToArray();
|
||||
m.Close();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
25
NDS/NDS.cs
25
NDS/NDS.cs
@ -8,7 +8,7 @@ using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using LibEveryFileExplorer.Files.SimpleFileSystem;
|
||||
using NDS.UI;
|
||||
using NDS.CPU;
|
||||
using NDS.Nitro;
|
||||
|
||||
namespace NDS
|
||||
{
|
||||
@ -21,6 +21,11 @@ namespace NDS
|
||||
|
||||
er.BaseStream.Position = Header.MainRomOffset;
|
||||
MainRom = er.ReadBytes((int)Header.MainSize);
|
||||
if (er.ReadUInt32() == 0xDEC00621)//Nitro Footer!
|
||||
{
|
||||
er.BaseStream.Position -= 4;
|
||||
StaticFooter = new NitroFooter(er);
|
||||
}
|
||||
|
||||
er.BaseStream.Position = Header.SubRomOffset;
|
||||
SubRom = er.ReadBytes((int)Header.SubSize);
|
||||
@ -159,6 +164,21 @@ namespace NDS
|
||||
public UInt16 HeaderCRC;
|
||||
}
|
||||
public Byte[] MainRom;
|
||||
public NitroFooter StaticFooter;
|
||||
public class NitroFooter
|
||||
{
|
||||
public NitroFooter(EndianBinaryReader er)
|
||||
{
|
||||
NitroCode = er.ReadUInt32();
|
||||
_start_ModuleParamsOffset = er.ReadUInt32();
|
||||
Unknown = er.ReadUInt32();
|
||||
}
|
||||
public UInt32 NitroCode;
|
||||
public UInt32 _start_ModuleParamsOffset;
|
||||
public UInt32 Unknown;
|
||||
}
|
||||
|
||||
|
||||
public Byte[] SubRom;
|
||||
public RomFNT Fnt;
|
||||
public class RomFNT
|
||||
@ -352,7 +372,8 @@ namespace NDS
|
||||
|
||||
public byte[] GetDecompressedARM9()
|
||||
{
|
||||
return ARM9.Decompress(MainRom, Header.MainRamAddress, Header.MainEntryAddress, Header.MainAutoloadDone);
|
||||
if (StaticFooter != null) return ARM9.Decompress(MainRom, StaticFooter._start_ModuleParamsOffset);
|
||||
else return ARM9.Decompress(MainRom);
|
||||
}
|
||||
|
||||
public class NDSIdentifier : FileFormatIdentifier
|
||||
|
@ -52,8 +52,8 @@
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CPU\ARM9.cs" />
|
||||
<Compile Include="CPU\ASMHackInfo.cs" />
|
||||
<Compile Include="Nitro\ARM9.cs" />
|
||||
<Compile Include="Nitro\ASMHack.cs" />
|
||||
<Compile Include="GPU\CommandContext.cs" />
|
||||
<Compile Include="GPU\Textures.cs" />
|
||||
<Compile Include="NDS.cs" />
|
||||
@ -67,6 +67,7 @@
|
||||
<Compile Include="NitroSystem\G3D\SBC.cs" />
|
||||
<Compile Include="NitroSystem\G3D\TEX0.cs" />
|
||||
<Compile Include="NitroSystem\G3D\Util.cs" />
|
||||
<Compile Include="Nitro\CRT0.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Resource.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
|
169
NDS/Nitro/ARM9.cs
Normal file
169
NDS/Nitro/ARM9.cs
Normal file
@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using LibEveryFileExplorer.IO;
|
||||
using System.IO;
|
||||
|
||||
namespace NDS.Nitro
|
||||
{
|
||||
public class ARM9
|
||||
{
|
||||
private UInt32 RamAddress;
|
||||
|
||||
private byte[] StaticData;
|
||||
|
||||
private UInt32 _start_ModuleParamsOffset;
|
||||
private CRT0.ModuleParams _start_ModuleParams;
|
||||
|
||||
private List<CRT0.AutoLoadEntry> AutoLoadList;
|
||||
|
||||
public ARM9(byte[] Data, UInt32 RamAddress)
|
||||
: this(Data, RamAddress, FindModuleParams(Data)) { }
|
||||
|
||||
public ARM9(byte[] Data, UInt32 RamAddress, UInt32 _start_ModuleParamsOffset)
|
||||
{
|
||||
//Unimportant static footer! Use it for _start_ModuleParamsOffset and remove it.
|
||||
if (IOUtil.ReadU32LE(Data, Data.Length - 12) == 0xDEC00621)
|
||||
{
|
||||
_start_ModuleParamsOffset = IOUtil.ReadU32LE(Data, Data.Length - 8);
|
||||
byte[] data_tmp = new byte[Data.Length - 12];
|
||||
Array.Copy(Data, data_tmp, Data.Length - 12);
|
||||
Data = data_tmp;
|
||||
}
|
||||
|
||||
this.RamAddress = RamAddress;
|
||||
this._start_ModuleParamsOffset = _start_ModuleParamsOffset;
|
||||
_start_ModuleParams = new CRT0.ModuleParams(Data, _start_ModuleParamsOffset);
|
||||
if (_start_ModuleParams.CompressedStaticEnd != 0)
|
||||
{
|
||||
Data = Decompress(Data, _start_ModuleParamsOffset);
|
||||
_start_ModuleParams = new CRT0.ModuleParams(Data, _start_ModuleParamsOffset);
|
||||
}
|
||||
|
||||
StaticData = new byte[_start_ModuleParams.AutoLoadStart - RamAddress];
|
||||
Array.Copy(Data, StaticData, _start_ModuleParams.AutoLoadStart - RamAddress);
|
||||
|
||||
AutoLoadList = new List<CRT0.AutoLoadEntry>();
|
||||
uint nr = (_start_ModuleParams.AutoLoadListEnd - _start_ModuleParams.AutoLoadListOffset) / 0xC;
|
||||
uint Offset = _start_ModuleParams.AutoLoadStart - RamAddress;
|
||||
for (int i = 0; i < nr; i++)
|
||||
{
|
||||
var entry = new CRT0.AutoLoadEntry(Data, _start_ModuleParams.AutoLoadListOffset - RamAddress + (uint)i * 0xC);
|
||||
entry.Data = new byte[entry.Size];
|
||||
Array.Copy(Data, Offset, entry.Data, 0, entry.Size);
|
||||
AutoLoadList.Add(entry);
|
||||
Offset += entry.Size;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Write()
|
||||
{
|
||||
MemoryStream m = new MemoryStream();
|
||||
EndianBinaryWriter er = new EndianBinaryWriter(m, Endianness.LittleEndian);
|
||||
er.Write(StaticData, 0, StaticData.Length);
|
||||
_start_ModuleParams.AutoLoadStart = (uint)er.BaseStream.Position + RamAddress;
|
||||
foreach (var v in AutoLoadList) er.Write(v.Data, 0, v.Data.Length);
|
||||
_start_ModuleParams.AutoLoadListOffset = (uint)er.BaseStream.Position + RamAddress;
|
||||
foreach (var v in AutoLoadList) v.Write(er);
|
||||
_start_ModuleParams.AutoLoadListEnd = (uint)er.BaseStream.Position + RamAddress;
|
||||
long curpos = er.BaseStream.Position;
|
||||
er.BaseStream.Position = _start_ModuleParamsOffset;
|
||||
_start_ModuleParams.Write(er);
|
||||
er.BaseStream.Position = curpos;
|
||||
byte[] data = m.ToArray();
|
||||
er.Close();
|
||||
return data;
|
||||
}
|
||||
|
||||
public void AddAutoLoadEntry(UInt32 Address, byte[] Data)
|
||||
{
|
||||
AutoLoadList.Add(new CRT0.AutoLoadEntry(Address, Data));
|
||||
}
|
||||
|
||||
public bool WriteU16LE(UInt32 Address, UInt16 Value)
|
||||
{
|
||||
if (Address > RamAddress && Address < _start_ModuleParams.AutoLoadStart)
|
||||
{
|
||||
IOUtil.WriteU16LE(StaticData, (int)(Address - RamAddress), Value);
|
||||
return true;
|
||||
}
|
||||
foreach (var v in AutoLoadList)
|
||||
{
|
||||
if (Address > v.Address && Address < (v.Address + v.Size))
|
||||
{
|
||||
IOUtil.WriteU16LE(v.Data, (int)(Address - v.Address), Value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public UInt32 ReadU32LE(UInt32 Address)
|
||||
{
|
||||
if (Address > RamAddress && Address < _start_ModuleParams.AutoLoadStart)
|
||||
{
|
||||
return IOUtil.ReadU32LE(StaticData, (int)(Address - RamAddress));
|
||||
}
|
||||
foreach (var v in AutoLoadList)
|
||||
{
|
||||
if (Address > v.Address && Address < (v.Address + v.Size))
|
||||
{
|
||||
return IOUtil.ReadU32LE(v.Data, (int)(Address - v.Address));
|
||||
}
|
||||
}
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
public bool WriteU32LE(UInt32 Address, UInt32 Value)
|
||||
{
|
||||
if (Address > RamAddress && Address < _start_ModuleParams.AutoLoadStart)
|
||||
{
|
||||
IOUtil.WriteU32LE(StaticData, (int)(Address - RamAddress), Value);
|
||||
return true;
|
||||
}
|
||||
foreach (var v in AutoLoadList)
|
||||
{
|
||||
if (Address > v.Address && Address < (v.Address + v.Size))
|
||||
{
|
||||
IOUtil.WriteU32LE(v.Data, (int)(Address - v.Address), Value);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static byte[] Decompress(byte[] Data)
|
||||
{
|
||||
return Decompress(Data, FindModuleParams(Data));
|
||||
}
|
||||
|
||||
public static byte[] Decompress(byte[] Data, UInt32 _start_ModuleParamsOffset)
|
||||
{
|
||||
if (IOUtil.ReadU32LE(Data, (int)_start_ModuleParamsOffset + 0x14) == 0) return Data;//Not Compressed!
|
||||
byte[] Result = CRT0.MIi_UncompressBackward(Data);
|
||||
IOUtil.WriteU32LE(Data, (int)_start_ModuleParamsOffset + 0x14, 0);
|
||||
return Result;
|
||||
}
|
||||
|
||||
private static uint FindModuleParams(byte[] Data)
|
||||
{
|
||||
return (uint)IndexOf(Data, new byte[] { 0x21, 0x06, 0xC0, 0xDE, 0xDE, 0xC0, 0x06, 0x21 }) - 0x1C;
|
||||
}
|
||||
|
||||
private static unsafe long IndexOf(byte[] Data, byte[] Search)
|
||||
{
|
||||
fixed (byte* H = Data) fixed (byte* N = Search)
|
||||
{
|
||||
long i = 0;
|
||||
for (byte* hNext = H, hEnd = H + Data.LongLength; hNext < hEnd; i++, hNext++)
|
||||
{
|
||||
bool Found = true;
|
||||
for (byte* hInc = hNext, nInc = N, nEnd = N + Search.LongLength; Found && nInc < nEnd; Found = *nInc == *hInc, nInc++, hInc++) ;
|
||||
if (Found) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
165
NDS/Nitro/ASMHack.cs
Normal file
165
NDS/Nitro/ASMHack.cs
Normal file
@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml.Serialization;
|
||||
using System.IO;
|
||||
using System.Windows.Forms;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace NDS.Nitro
|
||||
{
|
||||
public class ASMHack
|
||||
{
|
||||
public void Insert(String Path, ARM9 Arm9)
|
||||
{
|
||||
ASMHackInfo Info = ASMHackInfo.FromByteArray(File.ReadAllBytes(Path + "\\config.xml"));
|
||||
|
||||
UInt32 ArenaLoOffset = Info.ArenaLo;//UInt32.Parse(File.ReadAllText(CodeDir + "\\arenaoffs.txt"), System.Globalization.NumberStyles.HexNumber);
|
||||
UInt32 ArenaLo = Arm9.ReadU32LE(ArenaLoOffset);
|
||||
Compile(Path, ArenaLo);
|
||||
if (!File.Exists(Path + "\\newcode.bin"))
|
||||
{
|
||||
MessageBox.Show("An compile error occurred!");
|
||||
return;
|
||||
}
|
||||
byte[] NewCode = File.ReadAllBytes(Path + "\\newcode.bin");
|
||||
|
||||
StreamReader r = new StreamReader(Path + "\\newcode.sym");
|
||||
string CurrentLine;
|
||||
while ((CurrentLine = r.ReadLine()) != null)
|
||||
{
|
||||
string[] Line = CurrentLine.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (Line.Length == 4)
|
||||
{
|
||||
if (Line[3].Length < 7) continue;
|
||||
switch (Line[3].Remove(6))
|
||||
{
|
||||
case "arepl_":
|
||||
{
|
||||
String ReplaceOffsetString = Line[3].Replace("arepl_", "");
|
||||
UInt32 ReplaceOffset = UInt32.Parse(ReplaceOffsetString, System.Globalization.NumberStyles.HexNumber);
|
||||
UInt32 Replace = 0xEB000000;//BL Instruction
|
||||
UInt32 DestinationOffset = UInt32.Parse(Line[0], System.Globalization.NumberStyles.HexNumber);
|
||||
UInt32 RelativeDestinationOffset = (DestinationOffset / 4) - (ReplaceOffset / 4) - 2;
|
||||
RelativeDestinationOffset &= 0x00FFFFFF;
|
||||
Replace |= RelativeDestinationOffset;
|
||||
if (!Arm9.WriteU32LE(ReplaceOffset, Replace)) System.Windows.Forms.MessageBox.Show("The offset of function " + Line[3] + " is invalid. Maybe your code is inside an overlay or you wrote the wrong offset.");
|
||||
break;
|
||||
}
|
||||
case "ansub_":
|
||||
{
|
||||
String ReplaceOffsetString = Line[3].Replace("ansub_", "");
|
||||
UInt32 ReplaceOffset = UInt32.Parse(ReplaceOffsetString, System.Globalization.NumberStyles.HexNumber);
|
||||
UInt32 Replace = 0xEA000000;//B Instruction
|
||||
UInt32 DestinationOffset = UInt32.Parse(Line[0], System.Globalization.NumberStyles.HexNumber);
|
||||
UInt32 RelativeDestinationOffset = (DestinationOffset / 4) - (ReplaceOffset / 4) - 2;
|
||||
RelativeDestinationOffset &= 0x00FFFFFF;
|
||||
Replace |= RelativeDestinationOffset;
|
||||
if (!Arm9.WriteU32LE(ReplaceOffset, Replace)) System.Windows.Forms.MessageBox.Show("The offset of function " + Line[3] + " is invalid. Maybe your code is inside an overlay or you wrote the wrong offset.");
|
||||
break;
|
||||
}
|
||||
case "trepl_":
|
||||
{
|
||||
String ReplaceOffsetString = Line[3].Replace("trepl_", "");
|
||||
UInt32 ReplaceOffset = UInt32.Parse(ReplaceOffsetString, System.Globalization.NumberStyles.HexNumber);
|
||||
UInt16 Replace1 = 0xF000;//BLX Instruction (Part 1)
|
||||
UInt16 Replace2 = 0xE800;//BLX Instruction (Part 2)
|
||||
UInt32 DestinationOffset = UInt32.Parse(Line[0], System.Globalization.NumberStyles.HexNumber);
|
||||
UInt32 RelativeDestinationOffset = DestinationOffset - ReplaceOffset - 2;
|
||||
RelativeDestinationOffset >>= 1;
|
||||
RelativeDestinationOffset &= 0x003FFFFF;
|
||||
Replace1 |= (UInt16)((RelativeDestinationOffset >> 11) & 0x7FF);
|
||||
Replace2 |= (UInt16)((RelativeDestinationOffset >> 0) & 0x7FE);
|
||||
if (!Arm9.WriteU16LE(ReplaceOffset, Replace1)) { MessageBox.Show("The offset of function " + Line[3] + " is invalid. Maybe your code is inside an overlay or you wrote the wrong offset.\r\nIf your code is inside an overlay, this is an action replay code to let your asm hack still work:\r\n1" + string.Format("{0:X7}", ReplaceOffset) + " 0000" + string.Format("{0:X4}", Replace1) + "\r\n1" + string.Format("{0:X7}", ReplaceOffset + 2) + " 0000" + string.Format("{0:X4}", Replace2)); break; }
|
||||
else Arm9.WriteU16LE(ReplaceOffset + 2, Replace2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
r.Close();
|
||||
Arm9.WriteU32LE(ArenaLoOffset, ArenaLo + (uint)NewCode.Length);
|
||||
Arm9.AddAutoLoadEntry(ArenaLo, NewCode);
|
||||
File.Delete(Path + "\\newcode.bin");
|
||||
File.Delete(Path + "\\newcode.elf");
|
||||
File.Delete(Path + "\\newcode.sym");
|
||||
Directory.Delete(Path + "\\build", true);
|
||||
}
|
||||
|
||||
private static void Compile(String Path, UInt32 ArenaLo)
|
||||
{
|
||||
Process p = new Process();
|
||||
p.StartInfo.FileName = "cmd";
|
||||
p.StartInfo.Arguments = "/C make CODEADDR=0x" + ArenaLo.ToString("X8") + " || pause";
|
||||
p.StartInfo.WorkingDirectory = Path;
|
||||
p.Start();
|
||||
p.WaitForExit();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[XmlRoot("ASMHack")]
|
||||
public class ASMHackInfo : IXmlSerializable
|
||||
{
|
||||
public ASMHackInfo() { }
|
||||
public ASMHackInfo(NDS Rom, UInt32 AreaLo)
|
||||
{
|
||||
RamAddress = Rom.Header.MainRamAddress;
|
||||
this.ArenaLo = AreaLo;
|
||||
}
|
||||
|
||||
public UInt32 RamAddress;
|
||||
public UInt32 ArenaLo;
|
||||
public System.Xml.Schema.XmlSchema GetSchema()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ReadXml(System.Xml.XmlReader reader)
|
||||
{
|
||||
reader.ReadStartElement("RamAddress");
|
||||
{
|
||||
RamAddress = uint.Parse(reader.ReadString().Replace("0x", ""), System.Globalization.NumberStyles.HexNumber);
|
||||
}
|
||||
reader.ReadEndElement();
|
||||
reader.ReadStartElement("ArenaLo");
|
||||
{
|
||||
ArenaLo = uint.Parse(reader.ReadString().Replace("0x", ""), System.Globalization.NumberStyles.HexNumber);
|
||||
}
|
||||
reader.ReadEndElement();
|
||||
}
|
||||
|
||||
public void WriteXml(System.Xml.XmlWriter writer)
|
||||
{
|
||||
writer.WriteStartElement("RamAddress");
|
||||
{
|
||||
writer.WriteString("0x" + RamAddress.ToString("X8"));
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
writer.WriteStartElement("ArenaLo");
|
||||
{
|
||||
writer.WriteString("0x" + ArenaLo.ToString("X8"));
|
||||
}
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
public static ASMHackInfo FromByteArray(byte[] Data)
|
||||
{
|
||||
XmlSerializer s = new XmlSerializer(typeof(ASMHackInfo));
|
||||
return (ASMHackInfo)s.Deserialize(new MemoryStream(Data));
|
||||
}
|
||||
|
||||
public byte[] Write()
|
||||
{
|
||||
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
|
||||
ns.Add("", "");
|
||||
XmlSerializer s = new XmlSerializer(typeof(ASMHackInfo));
|
||||
MemoryStream m = new MemoryStream();
|
||||
s.Serialize(m, this, ns);
|
||||
byte[] data = m.ToArray();
|
||||
m.Close();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
110
NDS/Nitro/CRT0.cs
Normal file
110
NDS/Nitro/CRT0.cs
Normal file
@ -0,0 +1,110 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using LibEveryFileExplorer.IO;
|
||||
using System.IO;
|
||||
|
||||
namespace NDS.Nitro
|
||||
{
|
||||
public class CRT0
|
||||
{
|
||||
public class ModuleParams
|
||||
{
|
||||
public ModuleParams(byte[] Data, uint Offset)
|
||||
{
|
||||
AutoLoadListOffset = IOUtil.ReadU32LE(Data, (int)Offset + 0);
|
||||
AutoLoadListEnd = IOUtil.ReadU32LE(Data, (int)Offset + 4);
|
||||
AutoLoadStart = IOUtil.ReadU32LE(Data, (int)Offset + 8);
|
||||
StaticBssStart = IOUtil.ReadU32LE(Data, (int)Offset + 12);
|
||||
StaticBssEnd = IOUtil.ReadU32LE(Data, (int)Offset + 16);
|
||||
CompressedStaticEnd = IOUtil.ReadU32LE(Data, (int)Offset + 20);
|
||||
SDKVersion = IOUtil.ReadU32LE(Data, (int)Offset + 24);
|
||||
NitroCodeBE = IOUtil.ReadU32LE(Data, (int)Offset + 28);
|
||||
NitroCodeLE = IOUtil.ReadU32LE(Data, (int)Offset + 32);
|
||||
}
|
||||
public void Write(EndianBinaryWriter er)
|
||||
{
|
||||
er.Write(AutoLoadListOffset);
|
||||
er.Write(AutoLoadListEnd);
|
||||
er.Write(AutoLoadStart);
|
||||
er.Write(StaticBssStart);
|
||||
er.Write(StaticBssEnd);
|
||||
er.Write(CompressedStaticEnd);
|
||||
er.Write(SDKVersion);
|
||||
er.Write(NitroCodeBE);
|
||||
er.Write(NitroCodeLE);
|
||||
}
|
||||
public UInt32 AutoLoadListOffset;
|
||||
public UInt32 AutoLoadListEnd;
|
||||
public UInt32 AutoLoadStart;
|
||||
public UInt32 StaticBssStart;
|
||||
public UInt32 StaticBssEnd;
|
||||
public UInt32 CompressedStaticEnd;
|
||||
public UInt32 SDKVersion;
|
||||
public UInt32 NitroCodeBE;
|
||||
public UInt32 NitroCodeLE;
|
||||
}
|
||||
|
||||
public class AutoLoadEntry
|
||||
{
|
||||
public AutoLoadEntry(UInt32 Address, byte[] Data)
|
||||
{
|
||||
this.Address = Address;
|
||||
this.Data = Data;
|
||||
Size = (uint)Data.Length;
|
||||
BssSize = 0;
|
||||
}
|
||||
public AutoLoadEntry(byte[] Data, uint Offset)
|
||||
{
|
||||
Address = IOUtil.ReadU32LE(Data, (int)Offset + 0);
|
||||
Size = IOUtil.ReadU32LE(Data, (int)Offset + 4);
|
||||
BssSize = IOUtil.ReadU32LE(Data, (int)Offset + 8);
|
||||
}
|
||||
public void Write(EndianBinaryWriter er)
|
||||
{
|
||||
er.Write(Address);
|
||||
er.Write(Size);
|
||||
er.Write(BssSize);
|
||||
}
|
||||
public UInt32 Address;
|
||||
public UInt32 Size;
|
||||
public UInt32 BssSize;
|
||||
|
||||
public byte[] Data;
|
||||
}
|
||||
|
||||
public static byte[] MIi_UncompressBackward(byte[] Data)
|
||||
{
|
||||
UInt32 leng = IOUtil.ReadU32LE(Data, Data.Length - 4) + (uint)Data.Length;
|
||||
byte[] Result = new byte[leng];
|
||||
Array.Copy(Data, Result, Data.Length);
|
||||
int Offs = (int)(Data.Length - (IOUtil.ReadU32LE(Data, Data.Length - 8) >> 24));
|
||||
int dstoffs = (int)leng;
|
||||
while (true)
|
||||
{
|
||||
byte header = Result[--Offs];
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if ((header & 0x80) == 0) Result[--dstoffs] = Result[--Offs];
|
||||
else
|
||||
{
|
||||
byte a = Result[--Offs];
|
||||
byte b = Result[--Offs];
|
||||
int offs = (((a & 0xF) << 8) | b) + 2;//+ 1;
|
||||
int length = (a >> 4) + 2;
|
||||
do
|
||||
{
|
||||
Result[dstoffs - 1] = Result[dstoffs + offs];
|
||||
dstoffs--;
|
||||
length--;
|
||||
}
|
||||
while (length >= 0);
|
||||
}
|
||||
if (Offs <= (Data.Length - (IOUtil.ReadU32LE(Data, Data.Length - 8) & 0xFFFFFF))) return Result;
|
||||
header <<= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
2
NDS/UI/NDSViewer.Designer.cs
generated
2
NDS/UI/NDSViewer.Designer.cs
generated
@ -341,7 +341,7 @@
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Menu = this.mainMenu1;
|
||||
this.Name = "NDSViewer";
|
||||
this.Text = "NARC Viewer";
|
||||
this.Text = "NDS Viewer";
|
||||
this.Load += new System.EventHandler(this.NARCViewer_Load);
|
||||
this.splitContainer1.Panel1.ResumeLayout(false);
|
||||
this.splitContainer1.Panel2.ResumeLayout(false);
|
||||
|
Loading…
Reference in New Issue
Block a user