rs6502 0.3.4

A 6502 Microprocessor tool suite. Includes a Disassembler, Assembler and Emulator.
Documentation
use byteorder::{ByteOrder, LittleEndian};

#[derive(Debug, PartialEq)]
pub struct StackError {
    message: String,
}

impl StackError {
    pub fn overflow() -> StackError {
        StackError { message: "Stack overflow occurred".into() }
    }

    pub fn underflow() -> StackError {
        StackError { message: "Stack underflow; unable to pop from empty stack".into() }
    }
}

pub type StackPushResult = Result<(), StackError>;
pub type StackPopResult<T> = Result<T, StackError>;

pub struct Stack {
    pub pointer: usize,
}

impl Stack {
    pub fn new() -> Stack {
        Stack { pointer: 0xFF }
    }

    pub fn push(&mut self, stack_area: &mut [u8], val: u8) -> StackPushResult {
        if self.pointer > 0x00 {
            stack_area[self.pointer] = val;
            self.pointer -= 0x01;

            Ok(())
        } else {
            Err(StackError::overflow())
        }
    }

    pub fn push_u16(&mut self, stack_area: &mut [u8], val: u16) -> StackPushResult {
        if self.pointer >= 0x01 {
            LittleEndian::write_u16(&mut stack_area[self.pointer - 0x01..], val);
            self.pointer -= 0x02;

            Ok(())
        } else {
            Err(StackError::overflow())
        }
    }

    pub fn pop(&mut self, stack_area: &[u8]) -> StackPopResult<u8> {
        if self.pointer == 0xFF {
            Err(StackError::underflow())
        } else {
            self.pointer += 0x01;
            let val = stack_area[self.pointer];

            Ok(val)
        }
    }

    pub fn pop_u16(&mut self, stack_area: &mut [u8]) -> StackPopResult<u16> {
        if self.pointer <= 0xFE {
            self.pointer += 0x01;
            let result = LittleEndian::read_u16(&stack_area[self.pointer..]);
            self.pointer += 0x01;

            Ok(result)
        } else {
            Err(StackError::underflow())
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn can_push() {
        let mut stack_area = [0u8; 0x100];
        let mut stack = Stack::new();

        stack.push(&mut stack_area, 55);

        assert_eq!(55, stack_area[0xFF]);
    }

    #[test]
    fn can_push_then_pop() {
        let mut stack_area = [0u8; 0x100];
        let mut stack = Stack::new();

        stack.push(&mut stack_area, 55);
        let val = stack.pop(&mut stack_area).unwrap();

        assert_eq!(55, val);
    }

    #[test]
    fn can_push_then_pop_multiple() {
        let mut stack_area = [0u8; 0x100];
        let mut stack = Stack::new();

        stack.push(&mut stack_area, 5);
        stack.push(&mut stack_area, 10);
        stack.push(&mut stack_area, 15);
        stack.push(&mut stack_area, 20);

        let twenty = stack.pop(&mut stack_area).unwrap();
        let fifteen = stack.pop(&mut stack_area).unwrap();
        let ten = stack.pop(&mut stack_area).unwrap();
        let five = stack.pop(&mut stack_area).unwrap();

        assert_eq!(20, twenty);
        assert_eq!(15, fifteen);
        assert_eq!(10, ten);
        assert_eq!(5, five);
    }

    #[test]
    fn can_not_pop_empty_stack() {
        let mut stack_area = [0u8; 0x100];
        let mut stack = Stack::new();

        let result = stack.pop(&mut stack_area);

        assert_eq!(Err(StackError::underflow()), result);
    }

    #[test]
    fn can_not_push_to_full_stack() {
        let mut stack_area = [0u8; 0x100];
        let mut stack = Stack::new();

        for _ in 0..0xFF {
            stack.push(&mut stack_area, 5);
        }

        let result = stack.push(&mut stack_area, 5);

        assert_eq!(Err(StackError::overflow()), result);
    }

    #[test]
    fn can_push_u16() {
        let mut stack_area = [0u8; 0x100];
        let mut stack = Stack::new();

        stack.push_u16(&mut stack_area, 0x4400);

        assert_eq!(0x44, stack_area[0xFF]);
        assert_eq!(0x00, stack_area[0xFE]);
    }

    #[test]
    fn can_push_then_pop_u16() {
        let mut stack_area = [0u8; 0x100];
        let mut stack = Stack::new();

        stack.push_u16(&mut stack_area, 0x4400);
        let result = stack.pop_u16(&mut stack_area).unwrap();

        assert_eq!(0x4400, result);
    }
}