split files
This commit is contained in:
parent
f319d0dbaf
commit
aef5b89cdb
@ -1,8 +1,12 @@
|
||||
use crate::vm::{Value, VirtualMachine};
|
||||
use crate::Machine;
|
||||
use crate::vm::{NativeInterface, Value, VirtualMachine};
|
||||
|
||||
pub trait NativeInterface {
|
||||
fn syscall(&mut self, id: u32, vm: &mut crate::vm::VirtualMachine) -> Result<u64, String>;
|
||||
}
|
||||
|
||||
impl NativeInterface for Machine {
|
||||
fn call(&mut self, id: u32, vm: &mut VirtualMachine) -> Result<u64, String> {
|
||||
fn syscall(&mut self, id: u32, vm: &mut VirtualMachine) -> Result<u64, String> {
|
||||
match id {
|
||||
// system.has_cart() -> bool
|
||||
0x0001 => {
|
||||
@ -69,7 +73,7 @@ impl NativeInterface for Machine {
|
||||
}
|
||||
Ok(300)
|
||||
}
|
||||
_ => Err(format!("Unknown native call: 0x{:08X}", id)),
|
||||
_ => Err(format!("Unknown syscall: 0x{:08X}", id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
5
crates/core/src/vm/call_frame.rs
Normal file
5
crates/core/src/vm/call_frame.rs
Normal file
@ -0,0 +1,5 @@
|
||||
pub struct CallFrame {
|
||||
pub return_address: usize,
|
||||
pub stack_base: usize,
|
||||
pub locals_count: usize,
|
||||
}
|
||||
7
crates/core/src/vm/mod.rs
Normal file
7
crates/core/src/vm/mod.rs
Normal file
@ -0,0 +1,7 @@
|
||||
mod virtual_machine;
|
||||
mod value;
|
||||
mod opcode;
|
||||
mod call_frame;
|
||||
|
||||
pub use value::Value;
|
||||
pub use virtual_machine::VirtualMachine;
|
||||
133
crates/core/src/vm/opcode.rs
Normal file
133
crates/core/src/vm/opcode.rs
Normal file
@ -0,0 +1,133 @@
|
||||
|
||||
#[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,
|
||||
}
|
||||
}
|
||||
}
|
||||
43
crates/core/src/vm/value.rs
Normal file
43
crates/core/src/vm/value.rs
Normal file
@ -0,0 +1,43 @@
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Value {
|
||||
Integer(i64),
|
||||
Float(f64),
|
||||
Boolean(bool),
|
||||
String(String),
|
||||
Ref(usize), // Referência ao heap
|
||||
Null,
|
||||
}
|
||||
|
||||
impl PartialEq for Value {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Value::Integer(a), Value::Integer(b)) => a == b,
|
||||
(Value::Float(a), Value::Float(b)) => a == b,
|
||||
(Value::Integer(a), Value::Float(b)) => *a as f64 == *b,
|
||||
(Value::Float(a), Value::Integer(b)) => *a == *b as f64,
|
||||
(Value::Boolean(a), Value::Boolean(b)) => a == b,
|
||||
(Value::String(a), Value::String(b)) => a == b,
|
||||
(Value::Ref(a), Value::Ref(b)) => a == b,
|
||||
(Value::Null, Value::Null) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn as_float(&self) -> Option<f64> {
|
||||
match self {
|
||||
Value::Integer(i) => Some(*i as f64),
|
||||
Value::Float(f) => Some(*f),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_integer(&self) -> Option<i64> {
|
||||
match self {
|
||||
Value::Integer(i) => Some(*i),
|
||||
Value::Float(f) => Some(*f as i64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,191 +1,8 @@
|
||||
use std::convert::TryFrom;
|
||||
use crate::native_interface::NativeInterface;
|
||||
use crate::vm::call_frame::CallFrame;
|
||||
use crate::vm::opcode::OpCode;
|
||||
use crate::vm::value::Value;
|
||||
|
||||
#[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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Value {
|
||||
Integer(i64),
|
||||
Float(f64),
|
||||
Boolean(bool),
|
||||
String(String),
|
||||
Ref(usize), // Referência ao heap
|
||||
Null,
|
||||
}
|
||||
|
||||
impl PartialEq for Value {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Value::Integer(a), Value::Integer(b)) => a == b,
|
||||
(Value::Float(a), Value::Float(b)) => a == b,
|
||||
(Value::Integer(a), Value::Float(b)) => *a as f64 == *b,
|
||||
(Value::Float(a), Value::Integer(b)) => *a == *b as f64,
|
||||
(Value::Boolean(a), Value::Boolean(b)) => a == b,
|
||||
(Value::String(a), Value::String(b)) => a == b,
|
||||
(Value::Ref(a), Value::Ref(b)) => a == b,
|
||||
(Value::Null, Value::Null) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn as_float(&self) -> Option<f64> {
|
||||
match self {
|
||||
Value::Integer(i) => Some(*i as f64),
|
||||
Value::Float(f) => Some(*f),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_integer(&self) -> Option<i64> {
|
||||
match self {
|
||||
Value::Integer(i) => Some(*i),
|
||||
Value::Float(f) => Some(*f as i64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CallFrame {
|
||||
pub return_address: usize,
|
||||
pub stack_base: usize,
|
||||
pub locals_count: usize,
|
||||
}
|
||||
|
||||
pub trait NativeInterface {
|
||||
fn call(&mut self, id: u32, vm: &mut VirtualMachine) -> Result<u64, String>;
|
||||
}
|
||||
|
||||
pub struct VirtualMachine {
|
||||
pub pc: usize,
|
||||
@ -575,7 +392,7 @@ impl VirtualMachine {
|
||||
}
|
||||
OpCode::Syscall => {
|
||||
let id = self.read_u32()?;
|
||||
let native_cycles = native.call(id, self).map_err(|e| format!("Native call 0x{:08X} failed: {}", id, e))?;
|
||||
let native_cycles = native.syscall(id, self).map_err(|e| format!("syscall 0x{:08X} failed: {}", id, e))?;
|
||||
self.cycles += native_cycles;
|
||||
}
|
||||
OpCode::FrameSync => {
|
||||
@ -655,7 +472,7 @@ mod tests {
|
||||
fn test_add_instructions() {
|
||||
struct NoopNative;
|
||||
impl NativeInterface for NoopNative {
|
||||
fn call(&mut self, _id: u32, _vm: &mut VirtualMachine) -> Result<u64, String> { Ok(0) }
|
||||
fn syscall(&mut self, _id: u32, _vm: &mut VirtualMachine) -> Result<u64, String> { Ok(0) }
|
||||
}
|
||||
let mut native = NoopNative;
|
||||
|
||||
@ -681,7 +498,7 @@ mod tests {
|
||||
fn test_jump_and_loop() {
|
||||
struct NoopNative;
|
||||
impl NativeInterface for NoopNative {
|
||||
fn call(&mut self, _id: u32, _vm: &mut VirtualMachine) -> Result<u64, String> { Ok(0) }
|
||||
fn syscall(&mut self, _id: u32, _vm: &mut VirtualMachine) -> Result<u64, String> { Ok(0) }
|
||||
}
|
||||
let mut native = NoopNative;
|
||||
|
||||
@ -741,7 +558,7 @@ mod tests {
|
||||
cleared_color: Option<usize>,
|
||||
}
|
||||
impl NativeInterface for MockGfx {
|
||||
fn call(&mut self, id: u32, vm: &mut VirtualMachine) -> Result<u64, String> {
|
||||
fn syscall(&mut self, id: u32, vm: &mut VirtualMachine) -> Result<u64, String> {
|
||||
if id == 0x1001 {
|
||||
let color = vm.pop_integer()? as usize;
|
||||
self.cleared_color = Some(color);
|
||||
Loading…
x
Reference in New Issue
Block a user