Skip to content

External data as tag? #6

@stevefan1999-personal

Description

@stevefan1999-personal

I want to use this library to encode a simple instruction set

use bin_proto::{ BitCodec, BitDecode, BitEncode, LittleEndian};

#[derive(Debug, BitDecode, BitEncode, PartialEq)]
#[bin_proto(discriminant_type = u16, bits = 10)]
#[repr(u8)]
pub enum Opcode {
    Nop = 0,
    Load(UnaryOp) = 1,
    Store(UnaryOp) = 2,
    Add(BinaryOp) = 3,
    Sub(BinaryOp) = 4,
    Mul(BinaryOp) = 5,
    Div(BinaryOp) = 6,
    Mod(BinaryOp) = 7,
    And(BinaryOp) = 8,
    Or(BinaryOp) = 9,
    Xor(BinaryOp) = 10,
    Equal(BinaryOp) = 11,
    NotEqual(BinaryOp) = 12,
    LessThan(BinaryOp) = 13,
    GreaterThan(BinaryOp) = 14,
    Not(UnaryOp) = 15,
    LogicalNot(UnaryOp) = 16,
    Shl(BinaryOp) = 17,
    Shr(BinaryOp) = 18,
}

#[derive(Debug, BitDecode, BitEncode, PartialEq)]
pub struct UnaryOp {
    pub with: WithFlags,
    pub dest: Operands,
    pub src: Operands
}

#[derive(Debug, BitDecode, BitEncode, PartialEq)]
pub struct WithFlags {
    #[bin_proto(bits = 1)]
    pub set_carry: bool,
    #[bin_proto(bits = 1)]
    pub set_zero: bool,
    #[bin_proto(bits = 1)]
    pub set_overflow: bool
}

#[derive(Debug, BitDecode, BitEncode, PartialEq)]
pub struct BinaryOp {
    pub with: WithFlags,
    pub dest: Operands,
    pub src1: Operands,
    pub src2: Operands
}

#[derive(Debug, BitDecode, BitEncode, PartialEq)]
#[bin_proto(discriminant_type = u8, bits = 2)]
#[repr(u8)]
pub enum Register {
    Integer(#[bin_proto(bits = 4)] u8) = 0,
    Float(#[bin_proto(bits = 4)] u8) = 1,
}

// Memory addressing (4 bits for mode + data)
#[derive(Debug, BitDecode, BitEncode, PartialEq)]
#[bin_proto(discriminant_type = u8, bits = 3)]
#[repr(u8)]
pub enum MemAccess {
    Indirect(Register) = 0,                              // [reg]
    BaseDisp(Register, #[bin_proto(bits = 16)] i16) = 1, // [reg+disp]
    Indexed(Register, Register) = 2,                     // [base+index]
    Absolute(usize) = 3,           // [addr]
}

#[derive(Debug, BitDecode, BitEncode, PartialEq)]
#[bin_proto(discriminant_type = u8, bits = 4)]
#[repr(u8)]
pub enum Immediate {
    I8(#[bin_proto(bits = 8)] i8) = 0,
    I16(#[bin_proto(bits = 16)] i16) = 1,
    I32(#[bin_proto(bits = 32)] i32) = 2,
    I64(#[bin_proto(bits = 64)] i64) = 3,
    I128(#[bin_proto(bits = 128)] i128) = 4,
    U8(#[bin_proto(bits = 8)] u8) = 5,
    U16(#[bin_proto(bits = 16)] u16) = 6,
    U32(#[bin_proto(bits = 32)] u32) = 7,
    U64(#[bin_proto(bits = 64)] u64) = 8,
    U128(#[bin_proto(bits = 128)] u128) = 9,
    Pointer(usize) = 10,
}

#[derive(Debug, BitDecode, BitEncode, PartialEq)]
#[bin_proto(discriminant_type = u8, bits = 2)]
#[repr(u8)]
pub enum Operands {
    Register(Register) = 0,
    Immediate(Immediate) = 1,
    MemAccess(MemAccess) = 2,
}

fn main() {
    let op_nop = Opcode::Nop;
    let encoded_nop = op_nop.encode_bytes(LittleEndian).unwrap();
    println!("Encoded NOP: {:?}", encoded_nop);

    let op_add = Opcode::Add(BinaryOp {
        with: WithFlags {
            set_carry: true,
            set_zero: true,
            set_overflow: false,
        },
        dest: Operands::Register(Register::Integer(1)),
        src1: Operands::Immediate(Immediate::I16(2)),
        src2: Operands::Immediate(Immediate::I16(122)),
    });
    let encoded_add = op_add.encode_bytes(LittleEndian).unwrap();
    println!("Encoded ADD: {:?}", encoded_add);
    let (decoded_add, read) = Opcode::decode_bytes(&encoded_add, LittleEndian).unwrap();
    println!("Decoded ADD: {:?}, read: {read}", decoded_add);

    let op_not = Opcode::Not(UnaryOp {
        with: WithFlags {
            set_carry: false,
            set_zero: true,
            set_overflow: false,
        },
        dest: Operands::Register(Register::Integer(1)),
        src: Operands::Register(Register::Integer(1)),
    });
    let encoded_not = op_not.encode_bytes(LittleEndian).unwrap();
    println!("Encoded NOT: {:?}", encoded_not);
    let (decoded_not, read) = Opcode::decode_bytes(&encoded_not, LittleEndian).unwrap();
    println!("Decoded NOT: {:?}, read: {read}", decoded_not);
}

I want to make it look like x86 but with a format like this, is it really the most efficient? How do I handle alignment? I noticed that the data I encoded often has some remaining bits left, what's the best practice to skip them in the instruction parsing stream?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions