1use std::{
2 cmp::min,
3 io::{self, Error, ErrorKind},
4};
5
6use crate::instruction::{
7 C6000Instruction, ConditionalOperation, InstructionData,
8 parser::{ParsedVariable, ParsingInstruction, parse},
9 register::{ControlRegister, Register},
10};
11
12pub enum BranchUsing {
13 Displacement(i32),
14 Register(Register),
15 Pointer(ControlRegister),
16}
17
18pub struct BranchInstruction {
19 instruction_data: InstructionData,
20 pub branch_using: BranchUsing,
21 pub side: bool,
22 pce1_address: u32,
23 pub nop_count: u8,
24}
25
26impl BranchInstruction {
27 pub fn calculate_displacement_address(&self) -> io::Result<u32> {
28 match self.branch_using {
29 BranchUsing::Displacement(displacement) => {
30 let displacement_abs = displacement.unsigned_abs();
31 if self.pce1_address == 0 {
32 return Err(Error::other("PCE1 = 0"));
33 };
34 let branch_address = {
35 if displacement.is_positive() {
36 self.pce1_address + displacement_abs
37 } else {
38 self.pce1_address - displacement_abs
39 }
40 };
41 return Ok(branch_address);
42 }
43 _ => return Err(Error::other("Not displacement")),
44 }
45 }
46}
47
48impl C6000Instruction for BranchInstruction {
49 fn new(input: &super::InstructionInput) -> std::io::Result<Self> {
50 let formats = [
51 vec![
52 ParsingInstruction::Bit {
53 name: String::from("p"),
54 },
55 ParsingInstruction::Bit {
56 name: String::from("s"),
57 },
58 ParsingInstruction::Match {
59 size: 5,
60 value: 0b100,
61 },
62 ParsingInstruction::Signed {
63 size: 21,
64 name: String::from("cst"),
65 },
66 ParsingInstruction::ConditionalOperation {
67 name: String::from("cond"),
68 },
69 ],
70 vec![
71 ParsingInstruction::Bit {
72 name: String::from("p"),
73 },
74 ParsingInstruction::Bit {
75 name: String::from("s"),
76 },
77 ParsingInstruction::Match {
78 size: 10,
79 value: 0xD8,
80 },
81 ParsingInstruction::Bit {
82 name: String::from("x"),
83 },
84 ParsingInstruction::Match { size: 5, value: 0 },
85 ParsingInstruction::RegisterCrosspath {
86 size: 5,
87 name: String::from("src"),
88 },
89 ParsingInstruction::Match { size: 5, value: 0 },
90 ParsingInstruction::ConditionalOperation {
91 name: String::from("cond"),
92 },
93 ],
94 vec![
95 ParsingInstruction::Bit {
96 name: String::from("p"),
97 },
98 ParsingInstruction::Match {
99 size: 17,
100 value: 0x71,
101 },
102 ParsingInstruction::Unsigned {
103 size: 3,
104 name: String::from("op"),
105 },
106 ParsingInstruction::Match { size: 7, value: 0 },
107 ParsingInstruction::ConditionalOperation {
108 name: String::from("cond"),
109 },
110 ],
111 vec![
112 ParsingInstruction::Bit {
113 name: String::from("p"),
114 },
115 ParsingInstruction::Bit {
116 name: String::from("s"),
117 },
118 ParsingInstruction::Match {
119 size: 11,
120 value: 0x48,
121 },
122 ParsingInstruction::Unsigned {
123 size: 3,
124 name: String::from("nop"),
125 },
126 ParsingInstruction::Signed {
127 size: 12,
128 name: String::from("cst"),
129 },
130 ParsingInstruction::ConditionalOperation {
131 name: String::from("cond"),
132 },
133 ],
134 vec![
135 ParsingInstruction::Bit {
136 name: String::from("p"),
137 },
138 ParsingInstruction::BitMatch {
139 name: String::from("s"),
140 value: true,
141 },
142 ParsingInstruction::Match {
143 size: 10,
144 value: 0xD8,
145 },
146 ParsingInstruction::Bit {
147 name: String::from("x"),
148 },
149 ParsingInstruction::Unsigned {
150 size: 3,
151 name: String::from("nop"),
152 },
153 ParsingInstruction::Match { size: 2, value: 0 },
154 ParsingInstruction::RegisterCrosspath {
155 size: 5,
156 name: String::from("src"),
157 },
158 ParsingInstruction::Match { size: 5, value: 1 },
159 ParsingInstruction::ConditionalOperation {
160 name: String::from("cond"),
161 },
162 ],
163 ];
164 for format in formats {
165 let Ok(parsed_variables) = parse(input.opcode, format.as_slice()) else {
166 continue;
167 };
168 let p_bit = ParsedVariable::try_get(&parsed_variables, "p")?.get_bool()?;
169 let side = ParsedVariable::try_get(&parsed_variables, "s")?.get_bool()?;
170 let conditional_operation =
171 ParsedVariable::try_get(&parsed_variables, "cond")?.get_conditional_operation()?;
172 let nop_count = {
173 if let Ok(variable) = ParsedVariable::try_get(&parsed_variables, "nop") {
174 variable.get_u8()?
175 } else {
176 0
177 }
178 };
179 let branch_using = {
180 if let Ok(variable) = ParsedVariable::try_get(&parsed_variables, "cst") {
181 BranchUsing::Displacement(
182 variable.get_i32()? << {
183 if nop_count > 0 && input.fphead.is_some() {
184 1
185 } else {
186 2
187 }
188 },
189 )
190 } else if let Ok(variable) = ParsedVariable::try_get(&parsed_variables, "src") {
191 BranchUsing::Register(variable.get_register()?)
192 } else if let Ok(variable) = ParsedVariable::try_get(&parsed_variables, "op") {
193 let opcode = variable.get_u8()?;
194 match opcode {
195 0b110 => BranchUsing::Pointer(ControlRegister::IRP),
196 0b111 => BranchUsing::Pointer(ControlRegister::NRP),
197 _ => continue,
198 }
199 } else {
200 continue;
201 }
202 };
203 return Ok(Self {
204 side,
205 branch_using,
206 pce1_address: input.pce1_address,
207 nop_count,
208 instruction_data: InstructionData {
209 opcode: input.opcode,
210 compact: false,
211 conditional_operation,
212 p_bit,
213 ..Default::default()
214 },
215 });
216 }
217 Err(Error::new(
218 ErrorKind::InvalidInput,
219 "Not a branch instruction",
220 ))
221 }
222
223 fn new_compact(input: &super::InstructionInput) -> std::io::Result<Self> {
224 let Some(fphead) = &input.fphead else {
225 return Err(Error::new(ErrorKind::InvalidInput, "No fphead"));
226 };
227 if !fphead.decode_compact_branches {
228 return Err(Error::new(
229 ErrorKind::InvalidInput,
230 "Decoding compact branch instructions set to false (BR = 0)",
231 ));
232 }
233
234 let formats = [
235 (
236 "sbs7",
237 vec![
238 ParsingInstruction::Bit {
239 name: String::from("s"),
240 },
241 ParsingInstruction::Match {
242 size: 5,
243 value: 0x5,
244 },
245 ParsingInstruction::Signed {
246 size: 7,
247 name: String::from("cst"),
248 },
249 ParsingInstruction::Unsigned {
250 size: 3,
251 name: String::from("nop"),
252 },
253 ],
254 ),
255 (
256 "sbu8",
257 vec![
258 ParsingInstruction::Bit {
259 name: String::from("s"),
260 },
261 ParsingInstruction::Match {
262 size: 5,
263 value: 0x5,
264 },
265 ParsingInstruction::Unsigned {
266 size: 8,
267 name: String::from("cst"),
268 },
269 ParsingInstruction::Match {
270 size: 2,
271 value: 0b11,
272 },
273 ],
274 ),
275 (
276 "scs10",
277 vec![
278 ParsingInstruction::Bit {
279 name: String::from("s"),
280 },
281 ParsingInstruction::Match {
282 size: 5,
283 value: 0xD,
284 },
285 ParsingInstruction::Signed {
286 size: 10,
287 name: String::from("cst"),
288 },
289 ],
290 ),
291 (
292 "sbs7c",
293 vec![
294 ParsingInstruction::Bit {
295 name: String::from("s"),
296 },
297 ParsingInstruction::Match {
298 size: 3,
299 value: 0x5,
300 },
301 ParsingInstruction::Bit {
302 name: String::from("z"),
303 },
304 ParsingInstruction::Match { size: 1, value: 1 },
305 ParsingInstruction::Signed {
306 size: 7,
307 name: String::from("cst"),
308 },
309 ParsingInstruction::Unsigned {
310 size: 3,
311 name: String::from("nop"),
312 },
313 ],
314 ),
315 (
316 "sbu8c",
317 vec![
318 ParsingInstruction::Bit {
319 name: String::from("s"),
320 },
321 ParsingInstruction::Match {
322 size: 3,
323 value: 0x5,
324 },
325 ParsingInstruction::Bit {
326 name: String::from("z"),
327 },
328 ParsingInstruction::Match { size: 1, value: 1 },
329 ParsingInstruction::Unsigned {
330 size: 8,
331 name: String::from("cst"),
332 },
333 ParsingInstruction::Match {
334 size: 2,
335 value: 0b11,
336 },
337 ],
338 ),
339 (
340 "sx1b",
341 vec![
342 ParsingInstruction::Bit {
343 name: String::from("s"),
344 },
345 ParsingInstruction::Match {
346 size: 6,
347 value: 0x37,
348 },
349 ParsingInstruction::Unsigned {
350 size: 4,
351 name: String::from("src"),
352 },
353 ParsingInstruction::Match { size: 2, value: 0 },
354 ParsingInstruction::Unsigned {
355 size: 3,
356 name: String::from("nop"),
357 },
358 ],
359 ),
360 ];
361
362 for (name, format) in formats {
363 let Ok(parsed_variables) = parse(input.opcode, format.as_slice()) else {
364 continue;
365 };
366 let side = ParsedVariable::try_get(&parsed_variables, "s")?.get_bool()?;
367 let branch_using = {
368 if name == "sx1b" {
369 let num = ParsedVariable::try_get(&parsed_variables, "src")?.get_u8()?;
370 BranchUsing::Register(Register::B(num))
371 } else {
372 BranchUsing::Displacement(if name == "sbu8" || name == "sbu8c" {
373 (ParsedVariable::try_get(&parsed_variables, "cst")?.get_u8()? as i32) << 1
374 } else {
375 ParsedVariable::try_get(&parsed_variables, "cst")?.get_i32()? << {
376 if name == "scs10" { 2 } else { 1 }
377 }
378 })
379 }
380 };
381 let nop_count = {
382 if name == "sbs7" || name == "sbs7c" || name == "sx1b" {
383 min(
384 ParsedVariable::try_get(&parsed_variables, "nop")?.get_u8()?,
385 5,
386 )
387 } else {
388 5
389 }
390 };
391 let conditional_operation = {
392 if name == "scs10" {
393 Some(ConditionalOperation::ReservedLow)
394 } else if name == "sbs7c" || name == "sbu8c" {
395 let z = ParsedVariable::try_get(&parsed_variables, "z")?.get_bool()?;
396 if z {
397 Some(ConditionalOperation::Zero(Register::from(0, side)))
398 } else {
399 Some(ConditionalOperation::NonZero(Register::from(0, side)))
400 }
401 } else {
402 None
403 }
404 };
405 return Ok(Self {
406 instruction_data: InstructionData {
407 opcode: input.opcode,
408 compact: true,
409 conditional_operation,
410 ..Default::default()
411 },
412 branch_using,
413 side,
414 pce1_address: input.pce1_address,
415 nop_count,
416 });
417 }
418
419 Err(Error::new(
420 ErrorKind::InvalidInput,
421 "Not a branch instruction",
422 ))
423 }
424
425 fn instruction_clean(&self) -> String {
426 if let Some(co) = self.conditional_operation()
427 && co == ConditionalOperation::ReservedLow
428 {
429 String::from("CALLP")
430 } else {
431 if self.nop_count > 0 {
432 String::from("BNOP")
433 } else {
434 String::from("B")
435 }
436 }
437 }
438
439 fn instruction(&self) -> String {
440 let unit_num = if self.side { 2 } else { 1 };
441 let mut instruction = format!("{}.S{unit_num}", self.instruction_clean());
442 if let BranchUsing::Register(register) = self.branch_using
443 && register.side() != self.side
444 {
445 instruction += "X";
446 }
447 instruction
448 }
449
450 fn operands(&self) -> String {
451 let operands = match self.branch_using {
452 BranchUsing::Displacement(displacement) => {
453 let displacement_abs = displacement.unsigned_abs();
454 let address_result = self.calculate_displacement_address();
455 let Ok(branch_address) = self.calculate_displacement_address() else {
456 return address_result
457 .map_err(|e| format!("ERROR {e}"))
458 .unwrap_err();
459 };
460 format!(
461 "0x{branch_address:08X} (PCE1{}0x{displacement_abs:08X})",
462 if displacement.is_positive() { "+" } else { "-" }
463 )
464 }
465 BranchUsing::Register(register) => register.to_string(),
466 BranchUsing::Pointer(register) => register.to_string(),
467 };
468
469 if let Some(co) = self.conditional_operation()
470 && co == ConditionalOperation::ReservedLow
471 {
472 format!("{operands}, {}", Register::from(3, self.side).to_string())
473 } else if self.nop_count > 0 {
474 format!("{operands}, {}", self.nop_count)
475 } else {
476 operands
477 }
478 }
479
480 fn instruction_data(&self) -> &InstructionData {
481 &self.instruction_data
482 }
483
484 fn instruction_data_mut(&mut self) -> &mut InstructionData {
485 &mut self.instruction_data
486 }
487}