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, };
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}