// Instruction encoding: pack / unpack a 32-bit instruction word.
//
// M1 uses a single-width instruction format: every instruction is a `UInt`
// with four byte-sized fields:
//
// bits 0..7 opcode
// bits 8..15 operand A
// bits 16..23 operand B
// bits 24..31 operand C
//
// Callers should treat the layout as opaque and go through `encode` / `decode`.
// The wide-prefix convention that spans two instruction words is handled
// higher up in `chunk.mbt`; this file deals only with a single word.
///|
/// Decoded view of a single instruction word. Field names match the encoding
/// documented at the top of this file.
pub struct DecodedInstr {
op : Byte
a : Byte
b : Byte
c : Byte
} derive(Eq, @debug.Debug)
///|
/// Pack four bytes into an instruction word. Round-trips with `decode`.
pub fn encode(op : Byte, a : Byte, b : Byte, c : Byte) -> UInt {
let op_u = op.to_uint()
let a_u = a.to_uint() << 8
let b_u = b.to_uint() << 16
let c_u = c.to_uint() << 24
op_u | a_u | b_u | c_u
}
///|
/// Unpack an instruction word into `(op, a, b, c)`.
pub fn decode(word : UInt) -> DecodedInstr {
{
op: (word & 0xFFU).to_byte(),
a: ((word >> 8) & 0xFFU).to_byte(),
b: ((word >> 16) & 0xFFU).to_byte(),
c: ((word >> 24) & 0xFFU).to_byte(),
}
}