osiris_process/operation/
scheme.rs

1use std::fmt::{Display, Formatter};
2use std::hash::{Hash, Hasher};
3
4use osiris_data::data::identification::Identifier;
5
6use crate::register::{RegisterId, RegisterRange};
7use crate::operation::error::{OperationError, OperationResult};
8
9/// Identifies a [crate::operation::Operation] in a [crate::operation::OperationSet]. 
10#[derive(Copy, Clone, Debug, Eq, PartialEq)]
11pub struct OperationId(u16);
12
13impl OperationId {
14    pub const fn new(raw: u16) -> Self { Self(raw) }
15    pub const fn to_u16(&self) -> u16 { self.0 }
16}
17
18impl Hash for OperationId {
19    fn hash<H: Hasher>(&self, state: &mut H) {
20        state.write_usize(self.to_usize());
21    }
22}
23
24impl Identifier for OperationId {
25    fn to_usize(&self) -> usize { self.0 as usize }
26}
27
28#[derive(Copy, Clone, Debug, Eq, PartialEq)]
29pub enum ArgumentType {
30    NoArgument,
31    Range,
32    OneU32,
33    TwoU16,
34    FourU8,
35}
36
37impl ArgumentType {
38    pub fn to_asm_template(&self) -> String {
39        match self {
40            ArgumentType::NoArgument => String::new(),
41            ArgumentType::Range => "[{start}, {end}]".to_string(),
42            ArgumentType::OneU32 => "{argument}".to_string(),
43            ArgumentType::TwoU16 => "{first}, {second}".to_string(),
44            ArgumentType::FourU8 => "{first}, {second}, {third}, {fourth}".to_string(),
45        }
46    }
47}
48
49#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
50pub enum ArgumentValue {
51    OneU32(u32),
52    TwoU16(u16, u16),
53    FourU8(u8, u8, u8, u8),
54}
55
56impl ArgumentValue {
57    pub fn to_u32(&self) -> u32 {
58        match self {
59            ArgumentValue::OneU32(v) => *v,
60            ArgumentValue::TwoU16(t, b) => (*t as u32) << 8 | *b as u32,
61            ArgumentValue::FourU8(a, b, c, d) => (*a as u32) << 24 | (*b as u32) << 16 | (*c as u32) << 8 | *d as u32,
62        }
63    }
64}
65
66impl Display for ArgumentValue {
67    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
68        write!(f, "{}", match self {
69            ArgumentValue::OneU32(a) => format!("{:08x}", a),
70            ArgumentValue::TwoU16(a, b) => format!("{:04x}:{:04x}", a, b),
71            ArgumentValue::FourU8(a, b, c, d) => format!("{:02x}:{:02x}:{:02x}:{:02x}", a, b, c, d),
72        })
73    }
74}
75
76#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
77pub enum ArgumentScheme {
78    NoArgument,
79    Range(RegisterRange),
80    Value(ArgumentValue),
81}
82
83impl ArgumentScheme {
84    pub fn from_type(arg_type: ArgumentType, data: u32) -> ArgumentScheme {
85        match arg_type {
86            ArgumentType::NoArgument => ArgumentScheme::NoArgument,
87            ArgumentType::Range => ArgumentScheme::Range(RegisterRange::from_u32(data)),
88            ArgumentType::OneU32 => ArgumentScheme::Value(ArgumentValue::OneU32(data)),
89            ArgumentType::TwoU16 => ArgumentScheme::Value(ArgumentValue::TwoU16((data >> 16) as u16, data as u16)),
90            ArgumentType::FourU8 => ArgumentScheme::Value(ArgumentValue::FourU8((data >> 24) as u8, (data >> 16) as u8, (data >> 8) as u8, data as u8)),
91        }
92    }
93
94    pub fn get_type(&self) -> ArgumentType {
95        match self {
96            ArgumentScheme::NoArgument => ArgumentType::NoArgument,
97            ArgumentScheme::Value(a) => match a {
98                ArgumentValue::OneU32(_) => ArgumentType::OneU32,
99                ArgumentValue::TwoU16(_, _) => ArgumentType::TwoU16,
100                ArgumentValue::FourU8(_, _, _, _) => ArgumentType::FourU8,
101            },
102            ArgumentScheme::Range(_) => ArgumentType::Range,
103        }
104    }
105
106    pub fn to_u32(&self) -> u32 {
107        match self {
108            ArgumentScheme::NoArgument => 0,
109            ArgumentScheme::Value(a) => a.to_u32(),
110            ArgumentScheme::Range(range) => {
111                let start = range.start.to_u16() as u32;
112                let end = range.end.to_u16() as u32;
113                (start << 16) | end
114            }
115        }
116    }
117
118    pub fn to_asm(&self) -> String {
119        match self {
120            ArgumentScheme::NoArgument => String::new(),
121            ArgumentScheme::Value(value) => value.to_string(),
122            ArgumentScheme::Range(range) => range.to_string(),
123        }
124    }
125
126    /// Can return an [OperationError::InvalidArgumentType].
127    pub fn get_no_argument(&self) -> OperationResult<()> {
128        match self {
129            ArgumentScheme::NoArgument => { Ok(()) }
130            ArgumentScheme::Value(_) => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::NoArgument, provided: self.get_type() }) }
131            ArgumentScheme::Range(_) => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::NoArgument, provided: ArgumentType::Range }) }
132        }
133    }
134
135    /// Can return an [OperationError::InvalidArgumentType].
136    pub fn get_value(&self) -> OperationResult<u32> {
137        match self {
138            ArgumentScheme::NoArgument => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::OneU32, provided: ArgumentType::NoArgument }) }
139            ArgumentScheme::Value(v) => { Ok(v.to_u32()) }
140            ArgumentScheme::Range(_) => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::OneU32, provided: ArgumentType::Range }) }
141        }
142    }
143
144    /// Can return an [OperationError::InvalidArgumentType].
145    pub fn get_range(&self) -> OperationResult<RegisterRange> {
146        match self {
147            ArgumentScheme::NoArgument => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::Range, provided: ArgumentType::NoArgument }) }
148            ArgumentScheme::Value(_) => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::Range, provided: ArgumentType::OneU32 }) }
149            ArgumentScheme::Range(r) => { Ok(*r) }
150        }
151    }
152
153    /// Can return an [OperationError::InvalidArgumentType].
154    pub fn get_one_u32(&self) -> OperationResult<u32> {
155        match self {
156            ArgumentScheme::NoArgument => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::OneU32, provided: ArgumentType::NoArgument }) }
157            ArgumentScheme::Value(v) => {
158                match v {
159                    ArgumentValue::OneU32(v) => Ok(*v),
160                    ArgumentValue::TwoU16(_, _) => Err(OperationError::InvalidArgumentType { expected: ArgumentType::OneU32, provided: ArgumentType::TwoU16 }),
161                    ArgumentValue::FourU8(_, _, _, _) => Err(OperationError::InvalidArgumentType { expected: ArgumentType::OneU32, provided: ArgumentType::FourU8 }),
162                }
163            }
164            ArgumentScheme::Range(_) => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::OneU32, provided: ArgumentType::Range }) }
165        }
166    }
167
168    /// Can return an [OperationError::InvalidArgumentType].
169    pub fn get_two_u16(&self) -> OperationResult<(u16, u16)> {
170        match self {
171            ArgumentScheme::NoArgument => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::TwoU16, provided: ArgumentType::NoArgument }) }
172            ArgumentScheme::Value(v) => {
173                match v {
174                    ArgumentValue::OneU32(_) => Err(OperationError::InvalidArgumentType { expected: ArgumentType::TwoU16, provided: ArgumentType::OneU32 }),
175                    ArgumentValue::TwoU16(a, b) => Ok((*a, *b)),
176                    ArgumentValue::FourU8(_, _, _, _) => Err(OperationError::InvalidArgumentType { expected: ArgumentType::TwoU16, provided: ArgumentType::FourU8 }),
177                }
178            }
179            ArgumentScheme::Range(_) => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::TwoU16, provided: ArgumentType::Range }) }
180        }
181    }
182
183    /// Can return an [OperationError::InvalidArgumentType].
184    pub fn get_four_u8(&self) -> OperationResult<(u8, u8, u8, u8)> {
185        match self {
186            ArgumentScheme::NoArgument => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::FourU8, provided: ArgumentType::NoArgument }) }
187            ArgumentScheme::Value(v) => {
188                match v {
189                    ArgumentValue::OneU32(_) => Err(OperationError::InvalidArgumentType { expected: ArgumentType::FourU8, provided: ArgumentType::OneU32 }),
190                    ArgumentValue::TwoU16(_, _) => Err(OperationError::InvalidArgumentType { expected: ArgumentType::FourU8, provided: ArgumentType::TwoU16 }),
191                    ArgumentValue::FourU8(a, b, c, d) => Ok((*a, *b, *c, *d)),
192                }
193            }
194            ArgumentScheme::Range(_) => { Err(OperationError::InvalidArgumentType { expected: ArgumentType::FourU8, provided: ArgumentType::Range }) }
195        }
196    }
197}
198
199#[derive(Copy, Clone, Debug, Eq, PartialEq)]
200pub struct InstructionScheme {
201    pub identifier: OperationId,
202    pub target: RegisterId,
203    pub argument: ArgumentScheme,
204}
205
206impl InstructionScheme {
207    pub fn to_u64(&self) -> u64 {
208        (self.identifier.to_u16() as u64) << 48
209            | (self.target.to_u16() as u64) << 32
210            | self.argument.to_u32() as u64
211    }
212}