Bloqade Lanes

Bloqade Lanes is a component of QuEra's Neutral Atom SDK. It compiles quantum circuits down to physical atom movement instructions for neutral atom quantum processors.

What's in this book

  • Architecture Specification — the ArchSpec JSON format that defines device topology, transport buses, zones, and AOD paths
  • Instruction Quick Reference — compact summary of all 24 instructions with opcodes and stack effects
  • Instruction Set — the fixed-width instruction encoding, opcode layout, and per-instruction reference
  • CLI Reference — the bloqade-bytecode CLI tool for assembling, disassembling, and validating bytecode programs

Crate documentation

The Rust API documentation is generated separately via cargo doc:

Repository

Source code: github.com/QuEraComputing/bloqade-lanes

ArchSpec — Architecture Specification

The ArchSpec defines the physical topology and transport capabilities of a Bloqade quantum device. It is the input that the bytecode compiler and validator use to determine which instructions are legal for a given hardware configuration.

The formal JSON Schema is available at archspec-schema.json.

Top-Level Structure

{
  "version": "1.0",
  "geometry": { ... },
  "buses": { ... },
  "words_with_site_buses": [...],
  "sites_with_word_buses": [...],
  "zones": [...],
  "entangling_zones": [...],
  "measurement_mode_zones": [...],
  "paths": [...],                 // optional
  "feed_forward": false,          // optional, default false
  "atom_reloading": false          // optional, default false
}
FieldTypeDescription
versionstringFormat version as "major.minor" (e.g. "1.0").
geometryobjectPhysical geometry — words, grids, and site positions.
busesobjectTransport bus definitions (site buses and word buses).
words_with_site_busesinteger[]Word IDs with intra-word site transport capability.
sites_with_word_busesinteger[]Site indices that serve as landing pads for inter-word transport.
zonesZone[]Logical groupings of words for execution phases.
entangling_zonesinteger[]Zone IDs where CZ gates can be performed.
measurement_mode_zonesinteger[]Zone IDs that support measurement.
pathsTransportPath[](optional) AOD transport paths between locations.
feed_forwardbool(optional, default false) Whether the device supports mid-circuit measurement with classical feedback.
atom_reloadingbool(optional, default false) Whether the device supports reloading atoms after initial fill.

Geometry

The geometry describes the physical layout of the device: how many words exist, how many sites each word contains, and where those sites are in 2D space.

"geometry": {
  "sites_per_word": 10,
  "words": [
    {
      "positions": {
        "x_start": 1.0,
        "y_start": 2.5,
        "x_spacing": [2.0, 2.0, 2.0, 2.0],
        "y_spacing": [2.5]
      },
      "site_indices": [[0, 0], [1, 0], [2, 0], ...],
      "has_cz": [[0, 5], [0, 6], ...]       // optional
    }
  ]
}

Word

A word is an independent register of atom trapping sites arranged on a 2D grid. It is the fundamental unit of the device topology.

A word's ID is its index in the geometry.words array (e.g., the first word is word 0).

FieldTypeDescription
positionsGridThe 2D coordinate system for this word.
site_indices[x_idx, y_idx][]Site positions as index pairs into the grid's x and y coordinate arrays.
has_cz[word_id, site_id][](optional) CZ entanglement partner for each site. has_cz[i] is the site that site i entangles with.

Grid

A grid defines the physical coordinate axes for a word using a start position and spacing values. Positions are typically in micrometers (µm).

FieldTypeDescription
x_startfloatX-coordinate of the first grid point.
y_startfloatY-coordinate of the first grid point.
x_spacingfloat[]Spacing between consecutive x-coordinates. The number of x grid points is len(x_spacing) + 1.
y_spacingfloat[]Spacing between consecutive y-coordinates. The number of y grid points is len(y_spacing) + 1.

The x-coordinates are computed as [x_start, x_start + x_spacing[0], x_start + x_spacing[0] + x_spacing[1], ...] (cumulative sum of spacings from the start). Same for y. Sites reference grid positions by index: site [2, 1] is located at the 3rd x-coordinate and 2nd y-coordinate.

All words must have the same grid shape — i.e., the same number of x and y grid points (same x_spacing and y_spacing lengths). The actual coordinate values may differ (words can be at different physical locations), but the grid dimensions must be consistent.


Buses

Buses are the physical transport channels that move atoms. There are two kinds:

