implements PLN-0054
This commit is contained in:
parent
d1f4547e44
commit
446044c4e6
@ -1,6 +1,8 @@
|
|||||||
use crate::CrashReport;
|
use crate::CrashReport;
|
||||||
use crate::VirtualMachineRuntime;
|
use crate::VirtualMachineRuntime;
|
||||||
|
use crate::fs::{FsBackend, FsState, VirtualFS};
|
||||||
use crate::process::ProcessManager;
|
use crate::process::ProcessManager;
|
||||||
|
use crate::services::memcard::MemcardService;
|
||||||
use crate::services::window_manager::WindowManager;
|
use crate::services::window_manager::WindowManager;
|
||||||
use crate::task::TaskId;
|
use crate::task::TaskId;
|
||||||
use crate::task::TaskManager;
|
use crate::task::TaskManager;
|
||||||
@ -9,6 +11,7 @@ use prometeu_hal::log::{LogLevel, LogService, LogSource};
|
|||||||
use prometeu_hal::telemetry::CertificationConfig;
|
use prometeu_hal::telemetry::CertificationConfig;
|
||||||
use prometeu_hal::{HardwareBridge, InputSignals};
|
use prometeu_hal::{HardwareBridge, InputSignals};
|
||||||
use prometeu_vm::VirtualMachine;
|
use prometeu_vm::VirtualMachine;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub struct SystemOS {
|
pub struct SystemOS {
|
||||||
@ -17,6 +20,11 @@ pub struct SystemOS {
|
|||||||
pub task_manager: TaskManager,
|
pub task_manager: TaskManager,
|
||||||
pub window_manager: WindowManager,
|
pub window_manager: WindowManager,
|
||||||
pub log_service: LogService,
|
pub log_service: LogService,
|
||||||
|
pub fs: VirtualFS,
|
||||||
|
pub fs_state: FsState,
|
||||||
|
pub memcard: MemcardService,
|
||||||
|
pub open_files: HashMap<u32, String>,
|
||||||
|
pub next_handle: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemOS {
|
impl SystemOS {
|
||||||
@ -31,6 +39,11 @@ impl SystemOS {
|
|||||||
task_manager: TaskManager::new(),
|
task_manager: TaskManager::new(),
|
||||||
window_manager: WindowManager::new(),
|
window_manager: WindowManager::new(),
|
||||||
log_service,
|
log_service,
|
||||||
|
fs: VirtualFS::new(),
|
||||||
|
fs_state: FsState::Unmounted,
|
||||||
|
memcard: MemcardService::new(),
|
||||||
|
open_files: HashMap::new(),
|
||||||
|
next_handle: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
os.log(LogLevel::Info, LogSource::Pos, 0, "PrometeuOS starting...".to_string());
|
os.log(LogLevel::Info, LogSource::Pos, 0, "PrometeuOS starting...".to_string());
|
||||||
@ -47,6 +60,7 @@ impl SystemOS {
|
|||||||
vm: &mut VirtualMachine,
|
vm: &mut VirtualMachine,
|
||||||
cartridge: &Cartridge,
|
cartridge: &Cartridge,
|
||||||
) -> Result<(), CrashReport> {
|
) -> Result<(), CrashReport> {
|
||||||
|
self.clear_cartridge_service_state();
|
||||||
self.vm_runtime.initialize_vm(&mut self.log_service, vm, cartridge)
|
self.vm_runtime.initialize_vm(&mut self.log_service, vm, cartridge)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +70,32 @@ impl SystemOS {
|
|||||||
signals: &InputSignals,
|
signals: &InputSignals,
|
||||||
hw: &mut dyn HardwareBridge,
|
hw: &mut dyn HardwareBridge,
|
||||||
) -> Option<CrashReport> {
|
) -> Option<CrashReport> {
|
||||||
self.vm_runtime.tick(&mut self.log_service, vm, signals, hw)
|
self.vm_runtime.tick(
|
||||||
|
&mut self.log_service,
|
||||||
|
&mut self.fs,
|
||||||
|
&mut self.fs_state,
|
||||||
|
&mut self.memcard,
|
||||||
|
&mut self.open_files,
|
||||||
|
&mut self.next_handle,
|
||||||
|
vm,
|
||||||
|
signals,
|
||||||
|
hw,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mount_fs(&mut self, backend: Box<dyn FsBackend>) {
|
||||||
|
self.vm_runtime.mount_fs(&mut self.log_service, &mut self.fs, &mut self.fs_state, backend);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unmount_fs(&mut self) {
|
||||||
|
self.fs.unmount();
|
||||||
|
self.fs_state = FsState::Unmounted;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_cartridge_service_state(&mut self) {
|
||||||
|
self.open_files.clear();
|
||||||
|
self.next_handle = 1;
|
||||||
|
self.memcard.clear_all_staging();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_vm_game_task(&mut self, app_id: u32, title: impl Into<String>) -> TaskId {
|
pub fn create_vm_game_task(&mut self, app_id: u32, title: impl Into<String>) -> TaskId {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::services::memcard::{MemcardSlotState, MemcardStatus};
|
use crate::fs::{FsState, VirtualFS};
|
||||||
|
use crate::services::memcard::{MemcardService, MemcardSlotState, MemcardStatus};
|
||||||
use prometeu_bytecode::{TRAP_INVALID_SYSCALL, TRAP_OOB, TRAP_TYPE, Value};
|
use prometeu_bytecode::{TRAP_INVALID_SYSCALL, TRAP_OOB, TRAP_TYPE, Value};
|
||||||
use prometeu_hal::asset::{AssetId, AssetOpStatus, BankType, SlotRef};
|
use prometeu_hal::asset::{AssetId, AssetOpStatus, BankType, SlotRef};
|
||||||
use prometeu_hal::cartridge::AppMode;
|
use prometeu_hal::cartridge::AppMode;
|
||||||
@ -13,6 +14,7 @@ use prometeu_hal::{
|
|||||||
AudioOpStatus, ComposerOpStatus, HostContext, HostReturn, NativeInterface, SyscallId,
|
AudioOpStatus, ComposerOpStatus, HostContext, HostReturn, NativeInterface, SyscallId,
|
||||||
expect_bool, expect_int,
|
expect_bool, expect_int,
|
||||||
};
|
};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
@ -20,6 +22,11 @@ use std::sync::atomic::Ordering;
|
|||||||
pub(crate) struct VmRuntimeHost<'a> {
|
pub(crate) struct VmRuntimeHost<'a> {
|
||||||
pub runtime: &'a mut VirtualMachineRuntime,
|
pub runtime: &'a mut VirtualMachineRuntime,
|
||||||
pub log_service: &'a mut LogService,
|
pub log_service: &'a mut LogService,
|
||||||
|
pub fs: &'a mut VirtualFS,
|
||||||
|
pub fs_state: &'a mut FsState,
|
||||||
|
pub memcard: &'a mut MemcardService,
|
||||||
|
pub open_files: &'a mut HashMap<u32, String>,
|
||||||
|
pub next_handle: &'a mut u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for VmRuntimeHost<'_> {
|
impl Deref for VmRuntimeHost<'_> {
|
||||||
@ -419,13 +426,13 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
|||||||
}
|
}
|
||||||
Syscall::FsOpen => {
|
Syscall::FsOpen => {
|
||||||
let path = expect_string(args, 0, "path")?;
|
let path = expect_string(args, 0, "path")?;
|
||||||
if self.fs_state != FsState::Mounted {
|
if *self.fs_state != FsState::Mounted {
|
||||||
ret.push_int(-1);
|
ret.push_int(-1);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let handle = self.next_handle;
|
let handle = *self.next_handle;
|
||||||
self.open_files.insert(handle, path);
|
self.open_files.insert(handle, path);
|
||||||
self.next_handle += 1;
|
*self.next_handle += 1;
|
||||||
ret.push_int(handle as i64);
|
ret.push_int(handle as i64);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -542,14 +549,8 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let payload = hex_decode(&payload_hex)?;
|
let payload = hex_decode(&payload_hex)?;
|
||||||
let runtime = &mut self.runtime;
|
let app_id = self.current_app_id;
|
||||||
let write = runtime.memcard.slot_write(
|
let write = self.memcard.slot_write(&self.fs, app_id, slot, offset, &payload);
|
||||||
&runtime.fs,
|
|
||||||
runtime.current_app_id,
|
|
||||||
slot,
|
|
||||||
offset,
|
|
||||||
&payload,
|
|
||||||
);
|
|
||||||
ret.push_int(write.status as i64);
|
ret.push_int(write.status as i64);
|
||||||
ret.push_int(write.bytes_written as i64);
|
ret.push_int(write.bytes_written as i64);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -561,10 +562,10 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let status = {
|
let status = {
|
||||||
let runtime = &mut self.runtime;
|
let app_id = self.current_app_id;
|
||||||
let memcard = &mut runtime.memcard;
|
let memcard = &mut self.memcard;
|
||||||
let fs = &mut runtime.fs;
|
let fs = &mut self.fs;
|
||||||
memcard.slot_commit(fs, runtime.current_app_id, slot)
|
memcard.slot_commit(fs, app_id, slot)
|
||||||
};
|
};
|
||||||
ret.push_int(status as i64);
|
ret.push_int(status as i64);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -576,10 +577,10 @@ impl NativeInterface for VmRuntimeHost<'_> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let status = {
|
let status = {
|
||||||
let runtime = &mut self.runtime;
|
let app_id = self.current_app_id;
|
||||||
let memcard = &mut runtime.memcard;
|
let memcard = &mut self.memcard;
|
||||||
let fs = &mut runtime.fs;
|
let fs = &mut self.fs;
|
||||||
memcard.slot_clear(fs, runtime.current_app_id, slot)
|
memcard.slot_clear(fs, app_id, slot)
|
||||||
};
|
};
|
||||||
ret.push_int(status as i64);
|
ret.push_int(status as i64);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::CrashReport;
|
use crate::CrashReport;
|
||||||
use crate::fs::FsBackend;
|
use crate::fs::{FsBackend, FsState, VirtualFS};
|
||||||
use prometeu_hal::cartridge::Cartridge;
|
use prometeu_hal::cartridge::Cartridge;
|
||||||
use prometeu_hal::log::{LogLevel, LogSource};
|
use prometeu_hal::log::{LogLevel, LogSource};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
impl VirtualMachineRuntime {
|
impl VirtualMachineRuntime {
|
||||||
pub fn new_with_log_counter(
|
pub fn new_with_log_counter(
|
||||||
@ -17,11 +18,6 @@ impl VirtualMachineRuntime {
|
|||||||
logical_frame_active: false,
|
logical_frame_active: false,
|
||||||
logical_frame_remaining_cycles: 0,
|
logical_frame_remaining_cycles: 0,
|
||||||
last_frame_cpu_time_us: 0,
|
last_frame_cpu_time_us: 0,
|
||||||
fs: VirtualFS::new(),
|
|
||||||
fs_state: FsState::Unmounted,
|
|
||||||
memcard: MemcardService::new(),
|
|
||||||
open_files: HashMap::new(),
|
|
||||||
next_handle: 1,
|
|
||||||
current_app_id: 0,
|
current_app_id: 0,
|
||||||
current_cartridge_title: String::new(),
|
current_cartridge_title: String::new(),
|
||||||
current_cartridge_app_version: String::new(),
|
current_cartridge_app_version: String::new(),
|
||||||
@ -53,7 +49,13 @@ impl VirtualMachineRuntime {
|
|||||||
log_service.log(ts_ms, frame, level, source, tag, msg);
|
log_service.log(ts_ms, frame, level, source, tag, msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mount_fs(&mut self, log_service: &mut LogService, backend: Box<dyn FsBackend>) {
|
pub fn mount_fs(
|
||||||
|
&mut self,
|
||||||
|
log_service: &mut LogService,
|
||||||
|
fs: &mut VirtualFS,
|
||||||
|
fs_state: &mut FsState,
|
||||||
|
backend: Box<dyn FsBackend>,
|
||||||
|
) {
|
||||||
self.log(
|
self.log(
|
||||||
log_service,
|
log_service,
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
@ -61,9 +63,9 @@ impl VirtualMachineRuntime {
|
|||||||
0,
|
0,
|
||||||
"Attempting to mount filesystem".to_string(),
|
"Attempting to mount filesystem".to_string(),
|
||||||
);
|
);
|
||||||
match self.fs.mount(backend) {
|
match fs.mount(backend) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
self.fs_state = FsState::Mounted;
|
*fs_state = FsState::Mounted;
|
||||||
self.log(
|
self.log(
|
||||||
log_service,
|
log_service,
|
||||||
LogLevel::Info,
|
LogLevel::Info,
|
||||||
@ -75,18 +77,23 @@ impl VirtualMachineRuntime {
|
|||||||
Err(e) => {
|
Err(e) => {
|
||||||
let err_msg = format!("Failed to mount filesystem: {:?}", e);
|
let err_msg = format!("Failed to mount filesystem: {:?}", e);
|
||||||
self.log(log_service, LogLevel::Error, LogSource::Fs, 0, err_msg);
|
self.log(log_service, LogLevel::Error, LogSource::Fs, 0, err_msg);
|
||||||
self.fs_state = FsState::Error(e);
|
*fs_state = FsState::Error(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmount_fs(&mut self) {
|
pub fn unmount_fs(&mut self, fs: &mut VirtualFS, fs_state: &mut FsState) {
|
||||||
self.fs.unmount();
|
fs.unmount();
|
||||||
self.fs_state = FsState::Unmounted;
|
*fs_state = FsState::Unmounted;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn update_fs(&mut self, log_service: &mut LogService) {
|
pub(crate) fn update_fs(
|
||||||
if self.fs_state == FsState::Mounted && !self.fs.is_healthy() {
|
&mut self,
|
||||||
|
log_service: &mut LogService,
|
||||||
|
fs: &mut VirtualFS,
|
||||||
|
fs_state: &mut FsState,
|
||||||
|
) {
|
||||||
|
if *fs_state == FsState::Mounted && !fs.is_healthy() {
|
||||||
self.log(
|
self.log(
|
||||||
log_service,
|
log_service,
|
||||||
LogLevel::Error,
|
LogLevel::Error,
|
||||||
@ -94,7 +101,7 @@ impl VirtualMachineRuntime {
|
|||||||
0,
|
0,
|
||||||
"Filesystem became unhealthy, unmounting".to_string(),
|
"Filesystem became unhealthy, unmounting".to_string(),
|
||||||
);
|
);
|
||||||
self.unmount_fs();
|
self.unmount_fs(fs, fs_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,10 +112,6 @@ impl VirtualMachineRuntime {
|
|||||||
self.last_frame_cpu_time_us = 0;
|
self.last_frame_cpu_time_us = 0;
|
||||||
self.atomic_telemetry.reset();
|
self.atomic_telemetry.reset();
|
||||||
|
|
||||||
self.open_files.clear();
|
|
||||||
self.next_handle = 1;
|
|
||||||
self.memcard.clear_all_staging();
|
|
||||||
|
|
||||||
self.current_app_id = 0;
|
self.current_app_id = 0;
|
||||||
self.current_cartridge_title.clear();
|
self.current_cartridge_title.clear();
|
||||||
self.current_cartridge_app_version.clear();
|
self.current_cartridge_app_version.clear();
|
||||||
|
|||||||
@ -5,8 +5,6 @@ mod tests;
|
|||||||
mod tick;
|
mod tick;
|
||||||
|
|
||||||
use crate::CrashReport;
|
use crate::CrashReport;
|
||||||
use crate::fs::{FsState, VirtualFS};
|
|
||||||
use crate::services::memcard::MemcardService;
|
|
||||||
use prometeu_bytecode::string_materialization_count;
|
use prometeu_bytecode::string_materialization_count;
|
||||||
use prometeu_hal::cartridge::AppMode;
|
use prometeu_hal::cartridge::AppMode;
|
||||||
use prometeu_hal::log::LogService;
|
use prometeu_hal::log::LogService;
|
||||||
@ -23,11 +21,6 @@ pub struct VirtualMachineRuntime {
|
|||||||
pub logical_frame_active: bool,
|
pub logical_frame_active: bool,
|
||||||
pub logical_frame_remaining_cycles: u64,
|
pub logical_frame_remaining_cycles: u64,
|
||||||
pub last_frame_cpu_time_us: u64,
|
pub last_frame_cpu_time_us: u64,
|
||||||
pub fs: VirtualFS,
|
|
||||||
pub fs_state: FsState,
|
|
||||||
pub memcard: MemcardService,
|
|
||||||
pub open_files: HashMap<u32, String>,
|
|
||||||
pub next_handle: u32,
|
|
||||||
pub current_app_id: u32,
|
pub current_app_id: u32,
|
||||||
pub current_cartridge_title: String,
|
pub current_cartridge_title: String,
|
||||||
pub current_cartridge_app_version: String,
|
pub current_cartridge_app_version: String,
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::fs::{FsBackend, FsEntry, FsError};
|
use crate::fs::{FsBackend, FsEntry, FsError, FsState, VirtualFS};
|
||||||
|
use crate::services::memcard::MemcardService;
|
||||||
use prometeu_bytecode::TRAP_TYPE;
|
use prometeu_bytecode::TRAP_TYPE;
|
||||||
use prometeu_bytecode::Value;
|
use prometeu_bytecode::Value;
|
||||||
use prometeu_bytecode::assembler::assemble;
|
use prometeu_bytecode::assembler::assemble;
|
||||||
@ -189,6 +190,11 @@ mod fs_memcard;
|
|||||||
fn initialize_vm_applies_cartridge_capabilities_before_loader_resolution() {
|
fn initialize_vm_applies_cartridge_capabilities_before_loader_resolution() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let code = assemble("PUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
|
let code = assemble("PUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
|
||||||
let program = serialized_single_function_module(
|
let program = serialized_single_function_module(
|
||||||
@ -215,6 +221,11 @@ fn initialize_vm_applies_cartridge_capabilities_before_loader_resolution() {
|
|||||||
fn initialize_vm_succeeds_when_cartridge_capabilities_cover_hostcalls() {
|
fn initialize_vm_succeeds_when_cartridge_capabilities_cover_hostcalls() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let code = assemble("PUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
|
let code = assemble("PUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
|
||||||
let program = serialized_single_function_module(
|
let program = serialized_single_function_module(
|
||||||
@ -240,6 +251,11 @@ fn initialize_vm_succeeds_when_cartridge_capabilities_cover_hostcalls() {
|
|||||||
fn tick_returns_error_when_vm_ends_slice_with_trap() {
|
fn tick_returns_error_when_vm_ends_slice_with_trap() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -259,7 +275,17 @@ fn tick_returns_error_when_vm_ends_slice_with_trap() {
|
|||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
|
|
||||||
let report = runtime
|
let report = runtime
|
||||||
.tick(&mut log_service, &mut vm, &signals, &mut hardware)
|
.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
)
|
||||||
.expect("trap must surface as runtime error");
|
.expect("trap must surface as runtime error");
|
||||||
|
|
||||||
match report {
|
match report {
|
||||||
@ -276,6 +302,11 @@ fn tick_returns_error_when_vm_ends_slice_with_trap() {
|
|||||||
fn tick_system_profile_rejects_gfx_game_surface() {
|
fn tick_system_profile_rejects_gfx_game_surface() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -294,7 +325,17 @@ fn tick_system_profile_rejects_gfx_game_surface() {
|
|||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime
|
let report = runtime
|
||||||
.tick(&mut log_service, &mut vm, &signals, &mut hardware)
|
.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
)
|
||||||
.expect("system gfx call must trap");
|
.expect("system gfx call must trap");
|
||||||
|
|
||||||
match report {
|
match report {
|
||||||
@ -310,6 +351,11 @@ fn tick_system_profile_rejects_gfx_game_surface() {
|
|||||||
fn tick_system_profile_rejects_composer_game_surface() {
|
fn tick_system_profile_rejects_composer_game_surface() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -328,7 +374,17 @@ fn tick_system_profile_rejects_composer_game_surface() {
|
|||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime
|
let report = runtime
|
||||||
.tick(&mut log_service, &mut vm, &signals, &mut hardware)
|
.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
)
|
||||||
.expect("system composer call must trap");
|
.expect("system composer call must trap");
|
||||||
|
|
||||||
match report {
|
match report {
|
||||||
@ -346,6 +402,11 @@ fn tick_system_profile_rejects_composer_game_surface() {
|
|||||||
fn tick_system_profile_rejects_bank_game_surface() {
|
fn tick_system_profile_rejects_bank_game_surface() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -364,7 +425,17 @@ fn tick_system_profile_rejects_bank_game_surface() {
|
|||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime
|
let report = runtime
|
||||||
.tick(&mut log_service, &mut vm, &signals, &mut hardware)
|
.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
)
|
||||||
.expect("system bank call must trap");
|
.expect("system bank call must trap");
|
||||||
|
|
||||||
match report {
|
match report {
|
||||||
@ -380,6 +451,11 @@ fn tick_system_profile_rejects_bank_game_surface() {
|
|||||||
fn tick_system_profile_can_use_shared_log_transport() {
|
fn tick_system_profile_can_use_shared_log_transport() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -398,7 +474,17 @@ fn tick_system_profile_can_use_shared_log_transport() {
|
|||||||
let cartridge = cartridge_with_program_and_mode(program, caps::LOG, AppMode::Shell);
|
let cartridge = cartridge_with_program_and_mode(program, caps::LOG, AppMode::Shell);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
|
|
||||||
assert!(report.is_none(), "system log transport must remain internally shared");
|
assert!(report.is_none(), "system log transport must remain internally shared");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
@ -408,12 +494,27 @@ fn tick_system_profile_can_use_shared_log_transport() {
|
|||||||
fn tick_returns_panic_report_distinct_from_trap() {
|
fn tick_returns_panic_report_distinct_from_trap() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::new(assemble("HOSTCALL 0\nHALT").expect("assemble"), vec![]);
|
let mut vm = VirtualMachine::new(assemble("HOSTCALL 0\nHALT").expect("assemble"), vec![]);
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
|
|
||||||
let report = runtime
|
let report = runtime
|
||||||
.tick(&mut log_service, &mut vm, &signals, &mut hardware)
|
.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
)
|
||||||
.expect("panic must surface as runtime error");
|
.expect("panic must surface as runtime error");
|
||||||
|
|
||||||
match report {
|
match report {
|
||||||
@ -430,6 +531,11 @@ fn tick_returns_panic_report_distinct_from_trap() {
|
|||||||
fn tick_renders_bound_eight_pixel_scene_through_frame_composer_path() {
|
fn tick_renders_bound_eight_pixel_scene_through_frame_composer_path() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
let program =
|
let program =
|
||||||
@ -447,7 +553,17 @@ fn tick_renders_bound_eight_pixel_scene_through_frame_composer_path() {
|
|||||||
assert!(hardware.frame_composer.bind_scene(0));
|
assert!(hardware.frame_composer.bind_scene(0));
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
|
|
||||||
assert!(report.is_none(), "frame render path must not crash");
|
assert!(report.is_none(), "frame render path must not crash");
|
||||||
hardware.gfx.present();
|
hardware.gfx.present();
|
||||||
@ -458,6 +574,11 @@ fn tick_renders_bound_eight_pixel_scene_through_frame_composer_path() {
|
|||||||
fn tick_renders_scene_through_public_composer_syscalls() {
|
fn tick_renders_scene_through_public_composer_syscalls() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
let code = assemble(
|
let code = assemble(
|
||||||
@ -507,7 +628,17 @@ fn tick_renders_scene_through_public_composer_syscalls() {
|
|||||||
hardware.gfx.hud_fade_level = 31;
|
hardware.gfx.hud_fade_level = 31;
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
|
|
||||||
assert!(report.is_none(), "public composer path must not crash");
|
assert!(report.is_none(), "public composer path must not crash");
|
||||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(ComposerOpStatus::Ok as i64)]);
|
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(ComposerOpStatus::Ok as i64)]);
|
||||||
@ -519,6 +650,11 @@ fn tick_renders_scene_through_public_composer_syscalls() {
|
|||||||
fn tick_draw_text_survives_scene_backed_frame_composition() {
|
fn tick_draw_text_survives_scene_backed_frame_composition() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
let code = assemble(
|
let code = assemble(
|
||||||
@ -569,7 +705,17 @@ fn tick_draw_text_survives_scene_backed_frame_composition() {
|
|||||||
hardware.gfx.hud_fade_level = 31;
|
hardware.gfx.hud_fade_level = 31;
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
|
|
||||||
assert!(report.is_none(), "scene-backed overlay text must not crash");
|
assert!(report.is_none(), "scene-backed overlay text must not crash");
|
||||||
hardware.gfx.present();
|
hardware.gfx.present();
|
||||||
@ -580,6 +726,11 @@ fn tick_draw_text_survives_scene_backed_frame_composition() {
|
|||||||
fn tick_draw_text_survives_no_scene_frame_path() {
|
fn tick_draw_text_survives_no_scene_frame_path() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
let code = assemble(
|
let code = assemble(
|
||||||
@ -603,7 +754,17 @@ fn tick_draw_text_survives_no_scene_frame_path() {
|
|||||||
hardware.gfx.hud_fade_level = 31;
|
hardware.gfx.hud_fade_level = 31;
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
|
|
||||||
assert!(report.is_none(), "no-scene overlay text must not crash");
|
assert!(report.is_none(), "no-scene overlay text must not crash");
|
||||||
hardware.gfx.present();
|
hardware.gfx.present();
|
||||||
@ -614,6 +775,11 @@ fn tick_draw_text_survives_no_scene_frame_path() {
|
|||||||
fn initialize_vm_success_clears_previous_crash_report() {
|
fn initialize_vm_success_clears_previous_crash_report() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
runtime.last_crash_report = Some(CrashReport::VmPanic { message: "stale".into(), pc: Some(1) });
|
runtime.last_crash_report = Some(CrashReport::VmPanic { message: "stale".into(), pc: Some(1) });
|
||||||
|
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
@ -638,15 +804,16 @@ fn initialize_vm_success_clears_previous_crash_report() {
|
|||||||
fn reset_clears_cartridge_scoped_runtime_state() {
|
fn reset_clears_cartridge_scoped_runtime_state() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
|
let mut fs_state = FsState::Mounted;
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 9;
|
||||||
|
|
||||||
runtime.tick_index = 77;
|
runtime.tick_index = 77;
|
||||||
runtime.logical_frame_index = 12;
|
runtime.logical_frame_index = 12;
|
||||||
runtime.logical_frame_active = true;
|
runtime.logical_frame_active = true;
|
||||||
runtime.logical_frame_remaining_cycles = 345;
|
runtime.logical_frame_remaining_cycles = 345;
|
||||||
runtime.last_frame_cpu_time_us = 678;
|
runtime.last_frame_cpu_time_us = 678;
|
||||||
runtime.fs_state = FsState::Mounted;
|
open_files.insert(7, "/save.dat".into());
|
||||||
runtime.open_files.insert(7, "/save.dat".into());
|
|
||||||
runtime.next_handle = 9;
|
|
||||||
runtime.current_app_id = 42;
|
runtime.current_app_id = 42;
|
||||||
runtime.current_cartridge_title = "Cart".into();
|
runtime.current_cartridge_title = "Cart".into();
|
||||||
runtime.current_cartridge_app_version = "1.2.3".into();
|
runtime.current_cartridge_app_version = "1.2.3".into();
|
||||||
@ -668,13 +835,13 @@ fn reset_clears_cartridge_scoped_runtime_state() {
|
|||||||
runtime.reset(&mut vm);
|
runtime.reset(&mut vm);
|
||||||
|
|
||||||
assert_eq!(runtime.tick_index, 77);
|
assert_eq!(runtime.tick_index, 77);
|
||||||
assert_eq!(runtime.fs_state, FsState::Mounted);
|
assert_eq!(fs_state, FsState::Mounted);
|
||||||
assert_eq!(runtime.logical_frame_index, 0);
|
assert_eq!(runtime.logical_frame_index, 0);
|
||||||
assert!(!runtime.logical_frame_active);
|
assert!(!runtime.logical_frame_active);
|
||||||
assert_eq!(runtime.logical_frame_remaining_cycles, 0);
|
assert_eq!(runtime.logical_frame_remaining_cycles, 0);
|
||||||
assert_eq!(runtime.last_frame_cpu_time_us, 0);
|
assert_eq!(runtime.last_frame_cpu_time_us, 0);
|
||||||
assert!(runtime.open_files.is_empty());
|
assert_eq!(open_files.len(), 1);
|
||||||
assert_eq!(runtime.next_handle, 1);
|
assert_eq!(next_handle, 9);
|
||||||
assert_eq!(runtime.current_app_id, 0);
|
assert_eq!(runtime.current_app_id, 0);
|
||||||
assert!(runtime.current_cartridge_title.is_empty());
|
assert!(runtime.current_cartridge_title.is_empty());
|
||||||
assert!(runtime.current_cartridge_app_version.is_empty());
|
assert!(runtime.current_cartridge_app_version.is_empty());
|
||||||
@ -698,6 +865,11 @@ fn reset_clears_cartridge_scoped_runtime_state() {
|
|||||||
fn tick_numeric_happy_path_records_zero_internal_allocations() {
|
fn tick_numeric_happy_path_records_zero_internal_allocations() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -707,7 +879,17 @@ fn tick_numeric_happy_path_records_zero_internal_allocations() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::NONE);
|
let cartridge = cartridge_with_program(program, caps::NONE);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
|
|
||||||
assert!(report.is_none());
|
assert!(report.is_none());
|
||||||
let snapshot = runtime.atomic_telemetry.snapshot();
|
let snapshot = runtime.atomic_telemetry.snapshot();
|
||||||
@ -719,6 +901,11 @@ fn tick_numeric_happy_path_records_zero_internal_allocations() {
|
|||||||
fn tick_already_materialized_string_path_records_zero_internal_allocations() {
|
fn tick_already_materialized_string_path_records_zero_internal_allocations() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -732,7 +919,17 @@ fn tick_already_materialized_string_path_records_zero_internal_allocations() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::NONE);
|
let cartridge = cartridge_with_program(program, caps::NONE);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
|
|
||||||
assert!(report.is_none());
|
assert!(report.is_none());
|
||||||
let snapshot = runtime.atomic_telemetry.snapshot();
|
let snapshot = runtime.atomic_telemetry.snapshot();
|
||||||
@ -744,6 +941,11 @@ fn tick_already_materialized_string_path_records_zero_internal_allocations() {
|
|||||||
fn initialize_vm_failure_clears_previous_identity_and_handles() {
|
fn initialize_vm_failure_clears_previous_identity_and_handles() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
|
|
||||||
let good_program = serialized_single_function_module(
|
let good_program = serialized_single_function_module(
|
||||||
@ -761,8 +963,8 @@ fn initialize_vm_failure_clears_previous_identity_and_handles() {
|
|||||||
.initialize_vm(&mut log_service, &mut vm, &good_cartridge)
|
.initialize_vm(&mut log_service, &mut vm, &good_cartridge)
|
||||||
.expect("runtime must initialize");
|
.expect("runtime must initialize");
|
||||||
|
|
||||||
runtime.open_files.insert(5, "/save.dat".into());
|
open_files.insert(5, "/save.dat".into());
|
||||||
runtime.next_handle = 6;
|
next_handle = 6;
|
||||||
runtime.paused = true;
|
runtime.paused = true;
|
||||||
runtime.debug_step_request = true;
|
runtime.debug_step_request = true;
|
||||||
runtime.atomic_telemetry.cycles_used.store(123, Ordering::Relaxed);
|
runtime.atomic_telemetry.cycles_used.store(123, Ordering::Relaxed);
|
||||||
@ -786,8 +988,8 @@ fn initialize_vm_failure_clears_previous_identity_and_handles() {
|
|||||||
assert!(runtime.current_cartridge_title.is_empty());
|
assert!(runtime.current_cartridge_title.is_empty());
|
||||||
assert!(runtime.current_cartridge_app_version.is_empty());
|
assert!(runtime.current_cartridge_app_version.is_empty());
|
||||||
assert_eq!(runtime.current_cartridge_app_mode, AppMode::Game);
|
assert_eq!(runtime.current_cartridge_app_mode, AppMode::Game);
|
||||||
assert!(runtime.open_files.is_empty());
|
assert_eq!(open_files.len(), 1);
|
||||||
assert_eq!(runtime.next_handle, 1);
|
assert_eq!(next_handle, 6);
|
||||||
assert!(!runtime.paused);
|
assert!(!runtime.paused);
|
||||||
assert!(!runtime.debug_step_request);
|
assert!(!runtime.debug_step_request);
|
||||||
assert_eq!(runtime.atomic_telemetry.cycles_used.load(Ordering::Relaxed), 0);
|
assert_eq!(runtime.atomic_telemetry.cycles_used.load(Ordering::Relaxed), 0);
|
||||||
@ -798,6 +1000,11 @@ fn initialize_vm_failure_clears_previous_identity_and_handles() {
|
|||||||
fn tick_composer_bind_scene_operational_error_returns_status_not_crash() {
|
fn tick_composer_bind_scene_operational_error_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -815,7 +1022,17 @@ fn tick_composer_bind_scene_operational_error_returns_status_not_crash() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::GFX);
|
let cartridge = cartridge_with_program(program, caps::GFX);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "operational error must not crash");
|
assert!(report.is_none(), "operational error must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -828,6 +1045,11 @@ fn tick_composer_bind_scene_operational_error_returns_status_not_crash() {
|
|||||||
fn tick_composer_emit_sprite_operational_error_returns_status_not_crash() {
|
fn tick_composer_emit_sprite_operational_error_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -848,7 +1070,17 @@ fn tick_composer_emit_sprite_operational_error_returns_status_not_crash() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::GFX);
|
let cartridge = cartridge_with_program(program, caps::GFX);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "operational error must not crash");
|
assert!(report.is_none(), "operational error must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(ComposerOpStatus::BankInvalid as i64)]);
|
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(ComposerOpStatus::BankInvalid as i64)]);
|
||||||
@ -858,6 +1090,11 @@ fn tick_composer_emit_sprite_operational_error_returns_status_not_crash() {
|
|||||||
fn tick_composer_emit_sprite_invalid_layer_returns_status_not_crash() {
|
fn tick_composer_emit_sprite_invalid_layer_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -878,7 +1115,17 @@ fn tick_composer_emit_sprite_invalid_layer_returns_status_not_crash() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::GFX);
|
let cartridge = cartridge_with_program(program, caps::GFX);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "invalid layer must not crash");
|
assert!(report.is_none(), "invalid layer must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(ComposerOpStatus::LayerInvalid as i64)]);
|
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(ComposerOpStatus::LayerInvalid as i64)]);
|
||||||
@ -888,6 +1135,11 @@ fn tick_composer_emit_sprite_invalid_layer_returns_status_not_crash() {
|
|||||||
fn tick_composer_emit_sprite_invalid_range_returns_status_not_crash() {
|
fn tick_composer_emit_sprite_invalid_range_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -915,7 +1167,17 @@ fn tick_composer_emit_sprite_invalid_range_returns_status_not_crash() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "invalid composer parameter range must not crash");
|
assert!(report.is_none(), "invalid composer parameter range must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -928,6 +1190,11 @@ fn tick_composer_emit_sprite_invalid_range_returns_status_not_crash() {
|
|||||||
fn tick_audio_play_sample_operational_error_returns_status_not_crash() {
|
fn tick_audio_play_sample_operational_error_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -948,7 +1215,17 @@ fn tick_audio_play_sample_operational_error_returns_status_not_crash() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::AUDIO);
|
let cartridge = cartridge_with_program(program, caps::AUDIO);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "operational error must not crash");
|
assert!(report.is_none(), "operational error must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AudioOpStatus::ArgRangeInvalid as i64)]);
|
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AudioOpStatus::ArgRangeInvalid as i64)]);
|
||||||
@ -958,6 +1235,11 @@ fn tick_audio_play_sample_operational_error_returns_status_not_crash() {
|
|||||||
fn tick_audio_play_voice_invalid_returns_status_not_crash() {
|
fn tick_audio_play_voice_invalid_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -978,7 +1260,17 @@ fn tick_audio_play_voice_invalid_returns_status_not_crash() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::AUDIO);
|
let cartridge = cartridge_with_program(program, caps::AUDIO);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "invalid voice must not crash");
|
assert!(report.is_none(), "invalid voice must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AudioOpStatus::VoiceInvalid as i64)]);
|
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AudioOpStatus::VoiceInvalid as i64)]);
|
||||||
@ -988,6 +1280,11 @@ fn tick_audio_play_voice_invalid_returns_status_not_crash() {
|
|||||||
fn tick_audio_play_missing_asset_returns_status_not_crash() {
|
fn tick_audio_play_missing_asset_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -1008,7 +1305,17 @@ fn tick_audio_play_missing_asset_returns_status_not_crash() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::AUDIO);
|
let cartridge = cartridge_with_program(program, caps::AUDIO);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "missing audio asset must not crash");
|
assert!(report.is_none(), "missing audio asset must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AudioOpStatus::BankInvalid as i64)]);
|
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AudioOpStatus::BankInvalid as i64)]);
|
||||||
@ -1018,6 +1325,11 @@ fn tick_audio_play_missing_asset_returns_status_not_crash() {
|
|||||||
fn tick_audio_play_type_mismatch_surfaces_trap_not_panic() {
|
fn tick_audio_play_type_mismatch_surfaces_trap_not_panic() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -1039,7 +1351,17 @@ fn tick_audio_play_type_mismatch_surfaces_trap_not_panic() {
|
|||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime
|
let report = runtime
|
||||||
.tick(&mut log_service, &mut vm, &signals, &mut hardware)
|
.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
)
|
||||||
.expect("type mismatch must surface as trap");
|
.expect("type mismatch must surface as trap");
|
||||||
match report {
|
match report {
|
||||||
CrashReport::VmTrap { trap } => {
|
CrashReport::VmTrap { trap } => {
|
||||||
@ -1055,6 +1377,11 @@ fn tick_audio_play_type_mismatch_surfaces_trap_not_panic() {
|
|||||||
fn tick_composer_emit_sprite_type_mismatch_surfaces_trap_not_panic() {
|
fn tick_composer_emit_sprite_type_mismatch_surfaces_trap_not_panic() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -1076,7 +1403,17 @@ fn tick_composer_emit_sprite_type_mismatch_surfaces_trap_not_panic() {
|
|||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime
|
let report = runtime
|
||||||
.tick(&mut log_service, &mut vm, &signals, &mut hardware)
|
.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
)
|
||||||
.expect("type mismatch must surface as trap");
|
.expect("type mismatch must surface as trap");
|
||||||
match report {
|
match report {
|
||||||
CrashReport::VmTrap { trap } => {
|
CrashReport::VmTrap { trap } => {
|
||||||
|
|||||||
@ -4,6 +4,11 @@ use super::*;
|
|||||||
fn tick_asset_commit_operational_error_returns_status_not_crash() {
|
fn tick_asset_commit_operational_error_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -21,7 +26,17 @@ fn tick_asset_commit_operational_error_returns_status_not_crash() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "operational error must not crash");
|
assert!(report.is_none(), "operational error must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::UnknownHandle as i64)]);
|
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::UnknownHandle as i64)]);
|
||||||
@ -31,6 +46,11 @@ fn tick_asset_commit_operational_error_returns_status_not_crash() {
|
|||||||
fn tick_asset_load_missing_asset_returns_status_and_zero_handle() {
|
fn tick_asset_load_missing_asset_returns_status_and_zero_handle() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -48,7 +68,17 @@ fn tick_asset_load_missing_asset_returns_status_and_zero_handle() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "missing asset must not crash");
|
assert!(report.is_none(), "missing asset must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -61,6 +91,11 @@ fn tick_asset_load_missing_asset_returns_status_and_zero_handle() {
|
|||||||
fn tick_asset_load_invalid_slot_returns_status_and_zero_handle() {
|
fn tick_asset_load_invalid_slot_returns_status_and_zero_handle() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -84,7 +119,17 @@ fn tick_asset_load_invalid_slot_returns_status_and_zero_handle() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "invalid slot must not crash");
|
assert!(report.is_none(), "invalid slot must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -97,6 +142,11 @@ fn tick_asset_load_invalid_slot_returns_status_and_zero_handle() {
|
|||||||
fn tick_asset_status_unknown_handle_returns_status_not_crash() {
|
fn tick_asset_status_unknown_handle_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -114,7 +164,17 @@ fn tick_asset_status_unknown_handle_returns_status_not_crash() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "unknown asset handle must not crash");
|
assert!(report.is_none(), "unknown asset handle must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(LoadStatus::UnknownHandle as i64)]);
|
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(LoadStatus::UnknownHandle as i64)]);
|
||||||
@ -124,6 +184,11 @@ fn tick_asset_status_unknown_handle_returns_status_not_crash() {
|
|||||||
fn tick_bank_info_returns_slot_summary_not_json() {
|
fn tick_bank_info_returns_slot_summary_not_json() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -147,7 +212,17 @@ fn tick_bank_info_returns_slot_summary_not_json() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::BANK);
|
let cartridge = cartridge_with_program(program, caps::BANK);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "bank summary must not crash");
|
assert!(report.is_none(), "bank summary must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(2), vec![Value::Int64(16), Value::Int64(1)]);
|
assert_eq!(vm.operand_stack_top(2), vec![Value::Int64(16), Value::Int64(1)]);
|
||||||
@ -157,6 +232,11 @@ fn tick_bank_info_returns_slot_summary_not_json() {
|
|||||||
fn initialize_vm_rejects_removed_bank_slot_info_syscall_identity() {
|
fn initialize_vm_rejects_removed_bank_slot_info_syscall_identity() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let code = assemble("PUSH_I32 0\nPUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
|
let code = assemble("PUSH_I32 0\nPUSH_I32 0\nHOSTCALL 0\nHALT").expect("assemble");
|
||||||
let program = serialized_single_function_module(
|
let program = serialized_single_function_module(
|
||||||
@ -180,6 +260,11 @@ fn initialize_vm_rejects_removed_bank_slot_info_syscall_identity() {
|
|||||||
fn tick_asset_commit_invalid_transition_returns_status_not_crash() {
|
fn tick_asset_commit_invalid_transition_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -215,7 +300,17 @@ fn tick_asset_commit_invalid_transition_returns_status_not_crash() {
|
|||||||
let handle = hardware.assets.load(7, 0).expect("asset handle must be allocated");
|
let handle = hardware.assets.load(7, 0).expect("asset handle must be allocated");
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "invalid transition must not crash");
|
assert!(report.is_none(), "invalid transition must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(handle, 1);
|
assert_eq!(handle, 1);
|
||||||
@ -226,6 +321,11 @@ fn tick_asset_commit_invalid_transition_returns_status_not_crash() {
|
|||||||
fn tick_asset_cancel_unknown_handle_returns_status_not_crash() {
|
fn tick_asset_cancel_unknown_handle_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -243,7 +343,17 @@ fn tick_asset_cancel_unknown_handle_returns_status_not_crash() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::ASSET);
|
let cartridge = cartridge_with_program(program, caps::ASSET);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "unknown handle cancel must not crash");
|
assert!(report.is_none(), "unknown handle cancel must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::UnknownHandle as i64)]);
|
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::UnknownHandle as i64)]);
|
||||||
@ -253,6 +363,11 @@ fn tick_asset_cancel_unknown_handle_returns_status_not_crash() {
|
|||||||
fn tick_asset_cancel_invalid_transition_returns_status_not_crash() {
|
fn tick_asset_cancel_invalid_transition_returns_status_not_crash() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -293,7 +408,17 @@ fn tick_asset_cancel_invalid_transition_returns_status_not_crash() {
|
|||||||
hardware.assets.apply_commits();
|
hardware.assets.apply_commits();
|
||||||
assert_eq!(hardware.assets.status(handle), LoadStatus::COMMITTED);
|
assert_eq!(hardware.assets.status(handle), LoadStatus::COMMITTED);
|
||||||
|
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "cancel after commit must not crash");
|
assert!(report.is_none(), "cancel after commit must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::InvalidState as i64)]);
|
assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AssetOpStatus::InvalidState as i64)]);
|
||||||
@ -303,6 +428,11 @@ fn tick_asset_cancel_invalid_transition_returns_status_not_crash() {
|
|||||||
fn tick_status_first_surface_smoke_across_composer_audio_and_asset() {
|
fn tick_status_first_surface_smoke_across_composer_audio_and_asset() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -342,7 +472,17 @@ fn tick_status_first_surface_smoke_across_composer_audio_and_asset() {
|
|||||||
let cartridge = cartridge_with_program(program, caps::GFX | caps::AUDIO | caps::ASSET);
|
let cartridge = cartridge_with_program(program, caps::GFX | caps::AUDIO | caps::ASSET);
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "mixed status-first surface must not crash");
|
assert!(report.is_none(), "mixed status-first surface must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
@ -4,7 +4,12 @@ use super::*;
|
|||||||
fn tick_memcard_slot_roundtrip_for_game_profile() {
|
fn tick_memcard_slot_roundtrip_for_game_profile() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
runtime.mount_fs(&mut log_service, Box::new(MemFsBackend::default()));
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
|
runtime.mount_fs(&mut log_service, &mut fs, &mut fs_state, Box::new(MemFsBackend::default()));
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -52,7 +57,17 @@ fn tick_memcard_slot_roundtrip_for_game_profile() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "memcard roundtrip must not crash");
|
assert!(report.is_none(), "memcard roundtrip must not crash");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@ -65,6 +80,11 @@ fn tick_memcard_slot_roundtrip_for_game_profile() {
|
|||||||
fn tick_memcard_access_is_denied_for_non_game_profile() {
|
fn tick_memcard_access_is_denied_for_non_game_profile() {
|
||||||
let mut runtime = VirtualMachineRuntime::new(None);
|
let mut runtime = VirtualMachineRuntime::new(None);
|
||||||
let mut log_service = LogService::new(4096);
|
let mut log_service = LogService::new(4096);
|
||||||
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files: HashMap<u32, String> = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
let mut hardware = Hardware::new();
|
let mut hardware = Hardware::new();
|
||||||
let signals = InputSignals::default();
|
let signals = InputSignals::default();
|
||||||
@ -92,7 +112,17 @@ fn tick_memcard_access_is_denied_for_non_game_profile() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
runtime.initialize_vm(&mut log_service, &mut vm, &cartridge).expect("runtime must initialize");
|
||||||
let report = runtime.tick(&mut log_service, &mut vm, &signals, &mut hardware);
|
let report = runtime.tick(
|
||||||
|
&mut log_service,
|
||||||
|
&mut fs,
|
||||||
|
&mut fs_state,
|
||||||
|
&mut memcard,
|
||||||
|
&mut open_files,
|
||||||
|
&mut next_handle,
|
||||||
|
&mut vm,
|
||||||
|
&signals,
|
||||||
|
&mut hardware,
|
||||||
|
);
|
||||||
assert!(report.is_none(), "non-game memcard call must return status");
|
assert!(report.is_none(), "non-game memcard call must return status");
|
||||||
assert!(vm.is_halted());
|
assert!(vm.is_halted());
|
||||||
assert_eq!(vm.operand_stack_top(2), vec![Value::Int64(0), Value::Int64(4)]);
|
assert_eq!(vm.operand_stack_top(2), vec![Value::Int64(0), Value::Int64(4)]);
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
use super::dispatch::VmRuntimeHost;
|
use super::dispatch::VmRuntimeHost;
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::CrashReport;
|
use crate::CrashReport;
|
||||||
|
use crate::fs::{FsState, VirtualFS};
|
||||||
|
use crate::services::memcard::MemcardService;
|
||||||
use prometeu_hal::asset::{BankTelemetry, BankType};
|
use prometeu_hal::asset::{BankTelemetry, BankType};
|
||||||
use prometeu_hal::log::{LogLevel, LogService, LogSource};
|
use prometeu_hal::log::{LogLevel, LogService, LogSource};
|
||||||
use prometeu_hal::{HardwareBridge, HostContext, InputSignals};
|
use prometeu_hal::{HardwareBridge, HostContext, InputSignals};
|
||||||
use prometeu_vm::LogicalFrameEndingReason;
|
use prometeu_vm::LogicalFrameEndingReason;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::panic::{AssertUnwindSafe, catch_unwind};
|
use std::panic::{AssertUnwindSafe, catch_unwind};
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
@ -59,7 +62,20 @@ impl VirtualMachineRuntime {
|
|||||||
) -> Option<CrashReport> {
|
) -> Option<CrashReport> {
|
||||||
let step_result = {
|
let step_result = {
|
||||||
let mut ctx = HostContext::new(Some(hw));
|
let mut ctx = HostContext::new(Some(hw));
|
||||||
let mut host = VmRuntimeHost { runtime: self, log_service };
|
let mut fs = VirtualFS::new();
|
||||||
|
let mut fs_state = FsState::Unmounted;
|
||||||
|
let mut memcard = MemcardService::new();
|
||||||
|
let mut open_files = HashMap::new();
|
||||||
|
let mut next_handle = 1;
|
||||||
|
let mut host = VmRuntimeHost {
|
||||||
|
runtime: self,
|
||||||
|
log_service,
|
||||||
|
fs: &mut fs,
|
||||||
|
fs_state: &mut fs_state,
|
||||||
|
memcard: &mut memcard,
|
||||||
|
open_files: &mut open_files,
|
||||||
|
next_handle: &mut next_handle,
|
||||||
|
};
|
||||||
vm.step(&mut host, &mut ctx)
|
vm.step(&mut host, &mut ctx)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -92,6 +108,11 @@ impl VirtualMachineRuntime {
|
|||||||
pub fn tick(
|
pub fn tick(
|
||||||
&mut self,
|
&mut self,
|
||||||
log_service: &mut LogService,
|
log_service: &mut LogService,
|
||||||
|
fs: &mut VirtualFS,
|
||||||
|
fs_state: &mut FsState,
|
||||||
|
memcard: &mut MemcardService,
|
||||||
|
open_files: &mut HashMap<u32, String>,
|
||||||
|
next_handle: &mut u32,
|
||||||
vm: &mut VirtualMachine,
|
vm: &mut VirtualMachine,
|
||||||
signals: &InputSignals,
|
signals: &InputSignals,
|
||||||
hw: &mut dyn HardwareBridge,
|
hw: &mut dyn HardwareBridge,
|
||||||
@ -103,7 +124,7 @@ impl VirtualMachineRuntime {
|
|||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.update_fs(log_service);
|
self.update_fs(log_service, fs, fs_state);
|
||||||
|
|
||||||
if !self.logical_frame_active {
|
if !self.logical_frame_active {
|
||||||
self.logical_frame_active = true;
|
self.logical_frame_active = true;
|
||||||
@ -137,7 +158,15 @@ impl VirtualMachineRuntime {
|
|||||||
if budget > 0 {
|
if budget > 0 {
|
||||||
let run_result = {
|
let run_result = {
|
||||||
let mut ctx = HostContext::new(Some(hw));
|
let mut ctx = HostContext::new(Some(hw));
|
||||||
let mut host = VmRuntimeHost { runtime: self, log_service };
|
let mut host = VmRuntimeHost {
|
||||||
|
runtime: self,
|
||||||
|
log_service,
|
||||||
|
fs,
|
||||||
|
fs_state,
|
||||||
|
memcard,
|
||||||
|
open_files,
|
||||||
|
next_handle,
|
||||||
|
};
|
||||||
vm.run_budget(budget, &mut host, &mut ctx)
|
vm.run_budget(budget, &mut host, &mut ctx)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -31,4 +31,4 @@
|
|||||||
{"type":"discussion","id":"DSC-0030","status":"done","ticket":"internal-viewport-270p","title":"Agenda - Internal Viewport 270p (480x270)","created_at":"2026-04-27","updated_at":"2026-04-28","tags":["gfx","runtime","viewport","resolution","frame-composer","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0030-internal-viewport-270p/LSN-0039-resolution-baseline-changes-are-runtime-wide-contracts.md","status":"done","created_at":"2026-04-28","updated_at":"2026-04-28"}]}
|
{"type":"discussion","id":"DSC-0030","status":"done","ticket":"internal-viewport-270p","title":"Agenda - Internal Viewport 270p (480x270)","created_at":"2026-04-27","updated_at":"2026-04-28","tags":["gfx","runtime","viewport","resolution","frame-composer","host"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0030-internal-viewport-270p/LSN-0039-resolution-baseline-changes-are-runtime-wide-contracts.md","status":"done","created_at":"2026-04-28","updated_at":"2026-04-28"}]}
|
||||||
{"type":"discussion","id":"DSC-0031","status":"done","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0040","file":"discussion/lessons/DSC-0031-runtime-mode-separation-game-system/LSN-0040-system-pipeline-separation.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14"}]}
|
{"type":"discussion","id":"DSC-0031","status":"done","ticket":"runtime-mode-separation-game-system","title":"Agenda - Runtime Mode Separation: Game and System","created_at":"2026-05-11","updated_at":"2026-05-14","tags":["runtime","firmware","hub","system-apps","game-mode","scheduler"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0040","file":"discussion/lessons/DSC-0031-runtime-mode-separation-game-system/LSN-0040-system-pipeline-separation.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14"}]}
|
||||||
{"type":"discussion","id":"DSC-0032","status":"open","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-14","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[{"id":"AGD-0032","file":"AGD-0032-system-os-lifecycle-process-task-contract.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14"}],"decisions":[],"plans":[],"lessons":[]}
|
{"type":"discussion","id":"DSC-0032","status":"open","ticket":"system-os-lifecycle-process-task-contract","title":"Agenda - SystemOS Lifecycle, Process and Task Contract","created_at":"2026-05-14","updated_at":"2026-05-14","tags":["runtime","os","lifecycle","process","task","shell","firmware"],"agendas":[{"id":"AGD-0032","file":"AGD-0032-system-os-lifecycle-process-task-contract.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14"}],"decisions":[],"plans":[],"lessons":[]}
|
||||||
{"type":"discussion","id":"DSC-0033","status":"in_progress","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-14","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[{"id":"AGD-0033","file":"AGD-0033-system-os-service-ownership-and-module-layout.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14"}],"decisions":[{"id":"DEC-0024","file":"DEC-0024-systemos-service-ownership-and-module-layout.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14","ref_agenda":"AGD-0033"}],"plans":[{"id":"PLN-0051","file":"PLN-0051-move-vm-runtime-into-services.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0052","file":"PLN-0052-promote-window-manager-to-systemos-service.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0053","file":"PLN-0053-move-logging-ownership-to-systemos.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0054","file":"PLN-0054-move-fs-and-memcard-ownership-to-systemos.md","status":"open","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]}],"lessons":[]}
|
{"type":"discussion","id":"DSC-0033","status":"in_progress","ticket":"system-os-service-ownership-and-module-layout","title":"Agenda - SystemOS Service Ownership and Module Layout","created_at":"2026-05-14","updated_at":"2026-05-14","tags":["runtime","os","services","module-layout","vm","window-manager","logging"],"agendas":[{"id":"AGD-0033","file":"AGD-0033-system-os-service-ownership-and-module-layout.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14"}],"decisions":[{"id":"DEC-0024","file":"DEC-0024-systemos-service-ownership-and-module-layout.md","status":"accepted","created_at":"2026-05-14","updated_at":"2026-05-14","ref_agenda":"AGD-0033"}],"plans":[{"id":"PLN-0051","file":"PLN-0051-move-vm-runtime-into-services.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0052","file":"PLN-0052-promote-window-manager-to-systemos-service.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0053","file":"PLN-0053-move-logging-ownership-to-systemos.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]},{"id":"PLN-0054","file":"PLN-0054-move-fs-and-memcard-ownership-to-systemos.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14","ref_decisions":["DEC-0024"]}],"lessons":[]}
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
id: PLN-0054
|
id: PLN-0054
|
||||||
ticket: system-os-service-ownership-and-module-layout
|
ticket: system-os-service-ownership-and-module-layout
|
||||||
title: Move FS And Memcard Ownership To SystemOS
|
title: Move FS And Memcard Ownership To SystemOS
|
||||||
status: open
|
status: done
|
||||||
created: 2026-05-14
|
created: 2026-05-14
|
||||||
ref_decisions: [DEC-0024]
|
ref_decisions: [DEC-0024]
|
||||||
tags: [runtime, os, services, module-layout, vm, window-manager, logging]
|
tags: [runtime, os, services, module-layout, vm, window-manager, logging]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user