Implement a stack for emulation
This commit is contained in:
parent
3c6aad798c
commit
e31c05ac9b
4 changed files with 85 additions and 11 deletions
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/// Represents the display's width in pixels.
|
/// Represents the display's width in pixels.
|
||||||
const DISPLAY_WIDTH: usize = 64;
|
const DISPLAY_WIDTH: usize = 64;
|
||||||
|
|
||||||
|
@ -22,7 +21,7 @@ pub struct TerminalDisplay {
|
||||||
impl TerminalDisplay {
|
impl TerminalDisplay {
|
||||||
pub fn new() -> TerminalDisplay {
|
pub fn new() -> TerminalDisplay {
|
||||||
TerminalDisplay {
|
TerminalDisplay {
|
||||||
display_data: [false; DISPLAY_WIDTH * DISPLAY_HEIGHT]
|
display_data: [false; DISPLAY_WIDTH * DISPLAY_HEIGHT],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,4 +46,4 @@ impl Display for TerminalDisplay {
|
||||||
print!("\n")
|
print!("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
use crate::display::Display;
|
||||||
|
use crate::stack::Stack;
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::{Path};
|
use std::path::Path;
|
||||||
use crate::display::{Display};
|
|
||||||
|
|
||||||
const MEMORY_SIZE: usize = 4096;
|
const MEMORY_SIZE: usize = 4096;
|
||||||
const NUMBER_OF_REGISTERS: usize = 16;
|
const NUMBER_OF_REGISTERS: usize = 16;
|
||||||
|
@ -27,7 +28,10 @@ const FONT_SPRITES: [u8; 80] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
/// Emulator emulates the Chip8 CPU.
|
/// Emulator emulates the Chip8 CPU.
|
||||||
pub struct Emulator<D> where D: Display {
|
pub struct Emulator<D>
|
||||||
|
where
|
||||||
|
D: Display,
|
||||||
|
{
|
||||||
/// Memory represents the emulator's memory.
|
/// Memory represents the emulator's memory.
|
||||||
memory: [u8; MEMORY_SIZE],
|
memory: [u8; MEMORY_SIZE],
|
||||||
/// Registers holds the general purpose registers.
|
/// Registers holds the general purpose registers.
|
||||||
|
@ -44,10 +48,14 @@ pub struct Emulator<D> where D: Display {
|
||||||
/// The stack pointer register.
|
/// The stack pointer register.
|
||||||
stack_pointer: u8,
|
stack_pointer: u8,
|
||||||
/// The display_data holds all the data associated with the display
|
/// The display_data holds all the data associated with the display
|
||||||
display: D
|
display: D,
|
||||||
|
stack: Stack<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <D> Emulator<D> where D: Display {
|
impl<D> Emulator<D>
|
||||||
|
where
|
||||||
|
D: Display,
|
||||||
|
{
|
||||||
/// Creates a new `Emulator` instance.
|
/// Creates a new `Emulator` instance.
|
||||||
///
|
///
|
||||||
pub fn new(display: D) -> Emulator<D> {
|
pub fn new(display: D) -> Emulator<D> {
|
||||||
|
@ -60,6 +68,7 @@ impl <D> Emulator<D> where D: Display {
|
||||||
delay_timer: 0,
|
delay_timer: 0,
|
||||||
sound_timer: 0,
|
sound_timer: 0,
|
||||||
stack_pointer: 0,
|
stack_pointer: 0,
|
||||||
|
stack: Stack::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
emulator.load_font_data();
|
emulator.load_font_data();
|
||||||
|
@ -113,7 +122,7 @@ impl <D> Emulator<D> where D: Display {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::display::{TerminalDisplay};
|
use crate::display::TerminalDisplay;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
use crate::display::TerminalDisplay;
|
||||||
use crate::emulator::Emulator;
|
use crate::emulator::Emulator;
|
||||||
use env_logger;
|
use env_logger;
|
||||||
use crate::display::TerminalDisplay;
|
|
||||||
|
|
||||||
mod emulator;
|
|
||||||
mod display;
|
mod display;
|
||||||
|
mod emulator;
|
||||||
|
mod stack;
|
||||||
|
|
||||||
fn main() -> Result<(), anyhow::Error> {
|
fn main() -> Result<(), anyhow::Error> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
65
src/stack.rs
Normal file
65
src/stack.rs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
/// Implements a simple stack based on a vector.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Stack<T> {
|
||||||
|
storage: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Debug> Stack<T> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Stack {
|
||||||
|
storage: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pushes an element on the top of the stack
|
||||||
|
pub fn push(&mut self, element: T) {
|
||||||
|
self.storage.push(element)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the top element from the stack.
|
||||||
|
pub fn pop(&mut self) -> Option<T> {
|
||||||
|
self.storage.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
pub fn peek(&self) -> Option<&T> {
|
||||||
|
self.storage.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Size returns the size of the stack.
|
||||||
|
pub fn size(&self) -> usize {
|
||||||
|
self.storage.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is Empty returns true if the stack is empty.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.storage.len() == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn basic_operations() {
|
||||||
|
// Given
|
||||||
|
let mut stack = Stack::<u16>::new();
|
||||||
|
|
||||||
|
// Then
|
||||||
|
stack.push(15);
|
||||||
|
|
||||||
|
assert_eq!(1, stack.size());
|
||||||
|
assert_eq!(15u16, *stack.peek().unwrap());
|
||||||
|
|
||||||
|
let element = stack.pop();
|
||||||
|
assert_eq!(15u16, element.unwrap());
|
||||||
|
assert_eq!(0, stack.size());
|
||||||
|
assert_eq!(true, stack.is_empty());
|
||||||
|
|
||||||
|
let element = stack.pop();
|
||||||
|
assert_eq!(true, element.is_none())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue