mod inhx; mod inhx32; mod raw; mod debug; pub use inhx::*; pub use inhx32::*; pub use raw::*; pub use debug::*; use crate::*; use log::*; #[derive(Clone, Copy, PartialEq)] pub enum Format { Debug, Inhx, Inhx32, Raw, Source, } impl Format { pub fn from_str(string: &str) -> Self { match string { "debug" => Self::Debug, "inhx" => Self::Inhx, "inhx32" => Self::Inhx32, "raw" => Self::Raw, "source" => Self::Source, _ => fatal!("Unknown format '{string}', expected 'debug', 'inhx', 'inhx32', 'raw', or 'source'"), } } } impl std::fmt::Display for Format { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { let string = match self { Self::Debug => "debug", Self::Inhx => "inhx", Self::Inhx32 => "inhx32", Self::Raw => "raw", Self::Source => "source", }; write!(f, "{string}") } } pub enum FormatError { /// (expected, received) AddressTooLarge(usize, usize), /// (expected, received) WordTooWide(u32, u32, SourceSpan), /// ExpectedFixedWidth, } pub fn report_format_error(error: &FormatError, format: Format, source_code: &str) { match error { FormatError::AddressTooLarge(expected, received) => error!("The {format} format requires that addresses do not exceed {expected}, but the address {received} was reached"), FormatError::WordTooWide(expected, received, source) => { let message = format!("The {format} format requires that words are no wider than {expected} bits, but a {received} bit word was found"); let context = Context { source_code, source }; report_source_issue(LogLevel::Error, &context, &message); } FormatError::ExpectedFixedWidth => error!("The {format} format requires all words to be the same width"), } std::process::exit(1); } pub struct InhxRecord { bytes: Vec, } 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") } } pub fn calculate_fixed_width(segments: &[Segment]) -> Option { let mut width = None; for segment in segments { for word in &segment.words { let word_width = word.value.width; match width { Some(width) => if word_width != width { return None; } None => width = Some(word_width), } } } return width.or(Some(0)); }