Site Bus

A site bus moves atoms between sites within the same word. It defines a paired mapping where src[i] moves to dst[i].

{ "src": [0, 1, 2, 3, 4], "dst": [5, 6, 7, 8, 9] }

This means atom at site 0 moves to site 5, atom at site 1 moves to site 6, and so on — all in a single transport operation. The src and dst arrays must be the same length and must not overlap (no site can be both a source and a destination in the same bus). A site bus's ID is its index in the buses.site_buses array.

Word Bus

A word bus moves atoms between sites across different words. The src and dst arrays contain word IDs (not site indices). A word bus's ID is its index in the buses.word_buses array.

{ "src": [0], "dst": [1] }

The specific sites involved in inter-word transport are those listed in sites_with_word_buses — these are the "landing pad" positions within each word.

Supporting Fields

FieldDescription
words_with_site_busesWhich words have site bus hardware. Only these words can execute intra-word site moves.
sites_with_word_busesWhich site indices serve as landing pads for word-bus moves. These positions within each word are where atoms arrive and depart during inter-word transport.

Zones

A zone groups words into logical regions for different execution phases (entangling, measurement, etc.).

"zones": [
  { "words": [0, 1, 2] }
]

A zone's ID is its index in the zones array (e.g., the first zone is zone 0).

Zone 0 is special — it must contain every word in the geometry. This ensures there is always a "global" zone that covers the entire device.

Entangling Zones

entangling_zones lists zone IDs where CZ (entangling) gates can be performed. Words in these zones must have has_cz defined to specify entanglement partners.

Measurement Mode Zones

measurement_mode_zones lists zone IDs that support measurement operations. If non-empty, the first entry must be zone 0.


Paths (Optional)

AOD (Acousto-Optic Deflector) transport paths. Each path identifies a transport lane and provides a sequence of [x, y] waypoints defining the physical trajectory atoms follow during transport.

The lane is identified by its encoded LaneAddr, serialized as a hex string. See Address Encoding for the LaneAddr bit layout.

"paths": [
  {
    "lane": "0xC000000000000000",                        // encoded LaneAddr (hex, 16-digit)
    "waypoints": [[1.0, 12.5], [1.0, 7.5], [1.0, 2.5]]  // physical trajectory
  }
]

Each TransportPath entry has:

FieldTypeDescription
lanestringEncoded LaneAddr as a "0x..." hex string.
waypoints[x, y][]Sequence of physical coordinate waypoints.

To decode the lane hex string, parse it as a 64-bit unsigned integer. The low 32 bits (data0) contain [word_id:16][site_id:16] and the high 32 bits (data1) contain [dir:1][mt:1][pad:14][bus_id:16]. For example, "0xC000000000000000" decodes to direction=Backward, move_type=WordBus, word=0, site=0, bus=0. In the lane address convention, word_id always encodes the forward-direction source word for that lane; in this specific example the bus mapping is src=[0], dst=[1], so direction=Backward means the move goes from word 1 back to word 0.

This field is omitted from the JSON when not needed.


Capability Flags (Optional)

Two boolean flags describe device capabilities that affect bytecode validation:

FieldDefaultDescription
feed_forwardfalseMid-circuit measurement with classical feedback. When false, at most one measure instruction is allowed per program.
atom_reloadingfalseAtom reloading after initial fill. When false, no fill instruction is allowed (only initial_fill).

Both fields are optional in the JSON — existing arch spec files that omit them default to false, which is the most restrictive setting.

{
  "feed_forward": true,
  "atom_reloading": false
}

Validation Rules

The ArchSpec::validate() method checks all structural rules in a single pass, collecting every error rather than failing fast. The following rules are enforced:

Zone Rules

RuleError
Zone 0 must include every word ID in the geometryZone0MissingWords
measurement_mode_zones must not be emptyMeasurementModeZonesEmpty
measurement_mode_zones[0] must be zone 0MeasurementModeFirstNotZone0
Every ID in entangling_zones must reference a defined zoneInvalidEntanglingZone
Every ID in measurement_mode_zones must reference a defined zoneInvalidMeasurementModeZone

Word / Site Rules

RuleError
Every word must have exactly sites_per_word site_indicesWrongSiteCount
If present, has_cz must have exactly sites_per_word entriesWrongCzPairsCount
All words must have the same grid shape (same number of x and y positions)InconsistentGridShape
Grid coordinates must be finite (no NaN or Inf)NonFiniteGridValue
Site x_idx must be < number of x grid points (len(x_spacing) + 1)SiteXIndexOutOfRange
Site y_idx must be < number of y grid points (len(y_spacing) + 1)SiteYIndexOutOfRange

Site Bus Rules

RuleError
src.length must equal dst.lengthSiteBusLengthMismatch
src and dst must be disjoint (no shared site indices)SiteBusSrcDstOverlap
All site indices in src and dst must be < sites_per_wordSiteBusIndexOutOfRange

Word Bus Rules

RuleError
src.length must equal dst.lengthWordBusLengthMismatch
All word IDs in src and dst must exist in geometry.wordsWordBusInvalidWordId

Cross-Reference Rules

RuleError
Every ID in words_with_site_buses must be a valid word IDInvalidWordWithSiteBus
Every index in sites_with_word_buses must be < sites_per_wordInvalidSiteWithWordBus

Path Rules

RuleError
Every path's lane must decode to a valid LaneAddr (valid bus ID, word ID, site ID)InvalidPathLane
Every path must have at least 2 waypointsPathTooFewWaypoints
The first waypoint must match the source position of the lane, and the last waypoint must match the destination positionPathEndpointMismatch
Waypoint coordinates must be finite (no NaN or Inf)NonFiniteWaypoint

Capability Rules (Bytecode Validation)

These rules are checked during bytecode validation when an ArchSpec is provided:

RuleError
If feed_forward = false, at most one measure instruction is allowedFeedForwardNotSupported
If atom_reloading = false, no fill instruction is allowedAtomReloadingNotSupported

Address Encoding

At the bytecode level, locations and lanes are encoded as bit-packed integers with 16-bit address fields. Each address type is packed into instruction data words (u32):

TypeWidthLayoutDescription
LocationAddr32 bits (1 × u32)data0: [word_id:16][site_id:16]Identifies a specific site within a word.
LaneAddr64 bits (2 × u32)data0: [word_id:16][site_id:16], data1: [dir:1][mt:1][pad:14][bus_id:16]Identifies a transport lane (direction + move type + site + bus).
ZoneAddr32 bits (1 × u32)data0: [pad:16][zone_id:16]Identifies a zone.

These packed addresses are used in 16-byte bytecode instructions (opcode + 3 data words) and are validated against the arch spec during program validation. In JSON and Python, LaneAddr is represented as a 64-bit integer (16-digit hex string in JSON, u64 in Python).


Examples

Minimal spec with one word and one site bus:

{
  "version": "1.0",
  "geometry": {
    "sites_per_word": 5,
    "words": [
      {
        "positions": {
          "x_start": 1.0,
          "y_start": 2.0,
          "x_spacing": [2.0, 2.0, 2.0, 2.0],
          "y_spacing": []
        },
        "site_indices": [[0, 0], [1, 0], [2, 0], [3, 0], [4, 0]]
      }
    ]
  },
  "buses": {
    "site_buses": [
      { "src": [0, 1], "dst": [3, 4] }
    ],
    "word_buses": []
  },
  "words_with_site_buses": [0],
  "sites_with_word_buses": [],
  "zones": [
    { "words": [0] }
  ],
  "entangling_zones": [],
  "measurement_mode_zones": [0]
}

A fuller example with multiple words, CZ pairs, and word buses is available at examples/arch/full.json.

Instruction Quick Reference

A compact summary of all 24 bytecode instructions. See the Instruction Set for full encoding details.

Cpu (0x00)

Stack manipulation, constants, and control flow (FLAIR-aligned).

InstructionOpcodeStack EffectDescription
const_int0x0200( -- int)Push 64-bit integer constant
const_float0x0300( -- float)Push 64-bit float constant
dup0x0400(a -- a a)Duplicate top of stack
pop0x0500(a -- )Discard top of stack
swap0x0600(a b -- b a)Swap top two elements
return0x6400( -- )Return from program
halt0xFF00( -- )Halt execution

LaneConstants (0x0F)

Address constant instructions.

InstructionOpcodeStack EffectDescription
const_loc0x000F( -- loc)Push location address
const_lane0x010F( -- lane)Push lane address
const_zone0x020F( -- zone)Push zone address

AtomArrangement (0x10)

Atom filling and transport.

InstructionOpcodeStack EffectDescription
initial_fill0x0010(loc₁..locₙ -- )Initial atom loading
fill0x0110(loc₁..locₙ -- )Atom refill
move0x0210(lane₁..laneₙ -- )Atom transport along lanes

QuantumGate (0x11)

Single- and multi-qubit gate operations.

InstructionOpcodeStack EffectDescription
local_r0x0011(loc₁..locₙ θ φ -- )Local R rotation
local_rz0x0111(loc₁..locₙ θ -- )Local Rz rotation
global_r0x0211(θ φ -- )Global R rotation
global_rz0x0311(θ -- )Global Rz rotation
cz0x0411(zone -- )Controlled-Z gate on zone

Measurement (0x12)

Qubit measurement.

InstructionOpcodeStack EffectDescription
measure0x0012(zone₁..zoneₙ -- future₁..futureₙ)Initiate measurement
await_measure0x0112(future -- array_ref)Wait for measurement result

Array (0x13)

Array construction and indexing.

InstructionOpcodeStack EffectDescription
new_array0x0013(elem₁..elemₙ -- array_ref)Construct array from stack
get_item0x0113(array_ref idx₁..idxₙ -- value)Index into array

DetectorObservable (0x14)

Detector and observable setup.

InstructionOpcodeStack EffectDescription
set_detector0x0014(array_ref -- detector_ref)Set detector
set_observable0x0114(array_ref -- observable_ref)Set observable

Bloqade Lanes Bytecode Instruction Specification

This document specifies the bytecode instruction set used by Bloqade Lanes to describe atom shuttling programs for neutral atom quantum processors. A bytecode program is a sequence of fixed-width instructions that drive the full lifecycle of a computation: loading atoms into an optical lattice, shuttling them between sites using AOD (Acousto-Optic Deflector) transport, applying quantum gates, and reading out measurement results.

The instruction set is organized around the physical structure of the hardware. Atoms occupy sites within words (rows of trapping positions in the lattice). Buses define the AOD transport channels that move atoms between sites (site buses) or between words (word buses). A lane is a single atom trajectory along a bus — one source site to one destination site. A zone groups words that share a global entangling interaction (e.g. a Rydberg pulse) or define locations where atoms are measured. These concepts map directly to the address types used in the bytecode: LocationAddr (word, site), LaneAddr (word, site, bus, direction), and ZoneAddr (zone).

Programs execute on a stack machine. Address constants and numeric parameters are pushed onto the stack, then consumed by operation instructions (fills, moves, gates, measurements). The bytecode is designed to be validated offline against an architecture specification (ArchSpec) that captures the geometry, bus topology, and zone layout of a specific device.

Instruction Format

Every instruction is a fixed 16 bytes: a 32-bit opcode word followed by three 32-bit data words, all little-endian.

┌──────────────┬──────────────┬──────────────┬──────────────┐
│ opcode (u32) │ data0 (u32)  │ data1 (u32)  │ data2 (u32)  │
├──────────────┼──────────────┼──────────────┼──────────────┤
│  bytes 0–3   │  bytes 4–7   │  bytes 8–11  │ bytes 12–15  │
└──────────────┴──────────────┴──────────────┴──────────────┘

Instructions that take no operands ignore the data words (should be zero). Instructions with operands encode them in the data words as described per-instruction below.

Opcode Packing

The opcode word is packed as a 1-byte instruction code and a 1-byte device code in the low 16 bits of the u32. The upper 16 bits are unused (must be zero). The device code occupies the least significant byte.

┌──────────────┬──────────────────┬──────────────────┐
│   unused     │ instruction code │   device code    │
│  (16 bits)   │    (8 bits)      │    (8 bits)      │
└──────────────┴──────────────────┴──────────────────┘
  bits 31–16       bits 15–8          bits 7–0

Full opcode = (instruction_code << 8) | device_code.

In little-endian memory layout:

byte[0] = device_code        (bits 7–0)
byte[1] = instruction_code   (bits 15–8)
byte[2] = 0x00               (unused)
byte[3] = 0x00               (unused)

Instruction codes can overlap across different devices — the device code byte disambiguates.

Device Codes

Device CodeNameDescription
0x00CpuStack manipulation, constants, control flow (FLAIR-aligned)
0x0FLaneConstantsLane-specific constant instructions
0x10AtomArrangementAtom filling and movement
0x11QuantumGateSingle- and multi-qubit gate operations
0x12MeasurementQubit measurement
0x13ArrayArray construction and indexing
0x14DetectorObservableDetector and observable setup

Device codes 0x010x0E are reserved for future FLAIR device types.

Address Encoding

All address field components are 16-bit, packed into the data words.

LocationAddr

Packed in a single data word (data0):

data0: [word_id:16][site_id:16]
        bits 31–16   bits 15–0

Total: 32 bits (u32).

LaneAddr

Packed across two data words (data0 + data1):

data0: [word_id:16][site_id:16]
        bits 31–16   bits 15–0

data1: [dir:1][mt:1][pad:14][bus_id:16]
       bit 31  bit 30  29–16  bits 15–0
  • dir — direction: 0 = Forward, 1 = Backward
  • mt — move type: 0 = SiteBus, 1 = WordBus

Total: 64 bits across two u32 words. Note that data0 shares the same layout as LocationAddr.

Lane address convention

The word_id and site_id fields in a LaneAddr always encode the forward-direction source — the position where the atom starts in a forward move. The direction field does not change which position is encoded; it only controls which endpoint is treated as source vs destination when the lane is resolved.

Endpoint resolution always starts by resolving the forward direction:

  1. Look up the bus (site bus or word bus, selected by move_type and bus_id)
  2. Find the index i where bus.src[i] matches the encoded site_id (for site buses) or word_id (for word buses)
  3. The forward source is (word_id, site_id) as encoded; the forward destination is (word_id, bus.dst[i]) for site buses or (bus.dst[i], site_id) for word buses
  4. If direction = Forward: return (fwd_source, fwd_destination)
  5. If direction = Backward: return (fwd_destination, fwd_source) — the endpoints are swapped

Example: Given a site bus with src=[0,1,2,3,4] dst=[5,6,7,8,9]:

LaneEncodedResolved src → dst
site_id=0, dir=ForwardForward source is site 0Site 0 → Site 5
site_id=0, dir=BackwardForward source is still site 0Site 5 → Site 0
site_id=2, dir=BackwardForward source is site 2Site 7 → Site 2

Note that a backward lane with site_id=0 means the atom moves from site 5 to site 0 — not that site 0 is the destination of a forward move.

Lane validation rules

The validator (check_lane) checks the following for each LaneAddr:

RuleError condition
Bus must existbus_id out of range for the given move_type
word_id in rangeword_id >= num_words
site_id in rangesite_id >= sites_per_word
Bus membershipFor site buses: word_id must be in words_with_site_buses. For word buses: site_id must be in sites_with_word_buses.
Valid forward sourceFor site buses: bus.resolve_forward(site_id) must succeed (i.e. site_id is in bus.src). For word buses: bus.resolve_forward(word_id) must succeed (i.e. word_id is in bus.src).

Validation is always performed against the forward-direction source, regardless of the direction field.

ZoneAddr

Packed in a single data word (data0):

data0: [pad:16][zone_id:16]
       bits 31–16  bits 15–0

Total: 32 bits (u32).

Instructions

Cpu (0x00) — FLAIR-aligned shared opcodes

These instruction codes are shared with the FLAIR VM/IR spec and use identical values.

const_int — Push integer constant

FieldValue
Device Code0x00
Instruction Code0x02
Full Opcode0x0200
data0i64 LE low 32 bits
data1i64 LE high 32 bits
data2unused
Stack( -- int)

Pushes a signed 64-bit integer onto the stack. The value is stored as a little-endian i64 across data0 (low) and data1 (high).

const_float — Push float constant

FieldValue
Device Code0x00
Instruction Code0x03
Full Opcode0x0300
data0f64 LE low 32 bits
data1f64 LE high 32 bits
data2unused
Stack( -- float)

Pushes a 64-bit float onto the stack. The value is stored as a little-endian f64 across data0 (low) and data1 (high).

dup — Duplicate top of stack

FieldValue
Device Code0x00
Instruction Code0x04
Full Opcode0x0400
data0–2unused
Stack(a -- a a)

pop — Discard top of stack

FieldValue
Device Code0x00
Instruction Code0x05
Full Opcode0x0500
data0–2unused
Stack(a -- )

swap — Swap top two stack elements

FieldValue
Device Code0x00
Instruction Code0x06
Full Opcode0x0600
data0–2unused
Stack(a b -- b a)

