diff options
| author | Miquel Sabaté Solà <mssola@mssola.com> | 2026-04-24 22:29:47 +0200 |
|---|---|---|
| committer | Miquel Sabaté Solà <mssola@mssola.com> | 2026-04-24 22:29:47 +0200 |
| commit | 1410c98545d00c8508a715a566cf8e3e4e424773 (patch) | |
| tree | a458d8c0934a69c37d1d374dec7a4b32ac2d4f14 | |
| parent | c8138a0fc5353dc9017fc32fb5ef12a6fe780415 (diff) | |
| download | tools.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>
| -rw-r--r-- | lib/xixanta/src/assembler.rs | 46 | ||||
| -rw-r--r-- | lib/xixanta/src/node.rs | 2 | ||||
| -rw-r--r-- | lib/xixanta/src/opcodes.rs | 30 |
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, |
