static void BindSegment(RomVersion version, ORom.FileList fileO, MRom.FileList fileM, ref Ptr ram, ref Ptr rom) { RomFileToken token = RomFileToken.Select(version, fileO, fileM); if (Options.MapfileOptions.CanUseMap(version)) { Segment seg = Options.MapfileOptions.SymbolMap.GetSegment(token.ToString()); if (seg != null) { ram = SPtr.New(seg.Address); rom = SPtr.New(seg.LoadAddress); } else { Console.WriteLine($"Segment {token} not found."); } } else { Addresser.TryGetRam(token, version, out var t1); ram = SPtr.New(t1); Addresser.TryGetRom(token, version, t1, out var t2); rom = SPtr.New(t2); } }
public static void MMEntranceTable(IExperimentFace face, List <string> file) { MRom rom = new(file[0], MRom.Build.U0); //scenes (7 bits, 0x6E max) //entrance sets (5 bits, 32 max) //entrance setups(32 max) StringBuilder sb = new(); RomFile code = rom.Files.GetFile(MRom.FileList.code); BinaryReader br = new(code); int sceneBase; //Sets of entrance records per scene int entranceSetsPointerAddr; uint entranceSetsPointer; int entranceSetsAddr; //Single set of entrance records (single entrance) int eNumPointerAddr; uint eNumPointer; int eNumAddr; //get rom address of sceneTableBase sceneBase = Addresser.GetRom(MRom.FileList.code, rom.Version, AddressToken.EntranceIndexTable_Start); //for every scene for (int scene = 0; scene < 0x6E; scene++) { //get offset of pointer to the entrance sets entranceSetsPointerAddr = sceneBase + (sizeof(int) * 3) * scene + 4; //move the stream to the entrance sets pointer br.BaseStream.Position = code.Record.GetRelativeAddress(entranceSetsPointerAddr); //read the entranceSetsPointer (scene) entranceSetsPointer = br.ReadBigUInt32(); //if invalid if (!IsPointer(entranceSetsPointer) || !Addresser.TryGetRom (MRom.FileList.code, rom.Version, entranceSetsPointer, out entranceSetsAddr) || code.Record.GetRelativeAddress(entranceSetsAddr) >= code.Record.VRom.End) { //entrance index base, offset, sptr, eptr, entb1,2,3,4 sb.AppendFormat("{0:X4},{1},{2:X8},{3:X8},{4:X2},{5:X2},{6:X2},{7:X2}", GetEntranceIndex(scene, 0), 0, entranceSetsPointer, 0, 255, 0, 0, 0); sb.AppendLine(); continue; } //entranceSetsAddr now contains the rom address to the first entrance set pointer //for every theoretical entrance set for (int entranceSet = 0; entranceSet < 32; entranceSet++) { eNumPointerAddr = entranceSetsAddr + (sizeof(UInt32) * entranceSet); //move the stream to the entrance set pointer br.BaseStream.Position = code.Record.GetRelativeAddress(eNumPointerAddr); //read the entranceSetPointer (entrance set) eNumPointer = br.ReadBigUInt32(); //if invalid if (!IsPointer(eNumPointer) || !Addresser.TryGetRom (MRom.FileList.code, rom.Version, eNumPointer, out eNumAddr) || code.Record.GetRelativeAddress(eNumAddr) >= code.Record.VRom.End) { //entrance index base, offset, sptr, eptr, entb1,2,3,4 sb.AppendFormat("{0:X4},{1},{2:X8},{3:X8},{4:X2},{5:X2},{6:X2},{7:X2}", GetEntranceIndex(scene, entranceSet), 0, entranceSetsPointer, eNumPointer, 255, 0, 0, 0); sb.AppendLine(); continue; } //eNumAddr is valid br.BaseStream.Position = code.Record.GetRelativeAddress(eNumAddr); for (int entrance = 0; entrance < 32; entrance++) { //entrance index base, offset, sptr, eptr, entb1,2,3,4 sb.AppendFormat("{0:X4},{1},{2:X8},{3:X8},{4:X2},{5:X2},{6:X2},{7:X2}", GetEntranceIndex(scene, entranceSet), entrance, entranceSetsPointer, eNumPointer, br.ReadByte(), br.ReadByte(), br.ReadByte(), br.ReadByte()); sb.AppendLine(); } } } face.OutputText(sb.ToString()); }
public static StringBuilder Calculate(IExperimentFace face, List <string> files) { StringBuilder result = new StringBuilder(); int N0_SceneEndAddr = 0x384980; int N0_CodeAddr = 0x110A0; SegmentAddress[] SegmentTable = new SegmentAddress[16]; Dictionary <short, EntranceTableRecord> EntranceTableSimplified = new Dictionary <short, EntranceTableRecord>(); Rom N0 = new ORom(files[0], ORom.Build.N0); Addresser.TryGetRom(ORom.FileList.code, N0.Version, AddressToken.EntranceIndexTable_Start, out int entranceTableAddress); Addresser.TryGetRom(ORom.FileList.code, N0.Version, AddressToken.ActorTable_Start, out int actorTableRomAddress); var code_File = N0.Files.GetFile(ORom.FileList.code); var codeStr = new BinaryReader(code_File); codeStr.BaseStream.Position = code_File.Record.GetRelativeAddress(entranceTableAddress); //remove redundant entrance table records for (int i = 0; i < 0x614; i++) { var record = new EntranceTableRecord(codeStr); short key = (short)((record.Scene << 8) + record.Spawn); if (!EntranceTableSimplified.ContainsKey(key)) { EntranceTableSimplified.Add(key, record); } } int lastScene = -1; RomFile scene_File = null; BinaryReader sceneStr = null; foreach (EntranceTableRecord record in EntranceTableSimplified.Values.OrderBy(x => x.Scene)) { if (sceneStr != null) { sceneStr.BaseStream.Position = 0; } if (record.Scene != lastScene) { if (record.Scene >= 101) { WriteResult(result, record, -1, ResultType.Crash, "No Scene"); continue; } scene_File = N0.Files.GetSceneFile(record.Scene); sceneStr = new BinaryReader(scene_File.Stream); SegmentTable[2] = N0_SceneEndAddr - scene_File.Record.VRom.Size; } //First, 0x18 command byte cmdId = sceneStr.ReadByte(); sceneStr.BaseStream.Position--; List <AlternateSetup> setups = new List <AlternateSetup>(); if (cmdId == 0x18) { sceneStr.BaseStream.Position += 4; int headerListOffset = sceneStr.ReadBigInt32() & 0xFFFFFF; sceneStr.BaseStream.Position = headerListOffset + 0xC; for (int i = 0; i < 0xD; i++) { int data = sceneStr.ReadBigInt32(); setups.Add(new AlternateSetup(i, data)); } } else { setups.Add(new AlternateSetup(-1, 0x02000000)); } //parse headers foreach (var setup in setups) { SceneHeader sceneHeader = new SceneHeader(); FaroresTest ft = FaroresTest.NA; //resolve header start if (setup.SegmentAddress.Segment != 2 || !(setup.SegmentAddress.Offset < scene_File.Record.VRom.Size)) { WriteResult(result, record, setup.SceneSetup, ResultType.Crash_Likely, UnresolvedAddress("Scene Setup", setup.SegmentAddress)); continue; } //set header start sceneStr.BaseStream.Position = setup.SegmentAddress.Offset; int loop = 32; while (loop > 0) { loop--; cmdId = sceneStr.ReadByte(); sceneStr.BaseStream.Position--; switch (cmdId) { case 0x14: if (sceneHeader.Cutscene == 0) { WriteResult(result, record, setup.SceneSetup, ResultType.Cutscene_Pointer, "No Known Issues", ft); } else { WriteResult(result, record, setup.SceneSetup, ResultType.Cutscene, "No Known Issues", ft); } loop = -1; break; case 0x04: //room definitions { sceneStr.BaseStream.Position += 1; sceneHeader.Rooms = sceneStr.ReadByte(); sceneStr.BaseStream.Position += 2; sceneHeader.RoomsAddress = sceneStr.ReadBigInt32(); break; } case 0x06: //entrance index definitions { sceneStr.BaseStream.Position += 4; sceneHeader.EntranceIndexDefinitionsAddress = sceneStr.ReadBigInt32(); break; } case 0x00: //Link spawns definitions { long seekBack; sceneStr.BaseStream.Position += 1; sceneHeader.LinkSpawns = sceneStr.ReadByte(); sceneStr.BaseStream.Position += 2; sceneHeader.LinkSpawnsAddress = sceneStr.ReadBigInt32(); //start resolving things here I guess SegmentAddress selectEntDefAddr = sceneHeader.EntranceIndexDefinitionsAddress + (record.Spawn << 1); if (selectEntDefAddr.Segment != 2 && selectEntDefAddr.Offset > scene_File.Record.VRom.Size) { WriteResult(result, record, setup.SceneSetup, ResultType.Crash_Likely, UnresolvedAddress("Entrance Definitions", selectEntDefAddr)); loop = -1; break; } seekBack = sceneStr.BaseStream.Position; sceneStr.BaseStream.Position = selectEntDefAddr.Offset; int spawnId = sceneStr.ReadByte(); int mapId = sceneStr.ReadByte(); //test if Link Spawn is invalid (phase 1) SegmentAddress selectSpawnAddr = sceneHeader.LinkSpawnsAddress + (spawnId << 4); if (selectSpawnAddr.Segment != 2 && selectSpawnAddr.Offset > scene_File.Record.VRom.Size) { WriteResult(result, record, setup.SceneSetup, ResultType.Crash_Likely, UnresolvedAddress("Link Spawn", selectSpawnAddr), ft); loop = -1; break; } //test if Map Id is invalid, making FW mandatory if (!(mapId < sceneHeader.Rooms)) { WriteResult(result, record, setup.SceneSetup, ResultType.Crash, string.Format("Invalid Room Id ({0})", mapId), FaroresTest.Without); ft = FaroresTest.With; //Don't break because we can continue parsing for FW purposes } //Check if Link spawn is valid (phase 2) sceneStr.BaseStream.Position = selectSpawnAddr.Offset; var actorId = sceneStr.ReadBigInt16(); int linkActorVarsRomAddr = actorId * 0x20 + 0x14; linkActorVarsRomAddr += actorTableRomAddress; var linkActorVarsRelOff = code_File.Record.GetRelativeAddress(linkActorVarsRomAddr); //pointer to Link's Actor vars can't be resolved if (linkActorVarsRelOff < 0 || !(linkActorVarsRelOff < code_File.Record.VRom.Size)) { WriteResult(result, record, setup.SceneSetup, ResultType.Crash_Likely, UnresolvedAddress("Link Actor Var Pointer", (int)(linkActorVarsRelOff + N0_CodeAddr)), ft); loop = -1; break; } codeStr.BaseStream.Position = linkActorVarsRelOff; int linkActorVarsWriteAddr = codeStr.ReadBigInt32(); int linkActorVarsWriteOff = (linkActorVarsWriteAddr - N0_CodeAddr + 8) & 0xFFFFFF; //pointer to where to update Link's object number can't be resolved if (linkActorVarsWriteOff < 0 || !(linkActorVarsWriteOff < code_File.Record.VRom.Size)) { WriteResult(result, record, setup.SceneSetup, ResultType.Crash_Likely, UnresolvedAddress("Link Object Dependency Write", linkActorVarsWriteAddr + 8), ft); loop = -1; break; } //check if pointer is going to do an unaligned write if (linkActorVarsWriteAddr % 2 == 1) { WriteResult(result, record, setup.SceneSetup, ResultType.Crash, string.Format("N64: Unaligned SH write to address {0:X8}", linkActorVarsWriteAddr + 8), ft); } sceneStr.BaseStream.Position = seekBack; break; } case 0x17: { sceneStr.BaseStream.Position += 4; sceneHeader.Cutscene = sceneStr.ReadBigInt32(); break; } default: sceneStr.BaseStream.Position += 8; break; } if (loop == 0) { WriteResult(result, record, setup.SceneSetup, ResultType.Error, "Header Parse Error"); } } } } face.OutputText(result.ToString()); return(result); }
internal static void ChangeVersion(RomVersion version, bool setGctx = true) { RomFileToken fileToken; //dma data fileToken = RomFileToken.Select(version, ORom.FileList.dmadata, MRom.FileList.dmadata); Addresser.TryGetRam(fileToken, version, out N64Ptr dmadataStart); Dmadata_Addr = SPtr.New(dmadataStart); //code fileToken = RomFileToken.Select(version, ORom.FileList.code, MRom.FileList.code); Addresser.TryGetRam(fileToken, version, out Code_Addr); Addresser.TryGetRom(fileToken, version, Code_Addr.Offset, out Code_VRom); int temp; //Global Context if (setGctx) { Addresser.TryGetRam(AddressToken.RAM_GLOBAL_CONTEXT, version, out temp); if (version == ORom.Build.IQUEC || version == ORom.Build.IQUET) { GlobalContext = SPtr.New(temp); } else { GlobalContext = SPtr.New(temp).Deref(); } } SetGfxContext(version); //Heap Addresser.TryGetRam(AddressToken.RAM_ARENA_MAIN, version, out temp); Main_Heap_Ptr = SPtr.New(temp).Deref(); Addresser.TryGetRam(AddressToken.RAM_ARENA_SCENES, version, out temp); Scene_Heap_Ptr = SPtr.New(temp).Deref(); Addresser.TryGetRam(AddressToken.RAM_ARENA_DEBUG, version, out temp); if (temp == 0) { Debug_Heap_Ptr = SPtr.New(0); } else { Debug_Heap_Ptr = SPtr.New(temp).Deref(); } Addresser.TryGetOffset(AddressToken.ACTOR_CAT_LL_Start, version, out temp); Actor_Category_Table = GlobalContext.RelOff(temp); //Overlay Tables Addresser.TryGetRam(AddressToken.ActorTable_Start, ORom.FileList.code, version, out Actor_Ovl_Table); Addresser.TryGetRam(AddressToken.PlayerPauseOverlayTable_Start, ORom.FileList.code, version, out Player_Pause_Ovl_Table); Addresser.TryGetRam(AddressToken.ParticleTable_Start, ORom.FileList.code, version, out ParticleEffect_Ovl_Table); Addresser.TryGetRam(AddressToken.ObjectTable_Start, ORom.FileList.code, version, out Object_File_Table); Addresser.TryGetOffset(AddressToken.OBJ_ALLOC_TABLE, version, out temp); Object_Allocation_Table = GlobalContext.RelOff(temp); Addresser.TryGetOffset(AddressToken.ROOM_ALLOC_ADDR, version, out temp); Room_Allocation_Table = GlobalContext.RelOff(temp); Addresser.TryGetRam(AddressToken.SRAM_START, version, out temp); SaveContext = SPtr.New(temp); Addresser.TryGetRam(AddressToken.RAM_SEGMENT_TABLE, version, out temp); Segment_Table = temp; if (Addresser.TryGetRam(AddressToken.SceneTable_Start, version, out temp)) { SceneTable = SPtr.New(temp); } else { SceneTable = null; } if (Addresser.TryGetRam(AddressToken.EntranceIndexTable_Start, version, out temp)) { EntranceTable = SPtr.New(temp); } else { EntranceTable = null; } Addresser.TryGetRam(AddressToken.QUEUE_THREAD, version, out temp); Queue_Thread_Ptr = SPtr.New(temp); Addresser.TryGetRam(AddressToken.STACK_LIST, version, out temp); Stack_List_Ptr = SPtr.New(temp); }
internal static void ChangeVersion(RomVersion version, bool setGctx = true) { RomFileToken fileToken; //dma data fileToken = (version == Game.OcarinaOfTime) ? (RomFileToken)ORom.FileList.dmadata : (RomFileToken)MRom.FileList.dmadata; Addresser.TryGetRam(fileToken, version, out int temp); Dmadata_Addr = SPtr.New(temp); //code fileToken = (version == Game.OcarinaOfTime) ? (RomFileToken)ORom.FileList.code : (RomFileToken)MRom.FileList.code; Addresser.TryGetRam(fileToken, version, out Code_Addr); Addresser.TryGetRom(fileToken, version, (uint)Code_Addr, out Code_VRom); //Global Context if (setGctx) { Addresser.TryGetRam("RAM_GLOBAL_CONTEXT", version, out temp); if (version == ORom.Build.IQUEC || version == ORom.Build.IQUET) { GlobalContext = SPtr.New(temp); } else { GlobalContext = SPtr.New(temp).Deref(); } } SetGfxContext(version); //Heap Addresser.TryGetRam("RAM_ARENA_MAIN", version, out temp); Main_Heap_Ptr = SPtr.New(temp).Deref(); Addresser.TryGetRam("RAM_ARENA_SCENES", version, out temp); Scene_Heap_Ptr = SPtr.New(temp).Deref(); Addresser.TryGetRam("RAM_ARENA_DEBUG", version, out temp); if (temp == 0) { Debug_Heap_Ptr = SPtr.New(0); } else { Debug_Heap_Ptr = SPtr.New(temp).Deref(); } Addresser.TryGetOffset("ACTOR_CAT_LL_Start", version, out temp); Actor_Category_Table = GlobalContext.RelOff(temp); //Overlay Tables Addresser.TryGetRam("ActorTable_Start", ORom.FileList.code, version, out Actor_Ovl_Table); Addresser.TryGetRam("PlayerPauseOverlayTable_Start", ORom.FileList.code, version, out Player_Pause_Ovl_Table); Addresser.TryGetRam("ParticleTable_Start", ORom.FileList.code, version, out ParticleEffect_Ovl_Table); Addresser.TryGetRam("ObjectTable_Start", ORom.FileList.code, version, out Object_File_Table); Addresser.TryGetOffset("OBJ_ALLOC_TABLE", version, out temp); Object_Allocation_Table = GlobalContext.RelOff(temp); Addresser.TryGetOffset("ROOM_ALLOC_ADDR", version, out temp); Room_Allocation_Table = GlobalContext.RelOff(temp); Addresser.TryGetRam("SRAM_START", version, out temp); SaveContext = SPtr.New(temp); Addresser.TryGetRam("RAM_SEGMENT_TABLE", version, out temp); Segment_Table = temp; if (Addresser.TryGetRam("SceneTable_Start", version, out temp)) { SceneTable = SPtr.New(temp); } else { SceneTable = null; } if (Addresser.TryGetRam("EntranceIndexTable_Start", version, out temp)) { EntranceTable = SPtr.New(temp); } else { EntranceTable = null; } Addresser.TryGetRam("QUEUE_THREAD", version, out temp); Queue_Thread_Ptr = SPtr.New(temp); Addresser.TryGetRam("STACK_LIST", version, out temp); Stack_List_Ptr = SPtr.New(temp); }