return — Return from program

FieldValue
Device Code0x00
Instruction Code0x64
Full Opcode0x6400
data0–2unused
Stack( -- )

halt — Halt execution

FieldValue
Device Code0x00
Instruction Code0xFF
Full Opcode0xFF00
data0–2unused
Stack( -- )

LaneConstants (0x0F)

const_loc — Push location address

FieldValue
Device Code0x0F
Instruction Code0x00
Full Opcode0x000F
data0LocationAddr[word_id:16][site_id:16]
data1unused
data2unused
Stack( -- loc)

const_lane — Push lane address

FieldValue
Device Code0x0F
Instruction Code0x01
Full Opcode0x010F
data0[word_id:16][site_id:16]
data1[dir:1][mt:1][pad:14][bus_id:16]
data2unused
Stack( -- lane)

const_zone — Push zone address

FieldValue
Device Code0x0F
Instruction Code0x02
Full Opcode0x020F
data0ZoneAddr[pad:16][zone_id:16]
data1unused
data2unused
Stack( -- zone)

AtomArrangement (0x10)

initial_fill — Initial atom loading

FieldValue
Device Code0x10
Instruction Code0x00
Full Opcode0x0010
data0u32 LE arity
data1unused
data2unused
Stack(loc₁ loc₂ … locₙ -- )

Pops n location addresses and performs the initial atom fill at those sites.

fill — Atom refill

FieldValue
Device Code0x10
Instruction Code0x01
Full Opcode0x0110
data0u32 LE arity
data1unused
data2unused
Stack(loc₁ loc₂ … locₙ -- )

Pops n location addresses and refills atoms at those sites.

move — Atom transport

FieldValue
Device Code0x10
Instruction Code0x02
Full Opcode0x0210
data0u32 LE arity
data1unused
data2unused
Stack(lane₁ lane₂ … laneₙ -- )

Pops n lane addresses and performs atom moves along those lanes. All lanes in a single move instruction are executed simultaneously as one AOD transport operation.

Lane group validation

When an ArchSpec is provided, the validator checks the group of lanes as a whole — not just each lane individually. These constraints reflect the physical limitations of a single AOD (Acousto-Optic Deflector). Each move instruction corresponds to one AOD operation:

Consistency — all lanes in the group must share the same move_type, bus_id, and direction. A single AOD operation cannot mix site-bus and word-bus moves, use different buses, or move atoms in different directions simultaneously.

Bus membership — for site-bus moves, every lane's word_id must be in words_with_site_buses. For word-bus moves, every lane's site_id must be in sites_with_word_buses.

Grid constraint — the physical positions of the lane sources must form a complete grid (Cartesian product of unique X and Y coordinates). An AOD addresses rows and columns independently, so it cannot select an arbitrary subset of positions — it must address every intersection of the selected rows and columns.

For example, if a move group contains lanes at positions (0,0), (0,1), (1,0), and (1,1), this is a valid 2x2 grid. But (0,0), (0,1), (1,0) alone is invalid — the AOD would also address (1,1), so the group must include it.

CheckError
All lanes share move_type, bus_id, directionInconsistent
Site-bus lane word_id in words_with_site_busesWordNotInSiteBusList
Word-bus lane site_id in sites_with_word_busesSiteNotInWordBusList
Lane positions form a complete gridAODConstraintViolation

QuantumGate (0x11)

local_r — Local R rotation

FieldValue
Device Code0x11
Instruction Code0x00
Full Opcode0x0011
data0u32 LE arity
data1unused
data2unused
Stack(loc₁ loc₂ … locₙ θ φ -- )

Pops 2 float parameters (φ = axis angle, θ = rotation angle) then n location addresses, and applies a local R rotation. The call convention matches the SSA IR: local_r(%φ, %θ, %loc₁, …) — first argument (φ) is pushed last and popped first.

local_rz — Local Rz rotation

FieldValue
Device Code0x11
Instruction Code0x01
Full Opcode0x0111
data0u32 LE arity
data1unused
data2unused
Stack(loc₁ loc₂ … locₙ θ -- )

Pops 1 float parameter (θ = rotation angle) then n location addresses, and applies a local Rz rotation. The call convention matches the SSA IR: local_rz(%θ, %loc₁, …).

global_r — Global R rotation

