1#![allow(clippy::module_name_repetitions)]
7
8use crate::exec::{ExecFunc, ExecInst};
9use std::{fmt::Display, ops::Deref, str::FromStr};
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14#[derive(PartialEq, Debug, Clone, Eq, Hash)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17pub enum Op {
18 Fail(String),
19 Acc,
20 Ix,
21 Cmp,
22 Ar,
23 Indirect(Box<Op>),
24 Addr(usize),
25 Literal(usize),
26 Gpr(usize),
27 MultiOp(Vec<Op>),
28 Null,
29}
30
31impl Op {
32 pub fn is_none(&self) -> bool {
33 matches!(self, Op::Null)
34 }
35
36 pub fn is_register(&self) -> bool {
37 matches!(self, Op::Acc | Op::Ix | Op::Ar | Op::Gpr(_))
38 }
39
40 pub fn is_read_write(&self) -> bool {
41 self.is_register()
42 || match self {
43 Op::Indirect(op) if op.is_read_write() => true,
44 _ => matches!(self, Op::Addr(_)),
45 }
46 }
47
48 pub fn is_usizeable(&self) -> bool {
49 self.is_read_write() || matches!(self, Op::Literal(_))
50 }
51
52 pub fn is_address(&self) -> bool {
53 matches!(self, Op::Addr(_) | Op::Indirect(_)) && self.is_read_write()
54 }
55}
56
57impl Display for Op {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 #[allow(clippy::enum_glob_use)]
60 use Op::*;
61
62 let s = match self {
63 Null => String::new(),
64 Acc => "ACC".into(),
65 Ix => "IX".into(),
66 Cmp => "CMP".into(),
67 Ar => "AR".into(),
68 Addr(x) => format!("{x}"),
69 Literal(x) => format!("#{x}"),
70 Indirect(op) => format!("({op})"),
71 Fail(x) => x.clone(),
72 Gpr(x) => format!("r{x}"),
73 MultiOp(v) => v
74 .iter()
75 .map(ToString::to_string)
76 .collect::<Vec<_>>()
77 .join(","),
78 };
79
80 f.write_str(&s)
81 }
82}
83
84fn get_literal(mut op: String) -> usize {
85 if op.starts_with('#') {
86 op.remove(0);
87
88 match op.chars().next().unwrap() {
89 'b' | 'B' => {
90 op.remove(0);
91 usize::from_str_radix(&op, 2).unwrap()
92 }
93 'x' | 'X' => {
94 op.remove(0);
95 usize::from_str_radix(&op, 16).unwrap()
96 }
97 'o' | 'O' => {
98 op.remove(0);
99 usize::from_str_radix(&op, 8).unwrap()
100 }
101 '0'..='9' => op.parse().unwrap(),
102 _ => unreachable!(),
103 }
104 } else {
105 panic!("Literal `{op}` is invalid")
106 }
107}
108
109fn get_reg_no(mut op: String) -> usize {
110 op = op.to_lowercase();
111 op.remove(0);
112
113 op.parse().unwrap()
115}
116
117impl<T: Deref<Target = str>> From<T> for Op {
118 fn from(inp: T) -> Self {
119 fn get_op(inp: &str) -> Op {
120 #[allow(clippy::enum_glob_use)]
121 use Op::*;
122
123 if inp.is_empty() {
124 Null
125 } else if let Ok(x) = inp.parse() {
126 Addr(x)
127 } else if inp.contains('#') {
128 Literal(get_literal(inp.into()))
129 } else if inp.to_lowercase().starts_with('r')
130 && inp.trim_start_matches('r').chars().all(char::is_numeric)
131 {
132 let x = get_reg_no(inp.into());
133
134 if x > 29 {
135 panic!("Only registers from r0 to r29 are allowed")
136 } else {
137 Gpr(x)
138 }
139 } else {
140 match inp.to_lowercase().as_str() {
141 "acc" => Acc,
142 "cmp" => Cmp,
143 "ix" => Ix,
144 _ => Fail(inp.into()),
145 }
146 }
147 }
148
149 if inp.contains(',') {
150 Op::MultiOp(inp.split(',').map(get_op).collect())
151 } else {
152 get_op(&inp)
153 }
154 }
155}
156
157pub trait InstSet: FromStr + Display
162where
163 <Self as FromStr>::Err: Display,
164{
165 fn as_func_ptr(&self) -> ExecFunc;
166 fn id(&self) -> u64;
167 fn from_id(_: u64) -> Result<Self, <Self as FromStr>::Err>;
168}
169
170#[macro_export]
174macro_rules! inst_set {
175 ($(#[$outer:meta])* $vis:vis $name:ident { $( $inst:ident => $func:expr,)+ }) => {
176 inst_set! { $(#[$outer])* $vis $name use std; { $( $inst => $func,)+ } }
177 };
178 ($(#[$outer:meta])* $vis:vis $name:ident $using:item { $( $inst:ident => $func:expr,)+ }) => {
179 $(#[$outer])*
180 #[repr(u64)]
181 #[derive(Clone, Copy)]
182 $vis enum $name {
183 $($inst,)+
184 }
185
186 $(#[$outer])*
187 impl std::str::FromStr for $name {
188 type Err = String;
189
190 fn from_str(s: &str) -> Result<Self, Self::Err> {
191 match s.to_uppercase().as_str() {
192 $( stringify!($inst) => Ok(Self::$inst),)+
193 _ => Err(format!("{s} is not an instruction")),
194 }
195 }
196 }
197
198 $(#[$outer])*
199 impl std::fmt::Display for $name {
200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
201 f.write_str(match self {
202 $(Self::$inst => stringify!($inst),)+
203 })
204 }
205 }
206
207 $(#[$outer])*
208 impl $crate::inst::InstSet for $name {
209 fn as_func_ptr(&self) -> $crate::exec::ExecFunc {
210 $using
211 match self {
212 $(Self::$inst => $func,)+
213 }
214 }
215
216 fn id(&self) -> u64 {
217 *self as u64
218 }
219
220 fn from_id(id: u64) -> Result<Self, String> {
221 match id {
222 $(x if x == Self::$inst as u64 => Ok(Self::$inst),)+
223 _ => Err(format!("0x{:X} is not a valid instruction ID", id)),
224 }
225 }
226 }
227 };
228}
229
230#[macro_export]
236macro_rules! extend {
237 ($(#[$outer:meta])* $vis:vis $name:ident extends $parent:ident { $( $inst:ident => $func:expr,)+ }) => {
238 extend! { $(#[$outer])* $vis $name extends $parent use std; { $( $inst => $func,)+ } }
239 };
240 ($(#[$outer:meta])* $vis:vis $name:ident extends $parent:ident $using:item { $( $inst:ident => $func:expr,)+ }) => {
241 $(#[$outer])*
242 $vis struct $name {
243 __private: extend_priv::Combined,
244 }
245
246 $(#[$outer])*
247 pub(crate) mod extend_priv {
248 use $crate::inst::InstSet;
249 use super::$parent;
250 #[repr(u64)]
251 #[derive(Clone, Copy)]
252 pub enum $name {
253 $($inst,)+
254 #[allow(non_camel_case_types)]
255 LAST_INST_MARKER,
256 }
257
258 impl std::str::FromStr for $name {
259 type Err = String;
260
261 fn from_str(s: &str) -> Result<Self, Self::Err> {
262 match s.to_uppercase().as_str() {
263 $( stringify!($inst) => Ok(Self::$inst),)+
264 _ => Err(String::new()),
265 }
266 }
267 }
268
269 impl $name {
270 fn id(self) -> u64 {
271 self as u64
272 }
273
274 fn as_func_ptr(&self) -> $crate::exec::ExecFunc {
275 $using
276 match self {
277 $(Self::$inst => $func,)+
278 Self::LAST_INST_MARKER => panic!("This should never happen, report this as a bug"),
279 }
280 }
281
282 fn from_id(id: u64) -> Result<Self, String> {
283 match id {
284 $(x if x == Self::$inst as u64 => Ok(Self::$inst),)+
285 _ => Err(format!("0x{id:X} is not a valid instruction ID")),
286 }
287 }
288 }
289
290 impl std::fmt::Display for $name {
291 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
292 match self {
293 $(Self::$inst => f.write_str(stringify!($inst)),)+
294 Self::LAST_INST_MARKER => panic!("This should never happen, report this as a bug"),
295 }
296 }
297 }
298
299 pub enum Combined {
300 Extension($name),
301 Parent($parent),
302 }
303
304 impl Combined {
305 const LAST_INST_MARKER: u64 = $name::LAST_INST_MARKER as u64;
306
307 pub fn id(&self) -> u64 {
308 match self {
309 Self::Extension(ext) => ext.id(),
310 Self::Parent(parent) => Self::LAST_INST_MARKER + parent.id()
311 }
312 }
313
314 pub fn from_id(id: u64) -> Result<Self, String> {
315 if id >= $name::LAST_INST_MARKER as u64 {
316 Ok(Combined::Parent($parent::from_id(id - Self::LAST_INST_MARKER)?))
317 } else {
318 Ok(Combined::Extension($name::from_id(id)?))
319 }
320 }
321
322 pub fn as_func_ptr(&self) -> $crate::exec::ExecFunc {
323 match self {
324 Self::Extension(e) => e.as_func_ptr(),
325 Self::Parent(p) => p.as_func_ptr(),
326 }
327 }
328 }
329
330 impl std::str::FromStr for Combined {
331 type Err = String;
332
333 fn from_str(s: &str) -> Result<Self, Self::Err> {
334 if let Ok(res) = s.parse::<$name>() {
335 Ok(Combined::Extension(res))
336 } else if let Ok(res) = s.parse::<$parent>() {
337 Ok(Combined::Parent(res))
338 } else {
339 Err(format!("{s} is not an instruction"))
340 }
341 }
342 }
343
344 impl std::fmt::Display for Combined {
345 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
346 match self {
347 Self::Extension(e) => write!(f, "{e}"),
348 Self::Parent(p) => write!(f, "{p}"),
349 }
350 }
351 }
352 }
353
354 $(#[$outer])*
355 impl std::str::FromStr for $name {
356 type Err = String;
357
358 fn from_str(s: &str) -> Result<Self, Self::Err> {
359 Ok($name { __private: s.to_uppercase().as_str().parse::<extend_priv::Combined>()? })
360 }
361 }
362
363 $(#[$outer])*
364 impl std::fmt::Display for $name {
365 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
366 write!(f, "{}", self.__private)
367 }
368 }
369
370 $(#[$outer])*
371 impl $crate::inst::InstSet for $name {
372 fn as_func_ptr(&self) -> $crate::exec::ExecFunc {
373 self.__private.as_func_ptr()
374 }
375
376 fn id(&self) -> u64 {
377 self.__private.id()
378 }
379
380 fn from_id(id: u64) -> Result<Self, String> {
381 Ok( Self { __private: extend_priv::Combined::from_id(id)? })
382 }
383 }
384 };
385}
386
387pub struct Inst<T>
389where
390 T: InstSet,
391 <T as FromStr>::Err: Display,
392{
393 pub id: u64,
394 pub inst: T,
395 pub op: Op,
396}
397
398impl<T> Inst<T>
399where
400 T: InstSet,
401 <T as FromStr>::Err: Display,
402{
403 pub fn new(inst: T, op: Op) -> Self {
404 Self {
405 id: inst.id(),
406 op,
407 inst,
408 }
409 }
410
411 pub fn to_exec_inst(self) -> ExecInst {
412 ExecInst::new(self.id, self.inst.as_func_ptr(), self.op)
413 }
414}