C++ interface contracts#
The CPU, TCU and control records below connect the simulator’s components. See simulation timing for call order and file formats for program and JSON inputs.
Time and cycle units#
Tick stores physical timestamps and durations. TcuCycle identifies logical
TCU cycles in timing control, timing-point intervals and the TCU model.
Serialized cycle fields and instruction operands
remain integers with the units listed below.
Fields |
Unit |
|---|---|
|
Nanoseconds |
Mailbox |
Global simulation ticks, 1 ns each |
|
Global simulation ticks |
Action |
Nanoseconds |
|
TCU cycles since the preceding time point |
TCU |
Logical TCU cycle in the current epoch |
|
Kind-specific CPU edge index or logical TCU cycle; see trace fields |
|
CPU periods after acceptance |
Configured mailbox communication latencies |
Receiver edges, starting strictly after publication |
CPU adapter#
Core calls step() once per CPU edge. The model owns its registers,
PC and pipeline state. CpuPorts::control returns an optional 32-bit result:
absence means the same operation must remain held; a present value completes it.
Use the CPU factory to supply another implementation.
Source: include/qsbit/cpu.hpp.
struct CpuPorts {
MemoryPort &fetch;
MemoryPort &data;
std::function<std::optional<std::uint32_t>(const ControlOperation &)> control;
};
class ICpuCycleModel {
public:
virtual ~ICpuCycleModel() = default;
virtual void step(Tick now, Epoch epoch, CpuPorts &ports) = 0;
virtual void reset(std::uint32_t entry) = 0;
[[nodiscard]] virtual const std::array<std::uint32_t, 32> ®isters() const = 0;
[[nodiscard]] virtual std::uint32_t pc() const = 0;
[[nodiscard]] virtual bool halted() const = 0;
};
TCU transition#
step() checks a due time point and an optional enqueue candidate at one TCU
edge. The preflight callback validates physical events before queue removal.
TcuOutput reports queue insertion, triggered events and delivered
measurement references.
The method computes the logical cycle from its tick and configured start.
Source: include/qsbit/tcu.hpp.
struct TcuOutput {
bool admitted = false;
std::optional<TriggeredEvents> launch;
std::vector<MeasurementReference> fast_delivered;
std::vector<std::uint32_t> synchronizations;
};
class TcuCycleModel {
public:
using Preflight = std::function<void(const TriggeredEvents &)>;
using SyncPreflight = std::function<void(std::span<const std::uint32_t>)>;
TcuCycleModel(TcuConfig profile, Trace &trace, std::size_t sync_capacity = 8);
TcuOutput step(Tick now, Epoch epoch, const TimingEvents *candidate,
const std::vector<Completion> &results, const Preflight &preflight,
bool synchronization_paused = false, const SyncPreflight &sync_preflight = {});
void close(const EndOfStream &end);
void reset(Tick epoch_origin = 0);
[[nodiscard]] bool drained() const;
[[nodiscard]] std::size_t timing_size() const { return timing_.size(); }
[[nodiscard]] std::size_t port_size(std::uint32_t port) const { return events_.at(port).size(); }
[[nodiscard]] Id last_label() const { return last_label_; }
[[nodiscard]] TcuCycle last_due() const { return last_due_; }
[[nodiscard]] const ExecutionFlags &execution_flags() const { return execution_flags_; }
private:
struct PauseState {
bool instruction_supply = false;
bool synchronization = false;
[[nodiscard]] bool paused() const { return instruction_supply || synchronization; }
};
struct TimingState {
bool running;
TcuCycle cycle;
PauseState pause;
};
struct Point {
TimingPoint point;
TcuCycle due;
};
struct Trigger {
TriggeredEvents batch;
std::vector<OperationEvent> cancelled;
std::vector<std::uint32_t> synchronizations;
};
static UnderflowPolicy policy_after(const TimingPoint &point, UnderflowPolicy previous);
[[nodiscard]] TimingState current_timing_state(Tick now, bool synchronization_paused) const;
[[nodiscard]] bool meets_deadline(Tick now, Tick due_tick, const PauseState &pause) const;
[[nodiscard]] std::optional<Trigger> prepare_trigger(Tick now, Epoch epoch,
const TimingState &state,
const Preflight &preflight,
const SyncPreflight &sync_preflight) const;
[[nodiscard]] std::optional<TcuCycle> prepare_admission(Tick now, Epoch epoch,
const TimingEvents &candidate,
const PauseState &pause) const;
void commit_trigger(Tick now, Epoch epoch, TcuCycle cycle, const Trigger &trigger);
void commit_admission(Tick now, Epoch epoch, TcuCycle cycle, const TimingEvents &candidate,
TcuCycle due);
void commit_fast_results(Tick now, Epoch epoch, TcuCycle cycle,
const std::vector<Completion> &results, ExecutionFlags next_flags,
TcuOutput &output);
void update_pause_state(Tick now, Epoch epoch, const TimingState &state, Tick paused_ticks);
const TcuConfig profile_;
Trace &trace_;
std::deque<Point> timing_;
std::vector<std::deque<OperationEvent>> events_;
ExecutionFlags execution_flags_;
TcuCycle last_due_;
Tick start_ = 0;
Tick paused_ticks_ = 0;
std::size_t sync_capacity_ = 8, sync_size_ = 0;
Id last_label_ = 0;
bool closed_ = false;
UnderflowPolicy admitted_policy_ = UnderflowPolicy::Strict;
UnderflowPolicy triggered_policy_ = UnderflowPolicy::Strict;
PauseState pause_;
};
Measurement records#
measurement.hpp defines measurement identities, completion bits and execution
flags without importing device configuration.
struct MeasurementReference {
Epoch epoch = 0;
Id measurement = 0;
std::uint32_t target = 0;
bool operator==(const MeasurementReference &) const = default;
};
struct Completion {
MeasurementReference reference;
bool value = false;
};
Control records#
TimingEvents combines one time point and its resolved events. The manifest lists
exact event IDs; configuration is the profile fingerprint. Per-port counts
are computed from the event list.
EnqueueReply acknowledges a label. EndOfStream identifies the last enqueued
label, with zero for an empty stream. Mailbox envelopes supply epoch and
visibility timing; each core has one control stream.
Source: include/qsbit/control_protocol.hpp.
enum class UnderflowPolicy { Inherit, Strict, PauseWhenEmpty };
struct OperationEvent {
Epoch epoch = 0;
Id id = 0, instruction = 0, label = 0;
std::uint32_t source_port = 0, codeword = 0;
EventSpec action;
std::optional<MeasurementReference> reference;
std::optional<std::uint32_t> core = {};
};
struct TimingPoint {
Epoch epoch = 0;
Id label = 0;
TcuCycle interval;
std::vector<Id> manifest;
std::vector<std::uint32_t> synchronizations = {};
UnderflowPolicy underflow_policy = UnderflowPolicy::Inherit;
};
// One enqueue request: a timing point and its associated operation events.
struct TimingEvents {
TimingPoint point;
std::vector<OperationEvent> events;
std::string configuration;
};
struct EnqueueReply {
Id label = 0;
};
struct EndOfStream {
Id last_label = 0;
};
struct TriggeredEvents {
Epoch epoch = 0;
Id label = 0;
Tick fire_tick = 0;
std::vector<OperationEvent> events;
};
Backend execution#
ControlElectronics commits time-ordered operations to BackendExecution.
BackendExecution owns each operation’s events and measurement references until execution.
IQuantumBackend::execute() consumes the complete batch synchronously and returns
one bit per reference in the measurement operation at the end of the batch,
or an empty vector when no measurement is present.
See backend execution for batch limits and reset behavior.
Source: include/qsbit/backend.hpp.
struct BackendActivity {
Id id;
Tick start, end;
EventSpec action;
std::optional<MeasurementReference> reference;
};
struct BackendEvolution {
Tick start, tick;
std::vector<BackendActivity> drives;
std::vector<BackendActivity> acquisitions;
};
struct BackendGates {
Tick tick;
std::vector<EventSpec> gates;
};
struct BackendMeasurement {
Tick tick;
std::vector<MeasurementReference> references;
};
using BackendOperation = std::variant<BackendEvolution, BackendGates, BackendMeasurement>;
struct BackendExecutionConfig {
std::uint32_t max_batch_operations = 1024;
};
class IQuantumBackend {
public:
virtual ~IQuantumBackend() = default;
virtual void validate(const EventSpec &action) const = 0;
virtual void reset(std::uint32_t qubits, std::uint32_t seed) = 0;
virtual std::vector<bool> execute(Epoch epoch, std::span<const BackendOperation> operations) = 0;
[[nodiscard]] virtual std::vector<std::complex<double>> state() const { return {}; }
[[nodiscard]] virtual std::vector<std::vector<std::complex<double>>> density_matrix() const {
return {};
}
};
Decoder configuration#
DecoderSystemConfig supplies bounded transport parameters and numerical
callbacks. Each callback accepts one measurement window and returns correction
bits. See decoder feedback for timing and register semantics.
struct DecoderConfig {
std::uint32_t id = 0, measurements = 0, outputs = 0;
Tick latency = 1, initiation_interval = 1;
std::function<std::vector<bool>(std::span<const std::uint8_t>)> decode;
};
struct DecoderSystemConfig {
std::uint32_t base = 0x40000000, request_capacity = 16, result_capacity = 16;
Tick link_latency = 1;
std::uint32_t bytes_per_tick = 1, packet_overhead = 16;
std::vector<DecoderConfig> decoders;
};
Trace record#
TraceEvent stores a timestamp, kind and event-specific fields.
The kind determines the meaning of id, cycle and value. Decoder events carry
an explicit DecoderTrace payload with decoder ID, tag and queue counts.
JSONL serialization adds schema: 1.
Source: include/qsbit/trace.hpp.
struct TraceEvent {
TraceEvent(Tick at, Epoch session, std::string type, Id identity = 0, Id timing_label = 0,
Tick local_cycle = 0)
: tick(at), epoch(session), kind(std::move(type)), id(identity), label(timing_label),
cycle(local_cycle) {}
TraceEvent(Tick at, Epoch session, Tick local_cycle, CpuPipelineState state)
: tick(at), epoch(session), kind("CpuPipelineUpdated"), cycle(local_cycle),
payload_(std::move(state)) {}
TraceEvent(Tick at, Epoch session, Id instruction, Tick local_cycle, InstructionRetired state)
: tick(at), epoch(session), kind("InstructionRetired"), id(instruction), cycle(local_cycle),
payload_(std::move(state)) {}
TraceEvent(Tick at, Epoch session, Id request, std::uint32_t core_id, DecoderEvent event);
template <typename T> [[nodiscard]] const T *get_if() const { return std::get_if<T>(&payload_); }
Tick tick = 0;
Epoch epoch = 0;
std::string kind;
Id id = 0, label = 0;
Tick cycle = 0;
std::uint32_t port = 0, codeword = 0;
std::vector<std::uint32_t> targets;
std::string operation, detail;
std::uint64_t value = 0;
std::optional<std::uint32_t> core;
private:
std::variant<std::monostate, CpuPipelineState, InstructionRetired, DecoderEvent> payload_;
};
Runtime installation#
runtime_layout() resolves the installation owned by the running executable.
installation_info(layout) serializes a resolved layout. Python-enabled CLI discovery
initializes the selected environment to record the imported backend location.
See installation discovery.
struct RuntimeLayout {
bool installed = false;
bool python_enabled = false;
std::filesystem::path web_root, python, backend;
std::string version, revision;
};
RuntimeLayout runtime_layout();
std::string installation_info(const RuntimeLayout &layout);
Selected Python session#
PythonSession initializes the caller-selected interpreter and imports the backend
package from that environment. backend_directory() reports the loaded package
location for discovery; it does not select or install a package.
class PythonSession {
public:
explicit PythonSession(const std::string &module_directory);
~PythonSession();
[[nodiscard]] std::string backend_directory() const;
PythonSession(const PythonSession &) = delete;
PythonSession &operator=(const PythonSession &) = delete;
private:
struct Impl;
std::unique_ptr<Impl> impl_;
};