FieldValue
Device Code0x11
Instruction Code0x02
Full Opcode0x0211
data0–2unused
Stack(θ φ -- )

Pops 2 float parameters (φ = axis angle, θ = rotation angle), applies a global R rotation. The call convention matches the SSA IR: global_r(%φ, %θ).

global_rz — Global Rz rotation

FieldValue
Device Code0x11
Instruction Code0x03
Full Opcode0x0311
data0–2unused
Stack(θ -- )

Pops 1 float parameter (θ = rotation angle), applies a global Rz rotation. Since there is only one parameter, it is both pushed last and popped first.

cz — Controlled-Z gate

FieldValue
Device Code0x11
Instruction Code0x04
Full Opcode0x0411
data0–2unused
Stack(zone -- )

Pops a zone address and applies a CZ gate across the zone.

Measurement (0x12)

measure — Initiate measurement

FieldValue
Device Code0x12
Instruction Code0x00
Full Opcode0x0012
data0u32 LE arity
data1unused
data2unused
Stack(zone₁ zone₂ … zoneₙ -- future₁ future₂ … futureₙ)

Pops n zone addresses and pushes n measure futures.

await_measure — Wait for measurement result

FieldValue
Device Code0x12
Instruction Code0x01
Full Opcode0x0112
data0–2unused
Stack(future -- array_ref)

Pops a measure future and pushes an array reference containing the measurement results.

Array (0x13)

new_array — Construct array from stack

FieldValue
Device Code0x13
Instruction Code0x00
Full Opcode0x0013
data0[type_tag:8][pad:8][dim0:16]
data1[pad:16][dim1:16]
data2unused
Stack(elem₁ elem₂ … elemₙ -- array_ref)

Constructs an array of dim0 × dim1 elements with element type type_tag. If dim1 is 0, the array is 1-dimensional with dim0 elements.

get_item — Index into array

FieldValue
Device Code0x13
Instruction Code0x01
Full Opcode0x0113
data0u16 LE ndims (upper 16 bits unused)
data1unused
data2unused
Stack(array_ref idx₁ … idxₙ -- value)

Pops ndims index values then the array reference, and pushes the indexed element.

DetectorObservable (0x14)

set_detector — Set detector

FieldValue
Device Code0x14
Instruction Code0x00
Full Opcode0x0014
data0–2unused
Stack(array_ref -- detector_ref)

Pops an array reference and pushes a detector reference.

set_observable — Set observable

FieldValue
Device Code0x14
Instruction Code0x01
Full Opcode0x0114
data0–2unused
Stack(array_ref -- observable_ref)

Pops an array reference and pushes an observable reference.

Reserved Opcode Ranges

RangeOwner
Device 0x00, inst codes 0x000x8FReserved for FLAIR. This project uses only 0x020x06, 0x64, 0xFF.
Device codes 0x010x0EReserved for future FLAIR device types
Device codes 0x0F0xFFProject-specific (currently 0x0F0x14 allocated)

Known FLAIR allocations (device 0x00)

Instruction CodePurpose
0x01const.bool
0x100x17Arithmetic (arith.add_int, arith.add_float, etc.)
0x200x23Comparison (cmp.gt_int, cmp.eq_float, etc.)
0x280x2ABoolean (bool.not, bool.and, bool.or)
0x300x33Waveform (waveform.poly4, waveform.delay, etc.)
0x400x43Channel (channel.emit, channel.play, etc.)
0x500x52Peer messaging
0x600x63Control flow (cf.jump, cf.branch, cf.call)
0x80debug.trace

CLI Reference

The bloqade-bytecode CLI assembles, disassembles, and validates lane-move bytecode programs.

bloqade-bytecode <COMMAND>

Installation

The CLI is bundled in the bloqade-lanes Python wheel and placed on your PATH automatically:

pip install bloqade-lanes

After installation, bloqade-bytecode is available as a command.

Note: The CLI is only included in pre-built platform wheels, not in the source distribution (sdist). If no wheel is available for your platform, use the cargo install method instead.

From source (cargo)

Install the CLI directly from the repository using cargo:

cargo install --path crates/bloqade-lanes-bytecode-cli

This compiles the binary and places it in ~/.cargo/bin/, which is typically on your PATH. No Python installation is required.

Alternatively, build without installing:

just build-cli       # Output: target/release/bloqade-bytecode

