Skip to main content

c6000_disassembler/instruction/
fphead.rs

1use std::io::{Error, ErrorKind, Result};
2
3use crate::instruction::{
4    C6000Instruction, DataSize, InstructionData,
5    parser::{ParsedVariable, ParsingInstruction, parse},
6};
7
8#[derive(Clone)]
9pub struct CompactInstructionHeader {
10    instruction_data: InstructionData,
11    /// Layout field
12    /// Determines if the i-th word holds two compact (16-bit) instructions (true)
13    /// or a regular, 32-bit instruction (false).
14    pub layout: [bool; 7],
15    /// PROT field.
16    /// Determines if 4 ``NOP`` cycles are added after every LD instruction.
17    pub loads_protected: bool,
18    /// RS field.
19    /// Determines if instructions use high register set for data source
20    /// and destination (true) or low register set (false).
21    pub register_set: bool,
22    pub primary_data_size: DataSize,
23    pub secondary_data_size: DataSize,
24    /// BR field.
25    /// Determines if compact instructions in the S unit are decoded
26    /// as branches.
27    pub decode_compact_branches: bool,
28    /// SAT field.
29    /// Determines if instructions are saturated.
30    ///
31    /// As a result, ``ADD``, ``SUB``, ``SHL``, ``MPY``, ``MPYH``, ``MPYLH`` and ``MPYHL``
32    /// instructions are decoded as ``SADD``, ``SUBS``, ``SSHL``, ``SMPY``, ``SMPYH``, ``SMPYLH`` and
33    /// ``SMPYHL`` respectively.
34    pub saturate: bool,
35    pub compact_p_bits: [bool; 14],
36}
37
38impl C6000Instruction for CompactInstructionHeader {
39    fn new(input: &super::InstructionInput) -> Result<Self> {
40        let format = [
41            ParsingInstruction::BitArray {
42                size: 14,
43                name: String::from("p"),
44            },
45            ParsingInstruction::Bit {
46                name: String::from("SAT"),
47            },
48            ParsingInstruction::Bit {
49                name: String::from("BR"),
50            },
51            ParsingInstruction::Unsigned {
52                size: 2,
53                name: String::from("DSZ_1"),
54            },
55            ParsingInstruction::Bit {
56                name: String::from("DSZ_2"),
57            },
58            ParsingInstruction::Bit {
59                name: String::from("RS"),
60            },
61            ParsingInstruction::Bit {
62                name: String::from("PROT"),
63            },
64            ParsingInstruction::BitArray {
65                size: 7,
66                name: String::from("layout"),
67            },
68            ParsingInstruction::Match {
69                size: 4,
70                value: 0b1110,
71            },
72        ];
73        let parsed_variables = parse(input.opcode, &format).map_err(|e| {
74            Error::new(
75                ErrorKind::InvalidInput,
76                format!("Not a compact instruction header: {e}"),
77            )
78        })?;
79
80        let layout = {
81            let layout_vec =
82                ParsedVariable::try_get(&parsed_variables, "layout")?.get_bool_vec()?;
83            let Some(layout_ref) = layout_vec.first_chunk::<7>() else {
84                return Err(Error::other("Layout doesn't have 7 elements"));
85            };
86            *layout_ref
87        };
88        let compact_p_bits = {
89            let layout_vec = ParsedVariable::try_get(&parsed_variables, "p")?.get_bool_vec()?;
90            let Some(layout_ref) = layout_vec.first_chunk::<14>() else {
91                return Err(Error::other("P-bits don't have 14 elements"));
92            };
93            *layout_ref
94        };
95        let loads_protected = ParsedVariable::try_get(&parsed_variables, "PROT")?.get_bool()?;
96        let register_set = ParsedVariable::try_get(&parsed_variables, "RS")?.get_bool()?;
97        let data_sizes_1 = ParsedVariable::try_get(&parsed_variables, "DSZ_1")?.get_u8()?;
98        let data_sizes_2 = ParsedVariable::try_get(&parsed_variables, "DSZ_2")?.get_bool()?;
99        let primary_data_size = {
100            if data_sizes_2 == true {
101                DataSize::DoubleWord
102            } else {
103                DataSize::Word
104            }
105        };
106        let secondary_data_size = {
107            if primary_data_size == DataSize::DoubleWord {
108                match data_sizes_1 {
109                    0 => DataSize::Word,
110                    1 => DataSize::Byte,
111                    2 => DataSize::NonAlignedWord,
112                    3 => DataSize::HalfWord,
113                    _ => DataSize::Word,
114                }
115            } else {
116                match data_sizes_1 {
117                    0 => DataSize::ByteUnsigned,
118                    1 => DataSize::Byte,
119                    2 => DataSize::HalfWordUnsigned,
120                    3 => DataSize::HalfWord,
121                    _ => DataSize::ByteUnsigned,
122                }
123            }
124        };
125        let decode_compact_branches =
126            ParsedVariable::try_get(&parsed_variables, "BR")?.get_bool()?;
127        let saturate = ParsedVariable::try_get(&parsed_variables, "SAT")?.get_bool()?;
128        Ok(Self {
129            instruction_data: InstructionData {
130                opcode: input.opcode,
131                ..Default::default()
132            },
133            layout,
134            compact_p_bits,
135            loads_protected,
136            register_set,
137            primary_data_size,
138            secondary_data_size,
139            decode_compact_branches,
140            saturate,
141        })
142    }
143
144    fn instruction(&self) -> String {
145        String::from(".fphead")
146    }
147    fn operands(&self) -> String {
148        let mut return_str = String::new();
149        if self.loads_protected {
150            return_str += "p";
151        } else {
152            return_str += "n";
153        }
154        return_str += ", ";
155        if self.register_set {
156            return_str += "h";
157        } else {
158            return_str += "l";
159        }
160        return_str += ", ";
161        return_str += (self.primary_data_size.to_short_string() + ", ").as_str();
162        return_str += (self.secondary_data_size.to_short_string() + ", ").as_str();
163        if self.decode_compact_branches {
164            return_str += "br";
165        } else {
166            return_str += "nobr";
167        }
168        return_str += ", ";
169        if self.saturate {
170            return_str += "sat";
171        } else {
172            return_str += "nosat";
173        }
174        return_str += ", ";
175        for i in (0..7).rev() {
176            if self.layout[i] {
177                return_str += "1";
178            } else {
179                return_str += "0";
180            }
181        }
182        return_str
183    }
184    fn instruction_data(&self) -> &InstructionData {
185        &self.instruction_data
186    }
187    fn instruction_data_mut(&mut self) -> &mut InstructionData {
188        &mut self.instruction_data
189    }
190}