dev/vm-improvements #3

Merged
bquarkz merged 7 commits from dev/vm-improvements into master 2026-01-20 10:18:45 +00:00
2 changed files with 51 additions and 14 deletions
Showing only changes of commit 89bd82ab82 - Show all commits

View File

@ -290,7 +290,7 @@ impl PrometeuOS {
// Helper para syscalls
fn syscall_log_write(&mut self, level_val: i64, tag: u16, msg: String) -> Result<u64, String> {
fn syscall_log_write(&mut self, vm: &mut VirtualMachine, level_val: i64, tag: u16, msg: String) -> Result<u64, String> {
let level = match level_val {
0 => LogLevel::Trace,
1 => LogLevel::Debug,
@ -308,6 +308,7 @@ impl PrometeuOS {
self.logs_written_this_frame.insert(app_id, count + 1);
self.log(LogLevel::Warn, LogSource::App { app_id }, 0, "App exceeded log limit per frame".to_string());
}
vm.push(Value::Null);
return Ok(50);
}
@ -320,6 +321,7 @@ impl PrometeuOS {
self.log(level, LogSource::App { app_id }, tag, final_msg);
vm.push(Value::Null);
Ok(100)
}
@ -529,6 +531,12 @@ mod tests {
let recent = os.log_service.get_recent(1);
assert_eq!(recent[0].msg, "Tagged Log");
assert_eq!(recent[0].tag, 42);
assert_eq!(vm.pop().unwrap(), Value::Null);
// 6. GFX Syscall return test
vm.push(Value::Int64(1)); // color_idx
os.syscall(0x1001, &mut vm, &mut hw).unwrap(); // gfx.clear
assert_eq!(vm.pop().unwrap(), Value::Null);
}
}
@ -552,24 +560,27 @@ impl NativeInterface for PrometeuOS {
// system.has_cart() -> bool
0x0001 => {
// Returns true if a cartridge is available.
vm.push(Value::Boolean(true)); // For now, assume true or check state
Ok(10)
}
// system.run_cart()
// system.run_cart() -> null
0x0002 => {
// Triggers loading and execution of the current cartridge.
vm.push(Value::Null);
Ok(100)
}
// --- GFX Syscalls ---
// gfx.clear(color_index)
// gfx.clear(color_index) -> null
0x1001 => {
let color_idx = vm.pop_integer()? as usize;
let color = self.get_color(color_idx, hw);
hw.gfx_mut().clear(color);
vm.push(Value::Null);
Ok(100)
}
// gfx.draw_rect(x, y, w, h, color_index)
// gfx.draw_rect(x, y, w, h, color_index) -> null
0x1002 => {
let color_idx = vm.pop_integer()? as usize;
let h = vm.pop_integer()? as i32;
@ -578,9 +589,10 @@ impl NativeInterface for PrometeuOS {
let x = vm.pop_integer()? as i32;
let color = self.get_color(color_idx, hw);
hw.gfx_mut().fill_rect(x, y, w, h, color);
vm.push(Value::Null);
Ok(200)
}
// gfx.draw_line(x1, y1, x2, y2, color_index)
// gfx.draw_line(x1, y1, x2, y2, color_index) -> null
0x1003 => {
let color_idx = vm.pop_integer()? as usize;
let y2 = vm.pop_integer()? as i32;
@ -589,9 +601,10 @@ impl NativeInterface for PrometeuOS {
let x1 = vm.pop_integer()? as i32;
let color = self.get_color(color_idx, hw);
hw.gfx_mut().draw_line(x1, y1, x2, y2, color);
vm.push(Value::Null);
Ok(200)
}
// gfx.draw_circle(x, y, r, color_index)
// gfx.draw_circle(x, y, r, color_index) -> null
0x1004 => {
let color_idx = vm.pop_integer()? as usize;
let r = vm.pop_integer()? as i32;
@ -599,9 +612,10 @@ impl NativeInterface for PrometeuOS {
let x = vm.pop_integer()? as i32;
let color = self.get_color(color_idx, hw);
hw.gfx_mut().draw_circle(x, y, r, color);
vm.push(Value::Null);
Ok(200)
}
// gfx.draw_disc(x, y, r, border_color_idx, fill_color_idx)
// gfx.draw_disc(x, y, r, border_color_idx, fill_color_idx) -> null
0x1005 => {
let fill_color_idx = vm.pop_integer()? as usize;
let border_color_idx = vm.pop_integer()? as usize;
@ -611,9 +625,10 @@ impl NativeInterface for PrometeuOS {
let fill_color = self.get_color(fill_color_idx, hw);
let border_color = self.get_color(border_color_idx, hw);
hw.gfx_mut().draw_disc(x, y, r, border_color, fill_color);
vm.push(Value::Null);
Ok(300)
}
// gfx.draw_square(x, y, w, h, border_color_idx, fill_color_idx)
// gfx.draw_square(x, y, w, h, border_color_idx, fill_color_idx) -> null
0x1006 => {
let fill_color_idx = vm.pop_integer()? as usize;
let border_color_idx = vm.pop_integer()? as usize;
@ -624,6 +639,7 @@ impl NativeInterface for PrometeuOS {
let fill_color = self.get_color(fill_color_idx, hw);
let border_color = self.get_color(border_color_idx, hw);
hw.gfx_mut().draw_square(x, y, w, h, border_color, fill_color);
vm.push(Value::Null);
Ok(200)
}
@ -657,6 +673,7 @@ impl NativeInterface for PrometeuOS {
if let Some(s) = sample {
hw.audio_mut().play(s, voice_id, volume, pan, pitch, 0, crate::hardware::LoopMode::Off);
}
vm.push(Value::Null);
Ok(300)
}
@ -718,6 +735,7 @@ impl NativeInterface for PrometeuOS {
0x4004 => {
let handle = vm.pop_integer()? as u32;
self.open_files.remove(&handle);
vm.push(Value::Null);
Ok(100)
}
// FS_LISTDIR(path)
@ -770,7 +788,7 @@ impl NativeInterface for PrometeuOS {
_ => return Err("Expected string message".into()),
};
let level = vm.pop_integer()?;
self.syscall_log_write(level, 0, msg)
self.syscall_log_write(vm, level, 0, msg)
}
// LOG_WRITE_TAG(level, tag, msg)
0x5002 => {
@ -780,7 +798,7 @@ impl NativeInterface for PrometeuOS {
};
let tag = vm.pop_integer()? as u16;
let level = vm.pop_integer()?;
self.syscall_log_write(level, tag, msg)
self.syscall_log_write(vm, level, tag, msg)
}
_ => Err(format!("Unknown syscall: 0x{:08X}", id)),

View File

@ -84,11 +84,30 @@ Do not exist:
---
## 4. Stack Conventions
## 4. Stack Conventions & Calling ABI
* Operations use the top of the stack
* Results always return to the stack
* Last pushed = first consumed
* Operations use the top of the stack.
* Results always return to the stack.
* **LIFO Order:** Last pushed = first consumed.
* **Mandatory Return:** Every function (`Call`) and `Syscall` MUST leave exactly **one** value on the stack upon completion. If there is no meaningful value to return, `Null` must be pushed.
### 4.1 Calling Convention (Call / Ret)
1. **Arguments:** The caller pushes arguments in order (arg0, arg1, ..., argN-1).
2. **Execution:** The `Call` instruction specifies `args_count`. These `N` values become the **locals** of the new frame (local 0 = arg0, local 1 = arg1, etc.).
3. **Return Value:** Before executing `Ret`, the callee MUST push its return value.
4. **Cleanup:** The `Ret` instruction is responsible for:
- Popping the return value.
- Removing all locals (the arguments) from the operand stack.
- Re-pushing the return value.
- Restoring the previous frame and PC.
### 4.2 Syscall Convention
1. **Arguments:** The caller pushes arguments in order.
2. **Execution:** The native implementation pops arguments as needed. Since it's a stack, it will pop them in reverse order (argN-1 first, then argN-2, ..., arg0).
3. **Return Value:** The native implementation MUST push exactly one value onto the stack before returning to the VM.
4. **Cleanup:** The native implementation is responsible for popping all arguments it expects.
Example: