summaryrefslogtreecommitdiff
path: root/src/rom.rs
blob: 77e64316ca874cf3e734f88fdf295cb284413289 (plain)
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
use std::fmt;

pub struct Rom {
    pub array: [u8; u16::max_value() as usize + 1],
}

impl fmt::Debug for Rom {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut v: Vec<char> = vec![];
        for (c, x) in self.array.iter().enumerate() {
            for hex_char in format!("{:02X}", *x).chars() {
                v.push(hex_char);
            }
            v.push(' ');
            if c % 8 == 7 {
                v.push('\n');
            }
        }
        write!(f, "{}", v.iter().collect::<String>())
    }
}

enum Rectyp {
    Data,
    EndOfFile,
    //ExtendedSegAddr,
    //StartSegAddr,
    //ExtendedLinearAddr,
    //StartLinearAddr,
}

struct HexLine {
    rectyp: Rectyp,
    offset: u16,
    data: Vec<u8>,
}

impl HexLine {
    fn from(s: &str) -> Result<Self, usize> {
        // The shortest possible sequence is EOF (:00000001FF)
        if s.len() < 11 {
            return Err(usize::max_value());
        }
        if &s[0..1] != ":" {
            return Err(0);
        }
        let offset = match u16::from_str_radix(&s[3..7], 16) {
            Ok(value) => value,
            Err(_) => return Err(3),
        };
        let bytecount = match usize::from_str_radix(&s[1..3], 16) {
            Ok(value) => value,
            Err(_) => return Err(1),
        };

        // If EOF reached
        if &s[7..9] == "01" {
            return Ok(HexLine {
                rectyp: Rectyp::EndOfFile,
                offset,
                data: vec![0],
            });
        } else if &s[7..9] == "00" {
            let mut counter = 9;
            let mut data = vec![];
            while counter < s.len() - 2 && counter < (9 + bytecount * 2) {
                data.push(match u8::from_str_radix(&s[counter..counter + 2], 16) {
                    Ok(value) => value,
                    Err(_) => return Err(counter),
                });
                counter += 2;
            }
            // TODO: check checksum
            return Ok(HexLine {
                rectyp: Rectyp::Data,
                offset,
                data,
            });
        }

        Err(3)
    }
}

impl Rom {
    pub fn from_hex(hex: String) -> Result<Self, String> {
        let mut array = [0; u16::max_value() as usize + 1];
        for (linenum, line) in hex.lines().enumerate() {
            let hex_line = match HexLine::from(line) {
                Ok(value) => value,
                Err(charnum) => return Err(format!("ihex parsing error {}:{}", linenum, charnum)),
            };
            let offset = hex_line.offset;
            match hex_line.rectyp {
                Rectyp::Data => {
                    for (ptr, byte) in hex_line.data.iter().enumerate() {
                        array[ptr + offset as usize] = *byte;
                    }
                }
                Rectyp::EndOfFile => {}
            }
        }
        Ok(Self { array })
    }
}