dev/vm-improvements #3
@ -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)),
|
||||
|
||||
@ -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:
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user