use crate::register::Register; use std::str::FromStr; use strawberryvm_derive::VmInstruction; /// All instructions for the VM. They are automatically /// implemented with an encode function to turn them into /// binary and also implements From traits. #[derive(Debug, VmInstruction)] pub enum Instruction { #[opcode(0x0)] Nop, #[opcode(0x1)] Push(u8), #[opcode(0x2)] PopReg(Register), #[opcode(0x3)] PushReg(Register), #[opcode(0x4)] AddStack, #[opcode(0x5)] AddReg(Register, Register), #[opcode(0x6)] Signal(u8), #[opcode(0x7)] Jmp(u8), } fn parse_instruction_arg(ins: u16) -> u8 { ((ins & 0xff00) >> 8) as u8 } impl TryFrom for Instruction { type Error = String; fn try_from(ins: u16) -> Result { let op = (ins & 0xff) as u8; let opcode = OpCode::try_from(op)?; match opcode { OpCode::Nop => Ok(Instruction::Nop), OpCode::Push => { let arg = parse_instruction_arg(ins); Ok(Instruction::Push(arg)) } OpCode::PopReg => { let reg = (ins & 0xf00) >> 8; let reg = Register::from(reg as u8); Ok(Instruction::PopReg(reg)) } OpCode::PushReg => { let reg = (ins & 0xf00) >> 8; let reg = Register::from(reg as u8); Ok(Instruction::PushReg(reg)) } OpCode::AddStack => Ok(Instruction::AddStack), OpCode::AddReg => { let r1 = Register::from(((ins & 0xf00) >> 8) as u8); let r2 = Register::from(((ins & 0xf00) >> 12) as u8); Ok(Instruction::AddReg(r1, r2)) } OpCode::Signal => { let arg = parse_instruction_arg(ins); Ok(Instruction::Signal(arg)) } OpCode::Jmp => { let reg = parse_instruction_arg(ins); Ok(Instruction::Jmp(reg)) } } } }