aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta/src/assembler.rs
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mikisabate@gmail.com>2024-12-20 15:41:46 +0100
committerMiquel Sabaté Solà <mikisabate@gmail.com>2024-12-20 15:41:46 +0100
commited3d34b0afb1edb405dfa6dcb00527b9a9a2e480 (patch)
tree35fb1e0e3d22b2d6d35db778b45e5ade05337929 /lib/xixanta/src/assembler.rs
parentea5f0f81b8a76408d8311cabbc48228798cc20e8 (diff)
downloadtools.nes-ed3d34b0afb1edb405dfa6dcb00527b9a9a2e480.tar.gz
tools.nes-ed3d34b0afb1edb405dfa6dcb00527b9a9a2e480.zip
Only shrink the addressing on resolved bundles
Commit ea5f0f81b8a7 ("Shrink some absolute instructions by one byte") applied the optimization in all cases, but we cannot perform it on bundles which are yet to be resolved. This is because in unresolved bundles the value is only an offset, which usually will fit on a single byte and hence the optimization would've been carried out. That being said, whenever we resolve this it might just be the case the it wouldn't have fit in that single byte, and hence we end up with an artificially shrinked instruction for a 16-bit address. Signed-off-by: Miquel Sabaté Solà <mikisabate@gmail.com>
Diffstat (limited to 'lib/xixanta/src/assembler.rs')
-rw-r--r--lib/xixanta/src/assembler.rs38
1 files changed, 35 insertions, 3 deletions
diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs
index 92f57cd..4fd8d92 100644
--- a/lib/xixanta/src/assembler.rs
+++ b/lib/xixanta/src/assembler.rs
@@ -1429,8 +1429,12 @@ impl Assembler {
"x" => {
// If the size == 2 but we can fit it on a single byte (i.e.
// because the second byte is just 0x00), then just "compress"
- // this instruction.
- if val.size == 1 || val.bytes[1] == 0x00 {
+ // this instruction. Note that this is only valid if the value
+ // is fully well-known (i.e. it's not yet to be resolved). When
+ // the value is not yet resolved, it usually revolves around an
+ // 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) {
// Re-inforce the optimization when val.size == 2 by forcing
// the size to 1.
val.size = 1;
@@ -1441,7 +1445,7 @@ impl Assembler {
}
"y" => {
// Same optimization as with the "x" case.
- if val.size == 1 || val.bytes[1] == 0x00 {
+ if val.size == 1 || (val.resolved && val.bytes[1] == 0x00) {
val.size = 1;
Ok((AddressingMode::ZeropageIndexedY, val))
} else {
@@ -2528,6 +2532,34 @@ nop
}
#[test]
+ fn label_in_instruction_addressing() {
+ let mut asm = Assembler::new(EMPTY.to_vec());
+ asm.mappings[0].segments[0].bundles = minimal_header();
+ asm.mappings[0].offset = 6;
+ asm.current_mapping = 1;
+ let res = &asm
+ .assemble(
+ std::env::current_dir().unwrap().to_path_buf(),
+ r#"
+ ldx #0
+@load_palettes_loop:
+ lda palettes, x
+palettes:
+ .byte $0F, $12, $22, $32
+"#
+ .as_bytes(),
+ )
+ .unwrap()[0x10..];
+
+ assert_instruction("ldx #0", &res[0].bytes);
+ assert_instruction("lda $8005, x", &res[1].bytes);
+ assert_eq!(&res[2].bytes, &[0x0F, 0x00, 0x00]);
+ assert_eq!(&res[3].bytes, &[0x12, 0x00, 0x00]);
+ assert_eq!(&res[4].bytes, &[0x22, 0x00, 0x00]);
+ assert_eq!(&res[5].bytes, &[0x32, 0x00, 0x00]);
+ }
+
+ #[test]
fn full_to_zeropage_optimization() {
assert_instruction("sta $0020", &[0x85, 0x20]);
assert_instruction("sty $021, x", &[0x94, 0x21]);