8 releases

0.3.1 Nov 11, 2020
0.3.0 Nov 6, 2020
0.2.0 Oct 19, 2020
0.1.4 Oct 18, 2020

#285 in Emulators

MIT/Apache

11KB
99 lines

imperative-rs

This crate provides a trait-definition, error types and a procedural macro to automatically derive instruction sets from enum.

The imperative_rs::InstructionSet-trait consists of two functions. fn InstructionSet::encode(&self, buf:&mut [u8]) -> Result<usize, EncodeError> encodes instructions (i.e. enum-variants) into opcodes (i.e. &[u8]) returning the number of bytes writte. fn decode(mem:&[u8]) -> Result<(usize, Self), DecodeError> decodes an instruction from a &[u8] and returns the instruction and number of bytes read.

Opcodes are defined by attributes on the corresponding enum-variants. The opcodes can be defined as binary or hex strings, can contain underscores for readability and variable names. This way the user can encode the position of encoded variables, but it also means that variable names can only be one symbol long (for now) and cannot contain hex digits.

Example

use imperative_rs::InstructionSet;

#[derive(InstructionSet)]
enum Is {
    //constant opcode
    #[opcode = "0x0000"]
    Nop,
    //hex opcode with split variable x
    #[opcode = "0x1x0x"]
    Inc{x:u8},
    //hex opcode with three variables
    #[ opcode = "0x2xxyyzz" ]
    Add{x:u8, y:u8, z:u8},
    //bin opcode with two variables and underscores for readability
    #[ opcode = "0b100000000_xxxxyyyyy_xyxyxyxy" ]
    Mov{x:u8, y:i8},
}

fn main() {
    let mut mem = [0u8; 1024];
    let (num_bytes, Is::Nop) = Is::decode(&mem).unwrap();
    let instruction = Is::Add{x:0xab, y:0xcd, z:0xef};
    assert_eq!(4, instruction.encode(&mut mem[100..]);
    assert_eq!([0x2a, 0xbc, 0xde, 0xf0], mem[100..104])
}

Dependencies

~1.5MB
~34K SLoC