Skip to main content

c6000_disassembler/instruction/
memory.rs

1use std::{
2    fmt::Display,
3    io::{Error, ErrorKind, Result},
4};
5
6use crate::instruction::{
7    C6000Instruction, DataSize, InstructionData,
8    parser::{ParsedVariable, ParsingInstruction, parse},
9    register::Register,
10};
11
12#[derive(PartialEq, Eq)]
13pub enum MemoryInstructionType {
14    Load,
15    Store,
16}
17
18pub enum AddressGeneratorMode {
19    NegativeR(Register),
20    PositiveR(Register),
21    PredecrementR(Register),
22    PreincrementR(Register),
23    PostdecrementR(Register),
24    PostincrementR(Register),
25    Negative(u32),
26    Positive(u32),
27    Predecrement(u32),
28    Preincrement(u32),
29    Postdecrement(u32),
30    Postincrement(u32),
31}
32
33impl AddressGeneratorMode {
34    pub fn get_register(&self) -> Option<Register> {
35        match self {
36            AddressGeneratorMode::NegativeR(register)
37            | AddressGeneratorMode::PositiveR(register)
38            | AddressGeneratorMode::PredecrementR(register)
39            | AddressGeneratorMode::PreincrementR(register)
40            | AddressGeneratorMode::PostdecrementR(register)
41            | AddressGeneratorMode::PostincrementR(register) => Some(*register),
42            _ => None,
43        }
44    }
45
46    pub fn get_constant(&self) -> Option<u32> {
47        match self {
48            AddressGeneratorMode::Negative(cst)
49            | AddressGeneratorMode::Positive(cst)
50            | AddressGeneratorMode::Predecrement(cst)
51            | AddressGeneratorMode::Preincrement(cst)
52            | AddressGeneratorMode::Postdecrement(cst)
53            | AddressGeneratorMode::Postincrement(cst) => Some(*cst),
54            _ => None,
55        }
56    }
57}
58
59impl Display for AddressGeneratorMode {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        match self {
62            AddressGeneratorMode::NegativeR(register) => write!(f, "*-R[{register}]"),
63            AddressGeneratorMode::PositiveR(register) => write!(f, "*+R[{register}]"),
64            AddressGeneratorMode::PredecrementR(register) => write!(f, "*--R[{register}]"),
65            AddressGeneratorMode::PreincrementR(register) => write!(f, "*++R[{register}]"),
66            AddressGeneratorMode::PostdecrementR(register) => write!(f, "*R--[{register}]"),
67            AddressGeneratorMode::PostincrementR(register) => write!(f, "*R++[{register}]"),
68            AddressGeneratorMode::Negative(cst) => write!(f, "*-R[{cst}]"),
69            AddressGeneratorMode::Positive(cst) => write!(f, "*+R[{cst}]"),
70            AddressGeneratorMode::Predecrement(cst) => write!(f, "*--R[{cst}]"),
71            AddressGeneratorMode::Preincrement(cst) => write!(f, "*++R[{cst}]"),
72            AddressGeneratorMode::Postdecrement(cst) => write!(f, "*R--[{cst}]"),
73            AddressGeneratorMode::Postincrement(cst) => write!(f, "*R++[{cst}]"),
74        }
75    }
76}
77
78pub struct MemoryInstruction {
79    instruction_data: InstructionData,
80    instruction_type: MemoryInstructionType,
81    data_size: DataSize,
82    base_register: Register,
83    mode: AddressGeneratorMode,
84    side: bool,
85    register: Register,
86}
87
88impl C6000Instruction for MemoryInstruction {
89    fn new(input: &super::InstructionInput) -> Result<Self> {
90        let formats = [
91            vec![
92                ParsingInstruction::Bit {
93                    name: String::from("p"),
94                },
95                ParsingInstruction::Bit {
96                    name: String::from("s"),
97                },
98                ParsingInstruction::Match { size: 2, value: 1 },
99                ParsingInstruction::Unsigned {
100                    size: 3,
101                    name: String::from("op"),
102                },
103                ParsingInstruction::Bit {
104                    name: String::from("y"),
105                },
106                ParsingInstruction::Bit {
107                    name: String::from("op2"),
108                },
109                ParsingInstruction::Unsigned {
110                    size: 4,
111                    name: String::from("mode"),
112                },
113                ParsingInstruction::Unsigned {
114                    size: 5,
115                    name: String::from("offset"),
116                },
117                ParsingInstruction::Unsigned {
118                    size: 5,
119                    name: String::from("baseR"),
120                },
121                ParsingInstruction::Register {
122                    size: 5,
123                    name: String::from("register"),
124                },
125                ParsingInstruction::ConditionalOperation {
126                    name: String::from("creg"),
127                },
128            ],
129            vec![
130                ParsingInstruction::Bit {
131                    name: String::from("p"),
132                },
133                ParsingInstruction::Bit {
134                    name: String::from("s"),
135                },
136                ParsingInstruction::Match {
137                    size: 2,
138                    value: 0b11,
139                },
140                ParsingInstruction::Unsigned {
141                    size: 3,
142                    name: String::from("op"),
143                },
144                ParsingInstruction::Bit {
145                    name: String::from("y"),
146                },
147                ParsingInstruction::Unsigned {
148                    size: 15,
149                    name: String::from("cst"),
150                },
151                ParsingInstruction::Register {
152                    size: 5,
153                    name: String::from("register"),
154                },
155                ParsingInstruction::ConditionalOperation {
156                    name: String::from("creg"),
157                },
158            ],
159        ];
160
161        for format in formats {
162            let Ok(parsed_variables) = parse(input.opcode, &format) else {
163                continue;
164            };
165            let p_bit = ParsedVariable::try_get(&parsed_variables, "p")?.get_bool()?;
166
167            let op2 = {
168                if let Ok(var) = ParsedVariable::try_get(&parsed_variables, "op2") {
169                    var.get_bool()?
170                } else {
171                    false
172                }
173            };
174            let (instruction_type, data_size) =
175                match ParsedVariable::try_get(&parsed_variables, "op")?.get_u8()? {
176                    0b111 if !op2 => (MemoryInstructionType::Store, DataSize::Word),
177                    0b011 if !op2 => (MemoryInstructionType::Store, DataSize::Byte),
178                    0b100 if op2 => (MemoryInstructionType::Store, DataSize::DoubleWord),
179                    0b101 if !op2 => (MemoryInstructionType::Store, DataSize::HalfWord),
180                    0b111 if op2 => (MemoryInstructionType::Store, DataSize::NonAlignedDoubleWord),
181                    0b101 if op2 => (MemoryInstructionType::Store, DataSize::NonAlignedWord),
182                    0b010 if !op2 => (MemoryInstructionType::Load, DataSize::Byte),
183                    0b001 if !op2 => (MemoryInstructionType::Load, DataSize::ByteUnsigned),
184                    0b110 if op2 => (MemoryInstructionType::Load, DataSize::DoubleWord),
185                    0b100 if !op2 => (MemoryInstructionType::Load, DataSize::HalfWord),
186                    0b000 if !op2 => (MemoryInstructionType::Load, DataSize::HalfWordUnsigned),
187                    0b010 if op2 => (MemoryInstructionType::Load, DataSize::NonAlignedDoubleWord),
188                    0b011 if op2 => (MemoryInstructionType::Load, DataSize::NonAlignedWord),
189                    0b110 if !op2 => (MemoryInstructionType::Load, DataSize::Word),
190                    _ => {
191                        return Err(Error::new(
192                            ErrorKind::InvalidInput,
193                            "Invalid memory instruction opcode",
194                        ));
195                    }
196                };
197
198            let side = ParsedVariable::try_get(&parsed_variables, "y")?.get_bool()?;
199            let mode = {
200                if let Ok(var) = ParsedVariable::try_get(&parsed_variables, "mode") {
201                    let offset = ParsedVariable::try_get(&parsed_variables, "offset")?.get_u8()?;
202                    let res = match var.get_u8()? {
203                        0b0000 => AddressGeneratorMode::Negative(offset as u32),
204                        0b0001 => AddressGeneratorMode::Positive(offset as u32),
205                        0b1000 => AddressGeneratorMode::Predecrement(offset as u32),
206                        0b1001 => AddressGeneratorMode::Preincrement(offset as u32),
207                        0b1010 => AddressGeneratorMode::Postdecrement(offset as u32),
208                        0b1011 => AddressGeneratorMode::Postincrement(offset as u32),
209                        0b0100 => AddressGeneratorMode::NegativeR(Register::from(offset, side)),
210                        0b0101 => AddressGeneratorMode::PositiveR(Register::from(offset, side)),
211                        0b1100 => AddressGeneratorMode::PredecrementR(Register::from(offset, side)),
212                        0b1101 => AddressGeneratorMode::PreincrementR(Register::from(offset, side)),
213                        0b1110 => {
214                            AddressGeneratorMode::PostdecrementR(Register::from(offset, side))
215                        }
216                        0b1111 => {
217                            AddressGeneratorMode::PostincrementR(Register::from(offset, side))
218                        }
219                        _ => {
220                            return Err(Error::new(
221                                ErrorKind::InvalidInput,
222                                "Invalid memory instruction mode",
223                            ));
224                        }
225                    };
226                    res
227                } else {
228                    let cst = ParsedVariable::try_get(&parsed_variables, "cst")?.get_u32()?;
229                    AddressGeneratorMode::Positive(cst)
230                }
231            };
232
233            let base_register = {
234                if let Ok(var) = ParsedVariable::try_get(&parsed_variables, "baseR") {
235                    Register::from(var.get_u8()?, side)
236                } else {
237                    if side {
238                        Register::B(15)
239                    } else {
240                        Register::B(14)
241                    }
242                }
243            };
244            let register =
245                ParsedVariable::try_get(&parsed_variables, "register")?.get_register()?;
246
247            return Ok(Self {
248                instruction_type,
249                data_size,
250                mode,
251                base_register,
252                side,
253                register,
254                instruction_data: InstructionData {
255                    opcode: input.opcode,
256                    compact: false,
257                    p_bit,
258                    ..Default::default()
259                },
260            });
261        }
262
263        Err(Error::new(
264            ErrorKind::InvalidInput,
265            "Not a memory load/store instruction",
266        ))
267    }
268
269    fn instruction_clean(&self) -> String {
270        let prefix = if self.instruction_type == MemoryInstructionType::Load {
271            String::from("LD")
272        } else {
273            String::from("ST")
274        };
275        format!("{prefix}{}", self.data_size.to_short_string())
276    }
277
278    fn instruction(&self) -> String {
279        format!(
280            "{}.D{}T{}",
281            self.instruction_clean(),
282            if self.side { 2 } else { 1 },
283            if self.register.side() { 2 } else { 1 },
284        )
285    }
286
287    fn operands(&self) -> String {
288        let mode = self
289            .mode
290            .to_string()
291            .replace("R", self.base_register.to_string().as_str());
292        let shift_by = match self.data_size {
293            DataSize::Byte | DataSize::ByteUnsigned => 0,
294            DataSize::HalfWord | DataSize::HalfWordUnsigned => 1,
295            DataSize::Word | DataSize::NonAlignedWord => 2,
296            DataSize::DoubleWord | DataSize::NonAlignedDoubleWord => 3, // NonAlignedDoubleWord varies based on sc field
297        };
298        let comment = {
299            if let Some(register) = self.mode.get_register() {
300                format!("({register} << {shift_by})")
301            } else if let Some(constant) = self.mode.get_constant()
302                && constant != 0
303            {
304                let result = constant << shift_by;
305                format!("({constant} << {shift_by} = 0x{result:04X})")
306            } else {
307                String::new()
308            }
309        };
310        if self.instruction_type == MemoryInstructionType::Load {
311            format!("{mode}, {} {comment}", self.register)
312        } else {
313            format!("{}, {mode} {comment}", self.register)
314        }
315    }
316
317    fn instruction_data(&self) -> &super::InstructionData {
318        &self.instruction_data
319    }
320
321    fn instruction_data_mut(&mut self) -> &mut super::InstructionData {
322        &mut self.instruction_data
323    }
324}