add small boot management
This commit is contained in:
parent
b51bd71352
commit
d1c87ef6e7
@ -3,5 +3,6 @@ pub mod peripherals;
|
|||||||
pub mod vm;
|
pub mod vm;
|
||||||
mod model;
|
mod model;
|
||||||
mod native_interface;
|
mod native_interface;
|
||||||
|
mod utilz;
|
||||||
|
|
||||||
pub use machine::Machine;
|
pub use machine::Machine;
|
||||||
|
|||||||
@ -1,13 +1,12 @@
|
|||||||
use crate::vm::Value;
|
use crate::vm::Program;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Cartridge {
|
pub struct Cartridge {
|
||||||
pub rom: Vec<u8>,
|
pub program: Program,
|
||||||
pub constant_pool: Vec<Value>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cartridge {
|
impl Cartridge {
|
||||||
pub fn new(rom: Vec<u8>, constant_pool: Vec<Value>) -> Self {
|
pub fn new(program: Program) -> Self {
|
||||||
Self { rom, constant_pool }
|
Self { program }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,11 +16,12 @@ impl NativeInterface for Machine {
|
|||||||
// system.run_cart()
|
// system.run_cart()
|
||||||
0x0002 => {
|
0x0002 => {
|
||||||
if let Some(cart) = self.cartridge.as_ref() {
|
if let Some(cart) = self.cartridge.as_ref() {
|
||||||
vm.rom = cart.rom.clone();
|
vm.program = cart.program.clone();
|
||||||
vm.constant_pool = cart.constant_pool.clone();
|
|
||||||
vm.pc = 0;
|
vm.pc = 0;
|
||||||
vm.operand_stack.clear();
|
vm.operand_stack.clear();
|
||||||
vm.call_stack.clear();
|
vm.call_stack.clear();
|
||||||
|
vm.globals.clear();
|
||||||
|
vm.heap.clear();
|
||||||
vm.halted = false;
|
vm.halted = false;
|
||||||
} else {
|
} else {
|
||||||
return Err("No cartridge inserted".into());
|
return Err("No cartridge inserted".into());
|
||||||
|
|||||||
18
crates/core/src/utilz.rs
Normal file
18
crates/core/src/utilz.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
use crate::vm::OpCode;
|
||||||
|
|
||||||
|
pub fn emit_u16(rom: &mut Vec<u8>, val: u16) {
|
||||||
|
rom.extend_from_slice(&val.to_le_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn emit_u32(rom: &mut Vec<u8>, val: u32) {
|
||||||
|
rom.extend_from_slice(&val.to_le_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn emit_op(rom: &mut Vec<u8>, op: OpCode) {
|
||||||
|
emit_u16(rom, op as u16);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn patch_u32(rom: &mut [u8], offset: usize, val: u32) {
|
||||||
|
let bytes = val.to_le_bytes();
|
||||||
|
rom[offset..offset + 4].copy_from_slice(&bytes);
|
||||||
|
}
|
||||||
@ -2,6 +2,9 @@ mod virtual_machine;
|
|||||||
mod value;
|
mod value;
|
||||||
mod opcode;
|
mod opcode;
|
||||||
mod call_frame;
|
mod call_frame;
|
||||||
|
mod program;
|
||||||
|
|
||||||
pub use value::Value;
|
pub use value::Value;
|
||||||
pub use virtual_machine::VirtualMachine;
|
pub use virtual_machine::VirtualMachine;
|
||||||
|
pub use opcode::OpCode;
|
||||||
|
pub use program::Program;
|
||||||
|
|||||||
17
crates/core/src/vm/program.rs
Normal file
17
crates/core/src/vm/program.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use crate::vm::Value;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct Program {
|
||||||
|
pub rom: Arc<[u8]>,
|
||||||
|
pub constant_pool: Arc<[Value]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Program {
|
||||||
|
pub fn new(rom: Vec<u8>, constant_pool: Vec<Value>) -> Self {
|
||||||
|
Self {
|
||||||
|
rom: Arc::from(rom),
|
||||||
|
constant_pool: Arc::from(constant_pool),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,16 +1,18 @@
|
|||||||
use crate::native_interface::NativeInterface;
|
use crate::native_interface::NativeInterface;
|
||||||
|
use crate::utilz;
|
||||||
use crate::vm::call_frame::CallFrame;
|
use crate::vm::call_frame::CallFrame;
|
||||||
use crate::vm::opcode::OpCode;
|
use crate::vm::opcode::OpCode;
|
||||||
use crate::vm::value::Value;
|
use crate::vm::value::Value;
|
||||||
|
|
||||||
|
|
||||||
|
use crate::vm::Program;
|
||||||
|
|
||||||
pub struct VirtualMachine {
|
pub struct VirtualMachine {
|
||||||
pub pc: usize,
|
pub pc: usize,
|
||||||
pub operand_stack: Vec<Value>,
|
pub operand_stack: Vec<Value>,
|
||||||
pub call_stack: Vec<CallFrame>,
|
pub call_stack: Vec<CallFrame>,
|
||||||
pub globals: Vec<Value>,
|
pub globals: Vec<Value>,
|
||||||
pub constant_pool: Vec<Value>,
|
pub program: Program,
|
||||||
pub rom: Vec<u8>,
|
|
||||||
pub heap: Vec<Value>, // Simplificado para demo, futuramente RAM/Heap real
|
pub heap: Vec<Value>, // Simplificado para demo, futuramente RAM/Heap real
|
||||||
pub cycles: u64,
|
pub cycles: u64,
|
||||||
pub halted: bool,
|
pub halted: bool,
|
||||||
@ -23,8 +25,7 @@ impl VirtualMachine {
|
|||||||
operand_stack: Vec::new(),
|
operand_stack: Vec::new(),
|
||||||
call_stack: Vec::new(),
|
call_stack: Vec::new(),
|
||||||
globals: Vec::new(),
|
globals: Vec::new(),
|
||||||
constant_pool,
|
program: Program::new(rom, constant_pool),
|
||||||
rom,
|
|
||||||
heap: Vec::new(),
|
heap: Vec::new(),
|
||||||
cycles: 0,
|
cycles: 0,
|
||||||
halted: false,
|
halted: false,
|
||||||
@ -37,95 +38,231 @@ impl VirtualMachine {
|
|||||||
let mut rom = Vec::new();
|
let mut rom = Vec::new();
|
||||||
let mut constant_pool = Vec::new();
|
let mut constant_pool = Vec::new();
|
||||||
|
|
||||||
// Constantes do Boot ROM
|
// Constant Pool
|
||||||
constant_pool.push(Value::Integer(140)); // 0: x
|
constant_pool.push(Value::Integer(160)); // 0: Center X
|
||||||
constant_pool.push(Value::Integer(70)); // 1: y
|
constant_pool.push(Value::Integer(90)); // 1: Center Y
|
||||||
constant_pool.push(Value::Integer(40)); // 2: largura
|
constant_pool.push(Value::Integer(40)); // 2: Logo Size
|
||||||
constant_pool.push(Value::Integer(40)); // 3: altura
|
constant_pool.push(Value::Integer(7)); // 3: Indigo (Logo)
|
||||||
constant_pool.push(Value::Integer(7)); // 4: cor rect (indigo)
|
constant_pool.push(Value::Integer(0)); // 4: Black (Background)
|
||||||
constant_pool.push(Value::Integer(0)); // 5: sample_id (square)
|
constant_pool.push(Value::Integer(180)); // 5: Splash Timeout (3s)
|
||||||
constant_pool.push(Value::Integer(0)); // 6: voice_id
|
constant_pool.push(Value::Integer(2)); // 6: Divisor
|
||||||
constant_pool.push(Value::Integer(255)); // 7: volume
|
constant_pool.push(Value::Integer(1)); // 7: 1
|
||||||
constant_pool.push(Value::Integer(127)); // 8: pan (center)
|
constant_pool.push(Value::Integer(10)); // 8: Start Button
|
||||||
constant_pool.push(Value::Float(1.0)); // 9: pitch
|
constant_pool.push(Value::Integer(0)); // 9: Square Sample
|
||||||
constant_pool.push(Value::Integer(0)); // 10: bg color (black)
|
constant_pool.push(Value::Integer(255)); // 10: Volume
|
||||||
constant_pool.push(Value::Integer(10)); // 11: button START
|
constant_pool.push(Value::Integer(127)); // 11: Pan
|
||||||
|
constant_pool.push(Value::Float(1.0)); // 12: Pitch
|
||||||
|
constant_pool.push(Value::Integer(0)); // 13: Voice ID
|
||||||
|
constant_pool.push(Value::Integer(0)); // 14: Zero
|
||||||
|
constant_pool.push(Value::Integer(6)); // 15: Cyan (SO Logo)
|
||||||
|
|
||||||
// -- PROGRAMA --
|
// -- INICIALIZAÇÃO --
|
||||||
|
|
||||||
// 1. Toca o som de boot "plim" (uma vez)
|
// G0 = 0 (Contador de frames)
|
||||||
// Push arguments for audio.play_sample(sample_id, voice_id, volume, pan, pitch)
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_u32(&mut rom, 14);
|
||||||
rom.extend_from_slice(&5u32.to_le_bytes()); // sample_id
|
utilz::emit_op(&mut rom, OpCode::SetGlobal);
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_u32(&mut rom, 0);
|
||||||
rom.extend_from_slice(&6u32.to_le_bytes()); // voice_id
|
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
// G1 = 0 (Estado BIOS: 0=Splash, 1=SO)
|
||||||
rom.extend_from_slice(&7u32.to_le_bytes()); // volume
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_u32(&mut rom, 14);
|
||||||
rom.extend_from_slice(&8u32.to_le_bytes()); // pan
|
utilz::emit_op(&mut rom, OpCode::SetGlobal);
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_u32(&mut rom, 1);
|
||||||
rom.extend_from_slice(&9u32.to_le_bytes()); // pitch
|
|
||||||
rom.extend_from_slice(&(OpCode::Syscall as u16).to_le_bytes());
|
// Toca o som de boot "plim"
|
||||||
rom.extend_from_slice(&0x3001u32.to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 9); // sample
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 13); // voice
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 10); // vol
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 11); // pan
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 12); // pitch
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
|
utilz::emit_u32(&mut rom, 0x3001);
|
||||||
|
|
||||||
|
// Escopo local para cálculos temporários [0:f, 1:s, 2:x, 3:y]
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushScope);
|
||||||
|
utilz::emit_u32(&mut rom, 4);
|
||||||
|
|
||||||
let loop_start = rom.len() as u32;
|
let loop_start = rom.len() as u32;
|
||||||
|
|
||||||
// 2. Verifica Cartucho e Input para Boot
|
// Limpa tela
|
||||||
// system.has_cart?
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&(OpCode::Syscall as u16).to_le_bytes());
|
utilz::emit_u32(&mut rom, 4); // black
|
||||||
rom.extend_from_slice(&0x0001u32.to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
|
utilz::emit_u32(&mut rom, 0x1001);
|
||||||
let jmp_no_cart_idx = rom.len();
|
|
||||||
rom.extend_from_slice(&(OpCode::JmpIfFalse as u16).to_le_bytes());
|
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes()); // placeholder
|
|
||||||
|
|
||||||
// Se tem cartucho, checa START
|
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
|
||||||
rom.extend_from_slice(&11u32.to_le_bytes()); // START button ID
|
|
||||||
rom.extend_from_slice(&(OpCode::Syscall as u16).to_le_bytes());
|
|
||||||
rom.extend_from_slice(&0x2001u32.to_le_bytes()); // input.get_pad
|
|
||||||
|
|
||||||
let jmp_no_start_idx = rom.len();
|
|
||||||
rom.extend_from_slice(&(OpCode::JmpIfFalse as u16).to_le_bytes());
|
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes()); // placeholder
|
|
||||||
|
|
||||||
// Se tem cartucho E START, run_cart!
|
|
||||||
rom.extend_from_slice(&(OpCode::Syscall as u16).to_le_bytes());
|
|
||||||
rom.extend_from_slice(&0x0002u32.to_le_bytes()); // system.run_cart
|
|
||||||
|
|
||||||
// Destino para quando não tem cartucho ou não apertou START
|
|
||||||
let skip_cart_addr = rom.len() as u32;
|
|
||||||
// Patch placeholders
|
|
||||||
let skip_bytes = skip_cart_addr.to_le_bytes();
|
|
||||||
rom[jmp_no_cart_idx+2..jmp_no_cart_idx+6].copy_from_slice(&skip_bytes);
|
|
||||||
rom[jmp_no_start_idx+2..jmp_no_start_idx+6].copy_from_slice(&skip_bytes);
|
|
||||||
|
|
||||||
// 3. Limpa a tela
|
// --- MÁQUINA DE ESTADOS (G1) ---
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::GetGlobal);
|
||||||
rom.extend_from_slice(&10u32.to_le_bytes()); // bg color
|
utilz::emit_u32(&mut rom, 1); // G1
|
||||||
rom.extend_from_slice(&(OpCode::Syscall as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&0x1001u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 14); // 0
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Eq);
|
||||||
|
let jmp_to_so = rom.len();
|
||||||
|
utilz::emit_op(&mut rom, OpCode::JmpIfFalse);
|
||||||
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
|
||||||
// 4. Desenha o quadrado no centro
|
// === ESTADO 0: SPLASH ===
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes()); // x
|
// 1. Cálculos da Animação
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::GetGlobal);
|
||||||
rom.extend_from_slice(&1u32.to_le_bytes()); // y
|
utilz::emit_u32(&mut rom, 0);
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::SetLocal);
|
||||||
rom.extend_from_slice(&2u32.to_le_bytes()); // w
|
utilz::emit_u32(&mut rom, 0); // L0 = f
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
|
||||||
rom.extend_from_slice(&3u32.to_le_bytes()); // h
|
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
|
||||||
rom.extend_from_slice(&4u32.to_le_bytes()); // color
|
|
||||||
rom.extend_from_slice(&(OpCode::Syscall as u16).to_le_bytes());
|
|
||||||
rom.extend_from_slice(&0x1002u32.to_le_bytes());
|
|
||||||
|
|
||||||
// 4. Sincroniza frame
|
// S = if f < 40 { f } else { 40 }
|
||||||
rom.extend_from_slice(&(OpCode::FrameSync as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::GetLocal);
|
||||||
|
utilz::emit_u32(&mut rom, 0); // f
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 2); // 40
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Lt);
|
||||||
|
let jmp_s_full = rom.len();
|
||||||
|
utilz::emit_op(&mut rom, OpCode::JmpIfFalse);
|
||||||
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
|
||||||
// 5. Loop infinito
|
utilz::emit_op(&mut rom, OpCode::GetLocal);
|
||||||
rom.extend_from_slice(&(OpCode::Jmp as u16).to_le_bytes());
|
utilz::emit_u32(&mut rom, 0); // f
|
||||||
rom.extend_from_slice(&loop_start.to_le_bytes());
|
let jmp_s_set = rom.len();
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Jmp);
|
||||||
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
|
||||||
|
let s_full_addr = rom.len() as u32;
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 2); // 40
|
||||||
|
|
||||||
|
let s_set_addr = rom.len() as u32;
|
||||||
|
utilz::patch_u32(&mut rom, jmp_s_full + 2, s_full_addr);
|
||||||
|
utilz::patch_u32(&mut rom, jmp_s_set + 2, s_set_addr);
|
||||||
|
utilz::emit_op(&mut rom, OpCode::SetLocal);
|
||||||
|
utilz::emit_u32(&mut rom, 1); // L1 = S
|
||||||
|
|
||||||
|
// X = 160 - S/2, Y = 90 - S/2
|
||||||
|
for (local_idx, const_idx) in [(2, 0), (3, 1)] {
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, const_idx);
|
||||||
|
utilz::emit_op(&mut rom, OpCode::GetLocal);
|
||||||
|
utilz::emit_u32(&mut rom, 1); // S
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 6); // 2
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Div);
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Sub);
|
||||||
|
utilz::emit_op(&mut rom, OpCode::SetLocal);
|
||||||
|
utilz::emit_u32(&mut rom, local_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Desenha Quadrado (Logo)
|
||||||
|
utilz::emit_op(&mut rom, OpCode::GetLocal);
|
||||||
|
utilz::emit_u32(&mut rom, 2); // X
|
||||||
|
utilz::emit_op(&mut rom, OpCode::GetLocal);
|
||||||
|
utilz::emit_u32(&mut rom, 3); // Y
|
||||||
|
utilz::emit_op(&mut rom, OpCode::GetLocal);
|
||||||
|
utilz::emit_u32(&mut rom, 1); // W
|
||||||
|
utilz::emit_op(&mut rom, OpCode::GetLocal);
|
||||||
|
utilz::emit_u32(&mut rom, 1); // H
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 3); // Indigo
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
|
utilz::emit_u32(&mut rom, 0x1002);
|
||||||
|
|
||||||
|
// Checagem de Saída do Splash (f >= 180 OR START)
|
||||||
|
utilz::emit_op(&mut rom, OpCode::GetGlobal);
|
||||||
|
utilz::emit_u32(&mut rom, 0); // f
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 5); // 180
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Gt); // f > 180 (ou eq, mas gt é mais seguro)
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 8); // Start
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
|
utilz::emit_u32(&mut rom, 0x2001); // get_pad
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Or);
|
||||||
|
let jmp_splash_continue = rom.len();
|
||||||
|
utilz::emit_op(&mut rom, OpCode::JmpIfFalse);
|
||||||
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
|
||||||
|
// Validação de Cartucho
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
|
utilz::emit_u32(&mut rom, 0x0001); // has_cart?
|
||||||
|
let jmp_no_cart_init = rom.len();
|
||||||
|
utilz::emit_op(&mut rom, OpCode::JmpIfFalse);
|
||||||
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
|
utilz::emit_u32(&mut rom, 0x0002); // run_cart
|
||||||
|
|
||||||
|
// Senão tem cartucho: vai para o SO
|
||||||
|
let no_cart_init_addr = rom.len() as u32;
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 7); // 1
|
||||||
|
utilz::emit_op(&mut rom, OpCode::SetGlobal);
|
||||||
|
utilz::emit_u32(&mut rom, 1); // G1 = 1 (SO)
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 14); // 0
|
||||||
|
utilz::emit_op(&mut rom, OpCode::SetGlobal);
|
||||||
|
utilz::emit_u32(&mut rom, 0); // f = 0 (reset counter for SO)
|
||||||
|
|
||||||
|
let splash_continue_addr = rom.len() as u32;
|
||||||
|
utilz::patch_u32(&mut rom, jmp_splash_continue + 2, splash_continue_addr);
|
||||||
|
utilz::patch_u32(&mut rom, jmp_no_cart_init + 2, no_cart_init_addr);
|
||||||
|
|
||||||
|
let jmp_end_state = rom.len();
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Jmp);
|
||||||
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
|
||||||
|
// === ESTADO 1: SO ===
|
||||||
|
let so_state_addr = rom.len() as u32;
|
||||||
|
utilz::patch_u32(&mut rom, jmp_to_so + 2, so_state_addr);
|
||||||
|
|
||||||
|
// Desenha "SO" (Quadrado Ciano)
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 0); // 160
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 1); // 90
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 2); // 40
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 2); // 40
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 15); // Cyan
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
|
utilz::emit_u32(&mut rom, 0x1002);
|
||||||
|
|
||||||
|
// Monitora Inserção de Cartucho (Hot-plug) + START
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
|
utilz::emit_u32(&mut rom, 0x0001); // has_cart?
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 8); // Start
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
|
utilz::emit_u32(&mut rom, 0x2001); // get_pad
|
||||||
|
utilz::emit_op(&mut rom, OpCode::And); // has_cart AND START
|
||||||
|
let jmp_so_continue = rom.len();
|
||||||
|
utilz::emit_op(&mut rom, OpCode::JmpIfFalse);
|
||||||
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
|
utilz::emit_u32(&mut rom, 0x0002); // run_cart
|
||||||
|
|
||||||
|
let so_continue_addr = rom.len() as u32;
|
||||||
|
utilz::patch_u32(&mut rom, jmp_so_continue + 2, so_continue_addr);
|
||||||
|
|
||||||
|
// Incrementa G0 (f)
|
||||||
|
let end_state_addr = rom.len() as u32;
|
||||||
|
utilz::patch_u32(&mut rom, jmp_end_state + 2, end_state_addr);
|
||||||
|
|
||||||
|
utilz::emit_op(&mut rom, OpCode::GetGlobal);
|
||||||
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
|
utilz::emit_u32(&mut rom, 7); // 1
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Add);
|
||||||
|
utilz::emit_op(&mut rom, OpCode::SetGlobal);
|
||||||
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
|
||||||
|
utilz::emit_op(&mut rom, OpCode::FrameSync);
|
||||||
|
utilz::emit_op(&mut rom, OpCode::Jmp);
|
||||||
|
utilz::emit_u32(&mut rom, loop_start);
|
||||||
|
|
||||||
Self::new(rom, constant_pool)
|
Self::new(rom, constant_pool)
|
||||||
}
|
}
|
||||||
@ -142,7 +279,7 @@ impl VirtualMachine {
|
|||||||
let start_cycles = self.cycles;
|
let start_cycles = self.cycles;
|
||||||
let mut budget_used = 0;
|
let mut budget_used = 0;
|
||||||
|
|
||||||
while budget_used < budget && !self.halted && self.pc < self.rom.len() {
|
while budget_used < budget && !self.halted && self.pc < self.program.rom.len() {
|
||||||
let pc_before = self.pc;
|
let pc_before = self.pc;
|
||||||
let cycles_before = self.cycles;
|
let cycles_before = self.cycles;
|
||||||
let opcode_val = self.peek_u16()?;
|
let opcode_val = self.peek_u16()?;
|
||||||
@ -168,18 +305,18 @@ impl VirtualMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn peek_u16(&self) -> Result<u16, String> {
|
fn peek_u16(&self) -> Result<u16, String> {
|
||||||
if self.pc + 2 > self.rom.len() {
|
if self.pc + 2 > self.program.rom.len() {
|
||||||
return Err("Unexpected end of ROM".into());
|
return Err("Unexpected end of ROM".into());
|
||||||
}
|
}
|
||||||
let bytes = [
|
let bytes = [
|
||||||
self.rom[self.pc],
|
self.program.rom[self.pc],
|
||||||
self.rom[self.pc + 1],
|
self.program.rom[self.pc + 1],
|
||||||
];
|
];
|
||||||
Ok(u16::from_le_bytes(bytes))
|
Ok(u16::from_le_bytes(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self, native: &mut dyn NativeInterface) -> Result<(), String> {
|
pub fn step(&mut self, native: &mut dyn NativeInterface) -> Result<(), String> {
|
||||||
if self.halted || self.pc >= self.rom.len() {
|
if self.halted || self.pc >= self.program.rom.len() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +341,7 @@ impl VirtualMachine {
|
|||||||
}
|
}
|
||||||
OpCode::PushConst => {
|
OpCode::PushConst => {
|
||||||
let idx = self.read_u32()? as usize;
|
let idx = self.read_u32()? as usize;
|
||||||
let val = self.constant_pool.get(idx).cloned().ok_or("Invalid constant index")?;
|
let val = self.program.constant_pool.get(idx).cloned().ok_or("Invalid constant index")?;
|
||||||
self.push(val);
|
self.push(val);
|
||||||
}
|
}
|
||||||
OpCode::Pop => {
|
OpCode::Pop => {
|
||||||
@ -405,26 +542,26 @@ impl VirtualMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_u32(&mut self) -> Result<u32, String> {
|
fn read_u32(&mut self) -> Result<u32, String> {
|
||||||
if self.pc + 4 > self.rom.len() {
|
if self.pc + 4 > self.program.rom.len() {
|
||||||
return Err("Unexpected end of ROM".into());
|
return Err("Unexpected end of ROM".into());
|
||||||
}
|
}
|
||||||
let bytes = [
|
let bytes = [
|
||||||
self.rom[self.pc],
|
self.program.rom[self.pc],
|
||||||
self.rom[self.pc + 1],
|
self.program.rom[self.pc + 1],
|
||||||
self.rom[self.pc + 2],
|
self.program.rom[self.pc + 2],
|
||||||
self.rom[self.pc + 3],
|
self.program.rom[self.pc + 3],
|
||||||
];
|
];
|
||||||
self.pc += 4;
|
self.pc += 4;
|
||||||
Ok(u32::from_le_bytes(bytes))
|
Ok(u32::from_le_bytes(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_u16(&mut self) -> Result<u16, String> {
|
fn read_u16(&mut self) -> Result<u16, String> {
|
||||||
if self.pc + 2 > self.rom.len() {
|
if self.pc + 2 > self.program.rom.len() {
|
||||||
return Err("Unexpected end of ROM".into());
|
return Err("Unexpected end of ROM".into());
|
||||||
}
|
}
|
||||||
let bytes = [
|
let bytes = [
|
||||||
self.rom[self.pc],
|
self.program.rom[self.pc],
|
||||||
self.rom[self.pc + 1],
|
self.program.rom[self.pc + 1],
|
||||||
];
|
];
|
||||||
self.pc += 2;
|
self.pc += 2;
|
||||||
Ok(u16::from_le_bytes(bytes))
|
Ok(u16::from_le_bytes(bytes))
|
||||||
@ -477,12 +614,12 @@ mod tests {
|
|||||||
let mut native = NoopNative;
|
let mut native = NoopNative;
|
||||||
|
|
||||||
let mut rom = Vec::new();
|
let mut rom = Vec::new();
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes()); // Const index 0
|
utilz::emit_u32(&mut rom, 0); // Const index 0
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&1u32.to_le_bytes()); // Const index 1
|
utilz::emit_u32(&mut rom, 1); // Const index 1
|
||||||
rom.extend_from_slice(&(OpCode::Add as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Add);
|
||||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Halt);
|
||||||
|
|
||||||
let constant_pool = vec![Value::Integer(10), Value::Integer(20)];
|
let constant_pool = vec![Value::Integer(10), Value::Integer(20)];
|
||||||
let mut vm = VirtualMachine::new(rom, constant_pool);
|
let mut vm = VirtualMachine::new(rom, constant_pool);
|
||||||
@ -504,39 +641,39 @@ mod tests {
|
|||||||
|
|
||||||
let mut rom = Vec::new();
|
let mut rom = Vec::new();
|
||||||
// Index 0: PUSH 0 (counter)
|
// Index 0: PUSH 0 (counter)
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
|
||||||
// Index 6: DUP
|
// Index 6: DUP
|
||||||
let loop_start = rom.len();
|
let loop_start = rom.len();
|
||||||
rom.extend_from_slice(&(OpCode::Dup as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Dup);
|
||||||
|
|
||||||
// PUSH 10
|
// PUSH 10
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&1u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 1);
|
||||||
|
|
||||||
// LT (counter < 10)
|
// LT (counter < 10)
|
||||||
rom.extend_from_slice(&(OpCode::Lt as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Lt);
|
||||||
|
|
||||||
// JMP_IF_FALSE to end
|
// JMP_IF_FALSE to end
|
||||||
rom.extend_from_slice(&(OpCode::JmpIfFalse as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::JmpIfFalse);
|
||||||
let jmp_placeholder = rom.len();
|
let jmp_placeholder = rom.len();
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 0);
|
||||||
|
|
||||||
// PUSH 1
|
// PUSH 1
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&2u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 2);
|
||||||
|
|
||||||
// ADD (increment counter)
|
// ADD (increment counter)
|
||||||
rom.extend_from_slice(&(OpCode::Add as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Add);
|
||||||
|
|
||||||
// JMP to start
|
// JMP to start
|
||||||
rom.extend_from_slice(&(OpCode::Jmp as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Jmp);
|
||||||
rom.extend_from_slice(&(loop_start as u32).to_le_bytes());
|
utilz::emit_u32(&mut rom, loop_start as u32);
|
||||||
|
|
||||||
// End
|
// End
|
||||||
let loop_end = rom.len();
|
let loop_end = rom.len();
|
||||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Halt);
|
||||||
|
|
||||||
// Patch JMP_IF_FALSE addr
|
// Patch JMP_IF_FALSE addr
|
||||||
let end_addr_bytes = (loop_end as u32).to_le_bytes();
|
let end_addr_bytes = (loop_end as u32).to_le_bytes();
|
||||||
@ -571,12 +708,12 @@ mod tests {
|
|||||||
|
|
||||||
let mut rom = Vec::new();
|
let mut rom = Vec::new();
|
||||||
// PUSH 5 (color index)
|
// PUSH 5 (color index)
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 0);
|
||||||
// CALL_NATIVE 0x1001
|
// CALL_NATIVE 0x1001
|
||||||
rom.extend_from_slice(&(OpCode::Syscall as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
rom.extend_from_slice(&0x1001u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 0x1001);
|
||||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Halt);
|
||||||
|
|
||||||
let constant_pool = vec![Value::Integer(5)];
|
let constant_pool = vec![Value::Integer(5)];
|
||||||
let mut vm = VirtualMachine::new(rom, constant_pool);
|
let mut vm = VirtualMachine::new(rom, constant_pool);
|
||||||
@ -597,9 +734,9 @@ mod tests {
|
|||||||
// 1. Verifica que não tem cartucho inicialmente
|
// 1. Verifica que não tem cartucho inicialmente
|
||||||
let mut rom = Vec::new();
|
let mut rom = Vec::new();
|
||||||
// CALL_NATIVE 0x0001 (has_cart)
|
// CALL_NATIVE 0x0001 (has_cart)
|
||||||
rom.extend_from_slice(&(OpCode::Syscall as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Syscall);
|
||||||
rom.extend_from_slice(&0x0001u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 0x0001);
|
||||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Halt);
|
||||||
|
|
||||||
machine.vm = VirtualMachine::new(rom, vec![]);
|
machine.vm = VirtualMachine::new(rom, vec![]);
|
||||||
let mut vm = std::mem::take(&mut machine.vm);
|
let mut vm = std::mem::take(&mut machine.vm);
|
||||||
@ -611,19 +748,19 @@ mod tests {
|
|||||||
// 2. Adiciona um cartucho e roda
|
// 2. Adiciona um cartucho e roda
|
||||||
let mut cart_rom = Vec::new();
|
let mut cart_rom = Vec::new();
|
||||||
// PUSH_CONST 0
|
// PUSH_CONST 0
|
||||||
cart_rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut cart_rom, OpCode::PushConst);
|
||||||
cart_rom.extend_from_slice(&0u32.to_le_bytes());
|
utilz::emit_u32(&mut cart_rom, 0);
|
||||||
cart_rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
utilz::emit_op(&mut cart_rom, OpCode::Halt);
|
||||||
let cart_pool = vec![Value::Integer(42)];
|
let cart_pool = vec![Value::Integer(42)];
|
||||||
|
|
||||||
let cart = Cartridge::new(cart_rom, cart_pool);
|
let cart = Cartridge::new(Program::new(cart_rom, cart_pool));
|
||||||
machine.load_cartridge(cart);
|
machine.load_cartridge(cart);
|
||||||
|
|
||||||
// Código para rodar o cartucho
|
// Código para rodar o cartucho
|
||||||
let mut boot_rom = Vec::new();
|
let mut boot_rom = Vec::new();
|
||||||
// CALL_NATIVE 0x0002 (run_cart)
|
// CALL_NATIVE 0x0002 (run_cart)
|
||||||
boot_rom.extend_from_slice(&(OpCode::Syscall as u16).to_le_bytes());
|
utilz::emit_op(&mut boot_rom, OpCode::Syscall);
|
||||||
boot_rom.extend_from_slice(&0x0002u32.to_le_bytes());
|
utilz::emit_u32(&mut boot_rom, 0x0002);
|
||||||
|
|
||||||
machine.vm = VirtualMachine::new(boot_rom, vec![]);
|
machine.vm = VirtualMachine::new(boot_rom, vec![]);
|
||||||
let mut vm = std::mem::take(&mut machine.vm);
|
let mut vm = std::mem::take(&mut machine.vm);
|
||||||
@ -645,13 +782,13 @@ mod tests {
|
|||||||
|
|
||||||
let mut rom = Vec::new();
|
let mut rom = Vec::new();
|
||||||
// PUSH 10, PUSH 20, SWAP, POP
|
// PUSH 10, PUSH 20, SWAP, POP
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 0);
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&1u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 1);
|
||||||
rom.extend_from_slice(&(OpCode::Swap as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Swap);
|
||||||
rom.extend_from_slice(&(OpCode::Pop as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Pop);
|
||||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Halt);
|
||||||
|
|
||||||
let constant_pool = vec![Value::Integer(10), Value::Integer(20)];
|
let constant_pool = vec![Value::Integer(10), Value::Integer(20)];
|
||||||
let mut vm = VirtualMachine::new(rom, constant_pool);
|
let mut vm = VirtualMachine::new(rom, constant_pool);
|
||||||
@ -671,13 +808,13 @@ mod tests {
|
|||||||
|
|
||||||
let mut rom = Vec::new();
|
let mut rom = Vec::new();
|
||||||
// PUSH true, NOT (-> false), PUSH true, OR (-> true)
|
// PUSH true, NOT (-> false), PUSH true, OR (-> true)
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes()); // true
|
utilz::emit_u32(&mut rom, 0); // true
|
||||||
rom.extend_from_slice(&(OpCode::Not as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Not);
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes()); // true
|
utilz::emit_u32(&mut rom, 0); // true
|
||||||
rom.extend_from_slice(&(OpCode::Or as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Or);
|
||||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Halt);
|
||||||
|
|
||||||
let constant_pool = vec![Value::Boolean(true)];
|
let constant_pool = vec![Value::Boolean(true)];
|
||||||
let mut vm = VirtualMachine::new(rom, constant_pool);
|
let mut vm = VirtualMachine::new(rom, constant_pool);
|
||||||
@ -696,16 +833,16 @@ mod tests {
|
|||||||
|
|
||||||
let mut rom = Vec::new();
|
let mut rom = Vec::new();
|
||||||
// PUSH_SCOPE 2 (reserves 2 nulls), PUSH 42, SET_LOCAL 0, GET_LOCAL 0, POP_SCOPE
|
// PUSH_SCOPE 2 (reserves 2 nulls), PUSH 42, SET_LOCAL 0, GET_LOCAL 0, POP_SCOPE
|
||||||
rom.extend_from_slice(&(OpCode::PushScope as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushScope);
|
||||||
rom.extend_from_slice(&2u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 2);
|
||||||
rom.extend_from_slice(&(OpCode::PushConst as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PushConst);
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes()); // 42
|
utilz::emit_u32(&mut rom, 0); // 42
|
||||||
rom.extend_from_slice(&(OpCode::SetLocal as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::SetLocal);
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 0);
|
||||||
rom.extend_from_slice(&(OpCode::GetLocal as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::GetLocal);
|
||||||
rom.extend_from_slice(&0u32.to_le_bytes());
|
utilz::emit_u32(&mut rom, 0);
|
||||||
rom.extend_from_slice(&(OpCode::PopScope as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::PopScope);
|
||||||
rom.extend_from_slice(&(OpCode::Halt as u16).to_le_bytes());
|
utilz::emit_op(&mut rom, OpCode::Halt);
|
||||||
|
|
||||||
let constant_pool = vec![Value::Integer(42)];
|
let constant_pool = vec![Value::Integer(42)];
|
||||||
let mut vm = VirtualMachine::new(rom, constant_pool);
|
let mut vm = VirtualMachine::new(rom, constant_pool);
|
||||||
|
|||||||
@ -373,18 +373,31 @@ Efeito prático:
|
|||||||
|
|
||||||
A **PROMETEU VM** nunca inicia em um estado totalmente "vazio" ou inativo.
|
A **PROMETEU VM** nunca inicia em um estado totalmente "vazio" ou inativo.
|
||||||
|
|
||||||
### 13.1 O Boot ROM
|
### 13.1 O Boot ROM (BIOS)
|
||||||
Se a máquina for inicializada sem um cartucho específico carregado, a VM executa um **Boot ROM padrão**. Este é um pequeno programa em bytecode embutido no core que:
|
Se a máquina for inicializada sem um cartucho específico carregado, a VM executa um **Boot ROM padrão**. Este é um pequeno programa em bytecode embutido no core que gerencia o ciclo de vida inicial da máquina através de uma máquina de estados:
|
||||||
* Emite um som de "plim" ao iniciar.
|
|
||||||
* Realiza um ciclo básico de limpeza de tela (preto).
|
|
||||||
* Exibe um quadrado centralizado (índigo).
|
|
||||||
* Serve como indicador visual e auditivo de que o hardware lógico está operacional.
|
|
||||||
|
|
||||||
### 13.2 Ciclo de Boot
|
#### Fase 1: BOOT (Splash & Som)
|
||||||
1. O Core é inicializado via `Machine::new()`.
|
1. **Som de Inicialização**: Emite um som de "plim" (`0x3001`) imediatamente ao ligar (frame 0).
|
||||||
2. A VM é carregada com o Boot ROM via `VirtualMachine::default()`.
|
2. **Splash Animation**: Exibe o logotipo (quadrado Índigo) crescendo suavemente (0-40 frames).
|
||||||
3. O PC (Program Counter) é definido como `0`.
|
3. **Splash Estático**: O logotipo permanece na tela até o frame 180 (~3 segundos).
|
||||||
4. A execução começa imediatamente no primeiro `step_frame`.
|
4. **Interrupção**: O usuário pode pular o Splash a qualquer momento pressionando **START**.
|
||||||
|
|
||||||
|
#### Fase 2: C_VALIDATION (Validação)
|
||||||
|
Ao fim do Splash ou interrupção, a BIOS verifica a presença de um cartucho:
|
||||||
|
- **Com Cartucho**: Chama `system.run_cart` (`0x0002`) para transferir o controle.
|
||||||
|
- **Sem Cartucho**: Transita para o **Estado de SO**.
|
||||||
|
|
||||||
|
#### Fase 3: RUN (Sistema Operacional / Fallback)
|
||||||
|
Se nenhum cartucho for detectado, a máquina entra em modo "SO":
|
||||||
|
1. **Interface**: Exibe um quadrado **Ciano** no centro da tela.
|
||||||
|
2. **Hot-plug**: Monitora em tempo real a inserção de cartuchos. Se um cartucho for inserido e o botão **START** for pressionado, o cartucho é iniciado.
|
||||||
|
|
||||||
|
### 13.2 Ciclo de Memória
|
||||||
|
A instrução `system.run_cart` garante um ambiente limpo para o novo programa:
|
||||||
|
1. Reseta o **PC** para 0.
|
||||||
|
2. Limpa as pilhas (**Operand Stack** e **Call Stack**).
|
||||||
|
3. Limpa a memória (**Globals** e **Heap**).
|
||||||
|
4. Carrega a nova **ROM** e **Constant Pool** do cartucho.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user