From da5c8173a56d5be7fa23d2b18eaba1542aa31dd6 Mon Sep 17 00:00:00 2001
From: Ben Bridle <ben@derelict.engineering>
Date: Fri, 28 Feb 2025 14:35:04 +1300
Subject: Implement inhx format

inhx is the original Intel hex format.
---
 src/formats/inhx.rs   | 38 ++++++++++++++++++++++++++++++++++++++
 src/formats/inhx32.rs | 51 ++++++---------------------------------------------
 src/formats/mod.rs    | 43 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 87 insertions(+), 45 deletions(-)
 create mode 100644 src/formats/inhx.rs

(limited to 'src/formats')

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")
+    }
+}
-- 
cgit v1.2.3-70-g09d2