1use enum_tags::enum_tags;
4
5use crate::arch::{bitmask, LocalAddress, Word, LOCAL_ADDRESS_BITS};
6
7pub type RawOpCode = u8;
9
10pub type Immediate = u16;
12
13pub type ExtendedImmediate = u32;
15
16pub const OPCODE_BITS: usize = 8; pub const IMM_BITS: usize = 16;
22
23pub const IMM_EXT_BITS: usize = 24;
25
26#[rustfmt::skip]
27 mod encoding_spec {
28 use super::*;
29 use static_assertions::{const_assert, const_assert_eq};
30
31 macro_rules! bits {
32 ($T:ty) => {
33 (8 * std::mem::size_of::<$T>())
34 };
35 }
36
37const_assert_eq!(bits![Word], OPCODE_BITS + 3 * LOCAL_ADDRESS_BITS);
42const_assert!(OPCODE_BITS + 2 * LOCAL_ADDRESS_BITS <= bits![Word]);
44const_assert_eq!(bits![Word], OPCODE_BITS + LOCAL_ADDRESS_BITS + IMM_BITS);
46const_assert_eq!(bits![Word], OPCODE_BITS + IMM_EXT_BITS);
48const_assert!(OPCODE_BITS <= bits![Word]);
50}
52
53#[repr(u8)]
55#[enum_tags]
56#[derive(Clone, Copy)]
57pub enum Op {
58 Mov(LocalAddress, LocalAddress),
60 MovI(LocalAddress, Immediate),
62 Add(LocalAddress, LocalAddress, LocalAddress),
65 Call(ExtendedImmediate),
68 Ret,
71 Nop,
73}
74
75impl Op {
76 pub fn encode_packed(&self) -> Word {
78 let encoded_args = match *self {
79 Self::Mov(a, b) => Self::encode_packed_ab_args(a, b),
80 Self::MovI(a, i) => Self::encode_packed_ai_args(a, i),
81 Self::Add(a, b, c) => Self::encode_packed_abc_args(a, b, c),
82 Self::Call(ix) => Self::encode_packed_ix_args(ix),
83 Self::Ret | Self::Nop => 0,
84 };
85
86 (self.opcode() as Word) | (encoded_args << OPCODE_BITS)
87 }
88
89 pub fn decode_packed(word: Word) -> Option<Self> {
91 let opcode = (word & bitmask(OPCODE_BITS)) as RawOpCode;
92 let args = word >> OPCODE_BITS;
93 match opcode {
94 Self::MOV_TAG => Self::decode_packed_ab_args(args, Self::Mov),
95 Self::MOVI_TAG => Self::decode_packed_ai_args(args, Self::MovI),
96 Self::ADD_TAG => Self::decode_packed_abc_args(args, Self::Add),
97 Self::CALL_TAG => Self::decode_packed_ix_args(args, Self::Call),
98 Self::RET_TAG => Some(Self::Ret),
99 Self::NOP_TAG => Some(Self::Nop),
100 _ => None,
101 }
102 }
103
104 pub fn opcode(&self) -> RawOpCode {
107 unsafe { *<*const _>::from(self).cast::<RawOpCode>() }
108 }
109
110 fn encode_packed_ab_args(a: LocalAddress, b: LocalAddress) -> Word {
111 (a as Word) | ((b as Word) << LOCAL_ADDRESS_BITS)
112 }
113
114 fn decode_packed_ab_args(
115 args: Word,
116 f: impl FnOnce(LocalAddress, LocalAddress) -> Self,
117 ) -> Option<Self> {
118 let a = args & bitmask(LOCAL_ADDRESS_BITS);
119 let b = (args >> LOCAL_ADDRESS_BITS) & bitmask(LOCAL_ADDRESS_BITS);
120 Some(f(a as LocalAddress, b as LocalAddress))
121 }
122
123 fn encode_packed_abc_args(
124 a: LocalAddress,
125 b: LocalAddress,
126 c: LocalAddress,
127 ) -> Word {
128 (a as Word)
129 | ((b as Word) << LOCAL_ADDRESS_BITS)
130 | ((c as Word) << (2 * LOCAL_ADDRESS_BITS))
131 }
132 fn decode_packed_abc_args(
133 args: Word,
134 f: impl FnOnce(LocalAddress, LocalAddress, LocalAddress) -> Self,
135 ) -> Option<Self> {
136 let a = args & bitmask(LOCAL_ADDRESS_BITS);
137 let b = (args >> LOCAL_ADDRESS_BITS) & bitmask(LOCAL_ADDRESS_BITS);
138 let c =
139 (args >> (2 * LOCAL_ADDRESS_BITS)) & bitmask(LOCAL_ADDRESS_BITS);
140 Some(f(a as LocalAddress, b as LocalAddress, c as LocalAddress))
141 }
142
143 fn encode_packed_ai_args(a: LocalAddress, i: Immediate) -> Word {
144 (a as Word) | ((i as Word) << LOCAL_ADDRESS_BITS)
145 }
146
147 fn decode_packed_ai_args(
148 args: Word,
149 f: impl FnOnce(LocalAddress, Immediate) -> Self,
150 ) -> Option<Self> {
151 let a = args & bitmask(LOCAL_ADDRESS_BITS);
152 let i = (args >> LOCAL_ADDRESS_BITS) & bitmask(IMM_BITS);
153 Some(f(a as LocalAddress, i as Immediate))
154 }
155
156 fn encode_packed_ix_args(ix: ExtendedImmediate) -> Word {
157 ix as Word
158 }
159
160 fn decode_packed_ix_args(
161 args: Word,
162 f: impl FnOnce(ExtendedImmediate) -> Self,
163 ) -> Option<Self> {
164 let ix = args & bitmask(IMM_EXT_BITS);
165 Some(f(ix as ExtendedImmediate))
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use crate::{
172 arch::{Word, LOCAL_ADDRESS_BITS},
173 opcode::{Op, OPCODE_BITS},
174 };
175
176 #[test]
177 fn encodes_correctly() {
178 assert_eq!(0, Op::Mov(0, 0).encode_packed());
179 assert_eq!(1, Op::MovI(0, 0).encode_packed());
180 assert_eq!(
181 (1 << OPCODE_BITS) | (1 << (OPCODE_BITS + LOCAL_ADDRESS_BITS)),
182 Op::Mov(1, 1).encode_packed()
183 );
184 assert_eq!(Op::Ret.opcode() as Word, Op::Ret.encode_packed());
185 }
186}