1use super::encode::DecodeError;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[repr(u8)]
9pub enum DeviceCode {
10 Cpu = 0x00,
11 LaneConstants = 0x0F,
12 AtomArrangement = 0x10,
13 QuantumGate = 0x11,
14 Measurement = 0x12,
15 Array = 0x13,
16 DetectorObservable = 0x14,
17}
18
19impl DeviceCode {
20 pub fn from_opcode(opcode: u32) -> Result<Self, DecodeError> {
22 let device_byte = (opcode & 0xFF) as u8;
23 Self::from_byte(device_byte)
24 }
25
26 pub fn from_byte(byte: u8) -> Result<Self, DecodeError> {
28 match byte {
29 0x00 => Ok(DeviceCode::Cpu),
30 0x0F => Ok(DeviceCode::LaneConstants),
31 0x10 => Ok(DeviceCode::AtomArrangement),
32 0x11 => Ok(DeviceCode::QuantumGate),
33 0x12 => Ok(DeviceCode::Measurement),
34 0x13 => Ok(DeviceCode::Array),
35 0x14 => Ok(DeviceCode::DetectorObservable),
36 _ => Err(DecodeError::UnknownDeviceCode(byte)),
37 }
38 }
39
40 pub fn code(&self) -> u8 {
42 *self as u8
43 }
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48#[repr(u8)]
49pub enum CpuInstCode {
50 ConstInt = 0x02,
51 ConstFloat = 0x03,
52 Dup = 0x04,
53 Pop = 0x05,
54 Swap = 0x06,
55 Return = 0x64,
56 Halt = 0xFF,
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61#[repr(u8)]
62pub enum LaneConstInstCode {
63 ConstLoc = 0x00,
64 ConstLane = 0x01,
65 ConstZone = 0x02,
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70#[repr(u8)]
71pub enum AtomArrangementInstCode {
72 InitialFill = 0x00,
73 Fill = 0x01,
74 Move = 0x02,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79#[repr(u8)]
80pub enum QuantumGateInstCode {
81 LocalR = 0x00,
82 LocalRz = 0x01,
83 GlobalR = 0x02,
84 GlobalRz = 0x03,
85 CZ = 0x04,
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
90#[repr(u8)]
91pub enum MeasurementInstCode {
92 Measure = 0x00,
93 AwaitMeasure = 0x01,
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98#[repr(u8)]
99pub enum ArrayInstCode {
100 NewArray = 0x00,
101 GetItem = 0x01,
102}
103
104#[derive(Debug, Clone, Copy, PartialEq, Eq)]
106#[repr(u8)]
107pub enum DetectorObservableInstCode {
108 SetDetector = 0x00,
109 SetObservable = 0x01,
110}
111
112pub const fn pack_opcode(device: u8, inst: u8) -> u16 {
114 ((inst as u16) << 8) | (device as u16)
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq)]
119pub enum OpCodeCategory {
120 Cpu(CpuInstCode),
121 LaneConstants(LaneConstInstCode),
122 AtomArrangement(AtomArrangementInstCode),
123 QuantumGate(QuantumGateInstCode),
124 Measurement(MeasurementInstCode),
125 Array(ArrayInstCode),
126 DetectorObservable(DetectorObservableInstCode),
127}
128
129pub fn decode_opcode(word: u32) -> Result<OpCodeCategory, DecodeError> {
131 let device_byte = (word & 0xFF) as u8;
132 let inst_byte = ((word >> 8) & 0xFF) as u8;
133
134 if word & 0xFFFF_0000 != 0 {
136 return Err(DecodeError::UnknownOpcode(word as u16));
137 }
138
139 let device = DeviceCode::from_byte(device_byte)?;
140
141 match device {
142 DeviceCode::Cpu => match inst_byte {
143 0x02 => Ok(OpCodeCategory::Cpu(CpuInstCode::ConstInt)),
144 0x03 => Ok(OpCodeCategory::Cpu(CpuInstCode::ConstFloat)),
145 0x04 => Ok(OpCodeCategory::Cpu(CpuInstCode::Dup)),
146 0x05 => Ok(OpCodeCategory::Cpu(CpuInstCode::Pop)),
147 0x06 => Ok(OpCodeCategory::Cpu(CpuInstCode::Swap)),
148 0x64 => Ok(OpCodeCategory::Cpu(CpuInstCode::Return)),
149 0xFF => Ok(OpCodeCategory::Cpu(CpuInstCode::Halt)),
150 _ => Err(DecodeError::UnknownOpcode(word as u16)),
151 },
152 DeviceCode::LaneConstants => match inst_byte {
153 0x00 => Ok(OpCodeCategory::LaneConstants(LaneConstInstCode::ConstLoc)),
154 0x01 => Ok(OpCodeCategory::LaneConstants(LaneConstInstCode::ConstLane)),
155 0x02 => Ok(OpCodeCategory::LaneConstants(LaneConstInstCode::ConstZone)),
156 _ => Err(DecodeError::UnknownOpcode(word as u16)),
157 },
158 DeviceCode::AtomArrangement => match inst_byte {
159 0x00 => Ok(OpCodeCategory::AtomArrangement(
160 AtomArrangementInstCode::InitialFill,
161 )),
162 0x01 => Ok(OpCodeCategory::AtomArrangement(
163 AtomArrangementInstCode::Fill,
164 )),
165 0x02 => Ok(OpCodeCategory::AtomArrangement(
166 AtomArrangementInstCode::Move,
167 )),
168 _ => Err(DecodeError::UnknownOpcode(word as u16)),
169 },
170 DeviceCode::QuantumGate => match inst_byte {
171 0x00 => Ok(OpCodeCategory::QuantumGate(QuantumGateInstCode::LocalR)),
172 0x01 => Ok(OpCodeCategory::QuantumGate(QuantumGateInstCode::LocalRz)),
173 0x02 => Ok(OpCodeCategory::QuantumGate(QuantumGateInstCode::GlobalR)),
174 0x03 => Ok(OpCodeCategory::QuantumGate(QuantumGateInstCode::GlobalRz)),
175 0x04 => Ok(OpCodeCategory::QuantumGate(QuantumGateInstCode::CZ)),
176 _ => Err(DecodeError::UnknownOpcode(word as u16)),
177 },
178 DeviceCode::Measurement => match inst_byte {
179 0x00 => Ok(OpCodeCategory::Measurement(MeasurementInstCode::Measure)),
180 0x01 => Ok(OpCodeCategory::Measurement(
181 MeasurementInstCode::AwaitMeasure,
182 )),
183 _ => Err(DecodeError::UnknownOpcode(word as u16)),
184 },
185 DeviceCode::Array => match inst_byte {
186 0x00 => Ok(OpCodeCategory::Array(ArrayInstCode::NewArray)),
187 0x01 => Ok(OpCodeCategory::Array(ArrayInstCode::GetItem)),
188 _ => Err(DecodeError::UnknownOpcode(word as u16)),
189 },
190 DeviceCode::DetectorObservable => match inst_byte {
191 0x00 => Ok(OpCodeCategory::DetectorObservable(
192 DetectorObservableInstCode::SetDetector,
193 )),
194 0x01 => Ok(OpCodeCategory::DetectorObservable(
195 DetectorObservableInstCode::SetObservable,
196 )),
197 _ => Err(DecodeError::UnknownOpcode(word as u16)),
198 },
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_pack_opcode() {
208 assert_eq!(pack_opcode(0x00, 0x02), 0x0200);
210 assert_eq!(pack_opcode(0x0F, 0x00), 0x000F);
212 assert_eq!(pack_opcode(0x10, 0x00), 0x0010);
214 assert_eq!(pack_opcode(0x11, 0x00), 0x0011);
216 assert_eq!(pack_opcode(0x00, 0xFF), 0xFF00);
218 }
219
220 #[test]
221 fn test_all_opcodes_decode() {
222 let cases: Vec<(u32, OpCodeCategory)> = vec![
223 (0x0200, OpCodeCategory::Cpu(CpuInstCode::ConstInt)),
224 (0x0300, OpCodeCategory::Cpu(CpuInstCode::ConstFloat)),
225 (0x0400, OpCodeCategory::Cpu(CpuInstCode::Dup)),
226 (0x0500, OpCodeCategory::Cpu(CpuInstCode::Pop)),
227 (0x0600, OpCodeCategory::Cpu(CpuInstCode::Swap)),
228 (0x6400, OpCodeCategory::Cpu(CpuInstCode::Return)),
229 (0xFF00, OpCodeCategory::Cpu(CpuInstCode::Halt)),
230 (
231 0x000F,
232 OpCodeCategory::LaneConstants(LaneConstInstCode::ConstLoc),
233 ),
234 (
235 0x010F,
236 OpCodeCategory::LaneConstants(LaneConstInstCode::ConstLane),
237 ),
238 (
239 0x020F,
240 OpCodeCategory::LaneConstants(LaneConstInstCode::ConstZone),
241 ),
242 (
243 0x0010,
244 OpCodeCategory::AtomArrangement(AtomArrangementInstCode::InitialFill),
245 ),
246 (
247 0x0110,
248 OpCodeCategory::AtomArrangement(AtomArrangementInstCode::Fill),
249 ),
250 (
251 0x0210,
252 OpCodeCategory::AtomArrangement(AtomArrangementInstCode::Move),
253 ),
254 (
255 0x0011,
256 OpCodeCategory::QuantumGate(QuantumGateInstCode::LocalR),
257 ),
258 (
259 0x0111,
260 OpCodeCategory::QuantumGate(QuantumGateInstCode::LocalRz),
261 ),
262 (
263 0x0211,
264 OpCodeCategory::QuantumGate(QuantumGateInstCode::GlobalR),
265 ),
266 (
267 0x0311,
268 OpCodeCategory::QuantumGate(QuantumGateInstCode::GlobalRz),
269 ),
270 (0x0411, OpCodeCategory::QuantumGate(QuantumGateInstCode::CZ)),
271 (
272 0x0012,
273 OpCodeCategory::Measurement(MeasurementInstCode::Measure),
274 ),
275 (
276 0x0112,
277 OpCodeCategory::Measurement(MeasurementInstCode::AwaitMeasure),
278 ),
279 (0x0013, OpCodeCategory::Array(ArrayInstCode::NewArray)),
280 (0x0113, OpCodeCategory::Array(ArrayInstCode::GetItem)),
281 (
282 0x0014,
283 OpCodeCategory::DetectorObservable(DetectorObservableInstCode::SetDetector),
284 ),
285 (
286 0x0114,
287 OpCodeCategory::DetectorObservable(DetectorObservableInstCode::SetObservable),
288 ),
289 ];
290
291 for (opcode, expected) in cases {
292 assert_eq!(
293 decode_opcode(opcode).unwrap(),
294 expected,
295 "failed for 0x{:04x}",
296 opcode
297 );
298 }
299 }
300
301 #[test]
302 fn test_unknown_opcode() {
303 assert!(decode_opcode(0x0001).is_err()); assert!(decode_opcode(0x0100).is_err()); assert!(decode_opcode(0x00010200).is_err());
309 }
310
311 #[test]
312 fn test_device_code_from_opcode() {
313 assert_eq!(DeviceCode::from_opcode(0x0200).unwrap(), DeviceCode::Cpu);
314 assert_eq!(
315 DeviceCode::from_opcode(0x000F).unwrap(),
316 DeviceCode::LaneConstants
317 );
318 assert_eq!(
319 DeviceCode::from_opcode(0x0010).unwrap(),
320 DeviceCode::AtomArrangement
321 );
322 }
323
324 #[test]
325 fn test_device_code_values() {
326 assert_eq!(DeviceCode::Cpu.code(), 0x00);
327 assert_eq!(DeviceCode::LaneConstants.code(), 0x0F);
328 assert_eq!(DeviceCode::AtomArrangement.code(), 0x10);
329 assert_eq!(DeviceCode::QuantumGate.code(), 0x11);
330 assert_eq!(DeviceCode::Measurement.code(), 0x12);
331 assert_eq!(DeviceCode::Array.code(), 0x13);
332 assert_eq!(DeviceCode::DetectorObservable.code(), 0x14);
333 }
334}