157 lines
4.2 KiB
Rust
157 lines
4.2 KiB
Rust
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
#[repr(u16)]
|
|
pub enum OpCode {
|
|
// 6.1 Controle de Execução
|
|
Nop = 0x00,
|
|
Halt = 0x01,
|
|
Jmp = 0x02,
|
|
JmpIfFalse = 0x03,
|
|
|
|
// 6.2 Pilha
|
|
PushConst = 0x10,
|
|
Pop = 0x11,
|
|
Dup = 0x12,
|
|
Swap = 0x13,
|
|
|
|
// 6.3 Aritmética
|
|
Add = 0x20,
|
|
Sub = 0x21,
|
|
Mul = 0x22,
|
|
Div = 0x23,
|
|
|
|
// 6.4 Comparação e Lógica
|
|
Eq = 0x30,
|
|
Neq = 0x31,
|
|
Lt = 0x32,
|
|
Gt = 0x33,
|
|
And = 0x34,
|
|
Or = 0x35,
|
|
Not = 0x36,
|
|
|
|
// 6.5 Variáveis
|
|
GetGlobal = 0x40,
|
|
SetGlobal = 0x41,
|
|
GetLocal = 0x42,
|
|
SetLocal = 0x43,
|
|
|
|
// 6.6 Funções
|
|
Call = 0x50,
|
|
Ret = 0x51,
|
|
PushScope = 0x52,
|
|
PopScope = 0x53,
|
|
|
|
// 6.7 Heap
|
|
Alloc = 0x60,
|
|
LoadRef = 0x61,
|
|
StoreRef = 0x62,
|
|
|
|
// 6.8 Periféricos e Sistema
|
|
Syscall = 0x70,
|
|
FrameSync = 0x80,
|
|
}
|
|
|
|
impl TryFrom<u16> for OpCode {
|
|
type Error = String;
|
|
|
|
fn try_from(value: u16) -> Result<Self, Self::Error> {
|
|
match value {
|
|
0x00 => Ok(OpCode::Nop),
|
|
0x01 => Ok(OpCode::Halt),
|
|
0x02 => Ok(OpCode::Jmp),
|
|
0x03 => Ok(OpCode::JmpIfFalse),
|
|
0x10 => Ok(OpCode::PushConst),
|
|
0x11 => Ok(OpCode::Pop),
|
|
0x12 => Ok(OpCode::Dup),
|
|
0x13 => Ok(OpCode::Swap),
|
|
0x20 => Ok(OpCode::Add),
|
|
0x21 => Ok(OpCode::Sub),
|
|
0x22 => Ok(OpCode::Mul),
|
|
0x23 => Ok(OpCode::Div),
|
|
0x30 => Ok(OpCode::Eq),
|
|
0x31 => Ok(OpCode::Neq),
|
|
0x32 => Ok(OpCode::Lt),
|
|
0x33 => Ok(OpCode::Gt),
|
|
0x34 => Ok(OpCode::And),
|
|
0x35 => Ok(OpCode::Or),
|
|
0x36 => Ok(OpCode::Not),
|
|
0x40 => Ok(OpCode::GetGlobal),
|
|
0x41 => Ok(OpCode::SetGlobal),
|
|
0x42 => Ok(OpCode::GetLocal),
|
|
0x43 => Ok(OpCode::SetLocal),
|
|
0x50 => Ok(OpCode::Call),
|
|
0x51 => Ok(OpCode::Ret),
|
|
0x52 => Ok(OpCode::PushScope),
|
|
0x53 => Ok(OpCode::PopScope),
|
|
0x60 => Ok(OpCode::Alloc),
|
|
0x61 => Ok(OpCode::LoadRef),
|
|
0x62 => Ok(OpCode::StoreRef),
|
|
0x70 => Ok(OpCode::Syscall),
|
|
0x80 => Ok(OpCode::FrameSync),
|
|
_ => Err(format!("Invalid OpCode: 0x{:04X}", value)),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl OpCode {
|
|
pub fn cycles(&self) -> u64 {
|
|
match self {
|
|
OpCode::Nop => 1,
|
|
OpCode::Halt => 1,
|
|
OpCode::Jmp => 2,
|
|
OpCode::JmpIfFalse => 3,
|
|
OpCode::PushConst => 2,
|
|
OpCode::Pop => 1,
|
|
OpCode::Dup => 1,
|
|
OpCode::Swap => 1,
|
|
OpCode::Add => 2,
|
|
OpCode::Sub => 2,
|
|
OpCode::Mul => 4,
|
|
OpCode::Div => 6,
|
|
OpCode::Eq => 2,
|
|
OpCode::Neq => 2,
|
|
OpCode::Lt => 2,
|
|
OpCode::Gt => 2,
|
|
OpCode::And => 2,
|
|
OpCode::Or => 2,
|
|
OpCode::Not => 1,
|
|
OpCode::GetGlobal => 3,
|
|
OpCode::SetGlobal => 3,
|
|
OpCode::GetLocal => 2,
|
|
OpCode::SetLocal => 2,
|
|
OpCode::Call => 5,
|
|
OpCode::Ret => 4,
|
|
OpCode::PushScope => 3,
|
|
OpCode::PopScope => 3,
|
|
OpCode::Alloc => 10,
|
|
OpCode::LoadRef => 3,
|
|
OpCode::StoreRef => 3,
|
|
OpCode::Syscall => 1, // Variável, mas vamos usar 1 como base ou definir via ID
|
|
OpCode::FrameSync => 1,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_opcode_decoding() {
|
|
assert_eq!(OpCode::try_from(0x00).unwrap(), OpCode::Nop);
|
|
assert_eq!(OpCode::try_from(0x10).unwrap(), OpCode::PushConst);
|
|
assert_eq!(OpCode::try_from(0x20).unwrap(), OpCode::Add);
|
|
assert_eq!(OpCode::try_from(0x70).unwrap(), OpCode::Syscall);
|
|
assert_eq!(OpCode::try_from(0x80).unwrap(), OpCode::FrameSync);
|
|
assert!(OpCode::try_from(0xFFFF).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_opcode_cycles() {
|
|
assert_eq!(OpCode::Nop.cycles(), 1);
|
|
assert_eq!(OpCode::Add.cycles(), 2);
|
|
assert_eq!(OpCode::Mul.cycles(), 4);
|
|
assert_eq!(OpCode::Div.cycles(), 6);
|
|
assert_eq!(OpCode::Alloc.cycles(), 10);
|
|
}
|
|
} |