diff options
| -rw-r--r-- | Cargo.lock | 1 | ||||
| -rw-r--r-- | crates/nasm/Cargo.toml | 1 | ||||
| -rw-r--r-- | crates/nasm/src/main.rs | 31 | ||||
| -rw-r--r-- | lib/xixanta/src/assembler.rs | 26 |
4 files changed, 58 insertions, 1 deletions
@@ -10,6 +10,7 @@ version = "0.1.0" name = "nasm" version = "0.1.0" dependencies = [ + "header", "xixanta", ] diff --git a/crates/nasm/Cargo.toml b/crates/nasm/Cargo.toml index f0f11db..f1294f7 100644 --- a/crates/nasm/Cargo.toml +++ b/crates/nasm/Cargo.toml @@ -6,3 +6,4 @@ authors = ["Miquel Sabaté Solà <mikisabate@gmail.com>"] [dependencies] xixanta.workspace = true +header.workspace = true diff --git a/crates/nasm/src/main.rs b/crates/nasm/src/main.rs index 3864587..6ca6d27 100644 --- a/crates/nasm/src/main.rs +++ b/crates/nasm/src/main.rs @@ -1,3 +1,4 @@ +use header::Header; use std::fs::File; use std::io::{self, Write}; use std::path::Path; @@ -205,8 +206,36 @@ fn main() { error_count += 1; } - // If everything was right, just deliver the bundles. + // Deliver the bundles unless the header is borked. if error_count == 0 { + // Fetch the header first. + let mut temptative_header = vec![]; + for b in &res.bundles { + for i in 0..b.size { + temptative_header.push(b.bytes[i as usize]); + } + if temptative_header.len() >= 0x10 { + break; + } + } + + // Validate the resulting header. + match Header::try_from(temptative_header.as_slice()) { + Ok(header) => { + if res.accessing_working_ram && !header.has_persistent_memory { + die( + "requires Working RAM but the ROM header does not advertise it".to_string(), + ); + } + } + Err(e) => { + die(format!( + "output would produce a malformed NES/Famicom ROM: {e}" + )); + } + }; + + // And now deliver the bundles. for b in res.bundles { for i in 0..b.size { if let Err(e) = output.write_all(&[b.bytes[i as usize]]) { diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs index 23d4219..5ab0e3d 100644 --- a/lib/xixanta/src/assembler.rs +++ b/lib/xixanta/src/assembler.rs @@ -83,6 +83,10 @@ struct Assembler<'a> { // Sources that have been evaluated for the current session. This is // directly tied to `Parser::sources`. sources: Vec<SourceInfo>, + + // Whether the assembler has detected accesses to Working RAM or not + // (0x6000-0x7FFF). + accessing_working_ram: bool, } /// All the information that a caller needs after calling either @@ -104,6 +108,10 @@ pub struct AssemblerResult { /// The resulting mappings after assembling a source. You can count on /// fields like `offset` if `errors` is empty. pub mappings: Vec<Mapping>, + + /// Whether the resulting ROM needs Working RAM to be available in order to + /// work. Ignore this field if `errors` is not empty. + pub accessing_working_ram: bool, } /// Read the contents from the `reader` as a source file and produce a list of @@ -131,6 +139,7 @@ pub fn assemble( }], warnings: vec![], mappings: vec![], + accessing_working_ram: false, }; } }; @@ -161,6 +170,7 @@ pub fn assemble_with_mapping( errors, warnings: asm.warnings, mappings: asm.mappings, + accessing_working_ram: asm.accessing_working_ram, }; } @@ -176,6 +186,7 @@ pub fn assemble_with_mapping( errors: e.into(), warnings: vec![], mappings: asm.mappings, + accessing_working_ram: asm.accessing_working_ram, }; } } @@ -188,6 +199,7 @@ pub fn assemble_with_mapping( errors, warnings: asm.warnings, mappings: asm.mappings, + accessing_working_ram: asm.accessing_working_ram, }; } @@ -201,6 +213,7 @@ pub fn assemble_with_mapping( errors, warnings: asm.warnings, mappings: asm.mappings, + accessing_working_ram: asm.accessing_working_ram, }; } @@ -212,6 +225,7 @@ pub fn assemble_with_mapping( errors, warnings: asm.warnings, mappings: asm.mappings, + accessing_working_ram: asm.accessing_working_ram, }; } @@ -222,12 +236,14 @@ pub fn assemble_with_mapping( errors: vec![], warnings: asm.warnings, mappings: asm.mappings, + accessing_working_ram: asm.accessing_working_ram, }, Err(errors) => AssemblerResult { bundles: vec![], errors, warnings: asm.warnings, mappings: asm.mappings, + accessing_working_ram: asm.accessing_working_ram, }, } } @@ -249,6 +265,7 @@ impl<'a> Assembler<'a> { repeats_seen: 0, warnings: vec![], sources: vec![], + accessing_working_ram: false, } } @@ -2003,6 +2020,15 @@ impl<'a> Assembler<'a> { None => (AddressingMode::Implied, Bundle::new(true)), }; + // If the instruction is accessing memory and the bundle is resolved, we + // can start gathering info on the memory being used. + if bundle.resolved && !matches!(mode, AddressingMode::Implied | AddressingMode::Immediate) { + let value = bundle.value() as usize; + if (0x6000..0x8000).contains(&value) { + self.accessing_working_ram = true; + } + } + let mnemonic = node.value.value.to_lowercase(); match INSTRUCTIONS.get(&mnemonic) { Some(entries) => match entries.get(&mode) { |
