bloqade_lanes_bytecode_core/bytecode/
instruction.rs

1use super::opcode::{
2    ArrayInstCode, AtomArrangementInstCode, CpuInstCode, DetectorObservableInstCode, DeviceCode,
3    LaneConstInstCode, MeasurementInstCode, QuantumGateInstCode, pack_opcode,
4};
5
6/// CPU/stack instructions (device code `0x00`, FLAIR-aligned).
7#[derive(Debug, Clone, Copy, PartialEq)]
8pub enum CpuInstruction {
9    /// Push a 64-bit float constant. Opcode `0x0300`.
10    ConstFloat(f64),
11    /// Push a 64-bit signed integer constant. Opcode `0x0200`.
12    ConstInt(i64),
13    /// Pop and discard the top stack value. Opcode `0x0500`.
14    Pop,
15    /// Duplicate the top stack value. Opcode `0x0400`.
16    Dup,
17    /// Swap the top two stack values. Opcode `0x0600`.
18    Swap,
19    /// Return from program. Opcode `0x6400`.
20    Return,
21    /// Halt execution. Opcode `0xFF00`.
22    Halt,
23}
24
25/// Lane-specific constant instructions (device code `0x0F`).
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum LaneConstInstruction {
28    /// Push a packed [`LocationAddr`](crate::arch::addr::LocationAddr). Opcode `0x000F`.
29    ConstLoc(u32),
30    /// Push a packed [`LaneAddr`](crate::arch::addr::LaneAddr) as (data0, data1). Opcode `0x010F`.
31    ConstLane(u32, u32),
32    /// Push a packed [`ZoneAddr`](crate::arch::addr::ZoneAddr). Opcode `0x020F`.
33    ConstZone(u32),
34}
35
36/// Atom arrangement instructions (device code `0x10`).
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum AtomArrangementInstruction {
39    /// Initial atom fill. Must be the first non-constant instruction. Opcode `0x0010`.
40    InitialFill { arity: u32 },
41    /// Refill atoms at locations. Opcode `0x0110`.
42    Fill { arity: u32 },
43    /// Move atoms along lanes. Opcode `0x0210`.
44    Move { arity: u32 },
45}
46
47/// Quantum gate instructions (device code `0x11`).
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum QuantumGateInstruction {
50    /// Local R rotation on `arity` locations. Opcode `0x0011`.
51    LocalR { arity: u32 },
52    /// Local Rz rotation on `arity` locations. Opcode `0x0111`.
53    LocalRz { arity: u32 },
54    /// Global R rotation. Opcode `0x0211`.
55    GlobalR,
56    /// Global Rz rotation. Opcode `0x0311`.
57    GlobalRz,
58    /// Controlled-Z gate on a zone. Opcode `0x0411`.
59    CZ,
60}
61
62/// Measurement instructions (device code `0x12`).
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum MeasurementInstruction {
65    /// Initiate measurement on `arity` zones. Opcode `0x0012`.
66    Measure { arity: u32 },
67    /// Block until measurement completes. Opcode `0x0112`.
68    AwaitMeasure,
69}
70
71/// Array construction and indexing instructions (device code `0x13`).
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
73pub enum ArrayInstruction {
74    /// Construct an array. Opcode `0x0013`.
75    NewArray { type_tag: u8, dim0: u16, dim1: u16 },
76    /// Index into an array. Opcode `0x0113`.
77    GetItem { ndims: u16 },
78}
79
80/// Detector and observable setup instructions (device code `0x14`).
81#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub enum DetectorObservableInstruction {
83    /// Build a detector record from an array. Opcode `0x0014`.
84    SetDetector,
85    /// Build an observable record from an array. Opcode `0x0114`.
86    SetObservable,
87}
88
89/// A single bytecode instruction.
90///
91/// Each variant wraps a device-specific instruction enum. The instruction
92/// can be encoded to a 16-byte binary word or printed as SST text assembly.
93#[derive(Debug, Clone, Copy, PartialEq)]
94pub enum Instruction {
95    /// CPU/stack operations (device `0x00`).
96    Cpu(CpuInstruction),
97    /// Lane address constants (device `0x0F`).
98    LaneConst(LaneConstInstruction),
99    /// Atom arrangement operations (device `0x10`).
100    AtomArrangement(AtomArrangementInstruction),
101    /// Quantum gate operations (device `0x11`).
102    QuantumGate(QuantumGateInstruction),
103    /// Measurement operations (device `0x12`).
104    Measurement(MeasurementInstruction),
105    /// Array operations (device `0x13`).
106    Array(ArrayInstruction),
107    /// Detector/observable setup (device `0x14`).
108    DetectorObservable(DetectorObservableInstruction),
109}
110
111impl Instruction {
112    /// Returns the packed opcode as a u16: `(instruction_code << 8) | device_code`.
113    pub fn opcode(&self) -> u16 {
114        match self {
115            Instruction::Cpu(cpu) => {
116                let inst = match cpu {
117                    CpuInstruction::ConstFloat(_) => CpuInstCode::ConstFloat as u8,
118                    CpuInstruction::ConstInt(_) => CpuInstCode::ConstInt as u8,
119                    CpuInstruction::Pop => CpuInstCode::Pop as u8,
120                    CpuInstruction::Dup => CpuInstCode::Dup as u8,
121                    CpuInstruction::Swap => CpuInstCode::Swap as u8,
122                    CpuInstruction::Return => CpuInstCode::Return as u8,
123                    CpuInstruction::Halt => CpuInstCode::Halt as u8,
124                };
125                pack_opcode(DeviceCode::Cpu as u8, inst)
126            }
127            Instruction::LaneConst(lc) => {
128                let inst = match lc {
129                    LaneConstInstruction::ConstLoc(_) => LaneConstInstCode::ConstLoc as u8,
130                    LaneConstInstruction::ConstLane(_, _) => LaneConstInstCode::ConstLane as u8,
131                    LaneConstInstruction::ConstZone(_) => LaneConstInstCode::ConstZone as u8,
132                };
133                pack_opcode(DeviceCode::LaneConstants as u8, inst)
134            }
135            Instruction::AtomArrangement(aa) => {
136                let inst = match aa {
137                    AtomArrangementInstruction::InitialFill { .. } => {
138                        AtomArrangementInstCode::InitialFill as u8
139                    }
140                    AtomArrangementInstruction::Fill { .. } => AtomArrangementInstCode::Fill as u8,
141                    AtomArrangementInstruction::Move { .. } => AtomArrangementInstCode::Move as u8,
142                };
143                pack_opcode(DeviceCode::AtomArrangement as u8, inst)
144            }
145            Instruction::QuantumGate(qg) => {
146                let inst = match qg {
147                    QuantumGateInstruction::LocalR { .. } => QuantumGateInstCode::LocalR as u8,
148                    QuantumGateInstruction::LocalRz { .. } => QuantumGateInstCode::LocalRz as u8,
149                    QuantumGateInstruction::GlobalR => QuantumGateInstCode::GlobalR as u8,
150                    QuantumGateInstruction::GlobalRz => QuantumGateInstCode::GlobalRz as u8,
151                    QuantumGateInstruction::CZ => QuantumGateInstCode::CZ as u8,
152                };
153                pack_opcode(DeviceCode::QuantumGate as u8, inst)
154            }
155            Instruction::Measurement(m) => {
156                let inst = match m {
157                    MeasurementInstruction::Measure { .. } => MeasurementInstCode::Measure as u8,
158                    MeasurementInstruction::AwaitMeasure => MeasurementInstCode::AwaitMeasure as u8,
159                };
160                pack_opcode(DeviceCode::Measurement as u8, inst)
161            }
162            Instruction::Array(arr) => {
163                let inst = match arr {
164                    ArrayInstruction::NewArray { .. } => ArrayInstCode::NewArray as u8,
165                    ArrayInstruction::GetItem { .. } => ArrayInstCode::GetItem as u8,
166                };
167                pack_opcode(DeviceCode::Array as u8, inst)
168            }
169            Instruction::DetectorObservable(dob) => {
170                let inst = match dob {
171                    DetectorObservableInstruction::SetDetector => {
172                        DetectorObservableInstCode::SetDetector as u8
173                    }
174                    DetectorObservableInstruction::SetObservable => {
175                        DetectorObservableInstCode::SetObservable as u8
176                    }
177                };
178                pack_opcode(DeviceCode::DetectorObservable as u8, inst)
179            }
180        }
181    }
182
183    /// Returns the device code for this instruction.
184    pub fn device_code(&self) -> DeviceCode {
185        match self {
186            Instruction::Cpu(_) => DeviceCode::Cpu,
187            Instruction::LaneConst(_) => DeviceCode::LaneConstants,
188            Instruction::AtomArrangement(_) => DeviceCode::AtomArrangement,
189            Instruction::QuantumGate(_) => DeviceCode::QuantumGate,
190            Instruction::Measurement(_) => DeviceCode::Measurement,
191            Instruction::Array(_) => DeviceCode::Array,
192            Instruction::DetectorObservable(_) => DeviceCode::DetectorObservable,
193        }
194    }
195}
196
197#[cfg(test)]
198mod tests {
199    use super::*;
200
201    #[test]
202    fn test_opcode_cpu() {
203        assert_eq!(
204            Instruction::Cpu(CpuInstruction::ConstFloat(1.0)).opcode(),
205            0x0300
206        );
207        assert_eq!(
208            Instruction::Cpu(CpuInstruction::ConstInt(1)).opcode(),
209            0x0200
210        );
211        assert_eq!(Instruction::Cpu(CpuInstruction::Pop).opcode(), 0x0500);
212        assert_eq!(Instruction::Cpu(CpuInstruction::Dup).opcode(), 0x0400);
213        assert_eq!(Instruction::Cpu(CpuInstruction::Swap).opcode(), 0x0600);
214        assert_eq!(Instruction::Cpu(CpuInstruction::Return).opcode(), 0x6400);
215        assert_eq!(Instruction::Cpu(CpuInstruction::Halt).opcode(), 0xFF00);
216    }
217
218    #[test]
219    fn test_opcode_lane_constants() {
220        assert_eq!(
221            Instruction::LaneConst(LaneConstInstruction::ConstLoc(0)).opcode(),
222            0x000F
223        );
224        assert_eq!(
225            Instruction::LaneConst(LaneConstInstruction::ConstLane(0, 0)).opcode(),
226            0x010F
227        );
228        assert_eq!(
229            Instruction::LaneConst(LaneConstInstruction::ConstZone(0)).opcode(),
230            0x020F
231        );
232    }
233
234    #[test]
235    fn test_opcode_atom_arrangement() {
236        assert_eq!(
237            Instruction::AtomArrangement(AtomArrangementInstruction::InitialFill { arity: 1 })
238                .opcode(),
239            0x0010
240        );
241        assert_eq!(
242            Instruction::AtomArrangement(AtomArrangementInstruction::Fill { arity: 1 }).opcode(),
243            0x0110
244        );
245        assert_eq!(
246            Instruction::AtomArrangement(AtomArrangementInstruction::Move { arity: 1 }).opcode(),
247            0x0210
248        );
249    }
250
251    #[test]
252    fn test_opcode_quantum_gate() {
253        assert_eq!(
254            Instruction::QuantumGate(QuantumGateInstruction::LocalR { arity: 1 }).opcode(),
255            0x0011
256        );
257        assert_eq!(
258            Instruction::QuantumGate(QuantumGateInstruction::LocalRz { arity: 1 }).opcode(),
259            0x0111
260        );
261        assert_eq!(
262            Instruction::QuantumGate(QuantumGateInstruction::GlobalR).opcode(),
263            0x0211
264        );
265        assert_eq!(
266            Instruction::QuantumGate(QuantumGateInstruction::GlobalRz).opcode(),
267            0x0311
268        );
269        assert_eq!(
270            Instruction::QuantumGate(QuantumGateInstruction::CZ).opcode(),
271            0x0411
272        );
273    }
274
275    #[test]
276    fn test_opcode_measurement() {
277        assert_eq!(
278            Instruction::Measurement(MeasurementInstruction::Measure { arity: 1 }).opcode(),
279            0x0012
280        );
281        assert_eq!(
282            Instruction::Measurement(MeasurementInstruction::AwaitMeasure).opcode(),
283            0x0112
284        );
285    }
286
287    #[test]
288    fn test_opcode_array() {
289        assert_eq!(
290            Instruction::Array(ArrayInstruction::NewArray {
291                type_tag: 0,
292                dim0: 10,
293                dim1: 20
294            })
295            .opcode(),
296            0x0013
297        );
298        assert_eq!(
299            Instruction::Array(ArrayInstruction::GetItem { ndims: 2 }).opcode(),
300            0x0113
301        );
302    }
303
304    #[test]
305    fn test_opcode_detector_observable() {
306        assert_eq!(
307            Instruction::DetectorObservable(DetectorObservableInstruction::SetDetector).opcode(),
308            0x0014
309        );
310        assert_eq!(
311            Instruction::DetectorObservable(DetectorObservableInstruction::SetObservable).opcode(),
312            0x0114
313        );
314    }
315
316    #[test]
317    fn test_device_code() {
318        assert_eq!(
319            Instruction::Cpu(CpuInstruction::Halt).device_code(),
320            DeviceCode::Cpu
321        );
322        assert_eq!(
323            Instruction::LaneConst(LaneConstInstruction::ConstLoc(0)).device_code(),
324            DeviceCode::LaneConstants
325        );
326        assert_eq!(
327            Instruction::AtomArrangement(AtomArrangementInstruction::Fill { arity: 1 })
328                .device_code(),
329            DeviceCode::AtomArrangement
330        );
331        assert_eq!(
332            Instruction::QuantumGate(QuantumGateInstruction::CZ).device_code(),
333            DeviceCode::QuantumGate
334        );
335        assert_eq!(
336            Instruction::Measurement(MeasurementInstruction::AwaitMeasure).device_code(),
337            DeviceCode::Measurement
338        );
339        assert_eq!(
340            Instruction::Array(ArrayInstruction::GetItem { ndims: 1 }).device_code(),
341            DeviceCode::Array
342        );
343        assert_eq!(
344            Instruction::DetectorObservable(DetectorObservableInstruction::SetDetector)
345                .device_code(),
346            DeviceCode::DetectorObservable
347        );
348    }
349}