1use std::collections::HashMap;
2
3use serde::Deserialize;
4
5#[derive(Debug, Deserialize)]
6pub struct RawRegisterGroup {
7 pub length: u8,
8 pub registers: Vec<String>,
9}
10
11#[derive(Debug, Deserialize)]
12#[serde(tag = "type")]
13pub enum RawArgumentDefinition {
14 #[serde(rename = "register")]
15 Register { group: String },
16 #[serde(rename = "register_address")]
17 RegisterAddress { group: String },
18 #[serde(rename = "data_address")]
19 DataAddress { bits: u8 },
20 #[serde(rename = "text_address")]
21 TextAddress { bits: u8 },
22 #[serde(rename = "padding")]
23 Padding { bits: u8 },
24 #[serde(rename = "immediate")]
25 Immediate { bits: u8 },
26}
27
28#[derive(Debug, Deserialize)]
29pub struct RawCommandDefinition {
30 pub mnemonic: String,
31 pub opcode: u8,
32 #[serde(default)]
33 pub arguments: Vec<RawArgumentDefinition>,
34}
35
36#[derive(Debug, Deserialize)]
37pub struct RawDefinition {
38 pub opcode_length: u8,
39 pub opcode_offset: u8,
40 pub text_byte_length: u8,
41 pub data_byte_length: u8,
42 pub text_address_size: u8,
43 pub data_address_size: u8,
44 pub register_groups: HashMap<String, RawRegisterGroup>,
45 pub commands: Vec<RawCommandDefinition>,
46}
47
48impl RawDefinition {
49 pub fn from_str(s: &str) -> Result<Self, serde_yaml::Error> {
50 serde_yaml::from_str(s)
51 }
52}
53
54#[derive(Debug, Clone)]
55pub struct RegisterGroup {
56 pub length: u8,
57 pub registers: Vec<String>,
58}
59
60impl From<RawRegisterGroup> for RegisterGroup {
61 fn from(raw: RawRegisterGroup) -> Self {
62 RegisterGroup {
63 length: raw.length,
64 registers: raw.registers,
65 }
66 }
67}
68
69#[derive(Debug)]
70pub enum ArgumentDefinition {
71 Register { group: RegisterGroup },
72 RegisterAddress { group: RegisterGroup },
73 DataAddress { bits: u8 },
74 TextAddress { bits: u8 },
75 Padding { bits: u8 },
76 Immediate { bits: u8 },
77}
78
79impl ArgumentDefinition {
80 pub fn size(&self) -> u8 {
81 match self {
82 ArgumentDefinition::Register { group } => group.length,
83 ArgumentDefinition::RegisterAddress { group } => group.length,
84 ArgumentDefinition::DataAddress { bits } => *bits,
85 ArgumentDefinition::TextAddress { bits } => *bits,
86 ArgumentDefinition::Padding { bits } => *bits,
87 ArgumentDefinition::Immediate { bits } => *bits,
88 }
89 }
90}
91
92impl TryFrom<(RawArgumentDefinition, HashMap<String, RegisterGroup>)> for ArgumentDefinition {
93 type Error = &'static str;
94
95 fn try_from(
96 raw: (RawArgumentDefinition, HashMap<String, RegisterGroup>),
97 ) -> Result<Self, Self::Error> {
98 match raw {
99 (RawArgumentDefinition::Register { group }, groups) => match groups.get(&group) {
100 Some(g) => Ok(ArgumentDefinition::Register { group: g.clone() }),
101 None => Err("Register group not found"),
102 },
103 (RawArgumentDefinition::RegisterAddress { group }, groups) => {
104 match groups.get(&group) {
105 Some(g) => Ok(ArgumentDefinition::RegisterAddress { group: g.clone() }),
106 None => Err("Register group not found"),
107 }
108 }
109 (RawArgumentDefinition::DataAddress { bits }, _) => {
110 Ok(ArgumentDefinition::DataAddress { bits })
111 }
112 (RawArgumentDefinition::TextAddress { bits }, _) => {
113 Ok(ArgumentDefinition::TextAddress { bits })
114 }
115 (RawArgumentDefinition::Padding { bits }, _) => {
116 Ok(ArgumentDefinition::Padding { bits })
117 }
118 (RawArgumentDefinition::Immediate { bits }, _) => {
119 Ok(ArgumentDefinition::Immediate { bits })
120 }
121 }
122 }
123}
124
125#[derive(Debug)]
126pub struct CommandDefinition {
127 pub mnemonic: String,
128 pub opcode: u8,
129 pub arguments: Vec<ArgumentDefinition>,
130}
131
132impl TryFrom<(RawCommandDefinition, HashMap<String, RegisterGroup>)> for CommandDefinition {
133 type Error = &'static str;
134
135 fn try_from(
136 raw: (RawCommandDefinition, HashMap<String, RegisterGroup>),
137 ) -> Result<Self, Self::Error> {
138 let (raw, groups) = raw;
139 let arguments = raw
140 .arguments
141 .into_iter()
142 .map(|a| ArgumentDefinition::try_from((a, groups.clone())))
143 .collect::<Result<Vec<ArgumentDefinition>, Self::Error>>()?;
144
145 Ok(CommandDefinition {
146 mnemonic: raw.mnemonic,
147 opcode: raw.opcode,
148 arguments,
149 })
150 }
151}
152
153impl CommandDefinition {
154 pub fn arguments_size(&self) -> u8 {
155 self.arguments.iter().map(|a| a.size()).sum()
156 }
157}
158
159#[derive(Debug)]
160pub struct Definition {
161 pub opcode_length: u8,
162 pub opcode_offset: u8,
163 pub text_byte_length: u8,
164 pub data_byte_length: u8,
165 pub address_size: u8,
166 pub register_groups: HashMap<String, RegisterGroup>,
167 pub commands: Vec<CommandDefinition>,
168}
169
170impl TryFrom<RawDefinition> for Definition {
171 type Error = String;
172
173 fn try_from(raw: RawDefinition) -> Result<Self, Self::Error> {
174 let register_groups: HashMap<String, RegisterGroup> = raw
175 .register_groups
176 .into_iter()
177 .map(|(k, v)| (k, RegisterGroup::from(v)))
178 .collect();
179
180 if raw.text_address_size != raw.data_address_size {
181 return Err("Differing text and data address sizes are not supported".to_string());
182 }
183
184 let definition = Definition {
185 opcode_length: raw.opcode_length,
186 opcode_offset: raw.opcode_offset,
187 text_byte_length: raw.text_byte_length,
188 data_byte_length: raw.data_byte_length,
189 address_size: raw.text_address_size,
190 register_groups: register_groups.clone(),
191 commands: raw
192 .commands
193 .into_iter()
194 .map(|c| CommandDefinition::try_from((c, register_groups.clone())))
195 .collect::<Result<Vec<CommandDefinition>, &'static str>>()?,
196 };
197
198 for command in &definition.commands {
200 for argument in &command.arguments {
201 match argument {
202 ArgumentDefinition::DataAddress { bits } => {
203 if *bits != definition.address_size {
204 return Err("Data address size mismatch".to_string());
205 }
206 }
207 ArgumentDefinition::TextAddress { bits } => {
208 if *bits != definition.address_size {
209 return Err("Text address size mismatch".to_string());
210 }
211 }
212 _ => {}
213 }
214 }
215 }
216
217 let mut opcodes = HashMap::new();
219 for command in &definition.commands {
220 if opcodes.contains_key(&command.opcode) {
221 return Err(format!(
222 "Duplicate opcode: {}, both for {} and {}",
223 command.opcode, opcodes[&command.opcode], command.mnemonic
224 ));
225 }
226 opcodes.insert(command.opcode, &command.mnemonic);
227 }
228
229 for command in &definition.commands {
231 if (definition.opcode_length + command.arguments_size()) % definition.text_byte_length
232 != 0
233 {
234 return Err(format!(
235 "Command size not divisible by text byte length: {} ({} bits)",
236 command.mnemonic,
237 command.arguments_size() + definition.opcode_length
238 ));
239 }
240 }
241
242 Ok(definition)
243 }
244}
245
246impl TryFrom<String> for Definition {
247 type Error = String;
248
249 fn try_from(s: String) -> Result<Self, Self::Error> {
250 let raw = RawDefinition::from_str(&s).map_err(|_| "Failed to parse YAML")?;
251 Definition::try_from(raw)
252 }
253}