Skip to content

Conversation

@jonathanpeppers
Copy link
Owner

One of the biggest problems with the existing code, is it writes directly to the System.IO.Stream.

This means we have hacks like this method:

void SeekBack(int length)
{
LastLDA = false;
_logger.WriteLine($"Seek back {length} bytes");
if (_writer.BaseStream.Length < length)
{
_writer.BaseStream.SetLength(0);
}
else
{
_writer.BaseStream.SetLength(_writer.BaseStream.Length - length);
}
}

We should create an in-memory representation of the 6502 program, so the code can iterate on the program in memory before writing.

I plan to complete this refactoring, before new features.

Updated NmiSetCallback to use correct zero page addresses and refactored NESWriter to use BuiltInSubroutines for NMI callback and pad poll logic. Added comprehensive test for PadPoll to verify generated bytes.
Updated several built-in subroutines (WaitSync3, Nmi, Popa, Popax, Pusha, Pushax, Incsp2, Initlib, Donelib) to more closely match NESWriter byte patterns and logic, including changes to branching, stack handling, and initialization. Adjusted corresponding unit tests to verify the new byte output for each subroutine.
Introduces CodeBaseOffset to NESWriter to correctly calculate code addresses after writing the NES header. Updates Transpiler to set this offset after writing the header, ensuring label and branch calculations are accurate. Refactors WriteBlock to use the new offset, and updates tests to reflect correct label addressing.
Replaces direct address calculations using _writer.BaseStream.Position and BaseAddress with a new CurrentAddress property. This centralizes and clarifies ROM address computation, improving maintainability and reducing code duplication.
Replaced individual Write_* methods with direct calls to WriteBlock and BuiltInSubroutines in WriteBuiltIns and WriteFinalBuiltIns. This reduces code duplication and simplifies the class by removing many private helper methods.
This reverts commit bcf5321.
Replaces individual Write_* methods with direct calls to WriteBlock using BuiltInSubroutines, reducing code duplication and improving maintainability. Labels are now set inline where needed, and redundant private methods have been removed.
Introduces a LabelOffset property to the Block class to allow labels to point to an offset within a block, supporting cases with prefix instructions. Updates Pusha and Pushax built-in subroutines to use label offsets, refactors NESWriter to set labels using the new offset, and standardizes the pad_poll label. Adjusts related tests to match the new label naming.
Removes the WriteBuiltIn method and replaces all calls with direct WriteBlock invocations using BuiltInSubroutines methods. Updates all built-in subroutine labels to remove leading underscores for consistency. Adjusts tests to match new label names and usage. This simplifies the codebase and improves maintainability by reducing indirection.
The WriteBuiltIns method in NESWriter and its usages in Transpiler and test classes were updated to remove the unused sizeOfMain parameter, simplifying the method signature and related calls.
Replaces usage of nameof() for label dictionary keys with string literals in IL2NESWriter and NESWriter for consistency and clarity. Moves post-main function address constants from NESWriter to NESConstants, adding 'rodata' to NESConstants. This improves maintainability and centralizes constant definitions.
Reordered and clarified the initialization of label entries in the NESWriter constructor. Added comments to explain forward references and fixed address labels, improving code readability and maintainability.
Replaces direct stream emission and SeekBack patterns in IL2NESWriter with a block buffering approach, introducing StartBlockBuffering, FlushMainBlock, RemoveLastInstructions, and Emit methods. Updates Transpiler to enable and flush block buffering in the second pass. This change improves instruction emission flexibility and prepares for further object model enhancements.
Eliminated NESInstruction.cs and NESInstructionConverter.cs, fully migrating to Opcode and AddressMode enums throughout the codebase. Updated Program6502Writer, NESWriter, IL2NESWriter, and all related tests to use the new instruction API, removing all references to the legacy NESInstruction enum. This simplifies the instruction handling and unifies the codebase under the new object model.
Refactored IL2NESWriter to always use block buffering mode, removing legacy stream-based code paths and related methods. Updated Transpiler, IL2NESWriterTests, and RoslynTests to enable block buffering and flush the main block as needed. This simplifies instruction emission and ensures consistent code generation.
Revised README and object model spec to clarify the transition from direct stream writes to a buffered object model for 6502 code generation. Updated examples and explanations to show resolved architectural issues, new code patterns, and the removal of legacy approaches like SeekBack and NESInstruction. Added details on the benefits and implementation phases of the new architecture.
Moved block buffering methods and state from IL2NESWriter to NESWriter for better code reuse and maintainability. IL2NESWriter now uses the shared buffering logic from the base class. Updated GetAddress to use label lookups and improved handling of optional and unimplemented methods.
Introduces methods to Program6502 for adding and managing standard NES built-in subroutines, including label resolution and program size calculation. Adds integration tests to verify built-in subroutine handling, label definitions, forward references, and program validity.
Introduces support for data-only blocks in the Program6502 object model, allowing raw byte data (e.g., lookup tables) to be represented as blocks. Updates NESWriter and related utilities to handle data blocks consistently, refactors label/address resolution, and adds tests to verify byte and label equivalence between the new object model and legacy NESWriter output.
Introduces Transpiler.BuildProgram6502 to construct a full Program6502 object model for analysis and debugging. Adds Program6502.AddMainProgram and AddProgramData for block and data management. IL2NESWriter exposes ByteArrays and provides GetMainBlock and CurrentBlock for block access. NESWriter.WriteFinalBuiltIns now uses Program6502 for built-in block centralization. Includes new TranspilerTests for BuildProgram6502 validation.
Introduces a single-pass transpilation mode in Transpiler that emits label references instead of resolved addresses, allowing address resolution in a final pass. Updates Block to support pending labels, adds EmitWithLabel to NESWriter, and refactors IL2NESWriter to emit JSR/JMP using label references when enabled. Includes new tests for single-pass transpilation and ensures output matches the two-pass method.
Eliminated the two-pass BuildProgram6502 method and its usage, consolidating to a single-pass transpilation approach. Removed the WriteFromProgram6502 method from NESWriter and updated TranspilerTests to only use the single-pass method.
Deleted the Program6502Writer adapter class and its associated unit tests. This likely reflects a migration away from the adapter layer to direct use of the Program6502 object model for 6502 code generation.
Updated BuiltInSubroutines to use nameof() and string constants for block and label names, improving maintainability and reducing string duplication. Added label name constants to NESConstants for use in code generation.
Deleted unused Write method overloads from NESWriter and removed related unit tests, including WriteLDA, WriteJSR, and Write_Main. This streamlines the codebase and eliminates redundant test coverage for removed functionality.
Refactored code to use method names directly as label references instead of mapping through GetLabelName. This simplifies label handling and reduces unnecessary indirection when emitting JSR instructions and looking up addresses.
Reordered the addition of final built-ins, byte array data, and string tables in Transpiler to match the legacy output order. Adjusted label definition in Program6502 to account for label offsets. Added a test to compare the new program output with the legacy transpiler for byte-level differences.
Introduces Immediate_LowByte and Immediate_HighByte address modes and corresponding LowByteOperand and HighByteOperand types to support label-based immediate operands for single-pass transpilation. Updates IL2NESWriter, NESWriter, and OpcodeTable to handle these new operand types and modes. Refactors Transpiler to use a single-pass approach, removing the previous two-pass logic, and updates tests to support the new label-based addressing.
Refactored IL2NESWriter to always use label references for JSR/JMP and byte arrays, eliminating the UseLabelReferences flag and related legacy address resolution code. Updated Transpiler and tests to match the new approach, simplifying code generation and improving maintainability.
Refactored BuiltInSubroutines to use named constants from NESConstants instead of hardcoded zero page addresses. Added TEMP2, TEMP3, and NMI_CALLBACK constants to NESConstants for improved code clarity and maintainability.
Refactored IL2NESWriter and related code to eliminate the unused sizeOfMain parameter from Write and helper methods. Updated all call sites in Transpiler and IL2NESWriterTests to match the new method signatures, simplifying the API and improving code clarity.
Deleted the RecordLabel and WriteByteArrays methods from IL2NESWriter, and the Write method from NESWriter, as they are no longer used. Updated documentation in copilot-instructions.md to reference BuiltInSubroutines.cs instead of IL2NESWriter.WriteBuiltIns().
Removed PRG_ROM, CHR_ROM, and related fields from NESWriter and updated tests to no longer set these properties. This simplifies the NESWriter class and its usage, as these fields were not required for current functionality.
@jonathanpeppers jonathanpeppers marked this pull request as ready for review January 31, 2026 13:00
@jonathanpeppers jonathanpeppers merged commit 9e6e7b2 into main Jan 31, 2026
1 check passed
@jonathanpeppers jonathanpeppers deleted the object-model branch January 31, 2026 13:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants