diff options
| author | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-01-08 16:09:09 +0100 |
|---|---|---|
| committer | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-01-08 16:09:09 +0100 |
| commit | c060ab9807e66caa328259a0e19559d7d2727533 (patch) | |
| tree | 61120b587c56ab5a17dbd7356f223907ae1c3c89 | |
| parent | 9b5e5aa6d36a550bed84f85df8e1e46fcf9765e1 (diff) | |
| download | tools.nes-c060ab9807e66caa328259a0e19559d7d2727533.tar.gz tools.nes-c060ab9807e66caa328259a0e19559d7d2727533.zip | |
Try absolute addressing on bad zeropage addressing
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à <mikisabate@gmail.com>
| -rw-r--r-- | lib/xixanta/src/assembler.rs | 31 |
1 files changed, 31 insertions, 0 deletions
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]); |
