use crate::vm::{addr::Addr, reg::Reg}; macro_rules! instructions { { $($variant:ident = $value:expr),* $(,)? } => { $( pub const $variant: InstOp = $value; )* pub fn inst_name(op: InstOp) -> Option<&'static str> { match op { $( $value => Some(stringify!($variant)), )* _ => None, } } }; } pub type InstOp = u16; instructions! { ADD = 0x0000, SUB = 0x0001, MUL = 0x0002, DIV = 0x0003, MOD = 0x0004, AND = 0x0005, OR = 0x0006, XOR = 0x0007, SHL = 0x0008, SHR = 0x0009, INEG = 0x000a, INV = 0x000b, NOT = 0x000c, CMPEQ = 0x1000, CMPLT = 0x1001, JMP = 0x1002, JZ = 0x1003, JNZ = 0x1004, MOV = 0x2000, HALT = 0xF000, NOP = 0xF001, DUMP = 0xF002, } #[derive(Debug, Clone, Copy)] pub enum Inst { Add(Dest, Source), Sub(Dest, Source), Mul(Dest, Source), Div(Dest, Source), Mod(Dest, Source), And(Dest, Source), Or(Dest, Source), Xor(Dest, Source), Shl(Dest, Source), Shr(Dest, Source), INeg(Dest, Source), Inv(Dest, Source), Not(Dest, Source), CmpEq(Source, Source), CmpLt(Source, Source), Jmp(Source), Jz(Source), Jnz(Source), Mov(Dest, Source), Halt, Nop, Dump, } impl Inst { pub fn op(&self) -> InstOp { match self { Inst::Add(_, _) => ADD, Inst::Sub(_, _) => SUB, Inst::Mul(_, _) => MUL, Inst::Div(_, _) => DIV, Inst::Mod(_, _) => MOD, Inst::And(_, _) => AND, Inst::Or(_, _) => OR, Inst::Xor(_, _) => XOR, Inst::Shl(_, _) => SHL, Inst::Shr(_, _) => SHL, Inst::INeg(_, _) => INEG, Inst::Inv(_, _) => INV, Inst::Not(_, _) => NOT, Inst::CmpEq(_, _) => CMPEQ, Inst::CmpLt(_, _) => CMPLT, Inst::Jmp(_) => JMP, Inst::Jz(_) => JZ, Inst::Jnz(_) => JNZ, Inst::Mov(_, _) => MOV, Inst::Halt => HALT, Inst::Nop => NOP, Inst::Dump => DUMP, } } pub fn len(&self) -> usize { match self { Inst::Add(dest, source) | Inst::Sub(dest, source) | Inst::Mul(dest, source) | Inst::Div(dest, source) | Inst::Mod(dest, source) | Inst::And(dest, source) | Inst::Or(dest, source) | Inst::Xor(dest, source) | Inst::Shl(dest, source) | Inst::Shr(dest, source) | Inst::INeg(dest, source) | Inst::Inv(dest, source) | Inst::Not(dest, source) | Inst::Mov(dest, source) => { 3 + dest.len() + source.len() } Inst::CmpEq(s1, s2) | Inst::CmpLt(s1, s2) => { 3 + s1.len() + s2.len() } Inst::Jmp(v) | Inst::Jz(v) | Inst::Jnz(v) => { 3 + v.len() } Inst::Halt | Inst::Nop | Inst::Dump => { 2 } } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Source { Addr64(Addr), Addr32(Addr), Addr16(Addr), Addr8(Addr), Reg(Reg), Imm(u64), } impl Source { pub fn len(&self) -> usize { match self { Source::Addr64(_) | Source::Addr32(_) | Source::Addr16(_) | Source::Addr8(_) => 8, Source::Reg(_) => 1, Source::Imm(_) => 8, } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Dest { Addr64(Addr), Addr32(Addr), Addr16(Addr), Addr8(Addr), Reg(Reg), } impl Dest { pub fn len(&self) -> usize { match self { Dest::Addr64(_) | Dest::Addr32(_) | Dest::Addr16(_) | Dest::Addr8(_) => 8, Dest::Reg(_) => 1, } } } pub const DEST_ADDR64: u8 = 0b0000; pub const DEST_ADDR32: u8 = 0b0001; pub const DEST_ADDR16: u8 = 0b0010; pub const DEST_ADDR8: u8 = 0b0011; pub const DEST_REG: u8 = 0b0100; pub const SOURCE_ADDR64: u8 = 0b0000; pub const SOURCE_ADDR32: u8 = 0b0001; pub const SOURCE_ADDR16: u8 = 0b0010; pub const SOURCE_ADDR8: u8 = 0b0011; pub const SOURCE_REG: u8 = 0b0100; pub const SOURCE_IMM64: u8 = 0b0101; pub const SOURCE_IMM32: u8 = 0b0110; pub const SOURCE_IMM16: u8 = 0b0111; pub const SOURCE_IMM8: u8 = 0b1000;