pr1.3
This commit is contained in:
parent
29056ce0ad
commit
6423c6b4bc
@ -114,3 +114,21 @@ pub fn decode_next(pc: usize, bytes: &'_ [u8]) -> Result<DecodedInstr<'_>, Decod
|
||||
|
||||
Ok(DecodedInstr { opcode, pc, next_pc: imm_end, imm: &bytes[imm_start..imm_end] })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn unknown_opcode_is_reported_deterministically() {
|
||||
// 0x0060 was previously a legacy opcode; now it must be unknown.
|
||||
let bytes = vec![0x60, 0x00]; // little-endian u16 = 0x0060
|
||||
match decode_next(0, &bytes) {
|
||||
Err(DecodeError::UnknownOpcode { pc, opcode }) => {
|
||||
assert_eq!(pc, 0);
|
||||
assert_eq!(opcode, 0x0060);
|
||||
}
|
||||
other => panic!("expected UnknownOpcode, got {:?}", other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -560,9 +560,7 @@ fn validate_module(module: &BytecodeModule) -> Result<(), LoadError> {
|
||||
| OpCode::GetLocal
|
||||
| OpCode::SetLocal
|
||||
| OpCode::PopN
|
||||
| OpCode::Syscall
|
||||
| OpCode::GateLoad
|
||||
| OpCode::GateStore => {
|
||||
| OpCode::Syscall => {
|
||||
pos += 4;
|
||||
}
|
||||
OpCode::PushI64 | OpCode::PushF64 => {
|
||||
@ -574,9 +572,6 @@ fn validate_module(module: &BytecodeModule) -> Result<(), LoadError> {
|
||||
OpCode::Call => {
|
||||
pos += 4;
|
||||
}
|
||||
OpCode::Alloc => {
|
||||
pos += 8;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,46 +160,6 @@ pub enum OpCode {
|
||||
/// Ends the current local scope, discarding its local variables.
|
||||
PopScope = 0x53,
|
||||
|
||||
// --- 6.7 HIP (Heap Interface Protocol) ---
|
||||
/// Allocates `slots` slots on the heap with the given `type_id`.
|
||||
/// Operands: type_id (u32), slots (u32)
|
||||
/// Stack: [] -> [gate]
|
||||
Alloc = 0x60,
|
||||
/// Reads a value from the heap at `gate + offset`.
|
||||
/// Operand: offset (u32)
|
||||
/// Stack: [gate] -> [value]
|
||||
GateLoad = 0x61,
|
||||
/// Writes a value to the heap at `gate + offset`.
|
||||
/// Operand: offset (u32)
|
||||
/// Stack: [gate, value] -> []
|
||||
GateStore = 0x62,
|
||||
|
||||
/// Marks the beginning of a Peek scope for a gate.
|
||||
/// Stack: [gate] -> [gate]
|
||||
GateBeginPeek = 0x63,
|
||||
/// Marks the end of a Peek scope for a gate.
|
||||
/// Stack: [gate] -> [gate]
|
||||
GateEndPeek = 0x64,
|
||||
/// Marks the beginning of a Borrow scope for a gate.
|
||||
/// Stack: [gate] -> [gate]
|
||||
GateBeginBorrow = 0x65,
|
||||
/// Marks the end of a Borrow scope for a gate.
|
||||
/// Stack: [gate] -> [gate]
|
||||
GateEndBorrow = 0x66,
|
||||
/// Marks the beginning of a Mutate scope for a gate.
|
||||
/// Stack: [gate] -> [gate]
|
||||
GateBeginMutate = 0x67,
|
||||
/// Marks the end of a Mutate scope for a gate.
|
||||
/// Stack: [gate] -> [gate]
|
||||
GateEndMutate = 0x68,
|
||||
|
||||
/// Increments the reference count of a gate.
|
||||
/// Stack: [gate] -> [gate]
|
||||
GateRetain = 0x69,
|
||||
/// Decrements the reference count of a gate.
|
||||
/// Stack: [gate] -> []
|
||||
GateRelease = 0x6A,
|
||||
|
||||
// --- 6.8 Peripherals and System ---
|
||||
/// Invokes a system function (Firmware/OS).
|
||||
/// Operand: syscall_id (u32)
|
||||
@ -261,17 +221,6 @@ impl TryFrom<u16> for OpCode {
|
||||
0x51 => Ok(OpCode::Ret),
|
||||
0x52 => Ok(OpCode::PushScope),
|
||||
0x53 => Ok(OpCode::PopScope),
|
||||
0x60 => Ok(OpCode::Alloc),
|
||||
0x61 => Ok(OpCode::GateLoad),
|
||||
0x62 => Ok(OpCode::GateStore),
|
||||
0x63 => Ok(OpCode::GateBeginPeek),
|
||||
0x64 => Ok(OpCode::GateEndPeek),
|
||||
0x65 => Ok(OpCode::GateBeginBorrow),
|
||||
0x66 => Ok(OpCode::GateEndBorrow),
|
||||
0x67 => Ok(OpCode::GateBeginMutate),
|
||||
0x68 => Ok(OpCode::GateEndMutate),
|
||||
0x69 => Ok(OpCode::GateRetain),
|
||||
0x6A => Ok(OpCode::GateRelease),
|
||||
0x70 => Ok(OpCode::Syscall),
|
||||
0x80 => Ok(OpCode::FrameSync),
|
||||
_ => Err(format!("Invalid OpCode: 0x{:04X}", value)),
|
||||
@ -330,17 +279,6 @@ impl OpCode {
|
||||
OpCode::Ret => 4,
|
||||
OpCode::PushScope => 3,
|
||||
OpCode::PopScope => 3,
|
||||
OpCode::Alloc => 10,
|
||||
OpCode::GateLoad => 3,
|
||||
OpCode::GateStore => 3,
|
||||
OpCode::GateBeginPeek => 1,
|
||||
OpCode::GateEndPeek => 1,
|
||||
OpCode::GateBeginBorrow => 1,
|
||||
OpCode::GateEndBorrow => 1,
|
||||
OpCode::GateBeginMutate => 1,
|
||||
OpCode::GateEndMutate => 1,
|
||||
OpCode::GateRetain => 1,
|
||||
OpCode::GateRelease => 1,
|
||||
OpCode::Syscall => 1,
|
||||
OpCode::FrameSync => 1,
|
||||
}
|
||||
|
||||
@ -434,105 +434,6 @@ impl OpCodeSpecExt for OpCode {
|
||||
is_terminator: false,
|
||||
may_trap: false,
|
||||
},
|
||||
OpCode::Alloc => OpcodeSpec {
|
||||
name: "ALLOC",
|
||||
imm_bytes: 8,
|
||||
pops: 0,
|
||||
pushes: 1,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::GateLoad => OpcodeSpec {
|
||||
name: "GATE_LOAD",
|
||||
imm_bytes: 4,
|
||||
pops: 1,
|
||||
pushes: 1,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::GateStore => OpcodeSpec {
|
||||
name: "GATE_STORE",
|
||||
imm_bytes: 4,
|
||||
pops: 2,
|
||||
pushes: 0,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::GateBeginPeek => OpcodeSpec {
|
||||
name: "GATE_BEGIN_PEEK",
|
||||
imm_bytes: 0,
|
||||
pops: 1,
|
||||
pushes: 1,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::GateEndPeek => OpcodeSpec {
|
||||
name: "GATE_END_PEEK",
|
||||
imm_bytes: 0,
|
||||
pops: 1,
|
||||
pushes: 1,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::GateBeginBorrow => OpcodeSpec {
|
||||
name: "GATE_BEGIN_BORROW",
|
||||
imm_bytes: 0,
|
||||
pops: 1,
|
||||
pushes: 1,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::GateEndBorrow => OpcodeSpec {
|
||||
name: "GATE_END_BORROW",
|
||||
imm_bytes: 0,
|
||||
pops: 1,
|
||||
pushes: 1,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::GateBeginMutate => OpcodeSpec {
|
||||
name: "GATE_BEGIN_MUTATE",
|
||||
imm_bytes: 0,
|
||||
pops: 1,
|
||||
pushes: 1,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::GateEndMutate => OpcodeSpec {
|
||||
name: "GATE_END_MUTATE",
|
||||
imm_bytes: 0,
|
||||
pops: 1,
|
||||
pushes: 1,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::GateRetain => OpcodeSpec {
|
||||
name: "GATE_RETAIN",
|
||||
imm_bytes: 0,
|
||||
pops: 1,
|
||||
pushes: 1,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::GateRelease => OpcodeSpec {
|
||||
name: "GATE_RELEASE",
|
||||
imm_bytes: 0,
|
||||
pops: 1,
|
||||
pushes: 0,
|
||||
is_branch: false,
|
||||
is_terminator: false,
|
||||
may_trap: true,
|
||||
},
|
||||
OpCode::Syscall => OpcodeSpec {
|
||||
name: "SYSCALL",
|
||||
imm_bytes: 4,
|
||||
|
||||
@ -970,119 +970,6 @@ impl VirtualMachine {
|
||||
})?;
|
||||
self.operand_stack.truncate(frame.scope_stack_base);
|
||||
}
|
||||
OpCode::Alloc => {
|
||||
// Allocate a new gate with given type and number of slots.
|
||||
let (type_id, slots_u32) = instr
|
||||
.imm_u32x2()
|
||||
.map_err(|e| LogicalFrameEndingReason::Panic(format!("{:?}", e)))?;
|
||||
let slots = slots_u32 as usize;
|
||||
|
||||
// Bump-allocate on the heap and zero-initialize with Null.
|
||||
let base_idx = self.heap.len();
|
||||
for _ in 0..slots {
|
||||
self.heap.push(Value::Null);
|
||||
}
|
||||
|
||||
// Insert entry into gate pool; GateId is index in this pool.
|
||||
let entry =
|
||||
GateEntry { alive: true, base: base_idx as u32, slots: slots_u32, type_id };
|
||||
let gate_id = self.gate_pool.len() as u32;
|
||||
self.gate_pool.push(entry);
|
||||
|
||||
// Push a Gate value that now carries the GateId instead of a heap base.
|
||||
self.push(Value::Gate(gate_id as usize));
|
||||
}
|
||||
OpCode::GateLoad => {
|
||||
let offset = instr
|
||||
.imm_u32()
|
||||
.map_err(|e| LogicalFrameEndingReason::Panic(format!("{:?}", e)))?
|
||||
as usize;
|
||||
let ref_val = self.pop().map_err(|e| LogicalFrameEndingReason::Panic(e))?;
|
||||
if let Value::Gate(gid_usize) = ref_val {
|
||||
let gid = gid_usize as GateId;
|
||||
let entry = self
|
||||
.resolve_gate(gid, OpCode::GateLoad as u16, start_pc as u32)
|
||||
.map_err(|t| t)?;
|
||||
// bounds check against slots
|
||||
let off_u32 = offset as u32;
|
||||
if off_u32 >= entry.slots {
|
||||
return Err(self.trap(
|
||||
TRAP_OOB,
|
||||
OpCode::GateLoad as u16,
|
||||
format!("Out-of-bounds heap access at offset {}", offset),
|
||||
start_pc as u32,
|
||||
));
|
||||
}
|
||||
let heap_idx = entry.base as usize + offset;
|
||||
let val = self.heap.get(heap_idx).cloned().ok_or_else(|| {
|
||||
// Should not happen if pool and heap are consistent, but keep defensive.
|
||||
self.trap(
|
||||
TRAP_OOB,
|
||||
OpCode::GateLoad as u16,
|
||||
format!("Out-of-bounds heap access at offset {}", offset),
|
||||
start_pc as u32,
|
||||
)
|
||||
})?;
|
||||
self.push(val);
|
||||
} else {
|
||||
return Err(self.trap(
|
||||
TRAP_TYPE,
|
||||
OpCode::GateLoad as u16,
|
||||
"Expected gate handle for GATE_LOAD".to_string(),
|
||||
start_pc as u32,
|
||||
));
|
||||
}
|
||||
}
|
||||
OpCode::GateStore => {
|
||||
let offset = instr
|
||||
.imm_u32()
|
||||
.map_err(|e| LogicalFrameEndingReason::Panic(format!("{:?}", e)))?
|
||||
as usize;
|
||||
let val = self.pop().map_err(|e| LogicalFrameEndingReason::Panic(e))?;
|
||||
let ref_val = self.pop().map_err(|e| LogicalFrameEndingReason::Panic(e))?;
|
||||
if let Value::Gate(gid_usize) = ref_val {
|
||||
let gid = gid_usize as GateId;
|
||||
let entry = self
|
||||
.resolve_gate(gid, OpCode::GateStore as u16, start_pc as u32)
|
||||
.map_err(|t| t)?;
|
||||
let off_u32 = offset as u32;
|
||||
if off_u32 >= entry.slots {
|
||||
return Err(self.trap(
|
||||
TRAP_OOB,
|
||||
OpCode::GateStore as u16,
|
||||
format!("Out-of-bounds heap access at offset {}", offset),
|
||||
start_pc as u32,
|
||||
));
|
||||
}
|
||||
let heap_idx = entry.base as usize + offset;
|
||||
if heap_idx >= self.heap.len() {
|
||||
return Err(self.trap(
|
||||
TRAP_OOB,
|
||||
OpCode::GateStore as u16,
|
||||
format!("Out-of-bounds heap access at offset {}", offset),
|
||||
start_pc as u32,
|
||||
));
|
||||
}
|
||||
self.heap[heap_idx] = val;
|
||||
} else {
|
||||
return Err(self.trap(
|
||||
TRAP_TYPE,
|
||||
OpCode::GateStore as u16,
|
||||
"Expected gate handle for GATE_STORE".to_string(),
|
||||
start_pc as u32,
|
||||
));
|
||||
}
|
||||
}
|
||||
OpCode::GateBeginPeek
|
||||
| OpCode::GateEndPeek
|
||||
| OpCode::GateBeginBorrow
|
||||
| OpCode::GateEndBorrow
|
||||
| OpCode::GateBeginMutate
|
||||
| OpCode::GateEndMutate
|
||||
| OpCode::GateRetain => {}
|
||||
OpCode::GateRelease => {
|
||||
self.pop().map_err(|e| LogicalFrameEndingReason::Panic(e))?;
|
||||
}
|
||||
OpCode::Syscall => {
|
||||
let pc_at_syscall = start_pc as u32;
|
||||
let id = instr
|
||||
@ -1912,134 +1799,19 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hip_traps_oob() {
|
||||
let mut native = MockNative;
|
||||
let mut ctx = HostContext::new(None);
|
||||
|
||||
// ALLOC int, 1 -> Gate(0)
|
||||
// GATE_LOAD 1 -> TRAP_OOB (size is 1, offset 1 is invalid)
|
||||
let mut rom = Vec::new();
|
||||
rom.extend_from_slice(&(OpCode::Alloc as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&0u32.to_le_bytes()); // type_id
|
||||
rom.extend_from_slice(&1u32.to_le_bytes()); // slots
|
||||
rom.extend_from_slice(&(OpCode::GateLoad as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&1u32.to_le_bytes()); // offset 1
|
||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
||||
|
||||
let mut vm = new_test_vm(rom.clone(), vec![]);
|
||||
let report = vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
||||
|
||||
match report.reason {
|
||||
LogicalFrameEndingReason::Trap(trap) => {
|
||||
assert_eq!(trap.code, TRAP_OOB);
|
||||
assert_eq!(trap.opcode, OpCode::GateLoad as u16);
|
||||
assert!(trap.message.contains("Out-of-bounds"));
|
||||
}
|
||||
_ => panic!("Expected Trap, got {:?}", report.reason),
|
||||
}
|
||||
fn test_hip_traps_oob_removed_legacy() {
|
||||
// Legacy HIP opcodes removed; test deleted.
|
||||
assert!(true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hip_traps_type() {
|
||||
let mut native = MockNative;
|
||||
let mut ctx = HostContext::new(None);
|
||||
|
||||
// PUSH_I32 42
|
||||
// GATE_LOAD 0 -> TRAP_TYPE (Expected gate handle, got Int32)
|
||||
let mut rom = Vec::new();
|
||||
rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&42i32.to_le_bytes());
|
||||
rom.extend_from_slice(&(OpCode::GateLoad as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
||||
|
||||
let mut vm = new_test_vm(rom.clone(), vec![]);
|
||||
let report = vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
||||
|
||||
match report.reason {
|
||||
LogicalFrameEndingReason::Trap(trap) => {
|
||||
assert_eq!(trap.code, TRAP_TYPE);
|
||||
assert_eq!(trap.opcode, OpCode::GateLoad as u16);
|
||||
}
|
||||
_ => panic!("Expected Trap, got {:?}", report.reason),
|
||||
}
|
||||
}
|
||||
fn test_hip_traps_type_removed_legacy() { assert!(true); }
|
||||
|
||||
#[test]
|
||||
fn test_gate_ids_distinct_and_round_trip() {
|
||||
let mut native = MockNative;
|
||||
let mut ctx = HostContext::new(None);
|
||||
|
||||
// Program:
|
||||
// ALLOC(type=0, slots=1) -> [g0]
|
||||
// ALLOC(type=0, slots=1) -> [g0, g1]
|
||||
// HALT
|
||||
let mut rom = Vec::new();
|
||||
rom.extend_from_slice(&(OpCode::Alloc as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
||||
rom.extend_from_slice(&1u32.to_le_bytes());
|
||||
rom.extend_from_slice(&(OpCode::Alloc as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
||||
rom.extend_from_slice(&1u32.to_le_bytes());
|
||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
||||
|
||||
let mut vm = new_test_vm(rom.clone(), vec![]);
|
||||
vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
||||
|
||||
let g1 = vm.pop().unwrap();
|
||||
let g0 = vm.pop().unwrap();
|
||||
assert_ne!(g0, g1, "GateIds must be distinct");
|
||||
|
||||
// Now test store/load round-trip using a new small program:
|
||||
// ALLOC(type=0, slots=1) -> [g]
|
||||
// DUP -> [g, g]
|
||||
// PushI32 123 -> [g, g, 123]
|
||||
// GateStore 0 -> []
|
||||
// GateLoad 0 -> [123]
|
||||
// HALT
|
||||
let mut rom = Vec::new();
|
||||
rom.extend_from_slice(&(OpCode::Alloc as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
||||
rom.extend_from_slice(&1u32.to_le_bytes());
|
||||
rom.extend_from_slice(&(OpCode::Dup as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&(OpCode::PushI32 as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&123i32.to_le_bytes());
|
||||
rom.extend_from_slice(&(OpCode::GateStore as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
||||
rom.extend_from_slice(&(OpCode::GateLoad as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
||||
|
||||
let mut vm = new_test_vm(rom.clone(), vec![]);
|
||||
vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
||||
assert_eq!(vm.pop().unwrap(), Value::Int32(123));
|
||||
}
|
||||
fn test_gate_ids_distinct_and_round_trip_removed_legacy() { assert!(true); }
|
||||
|
||||
#[test]
|
||||
fn test_invalid_gate_traps() {
|
||||
let mut native = MockNative;
|
||||
let mut ctx = HostContext::new(None);
|
||||
|
||||
// Program: GATE_LOAD 0; HALT
|
||||
// We'll seed the operand stack with an invalid GateId before running.
|
||||
let mut rom = Vec::new();
|
||||
rom.extend_from_slice(&(OpCode::GateLoad as u16).to_le_bytes());
|
||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
||||
|
||||
let mut vm = new_test_vm(rom.clone(), vec![]);
|
||||
// Push an invalid GateId that is out of range (no allocations were made)
|
||||
vm.operand_stack.push(Value::Gate(42usize));
|
||||
|
||||
let report = vm.run_budget(100, &mut native, &mut ctx).unwrap();
|
||||
match report.reason {
|
||||
LogicalFrameEndingReason::Trap(trap) => {
|
||||
assert_eq!(trap.code, TRAP_OOB);
|
||||
assert_eq!(trap.opcode, OpCode::GateLoad as u16);
|
||||
}
|
||||
_ => panic!("Expected Trap, got {:?}", report.reason),
|
||||
}
|
||||
}
|
||||
fn test_invalid_gate_traps_removed_legacy() { assert!(true); }
|
||||
|
||||
#[test]
|
||||
fn test_entry_point_ret_with_prepare_call() {
|
||||
|
||||
@ -1,39 +1,3 @@
|
||||
# PR-1.3 — Remove RC/HIP Opcodes From `opcode` and Decode/Encode Paths
|
||||
|
||||
### Briefing
|
||||
|
||||
Legacy opcodes must be removed entirely. Decoder/encoder must not recognize them, and there must be no compatibility decoding.
|
||||
|
||||
### Target
|
||||
|
||||
* Remove all RC/HIP opcodes and their textual/structural representation.
|
||||
* Ensure decoding fails deterministically for unknown opcodes.
|
||||
|
||||
### Work items
|
||||
|
||||
* Delete RC/HIP-related opcode variants from `prometeu-bytecode` opcode definitions.
|
||||
* Remove any encode/decode logic for those opcodes.
|
||||
* Ensure decoder behavior for unknown opcodes is:
|
||||
|
||||
* Deterministic.
|
||||
* Produces an actionable error message.
|
||||
* Has no fallback to “legacy”.
|
||||
* Update disasm formatting tables and opcode-name maps.
|
||||
* Update tests/fixtures that referenced removed opcodes.
|
||||
|
||||
### Acceptance checklist
|
||||
|
||||
* [ ] Opcode enum(s) no longer include RC/HIP concepts.
|
||||
* [ ] Encoder/decoder do not accept legacy opcodes.
|
||||
* [ ] Disasm no longer prints legacy opcode names.
|
||||
* [ ] `cargo test` passes.
|
||||
|
||||
### Tests
|
||||
|
||||
* Add/adjust a unit test ensuring decoding an unknown/removed opcode produces the expected error.
|
||||
|
||||
---
|
||||
|
||||
# PR-1.4 — Define the Minimal Core ISA Surface (Bytecode-Only)
|
||||
|
||||
### Briefing
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user