mirror of
https://github.com/ApfelTeeSaft/NESDecompiler.git
synced 2026-08-26 19:33:30 +00:00
Merge pull request #4 from KallDrexx/nmi_decompiling
Add decompililng of other entrypoints, and add specific support for NMI and IRQ vectors
This commit is contained in:
@@ -165,7 +165,7 @@ namespace NESDecompiler.CLI
|
||||
writer.WriteLine(" */");
|
||||
writer.WriteLine();
|
||||
|
||||
string guardName = Path.GetFileNameWithoutExtension(decompiler.ROMInfo.RawData[0].ToString()).ToUpper() + "_H";
|
||||
string guardName = Path.GetFileNameWithoutExtension(decompiler.ROMInfo.RawData![0].ToString()).ToUpper() + "_H";
|
||||
writer.WriteLine($"#ifndef {guardName}");
|
||||
writer.WriteLine($"#define {guardName}");
|
||||
writer.WriteLine();
|
||||
|
||||
@@ -1026,7 +1026,7 @@ namespace NESDecompiler.Core.Decompilation
|
||||
{
|
||||
// Process LDA, LDX, LDY
|
||||
string register = instruction.Info.Mnemonic.Substring(2);
|
||||
string variableName = GetVariableName(instruction);
|
||||
string? variableName = GetVariableName(instruction);
|
||||
|
||||
if (variableName != null)
|
||||
{
|
||||
@@ -1046,7 +1046,7 @@ namespace NESDecompiler.Core.Decompilation
|
||||
{
|
||||
// Process STA, STX, STY
|
||||
string register = instruction.Info.Mnemonic.Substring(2);
|
||||
string variableName = GetVariableName(instruction);
|
||||
string? variableName = GetVariableName(instruction);
|
||||
|
||||
if (variableName != null)
|
||||
{
|
||||
@@ -1314,7 +1314,7 @@ namespace NESDecompiler.Core.Decompilation
|
||||
private void GenerateArithmeticCode(DisassembledInstruction instruction, StringBuilder sb)
|
||||
{
|
||||
// Handle arithmetic operations: ADC, SBC
|
||||
string operand = GetOperandString(instruction);
|
||||
string? operand = GetOperandString(instruction);
|
||||
if (operand == null)
|
||||
return;
|
||||
|
||||
@@ -1359,7 +1359,7 @@ namespace NESDecompiler.Core.Decompilation
|
||||
private void GenerateIncrementCode(DisassembledInstruction instruction, StringBuilder sb)
|
||||
{
|
||||
// Handle increment operations: INC, INX, INY
|
||||
string operand = GetOperandString(instruction);
|
||||
string? operand = GetOperandString(instruction);
|
||||
|
||||
switch (instruction.Info.Mnemonic)
|
||||
{
|
||||
@@ -1393,7 +1393,7 @@ namespace NESDecompiler.Core.Decompilation
|
||||
private void GenerateDecrementCode(DisassembledInstruction instruction, StringBuilder sb)
|
||||
{
|
||||
// Handle decrement operations: DEC, DEX, DEY
|
||||
string operand = GetOperandString(instruction);
|
||||
string? operand = GetOperandString(instruction);
|
||||
|
||||
switch (instruction.Info.Mnemonic)
|
||||
{
|
||||
@@ -1427,7 +1427,7 @@ namespace NESDecompiler.Core.Decompilation
|
||||
private void GenerateShiftCode(DisassembledInstruction instruction, StringBuilder sb)
|
||||
{
|
||||
// Handle shift operations: ASL, LSR, ROL, ROR
|
||||
string operand;
|
||||
string? operand;
|
||||
|
||||
if (instruction.Info.AddressingMode == AddressingMode.Accumulator)
|
||||
{
|
||||
@@ -1489,7 +1489,7 @@ namespace NESDecompiler.Core.Decompilation
|
||||
private void GenerateLogicCode(DisassembledInstruction instruction, StringBuilder sb)
|
||||
{
|
||||
// Handle logic operations: AND, ORA, EOR, BIT
|
||||
string operand = GetOperandString(instruction);
|
||||
string? operand = GetOperandString(instruction);
|
||||
if (operand == null)
|
||||
return;
|
||||
|
||||
@@ -1533,7 +1533,7 @@ namespace NESDecompiler.Core.Decompilation
|
||||
private void GenerateCompareCode(DisassembledInstruction instruction, StringBuilder sb)
|
||||
{
|
||||
// Handle compare operations: CMP, CPX, CPY
|
||||
string operand = GetOperandString(instruction);
|
||||
string? operand = GetOperandString(instruction);
|
||||
if (operand == null)
|
||||
return;
|
||||
|
||||
@@ -1710,7 +1710,7 @@ namespace NESDecompiler.Core.Decompilation
|
||||
}
|
||||
}
|
||||
|
||||
private string GetOperandString(DisassembledInstruction instruction)
|
||||
private string? GetOperandString(DisassembledInstruction instruction)
|
||||
{
|
||||
if (instruction.Info.AddressingMode == AddressingMode.Immediate)
|
||||
{
|
||||
|
||||
@@ -25,17 +25,17 @@ namespace NESDecompiler.Core.Disassembly
|
||||
/// <summary>
|
||||
/// Information about this instruction's opcode
|
||||
/// </summary>
|
||||
public InstructionInfo Info { get; set; }
|
||||
public required InstructionInfo Info { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw bytes of this instruction (including operands)
|
||||
/// </summary>
|
||||
public byte[] Bytes { get; set; }
|
||||
public byte[]? Bytes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The operand bytes of this instruction
|
||||
/// </summary>
|
||||
public byte[] Operands => Bytes.Length > 1 ? Bytes[1..] : Array.Empty<byte>();
|
||||
public byte[] Operands => Bytes!.Length > 1 ? Bytes[1..] : Array.Empty<byte>();
|
||||
|
||||
/// <summary>
|
||||
/// The target address for branch and jump instructions
|
||||
@@ -85,7 +85,7 @@ namespace NESDecompiler.Core.Disassembly
|
||||
}
|
||||
|
||||
sb.Append($"{CPUAddress:X4} ");
|
||||
foreach (var b in Bytes)
|
||||
foreach (var b in Bytes!)
|
||||
{
|
||||
sb.Append($"{b:X2} ");
|
||||
}
|
||||
@@ -185,6 +185,19 @@ namespace NESDecompiler.Core.Disassembly
|
||||
{
|
||||
entryPoints.Add(romInfo.ResetVector);
|
||||
}
|
||||
|
||||
foreach (var entryPoint in romInfo.EntryPoints)
|
||||
{
|
||||
entryPoints.Add(entryPoint);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddEntyPoint(ushort address)
|
||||
{
|
||||
if (address >= 0x8000)
|
||||
{
|
||||
entryPoints.Add(address);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -398,7 +411,7 @@ namespace NESDecompiler.Core.Disassembly
|
||||
if (instruction.TargetAddress.HasValue)
|
||||
{
|
||||
ushort target = instruction.TargetAddress.Value;
|
||||
if (labels.TryGetValue(target, out string label))
|
||||
if (labels.TryGetValue(target, out string? label))
|
||||
{
|
||||
instruction.Comment = $"-> {label}";
|
||||
}
|
||||
|
||||
@@ -73,10 +73,20 @@ namespace NESDecompiler.Core.ROM
|
||||
/// </summary>
|
||||
public ushort ResetVector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The NMI handler address
|
||||
/// </summary>
|
||||
public ushort NmiVector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The IRQ handler address
|
||||
/// </summary>
|
||||
public ushort IrqVector { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The raw ROM data for reference
|
||||
/// </summary>
|
||||
public byte[] RawData { get; set; }
|
||||
public byte[]? RawData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// List of identified entry points (including reset vector and NMI)
|
||||
|
||||
@@ -21,13 +21,13 @@ namespace NESDecompiler.Core.ROM
|
||||
private const int FLAGS_10_OFFSET = 10;
|
||||
|
||||
// ROM data
|
||||
private byte[] romData;
|
||||
private ROMInfo romInfo;
|
||||
private byte[]? romData;
|
||||
private ROMInfo? romInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Information about the loaded ROM
|
||||
/// </summary>
|
||||
public ROMInfo ROMInfo => romInfo;
|
||||
public ROMInfo? ROMInfo => romInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Loads a NES ROM file from disk
|
||||
@@ -75,7 +75,7 @@ namespace NESDecompiler.Core.ROM
|
||||
private ROMInfo ParseROMHeader()
|
||||
{
|
||||
// Verify iNES header signature "NES" followed by MS-DOS EOF
|
||||
if (romData.Length < HEADER_SIZE ||
|
||||
if (romData!.Length < HEADER_SIZE ||
|
||||
romData[0] != 0x4E || romData[1] != 0x45 || romData[2] != 0x53 || romData[3] != 0x1A)
|
||||
{
|
||||
throw new InvalidROMFormatException("Invalid iNES ROM header");
|
||||
@@ -107,15 +107,38 @@ namespace NESDecompiler.Core.ROM
|
||||
|
||||
romInfo.CHRROMOffset = romInfo.PRGROMOffset + romInfo.PRGROMSize;
|
||||
|
||||
// Identify entry points (reset vector)
|
||||
var end = romInfo.PRGROMOffset + romInfo.PRGROMSize;
|
||||
var nmiOffset = end - 6;
|
||||
var resetOffset = end - 4;
|
||||
var irqOffset = end - 2;
|
||||
|
||||
ushort GetVectorAddress(int offset)
|
||||
{
|
||||
if (offset >= 0 && offset < romData.Length - 1)
|
||||
{
|
||||
return (ushort)(romData[offset] | (romData[offset + 1] << 8));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Identify entry points (reset vector), NMI handler, and irq handler
|
||||
if (romInfo.PRGROMSize > 0)
|
||||
{
|
||||
// In 6502, reset vector is at 0xFFFC-0xFFFD
|
||||
// For NES, this is mapped to the end of the first PRG ROM bank
|
||||
int resetVectorOffset = romInfo.PRGROMOffset + romInfo.PRGROMSize - 4;
|
||||
if (resetVectorOffset >= 0 && resetVectorOffset < romData.Length - 1)
|
||||
romInfo.ResetVector = GetVectorAddress(resetOffset);
|
||||
romInfo.NmiVector = GetVectorAddress(nmiOffset);
|
||||
romInfo.IrqVector = GetVectorAddress(irqOffset);
|
||||
|
||||
if (romInfo.NmiVector > 0)
|
||||
{
|
||||
romInfo.ResetVector = (ushort)(romData[resetVectorOffset] | (romData[resetVectorOffset + 1] << 8));
|
||||
romInfo.EntryPoints.Add(romInfo.NmiVector);
|
||||
}
|
||||
|
||||
if (romInfo.IrqVector > 0)
|
||||
{
|
||||
romInfo.EntryPoints.Add(romInfo.IrqVector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user