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<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")
}
}
pub fn calculate_fixed_width(segments: &[Segment]) -> Option<u32> {
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));
}