From dedf0fdc5b206e7e5b191c2966eb0325d9ae5cb7 Mon Sep 17 00:00:00 2001 From: Dominic Cerquetti Date: Sat, 30 Nov 2024 14:55:14 -0500 Subject: [PATCH] WIP: non-working: add support for labels with specific databanks - supposed to make it easier when games do weird stuff with databanks but reference the same WRAM address, but.... it's not quite working in all cases - probably best to just abandon this --- .../src/controllers/ProjectController.cs | 59 +++++++++++++++++++ .../src/interfaces/IControllers.cs | 1 + Diz.Core.Interfaces/ModelInterfaces.cs | 2 +- Diz.Cpu.65816/src/CPU65C816.cs | 17 ++++-- Diz.Cpu.65816/src/Cpu.cs | 2 +- Diz.Cpu.65816/src/SnesData.cs | 4 +- Diz.LogWriter | 2 +- DiztinGUIsh/window/MainWindow.Actions.cs | 14 +++++ DiztinGUIsh/window/MainWindow.MainTable.cs | 4 ++ 9 files changed, 96 insertions(+), 9 deletions(-) diff --git a/Diz.Controllers/Diz.Controllers/src/controllers/ProjectController.cs b/Diz.Controllers/Diz.Controllers/src/controllers/ProjectController.cs index 5a65dd5a..2165870e 100644 --- a/Diz.Controllers/Diz.Controllers/src/controllers/ProjectController.cs +++ b/Diz.Controllers/Diz.Controllers/src/controllers/ProjectController.cs @@ -9,6 +9,7 @@ using Diz.Core; using Diz.Core.export; using Diz.Core.model; +using Diz.Core.model.snes; using Diz.Core.serialization; using Diz.Core.serialization.xml_serializer; using Diz.Core.util; @@ -19,6 +20,7 @@ using Diz.Import.bsnes.usagemap; using Diz.LogWriter; using Diz.LogWriter.util; +using IX.Library.Collections; using JetBrains.Annotations; namespace Diz.Controllers.controllers; @@ -257,6 +259,63 @@ public void MarkChanged() if (Project.Session != null) Project.Session.UnsavedChanges = true; } + public int NormalizedMirroredAddresses() + { + // crappy but useful hack to deal with mirroring. + // sometimes things like tracelog capture will use mirrored addresses (typically using the DB register) + // to access RAM (or ROM) addresses. if we can detect that is happening, we can switch everything back to + // a normlized address and the exported assembly has a better chance of using the labels correctly. + // this is a little experimental but, should be OK. + // + // Diz3 won't need this because we deal with mirroring better. + if (Project == null || Project.Data.RomBytes.Count <= 0) + return 0; + + var modified = 0; + Project.Data.RomBytes + .Where(x => x.TypeFlag == FlagType.Opcode) + .ForEach(opcode => + { + // check #1: is DB register set to non-zero, and, can we set it back to zero but still generate the same IA? + if (!DataBankCanBeNormalizedToZero(opcode)) + return; + + opcode.DataBank = 0; + modified++; + }); + + return modified; + } + + private bool DataBankCanBeNormalizedToZero(RomByteData opcode) + { + // NOTE: there may be other interactions with the DB register we should check for too. + // for now, here's just the one + + if (opcode.DataBank == 0) + return false; // we're already set to bank 0 so, forget it + + // what is the IA normally? + var iaNormal = Project.Data.GetSnesApi()!.GetIntermediateAddress(opcode.Offset, false); + if (iaNormal == -1) + return false; + + // what would be the IA if we acted like the databank was actually set to zero (instead of whatever it is) + const int bankZeroOverride = 0; + var iaIfBankZero = Project.Data.GetSnesApi()!.GetIntermediateAddress(opcode.Offset, false, bankZeroOverride); + if (iaIfBankZero == -1) + return false; + + // see if our 2 IAs are, in fact, mirrors of the same exact address + // for instance, in LoRom, $009234, $809234, $7E9234 are all just mirrors of the same address. + // we'd prefer then to use $9234 because it would be easier to not have to track a bunch of labels for the same address + var unMirroredNormal = RomUtil.UnmirroredOffset(iaNormal, Project.Data.GetRomSize()); + var unMirroredOverride = RomUtil.UnmirroredOffset(iaIfBankZero, Project.Data.GetRomSize()); + + // if the unmirrored addresses are both valid AND the same, then, it doesn't matter if we set the DB to zero, so, indicate it's OK. + return unMirroredNormal != -1 && unMirroredNormal == unMirroredOverride; + } + public void SelectOffset(int offset, ISnesNavigation.HistoryArgs historyArgs = null) => ProjectView.SelectOffset(offset, historyArgs); diff --git a/Diz.Controllers/Diz.Controllers/src/interfaces/IControllers.cs b/Diz.Controllers/Diz.Controllers/src/interfaces/IControllers.cs index 0fdf4734..db3e79eb 100644 --- a/Diz.Controllers/Diz.Controllers/src/interfaces/IControllers.cs +++ b/Diz.Controllers/Diz.Controllers/src/interfaces/IControllers.cs @@ -100,6 +100,7 @@ public enum ProjectChangedType bool ExportAssemblyWithCurrentSettings(); void MarkChanged(); // rename to MarkUnsaved or similar in Diz3.0 + int NormalizedMirroredAddresses(); } public interface IProjectOpenerHandler : ILongRunningTaskHandler diff --git a/Diz.Core.Interfaces/ModelInterfaces.cs b/Diz.Core.Interfaces/ModelInterfaces.cs index 4bcd8ec2..2cf289c6 100644 --- a/Diz.Core.Interfaces/ModelInterfaces.cs +++ b/Diz.Core.Interfaces/ModelInterfaces.cs @@ -227,7 +227,7 @@ public interface ISnesIntermediateAddress int GetIntermediateAddressOrPointer(int offset); // -1 if not found - int GetIntermediateAddress(int offset, bool resolve = false); + int GetIntermediateAddress(int offset, bool resolve = false, int overrideDatabank = -1); bool IsMatchingIntermediateAddress(int intermediateAddress, int addressToMatch); } diff --git a/Diz.Cpu.65816/src/CPU65C816.cs b/Diz.Cpu.65816/src/CPU65C816.cs index 037c5a44..ae6ec1fd 100644 --- a/Diz.Cpu.65816/src/CPU65C816.cs +++ b/Diz.Cpu.65816/src/CPU65C816.cs @@ -135,7 +135,8 @@ public int MarkAsOpcodeAndOperandsStartingAt( // input: ROM offset // return: a SNES address - public override int GetIntermediateAddress(TByteSource data, int offset, bool resolve) + // if override_databank is not -1, then [if the instruction would look at it] then recorded databank is ignored and this one is used instead. + public override int GetIntermediateAddress(TByteSource data, int offset, bool resolve, int overrideDatabank = -1) { int bank; int programCounter; @@ -183,9 +184,17 @@ public override int GetIntermediateAddress(TByteSource data, int offset, bool re case Cpu65C816Constants.AddressMode.AddressYIndex: case Cpu65C816Constants.AddressMode.AddressXIndexIndirect: { - bank = opcode is 0x20 or 0x4C or 0x7C or 0xFC - ? data.ConvertPCtoSnes(offset) >> 16 - : data.GetDataBank(offset); + if (opcode is 0x20 or 0x4C or 0x7C or 0xFC) + { + bank = data.ConvertPCtoSnes(offset) >> 16; + } + else + { + bank = overrideDatabank == -1 + ? data.GetDataBank(offset) // normal + : overrideDatabank; // special case (not normally used) + } + var operand = data.GetRomWord(offset + 1); if (!operand.HasValue) return -1; diff --git a/Diz.Cpu.65816/src/Cpu.cs b/Diz.Cpu.65816/src/Cpu.cs index 72cccf11..d493bc6e 100644 --- a/Diz.Cpu.65816/src/Cpu.cs +++ b/Diz.Cpu.65816/src/Cpu.cs @@ -25,7 +25,7 @@ public class Cpu where TByteSource : IRomByteFlagsGettable, IRomByt public virtual int GetInstructionLength(TByteSource data, int offset) => 1; - public virtual int GetIntermediateAddress(TByteSource data, int offset, bool resolve) => -1; + public virtual int GetIntermediateAddress(TByteSource data, int offset, bool resolve, int overrideDatabank = -1) => -1; public virtual void MarkInOutPoints(TByteSource data, int offset) {} // nop public virtual int CalculateInOutPointsFromOffset( TByteSource data, diff --git a/Diz.Cpu.65816/src/SnesData.cs b/Diz.Cpu.65816/src/SnesData.cs index 341cf36c..5636ae6d 100644 --- a/Diz.Cpu.65816/src/SnesData.cs +++ b/Diz.Cpu.65816/src/SnesData.cs @@ -293,8 +293,8 @@ public void MarkAsOpcodeAndOperandsStartingAt(int offset, int? dataBank = null, } // FIX ME: log and generation of dp opcodes. search references - public int GetIntermediateAddress(int offset, bool resolve = false) => - GetCpu(offset).GetIntermediateAddress(this, offset, resolve); + public int GetIntermediateAddress(int offset, bool resolve = false, int overrideDatabank = -1) => + GetCpu(offset).GetIntermediateAddress(this, offset, resolve, overrideDatabank); public string GetInstruction(int offset) => GetCpu(offset).GetInstruction(this, offset); diff --git a/Diz.LogWriter b/Diz.LogWriter index 8f2fdf79..a24be605 160000 --- a/Diz.LogWriter +++ b/Diz.LogWriter @@ -1 +1 @@ -Subproject commit 8f2fdf79e5cc5b10b85554578238d0ae1cc3acfa +Subproject commit a24be605ecb350e661173680707fbfc0ef2564bc diff --git a/DiztinGUIsh/window/MainWindow.Actions.cs b/DiztinGUIsh/window/MainWindow.Actions.cs index fd85ced0..3b22165a 100644 --- a/DiztinGUIsh/window/MainWindow.Actions.cs +++ b/DiztinGUIsh/window/MainWindow.Actions.cs @@ -9,6 +9,7 @@ using Diz.Core.util; using Diz.Cpu._65816; using Diz.Ui.Winforms.dialogs; +using Diz.Ui.Winforms.util; using DiztinGUIsh.Properties; namespace DiztinGUIsh.window; @@ -290,6 +291,19 @@ private void UiFixMisalignedInstructions() RefreshUi(); ShowInfo($"Modified {countModified} flags!", "Done!"); } + + // Diz3 won't need this. but for us, we want it. + private void UiNormalizedMirroredAddresses() + { + GuiUtil.PromptToConfirmAction("Normalize mirrored databank addresses", + $"WARNING: EXPERIMENTAL: PLEASE SAVE FIRST.\nThis will analyze all recorded databank registers and set to zero if the IA isn't affected. (makes for easier labelling). Please be sure to inspect output data after use for correctness, this is a bit of a guess and could have unforseen side effects.", + () => true); + + var countModified = ProjectController.NormalizedMirroredAddresses(); + + RefreshUi(); + ShowInfo($"Normalized {countModified} instructions!", "Done!"); + } private void UiRescanForInOut() { diff --git a/DiztinGUIsh/window/MainWindow.MainTable.cs b/DiztinGUIsh/window/MainWindow.MainTable.cs index b65bf1a3..35d75cb3 100644 --- a/DiztinGUIsh/window/MainWindow.MainTable.cs +++ b/DiztinGUIsh/window/MainWindow.MainTable.cs @@ -140,6 +140,10 @@ private void table_KeyDown(object sender, KeyEventArgs e) GoToNextUnreachedInPoint(offset); break; + case Keys.F6: + UiNormalizedMirroredAddresses(); + break; + case Keys.Home: case Keys.PageUp: case Keys.Up: case Keys.End: case Keys.PageDown: case Keys.Down: ScrollVertically(offset, e.KeyCode switch