Skip to main content

cuda_instruction_set/
lib.rs

1/*!
2# cuda-instruction-set
3
4Agent-native instruction set unifying FLUX VM, cuda-genepool instincts,
5and cuda-axiom deliberation into one bytecode format.
6
7## Opcode Categories
8- Control (0x00-0x07): JMP, CALL, RET, HALT
9- ArithConf (0x08-0x17): Arithmetic with confidence propagation
10- Logic (0x18-0x1F): Bitwise with confidence
11- Compare (0x20-0x27): Confidence-aware comparisons
12- Stack (0x28-0x2F): Typed stack operations
13- Perception (0x30-0x37): IO, sensor fusion
14- A2A (0x38-0x4F): Agent-to-agent communication
15- Memory (0x50-0x57): Capability-based regions
16- Type (0x58-0x5F): Boxed values, casting
17- SIMD (0x60-0x67): 4-wide vector operations
18- Instinct (0x68-0x6F): Biological instinct activation
19- Energy (0x70-0x77): ATP budgets, apoptosis
20- System (0x78-0x7F): Debug, barriers, resources
21
22## Confidence Propagation
23Every ArithConf operation propagates uncertainty using Bayesian fusion:
24  post_conf = 1 / (1/conf_a + 1/conf_b)
25This ensures confidence decreases monotonically through computation chains.
26*/
27
28use serde::{Deserialize, Serialize};
29use std::fmt;
30
31/// Confidence value in [0.0, 1.0]
32#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
33pub struct Confidence(pub f32);
34
35impl Confidence {
36    pub const ZERO: Confidence = Confidence(0.0);
37    pub const CERTAIN: Confidence = Confidence(1.0);
38    pub const HIGH: Confidence = Confidence(0.95);
39    pub const MEDIUM: Confidence = Confidence(0.5);
40    pub const LOW: Confidence = Confidence(0.1);
41
42    pub fn new(v: f32) -> Self {
43        Confidence(v.clamp(0.0, 1.0))
44    }
45
46    /// Bayesian fusion of two independent confidences
47    pub fn fuse(a: Confidence, b: Confidence) -> Confidence {
48        if a.0 <= 0.0 && b.0 <= 0.0 { return Confidence::ZERO; }
49        if a.0 <= 0.0 { return b; }
50        if b.0 <= 0.0 { return a; }
51        Confidence::new(1.0 / (1.0 / a.0 + 1.0 / b.0))
52    }
53
54    /// Sequential composition: confidence decreases
55    pub fn chain(a: Confidence, b: Confidence) -> Confidence {
56        Confidence::new(a.0 * b.0)
57    }
58}
59
60/// Opcode categories
61#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
62pub enum OpCategory {
63    Control, ArithConf, Logic, Compare, Stack,
64    Perception, A2A, Memory, Type, SIMD,
65    Instinct, Energy, System,
66}
67
68/// All agent opcodes (80 instructions)
69#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
70#[repr(u8)]
71pub enum Opcode {
72    // Control 0x00-0x07
73    Nop          = 0x00,
74    Mov          = 0x01,
75    MovI         = 0x02,
76    Jmp          = 0x03,
77    Jz           = 0x04,
78    Jnz          = 0x05,
79    Call         = 0x06,
80    Ret          = 0x07,
81
82    // ArithConf 0x08-0x17 (confidence-propagating)
83    CAdd         = 0x08,
84    CSub         = 0x09,
85    CMul         = 0x0A,
86    CDiv         = 0x0B,
87    CMod         = 0x0C,
88    CNeg         = 0x0D,
89    CInc         = 0x0E,
90    CDec         = 0x0F,
91    CMin         = 0x10,
92    CMax         = 0x11,
93    CAbs         = 0x12,
94    CLerp        = 0x13,
95    ConfSet      = 0x14,
96    ConfFuse     = 0x15,
97    ConfChain    = 0x16,
98    ConfThreshold = 0x17,
99
100    // Logic 0x18-0x1F
101    And          = 0x18,
102    Or           = 0x19,
103    Xor          = 0x1A,
104    Not          = 0x1B,
105    Shl          = 0x1C,
106    Shr          = 0x1D,
107    RotL         = 0x1E,
108    RotR         = 0x1F,
109
110    // Compare 0x20-0x27
111    Cmp          = 0x20,
112    Eq           = 0x21,
113    Lt           = 0x22,
114    Gt           = 0x23,
115    Le           = 0x24,
116    Ge           = 0x25,
117    ConfEq       = 0x26,
118    Test         = 0x27,
119
120    // Stack 0x28-0x2F
121    Push         = 0x28,
122    Pop          = 0x29,
123    Dup          = 0x2A,
124    Swap         = 0x2B,
125    Rot3         = 0x2C,
126    Enter        = 0x2D,
127    Leave        = 0x2E,
128    Pick         = 0x2F,
129
130    // Perception 0x30-0x37
131    IoRead       = 0x30,
132    IoWrite      = 0x31,
133    SensorAcquire = 0x32,
134    FuseConf     = 0x33,
135    Perceive     = 0x34,
136    Sense        = 0x35,
137    Load8        = 0x36,
138    Store8       = 0x37,
139
140    // A2A 0x38-0x4F
141    Tell         = 0x38,
142    Ask          = 0x39,
143    Delegate     = 0x3A,
144    DelegResult  = 0x3B,
145    Broadcast    = 0x3C,
146    Reduce       = 0x3D,
147    TrustCheck   = 0x3E,
148    TrustUpdate  = 0x3F,
149    TrustQuery   = 0x40,
150    TrustRevoke  = 0x41,
151    CapRequire   = 0x42,
152    CapGrant     = 0x43,
153    CapRevoke    = 0x44,
154    DeclareIntent = 0x45,
155    AssertGoal   = 0x46,
156    VerifyOutcome = 0x47,
157    Barrier      = 0x48,
158    Formation    = 0x49,
159    SyncClock    = 0x4A,
160    ReportStatus = 0x4B,
161    ExplainFail  = 0x4C,
162    SetPriority  = 0x4D,
163    RequestOverride = 0x4E,
164    EmergencyStop = 0x4F,
165
166    // Memory 0x50-0x57
167    RegionCreate = 0x50,
168    RegionDestroy = 0x51,
169    RegionTransfer = 0x52,
170    MemCopy      = 0x53,
171    MemSet       = 0x54,
172    MemCmp       = 0x55,
173    Load         = 0x56,
174    Store        = 0x57,
175
176    // Type 0x58-0x5F
177    Cast         = 0x58,
178    Box          = 0x59,
179    Unbox        = 0x5A,
180    CheckType    = 0x5B,
181    CheckBounds  = 0x5C,
182    Tag          = 0x5D,
183    Untag        = 0x5E,
184    IsNil        = 0x5F,
185
186    // SIMD 0x60-0x67 (4-wide i32 + confidence)
187    VLoad        = 0x60,
188    VStore       = 0x61,
189    VAdd         = 0x62,
190    VSub         = 0x63,
191    VMul         = 0x64,
192    VDiv         = 0x65,
193    VFma         = 0x66,
194    VConfFuse    = 0x67,
195
196    // Instinct 0x68-0x6F (biological operations)
197    InstinctActivate = 0x68,
198    InstinctQuery = 0x69,
199    GeneExpress  = 0x6A,
200    EnzymeBind   = 0x6B,
201    RnaTranslate = 0x6C,
202    ProteinFold  = 0x6D,
203    MembraneCheck = 0x6E,
204    Quarantine   = 0x6F,
205
206    // Energy 0x70-0x77
207    AtpGenerate  = 0x70,
208    AtpConsume   = 0x71,
209    AtpQuery     = 0x72,
210    AtpTransfer  = 0x73,
211    ApoptosisCheck = 0x74,
212    ApoptosisTrigger = 0x75,
213    CircadianSet = 0x76,
214    CircadianGet = 0x77,
215
216    // System 0x78-0x7F
217    Halt         = 0x78,
218    Yield        = 0x79,
219    ResourceAcquire = 0x7A,
220    ResourceRelease = 0x7B,
221    Debug        = 0x7C,
222    DumpState    = 0x7D,
223    Trap         = 0x7E,
224    NopSys       = 0x7F,
225}
226
227impl Opcode {
228    pub fn from_byte(b: u8) -> Option<Self> {
229        // SAFETY: all values 0x00-0x7F are valid opcodes
230        if b <= 0x7F { Some(unsafe { std::mem::transmute(b) }) } else { None }
231    }
232
233    pub fn to_byte(self) -> u8 { self as u8 }
234
235    pub fn category(self) -> OpCategory {
236        match self as u8 {
237            0x00..=0x07 => OpCategory::Control,
238            0x08..=0x17 => OpCategory::ArithConf,
239            0x18..=0x1F => OpCategory::Logic,
240            0x20..=0x27 => OpCategory::Compare,
241            0x28..=0x2F => OpCategory::Stack,
242            0x30..=0x37 => OpCategory::Perception,
243            0x38..=0x4F => OpCategory::A2A,
244            0x50..=0x57 => OpCategory::Memory,
245            0x58..=0x5F => OpCategory::Type,
246            0x60..=0x67 => OpCategory::SIMD,
247            0x68..=0x6F => OpCategory::Instinct,
248            0x70..=0x77 => OpCategory::Energy,
249            0x78..=0x7F => OpCategory::System,
250            _ => OpCategory::Control,
251        }
252    }
253
254    pub fn name(self) -> &'static str {
255        match self {
256            Opcode::Nop => "NOP", Opcode::Mov => "MOV", Opcode::MovI => "MOVI",
257            Opcode::Jmp => "JMP", Opcode::Jz => "JZ", Opcode::Jnz => "JNZ",
258            Opcode::Call => "CALL", Opcode::Ret => "RET",
259            Opcode::CAdd => "CADD", Opcode::CSub => "CSUB", Opcode::CMul => "CMUL",
260            Opcode::CDiv => "CDIV", Opcode::CMod => "CMOD", Opcode::CNeg => "CNEG",
261            Opcode::CInc => "CINC", Opcode::CDec => "CDEC", Opcode::CMin => "CMIN",
262            Opcode::CMax => "CMAX", Opcode::CAbs => "CABS", Opcode::CLerp => "CLERP",
263            Opcode::ConfSet => "CONF_SET", Opcode::ConfFuse => "CONF_FUSE",
264            Opcode::ConfChain => "CONF_CHAIN", Opcode::ConfThreshold => "CONF_THRESH",
265            Opcode::And => "AND", Opcode::Or => "OR", Opcode::Xor => "XOR",
266            Opcode::Not => "NOT", Opcode::Shl => "SHL", Opcode::Shr => "SHR",
267            Opcode::RotL => "ROTL", Opcode::RotR => "ROTR",
268            Opcode::Cmp => "CMP", Opcode::Eq => "EQ", Opcode::Lt => "LT",
269            Opcode::Gt => "GT", Opcode::Le => "LE", Opcode::Ge => "GE",
270            Opcode::ConfEq => "CONF_EQ", Opcode::Test => "TEST",
271            Opcode::Push => "PUSH", Opcode::Pop => "POP", Opcode::Dup => "DUP",
272            Opcode::Swap => "SWAP", Opcode::Rot3 => "ROT3", Opcode::Enter => "ENTER",
273            Opcode::Leave => "LEAVE", Opcode::Pick => "PICK",
274            Opcode::IoRead => "IO_READ", Opcode::IoWrite => "IO_WRITE",
275            Opcode::SensorAcquire => "SENSOR_ACQ", Opcode::FuseConf => "FUSE_CONF",
276            Opcode::Perceive => "PERCEIVE", Opcode::Sense => "SENSE",
277            Opcode::Load8 => "LOAD8", Opcode::Store8 => "STORE8",
278            Opcode::Tell => "TELL", Opcode::Ask => "ASK", Opcode::Delegate => "DELEGATE",
279            Opcode::DelegResult => "DELEG_RESULT", Opcode::Broadcast => "BROADCAST",
280            Opcode::Reduce => "REDUCE", Opcode::TrustCheck => "TRUST_CHECK",
281            Opcode::TrustUpdate => "TRUST_UPDATE", Opcode::TrustQuery => "TRUST_QUERY",
282            Opcode::TrustRevoke => "TRUST_REVOKE", Opcode::CapRequire => "CAP_REQ",
283            Opcode::CapGrant => "CAP_GRANT", Opcode::CapRevoke => "CAP_REVOKE",
284            Opcode::DeclareIntent => "DECLARE_INTENT", Opcode::AssertGoal => "ASSERT_GOAL",
285            Opcode::VerifyOutcome => "VERIFY_OUTCOME", Opcode::Barrier => "BARRIER",
286            Opcode::Formation => "FORMATION", Opcode::SyncClock => "SYNC_CLOCK",
287            Opcode::ReportStatus => "REPORT_STATUS", Opcode::ExplainFail => "EXPLAIN_FAIL",
288            Opcode::SetPriority => "SET_PRIORITY", Opcode::RequestOverride => "REQ_OVERRIDE",
289            Opcode::EmergencyStop => "EMERGENCY_STOP",
290            Opcode::RegionCreate => "REGION_CREATE", Opcode::RegionDestroy => "REGION_DESTROY",
291            Opcode::RegionTransfer => "REGION_TRANSFER", Opcode::MemCopy => "MEMCOPY",
292            Opcode::MemSet => "MEMSET", Opcode::MemCmp => "MEMCMP",
293            Opcode::Load => "LOAD", Opcode::Store => "STORE",
294            Opcode::Cast => "CAST", Opcode::Box => "BOX", Opcode::Unbox => "UNBOX",
295            Opcode::CheckType => "CHECK_TYPE", Opcode::CheckBounds => "CHECK_BOUNDS",
296            Opcode::Tag => "TAG", Opcode::Untag => "UNTAG", Opcode::IsNil => "IS_NIL",
297            Opcode::VLoad => "VLOAD", Opcode::VStore => "VSTORE",
298            Opcode::VAdd => "VADD", Opcode::VSub => "VSUB",
299            Opcode::VMul => "VMUL", Opcode::VDiv => "VDIV",
300            Opcode::VFma => "VFMA", Opcode::VConfFuse => "VCONF_FUSE",
301            Opcode::InstinctActivate => "INSTINCT_ACT", Opcode::InstinctQuery => "INSTINCT_Q",
302            Opcode::GeneExpress => "GENE_EXPR", Opcode::EnzymeBind => "ENZYME_BIND",
303            Opcode::RnaTranslate => "RNA_TRANS", Opcode::ProteinFold => "PROTEIN_FOLD",
304            Opcode::MembraneCheck => "MEMBRANE_CHK", Opcode::Quarantine => "QUARANTINE",
305            Opcode::AtpGenerate => "ATP_GEN", Opcode::AtpConsume => "ATP_CONSUME",
306            Opcode::AtpQuery => "ATP_Q", Opcode::AtpTransfer => "ATP_TRANSFER",
307            Opcode::ApoptosisCheck => "APOPTOSIS_CHK", Opcode::ApoptosisTrigger => "APOPTOSIS_TRIGGER",
308            Opcode::CircadianSet => "CIRCADIAN_SET", Opcode::CircadianGet => "CIRCADIAN_GET",
309            Opcode::Halt => "HALT", Opcode::Yield => "YIELD",
310            Opcode::ResourceAcquire => "RES_ACQ", Opcode::ResourceRelease => "RES_REL",
311            Opcode::Debug => "DEBUG", Opcode::DumpState => "DUMP",
312            Opcode::Trap => "TRAP", Opcode::NopSys => "NOP_SYS",
313        }
314    }
315}
316
317impl fmt::Display for Opcode {
318    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.name()) }
319}
320
321/// A value with attached confidence
322#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
323pub struct ConfValue {
324    pub value: i64,
325    pub confidence: Confidence,
326}
327
328impl ConfValue {
329    pub fn certain(v: i64) -> Self { ConfValue { value: v, confidence: Confidence::CERTAIN } }
330    pub fn uncertain(v: i64, c: f32) -> Self { ConfValue { value: v, confidence: Confidence::new(c) } }
331    pub fn zero() -> Self { ConfValue { value: 0, confidence: Confidence::CERTAIN } }
332}
333
334/// Variable-length instruction
335#[derive(Clone, Debug, Serialize, Deserialize)]
336pub struct Instruction {
337    pub opcode: Opcode,
338    pub operands: Vec<u8>,
339}
340
341impl Instruction {
342    pub fn new(op: Opcode, ops: Vec<u8>) -> Self { Instruction { opcode: op, operands: ops } }
343    pub fn simple(op: Opcode) -> Self { Instruction { opcode: op, operands: vec![] } }
344    pub fn reg(op: Opcode, rd: u8) -> Self { Instruction { opcode: op, operands: vec![rd] } }
345    pub fn reg2(op: Opcode, rd: u8, rs: u8) -> Self { Instruction { opcode: op, operands: vec![rd, rs] } }
346    pub fn reg_imm(op: Opcode, rd: u8, imm: i16) -> Self {
347        Instruction { opcode: op, operands: vec![rd, (imm & 0xFF) as u8, ((imm >> 8) & 0xFF) as u8] }
348    }
349
350    /// Encode to bytes
351    pub fn encode(&self) -> Vec<u8> {
352        let mut bytes = vec![self.opcode.to_byte()];
353        // Variable-length payload: 2-byte length prefix for complex ops
354        match self.opcode.category() {
355            OpCategory::A2A | OpCategory::Memory | OpCategory::Type => {
356                let len = self.operands.len() as u16;
357                bytes.push((len & 0xFF) as u8);
358                bytes.push(((len >> 8) & 0xFF) as u8);
359                bytes.extend(&self.operands);
360            }
361            _ => { bytes.extend(&self.operands); }
362        }
363        bytes
364    }
365
366    /// Decode from bytes, returns (instruction, bytes_consumed)
367    pub fn decode(data: &[u8]) -> Option<(Self, usize)> {
368        if data.is_empty() { return None; }
369        let op = Opcode::from_byte(data[0])?;
370        let (operands, consumed) = match op.category() {
371            OpCategory::A2A | OpCategory::Memory | OpCategory::Type => {
372                if data.len() < 3 { return None; }
373                let len = (data[1] as u16) | ((data[2] as u16) << 8);
374                let end = 3 + len as usize;
375                if data.len() < end { return None; }
376                (data[3..end].to_vec(), end)
377            }
378            OpCategory::Control | OpCategory::ArithConf | OpCategory::Logic
379            | OpCategory::Compare | OpCategory::Stack | OpCategory::SIMD => {
380                // Fixed format: opcode + operands (1-3 bytes typical)
381                let op_len = match op {
382                    Opcode::MovI | Opcode::Jmp | Opcode::Jz | Opcode::Jnz
383                    | Opcode::Call => 4, // op + rd + imm16
384                    Opcode::Nop | Opcode::Ret | Opcode::Halt | Opcode::Yield
385                    | Opcode::Dup | Opcode::NopSys => 1,
386                    Opcode::Enter | Opcode::Leave => 2, // op + frame_size
387                    _ => 3, // op + rd + rs
388                };
389                let ops = if data.len() >= op_len { data[1..op_len].to_vec() } else { vec![] };
390                (ops, op_len)
391            }
392            _ => (vec![], 1),
393        };
394        Some((Instruction { opcode: op, operands }, consumed))
395    }
396}
397
398/// Simple text assembler
399pub struct Assembler {
400    pub instructions: Vec<Instruction>,
401    pub labels: std::collections::HashMap<String, usize>,
402    pub unresolved: Vec<(String, usize)>,
403}
404
405impl Assembler {
406    pub fn new() -> Self { Assembler { instructions: vec![], labels: std::collections::HashMap::new(), unresolved: vec![] } }
407
408    pub fn emit(&mut self, insn: Instruction) { self.instructions.push(insn); }
409
410    pub fn label(&mut self, name: &str) { self.labels.insert(name.to_string(), self.instructions.len()); }
411
412    pub fn emit_jmp(&mut self, label: &str) {
413        self.unresolved.push((label.to_string(), self.instructions.len()));
414        self.emit(Instruction::new(Opcode::Jmp, vec![0, 0, 0])); // placeholder
415    }
416
417    pub fn assemble(&mut self) -> Result<Vec<u8>, String> {
418        // Resolve labels
419        for (label, idx) in &self.unresolved {
420            if let Some(&target) = self.labels.get(label) {
421                let offset = target as i16 - *idx as i16;
422                if let Some(ref mut insn) = self.instructions.get_mut(*idx) {
423                    insn.operands = vec![0, (offset & 0xFF) as u8, ((offset >> 8) & 0xFF) as u8];
424                }
425            } else { return Err(format!("Unresolved label: {}", label)); }
426        }
427        // Encode all
428        let mut bytecode = vec![];
429        for insn in &self.instructions { bytecode.extend(insn.encode()); }
430        Ok(bytecode)
431    }
432}
433
434/// Text disassembler
435pub struct Disassembler;
436
437impl Disassembler {
438    pub fn disassemble(data: &[u8]) -> Vec<String> {
439        let mut lines = vec![];
440        let mut pc = 0;
441        while pc < data.len() {
442            if let Some((insn, consumed)) = Instruction::decode(&data[pc..]) {
443                let ops_str = insn.operands.iter().map(|b| format!("{}", b)).collect::<Vec<_>>().join(" ");
444                if ops_str.is_empty() { lines.push(format!("{:04X}: {}", pc, insn.opcode.name())); }
445                else { lines.push(format!("{:04X}: {} {}", pc, insn.opcode.name(), ops_str)); }
446                pc += consumed;
447            } else { lines.push(format!("{:04X}: ???", pc)); pc += 1; }
448        }
449        lines
450    }
451}
452
453/// A2A message encoding
454#[derive(Clone, Debug, Serialize, Deserialize)]
455pub struct A2AMessage {
456    pub sender_id: u32,
457    pub intent: String,
458    pub confidence: Confidence,
459    pub payload_hash: u64,
460    pub trust_level: f32,
461    pub priority: u8,
462}
463
464impl A2AMessage {
465    pub fn encode(&self) -> Vec<u8> {
466        let intent_bytes = self.intent.as_bytes();
467        let mut out = vec![];
468        out.extend(&self.sender_id.to_le_bytes());
469        out.push(intent_bytes.len() as u8);
470        out.extend(intent_bytes);
471        out.extend(&self.confidence.0.to_le_bytes());
472        out.extend(&self.payload_hash.to_le_bytes());
473        out.extend(&self.trust_level.to_le_bytes());
474        out.push(self.priority);
475        out
476    }
477
478    pub fn decode(data: &[u8]) -> Option<Self> {
479        if data.len() < 4 + 1 + 4 + 8 + 4 + 1 { return None; }
480        let sender_id = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
481        let intent_len = data[4] as usize;
482        if data.len() < 5 + intent_len + 4 + 8 + 4 + 1 { return None; }
483        let intent = String::from_utf8_lossy(&data[5..5 + intent_len]).to_string();
484        let mut offset = 5 + intent_len;
485        let confidence = f32::from_le_bytes([data[offset], data[offset+1], data[offset+2], data[offset+3]]);
486        offset += 4;
487        let payload_hash = u64::from_le_bytes(data[offset..offset+8].try_into().ok()?);
488        offset += 8;
489        let trust_level = f32::from_le_bytes([data[offset], data[offset+1], data[offset+2], data[offset+3]]);
490        offset += 4;
491        let priority = data[offset];
492        Some(A2AMessage { sender_id, intent, confidence: Confidence::new(confidence), payload_hash, trust_level, priority })
493    }
494}
495
496#[cfg(test)]
497mod tests {
498    use super::*;
499
500    #[test]
501    fn test_opcode_roundtrip() {
502        for b in 0..=0x7F {
503            let op = Opcode::from_byte(b).unwrap();
504            assert_eq!(op.to_byte(), b);
505            if b == 0 { assert_eq!(op.category(), Opcode::Nop.category()); }
506        }
507        assert!(Opcode::from_byte(0x80).is_none());
508    }
509
510    #[test]
511    fn test_confidence_fusion() {
512        let a = Confidence::new(0.8);
513        let b = Confidence::new(0.5);
514        let fused = Confidence::fuse(a, b);
515        // 1/(1/0.8 + 1/0.5) = 1/(1.25 + 2.0) = 1/3.25 ≈ 0.308
516        assert!((fused.0 - 0.308).abs() < 0.01);
517    }
518
519    #[test]
520    fn test_confidence_chain() {
521        let a = Confidence::new(0.9);
522        let b = Confidence::new(0.8);
523        let chained = Confidence::chain(a, b);
524        assert!((chained.0 - 0.72).abs() < 0.01);
525    }
526
527    #[test]
528    fn test_instruction_encode_decode() {
529        let insn = Instruction::reg2(Opcode::CAdd, 0, 1);
530        let bytes = insn.encode();
531        assert_eq!(bytes, vec![0x08, 0, 1]);
532        let (decoded, consumed) = Instruction::decode(&bytes).unwrap();
533        assert_eq!(decoded.opcode, Opcode::CAdd);
534        assert_eq!(decoded.operands, vec![0, 1]);
535        assert_eq!(consumed, 3);
536    }
537
538    #[test]
539    fn test_movi_encode_decode() {
540        let insn = Instruction::reg_imm(Opcode::MovI, 0, -42);
541        let bytes = insn.encode();
542        let (decoded, _) = Instruction::decode(&bytes).unwrap();
543        assert_eq!(decoded.opcode, Opcode::MovI);
544        assert_eq!(decoded.operands[0], 0);
545        // imm -42 = 0xFFD6
546        assert_eq!(decoded.operands[1], 0xD6);
547        assert_eq!(decoded.operands[2], 0xFF);
548    }
549
550    #[test]
551    fn test_a2a_message_roundtrip() {
552        let msg = A2AMessage {
553            sender_id: 42,
554            intent: "investigate_anomaly".to_string(),
555            confidence: Confidence::new(0.85),
556            payload_hash: 12345,
557            trust_level: 0.9,
558            priority: 3,
559        };
560        let encoded = msg.encode();
561        let decoded = A2AMessage::decode(&encoded).unwrap();
562        assert_eq!(decoded.sender_id, 42);
563        assert_eq!(decoded.intent, "investigate_anomaly");
564        assert!((decoded.confidence.0 - 0.85).abs() < 0.01);
565    }
566
567    #[test]
568    fn test_assembler_basic() {
569        let mut asm = Assembler::new();
570        asm.emit(Instruction::reg_imm(Opcode::MovI, 0, 10));
571        asm.emit(Instruction::reg_imm(Opcode::MovI, 1, 25));
572        asm.emit(Instruction::reg2(Opcode::CAdd, 0, 1));
573        asm.emit(Instruction::simple(Opcode::Halt));
574        let bytecode = asm.assemble().unwrap();
575        assert_eq!(bytecode[0], 0x02); // MOVI
576        assert_eq!(bytecode[bytecode.len()-1], 0x78); // HALT
577    }
578
579    #[test]
580    fn test_assembler_with_labels() {
581        let mut asm = Assembler::new();
582        asm.emit(Instruction::reg_imm(Opcode::MovI, 0, 1));
583        asm.label("loop");
584        asm.emit(Instruction::simple(Opcode::Nop));
585        asm.emit(Instruction::new(Opcode::Jz, vec![0, 3, 0]));
586        asm.emit_jmp("loop");
587        let bytecode = asm.assemble().unwrap();
588        assert!(!bytecode.is_empty());
589    }
590
591    #[test]
592    fn test_disassembler() {
593        let bytecode = vec![0x00, 0x78, 0x02, 0, 10, 0];
594        let lines = Disassembler::disassemble(&bytecode);
595        assert_eq!(lines[0], "0000: NOP");
596        assert_eq!(lines[1], "0001: HALT");
597        assert!(lines[2].starts_with("0002: MOVI"));
598    }
599
600    #[test]
601    fn test_opcode_names() {
602        assert_eq!(Opcode::Halt.name(), "HALT");
603        assert_eq!(Opcode::CAdd.name(), "CADD");
604        assert_eq!(Opcode::InstinctActivate.name(), "INSTINCT_ACT");
605        assert_eq!(Opcode::AtpGenerate.name(), "ATP_GEN");
606    }
607
608    #[test]
609    fn test_confidence_clamping() {
610        assert_eq!(Confidence::new(1.5).0, 1.0);
611        assert_eq!(Confidence::new(-0.5).0, 0.0);
612    }
613
614    #[test]
615    fn test_all_categories_covered() {
616        let cats = [
617            OpCategory::Control, OpCategory::ArithConf, OpCategory::Logic,
618            OpCategory::Compare, OpCategory::Stack, OpCategory::Perception,
619            OpCategory::A2A, OpCategory::Memory, OpCategory::Type,
620            OpCategory::SIMD, OpCategory::Instinct, OpCategory::Energy,
621            OpCategory::System,
622        ];
623        for cat in &cats {
624            let found = (0..=0x7Fu8).any(|b| Opcode::from_byte(b).map(|o| o.category() == *cat).unwrap_or(false));
625            assert!(found, "Category {:?} has no opcodes", cat);
626        }
627    }
628
629    #[test]
630    fn test_instinct_opcodes() {
631        assert_eq!(Opcode::InstinctActivate as u8, 0x68);
632        assert_eq!(Opcode::GeneExpress as u8, 0x6A);
633        assert_eq!(Opcode::EnzymeBind as u8, 0x6B);
634        assert_eq!(Opcode::ApoptosisCheck as u8, 0x74);
635        assert_eq!(Opcode::AtpGenerate as u8, 0x70);
636    }
637}