wai-quantum 0.6.0

A deterministic quantum stack in pure Rust: byte-exact circuit simulation (statevector / stabilizer / tensor-network MPS / sparse-Pauli backends), sparse Pauli dynamics at utility scale (arbitrary angles, 1024 qubits), belief-propagation tensor networks on the hardware graph, error mitigation, qLDPC decoding, noise learning, circuit-equivalence proofs, a phasor interference-ML layer, information-theoretic limits, noisy channels and state tomography, and signed energy-accounted receipts. No QPU, no cloud, no system libraries in the default features — identical results native, in the browser, and as a WASI component at the edge; the opt-in WebGPU member reaches the platform's GPU interface.
Documentation
//! The instructions of a dataflow accelerator's compute tile that the vector
//! member's programs use: their opcodes and fields, transcribed from the device
//! simulator's own instruction table, and checked against that table in CI.
//!
//! A word is `opcode << 24 | fields`. The tile's first RISC-V core passes a
//! word on to the tile when it meets one in its own instruction stream whose
//! low two bits are not `0b11`, rotated right by two: so a program carries
//! [`inline`] of the word.

/// One instruction: its name, opcode, and fields as (name, high bit, low bit).
pub struct Layout {
    pub name: &'static str,
    pub opcode: u8,
    pub fields: &'static [(&'static str, u8, u8)],
}

/// The instructions used, as the simulator's table gives them.
pub const LAYOUTS: &[Layout] = &[
    Layout { name: "INCRWC", opcode: 0x38, fields: &[("rwc_a", 9, 6), ("rwc_b", 13, 10), ("rwc_cr", 20, 18), ("rwc_d", 17, 14)] },
    Layout {
        name: "PACR",
        opcode: 0x41,
        fields: &[
            ("addr_cnt_context", 14, 13),
            ("addr_mode", 16, 15),
            ("cfg_context", 22, 21),
            ("concat", 4, 4),
            ("ctxt_ctrl", 3, 2),
            ("dst_access_mode", 17, 17),
            ("flush", 1, 1),
            ("last", 0, 0),
            ("ovrd_thread_id", 7, 7),
            ("read_intf_sel", 11, 8),
            ("row_pad_zero", 20, 18),
            ("zero_write", 12, 12),
        ],
    },
    Layout { name: "SETADCXX", opcode: 0x5e, fields: &[("cnt_set_mask", 23, 21), ("x_end2", 19, 10), ("x_start", 9, 0)] },
    Layout { name: "SETADCXY", opcode: 0x51, fields: &[("bit_mask", 3, 0), ("ch0_x", 8, 6), ("ch0_y", 11, 9), ("ch1_x", 14, 12), ("ch1_y", 17, 15), ("cnt_set_mask", 23, 21)] },
    Layout { name: "SETADCZW", opcode: 0x54, fields: &[("bit_mask", 3, 0), ("ch0_x", 8, 6), ("ch0_y", 11, 9), ("ch1_x", 14, 12), ("ch1_y", 17, 15), ("cnt_set_mask", 23, 21)] },
    Layout { name: "SETC16", opcode: 0xb2, fields: &[("setc16_reg", 23, 16), ("setc16_value", 15, 0)] },
    Layout { name: "SETGPR", opcode: 0x45, fields: &[("payload_sig_sel", 21, 8), ("payload_sig_sel_size", 23, 22), ("reg_index_16b", 6, 0), ("set_signals_mode", 7, 7)] },
    Layout { name: "SETRWC", opcode: 0x37, fields: &[("bit_mask", 3, 0), ("clear_ab_vld", 23, 22), ("rwc_a", 9, 6), ("rwc_b", 13, 10), ("rwc_cr", 21, 18), ("rwc_d", 17, 14)] },
    Layout { name: "SFPAND", opcode: 0x7e, fields: &[("imm12_math", 15, 12), ("instr_mod1", 3, 0), ("lreg_c", 11, 8), ("lreg_dest", 7, 4)] },
    Layout { name: "SFPCONFIG", opcode: 0x91, fields: &[("config_dest", 7, 4), ("imm16_math", 23, 8), ("instr_mod1", 3, 0)] },
    Layout { name: "SFPIADD", opcode: 0x79, fields: &[("imm12_math", 23, 12), ("instr_mod1", 3, 0), ("lreg_c", 11, 8), ("lreg_dest", 7, 4)] },
    Layout { name: "SFPLOAD", opcode: 0x70, fields: &[("dest_reg_addr", 9, 0), ("instr_mod0", 19, 16), ("lreg_ind", 23, 20), ("sfpu_addr_mode", 15, 13)] },
    Layout { name: "SFPLOADI", opcode: 0x71, fields: &[("imm16", 15, 0), ("instr_mod0", 19, 16), ("lreg_ind", 23, 20)] },
    Layout {
        name: "SFPMUL24",
        opcode: 0x98,
        fields: &[("instr_mod1", 3, 0), ("lreg_dest", 7, 4), ("lreg_src_a", 19, 16), ("lreg_src_b", 15, 12), ("lreg_src_c", 11, 8)],
    },
    Layout { name: "SFPNOP", opcode: 0x8f, fields: &[] },
    Layout { name: "SFPOR", opcode: 0x7f, fields: &[("imm12_math", 15, 12), ("instr_mod1", 3, 0), ("lreg_c", 11, 8), ("lreg_dest", 7, 4)] },
    Layout { name: "SFPSHFT", opcode: 0x7a, fields: &[("imm12_math", 23, 12), ("instr_mod1", 3, 0), ("lreg_c", 11, 8), ("lreg_dest", 7, 4)] },
    Layout { name: "SFPSTORE", opcode: 0x72, fields: &[("dest_reg_addr", 9, 0), ("instr_mod0", 19, 16), ("lreg_ind", 23, 20), ("sfpu_addr_mode", 15, 13)] },
    Layout { name: "STALLWAIT", opcode: 0xa2, fields: &[("stall_res", 23, 15), ("wait_res", 12, 0)] },
    Layout {
        name: "UNPACR",
        opcode: 0x42,
        fields: &[
            ("addr_cnt_context_id", 9, 8),
            ("addr_mode", 22, 15),
            ("auto_inc_context_id", 3, 3),
            ("cfg_context_cnt_inc", 13, 13),
            ("cfg_context_id", 12, 10),
            ("last", 0, 0),
            ("ovrd_thread_id", 7, 7),
            ("row_search", 2, 2),
            ("search_cache_flush", 1, 1),
            ("set_dat_valid", 6, 6),
            ("srcb_bcast", 5, 5),
            ("unpack_block_selection", 23, 23),
            ("zero_write2", 4, 4),
        ],
    },
];

