1use crate::op_params::ID::{Dec, Inc};
2use crate::op_params::PP::{Post, Pre};
3use crate::LangError;
4use crate::LangError::InvalidRegisterArgCode;
5
6pub const MASK: u8 = 0xF0;
7
8pub const REGISTER: u8 = 0b00000000;
9pub const POST_INC: u8 = 0b01000000;
13pub const POST_DEC: u8 = 0b01010000;
14pub const PRE_INC: u8 = 0b01100000;
15pub const PRE_DEC: u8 = 0b01110000;
16pub const INDIRECT: u8 = 0b10000000;
17pub const IND_OFFSET_REG: u8 = 0b10010000;
18pub const IND_OFFSET_EXT_REG: u8 = 0b10100000;
19pub const IND_OFFSET_NUM: u8 = 0b10110000;
20pub const IND_POST_INC: u8 = 0b11000000;
21pub const IND_POST_DEC: u8 = 0b11010000;
22pub const IND_PRE_INC: u8 = 0b11100000;
23pub const IND_PRE_DEC: u8 = 0b11110000;
24
25#[derive(Debug, Copy, Clone, Eq, PartialEq)]
26pub enum PP {
27 Pre,
28 Post,
29}
30
31#[derive(Debug, Copy, Clone, Eq, PartialEq)]
32pub enum ID {
33 Inc,
34 Dec,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Default)]
38pub struct RegisterPPID {
39 pub is_indirect: bool,
40 pub is_offset_reg: bool,
41 pub is_offset_ext_reg: bool,
42 pub is_offset_num: bool,
43 pub ppid: Option<(PP, ID)>,
44}
45
46impl RegisterPPID {
47 pub fn new(
48 is_indirect: bool,
49 is_offset_reg: bool,
50 is_offset_num: bool,
51 is_offset_ext_reg: bool,
52 ppid: Option<(PP, ID)>,
53 ) -> Self {
54 Self {
55 is_indirect,
56 is_offset_reg,
57 is_offset_num,
58 is_offset_ext_reg,
59 ppid,
60 }
61 }
62}
63
64impl TryFrom<u8> for RegisterPPID {
65 type Error = LangError;
66
67 fn try_from(value: u8) -> Result<Self, LangError> {
68 let ppid = match value & MASK {
69 IND_PRE_DEC => RegisterPPID::new(true, false, false, false, Some((Pre, Dec))),
70 IND_POST_DEC => RegisterPPID::new(true, false, false, false, Some((Post, Dec))),
71 IND_PRE_INC => RegisterPPID::new(true, false, false, false, Some((Pre, Inc))),
72 IND_POST_INC => RegisterPPID::new(true, false, false, false, Some((Post, Inc))),
73 INDIRECT => RegisterPPID::new(true, false, false, false, None),
74 PRE_DEC => RegisterPPID::new(false, false, false, false, Some((Pre, Dec))),
75 POST_DEC => RegisterPPID::new(false, false, false, false, Some((Post, Dec))),
76 PRE_INC => RegisterPPID::new(false, false, false, false, Some((Pre, Inc))),
77 POST_INC => RegisterPPID::new(false, false, false, false, Some((Post, Inc))),
78 REGISTER => RegisterPPID::new(false, false, false, false, None),
79 IND_OFFSET_REG => RegisterPPID::new(true, true, false, false, None),
80 IND_OFFSET_EXT_REG => RegisterPPID::new(true, false, false, true, None),
81 IND_OFFSET_NUM => RegisterPPID::new(true, false, true, false, None),
82 _ => return Err(InvalidRegisterArgCode(value)),
83 };
84 Ok(ppid)
85 }
86}
87
88impl From<RegisterPPID> for u8 {
89 fn from(arg: RegisterPPID) -> Self {
90 let mut byte = 0;
91
92 if arg.is_offset_reg {
93 return IND_OFFSET_REG;
94 } else if arg.is_offset_ext_reg {
95 return IND_OFFSET_EXT_REG;
96 } else if arg.is_offset_num {
97 return IND_OFFSET_NUM;
98 } else if arg.is_indirect {
99 byte |= INDIRECT;
100 }
101 if let Some(ppid) = arg.ppid {
102 match (ppid.0, ppid.1) {
103 (Pre, Inc) => byte |= PRE_INC,
104 (Post, Inc) => byte |= POST_INC,
105 (Pre, Dec) => byte |= PRE_DEC,
106 (Post, Dec) => byte |= POST_DEC,
107 }
108 }
109
110 byte
111 }
112}
113
114#[cfg(test)]
115mod test {
116 use super::*;
117
118 #[test]
119 fn check_alignment() {
120 let values = vec![
121 REGISTER,
122 POST_INC,
123 POST_DEC,
124 PRE_INC,
125 PRE_DEC,
126 INDIRECT,
127 IND_POST_INC,
128 IND_POST_DEC,
129 IND_PRE_INC,
130 IND_PRE_DEC,
131 IND_OFFSET_REG,
132 IND_OFFSET_EXT_REG,
133 IND_OFFSET_NUM,
134 ];
135 for value in values {
136 let ppid: RegisterPPID = value.try_into().unwrap();
137 let byte: u8 = ppid.into();
138 assert_eq!(value, byte, "{}", value);
139 }
140 }
141}