Skip to main content

c6000_disassembler/instruction/
parser.rs

1use std::{
2    collections::HashMap,
3    io::{Error, ErrorKind, Result},
4};
5
6use crate::instruction::{
7    ConditionalOperation, Unit,
8    register::{ControlRegister, Register},
9};
10
11pub fn parse(
12    opcode: u32,
13    format: &[ParsingInstruction],
14) -> Result<HashMap<String, ParsedVariable>> {
15    let mut resulting_map = HashMap::<String, ParsedVariable>::new();
16    let mut temp_opcode = opcode;
17
18    for instruction in format {
19        match instruction {
20            ParsingInstruction::Match { size, value } => {
21                let masked_value = read_u32(&mut temp_opcode, *size);
22                if masked_value != *value {
23                    return Err(Error::new(
24                        ErrorKind::InvalidInput,
25                        format!(
26                            "Opcode does not match instruction format (got {masked_value:b} instead of {value:b})"
27                        ),
28                    ));
29                }
30            }
31            ParsingInstruction::MatchMultiple { size, values } => {
32                let masked_value = read_u32(&mut temp_opcode, *size);
33                for value in values {
34                    if masked_value == *value {
35                        continue;
36                    }
37                }
38                return Err(Error::new(
39                    ErrorKind::InvalidInput,
40                    format!("Opcode does not match instruction format (got {masked_value:b})"),
41                ));
42            }
43            ParsingInstruction::Bit { name } => {
44                resulting_map.insert(
45                    name.clone(),
46                    ParsedVariable::Bool(read_bool(&mut temp_opcode)),
47                );
48            }
49            ParsingInstruction::BitMatch { name, value } => {
50                let read_value = read_bool(&mut temp_opcode);
51                if read_value != *value {
52                    return Err(Error::new(
53                        ErrorKind::InvalidInput,
54                        format!(
55                            "Opcode does not match instruction format ({name} is {read_value} instead of {value})"
56                        ),
57                    ));
58                }
59                resulting_map.insert(name.clone(), ParsedVariable::Bool(read_value));
60            }
61            ParsingInstruction::BitArray { size, name } => {
62                let mut value = Vec::<bool>::new();
63                for _ in 0..*size {
64                    value.push(read_bool(&mut temp_opcode));
65                }
66                resulting_map.insert(name.clone(), ParsedVariable::BoolVec(value));
67            }
68            ParsingInstruction::Unsigned { size, name } => {
69                let value = read_u32(&mut temp_opcode, *size);
70                let parsed_variable = {
71                    if *size > 8 {
72                        ParsedVariable::U32(value)
73                    } else {
74                        ParsedVariable::U8(value as u8)
75                    }
76                };
77                resulting_map.insert(name.clone(), parsed_variable);
78            }
79            ParsingInstruction::Signed { size, name } => {
80                let value = read_i32(&mut temp_opcode, *size);
81                resulting_map.insert(name.clone(), ParsedVariable::I32(value));
82            }
83            ParsingInstruction::Register { size, name }
84            | ParsingInstruction::RegisterCrosspath { size, name }
85            | ParsingInstruction::RegisterPair { size, name } => {
86                let u32_value = read_u32(&mut temp_opcode, *size);
87                let side = {
88                    let mut s = ParsedVariable::try_get(&resulting_map, "s")?.get_bool()?;
89                    if let ParsingInstruction::RegisterCrosspath { size: _, name: _ } = instruction
90                    {
91                        let crosspath = ParsedVariable::try_get(&resulting_map, "x")?.get_bool()?;
92                        s ^= crosspath;
93                    }
94                    s
95                };
96                let value = {
97                    if let ParsingInstruction::RegisterPair { size: _, name: _ } = instruction {
98                        Register::from_pair(u32_value as u8, side)
99                    } else {
100                        Register::from(u32_value as u8, side)
101                    }
102                };
103                resulting_map.insert(name.clone(), ParsedVariable::Register(value));
104            }
105            ParsingInstruction::ControlRegister { size, name } => {
106                let low_bits = read_u32(&mut temp_opcode, *size) as u8;
107                let high_bits = {
108                    if let Ok(variable) = ParsedVariable::try_get(&resulting_map, "crhi") {
109                        variable.get_u8()?
110                    } else {
111                        0
112                    }
113                };
114                let Some(value) = ControlRegister::from(low_bits, high_bits) else {
115                    return Err(Error::other(format!(
116                        "Invalid Control Register values (got crhi crlo {high_bits:b} {low_bits:b})"
117                    )));
118                };
119                resulting_map.insert(name.clone(), ParsedVariable::ControlRegister(value));
120            }
121            ParsingInstruction::LSDUnit { name } => {
122                let unit = match read_u32(&mut temp_opcode, 2) {
123                    0 => Unit::L,
124                    1 => Unit::S,
125                    2 => Unit::D,
126                    num => return Err(Error::other(format!("Invalid LSDUnit (got {num})"))),
127                };
128                resulting_map.insert(name.clone(), ParsedVariable::Unit(unit));
129            }
130            ParsingInstruction::ConditionalOperation { name } => {
131                let z = read_bool(&mut temp_opcode);
132                let creg = read_u32(&mut temp_opcode, 3) as u8;
133                resulting_map.insert(
134                    name.clone(),
135                    ParsedVariable::ConditionalOperation(ConditionalOperation::from(creg, z)),
136                );
137            }
138        }
139    }
140
141    Ok(resulting_map)
142}
143
144#[derive(Debug)]
145pub enum ParsingInstruction {
146    Match {
147        size: usize,
148        value: u32,
149    },
150    MatchMultiple {
151        size: usize,
152        values: Vec<u32>,
153    },
154    Bit {
155        name: String,
156    },
157    BitMatch {
158        name: String,
159        value: bool,
160    },
161    BitArray {
162        size: usize,
163        name: String,
164    },
165    Unsigned {
166        size: usize,
167        name: String,
168    },
169    Signed {
170        size: usize,
171        name: String,
172    },
173    Register {
174        size: usize,
175        name: String,
176    },
177    RegisterPair {
178        size: usize,
179        name: String,
180    },
181    RegisterCrosspath {
182        size: usize,
183        name: String,
184    },
185    ControlRegister {
186        size: usize,
187        name: String,
188    },
189    /// For .L .S and .D compact maps.
190    LSDUnit {
191        name: String,
192    },
193    ConditionalOperation {
194        name: String,
195    },
196}
197
198#[derive(Clone)]
199pub enum ParsedVariable {
200    Bool(bool),
201    BoolVec(Vec<bool>),
202    U32(u32),
203    U8(u8),
204    I32(i32),
205    Register(Register),
206    ControlRegister(ControlRegister),
207    Unit(Unit),
208    ConditionalOperation(Option<ConditionalOperation>),
209}
210
211impl ParsedVariable {
212    pub fn get_bool(&self) -> Result<bool> {
213        if let ParsedVariable::Bool(value) = self {
214            Ok(*value)
215        } else {
216            Err(Error::other("Not a Bool variable"))
217        }
218    }
219
220    pub fn get_bool_vec(&self) -> Result<Vec<bool>> {
221        if let ParsedVariable::BoolVec(value) = self {
222            Ok(value.clone())
223        } else {
224            Err(Error::other("Not a BoolVec variable"))
225        }
226    }
227
228    pub fn get_u32(&self) -> Result<u32> {
229        if let ParsedVariable::U32(value) = self {
230            Ok(*value)
231        } else if let ParsedVariable::U8(value) = self {
232            Ok(*value as u32)
233        } else {
234            Err(Error::other("Not a U32 variable"))
235        }
236    }
237
238    pub fn get_i32(&self) -> Result<i32> {
239        if let ParsedVariable::I32(value) = self {
240            Ok(*value)
241        } else if let ParsedVariable::U32(value) = self {
242            Ok(u32::cast_signed(*value))
243        } else if let ParsedVariable::U8(value) = self {
244            Ok(u8::cast_signed(*value) as i32)
245        } else {
246            Err(Error::other("Not a U32 variable"))
247        }
248    }
249
250    pub fn get_u8(&self) -> Result<u8> {
251        if let ParsedVariable::U8(value) = self {
252            Ok(*value)
253        } else if let ParsedVariable::U32(value) = self {
254            Ok(*value as u8)
255        } else {
256            Err(Error::other("Not a U8 variable"))
257        }
258    }
259
260    pub fn get_register(&self) -> Result<Register> {
261        if let ParsedVariable::Register(value) = self {
262            Ok(*value)
263        } else {
264            Err(Error::other("Not a Register variable"))
265        }
266    }
267
268    pub fn get_control_register(&self) -> Result<ControlRegister> {
269        if let ParsedVariable::ControlRegister(value) = self {
270            Ok(*value)
271        } else {
272            Err(Error::other("Not a Control Register variable"))
273        }
274    }
275
276    pub fn get_unit(&self) -> Result<Unit> {
277        if let ParsedVariable::Unit(value) = self {
278            Ok(*value)
279        } else {
280            Err(Error::other("Not a Unit variable"))
281        }
282    }
283
284    pub fn get_conditional_operation(&self) -> Result<Option<ConditionalOperation>> {
285        if let ParsedVariable::ConditionalOperation(value) = self {
286            Ok(*value)
287        } else {
288            Err(Error::other("Not a Conditional Operation variable"))
289        }
290    }
291
292    pub fn try_get<'a>(hashmap: &'a HashMap<String, Self>, name: &str) -> Result<&'a Self> {
293        let Some(value) = hashmap.get(name) else {
294            return Err(Error::other("Parsing error"));
295        };
296        Ok(value)
297    }
298}
299
300fn read_bool(opcode: &mut u32) -> bool {
301    let value = if *opcode & 1 == 1 { true } else { false };
302    *opcode >>= 1;
303    value
304}
305
306fn read_i32(opcode: &mut u32, size: usize) -> i32 {
307    let mask = create_mask(size);
308    let mut value_u32 = *opcode & mask;
309    *opcode >>= size;
310    let sign_bit_mask = 1 << (size - 1);
311    let value = {
312        if value_u32 & sign_bit_mask == sign_bit_mask {
313            value_u32 ^= mask;
314            value_u32 += 1;
315            -(value_u32 as i32)
316        } else {
317            value_u32 as i32
318        }
319    };
320    value
321}
322
323fn read_u32(opcode: &mut u32, size: usize) -> u32 {
324    let mask = create_mask(size);
325    let value = *opcode & mask;
326    *opcode >>= size;
327    value
328}
329
330fn create_mask(size: usize) -> u32 {
331    let mut mask = 0u32;
332    for _ in 0..size {
333        mask <<= 1;
334        mask += 1;
335    }
336    mask
337}