split files
This commit is contained in:
parent
cbb9b93ce1
commit
d051a1b246
@ -1,8 +1,12 @@
|
|||||||
|
use crate::vm::{Value, VirtualMachine};
|
||||||
use crate::Machine;
|
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 {
|
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 {
|
match id {
|
||||||
// system.has_cart() -> bool
|
// system.has_cart() -> bool
|
||||||
0x0001 => {
|
0x0001 => {
|
||||||
@ -69,7 +73,7 @@ impl NativeInterface for Machine {
|
|||||||
}
|
}
|
||||||
Ok(300)
|
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 struct VirtualMachine {
|
||||||
pub pc: usize,
|
pub pc: usize,
|
||||||
@ -575,7 +392,7 @@ impl VirtualMachine {
|
|||||||
}
|
}
|
||||||
OpCode::Syscall => {
|
OpCode::Syscall => {
|
||||||
let id = self.read_u32()?;
|
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;
|
self.cycles += native_cycles;
|
||||||
}
|
}
|
||||||
OpCode::FrameSync => {
|
OpCode::FrameSync => {
|
||||||
@ -655,7 +472,7 @@ mod tests {
|
|||||||
fn test_add_instructions() {
|
fn test_add_instructions() {
|
||||||
struct NoopNative;
|
struct NoopNative;
|
||||||
impl NativeInterface for 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;
|
let mut native = NoopNative;
|
||||||
|
|
||||||
@ -681,7 +498,7 @@ mod tests {
|
|||||||
fn test_jump_and_loop() {
|
fn test_jump_and_loop() {
|
||||||
struct NoopNative;
|
struct NoopNative;
|
||||||
impl NativeInterface for 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;
|
let mut native = NoopNative;
|
||||||
|
|
||||||
@ -741,7 +558,7 @@ mod tests {
|
|||||||
cleared_color: Option<usize>,
|
cleared_color: Option<usize>,
|
||||||
}
|
}
|
||||||
impl NativeInterface for MockGfx {
|
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 {
|
if id == 0x1001 {
|
||||||
let color = vm.pop_integer()? as usize;
|
let color = vm.pop_integer()? as usize;
|
||||||
self.cleared_color = Some(color);
|
self.cleared_color = Some(color);
|
||||||
Loading…
x
Reference in New Issue
Block a user