improve stack contract
This commit is contained in:
parent
6b033f9aa6
commit
89bd82ab82
@ -290,7 +290,7 @@ impl PrometeuOS {
|
|||||||
|
|
||||||
|
|
||||||
// Helper para syscalls
|
// 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 {
|
let level = match level_val {
|
||||||
0 => LogLevel::Trace,
|
0 => LogLevel::Trace,
|
||||||
1 => LogLevel::Debug,
|
1 => LogLevel::Debug,
|
||||||
@ -308,6 +308,7 @@ impl PrometeuOS {
|
|||||||
self.logs_written_this_frame.insert(app_id, count + 1);
|
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());
|
self.log(LogLevel::Warn, LogSource::App { app_id }, 0, "App exceeded log limit per frame".to_string());
|
||||||
}
|
}
|
||||||
|
vm.push(Value::Null);
|
||||||
return Ok(50);
|
return Ok(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,6 +321,7 @@ impl PrometeuOS {
|
|||||||
|
|
||||||
self.log(level, LogSource::App { app_id }, tag, final_msg);
|
self.log(level, LogSource::App { app_id }, tag, final_msg);
|
||||||
|
|
||||||
|
vm.push(Value::Null);
|
||||||
Ok(100)
|
Ok(100)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,6 +531,12 @@ mod tests {
|
|||||||
let recent = os.log_service.get_recent(1);
|
let recent = os.log_service.get_recent(1);
|
||||||
assert_eq!(recent[0].msg, "Tagged Log");
|
assert_eq!(recent[0].msg, "Tagged Log");
|
||||||
assert_eq!(recent[0].tag, 42);
|
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
|
// system.has_cart() -> bool
|
||||||
0x0001 => {
|
0x0001 => {
|
||||||
// Returns true if a cartridge is available.
|
// Returns true if a cartridge is available.
|
||||||
|
vm.push(Value::Boolean(true)); // For now, assume true or check state
|
||||||
Ok(10)
|
Ok(10)
|
||||||
}
|
}
|
||||||
// system.run_cart()
|
// system.run_cart() -> null
|
||||||
0x0002 => {
|
0x0002 => {
|
||||||
// Triggers loading and execution of the current cartridge.
|
// Triggers loading and execution of the current cartridge.
|
||||||
|
vm.push(Value::Null);
|
||||||
Ok(100)
|
Ok(100)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- GFX Syscalls ---
|
// --- GFX Syscalls ---
|
||||||
|
|
||||||
// gfx.clear(color_index)
|
// gfx.clear(color_index) -> null
|
||||||
0x1001 => {
|
0x1001 => {
|
||||||
let color_idx = vm.pop_integer()? as usize;
|
let color_idx = vm.pop_integer()? as usize;
|
||||||
let color = self.get_color(color_idx, hw);
|
let color = self.get_color(color_idx, hw);
|
||||||
hw.gfx_mut().clear(color);
|
hw.gfx_mut().clear(color);
|
||||||
|
vm.push(Value::Null);
|
||||||
Ok(100)
|
Ok(100)
|
||||||
}
|
}
|
||||||
// gfx.draw_rect(x, y, w, h, color_index)
|
// gfx.draw_rect(x, y, w, h, color_index) -> null
|
||||||
0x1002 => {
|
0x1002 => {
|
||||||
let color_idx = vm.pop_integer()? as usize;
|
let color_idx = vm.pop_integer()? as usize;
|
||||||
let h = vm.pop_integer()? as i32;
|
let h = vm.pop_integer()? as i32;
|
||||||
@ -578,9 +589,10 @@ impl NativeInterface for PrometeuOS {
|
|||||||
let x = vm.pop_integer()? as i32;
|
let x = vm.pop_integer()? as i32;
|
||||||
let color = self.get_color(color_idx, hw);
|
let color = self.get_color(color_idx, hw);
|
||||||
hw.gfx_mut().fill_rect(x, y, w, h, color);
|
hw.gfx_mut().fill_rect(x, y, w, h, color);
|
||||||
|
vm.push(Value::Null);
|
||||||
Ok(200)
|
Ok(200)
|
||||||
}
|
}
|
||||||
// gfx.draw_line(x1, y1, x2, y2, color_index)
|
// gfx.draw_line(x1, y1, x2, y2, color_index) -> null
|
||||||
0x1003 => {
|
0x1003 => {
|
||||||
let color_idx = vm.pop_integer()? as usize;
|
let color_idx = vm.pop_integer()? as usize;
|
||||||
let y2 = vm.pop_integer()? as i32;
|
let y2 = vm.pop_integer()? as i32;
|
||||||
@ -589,9 +601,10 @@ impl NativeInterface for PrometeuOS {
|
|||||||
let x1 = vm.pop_integer()? as i32;
|
let x1 = vm.pop_integer()? as i32;
|
||||||
let color = self.get_color(color_idx, hw);
|
let color = self.get_color(color_idx, hw);
|
||||||
hw.gfx_mut().draw_line(x1, y1, x2, y2, color);
|
hw.gfx_mut().draw_line(x1, y1, x2, y2, color);
|
||||||
|
vm.push(Value::Null);
|
||||||
Ok(200)
|
Ok(200)
|
||||||
}
|
}
|
||||||
// gfx.draw_circle(x, y, r, color_index)
|
// gfx.draw_circle(x, y, r, color_index) -> null
|
||||||
0x1004 => {
|
0x1004 => {
|
||||||
let color_idx = vm.pop_integer()? as usize;
|
let color_idx = vm.pop_integer()? as usize;
|
||||||
let r = vm.pop_integer()? as i32;
|
let r = vm.pop_integer()? as i32;
|
||||||
@ -599,9 +612,10 @@ impl NativeInterface for PrometeuOS {
|
|||||||
let x = vm.pop_integer()? as i32;
|
let x = vm.pop_integer()? as i32;
|
||||||
let color = self.get_color(color_idx, hw);
|
let color = self.get_color(color_idx, hw);
|
||||||
hw.gfx_mut().draw_circle(x, y, r, color);
|
hw.gfx_mut().draw_circle(x, y, r, color);
|
||||||
|
vm.push(Value::Null);
|
||||||
Ok(200)
|
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 => {
|
0x1005 => {
|
||||||
let fill_color_idx = vm.pop_integer()? as usize;
|
let fill_color_idx = vm.pop_integer()? as usize;
|
||||||
let border_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 fill_color = self.get_color(fill_color_idx, hw);
|
||||||
let border_color = self.get_color(border_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);
|
hw.gfx_mut().draw_disc(x, y, r, border_color, fill_color);
|
||||||
|
vm.push(Value::Null);
|
||||||
Ok(300)
|
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 => {
|
0x1006 => {
|
||||||
let fill_color_idx = vm.pop_integer()? as usize;
|
let fill_color_idx = vm.pop_integer()? as usize;
|
||||||
let border_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 fill_color = self.get_color(fill_color_idx, hw);
|
||||||
let border_color = self.get_color(border_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);
|
hw.gfx_mut().draw_square(x, y, w, h, border_color, fill_color);
|
||||||
|
vm.push(Value::Null);
|
||||||
Ok(200)
|
Ok(200)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -657,6 +673,7 @@ impl NativeInterface for PrometeuOS {
|
|||||||
if let Some(s) = sample {
|
if let Some(s) = sample {
|
||||||
hw.audio_mut().play(s, voice_id, volume, pan, pitch, 0, crate::hardware::LoopMode::Off);
|
hw.audio_mut().play(s, voice_id, volume, pan, pitch, 0, crate::hardware::LoopMode::Off);
|
||||||
}
|
}
|
||||||
|
vm.push(Value::Null);
|
||||||
Ok(300)
|
Ok(300)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,6 +735,7 @@ impl NativeInterface for PrometeuOS {
|
|||||||
0x4004 => {
|
0x4004 => {
|
||||||
let handle = vm.pop_integer()? as u32;
|
let handle = vm.pop_integer()? as u32;
|
||||||
self.open_files.remove(&handle);
|
self.open_files.remove(&handle);
|
||||||
|
vm.push(Value::Null);
|
||||||
Ok(100)
|
Ok(100)
|
||||||
}
|
}
|
||||||
// FS_LISTDIR(path)
|
// FS_LISTDIR(path)
|
||||||
@ -770,7 +788,7 @@ impl NativeInterface for PrometeuOS {
|
|||||||
_ => return Err("Expected string message".into()),
|
_ => return Err("Expected string message".into()),
|
||||||
};
|
};
|
||||||
let level = vm.pop_integer()?;
|
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)
|
// LOG_WRITE_TAG(level, tag, msg)
|
||||||
0x5002 => {
|
0x5002 => {
|
||||||
@ -780,7 +798,7 @@ impl NativeInterface for PrometeuOS {
|
|||||||
};
|
};
|
||||||
let tag = vm.pop_integer()? as u16;
|
let tag = vm.pop_integer()? as u16;
|
||||||
let level = vm.pop_integer()?;
|
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)),
|
_ => 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
|
* Operations use the top of the stack.
|
||||||
* Results always return to the stack
|
* Results always return to the stack.
|
||||||
* Last pushed = first consumed
|
* **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:
|
Example:
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user