Skip to content

Commit

Permalink
feat: implement call stack
Browse files Browse the repository at this point in the history
  • Loading branch information
heypoom committed Oct 5, 2023
1 parent d89e9c6 commit e0b22c9
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/instructions/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ impl Load for Memory {
let mut offset = CODE_START;

let mut write = |v: u16| {
self.set(offset, v.clone());
self.set(offset, v);
offset += 1;
};

Expand All @@ -22,7 +22,7 @@ impl Load for Memory {
// TODO: this is very repetitive!
// Can we detect the number of arguments and do this automatically?
match ins {
I::LoadString(v) | I::Store(v) | I::Load(v) | I::JumpNotZero(v) | I::JumpZero(v) | I::Jump(v) | I::Push(v) => write(v),
I::LoadString(v) | I::Store(v) | I::Load(v) | I::JumpNotZero(v) | I::JumpZero(v) | I::Jump(v) | I::Push(v) | I::Call(v) => write(v),
_ => {}
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,15 @@ pub enum Instruction {
GreaterThan,
GreaterThanOrEqual,

// Print the text at the memory address of operand zero.
// Print the text at the memory address of operand.
Print,

// Stores the PC on the call stack and jumps to the address.
Call(u16),

// Pop the return address from the call stack and jumps to it.
Return,

Halt,
}

Expand Down Expand Up @@ -96,6 +102,7 @@ impl From<Instruction> for u16 {
I::Load(_) => I::Load(0),
I::Store(_) => I::Store(0),
I::LoadString(_) => I::LoadString(0),
I::Call(_) => I::Call(0),
_ => ins,
};

Expand Down
1 change: 1 addition & 0 deletions src/machine/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ impl Decode for Machine {
I::Load(_) => I::Load(self.arg()),
I::Store(_) => I::Store(self.arg()),
I::LoadString(_) => I::LoadString(self.arg()),
I::Call(_) => I::Call(self.arg()),
_ => i
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/machine/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,18 @@ impl Execute for Machine {
self.stack().push(*v).expect("push error");
}
}

I::Call(address) => {
let pc = self.reg.get(PC);

self.call_stack().push(pc).unwrap();
self.reg.set(PC, address);
}

I::Return => {
let address = self.call_stack().pop().expect("cannot pop the return address");
self.reg.set(PC, address);
}
};

// Advance or jump the program counter.
Expand All @@ -122,6 +134,8 @@ impl Execute for Machine {
// Fetch, decode and execute the instruction.
fn tick(&mut self) {
let instruction = self.decode();
// println!("{:?}", instruction);

self.exec_op(instruction);
}

Expand Down
10 changes: 10 additions & 0 deletions src/machine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ mod decode;
mod execute;
mod handlers;

use crate::{CALL_STACK_END, CALL_STACK_START};
use crate::instructions::{Instruction, Load};
use crate::machine::handlers::Handlers;
use crate::mem::{Memory, StackManager};
use crate::Register::FP;
use crate::register::Registers;

pub use self::decode::Decode;
Expand All @@ -27,6 +29,14 @@ impl Machine {
pub fn stack(&mut self) -> StackManager {
StackManager::new(&mut self.mem, &mut self.reg)
}

pub fn call_stack(&mut self) -> StackManager {
let mut stack = self.stack();
stack.sp = FP;
stack.min = CALL_STACK_START;
stack.max = CALL_STACK_END;
stack
}
}

impl From<Vec<Instruction>> for Machine {
Expand Down
6 changes: 5 additions & 1 deletion src/mem/memory.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{MEMORY_SIZE, STACK_START};
use crate::{CALL_STACK_START, MEMORY_SIZE, STACK_START};

/**
* Memory defines a fixed-size memory area for the program.
Expand Down Expand Up @@ -38,6 +38,10 @@ impl Memory {
pub fn read_stack(&self, count: u16) -> Vec<u16> {
self.read(STACK_START, count)
}

pub fn read_call_stack(&self, count: u16) -> Vec<u16> {
self.read(CALL_STACK_START, count)
}
}

#[cfg(test)]
Expand Down
2 changes: 1 addition & 1 deletion src/mem/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl<'a> StackManager<'a> {

pub fn pop(&mut self) -> Result<u16, Whatever> {
if self.top() < self.min {
whatever!("stack underflow")
whatever!("stack underflow. top={}, min={}", self.top(), self.min)
}

let v = self.peek();
Expand Down
4 changes: 3 additions & 1 deletion src/register/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::STACK_START;
use crate::Register::FP;
use crate::{CALL_STACK_START, STACK_START};
use crate::register::Register::{PC, SP};

const REG_COUNT: usize = 0xF;
Expand Down Expand Up @@ -32,6 +33,7 @@ impl Registers {
// Initialize the stack pointer.
v.set(PC, 0);
v.set(SP, STACK_START - 1);
v.set(FP, CALL_STACK_START - 1);

v
}
Expand Down
30 changes: 30 additions & 0 deletions tests/call_stack.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#[cfg(test)]
mod call_stack_tests {
extern crate opcodes_to_algorithms as O;

use O::{Machine, Execute, Load, Instruction as I};

#[test]
fn test_call_stack() {
let mut m = Machine::new();

let ptr_pusher = 1;
let ptr_start = 6;

m.mem.load_code(vec![
I::Call(ptr_start),

// [pusher]
I::Push(0xAA),
I::Push(0xBB),
I::Return,

// [start]
I::Call(ptr_pusher),
I::Call(ptr_pusher),
]);

m.run();
assert_eq!(m.mem.read_stack(4), [0xAA, 0xBB, 0xAA, 0xBB]);
}
}

0 comments on commit e0b22c9

Please sign in to comment.