From db338d0c4e0a8c561f70c936487aa7af2f7e3231 Mon Sep 17 00:00:00 2001 From: bquarkz Date: Thu, 22 Jan 2026 15:22:13 +0000 Subject: [PATCH] dev/asset-management (#6) Co-authored-by: Nilton Constantino Reviewed-on: https://git-local.bquarkz.net/Intrepid/prometeu-runtime/pulls/6 --- .../prometeu-compiler/src/codegen/codegen.rs | 84 +- crates/prometeu-core/src/debugger_protocol.rs | 8 + crates/prometeu-core/src/firmware/firmware.rs | 7 +- .../firmware/firmware_step_game_running.rs | 2 +- .../src/firmware/firmware_step_hub_home.rs | 2 +- .../firmware/firmware_step_load_cartridge.rs | 8 + .../firmware/firmware_step_splash_screen.rs | 7 +- crates/prometeu-core/src/hardware/asset.rs | 864 +++++++++++++++++ crates/prometeu-core/src/hardware/audio.rs | 91 +- crates/prometeu-core/src/hardware/gfx.rs | 103 +- crates/prometeu-core/src/hardware/hardware.rs | 23 +- .../src/hardware/memory_banks.rs | 90 ++ crates/prometeu-core/src/hardware/mod.rs | 12 +- crates/prometeu-core/src/model/asset.rs | 80 ++ crates/prometeu-core/src/model/cartridge.rs | 20 +- .../src/model/cartridge_loader.rs | 12 +- crates/prometeu-core/src/model/mod.rs | 4 + crates/prometeu-core/src/model/sound_bank.rs | 16 + crates/prometeu-core/src/model/tile_bank.rs | 6 +- crates/prometeu-core/src/model/tile_layer.rs | 2 +- .../src/prometeu_os/prometeu_os.rs | 265 ++++- .../prometeu-core/src/prometeu_os/syscalls.rs | 28 + crates/prometeu-core/src/telemetry.rs | 10 + .../src/virtual_machine/virtual_machine.rs | 9 +- crates/prometeu-runtime-desktop/src/audio.rs | 26 +- .../prometeu-runtime-desktop/src/debugger.rs | 39 +- crates/prometeu-runtime-desktop/src/runner.rs | 35 +- crates/prometeu-runtime-desktop/src/stats.rs | 10 +- devtools/debugger-protocol/protocol.json | 6 +- devtools/typescript-sdk/types/index.d.ts | 6 +- docs/specs/topics/chapter-14.md | 4 +- docs/specs/topics/chapter-15.md | 331 +++++++ docs/specs/topics/table-of-contents.md | 1 + symbols.json | 80 -- temp_test_2.disasm.txt | 23 - .../color-square/build/program.disasm.txt | 304 +++--- .../color-square/build/program.pbc | Bin 817 -> 919 bytes .../color-square/build/symbols.json | 902 ++++++++++-------- .../color-square/cartridge/assets.pa | Bin 0 -> 90504 bytes .../color-square/cartridge/manifest.json | 34 +- .../color-square/cartridge/program.pbc | Bin 817 -> 919 bytes test-cartridges/color-square/run.sh | 1 + test-cartridges/color-square/src/main.ts | 2 +- test-cartridges/color-square/src/my_input.ts | 5 +- 44 files changed, 2697 insertions(+), 865 deletions(-) create mode 100644 crates/prometeu-core/src/hardware/asset.rs create mode 100644 crates/prometeu-core/src/hardware/memory_banks.rs create mode 100644 crates/prometeu-core/src/model/asset.rs create mode 100644 crates/prometeu-core/src/model/sound_bank.rs create mode 100644 docs/specs/topics/chapter-15.md delete mode 100644 symbols.json delete mode 100644 temp_test_2.disasm.txt create mode 100644 test-cartridges/color-square/cartridge/assets.pa diff --git a/crates/prometeu-compiler/src/codegen/codegen.rs b/crates/prometeu-compiler/src/codegen/codegen.rs index 08f0a77d..73d80bde 100644 --- a/crates/prometeu-compiler/src/codegen/codegen.rs +++ b/crates/prometeu-compiler/src/codegen/codegen.rs @@ -18,8 +18,10 @@ pub struct Codegen { pub symbols: Vec, instructions: Vec<(Asm, bool)>, // (Asm, has_symbol) locals: HashMap, + globals: HashMap, constant_pool: Vec, next_local: u32, + next_global: u32, label_count: u32, } @@ -31,8 +33,10 @@ impl Codegen { symbols: Vec::new(), instructions: Vec::new(), locals: HashMap::new(), + globals: HashMap::new(), constant_pool: vec![ConstantPoolEntry::Null], // Index 0 is always Null next_local: 0, + next_global: 0, label_count: 0, } } @@ -52,7 +56,7 @@ impl Codegen { } pub fn compile_programs(&mut self, programs: Vec<(String, String, &Program)>) -> Result> { - // First pass: collect all functions and their indices + // First pass: collect all functions and global variables let mut all_functions = Vec::new(); for (file, source, program) in &programs { for item in &program.body { @@ -63,6 +67,29 @@ impl Codegen { Statement::ExportNamedDeclaration(decl) => { if let Some(Declaration::FunctionDeclaration(f)) = &decl.declaration { all_functions.push((file.clone(), source.clone(), f.as_ref())); + } else if let Some(Declaration::VariableDeclaration(var)) = &decl.declaration { + for decl in &var.declarations { + if let BindingPattern::BindingIdentifier(ident) = &decl.id { + let name = ident.name.to_string(); + if !self.globals.contains_key(&name) { + let id = self.next_global; + self.globals.insert(name, id); + self.next_global += 1; + } + } + } + } + } + Statement::VariableDeclaration(var) => { + for decl in &var.declarations { + if let BindingPattern::BindingIdentifier(ident) = &decl.id { + let name = ident.name.to_string(); + if !self.globals.contains_key(&name) { + let id = self.next_global; + self.globals.insert(name, id); + self.next_global += 1; + } + } } } _ => {} @@ -70,8 +97,8 @@ impl Codegen { } } - // Find tick function (should be in the first program, which is the entry) - let mut tick_fn_name = None; + // Find frame function (should be in the first program, which is the entry) + let mut frame_fn_name = None; if let Some((_, _, entry_program)) = programs.first() { for item in &entry_program.body { let f_opt = match item { @@ -88,8 +115,8 @@ impl Codegen { if let Some(f) = f_opt { if let Some(ident) = &f.id { - if ident.name == "tick" { - tick_fn_name = Some(ident.name.to_string()); + if ident.name == "frame" { + frame_fn_name = Some(ident.name.to_string()); break; } } @@ -97,11 +124,45 @@ impl Codegen { } } - let tick_fn_name = tick_fn_name.ok_or_else(|| anyhow!("export function tick() not found in entry file"))?; + let frame_fn_name = frame_fn_name.ok_or_else(|| anyhow!("export function frame() not found in entry file"))?; - // Entry point: loop calling tick + // Initialize globals + for (file, source, program) in &programs { + self.file_name = file.clone(); + self.source_text = source.clone(); + for item in &program.body { + let var_opt = match item { + Statement::VariableDeclaration(var) => Some(var.as_ref()), + Statement::ExportNamedDeclaration(decl) => { + if let Some(Declaration::VariableDeclaration(var)) = &decl.declaration { + Some(var.as_ref()) + } else { + None + } + } + _ => None, + }; + + if let Some(var) = var_opt { + for decl in &var.declarations { + if let BindingPattern::BindingIdentifier(ident) = &decl.id { + let name = ident.name.to_string(); + let id = *self.globals.get(&name).unwrap(); + if let Some(init) = &decl.init { + self.compile_expr(init)?; + } else { + self.emit_op(OpCode::PushI32, vec![Operand::I32(0)], decl.span); + } + self.emit_op(OpCode::SetGlobal, vec![Operand::U32(id)], decl.span); + } + } + } + } + } + + // Entry point: loop calling frame self.emit_label("entry".to_string()); - self.emit_op(OpCode::Call, vec![Operand::Label(tick_fn_name), Operand::U32(0)], Span::default()); + self.emit_op(OpCode::Call, vec![Operand::Label(frame_fn_name), Operand::U32(0)], Span::default()); self.emit_op(OpCode::Pop, vec![], Span::default()); self.emit_op(OpCode::FrameSync, vec![], Span::default()); self.emit_op(OpCode::Jmp, vec![Operand::Label("entry".to_string())], Span::default()); @@ -221,7 +282,7 @@ impl Codegen { if val.fract() == 0.0 && val >= i32::MIN as f64 && val <= i32::MAX as f64 { self.emit_op(OpCode::PushI32, vec![Operand::I32(val as i32)], n.span); } else { - self.emit_op(OpCode::PushI64, vec![Operand::I64(val as i64)], n.span); + self.emit_op(OpCode::PushF64, vec![Operand::F64(val)], n.span); } } Expression::BooleanLiteral(b) => { @@ -238,6 +299,8 @@ impl Codegen { let name = ident.name.to_string(); if let Some(&id) = self.locals.get(&name) { self.emit_op(OpCode::GetLocal, vec![Operand::U32(id)], ident.span); + } else if let Some(&id) = self.globals.get(&name) { + self.emit_op(OpCode::GetGlobal, vec![Operand::U32(id)], ident.span); } else { return Err(anyhow!("Undefined variable: {} at {:?}", name, ident.span)); } @@ -249,6 +312,9 @@ impl Codegen { if let Some(&id) = self.locals.get(&name) { self.emit_op(OpCode::SetLocal, vec![Operand::U32(id)], assign.span); self.emit_op(OpCode::GetLocal, vec![Operand::U32(id)], assign.span); + } else if let Some(&id) = self.globals.get(&name) { + self.emit_op(OpCode::SetGlobal, vec![Operand::U32(id)], assign.span); + self.emit_op(OpCode::GetGlobal, vec![Operand::U32(id)], assign.span); } else { return Err(anyhow!("Undefined variable: {} at {:?}", name, ident.span)); } diff --git a/crates/prometeu-core/src/debugger_protocol.rs b/crates/prometeu-core/src/debugger_protocol.rs index 0e9b8c89..e154bcbe 100644 --- a/crates/prometeu-core/src/debugger_protocol.rs +++ b/crates/prometeu-core/src/debugger_protocol.rs @@ -80,6 +80,14 @@ pub enum DebugEvent { vm_steps: u32, syscalls: u32, cycles: u64, + host_cpu_time_us: u64, + violations: u32, + gfx_used_bytes: usize, + gfx_inflight_bytes: usize, + gfx_slots_occupied: u32, + audio_used_bytes: usize, + audio_inflight_bytes: usize, + audio_slots_occupied: u32, }, #[serde(rename = "cert")] Cert { diff --git a/crates/prometeu-core/src/firmware/firmware.rs b/crates/prometeu-core/src/firmware/firmware.rs index a6d109af..a91b3f46 100644 --- a/crates/prometeu-core/src/firmware/firmware.rs +++ b/crates/prometeu-core/src/firmware/firmware.rs @@ -46,8 +46,11 @@ impl Firmware { /// /// This method is called exactly once per Host frame (60Hz). /// It updates peripheral signals and delegates the logic to the current state. - pub fn step_frame(&mut self, signals: &InputSignals, hw: &mut dyn HardwareBridge) { - // 1. Update peripheral state using the latest signals from the Host. + pub fn tick(&mut self, signals: &InputSignals, hw: &mut dyn HardwareBridge) { + // 0. Process asset commits at the beginning of the frame boundary. + hw.assets_mut().apply_commits(); + + // 1. Update the peripheral state using the latest signals from the Host. // This ensures input is consistent throughout the entire update. hw.pad_mut().begin_frame(signals); hw.touch_mut().begin_frame(signals); diff --git a/crates/prometeu-core/src/firmware/firmware_step_game_running.rs b/crates/prometeu-core/src/firmware/firmware_step_game_running.rs index 6c095b25..9bb65c47 100644 --- a/crates/prometeu-core/src/firmware/firmware_step_game_running.rs +++ b/crates/prometeu-core/src/firmware/firmware_step_game_running.rs @@ -11,7 +11,7 @@ impl GameRunningStep { } pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option { - let result = ctx.os.step_frame(ctx.vm, ctx.signals, ctx.hw); + let result = ctx.os.tick(ctx.vm, ctx.signals, ctx.hw); if !ctx.os.logical_frame_active { ctx.hw.gfx_mut().present(); diff --git a/crates/prometeu-core/src/firmware/firmware_step_hub_home.rs b/crates/prometeu-core/src/firmware/firmware_step_hub_home.rs index accfb1a2..211ea674 100644 --- a/crates/prometeu-core/src/firmware/firmware_step_hub_home.rs +++ b/crates/prometeu-core/src/firmware/firmware_step_hub_home.rs @@ -21,7 +21,7 @@ impl HubHomeStep { ctx.hub.window_manager.remove_window(focused_id); } else { // System App runs here, drawing over the Hub background - error = ctx.os.step_frame(ctx.vm, ctx.signals, ctx.hw); + error = ctx.os.tick(ctx.vm, ctx.signals, ctx.hw); } } diff --git a/crates/prometeu-core/src/firmware/firmware_step_load_cartridge.rs b/crates/prometeu-core/src/firmware/firmware_step_load_cartridge.rs index fd6918ab..c9725057 100644 --- a/crates/prometeu-core/src/firmware/firmware_step_load_cartridge.rs +++ b/crates/prometeu-core/src/firmware/firmware_step_load_cartridge.rs @@ -11,6 +11,14 @@ pub struct LoadCartridgeStep { impl LoadCartridgeStep { pub fn on_enter(&mut self, ctx: &mut PrometeuContext) { ctx.os.log(LogLevel::Info, LogSource::Pos, 0, format!("Loading cartridge: {}", self.cartridge.title)); + + // Initialize Asset Manager + ctx.hw.assets_mut().initialize_for_cartridge( + self.cartridge.asset_table.clone(), + self.cartridge.preload.clone(), + self.cartridge.assets.clone() + ); + ctx.os.initialize_vm(ctx.vm, &self.cartridge); } diff --git a/crates/prometeu-core/src/firmware/firmware_step_splash_screen.rs b/crates/prometeu-core/src/firmware/firmware_step_splash_screen.rs index 8f5e7eaa..ec5c7af6 100644 --- a/crates/prometeu-core/src/firmware/firmware_step_splash_screen.rs +++ b/crates/prometeu-core/src/firmware/firmware_step_splash_screen.rs @@ -1,8 +1,7 @@ use crate::firmware::firmware_state::{FirmwareState, LaunchHubStep}; use crate::firmware::prometeu_context::PrometeuContext; -use crate::hardware::LoopMode; -use crate::model::Color; use crate::log::{LogLevel, LogSource}; +use crate::model::Color; #[derive(Debug, Clone)] pub struct SplashScreenStep { @@ -13,9 +12,7 @@ impl SplashScreenStep { pub fn on_enter(&mut self, ctx: &mut PrometeuContext) { ctx.os.log(LogLevel::Info, LogSource::Pos, 0, "Showing SplashScreen".to_string()); // Play sound on enter - if let Some(sample) = ctx.os.sample_square.clone() { - ctx.hw.audio_mut().play(sample, 0, 255, 127, 1.0, 0, LoopMode::Off); - } + // ctx.hw.audio_mut().play(0, 0, 0, 255, 127, 1.0, 0, LoopMode::Off); } pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option { diff --git a/crates/prometeu-core/src/hardware/asset.rs b/crates/prometeu-core/src/hardware/asset.rs new file mode 100644 index 00000000..5dae5fa0 --- /dev/null +++ b/crates/prometeu-core/src/hardware/asset.rs @@ -0,0 +1,864 @@ +use crate::hardware::memory_banks::{TileBankPoolInstaller, SoundBankPoolInstaller}; +use crate::model::{AssetEntry, BankStats, BankType, Color, HandleId, LoadStatus, SlotRef, SlotStats, TileBank, TileSize, SoundBank, Sample, PreloadEntry}; +use std::collections::HashMap; +use std::sync::{Arc, Mutex, RwLock}; +use std::thread; +use std::time::Instant; + +/// Resident metadata for a decoded/materialized asset inside a BankPolicy. +#[derive(Debug)] +pub struct ResidentEntry { + /// The resident, materialized object. + pub value: Arc, + + /// Resident size in bytes (post-decode). Used for telemetry/budgets. + pub bytes: usize, + + // /// Pin count (optional): if > 0, entry should not be evicted by policy. + // pub pins: u32, + + /// Telemetry / profiling fields (optional but useful). + pub loads: u64, + pub last_used: Instant, +} + +impl ResidentEntry { + pub fn new(value: Arc, bytes: usize) -> Self { + Self { + value, + bytes, + // pins: 0, + loads: 1, + last_used: Instant::now(), + } + } +} + +/// Encapsulates the residency and staging policy for a specific type of asset. +/// This is internal to the AssetManager and not visible to peripherals. +pub struct BankPolicy { + /// Dedup table: asset_id -> resident entry (value + telemetry). + resident: Arc>>>, + + /// Staging area: handle -> value ready to commit. + staging: Arc>>>, +} + +impl BankPolicy { + pub fn new() -> Self { + Self { + resident: Arc::new(RwLock::new(HashMap::new())), + staging: Arc::new(RwLock::new(HashMap::new())), + } + } + + /// Try get a resident value by asset_id (dedupe path). + pub fn get_resident(&self, asset_id: u32) -> Option> { + let mut map = self.resident.write().unwrap(); + let entry = map.get_mut(&asset_id)?; + entry.last_used = Instant::now(); + Some(Arc::clone(&entry.value)) + } + + /// Insert or reuse a resident entry. Returns the resident Arc. + pub fn put_resident(&self, asset_id: u32, value: Arc, bytes: usize) -> Arc { + let mut map = self.resident.write().unwrap(); + match map.get_mut(&asset_id) { + Some(existing) => { + existing.last_used = Instant::now(); + existing.loads += 1; + Arc::clone(&existing.value) + } + None => { + let entry = ResidentEntry::new(Arc::clone(&value), bytes); + map.insert(asset_id, entry); + value + } + } + } + + /// Place a value into staging for a given handle. + pub fn stage(&self, handle: HandleId, value: Arc) { + self.staging.write().unwrap().insert(handle, value); + } + + /// Take staged value (used by commit path). + pub fn take_staging(&self, handle: HandleId) -> Option> { + self.staging.write().unwrap().remove(&handle) + } + + pub fn clear(&self) { + self.resident.write().unwrap().clear(); + self.staging.write().unwrap().clear(); + } +} + +pub struct AssetManager { + assets: Arc>>, + name_to_id: Arc>>, + handles: Arc>>, + next_handle_id: Mutex, + assets_data: Arc>>, + + /// Narrow hardware interfaces + gfx_installer: Arc, + sound_installer: Arc, + + /// Track what is installed in each hardware slot (for stats/info). + gfx_slots: Arc; 16]>>, + sound_slots: Arc; 16]>>, + + /// Residency policy for GFX tile banks. + gfx_policy: BankPolicy, + /// Residency policy for sound banks. + sound_policy: BankPolicy, + + // Commits that are ready to be applied at the next frame boundary. + pending_commits: Mutex>, +} + +struct LoadHandleInfo { + _asset_id: u32, + slot: SlotRef, + status: LoadStatus, +} + +impl AssetManager { + pub fn new( + assets: Vec, + assets_data: Vec, + gfx_installer: Arc, + sound_installer: Arc, + ) -> Self { + let mut asset_map = HashMap::new(); + let mut name_to_id = HashMap::new(); + for entry in assets { + name_to_id.insert(entry.asset_name.clone(), entry.asset_id); + asset_map.insert(entry.asset_id, entry); + } + + Self { + assets: Arc::new(RwLock::new(asset_map)), + name_to_id: Arc::new(RwLock::new(name_to_id)), + gfx_installer, + sound_installer, + gfx_slots: Arc::new(RwLock::new(std::array::from_fn(|_| None))), + sound_slots: Arc::new(RwLock::new(std::array::from_fn(|_| None))), + gfx_policy: BankPolicy::new(), + sound_policy: BankPolicy::new(), + handles: Arc::new(RwLock::new(HashMap::new())), + next_handle_id: Mutex::new(1), + assets_data: Arc::new(RwLock::new(assets_data)), + pending_commits: Mutex::new(Vec::new()), + } + } + + pub fn initialize_for_cartridge(&self, assets: Vec, preload: Vec, assets_data: Vec) { + self.shutdown(); + { + let mut asset_map = self.assets.write().unwrap(); + let mut name_to_id = self.name_to_id.write().unwrap(); + asset_map.clear(); + name_to_id.clear(); + for entry in assets.iter() { + name_to_id.insert(entry.asset_name.clone(), entry.asset_id); + asset_map.insert(entry.asset_id, entry.clone()); + } + } + *self.assets_data.write().unwrap() = assets_data; + + // Perform Preload for assets in the preload list + for item in preload { + let entry_opt = { + let assets = self.assets.read().unwrap(); + let name_to_id = self.name_to_id.read().unwrap(); + name_to_id.get(&item.asset_name) + .and_then(|id| assets.get(id)) + .cloned() + }; + + if let Some(entry) = entry_opt { + let slot_index = item.slot; + match entry.bank_type { + BankType::TILES => { + if let Ok(bank) = Self::perform_load_tile_bank(&entry, self.assets_data.clone()) { + let bank_arc = Arc::new(bank); + self.gfx_policy.put_resident(entry.asset_id, Arc::clone(&bank_arc), entry.decoded_size as usize); + self.gfx_installer.install_tile_bank(slot_index, bank_arc); + let mut slots = self.gfx_slots.write().unwrap(); + if slot_index < slots.len() { + slots[slot_index] = Some(entry.asset_id); + } + println!("[AssetManager] Preloaded tile asset '{}' (id: {}) into slot {}", entry.asset_name, entry.asset_id, slot_index); + } else { + eprintln!("[AssetManager] Failed to preload tile asset '{}'", entry.asset_name); + } + } + BankType::SOUNDS => { + if let Ok(bank) = Self::perform_load_sound_bank(&entry, self.assets_data.clone()) { + let bank_arc = Arc::new(bank); + self.sound_policy.put_resident(entry.asset_id, Arc::clone(&bank_arc), entry.decoded_size as usize); + self.sound_installer.install_sound_bank(slot_index, bank_arc); + let mut slots = self.sound_slots.write().unwrap(); + if slot_index < slots.len() { + slots[slot_index] = Some(entry.asset_id); + } + println!("[AssetManager] Preloaded sound asset '{}' (id: {}) into slot {}", entry.asset_name, entry.asset_id, slot_index); + } else { + eprintln!("[AssetManager] Failed to preload sound asset '{}'", entry.asset_name); + } + } + } + } else { + eprintln!("[AssetManager] Preload failed: asset '{}' not found in table", item.asset_name); + } + } + } + + pub fn load(&self, asset_name: &str, slot: SlotRef) -> Result { + let entry = { + let assets = self.assets.read().unwrap(); + let name_to_id = self.name_to_id.read().unwrap(); + let id = name_to_id.get(asset_name).ok_or_else(|| format!("Asset not found: {}", asset_name))?; + assets.get(id).ok_or_else(|| format!("Asset ID {} not found in table", id))?.clone() + }; + let asset_id = entry.asset_id; + + if slot.asset_type != entry.bank_type { + return Err("INCOMPATIBLE_SLOT_KIND".to_string()); + } + + let mut next_id = self.next_handle_id.lock().unwrap(); + let handle_id = *next_id; + *next_id += 1; + + // Check if already resident (Dedup) + let already_resident = match entry.bank_type { + BankType::TILES => { + if let Some(bank) = self.gfx_policy.get_resident(asset_id) { + self.gfx_policy.stage(handle_id, bank); + true + } else { false } + } + BankType::SOUNDS => { + if let Some(bank) = self.sound_policy.get_resident(asset_id) { + self.sound_policy.stage(handle_id, bank); + true + } else { false } + } + }; + + if already_resident { + self.handles.write().unwrap().insert(handle_id, LoadHandleInfo { + _asset_id: asset_id, + slot, + status: LoadStatus::READY, + }); + return Ok(handle_id); + } + + // Not resident, start loading + self.handles.write().unwrap().insert(handle_id, LoadHandleInfo { + _asset_id: asset_id, + slot, + status: LoadStatus::PENDING, + }); + + let handles = self.handles.clone(); + let assets_data = self.assets_data.clone(); + let entry_clone = entry.clone(); + + // Capture policies for the worker thread + let gfx_policy_resident = Arc::clone(&self.gfx_policy.resident); + let gfx_policy_staging = Arc::clone(&self.gfx_policy.staging); + let sound_policy_resident = Arc::clone(&self.sound_policy.resident); + let sound_policy_staging = Arc::clone(&self.sound_policy.staging); + + thread::spawn(move || { + // Update status to LOADING + { + let mut handles_map = handles.write().unwrap(); + if let Some(h) = handles_map.get_mut(&handle_id) { + if h.status == LoadStatus::PENDING { + h.status = LoadStatus::LOADING; + } else { + return; + } + } else { + return; + } + } + + match entry_clone.bank_type { + BankType::TILES => { + let result = Self::perform_load_tile_bank(&entry_clone, assets_data); + if let Ok(tilebank) = result { + let bank_arc = Arc::new(tilebank); + let resident_arc = { + let mut map = gfx_policy_resident.write().unwrap(); + if let Some(existing) = map.get_mut(&asset_id) { + existing.last_used = Instant::now(); + existing.loads += 1; + Arc::clone(&existing.value) + } else { + let entry = ResidentEntry::new(Arc::clone(&bank_arc), entry_clone.decoded_size as usize); + map.insert(asset_id, entry); + bank_arc + } + }; + gfx_policy_staging.write().unwrap().insert(handle_id, resident_arc); + let mut handles_map = handles.write().unwrap(); + if let Some(h) = handles_map.get_mut(&handle_id) { + if h.status == LoadStatus::LOADING { h.status = LoadStatus::READY; } + } + } else { + let mut handles_map = handles.write().unwrap(); + if let Some(h) = handles_map.get_mut(&handle_id) { h.status = LoadStatus::ERROR; } + } + } + BankType::SOUNDS => { + let result = Self::perform_load_sound_bank(&entry_clone, assets_data); + if let Ok(soundbank) = result { + let bank_arc = Arc::new(soundbank); + let resident_arc = { + let mut map = sound_policy_resident.write().unwrap(); + if let Some(existing) = map.get_mut(&asset_id) { + existing.last_used = Instant::now(); + existing.loads += 1; + Arc::clone(&existing.value) + } else { + let entry = ResidentEntry::new(Arc::clone(&bank_arc), entry_clone.decoded_size as usize); + map.insert(asset_id, entry); + bank_arc + } + }; + sound_policy_staging.write().unwrap().insert(handle_id, resident_arc); + let mut handles_map = handles.write().unwrap(); + if let Some(h) = handles_map.get_mut(&handle_id) { + if h.status == LoadStatus::LOADING { h.status = LoadStatus::READY; } + } + } else { + let mut handles_map = handles.write().unwrap(); + if let Some(h) = handles_map.get_mut(&handle_id) { h.status = LoadStatus::ERROR; } + } + } + } + }); + + Ok(handle_id) + } + + fn perform_load_tile_bank(entry: &AssetEntry, assets_data: Arc>>) -> Result { + if entry.codec != "RAW" { + return Err(format!("Unsupported codec: {}", entry.codec)); + } + + let assets_data = assets_data.read().unwrap(); + + let start = entry.offset as usize; + let end = start + entry.size as usize; + + if end > assets_data.len() { + return Err("Asset offset/size out of bounds".to_string()); + } + + let buffer = &assets_data[start..end]; + + // Decode TILEBANK metadata + let tile_size_val = entry.metadata.get("tile_size").and_then(|v| v.as_u64()).ok_or("Missing tile_size")?; + let width = entry.metadata.get("width").and_then(|v| v.as_u64()).ok_or("Missing width")? as usize; + let height = entry.metadata.get("height").and_then(|v| v.as_u64()).ok_or("Missing height")? as usize; + + let tile_size = match tile_size_val { + 8 => TileSize::Size8, + 16 => TileSize::Size16, + 32 => TileSize::Size32, + _ => return Err(format!("Invalid tile_size: {}", tile_size_val)), + }; + + let pixel_data_size = width * height; + if buffer.len() < pixel_data_size + 2048 { + return Err("Buffer too small for TILEBANK".to_string()); + } + + let pixel_indices = buffer[0..pixel_data_size].to_vec(); + let palette_data = &buffer[pixel_data_size..pixel_data_size + 2048]; + + let mut palettes = [[Color::BLACK; 16]; 64]; + for p in 0..64 { + for c in 0..16 { + let offset = (p * 16 + c) * 2; + let color_raw = u16::from_le_bytes([palette_data[offset], palette_data[offset + 1]]); + palettes[p][c] = Color(color_raw); + } + } + + Ok(TileBank { + tile_size, + width, + height, + pixel_indices, + palettes, + }) + } + + fn perform_load_sound_bank(entry: &AssetEntry, assets_data: Arc>>) -> Result { + if entry.codec != "RAW" { + return Err(format!("Unsupported codec: {}", entry.codec)); + } + + let assets_data = assets_data.read().unwrap(); + + let start = entry.offset as usize; + let end = start + entry.size as usize; + + if end > assets_data.len() { + return Err("Asset offset/size out of bounds".to_string()); + } + + let buffer = &assets_data[start..end]; + + let sample_rate = entry.metadata.get("sample_rate").and_then(|v| v.as_u64()).unwrap_or(44100) as u32; + + let mut data = Vec::with_capacity(buffer.len() / 2); + for i in (0..buffer.len()).step_by(2) { + if i + 1 < buffer.len() { + data.push(i16::from_le_bytes([buffer[i], buffer[i+1]])); + } + } + + let sample = Arc::new(Sample::new(sample_rate, data)); + Ok(SoundBank::new(vec![sample])) + } + + pub fn status(&self, handle: HandleId) -> LoadStatus { + self.handles.read().unwrap().get(&handle).map(|h| h.status).unwrap_or(LoadStatus::ERROR) + } + + pub fn commit(&self, handle: HandleId) { + let mut handles_map = self.handles.write().unwrap(); + if let Some(h) = handles_map.get_mut(&handle) { + if h.status == LoadStatus::READY { + self.pending_commits.lock().unwrap().push(handle); + } + } + } + + pub fn cancel(&self, handle: HandleId) { + let mut handles_map = self.handles.write().unwrap(); + if let Some(h) = handles_map.get_mut(&handle) { + match h.status { + LoadStatus::PENDING | LoadStatus::LOADING | LoadStatus::READY => { + h.status = LoadStatus::CANCELED; + } + _ => {} + } + } + self.gfx_policy.take_staging(handle); + self.sound_policy.take_staging(handle); + } + + pub fn apply_commits(&self) { + let mut pending = self.pending_commits.lock().unwrap(); + let mut handles = self.handles.write().unwrap(); + + for handle_id in pending.drain(..) { + if let Some(h) = handles.get_mut(&handle_id) { + if h.status == LoadStatus::READY { + match h.slot.asset_type { + BankType::TILES => { + if let Some(bank) = self.gfx_policy.take_staging(handle_id) { + self.gfx_installer.install_tile_bank(h.slot.index, bank); + let mut slots = self.gfx_slots.write().unwrap(); + if h.slot.index < slots.len() { + slots[h.slot.index] = Some(h._asset_id); + } + h.status = LoadStatus::COMMITTED; + } + } + BankType::SOUNDS => { + if let Some(bank) = self.sound_policy.take_staging(handle_id) { + self.sound_installer.install_sound_bank(h.slot.index, bank); + let mut slots = self.sound_slots.write().unwrap(); + if h.slot.index < slots.len() { + slots[h.slot.index] = Some(h._asset_id); + } + h.status = LoadStatus::COMMITTED; + } + } + } + } + } + } + } + + pub fn bank_info(&self, kind: BankType) -> BankStats { + match kind { + BankType::TILES => { + let mut used_bytes = 0; + { + let resident = self.gfx_policy.resident.read().unwrap(); + for entry in resident.values() { + used_bytes += entry.bytes; + } + } + + let mut inflight_bytes = 0; + { + let staging = self.gfx_policy.staging.read().unwrap(); + let assets = self.assets.read().unwrap(); + let handles = self.handles.read().unwrap(); + + for (handle_id, _) in staging.iter() { + if let Some(h) = handles.get(handle_id) { + if let Some(entry) = assets.get(&h._asset_id) { + inflight_bytes += entry.decoded_size as usize; + } + } + } + } + + let mut slots_occupied = 0; + { + let slots = self.gfx_slots.read().unwrap(); + for s in slots.iter() { + if s.is_some() { slots_occupied += 1; } + } + } + + BankStats { + total_bytes: 16 * 1024 * 1024, + used_bytes, + free_bytes: (16usize * 1024 * 1024).saturating_sub(used_bytes), + inflight_bytes, + slot_count: 16, + slots_occupied, + } + } + BankType::SOUNDS => { + let mut used_bytes = 0; + { + let resident = self.sound_policy.resident.read().unwrap(); + for entry in resident.values() { + used_bytes += entry.bytes; + } + } + + let mut inflight_bytes = 0; + { + let staging = self.sound_policy.staging.read().unwrap(); + let assets = self.assets.read().unwrap(); + let handles = self.handles.read().unwrap(); + + for (handle_id, _) in staging.iter() { + if let Some(h) = handles.get(handle_id) { + if let Some(entry) = assets.get(&h._asset_id) { + inflight_bytes += entry.decoded_size as usize; + } + } + } + } + + let mut slots_occupied = 0; + { + let slots = self.sound_slots.read().unwrap(); + for s in slots.iter() { + if s.is_some() { slots_occupied += 1; } + } + } + + BankStats { + total_bytes: 32 * 1024 * 1024, + used_bytes, + free_bytes: (32usize * 1024 * 1024).saturating_sub(used_bytes), + inflight_bytes, + slot_count: 16, + slots_occupied, + } + } + } + } + + pub fn slot_info(&self, slot: SlotRef) -> SlotStats { + match slot.asset_type { + BankType::TILES => { + let slots = self.gfx_slots.read().unwrap(); + let asset_id = slots.get(slot.index).and_then(|s| s.clone()); + + let (bytes, asset_name) = if let Some(id) = &asset_id { + let bytes = self.gfx_policy.resident.read().unwrap() + .get(id) + .map(|entry| entry.bytes) + .unwrap_or(0); + let name = self.assets.read().unwrap().get(id).map(|e| e.asset_name.clone()); + (bytes, name) + } else { + (0, None) + }; + + SlotStats { + asset_id, + asset_name, + generation: 0, + resident_bytes: bytes, + } + } + BankType::SOUNDS => { + let slots = self.sound_slots.read().unwrap(); + let asset_id = slots.get(slot.index).and_then(|s| s.clone()); + + let (bytes, asset_name) = if let Some(id) = &asset_id { + let bytes = self.sound_policy.resident.read().unwrap() + .get(id) + .map(|entry| entry.bytes) + .unwrap_or(0); + let name = self.assets.read().unwrap().get(id).map(|e| e.asset_name.clone()); + (bytes, name) + } else { + (0, None) + }; + + SlotStats { + asset_id, + asset_name, + generation: 0, + resident_bytes: bytes, + } + } + } + } + + pub fn find_slot_by_name(&self, asset_name: &str, kind: BankType) -> Option { + let asset_id = { + let name_to_id = self.name_to_id.read().unwrap(); + *name_to_id.get(asset_name)? + }; + + match kind { + BankType::TILES => { + let slots = self.gfx_slots.read().unwrap(); + slots.iter().position(|&s| s == Some(asset_id)).map(|p| p as u8) + } + BankType::SOUNDS => { + let slots = self.sound_slots.read().unwrap(); + slots.iter().position(|&s| s == Some(asset_id)).map(|p| p as u8) + } + } + } + + pub fn shutdown(&self) { + self.gfx_policy.clear(); + self.sound_policy.clear(); + self.handles.write().unwrap().clear(); + self.pending_commits.lock().unwrap().clear(); + self.gfx_slots.write().unwrap().fill(None); + self.sound_slots.write().unwrap().fill(None); + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::hardware::memory_banks::{TileBankPoolAccess, SoundBankPoolAccess, MemoryBanks}; + + #[test] + fn test_asset_loading_flow() { + let banks = Arc::new(MemoryBanks::new()); + let gfx_installer = Arc::clone(&banks) as Arc; + let sound_installer = Arc::clone(&banks) as Arc; + + let mut data = vec![1u8; 256]; + data.extend_from_slice(&[0u8; 2048]); + + let asset_entry = AssetEntry { + asset_id: 0, + asset_name: "test_tiles".to_string(), + bank_type: BankType::TILES, + offset: 0, + size: data.len() as u64, + decoded_size: data.len() as u64, + codec: "RAW".to_string(), + metadata: serde_json::json!({ + "tile_size": 16, + "width": 16, + "height": 16 + }), + }; + + let am = AssetManager::new(vec![asset_entry], data, gfx_installer, sound_installer); + let slot = SlotRef::gfx(0); + + let handle = am.load("test_tiles", slot).expect("Should start loading"); + + let mut status = am.status(handle); + let start = Instant::now(); + while status != LoadStatus::READY && start.elapsed().as_secs() < 5 { + thread::sleep(std::time::Duration::from_millis(10)); + status = am.status(handle); + } + + assert_eq!(status, LoadStatus::READY); + + { + let staging = am.gfx_policy.staging.read().unwrap(); + assert!(staging.contains_key(&handle)); + } + + am.commit(handle); + am.apply_commits(); + + assert_eq!(am.status(handle), LoadStatus::COMMITTED); + assert!(banks.tile_bank_slot(0).is_some()); + } + + #[test] + fn test_asset_dedup() { + let banks = Arc::new(MemoryBanks::new()); + let gfx_installer = Arc::clone(&banks) as Arc; + let sound_installer = Arc::clone(&banks) as Arc; + + let mut data = vec![1u8; 256]; + data.extend_from_slice(&[0u8; 2048]); + + let asset_entry = AssetEntry { + asset_id: 0, + asset_name: "test_tiles".to_string(), + bank_type: BankType::TILES, + offset: 0, + size: data.len() as u64, + decoded_size: data.len() as u64, + codec: "RAW".to_string(), + metadata: serde_json::json!({ + "tile_size": 16, + "width": 16, + "height": 16 + }), + }; + + let am = AssetManager::new(vec![asset_entry], data, gfx_installer, sound_installer); + + let handle1 = am.load("test_tiles", SlotRef::gfx(0)).unwrap(); + let start = Instant::now(); + while am.status(handle1) != LoadStatus::READY && start.elapsed().as_secs() < 5 { + thread::sleep(std::time::Duration::from_millis(10)); + } + + let handle2 = am.load("test_tiles", SlotRef::gfx(1)).unwrap(); + assert_eq!(am.status(handle2), LoadStatus::READY); + + let staging = am.gfx_policy.staging.read().unwrap(); + let bank1 = staging.get(&handle1).unwrap(); + let bank2 = staging.get(&handle2).unwrap(); + assert!(Arc::ptr_eq(bank1, bank2)); + } + + #[test] + fn test_sound_asset_loading() { + let banks = Arc::new(MemoryBanks::new()); + let gfx_installer = Arc::clone(&banks) as Arc; + let sound_installer = Arc::clone(&banks) as Arc; + + // 100 samples of 16-bit PCM (zeros) + let data = vec![0u8; 200]; + + let asset_entry = AssetEntry { + asset_id: 1, + asset_name: "test_sound".to_string(), + bank_type: BankType::SOUNDS, + offset: 0, + size: data.len() as u64, + decoded_size: data.len() as u64, + codec: "RAW".to_string(), + metadata: serde_json::json!({ + "sample_rate": 44100 + }), + }; + + let am = AssetManager::new(vec![asset_entry], data, gfx_installer, sound_installer); + let slot = SlotRef::audio(0); + + let handle = am.load("test_sound", slot).expect("Should start loading"); + + let start = Instant::now(); + while am.status(handle) != LoadStatus::READY && start.elapsed().as_secs() < 5 { + thread::sleep(std::time::Duration::from_millis(10)); + } + + assert_eq!(am.status(handle), LoadStatus::READY); + + am.commit(handle); + am.apply_commits(); + + assert_eq!(am.status(handle), LoadStatus::COMMITTED); + assert!(banks.sound_bank_slot(0).is_some()); + } + + #[test] + fn test_preload_on_init() { + let banks = Arc::new(MemoryBanks::new()); + let gfx_installer = Arc::clone(&banks) as Arc; + let sound_installer = Arc::clone(&banks) as Arc; + + let data = vec![0u8; 200]; + + let asset_entry = AssetEntry { + asset_id: 2, + asset_name: "preload_sound".to_string(), + bank_type: BankType::SOUNDS, + offset: 0, + size: data.len() as u64, + decoded_size: data.len() as u64, + codec: "RAW".to_string(), + metadata: serde_json::json!({ + "sample_rate": 44100 + }), + }; + + let preload = vec![ + PreloadEntry { asset_name: "preload_sound".to_string(), slot: 5 } + ]; + + let am = AssetManager::new(vec![], vec![], gfx_installer, sound_installer); + + // Before init, slot 5 is empty + assert!(banks.sound_bank_slot(5).is_none()); + + am.initialize_for_cartridge(vec![asset_entry], preload, data); + + // After init, slot 5 should be occupied because of preload + assert!(banks.sound_bank_slot(5).is_some()); + assert_eq!(am.slot_info(SlotRef::audio(5)).asset_id, Some(2)); + } + + #[test] + fn test_find_slot_by_name() { + let banks = Arc::new(MemoryBanks::new()); + let gfx_installer = Arc::clone(&banks) as Arc; + let sound_installer = Arc::clone(&banks) as Arc; + + let mut data = vec![0u8; 256]; // pixels + data.extend_from_slice(&[0u8; 2048]); // palette + + let asset_entry = AssetEntry { + asset_id: 10, + asset_name: "my_tiles".to_string(), + bank_type: BankType::TILES, + offset: 0, + size: data.len() as u64, + decoded_size: data.len() as u64, + codec: "RAW".to_string(), + metadata: serde_json::json!({ "tile_size": 16, "width": 16, "height": 16 }), + }; + + let preload = vec![ + PreloadEntry { asset_name: "my_tiles".to_string(), slot: 3 } + ]; + + let am = AssetManager::new(vec![], vec![], gfx_installer, sound_installer); + am.initialize_for_cartridge(vec![asset_entry], preload, data); + + assert_eq!(am.find_slot_by_name("my_tiles", BankType::TILES), Some(3)); + assert_eq!(am.find_slot_by_name("unknown", BankType::TILES), None); + assert_eq!(am.find_slot_by_name("my_tiles", BankType::SOUNDS), None); + } +} diff --git a/crates/prometeu-core/src/hardware/audio.rs b/crates/prometeu-core/src/hardware/audio.rs index 849cc3dd..45fff287 100644 --- a/crates/prometeu-core/src/hardware/audio.rs +++ b/crates/prometeu-core/src/hardware/audio.rs @@ -1,3 +1,4 @@ +use crate::hardware::memory_banks::SoundBankPoolAccess; use crate::model::Sample; use std::sync::Arc; @@ -21,8 +22,10 @@ pub enum LoopMode { /// The Core maintains this state to provide information to the App (e.g., is_playing), /// but the actual real-time mixing is performed by the Host using commands. pub struct Channel { - /// Reference to the PCM data being played. + /// The actual sample data being played. pub sample: Option>, + /// Whether this channel is currently active. + pub active: bool, /// Current playback position within the sample (fractional for pitch shifting). pub pos: f64, /// Playback speed multiplier (1.0 = original speed). @@ -41,6 +44,7 @@ impl Default for Channel { fn default() -> Self { Self { sample: None, + active: false, pos: 0.0, pitch: 1.0, volume: 255, @@ -85,6 +89,10 @@ pub enum AudioCommand { voice_id: usize, pitch: f64, }, + /// Pause all audio processing. + MasterPause, + /// Resume audio processing. + MasterResume, } /// PROMETEU Audio Subsystem. @@ -97,68 +105,99 @@ pub struct Audio { pub voices: [Channel; MAX_CHANNELS], /// Queue of pending commands to be processed by the Host mixer. pub commands: Vec, + /// Interface to access sound memory banks. + pub sound_banks: Arc, } impl Audio { - /// Initializes the audio system with empty voices. - pub fn new() -> Self { - const EMPTY_CHANNEL: Channel = Channel { - sample: None, - pos: 0.0, - pitch: 1.0, - volume: 255, - pan: 127, - loop_mode: LoopMode::Off, - priority: 0, - }; - + /// Initializes the audio system with empty voices and sound bank access. + pub fn new(sound_banks: Arc) -> Self { Self { - voices: [EMPTY_CHANNEL; MAX_CHANNELS], + voices: std::array::from_fn(|_| Channel::default()), commands: Vec::new(), + sound_banks, } } - pub fn play(&mut self, sample: Arc, voice_id: usize, volume: u8, pan: u8, pitch: f64, priority: u8, loop_mode: LoopMode) { - if voice_id < MAX_CHANNELS { - self.commands.push(AudioCommand::Play { - sample, - voice_id, - volume, - pan, - pitch, - priority, - loop_mode, - }); + pub fn play(&mut self, bank_id: u8, sample_id: u16, voice_id: usize, volume: u8, pan: u8, pitch: f64, priority: u8, loop_mode: LoopMode) { + if voice_id >= MAX_CHANNELS { + return; } + + // Resolve the sample from the hardware pools + let sample = self.sound_banks.sound_bank_slot(bank_id as usize) + .and_then(|bank| bank.samples.get(sample_id as usize).map(Arc::clone)); + + + if let Some(s) = sample { + println!("[Audio] Resolved sample from bank {} sample {}. Playing on voice {}.", bank_id, sample_id, voice_id); + self.play_sample(s, voice_id, volume, pan, pitch, priority, loop_mode); + } else { + eprintln!("[Audio] Failed to resolve sample from bank {} sample {}.", bank_id, sample_id); + } + } + + pub fn play_sample(&mut self, sample: Arc, voice_id: usize, volume: u8, pan: u8, pitch: f64, priority: u8, loop_mode: LoopMode) { + if voice_id >= MAX_CHANNELS { + return; + } + + // Update local state + self.voices[voice_id] = Channel { + sample: Some(Arc::clone(&sample)), + active: true, + pos: 0.0, + pitch, + volume, + pan, + loop_mode, + priority, + }; + + // Push command to the host + self.commands.push(AudioCommand::Play { + sample, + voice_id, + volume, + pan, + pitch, + priority, + loop_mode, + }); } pub fn stop(&mut self, voice_id: usize) { if voice_id < MAX_CHANNELS { + self.voices[voice_id].active = false; + self.voices[voice_id].sample = None; self.commands.push(AudioCommand::Stop { voice_id }); } } pub fn set_volume(&mut self, voice_id: usize, volume: u8) { if voice_id < MAX_CHANNELS { + self.voices[voice_id].volume = volume; self.commands.push(AudioCommand::SetVolume { voice_id, volume }); } } pub fn set_pan(&mut self, voice_id: usize, pan: u8) { if voice_id < MAX_CHANNELS { + self.voices[voice_id].pan = pan; self.commands.push(AudioCommand::SetPan { voice_id, pan }); } } pub fn set_pitch(&mut self, voice_id: usize, pitch: f64) { if voice_id < MAX_CHANNELS { + self.voices[voice_id].pitch = pitch; self.commands.push(AudioCommand::SetPitch { voice_id, pitch }); } } pub fn is_playing(&self, voice_id: usize) -> bool { if voice_id < MAX_CHANNELS { - self.voices[voice_id].sample.is_some() + self.voices[voice_id].active } else { false } diff --git a/crates/prometeu-core/src/hardware/gfx.rs b/crates/prometeu-core/src/hardware/gfx.rs index 61381e85..f864c7d9 100644 --- a/crates/prometeu-core/src/hardware/gfx.rs +++ b/crates/prometeu-core/src/hardware/gfx.rs @@ -1,5 +1,6 @@ +use crate::hardware::memory_banks::TileBankPoolAccess; use crate::model::{Color, HudTileLayer, ScrollableTileLayer, Sprite, TileBank, TileMap, TileSize}; -use std::mem::size_of; +use std::sync::Arc; /// Blending modes inspired by classic 16-bit hardware. /// Defines how source pixels are combined with existing pixels in the framebuffer. @@ -46,8 +47,8 @@ pub struct Gfx { pub layers: [ScrollableTileLayer; 4], /// 1 fixed layer for User Interface. pub hud: HudTileLayer, - /// Up to 16 sets of graphical assets (tiles + palettes). - pub banks: [Option; 16], + /// Interface to access graphical memory banks. + pub tile_banks: Arc, /// Hardware sprites (Object Attribute Memory equivalent). pub sprites: [Sprite; 512], @@ -65,9 +66,8 @@ pub struct Gfx { } impl Gfx { - /// Initializes the graphics system with a specific resolution. - pub fn new(w: usize, h: usize) -> Self { - const EMPTY_BANK: Option = None; + /// Initializes the graphics system with a specific resolution and shared memory banks. + pub fn new(w: usize, h: usize, tile_banks: Arc) -> Self { const EMPTY_SPRITE: Sprite = Sprite { tile: crate::model::Tile { id: 0, flip_x: false, flip_y: false, palette_id: 0 }, x: 0, @@ -94,7 +94,7 @@ impl Gfx { back: vec![0; len], layers, hud: HudTileLayer::new(64, 32), - banks: [EMPTY_BANK; 16], + tile_banks, sprites: [EMPTY_SPRITE; 512], scene_fade_level: 31, scene_fade_color: Color::BLACK, @@ -328,25 +328,25 @@ impl Gfx { } // 1. Priority 0 sprites: drawn at the very back, behind everything else. - Self::draw_bucket_on_buffer(&mut self.back, self.w, self.h, &self.priority_buckets[0], &self.sprites, &self.banks); + Self::draw_bucket_on_buffer(&mut self.back, self.w, self.h, &self.priority_buckets[0], &self.sprites, &*self.tile_banks); // 2. Main layers and prioritized sprites. // Order: Layer 0 -> Sprites 1 -> Layer 1 -> Sprites 2 ... for i in 0..self.layers.len() { let bank_id = self.layers[i].bank_id as usize; - if let Some(Some(bank)) = self.banks.get(bank_id) { - Self::draw_tile_map(&mut self.back, self.w, self.h, &self.layers[i].map, bank, self.layers[i].scroll_x, self.layers[i].scroll_y); + if let Some(bank) = self.tile_banks.tile_bank_slot(bank_id) { + Self::draw_tile_map(&mut self.back, self.w, self.h, &self.layers[i].map, &bank, self.layers[i].scroll_x, self.layers[i].scroll_y); } // Draw sprites that belong to this depth level - Self::draw_bucket_on_buffer(&mut self.back, self.w, self.h, &self.priority_buckets[i + 1], &self.sprites, &self.banks); + Self::draw_bucket_on_buffer(&mut self.back, self.w, self.h, &self.priority_buckets[i + 1], &self.sprites, &*self.tile_banks); } // 4. Scene Fade: Applies a color blend to the entire world (excluding HUD). Self::apply_fade_to_buffer(&mut self.back, self.scene_fade_level, self.scene_fade_color); // 5. HUD: The fixed interface layer, always drawn on top of the world. - self.render_hud(); + Self::render_hud_with_pool(&mut self.back, self.w, self.h, &self.hud, &*self.tile_banks); // 6. HUD Fade: Independent fade effect for the UI. Self::apply_fade_to_buffer(&mut self.back, self.hud_fade_level, self.hud_fade_color); @@ -360,23 +360,27 @@ impl Gfx { let scroll_x = self.layers[layer_idx].scroll_x; let scroll_y = self.layers[layer_idx].scroll_y; - let bank = match self.banks.get(bank_id) { - Some(Some(b)) => b, + let bank = match self.tile_banks.tile_bank_slot(bank_id) { + Some(b) => b, _ => return, }; - Self::draw_tile_map(&mut self.back, self.w, self.h, &self.layers[layer_idx].map, bank, scroll_x, scroll_y); + Self::draw_tile_map(&mut self.back, self.w, self.h, &self.layers[layer_idx].map, &bank, scroll_x, scroll_y); } /// Renders the HUD (fixed position, no scroll). pub fn render_hud(&mut self) { - let bank_id = self.hud.bank_id as usize; - let bank = match self.banks.get(bank_id) { - Some(Some(b)) => b, + Self::render_hud_with_pool(&mut self.back, self.w, self.h, &self.hud, &*self.tile_banks); + } + + fn render_hud_with_pool(back: &mut [u16], w: usize, h: usize, hud: &HudTileLayer, tile_banks: &dyn TileBankPoolAccess) { + let bank_id = hud.bank_id as usize; + let bank = match tile_banks.tile_bank_slot(bank_id) { + Some(b) => b, _ => return, }; - Self::draw_tile_map(&mut self.back, self.w, self.h, &self.hud.map, bank, 0, 0); + Self::draw_tile_map(back, w, h, &hud.map, &bank, 0, 0); } /// Rasterizes a TileMap into the provided pixel buffer using scrolling. @@ -464,13 +468,13 @@ impl Gfx { screen_h: usize, bucket: &[usize], sprites: &[Sprite], - banks: &[Option], + tile_banks: &dyn TileBankPoolAccess, ) { for &idx in bucket { let s = &sprites[idx]; let bank_id = s.bank_id as usize; - if let Some(Some(bank)) = banks.get(bank_id) { - Self::draw_sprite_pixel_by_pixel(back, screen_w, screen_h, s, bank); + if let Some(bank) = tile_banks.tile_bank_slot(bank_id) { + Self::draw_sprite_pixel_by_pixel(back, screen_w, screen_h, s, &bank); } } } @@ -532,45 +536,6 @@ impl Gfx { } } - /// Returns the actual memory usage of the graphics structures in bytes. - /// Reflects index buffers, palettes, and OAM as per Chapter 10.8. - pub fn memory_usage_bytes(&self) -> usize { - let mut total = 0; - - // 1. Framebuffers (Front + Back) - // Each is Vec, occupying 2 bytes per pixel. - total += self.front.len() * 2; - total += self.back.len() * 2; - - // 2. Tile Layers (4 Game Layers) - for layer in &self.layers { - // Struct size + map data (Vec) - total += size_of::(); - total += layer.map.tiles.len() * size_of::(); - } - - // 3. HUD Layer - total += size_of::(); - total += self.hud.map.tiles.len() * size_of::(); - - // 4. Tile Banks (Assets and Palettes) - for bank_opt in &self.banks { - if let Some(bank) = bank_opt { - total += size_of::(); - total += bank.pixel_indices.len(); - - // Palette Table: 256 palettes * 16 colors * Color struct size - total += 256 * 16 * size_of::(); - } - } - - // 5. Sprites (OAM) - // Fixed array of 512 Sprites. - total += self.sprites.len() * size_of::(); - - total - } - pub fn draw_text(&mut self, x: i32, y: i32, text: &str, color: Color) { let mut cx = x; for c in text.chars() { @@ -647,10 +612,12 @@ impl Gfx { #[cfg(test)] mod tests { use super::*; + use crate::hardware::MemoryBanks; #[test] fn test_draw_pixel() { - let mut gfx = Gfx::new(10, 10); + let banks = Arc::new(MemoryBanks::new()); + let mut gfx = Gfx::new(10, 10, banks); gfx.draw_pixel(5, 5, Color::WHITE); assert_eq!(gfx.back[5 * 10 + 5], Color::WHITE.0); @@ -661,7 +628,8 @@ mod tests { #[test] fn test_draw_line() { - let mut gfx = Gfx::new(10, 10); + let banks = Arc::new(MemoryBanks::new()); + let mut gfx = Gfx::new(10, 10, banks); gfx.draw_line(0, 0, 9, 9, Color::WHITE); assert_eq!(gfx.back[0], Color::WHITE.0); assert_eq!(gfx.back[9 * 10 + 9], Color::WHITE.0); @@ -669,7 +637,8 @@ mod tests { #[test] fn test_draw_rect() { - let mut gfx = Gfx::new(10, 10); + let banks = Arc::new(MemoryBanks::new()); + let mut gfx = Gfx::new(10, 10, banks); gfx.draw_rect(0, 0, 10, 10, Color::WHITE); assert_eq!(gfx.back[0], Color::WHITE.0); assert_eq!(gfx.back[9], Color::WHITE.0); @@ -679,14 +648,16 @@ mod tests { #[test] fn test_fill_circle() { - let mut gfx = Gfx::new(10, 10); + let banks = Arc::new(MemoryBanks::new()); + let mut gfx = Gfx::new(10, 10, banks); gfx.fill_circle(5, 5, 2, Color::WHITE); assert_eq!(gfx.back[5 * 10 + 5], Color::WHITE.0); } #[test] fn test_draw_square() { - let mut gfx = Gfx::new(10, 10); + let banks = Arc::new(MemoryBanks::new()); + let mut gfx = Gfx::new(10, 10, banks); gfx.draw_square(2, 2, 6, 6, Color::WHITE, Color::BLACK); // Border assert_eq!(gfx.back[2 * 10 + 2], Color::WHITE.0); diff --git a/crates/prometeu-core/src/hardware/hardware.rs b/crates/prometeu-core/src/hardware/hardware.rs index 8495c9cf..5e7925fd 100644 --- a/crates/prometeu-core/src/hardware/hardware.rs +++ b/crates/prometeu-core/src/hardware/hardware.rs @@ -1,10 +1,14 @@ -use crate::hardware::{Audio, Gfx, HardwareBridge, Pad, Touch}; +use crate::hardware::{AssetManager, Audio, Gfx, HardwareBridge, Pad, Touch, MemoryBanks}; +use crate::hardware::memory_banks::{TileBankPoolAccess, TileBankPoolInstaller, SoundBankPoolAccess, SoundBankPoolInstaller}; +use std::sync::Arc; /// Aggregate structure for all virtual hardware peripherals. /// /// This struct represents the "Mainboard" of the PROMETEU console, /// containing instances of GFX, Audio, Input (Pad), and Touch. pub struct Hardware { + /// Shared memory banks for hardware assets. + pub memory_banks: Arc, /// The Graphics Processing Unit. pub gfx: Gfx, /// The Sound Processing Unit. @@ -13,6 +17,8 @@ pub struct Hardware { pub pad: Pad, /// The absolute pointer input device. pub touch: Touch, + /// The Asset Management system. + pub assets: AssetManager, } impl HardwareBridge for Hardware { @@ -27,6 +33,9 @@ impl HardwareBridge for Hardware { fn touch(&self) -> &Touch { &self.touch } fn touch_mut(&mut self) -> &mut Touch { &mut self.touch } + + fn assets(&self) -> &AssetManager { &self.assets } + fn assets_mut(&mut self) -> &mut AssetManager { &mut self.assets } } impl Hardware { @@ -37,11 +46,19 @@ impl Hardware { /// Creates a fresh hardware instance with default settings. pub fn new() -> Self { + let memory_banks = Arc::new(MemoryBanks::new()); Self { - gfx: Gfx::new(Self::W, Self::H), - audio: Audio::new(), + memory_banks: Arc::clone(&memory_banks), + gfx: Gfx::new(Self::W, Self::H, Arc::clone(&memory_banks) as Arc), + audio: Audio::new(Arc::clone(&memory_banks) as Arc), pad: Pad::default(), touch: Touch::default(), + assets: AssetManager::new( + vec![], + vec![], + Arc::clone(&memory_banks) as Arc, + Arc::clone(&memory_banks) as Arc, + ), } } } diff --git a/crates/prometeu-core/src/hardware/memory_banks.rs b/crates/prometeu-core/src/hardware/memory_banks.rs new file mode 100644 index 00000000..2c6d86d9 --- /dev/null +++ b/crates/prometeu-core/src/hardware/memory_banks.rs @@ -0,0 +1,90 @@ +use std::sync::{Arc, RwLock}; +use crate::model::{TileBank, SoundBank}; + +/// Non-generic interface for peripherals to access graphical tile banks. +pub trait TileBankPoolAccess: Send + Sync { + /// Returns a reference to the resident TileBank in the specified slot, if any. + fn tile_bank_slot(&self, slot: usize) -> Option>; + /// Returns the total number of slots available in this bank. + fn tile_bank_slot_count(&self) -> usize; +} + +/// Non-generic interface for the AssetManager to install graphical tile banks. +pub trait TileBankPoolInstaller: Send + Sync { + /// Atomically swaps the resident TileBank in the specified slot. + fn install_tile_bank(&self, slot: usize, bank: Arc); +} + +/// Non-generic interface for peripherals to access sound banks. +pub trait SoundBankPoolAccess: Send + Sync { + /// Returns a reference to the resident SoundBank in the specified slot, if any. + fn sound_bank_slot(&self, slot: usize) -> Option>; + /// Returns the total number of slots available in this bank. + fn sound_bank_slot_count(&self) -> usize; +} + +/// Non-generic interface for the AssetManager to install sound banks. +pub trait SoundBankPoolInstaller: Send + Sync { + /// Atomically swaps the resident SoundBank in the specified slot. + fn install_sound_bank(&self, slot: usize, bank: Arc); +} + +/// Centralized container for all hardware memory banks. +/// +/// MemoryBanks represent the actual hardware slot state. +/// Peripherals consume this state via narrow, non-generic traits. +/// AssetManager coordinates residency and installs assets into these slots. +pub struct MemoryBanks { + tile_bank_pool: Arc>; 16]>>, + sound_bank_pool: Arc>; 16]>>, +} + +impl MemoryBanks { + /// Creates a new set of memory banks with empty slots. + pub fn new() -> Self { + Self { + tile_bank_pool: Arc::new(RwLock::new(std::array::from_fn(|_| None))), + sound_bank_pool: Arc::new(RwLock::new(std::array::from_fn(|_| None))), + } + } +} + +impl TileBankPoolAccess for MemoryBanks { + fn tile_bank_slot(&self, slot: usize) -> Option> { + let pool = self.tile_bank_pool.read().unwrap(); + pool.get(slot).and_then(|s| s.as_ref().map(Arc::clone)) + } + + fn tile_bank_slot_count(&self) -> usize { + 16 + } +} + +impl TileBankPoolInstaller for MemoryBanks { + fn install_tile_bank(&self, slot: usize, bank: Arc) { + let mut pool = self.tile_bank_pool.write().unwrap(); + if slot < 16 { + pool[slot] = Some(bank); + } + } +} + +impl SoundBankPoolAccess for MemoryBanks { + fn sound_bank_slot(&self, slot: usize) -> Option> { + let pool = self.sound_bank_pool.read().unwrap(); + pool.get(slot).and_then(|s| s.as_ref().map(Arc::clone)) + } + + fn sound_bank_slot_count(&self) -> usize { + 16 + } +} + +impl SoundBankPoolInstaller for MemoryBanks { + fn install_sound_bank(&self, slot: usize, bank: Arc) { + let mut pool = self.sound_bank_pool.write().unwrap(); + if slot < 16 { + pool[slot] = Some(bank); + } + } +} diff --git a/crates/prometeu-core/src/hardware/mod.rs b/crates/prometeu-core/src/hardware/mod.rs index e530dc0a..8e240f35 100644 --- a/crates/prometeu-core/src/hardware/mod.rs +++ b/crates/prometeu-core/src/hardware/mod.rs @@ -1,16 +1,21 @@ +mod asset; mod gfx; mod pad; mod touch; mod input_signal; mod audio; +mod memory_banks; pub mod hardware; -pub use gfx::Gfx; +pub use crate::model::HandleId; +pub use asset::AssetManager; +pub use audio::{Audio, AudioCommand, Channel, LoopMode, MAX_CHANNELS, OUTPUT_SAMPLE_RATE}; pub use gfx::BlendMode; +pub use gfx::Gfx; pub use input_signal::InputSignals; +pub use memory_banks::MemoryBanks; pub use pad::Pad; pub use touch::Touch; -pub use audio::{Audio, AudioCommand, Channel, LoopMode, MAX_CHANNELS, OUTPUT_SAMPLE_RATE}; pub trait HardwareBridge { fn gfx(&self) -> &Gfx; @@ -24,4 +29,7 @@ pub trait HardwareBridge { fn touch(&self) -> &Touch; fn touch_mut(&mut self) -> &mut Touch; + + fn assets(&self) -> &AssetManager; + fn assets_mut(&mut self) -> &mut AssetManager; } diff --git a/crates/prometeu-core/src/model/asset.rs b/crates/prometeu-core/src/model/asset.rs new file mode 100644 index 00000000..195427f3 --- /dev/null +++ b/crates/prometeu-core/src/model/asset.rs @@ -0,0 +1,80 @@ +use serde::{Deserialize, Serialize}; + +pub type HandleId = u32; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Deserialize, Serialize)] +#[allow(non_camel_case_types)] +pub enum BankType { + TILES, + SOUNDS, + // TILEMAPS, + // BLOBS, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct AssetEntry { + pub asset_id: u32, + pub asset_name: String, + pub bank_type: BankType, + pub offset: u64, + pub size: u64, + pub decoded_size: u64, + pub codec: String, // e.g., "RAW" + pub metadata: serde_json::Value, +} + +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct PreloadEntry { + pub asset_name: String, + pub slot: usize, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum LoadStatus { + PENDING, + LOADING, + READY, + COMMITTED, + CANCELED, + ERROR, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BankStats { + pub total_bytes: usize, + pub used_bytes: usize, + pub free_bytes: usize, + pub inflight_bytes: usize, + pub slot_count: usize, + pub slots_occupied: usize, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SlotStats { + pub asset_id: Option, + pub asset_name: Option, + pub generation: u32, + pub resident_bytes: usize, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct SlotRef { + pub asset_type: BankType, + pub index: usize, +} + +impl SlotRef { + pub fn gfx(index: usize) -> Self { + Self { + asset_type: BankType::TILES, + index, + } + } + + pub fn audio(index: usize) -> Self { + Self { + asset_type: BankType::SOUNDS, + index, + } + } +} diff --git a/crates/prometeu-core/src/model/cartridge.rs b/crates/prometeu-core/src/model/cartridge.rs index f45a8793..6beadebc 100644 --- a/crates/prometeu-core/src/model/cartridge.rs +++ b/crates/prometeu-core/src/model/cartridge.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use crate::model::asset::{AssetEntry, PreloadEntry}; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] @@ -15,7 +15,9 @@ pub struct Cartridge { pub app_mode: AppMode, pub entrypoint: String, pub program: Vec, - pub assets_path: Option, + pub assets: Vec, + pub asset_table: Vec, + pub preload: Vec, } #[derive(Debug, Clone, Deserialize, Serialize)] @@ -26,7 +28,11 @@ pub struct CartridgeDTO { pub app_mode: AppMode, pub entrypoint: String, pub program: Vec, - pub assets_path: Option, + pub assets: Vec, + #[serde(default)] + pub asset_table: Vec, + #[serde(default)] + pub preload: Vec, } impl From for Cartridge { @@ -38,7 +44,9 @@ impl From for Cartridge { app_mode: dto.app_mode, entrypoint: dto.entrypoint, program: dto.program, - assets_path: dto.assets_path, + assets: dto.assets, + asset_table: dto.asset_table, + preload: dto.preload, } } } @@ -62,4 +70,8 @@ pub struct CartridgeManifest { pub app_version: String, pub app_mode: AppMode, pub entrypoint: String, + #[serde(default)] + pub asset_table: Vec, + #[serde(default)] + pub preload: Vec, } diff --git a/crates/prometeu-core/src/model/cartridge_loader.rs b/crates/prometeu-core/src/model/cartridge_loader.rs index fec55501..b8fd024d 100644 --- a/crates/prometeu-core/src/model/cartridge_loader.rs +++ b/crates/prometeu-core/src/model/cartridge_loader.rs @@ -48,11 +48,11 @@ impl DirectoryCartridgeLoader { let program = fs::read(program_path).map_err(|_| CartridgeError::IoError)?; - let assets_path = path.join("assets"); - let assets_path = if assets_path.exists() && assets_path.is_dir() { - Some(assets_path) + let assets_pa_path = path.join("assets.pa"); + let assets = if assets_pa_path.exists() { + fs::read(assets_pa_path).map_err(|_| CartridgeError::IoError)? } else { - None + Vec::new() }; let dto = CartridgeDTO { @@ -62,7 +62,9 @@ impl DirectoryCartridgeLoader { app_mode: manifest.app_mode, entrypoint: manifest.entrypoint, program, - assets_path, + assets, + asset_table: manifest.asset_table, + preload: manifest.preload, }; Ok(Cartridge::from(dto)) diff --git a/crates/prometeu-core/src/model/mod.rs b/crates/prometeu-core/src/model/mod.rs index 8eb4733b..3f7b7b61 100644 --- a/crates/prometeu-core/src/model/mod.rs +++ b/crates/prometeu-core/src/model/mod.rs @@ -1,19 +1,23 @@ +mod asset; mod color; mod button; mod tile; mod tile_layer; mod tile_bank; +mod sound_bank; mod sprite; mod sample; mod cartridge; mod cartridge_loader; mod window; +pub use asset::{AssetEntry, BankType, BankStats, LoadStatus, SlotRef, SlotStats, HandleId, PreloadEntry}; pub use button::{Button, ButtonId}; pub use cartridge::{AppMode, Cartridge, CartridgeDTO, CartridgeError}; pub use cartridge_loader::{CartridgeLoader, DirectoryCartridgeLoader, PackedCartridgeLoader}; pub use color::Color; pub use sample::Sample; +pub use sound_bank::SoundBank; pub use sprite::Sprite; pub use tile::Tile; pub use tile_bank::{TileBank, TileSize}; diff --git a/crates/prometeu-core/src/model/sound_bank.rs b/crates/prometeu-core/src/model/sound_bank.rs new file mode 100644 index 00000000..fbf70218 --- /dev/null +++ b/crates/prometeu-core/src/model/sound_bank.rs @@ -0,0 +1,16 @@ +use crate::model::Sample; +use std::sync::Arc; + +/// A container for audio assets. +/// +/// A SoundBank stores multiple audio samples that can be played by the +/// audio subsystem. +pub struct SoundBank { + pub samples: Vec>, +} + +impl SoundBank { + pub fn new(samples: Vec>) -> Self { + Self { samples } + } +} diff --git a/crates/prometeu-core/src/model/tile_bank.rs b/crates/prometeu-core/src/model/tile_bank.rs index 47c7489f..f22cac0f 100644 --- a/crates/prometeu-core/src/model/tile_bank.rs +++ b/crates/prometeu-core/src/model/tile_bank.rs @@ -27,8 +27,8 @@ pub struct TileBank { /// Pixel data stored as 4-bit indices (packed into 8-bit values). /// Index 0 is always reserved for transparency. pub pixel_indices: Vec, - /// Table of 256 palettes, each containing 16 RGB565 colors. - pub palettes: [[Color; 16]; 256], + /// Table of 64 palettes, each containing 16 RGB565 colors, total of 1024 colors for a bank. + pub palettes: [[Color; 16]; 64], } impl TileBank { @@ -39,7 +39,7 @@ impl TileBank { width, height, pixel_indices: vec![0; width * height], // Index 0 = Transparent - palettes: [[Color::BLACK; 16]; 256], + palettes: [[Color::BLACK; 16]; 64], } } diff --git a/crates/prometeu-core/src/model/tile_layer.rs b/crates/prometeu-core/src/model/tile_layer.rs index e0e0e8b7..f2153491 100644 --- a/crates/prometeu-core/src/model/tile_layer.rs +++ b/crates/prometeu-core/src/model/tile_layer.rs @@ -35,7 +35,7 @@ impl TileLayer { fn create(width: usize, height: usize, tile_size: TileSize) -> Self { Self { bank_id: 0, - tile_size: tile_size, + tile_size, map: TileMap::create(width, height), } } diff --git a/crates/prometeu-core/src/prometeu_os/prometeu_os.rs b/crates/prometeu-core/src/prometeu_os/prometeu_os.rs index 7680268c..bddec8b2 100644 --- a/crates/prometeu-core/src/prometeu_os/prometeu_os.rs +++ b/crates/prometeu-core/src/prometeu_os/prometeu_os.rs @@ -1,12 +1,11 @@ use crate::fs::{FsBackend, FsState, VirtualFS}; use crate::hardware::{HardwareBridge, InputSignals}; use crate::log::{LogLevel, LogService, LogSource}; -use crate::model::{Cartridge, Color, Sample}; +use crate::model::{BankType, Cartridge, Color}; use crate::prometeu_os::{NativeInterface, Syscall}; use crate::telemetry::{CertificationConfig, Certifier, TelemetryFrame}; use crate::virtual_machine::{Value, VirtualMachine}; use std::collections::HashMap; -use std::sync::Arc; use std::time::Instant; /// PrometeuOS (POS): The system firmware/base. @@ -25,11 +24,6 @@ pub struct PrometeuOS { /// Real-world CPU time (in microseconds) consumed by the last host tick. pub last_frame_cpu_time_us: u64, - // Example assets (kept for compatibility with v0 audio syscalls) - pub sample_square: Option>, - pub sample_kick: Option>, - pub sample_snare: Option>, - // Filesystem /// The virtual filesystem interface. pub fs: VirtualFS, @@ -87,9 +81,6 @@ impl PrometeuOS { logical_frame_active: false, logical_frame_remaining_cycles: 0, last_frame_cpu_time_us: 0, - sample_square: None, - sample_kick: None, - sample_snare: None, fs: VirtualFS::new(), fs_state: FsState::Unmounted, open_files: HashMap::new(), @@ -108,9 +99,6 @@ impl PrometeuOS { boot_time, }; - // Initializes basic samples (same logic as LogicalHardware) - os.sample_square = Some(Arc::new(Self::create_square_sample(440.0, 0.1))); - os.log(LogLevel::Info, LogSource::Pos, 0, "PrometeuOS starting...".to_string()); os @@ -188,8 +176,8 @@ impl PrometeuOS { /// This method is responsible for managing the logical frame lifecycle. /// A single host tick might execute a full logical frame, part of it, /// or multiple frames depending on the configured slices. - pub fn step_frame(&mut self, vm: &mut VirtualMachine, signals: &InputSignals, hw: &mut dyn HardwareBridge) -> Option { - let start = std::time::Instant::now(); + pub fn tick(&mut self, vm: &mut VirtualMachine, signals: &InputSignals, hw: &mut dyn HardwareBridge) -> Option { + let start = Instant::now(); self.tick_index += 1; // If the system is paused, we don't advance unless there's a debug step request. @@ -214,13 +202,13 @@ impl PrometeuOS { } // 2. Budget Allocation - // Determine how many cycles we can run in this host tick. + // Determines how many cycles we can run in this host tick. let budget = std::cmp::min(Self::SLICE_PER_TICK, self.logical_frame_remaining_cycles); // 3. VM Execution if budget > 0 { - // Run the VM until budget is hit or FRAME_SYNC is reached. - let run_result = vm.run_budget(budget, self, hw); + // Run the VM until the budget is hit or FRAME_SYNC is reached. + let run_result = vm.run_budget(budget, self, hw); // internally dispatch to frame on SDK match run_result { Ok(run) => { @@ -275,9 +263,26 @@ impl PrometeuOS { self.last_frame_cpu_time_us = start.elapsed().as_micros() as u64; + // Update bank telemetry in current frame (snapshot) + let gfx_stats = hw.assets().bank_info(BankType::TILES); + self.telemetry_current.gfx_used_bytes = gfx_stats.used_bytes; + self.telemetry_current.gfx_inflight_bytes = gfx_stats.inflight_bytes; + self.telemetry_current.gfx_slots_occupied = gfx_stats.slots_occupied as u32; + + let audio_stats = hw.assets().bank_info(BankType::SOUNDS); + self.telemetry_current.audio_used_bytes = audio_stats.used_bytes; + self.telemetry_current.audio_inflight_bytes = audio_stats.inflight_bytes; + self.telemetry_current.audio_slots_occupied = audio_stats.slots_occupied as u32; + // If the frame ended exactly in this tick, we update the final real time in the latch. if !self.logical_frame_active && self.telemetry_last.frame_index == self.logical_frame_index.wrapping_sub(1) { self.telemetry_last.host_cpu_time_us = self.last_frame_cpu_time_us; + self.telemetry_last.gfx_used_bytes = self.telemetry_current.gfx_used_bytes; + self.telemetry_last.gfx_inflight_bytes = self.telemetry_current.gfx_inflight_bytes; + self.telemetry_last.gfx_slots_occupied = self.telemetry_current.gfx_slots_occupied; + self.telemetry_last.audio_used_bytes = self.telemetry_current.audio_used_bytes; + self.telemetry_last.audio_inflight_bytes = self.telemetry_current.audio_inflight_bytes; + self.telemetry_last.audio_slots_occupied = self.telemetry_current.audio_slots_occupied; } None @@ -367,24 +372,6 @@ impl PrometeuOS { _ => false, } } - - fn create_square_sample(freq: f64, duration: f64) -> Sample { - let sample_rate = crate::hardware::OUTPUT_SAMPLE_RATE; - let num_samples = (duration * sample_rate as f64) as usize; - let mut data = Vec::with_capacity(num_samples); - let period = sample_rate as f64 / freq; - - for i in 0..num_samples { - let val = if (i as f64 % period) < (period / 2.0) { - 10000 - } else { - -10000 - }; - data.push(val); - } - - Sample::new(sample_rate, data) - } } #[cfg(test)] @@ -410,17 +397,19 @@ mod tests { app_mode: AppMode::Game, entrypoint: "0".to_string(), program: rom, - assets_path: None, + assets: vec![], + asset_table: vec![], + preload: vec![], }; os.initialize_vm(&mut vm, &cartridge); // First tick - os.step_frame(&mut vm, &signals, &mut hw); + os.tick(&mut vm, &signals, &mut hw); let cycles_after_tick_1 = vm.cycles; assert!(cycles_after_tick_1 >= PrometeuOS::CYCLES_PER_LOGICAL_FRAME); // Second tick - Now it SHOULD NOT gain more budget - os.step_frame(&mut vm, &signals, &mut hw); + os.tick(&mut vm, &signals, &mut hw); let cycles_after_tick_2 = vm.cycles; // FIX: It should not have consumed cycles in the second tick because the logical frame budget ended @@ -450,12 +439,14 @@ mod tests { app_mode: AppMode::Game, entrypoint: "0".to_string(), program: rom, - assets_path: None, + assets: vec![], + asset_table: vec![], + preload: vec![], }; os.initialize_vm(&mut vm, &cartridge); // First tick - os.step_frame(&mut vm, &signals, &mut hw); + os.tick(&mut vm, &signals, &mut hw); let cycles_after_tick_1 = vm.cycles; // Should have stopped at FrameSync @@ -463,7 +454,7 @@ mod tests { assert!(cycles_after_tick_1 < PrometeuOS::CYCLES_PER_LOGICAL_FRAME); // Second tick - Should reset the budget and run a bit more until the next FrameSync - os.step_frame(&mut vm, &signals, &mut hw); + os.tick(&mut vm, &signals, &mut hw); let cycles_after_tick_2 = vm.cycles; assert!(cycles_after_tick_2 > cycles_after_tick_1, "VM should have consumed more cycles because FrameSync reset the budget"); @@ -480,6 +471,54 @@ mod tests { assert_eq!(os.get_color(3), Color::from_raw(3)); } + #[test] + fn test_gfx_set_sprite_syscall_pops() { + let mut os = PrometeuOS::new(None); + let mut vm = VirtualMachine::default(); + let mut hw = Hardware::new(); + + // Push arguments in order 1 to 10 + vm.push(Value::String("mouse_cursor".to_string())); // arg1: assetName + vm.push(Value::Int32(0)); // arg2: id + + // Simulating touch.x and touch.y syscalls + vm.push(Value::Int32(10)); // arg3: x (returned from syscall) + vm.push(Value::Int32(20)); // arg4: y (returned from syscall) + + vm.push(Value::Int32(0)); // arg5: tileId + vm.push(Value::Int32(0)); // arg6: paletteId + vm.push(Value::Boolean(true)); // arg7: active + vm.push(Value::Boolean(false)); // arg8: flipX + vm.push(Value::Boolean(false)); // arg9: flipY + vm.push(Value::Int32(4)); // arg10: priority + + let res = os.syscall(0x1007, &mut vm, &mut hw); + assert!(res.is_ok(), "GfxSetSprite syscall should succeed, but got: {:?}", res.err()); + } + + #[test] + fn test_gfx_set_sprite_with_swapped_arguments_repro() { + let mut os = PrometeuOS::new(None); + let mut vm = VirtualMachine::default(); + let mut hw = Hardware::new(); + + // Repro: what if the compiler is pushing in reverse order? + vm.push(Value::Int32(4)); // arg10? + vm.push(Value::Boolean(false)); + vm.push(Value::Boolean(false)); + vm.push(Value::Boolean(true)); + vm.push(Value::Int32(0)); + vm.push(Value::Int32(0)); + vm.push(Value::Int32(20)); + vm.push(Value::Int32(10)); + vm.push(Value::Int32(0)); + vm.push(Value::String("mouse_cursor".to_string())); // arg1? + + let res = os.syscall(0x1007, &mut vm, &mut hw); + assert!(res.is_err()); + assert_eq!(res.err().unwrap(), "Expected integer"); // Because it tries to pop priority but gets a string + } + #[test] fn test_syscall_log_write_and_rate_limit() { let mut os = PrometeuOS::new(None); @@ -659,6 +698,40 @@ impl NativeInterface for PrometeuOS { vm.push(Value::Null); Ok(200) } + // gfx.set_sprite(asset_name, id, x, y, tile_id, palette_id, active, flip_x, flip_y, priority) + Syscall::GfxSetSprite => { + let priority = vm.pop_integer()? as u8; + let flip_y = vm.pop_integer()? != 0; + let flip_x = vm.pop_integer()? != 0; + let active = vm.pop_integer()? != 0; + let palette_id = vm.pop_integer()? as u8; + let tile_id = vm.pop_integer()? as u16; + let y = vm.pop_integer()? as i32; + let x = vm.pop_integer()? as i32; + let index = vm.pop_integer()? as usize; + let val = vm.pop()?; + let asset_name = match val { + Value::String(ref s) => s.clone(), + _ => return Err(format!("Expected string asset_name in GfxSetSprite, but got {:?}", val).into()), + }; + + let bank_id = hw.assets().find_slot_by_name(&asset_name, crate::model::BankType::TILES).unwrap_or(0); + + if index < 512 { + hw.gfx_mut().sprites[index] = crate::model::Sprite { + tile: crate::model::Tile { id: tile_id, flip_x: false, flip_y: false, palette_id }, + x, + y, + bank_id, + active, + flip_x, + flip_y, + priority, + }; + } + vm.push(Value::Null); + Ok(100) + } // --- Input Syscalls --- @@ -723,16 +796,31 @@ impl NativeInterface for PrometeuOS { let voice_id = vm.pop_integer()? as usize; let sample_id = vm.pop_integer()? as u32; - let sample = match sample_id { - 0 => self.sample_square.clone(), - 1 => self.sample_kick.clone(), - 2 => self.sample_snare.clone(), - _ => None, + hw.audio_mut().play(0, sample_id as u16, voice_id, volume, pan, pitch, 0, crate::hardware::LoopMode::Off); + vm.push(Value::Null); + Ok(300) + } + + // audio.play(asset_name, sample_id, voice_id, volume, pan, pitch, loop_mode) + Syscall::AudioPlay => { + let loop_mode = match vm.pop_integer()? { + 0 => crate::hardware::LoopMode::Off, + _ => crate::hardware::LoopMode::On, + }; + let pitch = vm.pop_number()?; + let pan = vm.pop_integer()? as u8; + let volume = vm.pop_integer()? as u8; + let voice_id = vm.pop_integer()? as usize; + let sample_id = vm.pop_integer()? as u16; + let val = vm.pop()?; + let asset_name = match val { + Value::String(ref s) => s.clone(), + _ => return Err(format!("Expected string asset_name in AudioPlay, but got {:?}", val).into()), }; - if let Some(s) = sample { - hw.audio_mut().play(s, voice_id, volume, pan, pitch, 0, crate::hardware::LoopMode::Off); - } + let bank_id = hw.assets().find_slot_by_name(&asset_name, crate::model::BankType::SOUNDS).unwrap_or(0); + + hw.audio_mut().play(bank_id, sample_id, voice_id, volume, pan, pitch, 0, loop_mode); vm.push(Value::Null); Ok(300) } @@ -860,6 +948,83 @@ impl NativeInterface for PrometeuOS { let level = vm.pop_integer()?; self.syscall_log_write(vm, level, tag, msg) } + + // --- Asset Syscalls --- + Syscall::AssetLoad => { + let asset_id = match vm.pop()? { + Value::String(s) => s, + _ => return Err("Expected string asset_id".into()), + }; + let asset_type_val = vm.pop_integer()? as u32; + let slot_index = vm.pop_integer()? as usize; + + let asset_type = match asset_type_val { + 0 => crate::model::BankType::TILES, + 1 => crate::model::BankType::SOUNDS, + _ => return Err("Invalid asset type".to_string()), + }; + let slot = crate::model::SlotRef { asset_type, index: slot_index }; + + match hw.assets().load(&asset_id, slot) { + Ok(handle) => { + vm.push(Value::Int64(handle as i64)); + Ok(1000) + } + Err(e) => Err(e), + } + } + Syscall::AssetStatus => { + let handle = vm.pop_integer()? as u32; + let status = hw.assets().status(handle); + let status_val = match status { + crate::model::LoadStatus::PENDING => 0, + crate::model::LoadStatus::LOADING => 1, + crate::model::LoadStatus::READY => 2, + crate::model::LoadStatus::COMMITTED => 3, + crate::model::LoadStatus::CANCELED => 4, + crate::model::LoadStatus::ERROR => 5, + }; + vm.push(Value::Int64(status_val)); + Ok(100) + } + Syscall::AssetCommit => { + let handle = vm.pop_integer()? as u32; + hw.assets().commit(handle); + vm.push(Value::Null); + Ok(100) + } + Syscall::AssetCancel => { + let handle = vm.pop_integer()? as u32; + hw.assets().cancel(handle); + vm.push(Value::Null); + Ok(100) + } + Syscall::BankInfo => { + let asset_type_val = vm.pop_integer()? as u32; + let asset_type = match asset_type_val { + 0 => crate::model::BankType::TILES, + 1 => crate::model::BankType::SOUNDS, + _ => return Err("Invalid asset type".to_string()), + }; + let info = hw.assets().bank_info(asset_type); + let json = serde_json::to_string(&info).unwrap_or_default(); + vm.push(Value::String(json)); + Ok(500) + } + Syscall::BankSlotInfo => { + let slot_index = vm.pop_integer()? as usize; + let asset_type_val = vm.pop_integer()? as u32; + let asset_type = match asset_type_val { + 0 => crate::model::BankType::TILES, + 1 => crate::model::BankType::SOUNDS, + _ => return Err("Invalid asset type".to_string()), + }; + let slot = crate::model::SlotRef { asset_type, index: slot_index }; + let info = hw.assets().slot_info(slot); + let json = serde_json::to_string(&info).unwrap_or_default(); + vm.push(Value::String(json)); + Ok(500) + } } } } \ No newline at end of file diff --git a/crates/prometeu-core/src/prometeu_os/syscalls.rs b/crates/prometeu-core/src/prometeu_os/syscalls.rs index f5be87c4..bc1a5b4c 100644 --- a/crates/prometeu-core/src/prometeu_os/syscalls.rs +++ b/crates/prometeu-core/src/prometeu_os/syscalls.rs @@ -12,6 +12,7 @@ pub enum Syscall { GfxDrawCircle = 0x1004, GfxDrawDisc = 0x1005, GfxDrawSquare = 0x1006, + GfxSetSprite = 0x1007, // Input InputGetPad = 0x2001, @@ -28,6 +29,7 @@ pub enum Syscall { // Audio AudioPlaySample = 0x3001, + AudioPlay = 0x3002, // FS FsOpen = 0x4001, @@ -41,6 +43,16 @@ pub enum Syscall { // Log LogWrite = 0x5001, LogWriteTag = 0x5002, + + // Asset + AssetLoad = 0x6001, + AssetStatus = 0x6002, + AssetCommit = 0x6003, + AssetCancel = 0x6004, + + // Bank + BankInfo = 0x6101, + BankSlotInfo = 0x6102, } impl Syscall { @@ -54,6 +66,7 @@ impl Syscall { 0x1004 => Some(Self::GfxDrawCircle), 0x1005 => Some(Self::GfxDrawDisc), 0x1006 => Some(Self::GfxDrawSquare), + 0x1007 => Some(Self::GfxSetSprite), 0x2001 => Some(Self::InputGetPad), 0x2002 => Some(Self::InputGetPadPressed), 0x2003 => Some(Self::InputGetPadReleased), @@ -65,6 +78,7 @@ impl Syscall { 0x2105 => Some(Self::TouchIsReleased), 0x2106 => Some(Self::TouchGetHold), 0x3001 => Some(Self::AudioPlaySample), + 0x3002 => Some(Self::AudioPlay), 0x4001 => Some(Self::FsOpen), 0x4002 => Some(Self::FsRead), 0x4003 => Some(Self::FsWrite), @@ -74,6 +88,12 @@ impl Syscall { 0x4007 => Some(Self::FsDelete), 0x5001 => Some(Self::LogWrite), 0x5002 => Some(Self::LogWriteTag), + 0x6001 => Some(Self::AssetLoad), + 0x6002 => Some(Self::AssetStatus), + 0x6003 => Some(Self::AssetCommit), + 0x6004 => Some(Self::AssetCancel), + 0x6101 => Some(Self::BankInfo), + 0x6102 => Some(Self::BankSlotInfo), _ => None, } } @@ -120,6 +140,7 @@ impl Syscall { "gfx.drawCircle" | "gfx.draw_circle" => Some(Self::GfxDrawCircle), "gfx.drawDisc" | "gfx.draw_disc" => Some(Self::GfxDrawDisc), "gfx.drawSquare" | "gfx.draw_square" => Some(Self::GfxDrawSquare), + "gfx.setSprite" | "gfx.set_sprite" => Some(Self::GfxSetSprite), "input.getPad" => Some(Self::InputGetPad), "input.getPadPressed" | "input.get_pad_pressed" => Some(Self::InputGetPadPressed), "input.getPadReleased" | "input.get_pad_released" => Some(Self::InputGetPadReleased), @@ -131,6 +152,7 @@ impl Syscall { "touch.isReleased" | "touch.is_released" => Some(Self::TouchIsReleased), "touch.getHold" | "touch.get_hold" => Some(Self::TouchGetHold), "audio.playSample" | "audio.play_sample" => Some(Self::AudioPlaySample), + "audio.play" => Some(Self::AudioPlay), "fs.open" => Some(Self::FsOpen), "fs.read" => Some(Self::FsRead), "fs.write" => Some(Self::FsWrite), @@ -140,6 +162,12 @@ impl Syscall { "fs.delete" => Some(Self::FsDelete), "log.write" => Some(Self::LogWrite), "log.writeTag" | "log.write_tag" => Some(Self::LogWriteTag), + "asset.load" => Some(Self::AssetLoad), + "asset.status" => Some(Self::AssetStatus), + "asset.commit" => Some(Self::AssetCommit), + "asset.cancel" => Some(Self::AssetCancel), + "bank.info" => Some(Self::BankInfo), + "bank.slotInfo" | "bank.slot_info" => Some(Self::BankSlotInfo), _ => { None } diff --git a/crates/prometeu-core/src/telemetry.rs b/crates/prometeu-core/src/telemetry.rs index 7c18996b..1ede92e0 100644 --- a/crates/prometeu-core/src/telemetry.rs +++ b/crates/prometeu-core/src/telemetry.rs @@ -8,6 +8,16 @@ pub struct TelemetryFrame { pub syscalls: u32, pub host_cpu_time_us: u64, pub violations: u32, + + // GFX Banks + pub gfx_used_bytes: usize, + pub gfx_inflight_bytes: usize, + pub gfx_slots_occupied: u32, + + // Audio Banks + pub audio_used_bytes: usize, + pub audio_inflight_bytes: usize, + pub audio_slots_occupied: u32, } #[derive(Debug, Clone, Copy, Default)] diff --git a/crates/prometeu-core/src/virtual_machine/virtual_machine.rs b/crates/prometeu-core/src/virtual_machine/virtual_machine.rs index fc25ced0..e4926aa9 100644 --- a/crates/prometeu-core/src/virtual_machine/virtual_machine.rs +++ b/crates/prometeu-core/src/virtual_machine/virtual_machine.rs @@ -666,6 +666,9 @@ impl VirtualMachine { pub fn pop_integer(&mut self) -> Result { let val = self.pop()?; + if let Value::Boolean(b) = val { + return Ok(if b { 1 } else { 0 }); + } val.as_integer().ok_or_else(|| "Expected integer".into()) } @@ -688,9 +691,9 @@ impl VirtualMachine { #[cfg(test)] mod tests { use super::*; - use crate::virtual_machine::Value; - use crate::prometeu_os::NativeInterface; use crate::hardware::HardwareBridge; + use crate::prometeu_os::NativeInterface; + use crate::virtual_machine::Value; struct MockNative; impl NativeInterface for MockNative { @@ -709,6 +712,8 @@ mod tests { fn pad_mut(&mut self) -> &mut crate::hardware::Pad { todo!() } fn touch(&self) -> &crate::hardware::Touch { todo!() } fn touch_mut(&mut self) -> &mut crate::hardware::Touch { todo!() } + fn assets(&self) -> &crate::hardware::AssetManager { todo!() } + fn assets_mut(&mut self) -> &mut crate::hardware::AssetManager { todo!() } } #[test] diff --git a/crates/prometeu-runtime-desktop/src/audio.rs b/crates/prometeu-runtime-desktop/src/audio.rs index ae194f5b..858767f9 100644 --- a/crates/prometeu-runtime-desktop/src/audio.rs +++ b/crates/prometeu-runtime-desktop/src/audio.rs @@ -1,5 +1,5 @@ -use prometeu_core::hardware::{AudioCommand, Channel, LoopMode, MAX_CHANNELS, OUTPUT_SAMPLE_RATE}; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; +use prometeu_core::hardware::{AudioCommand, Channel, LoopMode, MAX_CHANNELS, OUTPUT_SAMPLE_RATE}; use ringbuf::traits::{Consumer, Producer, Split}; use ringbuf::HeapRb; use std::sync::Arc; @@ -69,7 +69,9 @@ impl HostAudio { pub fn send_commands(&mut self, commands: &mut Vec) { if let Some(producer) = &mut self.producer { for cmd in commands.drain(..) { - let _ = producer.try_push(cmd); + if let Err(_) = producer.try_push(cmd) { + eprintln!("[HostAudio] Command ringbuffer full, dropping command."); + } } } } @@ -86,6 +88,7 @@ impl HostAudio { pub struct AudioMixer { voices: [Channel; MAX_CHANNELS], pub last_processing_time: Duration, + paused: bool, } impl AudioMixer { @@ -93,6 +96,7 @@ impl AudioMixer { Self { voices: Default::default(), last_processing_time: Duration::ZERO, + paused: false, } } @@ -108,8 +112,10 @@ impl AudioMixer { loop_mode, } => { if voice_id < MAX_CHANNELS { + println!("[AudioMixer] Playing voice {}: vol={}, pitch={}, loop={:?}", voice_id, volume, pitch, loop_mode); self.voices[voice_id] = Channel { sample: Some(sample), + active: true, pos: 0.0, pitch, volume, @@ -121,6 +127,7 @@ impl AudioMixer { } AudioCommand::Stop { voice_id } => { if voice_id < MAX_CHANNELS { + self.voices[voice_id].active = false; self.voices[voice_id].sample = None; } } @@ -139,6 +146,14 @@ impl AudioMixer { self.voices[voice_id].pitch = pitch; } } + AudioCommand::MasterPause => { + println!("[AudioMixer] Master Pause"); + self.paused = true; + } + AudioCommand::MasterResume => { + println!("[AudioMixer] Master Resume"); + self.paused = false; + } } } @@ -149,6 +164,11 @@ impl AudioMixer { *sample = 0.0; } + if self.paused { + self.last_processing_time = start.elapsed(); + return; + } + for voice in self.voices.iter_mut() { let sample_data = match &voice.sample { Some(s) => s, @@ -168,6 +188,7 @@ impl AudioMixer { let pos_fract = voice.pos - pos_int as f64; if pos_int >= sample_data.data.len() { + voice.active = false; voice.sample = None; break; } @@ -197,6 +218,7 @@ impl AudioMixer { let loop_start = sample_data.loop_start.unwrap_or(0) as f64; voice.pos = loop_start + (voice.pos - end_pos); } else { + voice.active = false; voice.sample = None; break; } diff --git a/crates/prometeu-runtime-desktop/src/debugger.rs b/crates/prometeu-runtime-desktop/src/debugger.rs index 84247690..a4545e51 100644 --- a/crates/prometeu-runtime-desktop/src/debugger.rs +++ b/crates/prometeu-runtime-desktop/src/debugger.rs @@ -230,17 +230,32 @@ impl HostDebugger { // Map Certification tags (0xCA01-0xCA03) to 'Cert' protocol events. if event.tag >= 0xCA01 && event.tag <= 0xCA03 { - let rule = match event.tag { - 0xCA01 => "cycles_budget", - 0xCA02 => "max_syscalls", - 0xCA03 => "max_host_cpu_us", - _ => "unknown" - }.to_string(); + let tel = &firmware.os.telemetry_last; + let cert_config = &firmware.os.certifier.config; + + let (rule, used, limit) = match event.tag { + 0xCA01 => ( + "cycles_budget".to_string(), + tel.cycles_used, + cert_config.cycles_budget_per_frame.unwrap_or(0), + ), + 0xCA02 => ( + "max_syscalls".to_string(), + tel.syscalls as u64, + cert_config.max_syscalls_per_frame.unwrap_or(0) as u64, + ), + 0xCA03 => ( + "max_host_cpu_us".to_string(), + tel.host_cpu_time_us, + cert_config.max_host_cpu_us_per_frame.unwrap_or(0), + ), + _ => ("unknown".to_string(), 0, 0), + }; self.send_event(DebugEvent::Cert { rule, - used: 0, - limit: 0, + used, + limit, frame_index: firmware.os.logical_frame_index, }); } @@ -261,6 +276,14 @@ impl HostDebugger { vm_steps: tel.vm_steps, syscalls: tel.syscalls, cycles: tel.cycles_used, + host_cpu_time_us: tel.host_cpu_time_us, + violations: tel.violations, + gfx_used_bytes: tel.gfx_used_bytes, + gfx_inflight_bytes: tel.gfx_inflight_bytes, + gfx_slots_occupied: tel.gfx_slots_occupied, + audio_used_bytes: tel.audio_used_bytes, + audio_inflight_bytes: tel.audio_inflight_bytes, + audio_slots_occupied: tel.audio_slots_occupied, }); self.last_telemetry_frame = current_frame; } diff --git a/crates/prometeu-runtime-desktop/src/runner.rs b/crates/prometeu-runtime-desktop/src/runner.rs index 6ae61c74..eb59992c 100644 --- a/crates/prometeu-runtime-desktop/src/runner.rs +++ b/crates/prometeu-runtime-desktop/src/runner.rs @@ -64,6 +64,8 @@ pub struct HostRunner { /// The physical audio driver. audio: HostAudio, + /// Last known pause state to sync with audio. + last_paused_state: bool, } impl HostRunner { @@ -99,6 +101,7 @@ impl HostRunner { debugger: HostDebugger::new(), overlay_enabled: false, audio: HostAudio::new(), + last_paused_state: false, } } @@ -124,21 +127,31 @@ impl HostRunner { let color_bg = prometeu_core::model::Color::INDIGO; // Dark blue to stand out let color_warn = prometeu_core::model::Color::RED; - self.hardware.gfx.fill_rect(5, 5, 140, 65, color_bg); + self.hardware.gfx.fill_rect(5, 5, 140, 100, color_bg); self.hardware.gfx.draw_text(10, 10, &format!("FPS: {:.1}", self.stats.current_fps), color_text); self.hardware.gfx.draw_text(10, 18, &format!("HOST: {:.2}MS", tel.host_cpu_time_us as f64 / 1000.0), color_text); self.hardware.gfx.draw_text(10, 26, &format!("STEPS: {}", tel.vm_steps), color_text); self.hardware.gfx.draw_text(10, 34, &format!("SYSC: {}", tel.syscalls), color_text); self.hardware.gfx.draw_text(10, 42, &format!("CYC: {}", tel.cycles_used), color_text); + self.hardware.gfx.draw_text(10, 50, &format!("GFX: {}K/16M ({}S)", tel.gfx_used_bytes / 1024, tel.gfx_slots_occupied), color_text); + if tel.gfx_inflight_bytes > 0 { + self.hardware.gfx.draw_text(10, 58, &format!("LOAD GFX: {}KB", tel.gfx_inflight_bytes / 1024), color_warn); + } + + self.hardware.gfx.draw_text(10, 66, &format!("AUD: {}K/32M ({}S)", tel.audio_used_bytes / 1024, tel.audio_slots_occupied), color_text); + if tel.audio_inflight_bytes > 0 { + self.hardware.gfx.draw_text(10, 74, &format!("LOAD AUD: {}KB", tel.audio_inflight_bytes / 1024), color_warn); + } + let cert_color = if tel.violations > 0 { color_warn } else { color_text }; - self.hardware.gfx.draw_text(10, 50, &format!("CERT LAST: {}", tel.violations), cert_color); + self.hardware.gfx.draw_text(10, 82, &format!("CERT LAST: {}", tel.violations), cert_color); if tel.violations > 0 { if let Some(event) = self.firmware.os.log_service.get_recent(10).into_iter().rev().find(|e| e.tag >= 0xCA01 && e.tag <= 0xCA03) { let mut msg = event.msg.clone(); if msg.len() > 30 { msg.truncate(30); } - self.hardware.gfx.draw_text(10, 58, &msg, color_warn); + self.hardware.gfx.draw_text(10, 90, &msg, color_warn); } } } @@ -266,7 +279,21 @@ impl ApplicationHandler for HostRunner { while self.accumulator >= self.frame_target_dt { // Unless the debugger is waiting for a 'start' command, advance the system. if !self.debugger.waiting_for_start { - self.firmware.step_frame(&self.input.signals, &mut self.hardware); + self.firmware.tick(&self.input.signals, &mut self.hardware); + } + + // Sync pause state with audio. + // We do this AFTER firmware.tick to avoid MasterPause/Resume commands + // being cleared by the OS if a new logical frame starts in this tick. + let is_paused = self.firmware.os.paused || self.debugger.waiting_for_start; + if is_paused != self.last_paused_state { + self.last_paused_state = is_paused; + let cmd = if is_paused { + prometeu_core::hardware::AudioCommand::MasterPause + } else { + prometeu_core::hardware::AudioCommand::MasterResume + }; + self.hardware.audio.commands.push(cmd); } // Sync virtual audio commands to the physical mixer. diff --git a/crates/prometeu-runtime-desktop/src/stats.rs b/crates/prometeu-runtime-desktop/src/stats.rs index 4bfbffef..b4350b91 100644 --- a/crates/prometeu-runtime-desktop/src/stats.rs +++ b/crates/prometeu-runtime-desktop/src/stats.rs @@ -1,7 +1,7 @@ +use prometeu_core::firmware::Firmware; +use prometeu_core::Hardware; use std::time::{Duration, Instant}; use winit::window::Window; -use prometeu_core::Hardware; -use prometeu_core::firmware::Firmware; pub struct HostStats { pub last_stats_update: Instant, @@ -31,14 +31,12 @@ impl HostStats { self.audio_load_samples += 1; } - pub fn update(&mut self, now: Instant, window: Option<&Window>, hardware: &Hardware, firmware: &Firmware) { + pub fn update(&mut self, now: Instant, window: Option<&Window>, _hardware: &Hardware, firmware: &Firmware) { let stats_elapsed = now.duration_since(self.last_stats_update); if stats_elapsed >= Duration::from_secs(1) { self.current_fps = self.frames_since_last_update as f64 / stats_elapsed.as_secs_f64(); if let Some(window) = window { - let kb = hardware.gfx.memory_usage_bytes() as f64 / 1024.0; - // Fixed comparison always against 60Hz, keep even when doing CPU stress tests let frame_budget_us = 16666.0; let cpu_load_core = (firmware.os.last_frame_cpu_time_us as f64 / frame_budget_us) * 100.0; @@ -51,7 +49,7 @@ impl HostStats { let title = format!( "PROMETEU | GFX: {:.1} KB | FPS: {:.1} | Load: {:.1}% (C) + {:.1}% (A) | Frame: tick {} logical {}", - kb, self.current_fps, cpu_load_core, cpu_load_audio, firmware.os.tick_index, firmware.os.logical_frame_index + 0, self.current_fps, cpu_load_core, cpu_load_audio, firmware.os.tick_index, firmware.os.logical_frame_index ); window.set_title(&title); } diff --git a/devtools/debugger-protocol/protocol.json b/devtools/debugger-protocol/protocol.json index f22366c1..af022f0b 100644 --- a/devtools/debugger-protocol/protocol.json +++ b/devtools/debugger-protocol/protocol.json @@ -51,7 +51,11 @@ }, { "event": "telemetry", - "fields": ["frame_index", "vm_steps", "syscalls", "cycles"] + "fields": [ + "frame_index", "vm_steps", "syscalls", "cycles", "host_cpu_time_us", "violations", + "gfx_used_bytes", "gfx_inflight_bytes", "gfx_slots_occupied", + "audio_used_bytes", "audio_inflight_bytes", "audio_slots_occupied" + ] }, { "event": "cert", diff --git a/devtools/typescript-sdk/types/index.d.ts b/devtools/typescript-sdk/types/index.d.ts index 7b1faa46..0503ff31 100644 --- a/devtools/typescript-sdk/types/index.d.ts +++ b/devtools/typescript-sdk/types/index.d.ts @@ -33,12 +33,15 @@ declare global { } interface Gfx { + clear(color: Color565): void; + fillRect(x: number, y: number, w: number, h: number, color: Color565): void; drawLine(x1: number, y1: number, x2: number, y2: number, color: Color565): void; drawCircle(x: number, y: number, r: number, color: Color565): void; drawDisc(x: number, y: number, r: number, borderColor: Color565, fillColor: Color565): void; drawSquare(x: number, y: number, w: number, h: number, borderColor: Color565, fillColor: Color565): void; - clear(color: Color565): void; + + setSprite(assetName: string, id: number, x: number, y: number, tileId: number, paletteId: number, active: boolean, flipX: boolean, flipY: boolean, priority: number): void; } interface Color { @@ -64,6 +67,7 @@ declare global { interface Audio { playSample(sampleId: number, voiceId: number, volume: number, pan: number, pitch: number): void; + play(assetName: string, sampleId: number, voiceId: number, volume: number, pan: number, pitch: number, loopMode: number): void; } interface Fs { diff --git a/docs/specs/topics/chapter-14.md b/docs/specs/topics/chapter-14.md index 7515929d..0d0634d8 100644 --- a/docs/specs/topics/chapter-14.md +++ b/docs/specs/topics/chapter-14.md @@ -1,4 +1,4 @@ -< [Back](chapter-13.md) | [Summary](table-of-contents.md) > +< [Back](chapter-13.md) | [Summary](table-of-contents.md) | [Next](chapter-15.md) > # Boot Profiles @@ -132,4 +132,4 @@ When `debug == true`: * New boot modes must be compatible extensions -< [Back](chapter-13.md) | [Summary](table-of-contents.md) > +< [Back](chapter-13.md) | [Summary](table-of-contents.md) | [Next](chapter-15.md) > diff --git a/docs/specs/topics/chapter-15.md b/docs/specs/topics/chapter-15.md new file mode 100644 index 00000000..5f41fc3b --- /dev/null +++ b/docs/specs/topics/chapter-15.md @@ -0,0 +1,331 @@ +< [Back](chapter-14.md) | [Summary](table-of-contents.md) > + +# Asset Management + +## Bank-Centric Hardware Asset Model + +**Scope:** Runtime / Hardware Asset Management (SDK-agnostic) + +--- + +## 1. Fundamental Principles + +1. **Every asset in Prometeu resides in a Bank** +2. **A Bank is a hardware memory management system** +3. **Assets are cold binaries stored in the cartridge** +4. **Asset memory belongs to the console, not to the VM** +5. **Loading, residency, and eviction are explicit** +6. **Hardware does not interpret gameplay semantics** +7. **The SDK orchestrates policies; hardware executes contracts** + +> In Prometeu, you do not load “data”. You load **residency**. + +--- + +## 2. Asset Origin (Cold Storage) + +* All assets initially reside in **cold storage** inside the cartridge. +* Typically, each asset corresponds to a binary file. +* The runtime **never scans the cartridge directly**. +* All access goes through the **Asset Table**. + +--- + +## 3. Asset Table + +The Asset Table is an index loaded at cartridge boot. + +It describes **content**, not residency. + +### Location + +* The Asset Table **must be embedded as JSON inside `manifest.json`**. +* Tooling may compile this JSON into a binary table for runtime use, but the source of truth is the manifest. + +### Required Fields (conceptual) + +* `asset_id` (integer, internal identifier) +* `asset_name` (string, user-facing identifier) +* `asset_type` (TILEBANK, SOUNDBANK, BLOB, TILEMAP, ...) +* `bank_kind` (mandatory, single) +* `offset` (byte offset in cartridge) +* `size` (cold size) +* `decoded_size` (resident size) +* `codec` (RAW, LZ4, ZSTD, ...) +* `asset_metadata` (type-specific) + +> `bank_kind` defines **where** an asset may reside in hardware. + +--- + +## 4. Bank — Definition + +> **A Bank is the residency and swapping mechanism of the Prometeu hardware.** + +A Bank: + +* owns **numbered slots** +* enforces **resident memory budgets** +* enforces **staging / inflight budgets** +* accepts only compatible assets +* supports **atomic swap via commit** +* exposes memory and residency metrics + +Banks are hardware infrastructure, not assets. + +--- + +## 5. BankKind + +Each Bank belongs to a **BankKind**, defining its pipeline and constraints. + +### Example BankKinds + +* `GFX_TILEBANK` +* `AUDIO_SOUNDBANK` +* `DATA_BLOBBANK` +* `MAP_TILEMAPBANK` + +Each BankKind defines: + +* slot count +* maximum resident memory +* inflight / staging memory budget +* decode and validation pipeline +* hardware consumer subsystem (renderer, audio mixer, etc.) + +--- + +## 6. Slots and Slot References + +* Each BankKind owns a fixed set of **slots**. +* A slot: + + * references a resident asset (or is empty) + * never stores data directly + * may expose a **generation counter** (debug) + +### Slot Reference + +Slots are always referenced with explicit BankKind context: + +* `gfxSlot(3)` +* `audioSlot(1)` +* `blobSlot(7)` + +This prevents cross-bank ambiguity. + +--- + +## 7. Bank Memory Model + +* Bank memory is **console-owned memory**. +* It does not belong to the VM heap. +* It does not participate in GC. +* It can be fully released when the cartridge shuts down. + +Each Bank manages: + +* total memory +* used memory +* free memory +* inflight (staging) memory + +Conceptually, each Bank is a **specialized allocator**. + +--- + +## 8. Unified Loader + +### Conceptual API + +```text +handle = asset.load(asset_name, slotRef, flags) +``` + +Load flow: + +1. Resolve `asset_name` via Asset Table to get its `asset_id` +2. Read `bank_kind` from asset entry +3. Validate compatibility with `slotRef` +4. Enqueue load request +5. Perform IO + decode on worker +6. Produce materialized asset in staging + +### Handle States + +* `PENDING` — enqueued +* `LOADING` — IO/decode in progress +* `READY` — staging completed +* `COMMITTED` — installed into slot +* `CANCELED` +* `ERROR` + +--- + +## 9. Commit + +```text +asset.commit(handle) +``` + +* Commit is **explicit** and **atomic** +* Executed at a safe frame boundary +* Performs **pointer swap** in the target slot +* Previous asset is released if no longer referenced + +The hardware **never swaps slots automatically**. + +--- + +## 10. Asset Deduplication + +* A decoded asset exists **at most once per BankKind**. +* Multiple slots may reference the same resident asset. +* Redundant loads become **install-only** operations. + +Memory duplication is forbidden by contract. + +--- + +## 11. Bank Specializations + +### 11.1 GFX_TILEBANK + +* AssetType: TILEBANK +* Immutable graphical tile + palette structure +* Consumed by the graphics subsystem + +### 11.2 AUDIO_SOUNDBANK + +* AssetType: SOUNDBANK +* Resident audio samples or streams +* Consumed by the audio mixer + +### 11.3 DATA_BLOBBANK + +* AssetType: BLOB +* Read-only byte buffers +* Hardware does not interpret contents + +Used by the SDK via: + +* **Views** (zero-copy, read-only) +* **Decode** (materialization into VM heap) + +--- + +## 12. Views and Decode (SDK Contract) + +* **View** + + * read-only + * zero-copy + * valid only while the blob remains resident + +* **Decode** + + * allocates VM-owned entities + * independent from the Bank after creation + +Hardware is unaware of Views and Decode semantics. + +--- + +## 13. Manifest and Initial Load + +* The cartridge may include a `manifest.json`. +* The manifest may declare: + + * assets to preload + * target slot references + +These loads occur **before the first frame**. + +--- + +## 14. Shutdown and Eviction + +* On cartridge shutdown: + + * all Banks are cleared + * all resident memory is released + +No implicit persistence exists. + +--- + +## 15. Debugger and Telemetry + +Each Bank must expose: + +* total memory +* used memory +* free memory +* inflight memory +* occupied slots +* `asset_id` per slot +* `asset_name` per slot +* generation per slot + +This enables debuggers to visualize: + +* memory stacks per Bank +* memory pressure +* streaming strategies + +--- + +## 16. Minimal Syscall API (Derived) + +The following syscalls form the minimal hardware contract for asset management: + +```text +asset.load(asset_name, slotRef, flags) -> handle +asset.status(handle) -> LoadStatus +asset.commit(handle) +asset.cancel(handle) + +bank.info(bank_kind) -> BankStats +bank.slot_info(slotRef) -> SlotStats +``` + +Where: + +* `LoadStatus` ∈ { PENDING, LOADING, READY, COMMITTED, CANCELED, ERROR } +* `BankStats` exposes memory usage and limits +* `SlotStats` exposes current asset_id, asset_name and generation + +--- + +## 17. Separation of Responsibilities + +### Hardware (Prometeu) + +* manages memory +* loads bytes +* decodes assets +* swaps pointers +* reports usage + +### SDK + +* defines packs, scenes, and policies +* interprets blobs +* creates VM entities + +### VM + +* executes logic +* manages its own heap +* never owns hardware assets + +--- + +## 18. Golden Rule + +> **Banks are the foundation of the hardware.** +> **Asset Types describe content.** +> **The SDK orchestrates; the hardware executes.** + +< [Back](chapter-14.md) | [Summary](table-of-contents.md) > \ No newline at end of file diff --git a/docs/specs/topics/table-of-contents.md b/docs/specs/topics/table-of-contents.md index e53c0abd..fdf147ba 100644 --- a/docs/specs/topics/table-of-contents.md +++ b/docs/specs/topics/table-of-contents.md @@ -14,6 +14,7 @@ - [Chapter 12: Firmware — PrometeuOS (POS) + PrometeuHub](chapter-12.md) - [Chapter 13: Cartridge](chapter-13.md) - [Chapter 14: Boot Profiles](chapter-14.md) +- [Chapter 15: Asset Management](chapter-15.md) --- [Back to README](../README.md) \ No newline at end of file diff --git a/symbols.json b/symbols.json deleted file mode 100644 index 506ddeff..00000000 --- a/symbols.json +++ /dev/null @@ -1,80 +0,0 @@ -[ - { - "pc": 20, - "file": "temp_test_2.ts", - "line": 1, - "col": 1 - }, - { - "pc": 22, - "file": "temp_test_2.ts", - "line": 2, - "col": 13 - }, - { - "pc": 28, - "file": "temp_test_2.ts", - "line": 2, - "col": 17 - }, - { - "pc": 34, - "file": "temp_test_2.ts", - "line": 2, - "col": 13 - }, - { - "pc": 46, - "file": "temp_test_2.ts", - "line": 5, - "col": 8 - }, - { - "pc": 48, - "file": "temp_test_2.ts", - "line": 6, - "col": 10 - }, - { - "pc": 54, - "file": "temp_test_2.ts", - "line": 6, - "col": 14 - }, - { - "pc": 60, - "file": "temp_test_2.ts", - "line": 6, - "col": 5 - }, - { - "pc": 70, - "file": "temp_test_2.ts", - "line": 6, - "col": 5 - }, - { - "pc": 72, - "file": "temp_test_2.ts", - "line": 7, - "col": 15 - }, - { - "pc": 78, - "file": "temp_test_2.ts", - "line": 7, - "col": 18 - }, - { - "pc": 84, - "file": "temp_test_2.ts", - "line": 7, - "col": 5 - }, - { - "pc": 90, - "file": "temp_test_2.ts", - "line": 7, - "col": 5 - } -] \ No newline at end of file diff --git a/temp_test_2.disasm.txt b/temp_test_2.disasm.txt deleted file mode 100644 index 5ccabf26..00000000 --- a/temp_test_2.disasm.txt +++ /dev/null @@ -1,23 +0,0 @@ -00000000 Call U32(46) U32(0) -0000000A Pop -0000000C FrameSync -0000000E Jmp U32(0) -00000014 PushScope ; temp_test_2.ts:1 -00000016 GetLocal U32(0) ; temp_test_2.ts:2 -0000001C GetLocal U32(1) ; temp_test_2.ts:2 -00000022 Add ; temp_test_2.ts:2 -00000024 PopScope -00000026 PushConst U32(0) -0000002C Ret -0000002E PushScope ; temp_test_2.ts:5 -00000030 PushI32 U32(10) ; temp_test_2.ts:6 -00000036 PushI32 U32(20) ; temp_test_2.ts:6 -0000003C Call U32(20) U32(2) ; temp_test_2.ts:6 -00000046 Pop ; temp_test_2.ts:6 -00000048 PushI32 U32(1) ; temp_test_2.ts:7 -0000004E PushConst U32(1) ; temp_test_2.ts:7 -00000054 Syscall U32(20481) ; temp_test_2.ts:7 -0000005A Pop ; temp_test_2.ts:7 -0000005C PopScope -0000005E PushConst U32(0) -00000064 Ret diff --git a/test-cartridges/color-square/build/program.disasm.txt b/test-cartridges/color-square/build/program.disasm.txt index ec0dcac5..ebf2b6da 100644 --- a/test-cartridges/color-square/build/program.disasm.txt +++ b/test-cartridges/color-square/build/program.disasm.txt @@ -3,156 +3,170 @@ 0000000C FrameSync 0000000E Jmp U32(0) 00000014 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:5 -00000016 Call U32(428) U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:6 +00000016 Call U32(92) U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:6 00000020 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:6 -00000022 Call U32(236) U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:7 +00000022 Call U32(564) U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:7 0000002C Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:7 -0000002E Call U32(362) U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:8 +0000002E Call U32(702) U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:8 00000038 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:8 -0000003A Call U32(92) U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:9 +0000003A Call U32(420) U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:9 00000044 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:9 -00000046 Call U32(644) U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:10 +00000046 Call U32(308) U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:10 00000050 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/main.ts:10 00000052 PopScope 00000054 PushConst U32(0) 0000005A Ret -0000005C PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:1 -0000005E PushConst U32(1) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:2 -00000064 Syscall U32(16385) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:2 -0000006A GetLocal U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 -00000070 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 -00000076 Gte ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 -00000078 JmpIfFalse U32(226) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 -0000007E PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 -00000080 GetLocal U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:4 -00000086 PushConst U32(2) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:4 -0000008C Syscall U32(16387) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:4 -00000092 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:4 -00000094 GetLocal U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:5 -0000009A Syscall U32(16386) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:5 -000000A0 GetLocal U32(1) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 -000000A6 JmpIfFalse U32(204) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 -000000AC PushI32 U32(2) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 -000000B2 PushI32 U32(101) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 -000000B8 GetLocal U32(1) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 -000000BE Syscall U32(20482) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 -000000C4 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 -000000C6 Jmp U32(204) -000000CC GetLocal U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:7 -000000D2 Syscall U32(16388) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:7 -000000D8 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:7 -000000DA PopScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 -000000DC Jmp U32(226) -000000E2 PopScope -000000E4 PushConst U32(0) -000000EA Ret -000000EC PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:1 -000000EE PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:2 -000000F4 Syscall U32(8193) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:2 -000000FA JmpIfFalse U32(286) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:2 -00000100 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:2 -00000102 PushI32 U32(2) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:3 -00000108 PushConst U32(3) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:3 -0000010E Syscall U32(20481) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:3 -00000114 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:3 -00000116 PopScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:2 -00000118 Jmp U32(286) -0000011E PushI32 U32(4) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:6 -00000124 Syscall U32(8194) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:6 -0000012A JmpIfFalse U32(352) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:6 -00000130 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:6 -00000132 PushI32 U32(1) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 -00000138 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 -0000013E PushI32 U32(255) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 -00000144 PushI32 U32(128) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 -0000014A PushI32 U32(1) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 -00000150 Syscall U32(12289) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 -00000156 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 -00000158 PopScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:6 -0000015A Jmp U32(352) -00000160 PopScope -00000162 PushConst U32(0) -00000168 Ret -0000016A PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:11 -0000016C Syscall U32(8451) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 -00000172 JmpIfFalse U32(418) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 -00000178 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 -0000017A Syscall U32(8449) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:13 -00000180 Syscall U32(8450) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:13 -00000186 PushI32 U32(5) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:13 -0000018C PushI32 U32(65535) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:13 -00000192 Syscall U32(4100) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:13 -00000198 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:13 -0000019A PopScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 -0000019C Jmp U32(418) -000001A2 PopScope -000001A4 PushConst U32(0) -000001AA Ret -000001AC PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:1 -000001AE PushI32 U32(18448) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:2 -000001B4 Syscall U32(4097) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:2 -000001BA Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:2 -000001BC PushI32 U32(10) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 -000001C2 PushI32 U32(10) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 -000001C8 PushI32 U32(50) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 -000001CE PushI32 U32(50) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 -000001D4 PushI32 U32(63488) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 -000001DA Syscall U32(4098) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 -000001E0 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 -000001E2 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 -000001E8 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 -000001EE PushI32 U32(128) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 -000001F4 PushI32 U32(128) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 -000001FA PushI32 U32(65535) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 -00000200 Syscall U32(4099) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 -00000206 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 -00000208 PushI32 U32(64) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 -0000020E PushI32 U32(64) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 -00000214 PushI32 U32(20) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 -0000021A PushI32 U32(31) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 -00000220 Syscall U32(4100) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 -00000226 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 -00000228 PushI32 U32(100) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 -0000022E PushI32 U32(100) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 -00000234 PushI32 U32(10) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 -0000023A PushI32 U32(2016) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 -00000240 PushI32 U32(65504) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 -00000246 Syscall U32(4101) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 -0000024C Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 -0000024E PushI32 U32(20) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 -00000254 PushI32 U32(100) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 -0000025A PushI32 U32(30) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 -00000260 PushI32 U32(30) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 -00000266 PushI32 U32(2047) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 -0000026C PushI32 U32(63519) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 -00000272 Syscall U32(4102) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 -00000278 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 -0000027A PopScope -0000027C PushConst U32(0) -00000282 Ret -00000284 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:10 -00000286 PushI32 U32(255) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -0000028C PushI32 U32(3) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -00000292 Shr ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -00000294 PushI32 U32(11) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -0000029A Shl ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -0000029C PushI32 U32(128) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -000002A2 PushI32 U32(2) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -000002A8 Shr ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -000002AA PushI32 U32(5) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -000002B0 Shl ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -000002B2 BitOr ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -000002B4 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -000002BA PushI32 U32(3) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -000002C0 Shr ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -000002C2 BitOr ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 -000002C4 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 -000002CA PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 -000002D0 PushI32 U32(5) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 -000002D6 PushI32 U32(5) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 -000002DC GetLocal U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 -000002E2 Syscall U32(4098) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 -000002E8 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 -000002EA PopScope -000002EC PushConst U32(0) -000002F2 Ret +0000005C PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:1 +0000005E PushI32 U32(18448) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:2 +00000064 Syscall U32(4097) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:2 +0000006A Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:2 +0000006C PushI32 U32(10) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 +00000072 PushI32 U32(10) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 +00000078 PushI32 U32(50) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 +0000007E PushI32 U32(50) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 +00000084 PushI32 U32(63488) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 +0000008A Syscall U32(4098) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 +00000090 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:3 +00000092 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 +00000098 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 +0000009E PushI32 U32(128) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 +000000A4 PushI32 U32(128) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 +000000AA PushI32 U32(65535) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 +000000B0 Syscall U32(4099) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 +000000B6 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:4 +000000B8 PushI32 U32(64) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 +000000BE PushI32 U32(64) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 +000000C4 PushI32 U32(20) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 +000000CA PushI32 U32(31) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 +000000D0 Syscall U32(4100) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 +000000D6 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:5 +000000D8 PushI32 U32(100) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 +000000DE PushI32 U32(100) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 +000000E4 PushI32 U32(10) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 +000000EA PushI32 U32(2016) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 +000000F0 PushI32 U32(65504) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 +000000F6 Syscall U32(4101) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 +000000FC Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:6 +000000FE PushI32 U32(20) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 +00000104 PushI32 U32(100) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 +0000010A PushI32 U32(30) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 +00000110 PushI32 U32(30) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 +00000116 PushI32 U32(2047) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 +0000011C PushI32 U32(63519) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 +00000122 Syscall U32(4102) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 +00000128 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:7 +0000012A PopScope +0000012C PushConst U32(0) +00000132 Ret +00000134 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:10 +00000136 PushI32 U32(255) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +0000013C PushI32 U32(3) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +00000142 Shr ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +00000144 PushI32 U32(11) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +0000014A Shl ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +0000014C PushI32 U32(128) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +00000152 PushI32 U32(2) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +00000158 Shr ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +0000015A PushI32 U32(5) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +00000160 Shl ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +00000162 BitOr ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +00000164 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +0000016A PushI32 U32(3) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +00000170 Shr ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +00000172 BitOr ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:11 +00000174 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 +0000017A PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 +00000180 PushI32 U32(5) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 +00000186 PushI32 U32(5) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 +0000018C GetLocal U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 +00000192 Syscall U32(4098) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 +00000198 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts:12 +0000019A PopScope +0000019C PushConst U32(0) +000001A2 Ret +000001A4 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:1 +000001A6 PushConst U32(1) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:2 +000001AC Syscall U32(16385) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:2 +000001B2 GetLocal U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 +000001B8 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 +000001BE Gte ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 +000001C0 JmpIfFalse U32(554) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 +000001C6 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 +000001C8 GetLocal U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:4 +000001CE PushConst U32(2) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:4 +000001D4 Syscall U32(16387) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:4 +000001DA Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:4 +000001DC GetLocal U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:5 +000001E2 Syscall U32(16386) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:5 +000001E8 GetLocal U32(1) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 +000001EE JmpIfFalse U32(532) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 +000001F4 PushI32 U32(2) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 +000001FA PushI32 U32(101) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 +00000200 GetLocal U32(1) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 +00000206 Syscall U32(20482) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 +0000020C Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:6 +0000020E Jmp U32(532) +00000214 GetLocal U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:7 +0000021A Syscall U32(16388) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:7 +00000220 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:7 +00000222 PopScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts:3 +00000224 Jmp U32(554) +0000022A PopScope +0000022C PushConst U32(0) +00000232 Ret +00000234 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:1 +00000236 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:2 +0000023C Syscall U32(8193) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:2 +00000242 JmpIfFalse U32(614) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:2 +00000248 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:2 +0000024A PushI32 U32(2) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:3 +00000250 PushConst U32(3) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:3 +00000256 Syscall U32(20481) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:3 +0000025C Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:3 +0000025E PopScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:2 +00000260 Jmp U32(614) +00000266 PushI32 U32(4) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:6 +0000026C Syscall U32(8194) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:6 +00000272 JmpIfFalse U32(692) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:6 +00000278 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:6 +0000027A PushConst U32(4) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 +00000280 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 +00000286 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 +0000028C PushI32 U32(128) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 +00000292 PushI32 U32(127) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 +00000298 PushI32 U32(1) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 +0000029E PushI32 U32(1) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 +000002A4 Syscall U32(12290) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 +000002AA Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:7 +000002AC PopScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:6 +000002AE Jmp U32(692) +000002B4 PopScope +000002B6 PushConst U32(0) +000002BC Ret +000002BE PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:11 +000002C0 PushConst U32(5) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002C6 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002CC Syscall U32(8449) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002D2 Syscall U32(8450) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002D8 PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002DE PushI32 U32(0) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002E4 PushBool Bool(true) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002E7 PushBool Bool(false) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002EA PushBool Bool(false) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002ED PushI32 U32(4) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002F3 Syscall U32(4103) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002F9 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:12 +000002FB Syscall U32(8451) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:13 +00000301 JmpIfFalse U32(817) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:13 +00000307 PushScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:13 +00000309 Syscall U32(8449) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:14 +0000030F Syscall U32(8450) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:14 +00000315 PushI32 U32(10) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:14 +0000031B PushI32 U32(65535) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:14 +00000321 Syscall U32(4100) ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:14 +00000327 Pop ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:14 +00000329 PopScope ; /Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts:13 +0000032B Jmp U32(817) +00000331 PopScope +00000333 PushConst U32(0) +00000339 Ret diff --git a/test-cartridges/color-square/build/program.pbc b/test-cartridges/color-square/build/program.pbc index c53077c1eebc1079a37d11097ac0f74bea19125b..d6da482e14daee99f4af285d095893ca57cde8bd 100644 GIT binary patch delta 383 zcmdnUHl3X{Ai&9)Z6d3QA`2%214B}JZhUTOab_|L50ICeUs{|RpIlm0oL^+kJkeUp zG6pCL0)h+y3?@tn_C6%`5=Ml$35>n@9%C@$#F=tTT1*pn>M)5gO?)mVAp+Fp1Xf(Y zz~TThHJE{kL5pd!ETarl8q;KJMw$9Fpc-)o7NDvE1||gt24;pWK#?E@0kD`jST~Gp z0P@5c>cJ$)VsQo#3Djo*GaIBg7^oKn0>P%R0$C9K1q_UeVAVhpW+ForP+E+EQ4B-^ qMIr8B2O1y#{yOj@)<}a!gc_JEi3x~ delta 315 zcmYk1p%Q{X5QhI-Kr5!3F)-K(2FL7RcTQ-G!ECxW(BKO&1iM)S@4-`$O^zLR518S? z-R`&l{(JkF*R#NwbnlnJhJI8Q%k4|Sodpa&eF%v!6MmZTJ4sS~RYEPQm=bDG9Vogs zj8iAH@ONO79E6rhj?nQVGU!2}V!%VhLxhQE$T?u4%-Abc4c}36`tzWdzx7TUor`aU qd!)b?>(N3QrsFNVl?;9|&qT?Y1@WyBIERk?cme)#zW^)icdq_vq$G|2 diff --git a/test-cartridges/color-square/build/symbols.json b/test-cartridges/color-square/build/symbols.json index d501c89f..bc9f7650 100644 --- a/test-cartridges/color-square/build/symbols.json +++ b/test-cartridges/color-square/build/symbols.json @@ -67,722 +67,806 @@ }, { "pc": 92, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 1, "col": 8 }, { "pc": 94, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 2, - "col": 21 - }, - { - "pc": 100, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 2, - "col": 13 - }, - { - "pc": 106, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 3, - "col": 9 - }, - { - "pc": 112, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 3, - "col": 14 - }, - { - "pc": 118, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 3, - "col": 9 - }, - { - "pc": 120, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 3, - "col": 5 - }, - { - "pc": 126, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 3, - "col": 17 - }, - { - "pc": 128, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 4, - "col": 18 - }, - { - "pc": 134, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 4, - "col": 21 - }, - { - "pc": 140, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 4, - "col": 9 - }, - { - "pc": 146, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 4, - "col": 9 - }, - { - "pc": 148, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 5, - "col": 31 - }, - { - "pc": 154, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 5, - "col": 23 - }, - { - "pc": 160, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 6, - "col": 13 - }, - { - "pc": 166, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 6, - "col": 9 - }, - { - "pc": 172, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 6, - "col": 35 - }, - { - "pc": 178, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 6, - "col": 38 - }, - { - "pc": 184, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 6, - "col": 43 - }, - { - "pc": 190, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 6, - "col": 22 - }, - { - "pc": 196, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 6, - "col": 22 - }, - { - "pc": 204, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 7, - "col": 18 - }, - { - "pc": 210, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 7, - "col": 9 - }, - { - "pc": 216, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 7, - "col": 9 - }, - { - "pc": 218, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", - "line": 3, - "col": 17 - }, - { - "pc": 236, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 1, - "col": 8 - }, - { - "pc": 238, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 2, - "col": 9 - }, - { - "pc": 244, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 2, - "col": 9 - }, - { - "pc": 250, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 2, - "col": 5 - }, - { - "pc": 256, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 2, - "col": 22 - }, - { - "pc": 258, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 3, - "col": 19 - }, - { - "pc": 264, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 3, - "col": 22 - }, - { - "pc": 270, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 3, - "col": 9 - }, - { - "pc": 276, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 3, - "col": 9 - }, - { - "pc": 278, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 2, - "col": 22 - }, - { - "pc": 286, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 6, - "col": 9 - }, - { - "pc": 292, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 6, - "col": 9 - }, - { - "pc": 298, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 6, - "col": 5 - }, - { - "pc": 304, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 6, - "col": 24 - }, - { - "pc": 306, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 7, - "col": 26 - }, - { - "pc": 312, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 7, - "col": 29 - }, - { - "pc": 318, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 7, - "col": 32 - }, - { - "pc": 324, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 7, - "col": 37 - }, - { - "pc": 330, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 7, - "col": 42 - }, - { - "pc": 336, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 7, - "col": 9 - }, - { - "pc": 342, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 7, - "col": 9 - }, - { - "pc": 344, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 6, - "col": 24 - }, - { - "pc": 362, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 11, - "col": 8 - }, - { - "pc": 364, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 12, - "col": 9 - }, - { - "pc": 370, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 12, - "col": 5 - }, - { - "pc": 376, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 12, - "col": 28 - }, - { - "pc": 378, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 13, - "col": 24 - }, - { - "pc": 384, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 13, - "col": 33 - }, - { - "pc": 390, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 13, - "col": 42 - }, - { - "pc": 396, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 13, - "col": 45 - }, - { - "pc": 402, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 13, - "col": 9 - }, - { - "pc": 408, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 13, - "col": 9 - }, - { - "pc": 410, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", - "line": 12, - "col": 28 - }, - { - "pc": 428, - "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", - "line": 1, - "col": 8 - }, - { - "pc": 430, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 2, "col": 15 }, { - "pc": 436, + "pc": 100, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 2, "col": 5 }, { - "pc": 442, + "pc": 106, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 2, "col": 5 }, { - "pc": 444, + "pc": 108, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 3, "col": 18 }, { - "pc": 450, + "pc": 114, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 3, "col": 22 }, { - "pc": 456, + "pc": 120, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 3, "col": 26 }, { - "pc": 462, + "pc": 126, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 3, "col": 30 }, { - "pc": 468, + "pc": 132, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 3, "col": 34 }, { - "pc": 474, + "pc": 138, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 3, "col": 5 }, { - "pc": 480, + "pc": 144, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 3, "col": 5 }, { - "pc": 482, + "pc": 146, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 4, "col": 18 }, { - "pc": 488, + "pc": 152, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 4, "col": 21 }, { - "pc": 494, + "pc": 158, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 4, "col": 24 }, { - "pc": 500, + "pc": 164, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 4, "col": 29 }, { - "pc": 506, + "pc": 170, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 4, "col": 34 }, { - "pc": 512, + "pc": 176, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 4, "col": 5 }, { - "pc": 518, + "pc": 182, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 4, "col": 5 }, { - "pc": 520, + "pc": 184, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 5, "col": 20 }, { - "pc": 526, + "pc": 190, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 5, "col": 24 }, { - "pc": 532, + "pc": 196, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 5, "col": 28 }, { - "pc": 538, + "pc": 202, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 5, "col": 32 }, { - "pc": 544, + "pc": 208, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 5, "col": 5 }, { - "pc": 550, + "pc": 214, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 5, "col": 5 }, { - "pc": 552, + "pc": 216, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 6, "col": 18 }, { - "pc": 558, + "pc": 222, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 6, "col": 23 }, { - "pc": 564, + "pc": 228, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 6, "col": 28 }, { - "pc": 570, + "pc": 234, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 6, "col": 32 }, { - "pc": 576, + "pc": 240, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 6, "col": 45 }, { - "pc": 582, + "pc": 246, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 6, "col": 5 }, { - "pc": 588, + "pc": 252, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 6, "col": 5 }, { - "pc": 590, + "pc": 254, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 7, "col": 20 }, { - "pc": 596, + "pc": 260, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 7, "col": 24 }, { - "pc": 602, + "pc": 266, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 7, "col": 29 }, { - "pc": 608, + "pc": 272, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 7, "col": 33 }, { - "pc": 614, + "pc": 278, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 7, "col": 37 }, { - "pc": 620, + "pc": 284, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 7, "col": 49 }, { - "pc": 626, + "pc": 290, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 7, "col": 5 }, { - "pc": 632, + "pc": 296, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 7, "col": 5 }, { - "pc": 644, + "pc": 308, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 10, "col": 8 }, { - "pc": 646, + "pc": 310, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 23 }, { - "pc": 652, + "pc": 316, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 658, + "pc": 322, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 660, + "pc": 324, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 666, + "pc": 330, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 668, + "pc": 332, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 28 }, { - "pc": 674, + "pc": 338, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 680, + "pc": 344, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 682, + "pc": 346, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 688, + "pc": 352, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 690, + "pc": 354, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 692, + "pc": 356, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 33 }, { - "pc": 698, + "pc": 362, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 704, + "pc": 368, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 706, + "pc": 370, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 11, "col": 13 }, { - "pc": 708, + "pc": 372, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 12, "col": 18 }, { - "pc": 714, + "pc": 378, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 12, "col": 21 }, { - "pc": 720, + "pc": 384, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 12, "col": 24 }, { - "pc": 726, + "pc": 390, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 12, "col": 27 }, { - "pc": 732, + "pc": 396, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 12, "col": 30 }, { - "pc": 738, + "pc": 402, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 12, "col": 5 }, { - "pc": 744, + "pc": 408, "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_gfx.ts", "line": 12, "col": 5 + }, + { + "pc": 420, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 1, + "col": 8 + }, + { + "pc": 422, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 2, + "col": 21 + }, + { + "pc": 428, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 2, + "col": 13 + }, + { + "pc": 434, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 3, + "col": 9 + }, + { + "pc": 440, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 3, + "col": 14 + }, + { + "pc": 446, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 3, + "col": 9 + }, + { + "pc": 448, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 3, + "col": 5 + }, + { + "pc": 454, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 3, + "col": 17 + }, + { + "pc": 456, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 4, + "col": 18 + }, + { + "pc": 462, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 4, + "col": 21 + }, + { + "pc": 468, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 4, + "col": 9 + }, + { + "pc": 474, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 4, + "col": 9 + }, + { + "pc": 476, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 5, + "col": 31 + }, + { + "pc": 482, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 5, + "col": 23 + }, + { + "pc": 488, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 6, + "col": 13 + }, + { + "pc": 494, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 6, + "col": 9 + }, + { + "pc": 500, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 6, + "col": 35 + }, + { + "pc": 506, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 6, + "col": 38 + }, + { + "pc": 512, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 6, + "col": 43 + }, + { + "pc": 518, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 6, + "col": 22 + }, + { + "pc": 524, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 6, + "col": 22 + }, + { + "pc": 532, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 7, + "col": 18 + }, + { + "pc": 538, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 7, + "col": 9 + }, + { + "pc": 544, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 7, + "col": 9 + }, + { + "pc": 546, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_fs.ts", + "line": 3, + "col": 17 + }, + { + "pc": 564, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 1, + "col": 8 + }, + { + "pc": 566, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 2, + "col": 9 + }, + { + "pc": 572, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 2, + "col": 9 + }, + { + "pc": 578, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 2, + "col": 5 + }, + { + "pc": 584, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 2, + "col": 22 + }, + { + "pc": 586, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 3, + "col": 19 + }, + { + "pc": 592, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 3, + "col": 22 + }, + { + "pc": 598, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 3, + "col": 9 + }, + { + "pc": 604, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 3, + "col": 9 + }, + { + "pc": 606, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 2, + "col": 22 + }, + { + "pc": 614, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 6, + "col": 9 + }, + { + "pc": 620, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 6, + "col": 9 + }, + { + "pc": 626, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 6, + "col": 5 + }, + { + "pc": 632, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 6, + "col": 24 + }, + { + "pc": 634, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 7, + "col": 20 + }, + { + "pc": 640, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 7, + "col": 33 + }, + { + "pc": 646, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 7, + "col": 36 + }, + { + "pc": 652, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 7, + "col": 39 + }, + { + "pc": 658, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 7, + "col": 44 + }, + { + "pc": 664, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 7, + "col": 49 + }, + { + "pc": 670, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 7, + "col": 54 + }, + { + "pc": 676, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 7, + "col": 9 + }, + { + "pc": 682, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 7, + "col": 9 + }, + { + "pc": 684, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 6, + "col": 24 + }, + { + "pc": 702, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 11, + "col": 8 + }, + { + "pc": 704, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 19 + }, + { + "pc": 710, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 35 + }, + { + "pc": 716, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 38 + }, + { + "pc": 722, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 47 + }, + { + "pc": 728, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 56 + }, + { + "pc": 734, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 59 + }, + { + "pc": 740, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 62 + }, + { + "pc": 743, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 68 + }, + { + "pc": 746, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 75 + }, + { + "pc": 749, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 82 + }, + { + "pc": 755, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 5 + }, + { + "pc": 761, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 12, + "col": 5 + }, + { + "pc": 763, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 13, + "col": 9 + }, + { + "pc": 769, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 13, + "col": 5 + }, + { + "pc": 775, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 13, + "col": 28 + }, + { + "pc": 777, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 14, + "col": 24 + }, + { + "pc": 783, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 14, + "col": 33 + }, + { + "pc": 789, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 14, + "col": 42 + }, + { + "pc": 795, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 14, + "col": 46 + }, + { + "pc": 801, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 14, + "col": 9 + }, + { + "pc": 807, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 14, + "col": 9 + }, + { + "pc": 809, + "file": "/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/runtime/test-cartridges/color-square/src/my_input.ts", + "line": 13, + "col": 28 } ] \ No newline at end of file diff --git a/test-cartridges/color-square/cartridge/assets.pa b/test-cartridges/color-square/cartridge/assets.pa new file mode 100644 index 0000000000000000000000000000000000000000..1062286afd4a4e1b15d0efd7209f6e6a021c790c GIT binary patch literal 90504 zcmeI*XLJ+Swg+%a?!EWkt0YUZtUlvVY+9T^LN}OjV_JYqF(iZ%LQN=!Yq&J$5^PKf z5D0{3TF$7;vMk$j@4feKW6MwP-Ilyh_v?FW>)Sa?UuHCCmez0Wz5fOVWFrH!G0O(q z*N#VA>7EiFZoui_7h$g>)2V#=6Xpnu%qivW2!eZ=8yc(auoA48O2WE{82{QO* zJRXM`JIXvxZ=~8q*@t%oX9Ps}Ui0jAjc{6Gx7jMyY_CzO!S1Ql@dLx>`=54qwR2mt z8X{_oD{q!%6u&F9(_F|~kjqvi$zDsAi7BGl#1%wAB;<;=A~I1*bc%Qqx%8a;oKmKu z=W7an&|WIdsW7bBQ9s>uyKQ5aurFxHZOr+->x{dhyQ#gU&ZfrUuFD#aG4I{}>L7BM zZR7wYJ35rPmvxT4lk3huE_f=ujjh0Q@oBsd&%_<^xfoa2$KTAm%Xt`kFvg8>nD#PC z9G)GL95~{;)l24P>ddrHv|eqVY`m6~G@UfDeq{H+g&t{#P3z9af!YgIE6eAVd{%T< zWx|QOYD$7fp^fiL~&vnYLFupL7rNzVBxpv@rCuhz}{2(N`J6F&=C) z?pq#Put%7RvGC{k7(R}_#JTuBY`+i}$a#+35H^W*m*E+`ma;oyO{ibcZ+-&rzqvO# zJ2^0HW?9TLNg&VF&6%7xx_oeVZ)Rt6Yh2T-x=*X^D@IF9w6h8xsS{NJN{W1^bU^$- zbepI}OOZ7)Mnd!)Z6{Jh*Th!R9NCYGce(cJtD29CVoMUr4_DRHCN)m9JnA^ulQgh! zWX{B#>3GsS<2mMRYj67jr^jx~y&8NM2BwER4!;w%gJ#ay5t9}BH%>CIjn5FqVYc{n zyjTB=o$kxWA!dIc@=j{f7aF&#N}&M8Om$&Lg{SDfT)@l8x4w zEwSR;IXP9h9`|(dJsD6MJQFq(Sw!7S?_h?;(l|Qq1%9`{3~RxT;tl!}QiFeumt&*C zQo%lcJ=dB;ibc!?^ek##q%!P!@S=bUpLowJu0@XHwl-F-X6{C=2F_Ei<9@@j{j0k# zwl_C_+)!2XUFGVsWyOaIi}RE6+;S}xF|sQXj@Vg5C(fV{{dIVuFOdV$Lzsw@B)!tt za-^J6ZOykStkc$%8dWZ?A?g=5Pqm@0%YBE3_KfX%pE|SGaF6LW%ayjVjx#P#Jm&j| z{M~~WhJ6~zpf*G&Gk;>eWnbe8_%{V=;Y%z9FT!Jup6?PF(VrrkaSZs<0d0+1H7K?9XTyNjhVIaRd(g% z65paPG;Mj8a}Ox4%K9Zo#Y;rV!~?`eM#v7WK^^EhL5R#HY0?kn@yb1_O7+eHjyAG% zenndKXx%qWL2XT)&wDcl(?(BCp4OcupEWsYvDap~L$FJY`+o2Deyf5mhTe%dN0}d8 z#0Y22XEV8tyyb#4;dj_<{5O0OAHg5t5qJvrnb22|$!q6~#;RksGiqpF6iS3ss5WrB zUx!zM`)TJ__GQ+s=3T~}r1t5yiSCi90r%edooTH-jhpLCsuktGl!%Lr3ihboRf7t$ ze37(JoG$tcp+Sp~1u{kPNP>A> zF2#KCyZ9hJg-h{7{4$m)+%A~rE#Youf5e(*d>M@>RS~Mt3qfrE9B*%rjV{+5UfJYX zXic=_LY-z(J6b%(`krZGFSOmZ*-g?&5x8IA=U(>XpG8 zqa3q`R+sFyInmrIJU9B52Ka|0gwKkyr#+_o#;k~4%?ai`mOFi8ciAe-?3U3@gUqR{@q5GX`s=%0IzDevH7u!} ztdy6%Ev_r1Y98f%o|~xHAyZ3I#9YxL;yQ}f{~k_gBbq=eqFNLoc`Dr}->bZ@a>{>H z@U?bV>BWlb>V$f2)BZMomtEi3VCQJtWV^1D+-cHeQE2mv!vPnDhuV9g|DB-P(4L3_ z%86)8W)kZwb`sZ=zgKWq_ye{Wm+POa0sJ=Zfq#s}3upKTc<(r}*efwC#*eg$sMc_0 z$niiQze`>NZcOKO_6MxLH%~J@Lpn8mYU2Dz<^bv$=-{?qYjm&6sXA1?rQ}GFTq97o zmrAYWIz@=;sM@KZxJXn|S?*DNu#Vi6 z-J0AP-Rm%DII5eNnI@6RCe!A<)&=&N&Pnb%ucLmgfgzz-L=>f)c92mSLuL|$JO!2FDxBlH* zfUn1&Vsc@IfXP44eZu~MwU}8H?N6N@$qh3Je(2Bg`N5;p#m{k;?J~=?rpbnDW>&vn zJGOb~+rFQ=TH6H8Ki6Y50~M-LjaFB%CcjVhRQZd%Mf#~^M$|^w5UI#Re?r30Im9A7 zMYuRqg2|i}LAhJ?D1I_@Hn_CtS0gabtPTRw25`&baIdIYXwunYV06hr#~U}_+h*OBV#RsQ~Y6W z5XU37in)<4qV`7igh_%^1IWHRJjJd$$6!0YRlM0eqj-ZkQ**}?hyT=nvirAo+m?L| zhP4kXzbV^Se7$fm|EoNDuAgF_?4Be+>@VUG=_p)(9qwosvLG6XanV9amGqYUuChV( zQGQ>+J8e#BT}4FA)%wup!nO-tTl$s^C5+8^A3u{|m|%)qM%kJ>7Q3AE@bkImKNJ)i z#)!11ilb*U&$Di`k8>mV7X?W82wRKi>wk|P{0H0;=V6h;TK+O#I_FaC`j|=jI@+bE z8{yxCa01o7v%E6gs+>&h{j4eGbYmKcGEJF?8Hpd*&~vq;sU@LNS-Y)@RUTXtSM*HNmw%e5uVMS%tBYNpCU=_XH>Hi&-| zWe}xkF|ySE@BIM1MPCuSL_djrq-xmNz#A zZ)Eqx?&&?Gy~exDQ>+)*dplRVed}f6w=3{PNJ+RN>KrYEaXRKz?5~_%yfHp5T!6Xa zH}QV`J4=awif3XEg$D(8{EggW?9D89=3k>5D7uLL&{sjp{*B%V9_cPJhjyDu3z8|> z&|pS4NgA^r3hi6mb-t~=DXG4%`gX;!($m`C3Ig+As*Wm;$=^vCk|t3hF^x7OXZ^dE ziZakVf+<=fmPj_pW-FHGX6E^7@(UjnKPzji#A;tOB({(`a=Y*JUl=|;eroEBL7LHN zv%^-K?c$t_+#Y%2zK;T?f&;_-qXwxL=|(Yev2!^NylnoYz!B@kzQ>#OC!`Wj#Wh%$ zP$AgF&*P4=+gaJnDEblVy~tZ(Uj+vT{Nm%~xz+WSW3FwzWrt~(VaH6{`;M`}A+vsJ z_ont&&7loXYt~n?%VLVx7Cz69%bQUS$^B#}B@to^Q5bOo1?o?TFFJ@kiE+Y7yiG!u z70N4=u6d{OsfDCsQdvahzM9VZ{mr56-CfeYheJ2VGT+~vxn-DbnqhgucD-YyYqiHN zpH6=~_|IW`BbQKTqW3dJtYY>7F_%c+fh60?}`jy4%(5z!a& zATZt!d3m`fJD;`x$@-=F8{^lcoavVn??&Sp=blB}W@%?kBQ zZl$6}#+4G{}?q+87Y`3m@Xn|jWy=TI@^AaGsC^uYn2}gB!zlLSW?uqbqo~K8C%P_!gCd@ z60XBS@SpKv{r_G9Pr%P&e-*A3bn%4TrEC_fp0OhON6O2HJE7ZxZ2ix954!VRwmF=& zxo(kdl1FgH5k_D->>}Qwf3mdr zCj2d?72XrfL+E)Rf3IVNt=Q{%d{Y9?q_d9Cz3rvpi#Z*6_^CsrP5b zE)PBIEA4V<-_TrIpHkym*;m@H^(ow+Z;_`~%H-qH6p6KXh;SvoM&9}p5`?}-QG~6C zExruqw{OyHvi|3c^sg&0U8Z^y^+UIur_L~nIjO*STfSiDwfSiDwfSiDw zfSiDwfSiDwfSiDwfSiDwfSiDwfSiDwK+Or%oak*4YEGc$1Zqy8<^*a^pymW>PN3!l zYEGc$1Zqy8<^*a^pymW>PM}){x^K;oD-OH0&`Aa&I!ypfjK8I=LF`Q zz=T+s5DODxVL~iSh=mEUFd-Hu#KMGFm=FsSVqrooOo)XEu`nSPCd9&oSjg6aY#qqf zfovVf)`4st$ku^u9mv*!Y#qqffovVf)`4st$ku^u9mv*!RANXahE!rmC5BXDNF|0; zVn`*1RANXahE!rmC5BXDNF|0;Vn`*1RN~E6sb+hPQVn)brH&sMKHvYeyQ`hslGOlm z0&)U!0&)U!0&)U!0&)U!0&)U!0&)U!0&)U!0&)U!0&-%7K0%e}260=|A>Jenkh>`3 zR5#Sj0+17s6Oa>-6Oa>-6Oa>-6Oa>-6Oa>-6Oa>-6Oa>-6Oa>-6L0$gr^jx~y&8NM z2BwER4!;w%gJ#ay5d(4pasqM!asqM!asqM!asqM!asqM!asqM!asqM!asqM!a$?OP z#UkbcdKNV=QW-6Oa>-6Oa>-6Oa>-6Oa>-6Oa>-6Oa>- z6Oa>-6LN`f(HEMwyvw-<6jx>alB41!qGaL$0yzOW0XYFV0XYFV0XYFV0XYFV0XYFV z0XYFV0XYFV0XYFVQCCsw9yKPmns%17@zrNe0-6Oa>-6Oa>-6Oa>-6Oa>-6Oa>-6Oa>-6Oa>-6OfZcq(zsAE20YVQmM6ErwCCU zRXY_F7lE9BoPeBwoPeBwoPeBwoPeBwoPeBwoPeBwoPeBwoPeBwoJgIHyHUJye1ihF zhNOj`h+0hRrZ0^-6$^3#asqM!asqM!asqM!asqM!asqM!asqM!asqM!asqM!a^ewN z#oS02QF|kM!X&||0c77Do?=&>BghHJ3CIb^3CIb^3CIb^3CIb^3CIb^3CIb^3CIb^ z3CIb^NnFwQ8bkHt+>45bGDB&)I9arrc!Kx{n@9%C@$#F=tTT1*pn>M)5gO?)mVAp+Fp1Xf(Y zz~TThHJE{kL5pd!ETarl8q;KJMw$9Fpc-)o7NDvE1||gt24;pWK#?E@0kD`jST~Gp z0P@5c>cJ$)VsQo#3Djo*GaIBg7^oKn0>P%R0$C9K1q_UeVAVhpW+ForP+E+EQ4B-^ qMIr8B2O1y#{yOj@)<}a!gc_JEi3x~ delta 315 zcmYk1p%Q{X5QhI-Kr5!3F)-K(2FL7RcTQ-G!ECxW(BKO&1iM)S@4-`$O^zLR518S? z-R`&l{(JkF*R#NwbnlnJhJI8Q%k4|Sodpa&eF%v!6MmZTJ4sS~RYEPQm=bDG9Vogs zj8iAH@ONO79E6rhj?nQVGU!2}V!%VhLxhQE$T?u4%-Abc4c}36`tzWdzx7TUor`aU qd!)b?>(N3QrsFNVl?;9|&qT?Y1@WyBIERk?cme)#zW^)icdq_vq$G|2 diff --git a/test-cartridges/color-square/run.sh b/test-cartridges/color-square/run.sh index a7713d6d..ea1ac387 100755 --- a/test-cartridges/color-square/run.sh +++ b/test-cartridges/color-square/run.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -e ./prometeu-sdk/prometeu build . cp build/program.pbc cartridge diff --git a/test-cartridges/color-square/src/main.ts b/test-cartridges/color-square/src/main.ts index 5ec0daef..f3d62af1 100644 --- a/test-cartridges/color-square/src/main.ts +++ b/test-cartridges/color-square/src/main.ts @@ -2,7 +2,7 @@ import {do_init_gfx, print_orange} from "./my_gfx"; import {do_pad, do_touch} from "./my_input"; import {do_fs} from "./my_fs"; -export function tick(): void { +export function frame(): void { do_init_gfx(); do_pad(); do_touch(); diff --git a/test-cartridges/color-square/src/my_input.ts b/test-cartridges/color-square/src/my_input.ts index 242df489..e112a159 100644 --- a/test-cartridges/color-square/src/my_input.ts +++ b/test-cartridges/color-square/src/my_input.ts @@ -4,12 +4,13 @@ export function do_pad(): void { } if (pad.a.pressed) { - audio.playSample(1, 0, 255, 128, 1.0); + audio.play("bgm_music", 0, 0, 128, 127, 1.0, 1); } } export function do_touch(): void { + gfx.setSprite("mouse_cursor", 0, touch.x, touch.y, 0, 0, true, false, false, 4); if (touch.button.down) { - gfx.drawCircle(touch.x, touch.y, 5, color.white); + gfx.drawCircle(touch.x, touch.y, 10, color.white); } } \ No newline at end of file