Skip to main content

quantrs2_sim/fpga_acceleration/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::circuit_interfaces::{InterfaceCircuit, InterfaceGate, InterfaceGateType};
6use crate::error::{Result, SimulatorError};
7use scirs2_core::ndarray::Array1;
8use scirs2_core::Complex64;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12/// Bitstream management
13#[derive(Debug, Clone)]
14pub struct BitstreamManager {
15    /// Available bitstreams
16    pub bitstreams: HashMap<String, Bitstream>,
17    /// Current configuration
18    pub current_config: Option<String>,
19    /// Reconfiguration time (ms)
20    pub reconfig_time_ms: f64,
21    /// Partial reconfiguration support
22    pub supports_partial_reconfig: bool,
23}
24/// Pipeline stage
25#[derive(Debug, Clone)]
26pub struct PipelineStage {
27    /// Stage name
28    pub name: String,
29    /// Stage operation
30    pub operation: PipelineOperation,
31    /// Latency (clock cycles)
32    pub latency: usize,
33    /// Throughput (operations per cycle)
34    pub throughput: f64,
35}
36/// Memory access patterns
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum MemoryAccessPattern {
39    Sequential,
40    Random,
41    Strided,
42    BlockTransfer,
43    Streaming,
44}
45/// Timing information
46#[derive(Debug, Clone, Default)]
47pub struct TimingInfo {
48    /// Critical path delay (ns)
49    pub critical_path_delay: f64,
50    /// Setup slack (ns)
51    pub setup_slack: f64,
52    /// Hold slack (ns)
53    pub hold_slack: f64,
54    /// Maximum frequency (MHz)
55    pub max_frequency: f64,
56}
57/// Memory interface types
58#[derive(Debug, Clone)]
59pub struct MemoryInterface {
60    /// Interface type
61    pub interface_type: MemoryInterfaceType,
62    /// Bandwidth (GB/s)
63    pub bandwidth: f64,
64    /// Capacity (GB)
65    pub capacity: f64,
66    /// Latency (ns)
67    pub latency: f64,
68}
69/// FPGA platform types
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
71pub enum FPGAPlatform {
72    /// Intel Arria 10
73    IntelArria10,
74    /// Intel Stratix 10
75    IntelStratix10,
76    /// Intel Agilex 7
77    IntelAgilex7,
78    /// Xilinx Virtex `UltraScale`+
79    XilinxVirtexUltraScale,
80    /// Xilinx Versal ACAP
81    XilinxVersal,
82    /// Xilinx Kintex `UltraScale`+
83    XilinxKintexUltraScale,
84    /// Simulation mode
85    Simulation,
86}
87/// FPGA device information
88#[derive(Debug, Clone)]
89pub struct FPGADeviceInfo {
90    /// Device ID
91    pub device_id: usize,
92    /// Platform type
93    pub platform: FPGAPlatform,
94    /// Logic elements/LUTs
95    pub logic_elements: usize,
96    /// DSP blocks
97    pub dsp_blocks: usize,
98    /// Block RAM (KB)
99    pub block_ram_kb: usize,
100    /// Clock frequency (MHz)
101    pub max_clock_frequency: f64,
102    /// Memory interfaces
103    pub memory_interfaces: Vec<MemoryInterface>,
104    /// `PCIe` lanes
105    pub pcie_lanes: usize,
106    /// Power consumption (W)
107    pub power_consumption: f64,
108    /// Supported arithmetic precision
109    pub supported_precision: Vec<ArithmeticPrecision>,
110}
111impl FPGADeviceInfo {
112    /// Return the published reference specifications for an FPGA platform.
113    ///
114    /// IMPORTANT: this is a static *reference spec table* (datasheet figures
115    /// such as logic-element / DSP-block counts), NOT a hardware-detection
116    /// result. It does not probe a `PCIe` bus or assert that any board is
117    /// present. Only [`FPGAPlatform::Simulation`] corresponds to something this
118    /// build can run: a CPU-side numerical simulation of the gate math (see
119    /// [`FPGAQuantumSimulator::new`]). The real-board rows exist purely as
120    /// reference data for callers that have such hardware elsewhere.
121    #[must_use]
122    pub fn for_platform(platform: FPGAPlatform) -> Self {
123        match platform {
124            FPGAPlatform::IntelArria10 => Self {
125                device_id: 1,
126                platform,
127                logic_elements: 1_150_000,
128                dsp_blocks: 1688,
129                block_ram_kb: 53_000,
130                max_clock_frequency: 400.0,
131                memory_interfaces: vec![MemoryInterface {
132                    interface_type: MemoryInterfaceType::DDR4,
133                    bandwidth: 34.0,
134                    capacity: 32.0,
135                    latency: 200.0,
136                }],
137                pcie_lanes: 16,
138                power_consumption: 100.0,
139                supported_precision: vec![
140                    ArithmeticPrecision::Fixed16,
141                    ArithmeticPrecision::Fixed32,
142                    ArithmeticPrecision::Float32,
143                ],
144            },
145            FPGAPlatform::IntelStratix10 => Self {
146                device_id: 2,
147                platform,
148                logic_elements: 2_800_000,
149                dsp_blocks: 5760,
150                block_ram_kb: 229_000,
151                max_clock_frequency: 500.0,
152                memory_interfaces: vec![
153                    MemoryInterface {
154                        interface_type: MemoryInterfaceType::DDR4,
155                        bandwidth: 68.0,
156                        capacity: 64.0,
157                        latency: 180.0,
158                    },
159                    MemoryInterface {
160                        interface_type: MemoryInterfaceType::HBM2,
161                        bandwidth: 460.0,
162                        capacity: 8.0,
163                        latency: 50.0,
164                    },
165                ],
166                pcie_lanes: 16,
167                power_consumption: 150.0,
168                supported_precision: vec![
169                    ArithmeticPrecision::Fixed16,
170                    ArithmeticPrecision::Fixed32,
171                    ArithmeticPrecision::Float32,
172                    ArithmeticPrecision::Float64,
173                ],
174            },
175            FPGAPlatform::IntelAgilex7 => Self {
176                device_id: 3,
177                platform,
178                logic_elements: 2_500_000,
179                dsp_blocks: 4608,
180                block_ram_kb: 180_000,
181                max_clock_frequency: 600.0,
182                memory_interfaces: vec![
183                    MemoryInterface {
184                        interface_type: MemoryInterfaceType::DDR5,
185                        bandwidth: 102.0,
186                        capacity: 128.0,
187                        latency: 150.0,
188                    },
189                    MemoryInterface {
190                        interface_type: MemoryInterfaceType::HBM3,
191                        bandwidth: 819.0,
192                        capacity: 16.0,
193                        latency: 40.0,
194                    },
195                ],
196                pcie_lanes: 32,
197                power_consumption: 120.0,
198                supported_precision: vec![
199                    ArithmeticPrecision::Fixed16,
200                    ArithmeticPrecision::Fixed32,
201                    ArithmeticPrecision::Float16,
202                    ArithmeticPrecision::Float32,
203                    ArithmeticPrecision::Float64,
204                ],
205            },
206            FPGAPlatform::XilinxVirtexUltraScale => Self {
207                device_id: 4,
208                platform,
209                logic_elements: 1_300_000,
210                dsp_blocks: 6840,
211                block_ram_kb: 75_900,
212                max_clock_frequency: 450.0,
213                memory_interfaces: vec![MemoryInterface {
214                    interface_type: MemoryInterfaceType::DDR4,
215                    bandwidth: 77.0,
216                    capacity: 64.0,
217                    latency: 190.0,
218                }],
219                pcie_lanes: 16,
220                power_consumption: 130.0,
221                supported_precision: vec![
222                    ArithmeticPrecision::Fixed16,
223                    ArithmeticPrecision::Fixed32,
224                    ArithmeticPrecision::Float32,
225                ],
226            },
227            FPGAPlatform::XilinxVersal => Self {
228                device_id: 5,
229                platform,
230                logic_elements: 1_968_000,
231                dsp_blocks: 9024,
232                block_ram_kb: 175_000,
233                max_clock_frequency: 700.0,
234                memory_interfaces: vec![
235                    MemoryInterface {
236                        interface_type: MemoryInterfaceType::DDR5,
237                        bandwidth: 120.0,
238                        capacity: 256.0,
239                        latency: 140.0,
240                    },
241                    MemoryInterface {
242                        interface_type: MemoryInterfaceType::HBM3,
243                        bandwidth: 1024.0,
244                        capacity: 32.0,
245                        latency: 35.0,
246                    },
247                ],
248                pcie_lanes: 32,
249                power_consumption: 100.0,
250                supported_precision: vec![
251                    ArithmeticPrecision::Fixed8,
252                    ArithmeticPrecision::Fixed16,
253                    ArithmeticPrecision::Fixed32,
254                    ArithmeticPrecision::Float16,
255                    ArithmeticPrecision::Float32,
256                    ArithmeticPrecision::Float64,
257                ],
258            },
259            FPGAPlatform::XilinxKintexUltraScale => Self {
260                device_id: 6,
261                platform,
262                logic_elements: 850_000,
263                dsp_blocks: 2928,
264                block_ram_kb: 75_900,
265                max_clock_frequency: 500.0,
266                memory_interfaces: vec![MemoryInterface {
267                    interface_type: MemoryInterfaceType::DDR4,
268                    bandwidth: 60.0,
269                    capacity: 32.0,
270                    latency: 200.0,
271                }],
272                pcie_lanes: 8,
273                power_consumption: 80.0,
274                supported_precision: vec![
275                    ArithmeticPrecision::Fixed16,
276                    ArithmeticPrecision::Fixed32,
277                    ArithmeticPrecision::Float32,
278                ],
279            },
280            FPGAPlatform::Simulation => Self {
281                device_id: 99,
282                platform,
283                logic_elements: 10_000_000,
284                dsp_blocks: 10_000,
285                block_ram_kb: 1_000_000,
286                max_clock_frequency: 1000.0,
287                memory_interfaces: vec![MemoryInterface {
288                    interface_type: MemoryInterfaceType::HBM3,
289                    bandwidth: 2000.0,
290                    capacity: 128.0,
291                    latency: 10.0,
292                }],
293                pcie_lanes: 64,
294                power_consumption: 50.0,
295                supported_precision: vec![
296                    ArithmeticPrecision::Fixed8,
297                    ArithmeticPrecision::Fixed16,
298                    ArithmeticPrecision::Fixed32,
299                    ArithmeticPrecision::Float16,
300                    ArithmeticPrecision::Float32,
301                    ArithmeticPrecision::Float64,
302                ],
303            },
304        }
305    }
306}
307/// Memory pool
308#[derive(Debug, Clone)]
309pub struct MemoryPool {
310    /// Pool name
311    pub name: String,
312    /// Size (KB)
313    pub size_kb: usize,
314    /// Used size (KB)
315    pub used_kb: usize,
316    /// Access pattern
317    pub access_pattern: MemoryAccessPattern,
318    /// Banking configuration
319    pub banks: usize,
320}
321/// Scheduling algorithms
322#[derive(Debug, Clone, Copy, PartialEq, Eq)]
323pub enum SchedulingAlgorithm {
324    FIFO,
325    RoundRobin,
326    PriorityBased,
327    DeadlineAware,
328    BandwidthOptimized,
329}
330/// Memory access scheduler
331#[derive(Debug, Clone)]
332pub struct MemoryAccessScheduler {
333    /// Scheduling algorithm
334    pub algorithm: SchedulingAlgorithm,
335    /// Request queue size
336    pub queue_size: usize,
337    /// Priority levels
338    pub priority_levels: usize,
339}
340/// FPGA quantum processing unit
341#[derive(Debug, Clone)]
342pub struct QuantumProcessingUnit {
343    /// Unit ID
344    pub unit_id: usize,
345    /// Supported gate types
346    pub supported_gates: Vec<InterfaceGateType>,
347    /// Pipeline stages
348    pub pipeline_stages: Vec<PipelineStage>,
349    /// Local memory (KB)
350    pub local_memory_kb: usize,
351    /// Processing frequency (MHz)
352    pub frequency: f64,
353    /// Utilization percentage
354    pub utilization: f64,
355}
356/// FPGA quantum simulator
357pub struct FPGAQuantumSimulator {
358    /// Configuration
359    config: FPGAConfig,
360    /// Device information
361    device_info: FPGADeviceInfo,
362    /// Processing units
363    processing_units: Vec<QuantumProcessingUnit>,
364    /// Generated HDL modules
365    pub hdl_modules: HashMap<String, HDLModule>,
366    /// Performance statistics
367    pub stats: FPGAStats,
368    /// Memory manager
369    pub memory_manager: FPGAMemoryManager,
370    /// Bitstream manager
371    pub bitstream_manager: BitstreamManager,
372}
373impl FPGAQuantumSimulator {
374    /// Create a new FPGA quantum simulator.
375    ///
376    /// HONEST BEHAVIOR: this build links no FPGA runtime / board driver, so NO
377    /// physical FPGA is ever programmed or used - regardless of the `platform`
378    /// requested. This constructor always builds a CPU-side *numerical
379    /// simulation* of the FPGA gate math: the gate applications compute the exact
380    /// state-vector linear algebra on the CPU. The `platform` field only selects
381    /// which datasheet reference-spec table to model (see
382    /// [`FPGADeviceInfo::for_platform`]); it does not detect or claim real
383    /// silicon. [`Self::is_fpga_available`] therefore always returns `false`.
384    pub fn new(config: FPGAConfig) -> Result<Self> {
385        let device_info = FPGADeviceInfo::for_platform(config.platform);
386        let processing_units = Self::create_processing_units(&config, &device_info)?;
387        let memory_manager = Self::create_memory_manager(&config, &device_info)?;
388        let bitstream_manager = Self::create_bitstream_manager(&config)?;
389        let mut simulator = Self {
390            config,
391            device_info,
392            processing_units,
393            hdl_modules: HashMap::new(),
394            stats: FPGAStats::default(),
395            memory_manager,
396            bitstream_manager,
397        };
398        simulator.generate_hdl_modules()?;
399        simulator.load_default_bitstream()?;
400        Ok(simulator)
401    }
402    /// Create processing units
403    pub fn create_processing_units(
404        config: &FPGAConfig,
405        device_info: &FPGADeviceInfo,
406    ) -> Result<Vec<QuantumProcessingUnit>> {
407        let mut units = Vec::new();
408        for i in 0..config.num_processing_units {
409            let pipeline_stages = vec![
410                PipelineStage {
411                    name: "Fetch".to_string(),
412                    operation: PipelineOperation::Fetch,
413                    latency: 1,
414                    throughput: 1.0,
415                },
416                PipelineStage {
417                    name: "Decode".to_string(),
418                    operation: PipelineOperation::Decode,
419                    latency: 1,
420                    throughput: 1.0,
421                },
422                PipelineStage {
423                    name: "Address".to_string(),
424                    operation: PipelineOperation::AddressCalculation,
425                    latency: 1,
426                    throughput: 1.0,
427                },
428                PipelineStage {
429                    name: "MemRead".to_string(),
430                    operation: PipelineOperation::MemoryRead,
431                    latency: 2,
432                    throughput: 0.5,
433                },
434                PipelineStage {
435                    name: "Execute".to_string(),
436                    operation: PipelineOperation::GateExecution,
437                    latency: 3,
438                    throughput: 1.0,
439                },
440                PipelineStage {
441                    name: "MemWrite".to_string(),
442                    operation: PipelineOperation::MemoryWrite,
443                    latency: 2,
444                    throughput: 0.5,
445                },
446                PipelineStage {
447                    name: "Writeback".to_string(),
448                    operation: PipelineOperation::Writeback,
449                    latency: 1,
450                    throughput: 1.0,
451                },
452            ];
453            let unit = QuantumProcessingUnit {
454                unit_id: i,
455                supported_gates: vec![
456                    InterfaceGateType::Hadamard,
457                    InterfaceGateType::PauliX,
458                    InterfaceGateType::PauliY,
459                    InterfaceGateType::PauliZ,
460                    InterfaceGateType::CNOT,
461                    InterfaceGateType::CZ,
462                    InterfaceGateType::RX(0.0),
463                    InterfaceGateType::RY(0.0),
464                    InterfaceGateType::RZ(0.0),
465                ],
466                pipeline_stages,
467                local_memory_kb: device_info.block_ram_kb / config.num_processing_units,
468                frequency: config.clock_frequency,
469                utilization: 0.0,
470            };
471            units.push(unit);
472        }
473        Ok(units)
474    }
475    /// Create memory manager
476    fn create_memory_manager(
477        config: &FPGAConfig,
478        device_info: &FPGADeviceInfo,
479    ) -> Result<FPGAMemoryManager> {
480        let mut onchip_pools = HashMap::new();
481        onchip_pools.insert(
482            "state_vector".to_string(),
483            MemoryPool {
484                name: "state_vector".to_string(),
485                size_kb: device_info.block_ram_kb / 2,
486                used_kb: 0,
487                access_pattern: MemoryAccessPattern::Sequential,
488                banks: 16,
489            },
490        );
491        onchip_pools.insert(
492            "gate_cache".to_string(),
493            MemoryPool {
494                name: "gate_cache".to_string(),
495                size_kb: device_info.block_ram_kb / 4,
496                used_kb: 0,
497                access_pattern: MemoryAccessPattern::Random,
498                banks: 8,
499            },
500        );
501        onchip_pools.insert(
502            "instruction_cache".to_string(),
503            MemoryPool {
504                name: "instruction_cache".to_string(),
505                size_kb: device_info.block_ram_kb / 8,
506                used_kb: 0,
507                access_pattern: MemoryAccessPattern::Sequential,
508                banks: 4,
509            },
510        );
511        let external_interfaces: Vec<ExternalMemoryInterface> = device_info
512            .memory_interfaces
513            .iter()
514            .enumerate()
515            .map(|(i, _)| ExternalMemoryInterface {
516                interface_id: i,
517                interface_type: device_info.memory_interfaces[i].interface_type,
518                controller: format!("mem_ctrl_{i}"),
519                utilization: 0.0,
520            })
521            .collect();
522        let access_scheduler = MemoryAccessScheduler {
523            algorithm: SchedulingAlgorithm::BandwidthOptimized,
524            queue_size: 64,
525            priority_levels: 4,
526        };
527        Ok(FPGAMemoryManager {
528            onchip_pools,
529            external_interfaces,
530            access_scheduler,
531            total_memory_kb: device_info.block_ram_kb,
532            used_memory_kb: 0,
533        })
534    }
535    /// Create bitstream manager
536    fn create_bitstream_manager(config: &FPGAConfig) -> Result<BitstreamManager> {
537        let mut bitstreams = HashMap::new();
538        bitstreams.insert(
539            "quantum_basic".to_string(),
540            Bitstream {
541                name: "quantum_basic".to_string(),
542                target_config: "Basic quantum gates".to_string(),
543                size_kb: 50_000,
544                config_time_ms: 200.0,
545                supported_algorithms: vec![
546                    "VQE".to_string(),
547                    "QAOA".to_string(),
548                    "Grover".to_string(),
549                ],
550            },
551        );
552        bitstreams.insert(
553            "quantum_advanced".to_string(),
554            Bitstream {
555                name: "quantum_advanced".to_string(),
556                target_config: "Advanced quantum algorithms".to_string(),
557                size_kb: 75_000,
558                config_time_ms: 300.0,
559                supported_algorithms: vec![
560                    "Shor".to_string(),
561                    "QFT".to_string(),
562                    "Phase_Estimation".to_string(),
563                ],
564            },
565        );
566        bitstreams.insert(
567            "quantum_ml".to_string(),
568            Bitstream {
569                name: "quantum_ml".to_string(),
570                target_config: "Quantum machine learning".to_string(),
571                size_kb: 60_000,
572                config_time_ms: 250.0,
573                supported_algorithms: vec![
574                    "QML".to_string(),
575                    "Variational_Circuits".to_string(),
576                    "Quantum_GAN".to_string(),
577                ],
578            },
579        );
580        Ok(BitstreamManager {
581            bitstreams,
582            current_config: None,
583            reconfig_time_ms: 200.0,
584            supports_partial_reconfig: matches!(
585                config.platform,
586                FPGAPlatform::IntelStratix10
587                    | FPGAPlatform::IntelAgilex7
588                    | FPGAPlatform::XilinxVersal
589            ),
590        })
591    }
592    /// Generate HDL modules for quantum operations
593    fn generate_hdl_modules(&mut self) -> Result<()> {
594        self.generate_single_qubit_module()?;
595        self.generate_two_qubit_module()?;
596        self.generate_control_unit_module()?;
597        self.generate_memory_controller_module()?;
598        self.generate_arithmetic_unit_module()?;
599        Ok(())
600    }
601    /// Generate single qubit gate HDL module.
602    ///
603    /// Only `SystemVerilog` and `OpenCL` have a complete generator. Other HDL
604    /// targets are not implemented and return an honest error rather than a stub
605    /// string masquerading as synthesizable HDL.
606    fn generate_single_qubit_module(&mut self) -> Result<()> {
607        let hdl_code = match self.config.hdl_target {
608            HDLTarget::SystemVerilog => self.generate_single_qubit_systemverilog(),
609            HDLTarget::OpenCL => self.generate_single_qubit_opencl(),
610            other => {
611                return Err(SimulatorError::UnsupportedOperation(format!(
612                    "FPGA HDL generation: target {other:?} is not implemented \
613                     for single_qubit_gate (only SystemVerilog and OpenCL are)"
614                )));
615            }
616        };
617        let module = HDLModule {
618            name: "single_qubit_gate".to_string(),
619            hdl_code,
620            resource_utilization: ResourceUtilization {
621                luts: 1000,
622                flip_flops: 500,
623                dsp_blocks: 8,
624                bram_kb: 2,
625                utilization_percent: 5.0,
626            },
627            timing_info: TimingInfo {
628                critical_path_delay: 3.2,
629                setup_slack: 0.8,
630                hold_slack: 1.5,
631                max_frequency: 312.5,
632            },
633            module_type: ModuleType::SingleQubitGate,
634        };
635        self.hdl_modules
636            .insert("single_qubit_gate".to_string(), module);
637        Ok(())
638    }
639    /// Generate `SystemVerilog` code for single qubit gates
640    fn generate_single_qubit_systemverilog(&self) -> String {
641        format!(
642            r"
643// Single Qubit Gate Processing Unit
644// Generated for platform: {:?}
645// Clock frequency: {:.1} MHz
646// Data path width: {} bits
647
648module single_qubit_gate #(
649    parameter DATA_WIDTH = {},
650    parameter ADDR_WIDTH = 20,
651    parameter PIPELINE_DEPTH = {}
652) (
653    input  logic                    clk,
654    input  logic                    rst_n,
655    input  logic                    enable,
656
657    // Gate parameters
658    input  logic [1:0]              gate_type,  // 00: H, 01: X, 10: Y, 11: Z
659    input  logic [DATA_WIDTH-1:0]   gate_param, // For rotation gates
660    input  logic [ADDR_WIDTH-1:0]   target_qubit,
661
662    // State vector interface
663    input  logic [DATA_WIDTH-1:0]   state_real_in,
664    input  logic [DATA_WIDTH-1:0]   state_imag_in,
665    output logic [DATA_WIDTH-1:0]   state_real_out,
666    output logic [DATA_WIDTH-1:0]   state_imag_out,
667
668    // Control signals
669    output logic                    ready,
670    output logic                    valid_out
671);
672
673    // Pipeline registers
674    logic [DATA_WIDTH-1:0] pipeline_real [0:PIPELINE_DEPTH-1];
675    logic [DATA_WIDTH-1:0] pipeline_imag [0:PIPELINE_DEPTH-1];
676    logic [1:0] pipeline_gate_type [0:PIPELINE_DEPTH-1];
677    logic [PIPELINE_DEPTH-1:0] pipeline_valid;
678
679    // Gate matrices (pre-computed constants)
680    localparam real SQRT2_INV = 0.7_071_067_811_865_476;
681
682    // Complex multiplication units
683    logic [DATA_WIDTH-1:0] mult_real, mult_imag;
684    logic [DATA_WIDTH-1:0] add_real, add_imag;
685
686    // DSP blocks for complex arithmetic
687    logic [DATA_WIDTH*2-1:0] dsp_mult_result;
688    logic [DATA_WIDTH-1:0] dsp_add_result;
689
690    always_ff @(posedge clk or negedge rst_n) begin
691        if (!rst_n) begin
692            pipeline_valid <= '0;
693            ready <= 1'b1;
694        end else if (enable) begin
695            // Pipeline stage advancement
696            for (int i = PIPELINE_DEPTH-1; i > 0; i--) begin
697                pipeline_real[i] <= pipeline_real[i-1];
698                pipeline_imag[i] <= pipeline_imag[i-1];
699                pipeline_gate_type[i] <= pipeline_gate_type[i-1];
700            end
701
702            // Input stage
703            pipeline_real[0] <= state_real_in;
704            pipeline_imag[0] <= state_imag_in;
705            pipeline_gate_type[0] <= gate_type;
706
707            // Valid signal pipeline
708            pipeline_valid <= {{pipeline_valid[PIPELINE_DEPTH-2:0], enable}};
709        end
710    end
711
712    // Gate operation logic (combinational)
713    always_comb begin
714        case (pipeline_gate_type[PIPELINE_DEPTH-1])
715            2'b00: begin // Hadamard
716                state_real_out = (pipeline_real[PIPELINE_DEPTH-1] + pipeline_imag[PIPELINE_DEPTH-1]) * SQRT2_INV;
717                state_imag_out = (pipeline_real[PIPELINE_DEPTH-1] - pipeline_imag[PIPELINE_DEPTH-1]) * SQRT2_INV;
718            end
719            2'b01: begin // Pauli-X
720                state_real_out = pipeline_imag[PIPELINE_DEPTH-1];
721                state_imag_out = pipeline_real[PIPELINE_DEPTH-1];
722            end
723            2'b10: begin // Pauli-Y
724                state_real_out = -pipeline_imag[PIPELINE_DEPTH-1];
725                state_imag_out = pipeline_real[PIPELINE_DEPTH-1];
726            end
727            2'b11: begin // Pauli-Z
728                state_real_out = pipeline_real[PIPELINE_DEPTH-1];
729                state_imag_out = -pipeline_imag[PIPELINE_DEPTH-1];
730            end
731            default: begin
732                state_real_out = pipeline_real[PIPELINE_DEPTH-1];
733                state_imag_out = pipeline_imag[PIPELINE_DEPTH-1];
734            end
735        endcase
736
737        valid_out = pipeline_valid[PIPELINE_DEPTH-1];
738    end
739
740endmodule
741",
742            self.config.platform,
743            self.config.clock_frequency,
744            self.config.data_path_width,
745            self.config.data_path_width,
746            self.config.pipeline_depth
747        )
748    }
749    /// Generate `OpenCL` code for single qubit gates
750    fn generate_single_qubit_opencl(&self) -> String {
751        r"
752// OpenCL kernel for single qubit gates
753__kernel void single_qubit_gate(
754    __global float2* state,
755    __global const float* gate_matrix,
756    const int target_qubit,
757    const int num_qubits
758) {
759    const int global_id = get_global_id(0);
760    const int total_states = 1 << num_qubits;
761
762    if (global_id >= total_states / 2) return;
763
764    const int target_mask = 1 << target_qubit;
765    const int i = global_id;
766    const int j = i | target_mask;
767
768    if ((i & target_mask) == 0) {
769        float2 state_i = state[i];
770        float2 state_j = state[j];
771
772        // Apply 2x2 gate matrix
773        state[i] = (float2)(
774            gate_matrix[0] * state_i.x - gate_matrix[1] * state_i.y +
775            gate_matrix[2] * state_j.x - gate_matrix[3] * state_j.y,
776            gate_matrix[0] * state_i.y + gate_matrix[1] * state_i.x +
777            gate_matrix[2] * state_j.y + gate_matrix[3] * state_j.x
778        );
779
780        state[j] = (float2)(
781            gate_matrix[4] * state_i.x - gate_matrix[5] * state_i.y +
782            gate_matrix[6] * state_j.x - gate_matrix[7] * state_j.y,
783            gate_matrix[4] * state_i.y + gate_matrix[5] * state_i.x +
784            gate_matrix[6] * state_j.y + gate_matrix[7] * state_j.x
785        );
786    }
787}
788"
789        .to_string()
790    }
791    /// Register the two-qubit-gate module metadata.
792    ///
793    /// No HDL generator is implemented for this module yet, so `hdl_code` is
794    /// left empty (rather than a stub comment pretending to be synthesizable).
795    /// The resource/timing figures are datasheet-style reference estimates.
796    /// [`Self::export_hdl`] returns an honest error for modules with no code.
797    fn generate_two_qubit_module(&mut self) -> Result<()> {
798        let hdl_code = String::new();
799        let module = HDLModule {
800            name: "two_qubit_gate".to_string(),
801            hdl_code,
802            resource_utilization: ResourceUtilization {
803                luts: 2500,
804                flip_flops: 1200,
805                dsp_blocks: 16,
806                bram_kb: 8,
807                utilization_percent: 12.0,
808            },
809            timing_info: TimingInfo {
810                critical_path_delay: 4.5,
811                setup_slack: 0.5,
812                hold_slack: 1.2,
813                max_frequency: 222.2,
814            },
815            module_type: ModuleType::TwoQubitGate,
816        };
817        self.hdl_modules
818            .insert("two_qubit_gate".to_string(), module);
819        Ok(())
820    }
821    /// Register the control-unit module metadata (no HDL generator implemented).
822    ///
823    /// See [`Self::generate_two_qubit_module`] for why `hdl_code` is empty.
824    fn generate_control_unit_module(&mut self) -> Result<()> {
825        let hdl_code = String::new();
826        let module = HDLModule {
827            name: "control_unit".to_string(),
828            hdl_code,
829            resource_utilization: ResourceUtilization {
830                luts: 5000,
831                flip_flops: 3000,
832                dsp_blocks: 4,
833                bram_kb: 16,
834                utilization_percent: 25.0,
835            },
836            timing_info: TimingInfo {
837                critical_path_delay: 2.8,
838                setup_slack: 1.2,
839                hold_slack: 2.0,
840                max_frequency: 357.1,
841            },
842            module_type: ModuleType::ControlUnit,
843        };
844        self.hdl_modules.insert("control_unit".to_string(), module);
845        Ok(())
846    }
847    /// Register the memory-controller module metadata (no HDL generator).
848    ///
849    /// See [`Self::generate_two_qubit_module`] for why `hdl_code` is empty.
850    fn generate_memory_controller_module(&mut self) -> Result<()> {
851        let hdl_code = String::new();
852        let module = HDLModule {
853            name: "memory_controller".to_string(),
854            hdl_code,
855            resource_utilization: ResourceUtilization {
856                luts: 3000,
857                flip_flops: 2000,
858                dsp_blocks: 0,
859                bram_kb: 32,
860                utilization_percent: 15.0,
861            },
862            timing_info: TimingInfo {
863                critical_path_delay: 3.5,
864                setup_slack: 0.9,
865                hold_slack: 1.8,
866                max_frequency: 285.7,
867            },
868            module_type: ModuleType::MemoryController,
869        };
870        self.hdl_modules
871            .insert("memory_controller".to_string(), module);
872        Ok(())
873    }
874    /// Register the arithmetic-unit module metadata (no HDL generator).
875    ///
876    /// See [`Self::generate_two_qubit_module`] for why `hdl_code` is empty.
877    fn generate_arithmetic_unit_module(&mut self) -> Result<()> {
878        let hdl_code = String::new();
879        let module = HDLModule {
880            name: "arithmetic_unit".to_string(),
881            hdl_code,
882            resource_utilization: ResourceUtilization {
883                luts: 4000,
884                flip_flops: 2500,
885                dsp_blocks: 32,
886                bram_kb: 4,
887                utilization_percent: 20.0,
888            },
889            timing_info: TimingInfo {
890                critical_path_delay: 3.8,
891                setup_slack: 0.7,
892                hold_slack: 1.5,
893                max_frequency: 263.2,
894            },
895            module_type: ModuleType::ArithmeticUnit,
896        };
897        self.hdl_modules
898            .insert("arithmetic_unit".to_string(), module);
899        Ok(())
900    }
901    /// Load default bitstream (model bookkeeping only; no real device program).
902    ///
903    /// In the CPU simulation there is no board to program, so this only records
904    /// the selected configuration. No fabricated configuration latency is added.
905    fn load_default_bitstream(&mut self) -> Result<()> {
906        self.bitstream_manager.current_config = Some("quantum_basic".to_string());
907        self.stats.reconfigurations += 1;
908        Ok(())
909    }
910    /// Execute a quantum circuit (CPU numerical simulation of the FPGA gate math).
911    pub fn execute_circuit(&mut self, circuit: &InterfaceCircuit) -> Result<Array1<Complex64>> {
912        let start_time = std::time::Instant::now();
913        let mut state = Array1::zeros(1 << circuit.num_qubits);
914        state[0] = Complex64::new(1.0, 0.0);
915        for gate in &circuit.gates {
916            state = self.apply_gate_fpga(&state, gate)?;
917        }
918        let execution_time = start_time.elapsed().as_secs_f64() * 1000.0;
919        // Honest: in a CPU simulation we cannot measure FPGA clock cycles. We
920        // record the real measured wall-time and count gates applied; we do not
921        // synthesize a clock-cycle figure from CPU time.
922        self.stats
923            .update_operation(execution_time, circuit.gates.len() as u64);
924        self.update_utilization();
925        Ok(state)
926    }
927    /// Apply a quantum gate (CPU numerical simulation of the FPGA gate math).
928    fn apply_gate_fpga(
929        &mut self,
930        state: &Array1<Complex64>,
931        gate: &InterfaceGate,
932    ) -> Result<Array1<Complex64>> {
933        let unit_id = self.select_processing_unit(gate)?;
934        let result = match &gate.gate_type {
935            InterfaceGateType::Hadamard
936            | InterfaceGateType::PauliX
937            | InterfaceGateType::PauliY
938            | InterfaceGateType::PauliZ => self.apply_single_qubit_gate_fpga(state, gate, unit_id),
939            InterfaceGateType::CNOT | InterfaceGateType::CZ => {
940                self.apply_two_qubit_gate_fpga(state, gate, unit_id)
941            }
942            InterfaceGateType::RX(_) | InterfaceGateType::RY(_) | InterfaceGateType::RZ(_) => {
943                self.apply_rotation_gate_fpga(state, gate, unit_id)
944            }
945            other => {
946                return Err(SimulatorError::UnsupportedOperation(format!(
947                    "FPGA simulation: gate {other:?} is not implemented"
948                )));
949            }
950        };
951        if result.is_ok() {
952            self.processing_units[unit_id].utilization += 1.0;
953        }
954        result
955    }
956    /// Select processing unit for gate execution
957    fn select_processing_unit(&self, gate: &InterfaceGate) -> Result<usize> {
958        let mut best_unit = 0;
959        let mut min_utilization = f64::INFINITY;
960        for (i, unit) in self.processing_units.iter().enumerate() {
961            if unit.supported_gates.contains(&gate.gate_type) && unit.utilization < min_utilization
962            {
963                best_unit = i;
964                min_utilization = unit.utilization;
965            }
966        }
967        Ok(best_unit)
968    }
969    /// Apply a single-qubit gate (CPU numerical simulation of the gate math).
970    ///
971    /// Uses the gate's canonical 2x2 unitary, so it correctly handles every
972    /// single-qubit gate including rotations `RX/RY/RZ` (the previous version
973    /// silently no-op'd rotations). No fabricated pipeline latency is injected.
974    pub fn apply_single_qubit_gate_fpga(
975        &self,
976        state: &Array1<Complex64>,
977        gate: &InterfaceGate,
978        _unit_id: usize,
979    ) -> Result<Array1<Complex64>> {
980        if gate.qubits.is_empty() {
981            return Err(SimulatorError::InvalidInput(
982                "single-qubit gate has no target qubit".to_string(),
983            ));
984        }
985        let target_qubit = gate.qubits[0];
986        let num_qubits = state.len().trailing_zeros() as usize;
987        if state.len() != 1usize << num_qubits {
988            return Err(SimulatorError::DimensionMismatch(format!(
989                "State length {} is not a power of two",
990                state.len()
991            )));
992        }
993        if target_qubit >= num_qubits {
994            return Err(SimulatorError::IndexOutOfBounds(target_qubit));
995        }
996        let unitary = gate.unitary_matrix()?;
997        let mut result = state.clone();
998        let target_mask = 1usize << target_qubit;
999        for i in 0..state.len() {
1000            if i & target_mask == 0 {
1001                let j = i | target_mask;
1002                let amp_0 = state[i];
1003                let amp_1 = state[j];
1004                result[i] = unitary[[0, 0]] * amp_0 + unitary[[0, 1]] * amp_1;
1005                result[j] = unitary[[1, 0]] * amp_0 + unitary[[1, 1]] * amp_1;
1006            }
1007        }
1008        Ok(result)
1009    }
1010    /// Apply a two-qubit gate (CPU numerical simulation of the FPGA gate math).
1011    ///
1012    /// No fabricated pipeline latency is injected.
1013    fn apply_two_qubit_gate_fpga(
1014        &self,
1015        state: &Array1<Complex64>,
1016        gate: &InterfaceGate,
1017        _unit_id: usize,
1018    ) -> Result<Array1<Complex64>> {
1019        if gate.qubits.len() < 2 {
1020            return Err(SimulatorError::InvalidInput(
1021                "two-qubit gate requires two qubits".to_string(),
1022            ));
1023        }
1024        let control = gate.qubits[0];
1025        let target = gate.qubits[1];
1026        let mut result = state.clone();
1027        match gate.gate_type {
1028            InterfaceGateType::CNOT => {
1029                for i in 0..state.len() {
1030                    if ((i >> control) & 1) == 1 {
1031                        let j = i ^ (1 << target);
1032                        if j < state.len() && i != j {
1033                            let temp = result[i];
1034                            result[i] = result[j];
1035                            result[j] = temp;
1036                        }
1037                    }
1038                }
1039            }
1040            InterfaceGateType::CZ => {
1041                for i in 0..state.len() {
1042                    if ((i >> control) & 1) == 1 && ((i >> target) & 1) == 1 {
1043                        result[i] = -result[i];
1044                    }
1045                }
1046            }
1047            _ => {}
1048        }
1049        Ok(result)
1050    }
1051    /// Apply rotation gate using FPGA
1052    fn apply_rotation_gate_fpga(
1053        &self,
1054        state: &Array1<Complex64>,
1055        gate: &InterfaceGate,
1056        unit_id: usize,
1057    ) -> Result<Array1<Complex64>> {
1058        self.apply_single_qubit_gate_fpga(state, gate, unit_id)
1059    }
1060    /// Update FPGA utilization metrics from the model's own bookkeeping.
1061    ///
1062    /// Only `fpga_utilization` (derived from the per-unit operation counts the
1063    /// model actually tracks) is set here. `pipeline_efficiency` and
1064    /// `memory_bandwidth_utilization` are intentionally left untouched: there is
1065    /// no real pipeline or memory bus to measure in a CPU simulation, so we do
1066    /// NOT fabricate fixed efficiency numbers for them.
1067    fn update_utilization(&mut self) {
1068        let total_utilization: f64 = self.processing_units.iter().map(|u| u.utilization).sum();
1069        self.stats.fpga_utilization = total_utilization / self.processing_units.len() as f64;
1070    }
1071    /// Get device information
1072    #[must_use]
1073    pub const fn get_device_info(&self) -> &FPGADeviceInfo {
1074        &self.device_info
1075    }
1076    /// Get performance statistics
1077    #[must_use]
1078    pub const fn get_stats(&self) -> &FPGAStats {
1079        &self.stats
1080    }
1081    /// Get HDL modules
1082    #[must_use]
1083    pub const fn get_hdl_modules(&self) -> &HashMap<String, HDLModule> {
1084        &self.hdl_modules
1085    }
1086    /// Select a different bitstream configuration (model bookkeeping only).
1087    ///
1088    /// In the CPU simulation there is no board to reprogram, so this validates
1089    /// and records the selection without fabricating a reconfiguration latency.
1090    pub fn reconfigure(&mut self, bitstream_name: &str) -> Result<()> {
1091        if !self
1092            .bitstream_manager
1093            .bitstreams
1094            .contains_key(bitstream_name)
1095        {
1096            return Err(SimulatorError::InvalidInput(format!(
1097                "Bitstream {bitstream_name} not found"
1098            )));
1099        }
1100        self.bitstream_manager.current_config = Some(bitstream_name.to_string());
1101        self.stats.reconfigurations += 1;
1102        Ok(())
1103    }
1104    /// Whether a *real* FPGA board is available.
1105    ///
1106    /// HONEST: this build links no FPGA runtime, so a physical board is never
1107    /// available. This returns `false` even when the CPU `Simulation` device is
1108    /// in use - that is a numerical model, not a programmed FPGA.
1109    #[must_use]
1110    pub const fn is_fpga_available(&self) -> bool {
1111        false
1112    }
1113    /// Export HDL code for synthesis.
1114    ///
1115    /// Returns an honest error for unknown modules and for modules that have no
1116    /// HDL generator implemented yet (empty `hdl_code`) - we never hand back a
1117    /// stub comment dressed up as synthesizable HDL.
1118    pub fn export_hdl(&self, module_name: &str) -> Result<String> {
1119        let module = self.hdl_modules.get(module_name).ok_or_else(|| {
1120            SimulatorError::InvalidInput(format!("Module {module_name} not found"))
1121        })?;
1122        if module.hdl_code.is_empty() {
1123            return Err(SimulatorError::UnsupportedOperation(format!(
1124                "FPGA HDL export: no HDL generator implemented for module \
1125                 '{module_name}' (only single_qubit_gate is generated)"
1126            )));
1127        }
1128        Ok(module.hdl_code.clone())
1129    }
1130}
1131/// FPGA bitstream
1132#[derive(Debug, Clone)]
1133pub struct Bitstream {
1134    /// Bitstream name
1135    pub name: String,
1136    /// Target configuration
1137    pub target_config: String,
1138    /// Size (KB)
1139    pub size_kb: usize,
1140    /// Configuration time (ms)
1141    pub config_time_ms: f64,
1142    /// Supported quantum algorithms
1143    pub supported_algorithms: Vec<String>,
1144}
1145/// Arithmetic precision types
1146#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1147pub enum ArithmeticPrecision {
1148    Fixed8,
1149    Fixed16,
1150    Fixed32,
1151    Float16,
1152    Float32,
1153    Float64,
1154    CustomFixed(u32),
1155    CustomFloat(u32, u32),
1156}
1157/// Pipeline operations
1158#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1159pub enum PipelineOperation {
1160    Fetch,
1161    Decode,
1162    AddressCalculation,
1163    MemoryRead,
1164    GateExecution,
1165    MemoryWrite,
1166    Writeback,
1167}
1168/// HDL module representation
1169#[derive(Debug, Clone)]
1170pub struct HDLModule {
1171    /// Module name
1172    pub name: String,
1173    /// HDL code
1174    pub hdl_code: String,
1175    /// Resource utilization
1176    pub resource_utilization: ResourceUtilization,
1177    /// Timing information
1178    pub timing_info: TimingInfo,
1179    /// Module type
1180    pub module_type: ModuleType,
1181}
1182/// Memory interface types
1183#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1184pub enum MemoryInterfaceType {
1185    DDR4,
1186    DDR5,
1187    HBM2,
1188    HBM3,
1189    GDDR6,
1190    OnChipRAM,
1191}
1192/// Hardware description language targets
1193#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1194pub enum HDLTarget {
1195    Verilog,
1196    SystemVerilog,
1197    VHDL,
1198    Chisel,
1199    HLS,
1200    OpenCL,
1201}
1202/// Module types
1203#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1204pub enum ModuleType {
1205    SingleQubitGate,
1206    TwoQubitGate,
1207    ControlUnit,
1208    MemoryController,
1209    ArithmeticUnit,
1210    StateVectorUnit,
1211}
1212/// Resource utilization
1213#[derive(Debug, Clone, Default)]
1214pub struct ResourceUtilization {
1215    /// LUTs used
1216    pub luts: usize,
1217    /// FFs used
1218    pub flip_flops: usize,
1219    /// DSP blocks used
1220    pub dsp_blocks: usize,
1221    /// Block RAM used (KB)
1222    pub bram_kb: usize,
1223    /// Utilization percentage
1224    pub utilization_percent: f64,
1225}
1226/// FPGA memory manager
1227#[derive(Debug, Clone)]
1228pub struct FPGAMemoryManager {
1229    /// On-chip memory pools
1230    pub onchip_pools: HashMap<String, MemoryPool>,
1231    /// External memory interfaces
1232    pub external_interfaces: Vec<ExternalMemoryInterface>,
1233    /// Memory access scheduler
1234    pub access_scheduler: MemoryAccessScheduler,
1235    /// Total available memory (KB)
1236    pub total_memory_kb: usize,
1237    /// Used memory (KB)
1238    pub used_memory_kb: usize,
1239}
1240/// FPGA performance statistics
1241#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1242pub struct FPGAStats {
1243    /// Total gate operations
1244    pub total_gate_operations: usize,
1245    /// Total execution time (ms)
1246    pub total_execution_time: f64,
1247    /// Average gate time (ns)
1248    pub avg_gate_time: f64,
1249    /// Clock cycles consumed
1250    pub total_clock_cycles: u64,
1251    /// FPGA utilization
1252    pub fpga_utilization: f64,
1253    /// Memory bandwidth utilization
1254    pub memory_bandwidth_utilization: f64,
1255    /// Pipeline efficiency
1256    pub pipeline_efficiency: f64,
1257    /// Reconfiguration count
1258    pub reconfigurations: usize,
1259    /// Total reconfiguration time (ms)
1260    pub total_reconfig_time: f64,
1261    /// Power consumption (W)
1262    pub power_consumption: f64,
1263}
1264impl FPGAStats {
1265    /// Update statistics after operation
1266    pub fn update_operation(&mut self, execution_time: f64, clock_cycles: u64) {
1267        self.total_gate_operations += 1;
1268        self.total_execution_time += execution_time;
1269        self.avg_gate_time =
1270            (self.total_execution_time * 1_000_000.0) / self.total_gate_operations as f64;
1271        self.total_clock_cycles += clock_cycles;
1272    }
1273    /// Calculate performance metrics
1274    #[must_use]
1275    pub fn get_performance_metrics(&self) -> HashMap<String, f64> {
1276        let mut metrics = HashMap::new();
1277        if self.total_execution_time > 0.0 {
1278            metrics.insert(
1279                "operations_per_second".to_string(),
1280                self.total_gate_operations as f64 / (self.total_execution_time / 1000.0),
1281            );
1282            metrics.insert(
1283                "cycles_per_operation".to_string(),
1284                self.total_clock_cycles as f64 / self.total_gate_operations as f64,
1285            );
1286        }
1287        metrics.insert("fpga_utilization".to_string(), self.fpga_utilization);
1288        metrics.insert("pipeline_efficiency".to_string(), self.pipeline_efficiency);
1289        metrics.insert(
1290            "memory_bandwidth_utilization".to_string(),
1291            self.memory_bandwidth_utilization,
1292        );
1293        if self.power_consumption > 0.0 && self.total_execution_time > 0.0 {
1294            metrics.insert(
1295                "power_efficiency".to_string(),
1296                self.total_gate_operations as f64
1297                    / (self.power_consumption * self.total_execution_time / 1000.0),
1298            );
1299        }
1300        metrics
1301    }
1302}
1303/// FPGA configuration
1304#[derive(Debug, Clone)]
1305pub struct FPGAConfig {
1306    /// Target FPGA platform
1307    pub platform: FPGAPlatform,
1308    /// Clock frequency (MHz)
1309    pub clock_frequency: f64,
1310    /// Number of processing units
1311    pub num_processing_units: usize,
1312    /// Memory bandwidth (GB/s)
1313    pub memory_bandwidth: f64,
1314    /// Enable pipelining
1315    pub enable_pipelining: bool,
1316    /// Pipeline depth
1317    pub pipeline_depth: usize,
1318    /// Data path width (bits)
1319    pub data_path_width: usize,
1320    /// Enable DSP optimization
1321    pub enable_dsp_optimization: bool,
1322    /// Enable block RAM optimization
1323    pub enable_bram_optimization: bool,
1324    /// Maximum state vector size
1325    pub max_state_size: usize,
1326    /// Enable real-time processing
1327    pub enable_realtime: bool,
1328    /// Hardware description language
1329    pub hdl_target: HDLTarget,
1330}
1331/// External memory interface
1332#[derive(Debug, Clone)]
1333pub struct ExternalMemoryInterface {
1334    /// Interface ID
1335    pub interface_id: usize,
1336    /// Interface type
1337    pub interface_type: MemoryInterfaceType,
1338    /// Controller module
1339    pub controller: String,
1340    /// Current utilization
1341    pub utilization: f64,
1342}