summaryrefslogtreecommitdiff
path: root/src/formats/mod.rs
blob: 132001a27fca5cdce930f1e40f50cf016add4cee (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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));
}