aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2025-01-08 16:09:09 +0100
committerMiquel Sabaté Solà <mikisabate@gmail.com>2025-01-08 16:09:09 +0100
commitc060ab9807e66caa328259a0e19559d7d2727533 (patch)
tree61120b587c56ab5a17dbd7356f223907ae1c3c89 /lib
parent9b5e5aa6d36a550bed84f85df8e1e46fcf9765e1 (diff)
downloadtools.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>
Diffstat (limited to 'lib')
-rw-r--r--lib/xixanta/src/assembler.rs31
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]);