cpu.rs: Remove stack from main memory
This commit is contained in:
parent
e842755d77
commit
45adf0a2b8
@ -129,14 +129,11 @@ impl State {
|
|||||||
Program [0x0200..0x1000] = &read(&options.file)?,
|
Program [0x0200..0x1000] = &read(&options.file)?,
|
||||||
// Create a screen
|
// Create a screen
|
||||||
Screen [0x1000..0x1100],
|
Screen [0x1000..0x1100],
|
||||||
// Create a stack
|
|
||||||
Stack [0x0EA0..0x0F00],
|
|
||||||
},
|
},
|
||||||
cpu: CPU::new(
|
cpu: CPU::new(
|
||||||
0x1000,
|
0x1000,
|
||||||
0x50,
|
0x50,
|
||||||
0x200,
|
0x200,
|
||||||
0xefe,
|
|
||||||
Dis::default(),
|
Dis::default(),
|
||||||
options.breakpoints,
|
options.breakpoints,
|
||||||
Flags {
|
Flags {
|
||||||
|
@ -55,9 +55,10 @@ pub struct CPU {
|
|||||||
// memory map info
|
// memory map info
|
||||||
screen: Adr,
|
screen: Adr,
|
||||||
font: Adr,
|
font: Adr,
|
||||||
|
// memory
|
||||||
|
stack: Vec<Adr>,
|
||||||
// registers
|
// registers
|
||||||
pc: Adr,
|
pc: Adr,
|
||||||
sp: Adr,
|
|
||||||
i: Adr,
|
i: Adr,
|
||||||
v: [u8; 16],
|
v: [u8; 16],
|
||||||
delay: f64,
|
delay: f64,
|
||||||
@ -93,7 +94,6 @@ impl CPU {
|
|||||||
screen: Adr,
|
screen: Adr,
|
||||||
font: Adr,
|
font: Adr,
|
||||||
pc: Adr,
|
pc: Adr,
|
||||||
sp: Adr,
|
|
||||||
disassembler: Dis,
|
disassembler: Dis,
|
||||||
breakpoints: Vec<Adr>,
|
breakpoints: Vec<Adr>,
|
||||||
flags: Flags,
|
flags: Flags,
|
||||||
@ -103,7 +103,6 @@ impl CPU {
|
|||||||
screen,
|
screen,
|
||||||
font,
|
font,
|
||||||
pc,
|
pc,
|
||||||
sp,
|
|
||||||
breakpoints,
|
breakpoints,
|
||||||
flags,
|
flags,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -548,7 +547,7 @@ impl CPU {
|
|||||||
std::println!(
|
std::println!(
|
||||||
"PC: {:04x}, SP: {:04x}, I: {:04x}\n{}DLY: {}, SND: {}, CYC: {:6}",
|
"PC: {:04x}, SP: {:04x}, I: {:04x}\n{}DLY: {}, SND: {}, CYC: {:6}",
|
||||||
self.pc,
|
self.pc,
|
||||||
self.sp,
|
self.stack.len(),
|
||||||
self.i,
|
self.i,
|
||||||
self.v
|
self.v
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -588,10 +587,10 @@ impl Default for CPU {
|
|||||||
/// ```
|
/// ```
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
CPU {
|
CPU {
|
||||||
|
stack: vec![],
|
||||||
screen: 0xf00,
|
screen: 0xf00,
|
||||||
font: 0x050,
|
font: 0x050,
|
||||||
pc: 0x200,
|
pc: 0x200,
|
||||||
sp: 0xefe,
|
|
||||||
i: 0,
|
i: 0,
|
||||||
v: [0; 16],
|
v: [0; 16],
|
||||||
delay: 0.0,
|
delay: 0.0,
|
||||||
|
@ -88,8 +88,6 @@ pub enum Region {
|
|||||||
Program,
|
Program,
|
||||||
/// Screen buffer
|
/// Screen buffer
|
||||||
Screen,
|
Screen,
|
||||||
/// Stack space
|
|
||||||
Stack,
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
/// Total number of named regions
|
/// Total number of named regions
|
||||||
Count,
|
Count,
|
||||||
@ -104,7 +102,6 @@ impl Display for Region {
|
|||||||
Region::Charset => "Charset",
|
Region::Charset => "Charset",
|
||||||
Region::Program => "Program",
|
Region::Program => "Program",
|
||||||
Region::Screen => "Screen",
|
Region::Screen => "Screen",
|
||||||
Region::Stack => "Stack",
|
|
||||||
_ => "",
|
_ => "",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -348,7 +345,7 @@ impl Bus {
|
|||||||
#[cfg(feature = "drawille")]
|
#[cfg(feature = "drawille")]
|
||||||
{
|
{
|
||||||
use drawille::Canvas;
|
use drawille::Canvas;
|
||||||
let mut canvas = Canvas::new(dbg!(width * 8), dbg!(height));
|
let mut canvas = Canvas::new(width * 8, height);
|
||||||
let width = width * 8;
|
let width = width * 8;
|
||||||
screen
|
screen
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -13,9 +13,9 @@ impl CPU {
|
|||||||
match instruction {
|
match instruction {
|
||||||
// Core Chip-8 instructions
|
// Core Chip-8 instructions
|
||||||
Insn::cls => self.clear_screen(bus),
|
Insn::cls => self.clear_screen(bus),
|
||||||
Insn::ret => self.ret(bus),
|
Insn::ret => self.ret(),
|
||||||
Insn::jmp { A } => self.jump(A),
|
Insn::jmp { A } => self.jump(A),
|
||||||
Insn::call { A } => self.call(A, bus),
|
Insn::call { A } => self.call(A),
|
||||||
Insn::seb { x, B } => self.skip_equals_immediate(x, B),
|
Insn::seb { x, B } => self.skip_equals_immediate(x, B),
|
||||||
Insn::sneb { x, B } => self.skip_not_equals_immediate(x, B),
|
Insn::sneb { x, B } => self.skip_not_equals_immediate(x, B),
|
||||||
Insn::se { y, x } => self.skip_equals(x, y),
|
Insn::se { y, x } => self.skip_equals(x, y),
|
||||||
@ -74,9 +74,8 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
/// |`00ee`| Returns from subroutine
|
/// |`00ee`| Returns from subroutine
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(super) fn ret(&mut self, bus: &impl ReadWrite<u16>) {
|
pub(super) fn ret(&mut self) {
|
||||||
self.sp = self.sp.wrapping_add(2);
|
self.pc = self.stack.pop().unwrap_or(0x200);
|
||||||
self.pc = bus.read(self.sp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,9 +96,8 @@ impl CPU {
|
|||||||
impl CPU {
|
impl CPU {
|
||||||
/// |`2aaa`| Pushes pc onto the stack, then jumps to a
|
/// |`2aaa`| Pushes pc onto the stack, then jumps to a
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(super) fn call(&mut self, a: Adr, bus: &mut impl ReadWrite<u16>) {
|
pub(super) fn call(&mut self, a: Adr) {
|
||||||
bus.write(self.sp, self.pc);
|
self.stack.push(self.pc);
|
||||||
self.sp = self.sp.wrapping_sub(2);
|
|
||||||
self.pc = a;
|
self.pc = a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,17 +106,14 @@ mod sys {
|
|||||||
#[test]
|
#[test]
|
||||||
fn ret() {
|
fn ret() {
|
||||||
let test_addr = random::<u16>() & 0x7ff;
|
let test_addr = random::<u16>() & 0x7ff;
|
||||||
let (mut cpu, mut bus) = setup_environment();
|
let (mut cpu, _) = setup_environment();
|
||||||
let sp_orig = cpu.sp;
|
|
||||||
// Place the address on the stack
|
// Place the address on the stack
|
||||||
bus.write(cpu.sp.wrapping_add(2), test_addr);
|
cpu.stack.push(test_addr);
|
||||||
|
|
||||||
cpu.ret(&bus);
|
cpu.ret();
|
||||||
|
|
||||||
// Verify the current address is the address from the stack
|
// Verify the current address is the address from the stack
|
||||||
assert_eq!(test_addr, cpu.pc);
|
assert_eq!(test_addr, cpu.pc);
|
||||||
// Verify the stack pointer has moved
|
|
||||||
assert!(dbg!(cpu.sp.wrapping_sub(sp_orig)) == 0x2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,9 +129,9 @@ mod cf {
|
|||||||
let (mut cpu, _) = setup_environment();
|
let (mut cpu, _) = setup_environment();
|
||||||
// Test all valid addresses
|
// Test all valid addresses
|
||||||
for addr in 0x000..0xffe {
|
for addr in 0x000..0xffe {
|
||||||
// Call an address
|
// Jump to an address
|
||||||
cpu.jump(addr);
|
cpu.jump(addr);
|
||||||
// Verify the current address is the called address
|
// Verify the current address is the jump target address
|
||||||
assert_eq!(addr, cpu.pc);
|
assert_eq!(addr, cpu.pc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,15 +140,15 @@ mod cf {
|
|||||||
#[test]
|
#[test]
|
||||||
fn call() {
|
fn call() {
|
||||||
let test_addr = random::<u16>();
|
let test_addr = random::<u16>();
|
||||||
let (mut cpu, mut bus) = setup_environment();
|
let (mut cpu, _) = setup_environment();
|
||||||
// Save the current address
|
// Save the current address
|
||||||
let curr_addr = cpu.pc;
|
let curr_addr = cpu.pc;
|
||||||
// Call an address
|
// Call an address
|
||||||
cpu.call(test_addr, &mut bus);
|
cpu.call(test_addr);
|
||||||
// Verify the current address is the called address
|
// Verify the current address is the called address
|
||||||
assert_eq!(test_addr, cpu.pc);
|
assert_eq!(test_addr, cpu.pc);
|
||||||
// Verify the previous address was stored on the stack (sp+2)
|
// Verify the previous address was stored on the stack (sp+2)
|
||||||
let stack_addr: u16 = bus.read(cpu.sp.wrapping_add(2));
|
let stack_addr: u16 = cpu.stack.pop().expect("This should return test_addr");
|
||||||
assert_eq!(stack_addr, curr_addr);
|
assert_eq!(stack_addr, curr_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,7 +592,7 @@ mod math {
|
|||||||
for reg in 0..=0xff {
|
for reg in 0..=0xff {
|
||||||
let (x, y) = (reg & 0xf, reg >> 4);
|
let (x, y) = (reg & 0xf, reg >> 4);
|
||||||
// set the register under test to `word`
|
// set the register under test to `word`
|
||||||
(cpu.v[x], cpu.v[y]) = dbg!(0, word);
|
(cpu.v[x], cpu.v[y]) = (0, word);
|
||||||
|
|
||||||
cpu.shift_left(x, y);
|
cpu.shift_left(x, y);
|
||||||
|
|
||||||
|
@ -30,11 +30,11 @@ mod bus {
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn display() {
|
fn display() {
|
||||||
println!("{Charset}{Program}{Screen}{Stack}{Count}");
|
println!("{Charset}{Program}{Screen}{Count}");
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn debug() {
|
fn debug() {
|
||||||
println!("{Charset:?}{Program:?}{Screen:?}{Stack:?}{Count:?}");
|
println!("{Charset:?}{Program:?}{Screen:?}{Count:?}");
|
||||||
}
|
}
|
||||||
// lmao the things you do for test coverage
|
// lmao the things you do for test coverage
|
||||||
#[test]
|
#[test]
|
||||||
@ -44,13 +44,13 @@ mod bus {
|
|||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn ord() {
|
fn ord() {
|
||||||
assert_eq!(Stack, Charset.max(Program).max(Screen).max(Stack));
|
assert_eq!(Screen, Charset.max(Program).max(Screen));
|
||||||
assert!(Charset < Program && Program < Screen && Screen < Stack);
|
assert!(Charset < Program && Program < Screen);
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
fn hash() {
|
fn hash() {
|
||||||
let mut hasher = DefaultHasher::new();
|
let mut hasher = DefaultHasher::new();
|
||||||
Stack.hash(&mut hasher);
|
Program.hash(&mut hasher);
|
||||||
println!("{hasher:?}");
|
println!("{hasher:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user