From c060ab9807e66caa328259a0e19559d7d2727533 Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Wed, 8 Jan 2025 16:09:09 +0100 Subject: Try absolute addressing on bad zeropage addressing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sometimes, out of clarity, the programmer may have written something along the lines of: lda $40, y This is invalid because the `lda` instruction does not allow zeropage y-indexing addressing mode. That being said, it does allow for absolute y-indexing addressing mode. This commit allows this syntax by transforming code like the previous one into: lda $0040, y This cannot always be done, but the assembler should at least try if it's possible and not trouble the programmer. That being said, this is otherwise a bit shady since the programmer might think that it's a 2-byte instruction when it's a 3-byte one. Hence, maybe a future linter can pick up code like this and suggest a more explicit writing. Signed-off-by: Miquel Sabaté Solà --- lib/xixanta/src/assembler.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'lib') diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs index c6615d2..eb4821a 100644 --- a/lib/xixanta/src/assembler.rs +++ b/lib/xixanta/src/assembler.rs @@ -1660,6 +1660,20 @@ impl<'a> Assembler<'a> { // address being referenced, which is never on the zeropage // section, so it wouldn't fit on a single byte anyways. if val.size == 1 || (val.resolved && val.bytes[1] == 0x00) { + // If despite all of the above the parsed instruction + + // zeropage indexing is actually not valid but the absolute + // indexing is, then convert this instruction to absolute + // indexing. + let mnemonic = node.value.value.to_lowercase(); + if let Some(entries) = INSTRUCTIONS.get(&mnemonic) { + if entries.get(&AddressingMode::ZeropageIndexedX).is_none() + && entries.get(&AddressingMode::IndexedX).is_some() + { + val.size = 2; + return Ok((AddressingMode::IndexedX, val)); + } + } + // Re-inforce the optimization when val.size == 2 by forcing // the size to 1. val.size = 1; @@ -1671,6 +1685,17 @@ impl<'a> Assembler<'a> { "y" => { // Same optimization as with the "x" case. if val.size == 1 || (val.resolved && val.bytes[1] == 0x00) { + // Similar to the case on "x" indexing. + let mnemonic = node.value.value.to_lowercase(); + if let Some(entries) = INSTRUCTIONS.get(&mnemonic) { + if entries.get(&AddressingMode::ZeropageIndexedY).is_none() + && entries.get(&AddressingMode::IndexedY).is_some() + { + val.size = 2; + return Ok((AddressingMode::IndexedY, val)); + } + } + val.size = 1; Ok((AddressingMode::ZeropageIndexedY, val)) } else { @@ -2360,6 +2385,9 @@ mod tests { assert_instruction("lda ($20, x)", &[0xA1, 0x20]); assert_instruction("lda ($20), y", &[0xB1, 0x20]); + // Expand zeropage-looking into absolute index. + assert_instruction("lda $42, y", &[0xB9, 0x42, 0x00]); + // ldx assert_instruction("ldx #$20", &[0xA2, 0x20]); assert_instruction("ldx $20", &[0xA6, 0x20]); @@ -2482,6 +2510,9 @@ mod tests { assert_instruction("sta ($20, x)", &[0x81, 0x20]); assert_instruction("sta ($20), y", &[0x91, 0x20]); + // Expand zeropage-looking into absolute index. + assert_instruction("sta $42, y", &[0x99, 0x42, 0x00]); + // stx assert_instruction("stx $20", &[0x86, 0x20]); assert_instruction("stx $20, y", &[0x96, 0x20]); -- cgit v1.2.3