add function calls
This commit is contained in:
parent
9db4c73a52
commit
17374c5fcc
|
|
@ -5,6 +5,10 @@ use thiserror::Error;
|
|||
pub enum ExecutionError {
|
||||
#[error("Trying to access invalid memory location!")]
|
||||
InvalidMemoryLocation,
|
||||
#[error("Stack Overflow")]
|
||||
StackOverflow,
|
||||
#[error("Stack Underflow")]
|
||||
StackUnderflow,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
|
|||
58
src/main.rs
58
src/main.rs
|
|
@ -30,30 +30,48 @@ fn main() -> anyhow::Result<()> {
|
|||
.ok()
|
||||
})
|
||||
.unwrap_or_else(|| {
|
||||
use Bytecode::*;
|
||||
vec![
|
||||
Bytecode::Nop as u32,
|
||||
Bytecode::Nop as u32,
|
||||
Bytecode::Nop as u32,
|
||||
Bytecode::Nop as u32,
|
||||
Bytecode::Set as u32,
|
||||
0x00,
|
||||
42,
|
||||
Bytecode::Set as u32,
|
||||
0x01,
|
||||
10,
|
||||
Bytecode::Add as u32,
|
||||
0x00,
|
||||
0x01,
|
||||
Bytecode::Store as u32,
|
||||
0x40,
|
||||
0x00,
|
||||
Bytecode::Inspect as u32,
|
||||
0x40,
|
||||
0xFF,
|
||||
/* 0 */ Jmp as u32,
|
||||
/* 1 */ 15,
|
||||
/* 2 */ Pop as u32,
|
||||
/* 3 */ 5,
|
||||
/* 4 */ Pop as u32,
|
||||
/* 5 */ 0,
|
||||
/* 6 */ Pop as u32,
|
||||
/* 7 */ 1,
|
||||
/* 8 */ Add as u32,
|
||||
/* 9 */ 0,
|
||||
/* 10 */ 1,
|
||||
/* 11 */ PushReg as u32,
|
||||
/* 12 */ 5,
|
||||
/* 13 */ RetReg as u32,
|
||||
/* 14 */ 0,
|
||||
/* 15 */ Nop as u32,
|
||||
/* 16 */ Nop as u32,
|
||||
/* 17 */ Nop as u32,
|
||||
/* 18 */ Nop as u32,
|
||||
/* 19 */ PushValue as u32,
|
||||
/* 20 */ 42,
|
||||
/* 21 */ LoadValue as u32,
|
||||
/* 22 */ 0,
|
||||
/* 23 */ 10,
|
||||
/* 24 */ PushReg as u32,
|
||||
/* 25 */ 0,
|
||||
/* 26 */ Call as u32,
|
||||
/* 27 */ 2,
|
||||
/* 28 */ Pop as u32,
|
||||
/* 29 */ 3,
|
||||
/* 30 */ Store as u32,
|
||||
/* 31 */ 40,
|
||||
/* 32 */ 3,
|
||||
/* 33 */ Inspect as u32,
|
||||
/* 34 */ 40,
|
||||
/* 35 */ Halt as u32,
|
||||
]
|
||||
});
|
||||
|
||||
let mut cpu = NativeCpu::new(1024 * 1024, 4);
|
||||
let mut cpu = NativeCpu::new(1024 * 1024, 6);
|
||||
cpu.set_verbose(verbose);
|
||||
|
||||
cpu.load_memory(0, &memory);
|
||||
|
|
|
|||
208
src/native.rs
208
src/native.rs
|
|
@ -3,15 +3,22 @@ use num_derive::{FromPrimitive, ToPrimitive};
|
|||
use num_traits::FromPrimitive;
|
||||
|
||||
#[derive(Debug, PartialEq, PartialOrd, Copy, Clone, Hash, Eq, Ord, FromPrimitive, ToPrimitive)]
|
||||
#[repr(usize)]
|
||||
#[repr(u32)]
|
||||
pub enum Bytecode {
|
||||
Nop = 0x00,
|
||||
Set = 0x01,
|
||||
Load = 0x02,
|
||||
LoadValue = 0x01,
|
||||
LoadMemory = 0x02,
|
||||
Store = 0x03,
|
||||
Add = 0x12,
|
||||
PushValue = 0x04,
|
||||
PushReg = 0x05,
|
||||
Pop = 0x06,
|
||||
Add = 0x10,
|
||||
Call = 0xF0,
|
||||
Ret = 0xF1,
|
||||
RetReg = 0xF2,
|
||||
Jmp = 0xF3,
|
||||
Inspect = 0xFE,
|
||||
Halt = 0xFF,
|
||||
Halt = 0xFFFFFFFF,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -19,9 +26,8 @@ pub struct NativeCpu {
|
|||
memory: Vec<u32>,
|
||||
memory_score_multiplier: usize,
|
||||
registers: Vec<u32>,
|
||||
pc: u32, // Program counter
|
||||
// sp: u32, // Stack pointer
|
||||
// call_stack: Vec<u32>, // Call stack for function calls
|
||||
instruction_pointer: u32,
|
||||
stack_pointer: u32, // Stack pointer
|
||||
verbose: bool,
|
||||
cycles: usize, // Performance counter for cycles
|
||||
memory_access_score: usize, // Tracks the performance score
|
||||
|
|
@ -81,14 +87,13 @@ impl CpuTrait for NativeCpu {
|
|||
}
|
||||
|
||||
impl NativeCpu {
|
||||
pub fn new(memory: u64, registers: u8) -> Self {
|
||||
pub fn new(memory_size: u32, registers: u8) -> Self {
|
||||
Self {
|
||||
memory: vec![0; memory as usize],
|
||||
memory: vec![0; memory_size as usize],
|
||||
memory_score_multiplier: 10,
|
||||
registers: vec![0; registers as usize],
|
||||
pc: 0,
|
||||
// sp: 1024 * 1024, // Stack grows downward
|
||||
// call_stack: Vec::new(),
|
||||
instruction_pointer: 0,
|
||||
stack_pointer: memory_size - 1, // Stack starts at the top of memory
|
||||
verbose: false,
|
||||
cycles: 0,
|
||||
memory_access_score: 0,
|
||||
|
|
@ -107,17 +112,19 @@ impl NativeCpu {
|
|||
fn run(&mut self, cycles: isize) -> Result<CpuStats, ExecutionError> {
|
||||
let mut executed = 0;
|
||||
|
||||
while (cycles < 0 || executed < cycles) && (self.pc as usize) < self.memory.len() {
|
||||
let opcode = self.read_memory(self.pc)?;
|
||||
self.pc += 1;
|
||||
while (cycles < 0 || executed < cycles)
|
||||
&& (self.instruction_pointer as usize) < self.memory.len()
|
||||
{
|
||||
let opcode = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
match Bytecode::from_u32(opcode) {
|
||||
Some(Bytecode::Set) => {
|
||||
let reg = self.read_memory(self.pc)?;
|
||||
self.pc += 1;
|
||||
Some(Bytecode::LoadValue) => {
|
||||
let reg = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
let imm = self.read_memory(self.pc)?;
|
||||
self.pc += 1;
|
||||
let imm = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
if self.verbose {
|
||||
println!("SET R{}, {}", reg, imm);
|
||||
|
|
@ -126,12 +133,12 @@ impl NativeCpu {
|
|||
self.registers[reg as usize] = imm;
|
||||
self.cycles += 2;
|
||||
}
|
||||
Some(Bytecode::Load) => {
|
||||
let reg = self.read_memory(self.pc)?;
|
||||
self.pc += 1;
|
||||
Some(Bytecode::LoadMemory) => {
|
||||
let reg = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
let addr = self.read_memory(self.pc)?;
|
||||
self.pc += 1;
|
||||
let addr = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
if self.verbose {
|
||||
println!("LOAD R{}, @{:#02x}", reg, addr);
|
||||
|
|
@ -141,11 +148,11 @@ impl NativeCpu {
|
|||
self.cycles += 2;
|
||||
}
|
||||
Some(Bytecode::Store) => {
|
||||
let addr = self.read_memory(self.pc)?;
|
||||
self.pc += 1;
|
||||
let addr = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
let reg = self.read_memory(self.pc)?;
|
||||
self.pc += 1;
|
||||
let reg = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
if self.verbose {
|
||||
println!("STORE @{:#02x}, R{}", addr, reg);
|
||||
|
|
@ -155,17 +162,17 @@ impl NativeCpu {
|
|||
self.cycles += 2;
|
||||
}
|
||||
Some(Bytecode::Inspect) => {
|
||||
let addr = self.read_memory(self.pc)?;
|
||||
self.pc += 1;
|
||||
let addr = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
println!("INSPECT @{:#02x} = {}", addr, self.read_memory(addr)?);
|
||||
}
|
||||
Some(Bytecode::Add) => {
|
||||
let reg1 = self.read_memory(self.pc)?;
|
||||
self.pc += 1;
|
||||
let reg1 = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
let reg2 = self.read_memory(self.pc)?;
|
||||
self.pc += 1;
|
||||
let reg2 = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
if self.verbose {
|
||||
println!(
|
||||
|
|
@ -181,6 +188,97 @@ impl NativeCpu {
|
|||
self.registers[reg1 as usize].wrapping_add(self.registers[reg2 as usize]);
|
||||
self.cycles += 1;
|
||||
}
|
||||
Some(Bytecode::Jmp) => {
|
||||
let imm = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer = imm;
|
||||
|
||||
if self.verbose {
|
||||
println!("JMP {}", imm);
|
||||
}
|
||||
|
||||
self.cycles += 2;
|
||||
}
|
||||
Some(Bytecode::PushValue) => {
|
||||
let imm = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
if self.verbose {
|
||||
println!("PUSH {}", imm);
|
||||
}
|
||||
|
||||
self.push_stack(imm)?;
|
||||
|
||||
self.cycles += 2;
|
||||
}
|
||||
Some(Bytecode::PushReg) => {
|
||||
let reg = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
let val = self.registers[reg as usize];
|
||||
|
||||
if self.verbose {
|
||||
println!("PUSH R{}", reg);
|
||||
}
|
||||
|
||||
self.push_stack(val)?;
|
||||
|
||||
self.cycles += 2;
|
||||
}
|
||||
Some(Bytecode::Pop) => {
|
||||
let reg = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
if self.verbose {
|
||||
println!("POP R{}", reg);
|
||||
}
|
||||
|
||||
self.registers[reg as usize] = self.pop_stack()?;
|
||||
|
||||
self.cycles += 2;
|
||||
}
|
||||
Some(Bytecode::Call) => {
|
||||
let target = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
if self.verbose {
|
||||
println!("CALL @{:#02x}", target);
|
||||
}
|
||||
|
||||
// Push the current PC onto the stack as the return address
|
||||
self.push_stack(self.instruction_pointer)?;
|
||||
|
||||
// Jump to the target address
|
||||
self.instruction_pointer = target;
|
||||
|
||||
self.cycles += 3; // CALL takes 3 cycles
|
||||
}
|
||||
Some(Bytecode::RetReg) => {
|
||||
let reg = self.read_memory(self.instruction_pointer)?;
|
||||
self.instruction_pointer += 1;
|
||||
|
||||
// Pop the return address from the stack
|
||||
let return_address = self.pop_stack()?;
|
||||
|
||||
if self.verbose {
|
||||
println!("RET R{} to @{:#02x}", reg, return_address);
|
||||
}
|
||||
|
||||
self.push_stack(self.registers[reg as usize])?;
|
||||
|
||||
self.instruction_pointer = return_address;
|
||||
self.cycles += 2; // RET takes 2 cycles
|
||||
}
|
||||
Some(Bytecode::Ret) => {
|
||||
// Pop the return address from the stack
|
||||
let return_address = self.pop_stack()?;
|
||||
|
||||
if self.verbose {
|
||||
println!("RET to @{:#02x}", return_address);
|
||||
}
|
||||
|
||||
self.instruction_pointer = return_address;
|
||||
self.cycles += 2; // RET takes 2 cycles
|
||||
}
|
||||
Some(Bytecode::Halt) => {
|
||||
if self.verbose {
|
||||
println!("HALT");
|
||||
|
|
@ -237,30 +335,22 @@ impl NativeCpu {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// fn push_to_stack(&mut self, value: u32) -> Result<(), ExecutionError> {
|
||||
// self.valid_address(self.sp)?;
|
||||
// self.sp -= 1;
|
||||
// self.memory[self.sp as usize] = value;
|
||||
// Ok(())
|
||||
// }
|
||||
fn push_stack(&mut self, value: u32) -> Result<(), ExecutionError> {
|
||||
if self.stack_pointer == 0 {
|
||||
return Err(ExecutionError::StackOverflow);
|
||||
}
|
||||
|
||||
// fn pop_from_stack(&mut self) -> Result<u32, ExecutionError> {
|
||||
// self.valid_address(self.sp)?;
|
||||
// let value = self.memory[self.sp as usize];
|
||||
// self.sp += 1;
|
||||
// Ok(value)
|
||||
// }
|
||||
self.memory[self.stack_pointer as usize] = value;
|
||||
self.stack_pointer -= 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// fn call_function(&mut self, function_address: u32) {
|
||||
// self.call_stack.push(self.pc); // Save current PC to call stack
|
||||
// self.pc = function_address; // Jump to the function's address
|
||||
// }
|
||||
fn pop_stack(&mut self) -> Result<u32, ExecutionError> {
|
||||
if self.stack_pointer as usize >= self.memory.len() - 1 {
|
||||
return Err(ExecutionError::StackUnderflow);
|
||||
}
|
||||
|
||||
// fn return_from_function(&mut self) {
|
||||
// if let Some(return_address) = self.call_stack.pop() {
|
||||
// self.pc = return_address; // Restore PC from the call stack
|
||||
// } else {
|
||||
// panic!("Call stack underflow: No return address");
|
||||
// }
|
||||
// }
|
||||
self.stack_pointer += 1;
|
||||
Ok(self.memory[self.stack_pointer as usize])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue