summaryrefslogtreecommitdiff
path: root/src/progmem.rs
blob: 325eab1aabc744bc6683747b2547c57bb447d416 (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
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
133
134
135
136
use crate::memory::Memory;
use std::fmt;

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

impl fmt::Debug for ProgramMemory {
    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 ProgramMemory {
    /// Empty constructor
    pub fn new() -> Self {
        Self {
            array: [0; u16::max_value() as usize + 1],
        }
    }

    /// Constructor from hex
    pub fn from_hex(hex: String) -> Result<Self, String> {
        Self::new().hex(hex)
    }

    /// Method for sequential consuming building
    pub fn hex(mut self, hex: String) -> Result<Self, String> {
        match self.load_hex(hex) {
            Ok(_) => Ok(self),
            Err(string) => Err(string),
        }
    }

    /// Method for occasional incremental hex loading
    pub fn load_hex(&mut self, hex: String) -> Result<(), String> {
        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() {
                        self.array[ptr + offset as usize] = *byte;
                    }
                }
                Rectyp::EndOfFile => {}
            }
        }
        Ok(())
    }
}

impl Memory<u16> for ProgramMemory {
    fn get(&self, a: u16) -> u8 {
        self.array[a as usize]
    }

    fn set(&mut self, a: u16, v: u8) {
        self.array[a as usize] = v;
    }
}