public static void ApplyExpansionPatch(byte[] targetRom) { // Apply expansion code prior to expansion // (for ease... atm expansion code targets the fixed bank at $F instead of $1F) // manually include defines string asm = Projects.ProjectResources.DefaultDefinesFile + Environment.NewLine + Mmc3Resources.ExpansionASM; asm = NopOutScreenLoad(asm); snarfblasm.Assembler assm = new snarfblasm.Assembler("mmc3Expander", asm, null); var output = assm.Assemble(); var errors = assm.GetErrors(); if (errors != null && errors.Count > 0) { // todo: more specific exception string error = "Assembler error: " + errors[0].File + " line " + errors[0].LineNumber + ": " + errors[0].Message; if (errors.Count > 1) { error += " (additional errors: " + (errors.Count - 1).ToString() + ")"; } throw new Exception(error); } var patches = assm.GetPatchSegments(); for (int i = 0; i < patches.Count; i++) { var patch = patches[i]; int patchLength = patch.Length; if (patchLength < 0) { patchLength = output.Length - patch.Start; } Array.Copy(output, patch.Start, targetRom, patch.PatchOffset, patchLength); } }
private void Assemble() { ClearScreenExtraBytes(); // Assemble (first pass (1)) to calculate size of each screen's code { string buildFile = ConstructBuildFile(1); var buildFileAsBin = System.Text.Encoding.UTF8.GetBytes(buildFile); snarfblasm.Assembler assembler = new snarfblasm.Assembler("Main File", new MemoryStream(buildFileAsBin), new FileProvider(this)); assembler.AllowInvalidOpcodes = false; assembler.OverflowChecking = snarfblasm.OverflowChecking.None; assembler.RequireColonOnLabels = true; assembler.RequireDotOnDirectives = true; var assembledBytes = assembler.Assemble(); ProcessAssembleErrors(assembler.GetErrors(), 1); if (FatalError) { return; } // Added first-pass-code to screens var patchSegments = assembler.GetPatchSegments(); ApplyPatches(assembledBytes, patchSegments, false); if (FatalError) { return; } // Serializing data causes ROM data layout to be updated, which is then used to set the base address for each screen's code CheckForOverrun(); if (FatalError) { return; } outputRom.SerializeAllData(); ApplyScreenCodeBases(); } // Assemble (second pass) with correct base addresses { string buildFile = ConstructBuildFile(0); // Reconstruct with correct base addresses byte[] buildFileAsBin = System.Text.Encoding.UTF8.GetBytes(buildFile); var assembler = new snarfblasm.Assembler("Main File", new MemoryStream(buildFileAsBin), new FileProvider(this)); assembler.Labels = new snarfblasm.AddressLabels(); assembler.AllowInvalidOpcodes = false; assembler.OverflowChecking = snarfblasm.OverflowChecking.Unsigned; assembler.RequireColonOnLabels = true; assembler.RequireDotOnDirectives = true; var assembledBytes = assembler.Assemble(); ProcessAssembleErrors(assembler.GetErrors(), 0); if (FatalError) { return; } if (project.GenerateDebugFiles && !string.IsNullOrEmpty(project.DebugOutputDirectory.Trim())) { BuildDebugFiles(assembler.Labels); } // Re-apply updated patch var patchSegments = assembler.GetPatchSegments(); ApplyPatches(assembledBytes, patchSegments, true); if (FatalError) { return; } // This causes updated asm bytes to be written to ROM outputRom.SerializeAllData(); CheckForOverrun(); if (FatalError) { return; } } }