/// The word for `name` with `fields` set (every other field zero).
pub fn word(name: &str, fields: &[(&str, u32)]) -> u32 {
    let l = LAYOUTS.iter().find(|l| l.name == name).unwrap_or_else(|| panic!("no instruction {name}"));
    let mut w = u32::from(l.opcode) << 24;
    for &(f, v) in fields {
        let &(_, hi, lo) = l.fields.iter().find(|x| x.0 == f).unwrap_or_else(|| panic!("{name} has no field {f}"));
        let width = u32::from(hi - lo + 1);
        assert!(u64::from(v) < (1u64 << width), "{name}.{f} = {v} does not fit {width} bits");
        w |= v << lo;
    }
    w
}

/// The word as the core's instruction stream carries it.
pub fn inline(word: u32) -> u32 {
    word.rotate_left(2)
}

#[cfg(test)]
mod tests {
    use super::*;

    /// Words worked out independently from the same table.
    #[test]
    fn words_match_an_independent_reading_of_the_table() {
        let checks: [(u32, u32); 12] = [
            (0x5420_000F, word("SETADCZW", &[("bit_mask", 0xF), ("cnt_set_mask", 1)])),
            (0x5E23_FC00, word("SETADCXX", &[("x_end2", 255), ("cnt_set_mask", 1)])),
            (0x4208_8081, word("UNPACR", &[("last", 1), ("ovrd_thread_id", 1), ("addr_mode", 0b0001_0001)])),
            (0xA280_0002, word("STALLWAIT", &[("stall_res", 1 << 8), ("wait_res", 1 << 1)])),
            (0x7004_0000, word("SFPLOAD", &[("instr_mod0", 4)])),
            (0x7264_0000, word("SFPSTORE", &[("lreg_ind", 6), ("instr_mod0", 4)])),
            (0x3800_8000, word("INCRWC", &[("rwc_d", 2)])),
            (0x3700_0004, word("SETRWC", &[("bit_mask", 4)])),
            (0x4100_0001, word("PACR", &[("last", 1)])),
            (0x4500_017E, word("SETGPR", &[("reg_index_16b", 126), ("payload_sig_sel", 1)])),
            (0x9100_00C0, word("SFPCONFIG", &[("config_dest", 12)])),
            (0x9802_3940, word("SFPMUL24", &[("lreg_src_a", 2), ("lreg_src_b", 3), ("lreg_src_c", 9), ("lreg_dest", 4)])),
        ];
        for (want, got) in checks {
            assert_eq!(got, want, "{got:#010x} vs {want:#010x}");
        }
        // An inline word is never a 32-bit RISC-V instruction: its low bits are not 0b11.
        for l in LAYOUTS {
            assert!(l.opcode < 0xc0);
            assert_ne!(inline(u32::from(l.opcode) << 24) & 3, 3, "{}", l.name);
        }
        assert_eq!(inline(0xA280_0002).rotate_right(2), 0xA280_0002);
    }

    /// With `WAI_QUANTUM_TENSIX_ISA` naming the simulator's table for the
    /// generation the vector programs drive (`data/bh/tensix_isa.json`), every
    /// transcribed layout must be the table's. (Another generation's table lays
    /// some instructions out differently: `PACR` has other fields.)
    #[test]
    fn layouts_are_the_simulators_table() {
        let Some(path) = std::env::var_os("WAI_QUANTUM_TENSIX_ISA") else { return };
        let table: serde_json::Value = serde_json::from_slice(&std::fs::read(&path).expect("the table reads")).expect("the table is JSON");
        for l in LAYOUTS {
            let t = &table[l.name];
            assert_eq!(t["opcode"].as_u64(), Some(u64::from(l.opcode)), "{} opcode", l.name);
            let args = t["args"].as_object().unwrap_or_else(|| panic!("{} has no args", l.name));
            assert_eq!(args.len(), l.fields.len(), "{} field count", l.name);
            for &(f, hi, lo) in l.fields {
                assert_eq!(args.get(f).and_then(|v| v.as_str()), Some(format!("{hi}:{lo}").as_str()), "{}.{f}", l.name);
            }
        }
        println!("tensix layouts: {} instructions match the table", LAYOUTS.len());
    }
}