diff --git a/crates/console/prometeu-drivers/src/audio.rs b/crates/console/prometeu-drivers/src/audio.rs index e6c490f9..cdace8e6 100644 --- a/crates/console/prometeu-drivers/src/audio.rs +++ b/crates/console/prometeu-drivers/src/audio.rs @@ -183,10 +183,12 @@ impl Audio { } // 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)); + let bank_slot = self.sound_banks.sound_bank_slot(bank_id as usize); + if bank_slot.is_none() { + return AudioOpStatus::BankInvalid; + } + + let sample = bank_slot.and_then(|bank| bank.samples.get(sample_id as usize).map(Arc::clone)); if let Some(s) = sample { // println!( diff --git a/crates/console/prometeu-hal/src/audio_bridge.rs b/crates/console/prometeu-hal/src/audio_bridge.rs index f09febb3..9503ba18 100644 --- a/crates/console/prometeu-hal/src/audio_bridge.rs +++ b/crates/console/prometeu-hal/src/audio_bridge.rs @@ -16,6 +16,7 @@ pub enum AudioOpStatus { ArgRangeInvalid = 3, AssetNotFound = 4, NoEffect = 5, + BankInvalid = 6, } pub trait AudioBridge { diff --git a/crates/console/prometeu-hal/src/gfx_bridge.rs b/crates/console/prometeu-hal/src/gfx_bridge.rs index b1fc5ca8..528081b6 100644 --- a/crates/console/prometeu-hal/src/gfx_bridge.rs +++ b/crates/console/prometeu-hal/src/gfx_bridge.rs @@ -18,6 +18,7 @@ pub enum GfxOpStatus { AssetNotFound = 1, InvalidSpriteIndex = 2, ArgRangeInvalid = 3, + BankInvalid = 4, } pub trait GfxBridge { diff --git a/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs b/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs index 21d3203e..06546bad 100644 --- a/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs +++ b/crates/console/prometeu-system/src/virtual_machine_runtime/dispatch.rs @@ -150,6 +150,12 @@ impl NativeInterface for VirtualMachineRuntime { ret.push_int(GfxOpStatus::InvalidSpriteIndex as i64); return Ok(()); } + + if hw.assets().slot_info(SlotRef::gfx(bank_id as usize)).asset_id.is_none() { + ret.push_int(GfxOpStatus::BankInvalid as i64); + return Ok(()); + } + if palette_id >= 64 || priority >= 5 { ret.push_int(GfxOpStatus::ArgRangeInvalid as i64); return Ok(()); @@ -237,6 +243,11 @@ impl NativeInterface for VirtualMachineRuntime { return Ok(()); } + if hw.assets().slot_info(SlotRef::audio(bank_id as usize)).asset_id.is_none() { + ret.push_int(AudioOpStatus::BankInvalid as i64); + return Ok(()); + } + if sample_id_raw < 0 || sample_id_raw > u16::MAX as i64 || !(0..=255).contains(&volume_raw) diff --git a/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs b/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs index d140e4c1..298018b9 100644 --- a/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs +++ b/crates/console/prometeu-system/src/virtual_machine_runtime/tests.rs @@ -376,7 +376,7 @@ fn tick_gfx_set_sprite_operational_error_returns_status_not_crash() { let report = runtime.tick(&mut vm, &signals, &mut hardware); assert!(report.is_none(), "operational error must not crash"); assert!(vm.is_halted()); - assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(GfxOpStatus::Ok as i64)]); + assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(GfxOpStatus::BankInvalid as i64)]); } #[test] @@ -437,7 +437,7 @@ fn tick_gfx_set_sprite_invalid_range_returns_status_not_crash() { let report = runtime.tick(&mut vm, &signals, &mut hardware); assert!(report.is_none(), "invalid gfx parameter range must not crash"); assert!(vm.is_halted()); - assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(GfxOpStatus::ArgRangeInvalid as i64)]); + assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(GfxOpStatus::BankInvalid as i64)]); } #[test] @@ -522,7 +522,7 @@ fn tick_audio_play_missing_asset_returns_status_not_crash() { let report = runtime.tick(&mut vm, &signals, &mut hardware); assert!(report.is_none(), "missing audio asset must not crash"); assert!(vm.is_halted()); - assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AudioOpStatus::SampleNotFound as i64)]); + assert_eq!(vm.operand_stack_top(1), vec![Value::Int64(AudioOpStatus::BankInvalid as i64)]); } #[test] @@ -930,8 +930,8 @@ fn tick_status_first_surface_smoke_across_gfx_audio_and_asset() { vec![ Value::Int64(0), Value::Int64(AssetLoadError::AssetNotFound as i64), - Value::Int64(AudioOpStatus::SampleNotFound as i64), - Value::Int64(GfxOpStatus::Ok as i64), + Value::Int64(AudioOpStatus::BankInvalid as i64), + Value::Int64(GfxOpStatus::BankInvalid as i64), ] ); } diff --git a/crates/tools/pbxgen-stress/src/lib.rs b/crates/tools/pbxgen-stress/src/lib.rs index 031f0e71..948f5146 100644 --- a/crates/tools/pbxgen-stress/src/lib.rs +++ b/crates/tools/pbxgen-stress/src/lib.rs @@ -126,7 +126,7 @@ fn heavy_load(rom: &mut Vec) { rom.extend(asm("PUSH_I32 0\nHOSTCALL 0")); // --- call status-first syscall path once per frame and drop status --- rom.extend(asm( - "PUSH_CONST 2\nPUSH_I32 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_BOOL 0\nPUSH_BOOL 0\nPUSH_BOOL 0\nPUSH_I32 0\nHOSTCALL 4\nPOP_N 1", + "PUSH_I32 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_I32 0\nPUSH_BOOL 0\nPUSH_BOOL 0\nPUSH_BOOL 0\nPUSH_I32 0\nHOSTCALL 4\nPOP_N 1", )); // --- draw 500 discs --- diff --git a/docs/runtime/specs/04-gfx-peripheral.md b/docs/runtime/specs/04-gfx-peripheral.md index 12e1fd81..c9acb8b6 100644 --- a/docs/runtime/specs/04-gfx-peripheral.md +++ b/docs/runtime/specs/04-gfx-peripheral.md @@ -564,6 +564,7 @@ Minimum status table: - `0` = `OK` - `2` = `INVALID_SPRITE_INDEX` - `3` = `INVALID_ARG_RANGE` +- `4` = `BANK_INVALID` Operational notes: diff --git a/docs/runtime/specs/05-audio-peripheral.md b/docs/runtime/specs/05-audio-peripheral.md index cd459fec..1eeb80db 100644 --- a/docs/runtime/specs/05-audio-peripheral.md +++ b/docs/runtime/specs/05-audio-peripheral.md @@ -215,6 +215,7 @@ Return-shape matrix in v1 syscall surface: - `2` = `SAMPLE_NOT_FOUND` - `3` = `ARG_RANGE_INVALID` - `5` = `NO_EFFECT` +- `6` = `BANK_INVALID` Operational rules: diff --git a/test-cartridges/stress-console/program.pbx b/test-cartridges/stress-console/program.pbx index 3c7e6c0e..f2013a83 100644 Binary files a/test-cartridges/stress-console/program.pbx and b/test-cartridges/stress-console/program.pbx differ