The binary can be run in place (./target/release/bloqade-bytecode) or copied to a directory on your PATH.

Development install

For local development, this builds the CLI, stages it into the Python package, and installs everything:

just develop

Testing

just test-rust       # Run Rust tests (core + CLI crates)
just cli-smoke-test  # CLI bytecode validation tests

Commands

assemble

Assemble a text program (.sst) into binary format (.bin).

bloqade-bytecode assemble <INPUT> -o <OUTPUT>
ArgumentDescription
<INPUT>Input text file (.sst)
-o, --output <OUTPUT>Output binary file (required)

Example:

bloqade-bytecode assemble prog.sst -o prog.bin
# assembled 12 instructions -> prog.bin

disassemble

Disassemble a binary program (.bin) into human-readable text format.

bloqade-bytecode disassemble <INPUT> [-o <OUTPUT>]
ArgumentDescription
<INPUT>Input binary file (.bin)
-o, --output <OUTPUT>Output text file (omit to print to stdout)

Examples:

# Print to stdout
bloqade-bytecode disassemble prog.bin

# Write to file
bloqade-bytecode disassemble prog.bin -o prog.sst
# disassembled 12 instructions -> prog.sst

The conversion is semantically lossless: assembling and then disassembling a program preserves its instructions, and the disassembler's canonical text output round-trips through text → binary → text.


validate

Validate a program for correctness. Accepts both text (.sst) and binary formats — the format is auto-detected from the file extension.

bloqade-bytecode validate <INPUT> [--arch <ARCH>] [--simulate-stack]
ArgumentDescription
<INPUT>Input file (.sst = text, otherwise binary)
--arch <ARCH>ArchSpec JSON file for address validation
--simulate-stackRun stack type simulation

Validation levels:

LevelWhenWhat it checks
StructuralAlwaysArity bounds, initial_fill ordering
Address--arch providedLocation, lane, zone, and bus validity against the architecture
Stack simulation--simulate-stackType safety, stack balance

Examples:

# Structural validation only
bloqade-bytecode validate prog.sst
# valid (12 instructions)

# Full validation with architecture and stack simulation
bloqade-bytecode validate prog.sst --arch gemini-logical.json --simulate-stack
# valid (12 instructions)

# Validation failure
bloqade-bytecode validate bad.sst --arch gemini-logical.json
#   [0] initial_fill: invalid location address ...
# error: 1 validation error(s)

arch

Pretty-print an architecture specification.

bloqade-bytecode arch <INPUT>
ArgumentDescription
<INPUT>ArchSpec JSON file

Example output:

ArchSpec v1.0

Geometry: 2 word(s), 10 sites/word
  Word 0: 2x10 grid, 10 sites
    x: start=0, spacing=[5.0]
    y: start=0, spacing=[1.0, 1.0, ...]
    site_indices: (0,0) (0,1) (0,2) ...
    has_cz: (1,0) (1,1) (1,2) ...

Buses: 1 site bus(es), 1 word bus(es)
  Site bus 0: src=[0, 1, 2, 3, 4] dst=[5, 6, 7, 8, 9]
  Word bus 0: src=[0] dst=[1]
  words_with_site_buses: [0, 1]
  sites_with_word_buses: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Zones: 1 zone(s)
  Zone 0: words=[0, 1]
  entangling_zones: [0]
  measurement_mode_zones: [0]

Paths: 1 path(s)
  0xC000000000000005: 3 waypoint(s)
    [1.0, 15.0]
    [1.0, 10.0]
    [1.0, 5.0]

The Paths section is only shown when the ArchSpec includes path data. Each path is identified by its 64-bit encoded lane address (in hex) and lists the AOD waypoints (physical coordinates) that define the transport trajectory.

arch validate

Validate an ArchSpec JSON file for internal consistency.

bloqade-bytecode arch validate <INPUT>
ArgumentDescription
<INPUT>ArchSpec JSON file

Example:

bloqade-bytecode arch validate gemini-logical.json
# arch spec is valid: gemini-logical.json

File Formats

ExtensionFormatDescription
.sstTextHuman-readable bytecode (one instruction per line, ; comments)
.binBinaryCompact binary encoding (BLQD magic header, 16 bytes per instruction)
.jsonJSONArchitecture specification

See also the Instruction Quick Reference for a compact summary of all 24 instructions, or the full Instruction Set for encoding details.