Beispiel #1
0
        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);
        }
Beispiel #4
0
        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);
        }