diff options
author | Ben Bridle <ben@derelict.engineering> | 2025-02-28 14:35:04 +1300 |
---|---|---|
committer | Ben Bridle <ben@derelict.engineering> | 2025-02-28 14:35:04 +1300 |
commit | da5c8173a56d5be7fa23d2b18eaba1542aa31dd6 (patch) | |
tree | 6ef7aa76568bfa2488b0d0d9a878016eabadcae0 | |
parent | dba769e13ca5029643c6068e53fa34ae0fea8421 (diff) | |
download | torque-asm-da5c8173a56d5be7fa23d2b18eaba1542aa31dd6.zip |
Implement inhx format
inhx is the original Intel hex format.
-rw-r--r-- | src/formats/inhx.rs | 38 | ||||
-rw-r--r-- | src/formats/inhx32.rs | 51 | ||||
-rw-r--r-- | src/formats/mod.rs | 43 | ||||
-rw-r--r-- | src/main.rs | 8 |
4 files changed, 94 insertions, 46 deletions
diff --git a/src/formats/inhx.rs b/src/formats/inhx.rs new file mode 100644 index 0000000..e83e870 --- /dev/null +++ b/src/formats/inhx.rs @@ -0,0 +1,38 @@ +use crate::*; + + +pub fn format_inhx(words: &[Word]) -> String { + let mut records = Vec::new(); + for (i, chunk) in words.chunks(16).enumerate() { + records.push(data_record(chunk, (i * 16) as u16)); + } + records.push(terminating_record()); + + let mut output = String::new(); + for record in records { + output.push_str(&record.to_string()); + } + return output; +} + +fn data_record(words: &[Word], address: u16) -> InhxRecord { + let mut record = InhxRecord::new(); + record.byte((words.len()) as u8); + record.be_double(address); + record.byte(0x00); + for word in words { + match word.bits <= 8 { + true => record.byte(word.value as u8), + false => panic!("Word '{word}' has more than 8 bits."), + }; + } + return record; +} + +fn terminating_record() -> InhxRecord { + let mut record = InhxRecord::new(); + record.byte(0x00); + record.be_double(0x0000); + record.byte(0x01); + return record; +} diff --git a/src/formats/inhx32.rs b/src/formats/inhx32.rs index d9c31d3..fd7fd7b 100644 --- a/src/formats/inhx32.rs +++ b/src/formats/inhx32.rs @@ -16,47 +16,8 @@ pub fn format_inhx32(words: &[Word]) -> String { return output; } -struct Record { - bytes: Vec<u8>, -} - -impl Record { - pub fn new() -> Self { - Self { bytes: Vec::new() } - } - - pub fn byte(&mut self, byte: u8) { - self.bytes.push(byte); - } - - pub fn be_double(&mut self, double: u16) { - let [high, low] = double.to_be_bytes(); - self.byte(high); - self.byte(low); - } - - pub fn le_double(&mut self, double: u16) { - let [high, low] = double.to_be_bytes(); - self.byte(low); - self.byte(high); - } - - pub fn to_string(self) -> String { - let mut sum: u8 = 0; - for byte in &self.bytes { - sum = sum.wrapping_add(*byte); - } - let checksum = sum.wrapping_neg(); - let mut output = String::new(); - for byte in &self.bytes { - output.push_str(&format!("{byte:0>2X}")); - } - format!(":{output}{checksum:0>2X}\n") - } -} - -fn data_record(words: &[Word], address: u16) -> Record { - let mut record = Record::new(); +fn data_record(words: &[Word], address: u16) -> InhxRecord { + let mut record = InhxRecord::new(); record.byte((words.len() * 2) as u8); record.be_double(address * 2); record.byte(0x00); @@ -69,8 +30,8 @@ fn data_record(words: &[Word], address: u16) -> Record { return record; } -fn extended_linear_address(address: u16) -> Record { - let mut record = Record::new(); +fn extended_linear_address(address: u16) -> InhxRecord { + let mut record = InhxRecord::new(); record.byte(0x02); record.be_double(0x0000); record.byte(0x04); @@ -78,8 +39,8 @@ fn extended_linear_address(address: u16) -> Record { return record; } -fn terminating_record() -> Record { - let mut record = Record::new(); +fn terminating_record() -> InhxRecord { + let mut record = InhxRecord::new(); record.byte(0x00); record.be_double(0x0000); record.byte(0x01); diff --git a/src/formats/mod.rs b/src/formats/mod.rs index 42d198c..82f19f1 100644 --- a/src/formats/mod.rs +++ b/src/formats/mod.rs @@ -1,2 +1,45 @@ +mod inhx; mod inhx32; + +pub use inhx::*; pub use inhx32::*; + + +pub struct InhxRecord { + bytes: Vec<u8>, +} + +impl InhxRecord { + pub fn new() -> Self { + Self { bytes: Vec::new() } + } + + pub fn byte(&mut self, byte: u8) { + self.bytes.push(byte); + } + + pub fn be_double(&mut self, double: u16) { + let [high, low] = double.to_be_bytes(); + self.byte(high); + self.byte(low); + } + + pub fn le_double(&mut self, double: u16) { + let [high, low] = double.to_be_bytes(); + self.byte(low); + self.byte(high); + } + + pub fn to_string(self) -> String { + let mut sum: u8 = 0; + for byte in &self.bytes { + sum = sum.wrapping_add(*byte); + } + let checksum = sum.wrapping_neg(); + let mut output = String::new(); + for byte in &self.bytes { + output.push_str(&format!("{byte:0>2X}")); + } + format!(":{output}{checksum:0>2X}\n") + } +} diff --git a/src/main.rs b/src/main.rs index 9fb404c..f271bcd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -47,7 +47,7 @@ fn main() { let dry_run = args.named("dry-run").short('n').as_bool(); let Ok(format) = Format::from_str(format.as_str()) else { - fatal!("Unknown format '{format}', expected 'debug', 'inhx32', 'raw', or 'source'. "); + fatal!("Unknown format '{format}', expected 'debug', 'inhx', 'inhx32', 'raw', or 'source'. "); }; // ----------------------------------------------------------------------- @@ -127,6 +127,10 @@ fn main() { } write_bytes_and_exit(output.as_bytes(), destination_path.as_ref()); } + Format::Inhx => { + let output = format_inhx(&bytecode.words); + write_bytes_and_exit(output.as_bytes(), destination_path.as_ref()); + } Format::Inhx32 => { let output = format_inhx32(&bytecode.words); write_bytes_and_exit(output.as_bytes(), destination_path.as_ref()); @@ -162,6 +166,7 @@ fn write_bytes_and_exit<P: AsRef<Path>>(bytes: &[u8], path: Option<&P>) -> ! { #[derive(PartialEq)] enum Format { Debug, + Inhx, Inhx32, Raw, Source, @@ -172,6 +177,7 @@ impl FromStr for Format { fn from_str(string: &str) -> Result<Self, ()> { match string { "debug" => Ok(Self::Debug), + "inhx" => Ok(Self::Inhx), "inhx32" => Ok(Self::Inhx32), "raw" => Ok(Self::Raw), "source" => Ok(Self::Source), |