aboutsummaryrefslogtreecommitdiff
path: root/lib/xixanta/src
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <mssola@mssola.com>2026-04-24 22:29:47 +0200
committerMiquel Sabaté Solà <mssola@mssola.com>2026-04-24 22:29:47 +0200
commit1410c98545d00c8508a715a566cf8e3e4e424773 (patch)
treea458d8c0934a69c37d1d374dec7a4b32ac2d4f14 /lib/xixanta/src
parentc8138a0fc5353dc9017fc32fb5ef12a6fe780415 (diff)
downloadtools.nes-1410c98545d00c8508a715a566cf8e3e4e424773.tar.gz
tools.nes-1410c98545d00c8508a715a566cf8e3e4e424773.zip
Add a big endian control statement
By default everything is little endian, and that should always be the case. That being said, if a literal is better expressed in big endian format for whatever reason, you can now use the .be or the .bigendian control statements. The terribly named .dbyt control statement can also be used for this purpose, but that's just to be compatible with the implementation from ca65. Signed-off-by: Miquel Sabaté Solà <mssola@mssola.com>
Diffstat (limited to 'lib/xixanta/src')
-rw-r--r--lib/xixanta/src/assembler.rs46
-rw-r--r--lib/xixanta/src/node.rs2
-rw-r--r--lib/xixanta/src/opcodes.rs30
3 files changed, 73 insertions, 5 deletions
diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs
index 646b072..614bee4 100644
--- a/lib/xixanta/src/assembler.rs
+++ b/lib/xixanta/src/assembler.rs
@@ -2097,9 +2097,14 @@ impl<'a> Assembler<'a> {
// Otherwise, check the function that could act as a statement that
// produces bundles.
match node.node_type {
- NodeType::Control(ControlType::Byte) => Ok(self.push_evaluated_arguments(node, 1)?),
+ NodeType::Control(ControlType::Byte) => {
+ Ok(self.push_evaluated_arguments(node, 1, true)?)
+ }
NodeType::Control(ControlType::Addr) | NodeType::Control(ControlType::Word) => {
- Ok(self.push_evaluated_arguments(node, 2)?)
+ Ok(self.push_evaluated_arguments(node, 2, true)?)
+ }
+ NodeType::Control(ControlType::BigEndianWord) => {
+ Ok(self.push_evaluated_arguments(node, 2, false)?)
}
NodeType::Control(ControlType::ReserveMemory) => Ok(self.reserve_memory(node)?),
NodeType::Control(ControlType::Asciiz) => Ok(self.push_ascii_string(node)?),
@@ -2472,7 +2477,18 @@ impl<'a> Assembler<'a> {
}
}
- fn push_evaluated_arguments(&mut self, node: &PNode, nbytes: u8) -> Result<(), Error> {
+ // Iterate through the arguments of 'node' and push the bundle that can be
+ // evaluated from each argument. The caller expects this bundle to span
+ // exactly 'nbytes' bytes, and if that is not met then zeroes should be
+ // added. Last but not least, set 'little_endian' to true if you want the
+ // bundle to be expressed in little endian format, or false if we should go
+ // for big endian (i.e. an explicit '.be' is being used).
+ fn push_evaluated_arguments(
+ &mut self,
+ node: &PNode,
+ nbytes: u8,
+ little_endian: bool,
+ ) -> Result<(), Error> {
match &node.args {
Some(args) => {
for arg in args {
@@ -2500,12 +2516,21 @@ impl<'a> Assembler<'a> {
}
2 => {
bundle.size = 2;
- bundle.bytes[1] = 0x00;
+ if little_endian {
+ bundle.bytes[1] = 0x00;
+ }
bundle.bytes[2] = 0x00;
}
_ => panic!("bad argument when evaluating arguments"),
}
}
+
+ // If this was supposed to be a big endian word, swap the
+ // bytes we've got before pushing the bundle.
+ if !little_endian {
+ bundle.bytes.swap(1, 0);
+ }
+
self.push_bundle(bundle, arg)?;
}
}
@@ -4572,10 +4597,11 @@ JAL procedure
.byte #Vars::Variable
.dw $2001, $02
+ .be $2001, $02
"#,
);
- assert_eq!(res.len(), 3);
+ assert_eq!(res.len(), 5);
// .byte
assert_eq!(res[0].bytes[0], 0x04);
@@ -4591,6 +4617,16 @@ JAL procedure
assert_eq!(res[2].bytes[0], 0x02);
assert_eq!(res[2].bytes[1], 0x00);
assert_eq!(res[2].size, 2);
+
+ // First .be argument.
+ assert_eq!(res[3].bytes[0], 0x20);
+ assert_eq!(res[3].bytes[1], 0x01);
+ assert_eq!(res[3].size, 2);
+
+ // Second .be argument.
+ assert_eq!(res[4].bytes[0], 0x00);
+ assert_eq!(res[4].bytes[1], 0x02);
+ assert_eq!(res[4].size, 2);
}
#[test]
diff --git a/lib/xixanta/src/node.rs b/lib/xixanta/src/node.rs
index af76edd..ee3ae24 100644
--- a/lib/xixanta/src/node.rs
+++ b/lib/xixanta/src/node.rs
@@ -155,6 +155,7 @@ pub enum ControlType {
Segment,
Byte,
Word,
+ BigEndianWord,
Addr,
IncBin,
StartRepeat,
@@ -187,6 +188,7 @@ impl fmt::Display for ControlType {
ControlType::Segment => write!(f, ".segment"),
ControlType::Byte => write!(f, ".byte/.db"),
ControlType::Word => write!(f, ".word/.dw"),
+ ControlType::BigEndianWord => write!(f, ".dbyt/.be/.bigendian"),
ControlType::Addr => write!(f, ".addr"),
ControlType::IncBin => write!(f, ".incbin"),
ControlType::StartRepeat => write!(f, ".repeat"),
diff --git a/lib/xixanta/src/opcodes.rs b/lib/xixanta/src/opcodes.rs
index 150813e..25b3add 100644
--- a/lib/xixanta/src/opcodes.rs
+++ b/lib/xixanta/src/opcodes.rs
@@ -1830,6 +1830,36 @@ pub static CONTROL_FUNCTIONS: LazyLock<HashMap<String, Control>> = LazyLock::new
},
);
functions.insert(
+ String::from(".dbyt"),
+ Control {
+ control_type: ControlType::BigEndianWord,
+ has_identifier: None,
+ required_args: None,
+ touches_context: false,
+ only_string: false,
+ },
+ );
+ functions.insert(
+ String::from(".be"),
+ Control {
+ control_type: ControlType::BigEndianWord,
+ has_identifier: None,
+ required_args: None,
+ touches_context: false,
+ only_string: false,
+ },
+ );
+ functions.insert(
+ String::from(".bigendian"),
+ Control {
+ control_type: ControlType::BigEndianWord,
+ has_identifier: None,
+ required_args: None,
+ touches_context: false,
+ only_string: false,
+ },
+ );
+ functions.insert(
String::from(".incbin"),
Control {
control_type: ControlType::IncBin,