rust8/chip8/
memory.rs

1use thiserror::Error;
2
3use super::constants::{INSTRUCTION_SIZE, MEMORY_SIZE, UNPROTECTED_MEMORY_START};
4use super::graphic::BitSlicePixelView;
5use super::instruction::Instruction;
6use crate::chip8::instruction::parser::InstructionParsingError;
7
8pub struct Memory {
9    pub raw_data: [u8; MEMORY_SIZE],
10}
11
12#[derive(Error, Debug)]
13pub enum ReadInstructionError {
14    #[error("instruction parsing error")]
15    ParseError(#[from] InstructionParsingError),
16    #[error("instruction address in protected memory area")]
17    AddressInProtectedMemoryArea(usize),
18    #[error("instruction address outside of the memory")]
19    AddressOutOfRange(usize),
20}
21
22#[derive(Error, Debug)]
23pub enum WriteError {
24    #[error("address range is inside of protected memory area")]
25    InProtectedMemoryArea(usize, usize),
26    #[error("address range is outside of the memory")]
27    OutOfRange(usize, usize),
28}
29
30impl Default for Memory {
31    fn default() -> Self {
32        Memory {
33            raw_data: [0; MEMORY_SIZE],
34        }
35    }
36}
37
38impl Memory {
39    pub fn new() -> Self {
40        Self::default()
41    }
42
43    pub fn clear(&mut self) {
44        self.raw_data.fill(0);
45    }
46
47    pub fn write_unrestricted(
48        &mut self,
49        data: &[u8],
50        write_address: usize,
51    ) -> Result<(), WriteError> {
52        self.raw_data
53            .get_mut(write_address..write_address + data.len())
54            .ok_or(WriteError::OutOfRange(
55                write_address,
56                write_address + data.len(),
57            ))?
58            .copy_from_slice(data);
59
60        Ok(())
61    }
62
63    pub fn write_restricted(
64        &mut self,
65        data: &[u8],
66        write_address: usize,
67    ) -> Result<(), WriteError> {
68        if write_address < UNPROTECTED_MEMORY_START {
69            return Err(WriteError::InProtectedMemoryArea(
70                write_address,
71                write_address + data.len(),
72            ));
73        }
74
75        self.write_unrestricted(data, write_address)
76    }
77
78    pub fn read_instruction(&self, address: usize) -> Result<Instruction, ReadInstructionError> {
79        if address < UNPROTECTED_MEMORY_START {
80            return Err(ReadInstructionError::AddressInProtectedMemoryArea(address));
81        }
82
83        let instruction_slice: &[u8; INSTRUCTION_SIZE] = self
84            .raw_data
85            .get(address..address + INSTRUCTION_SIZE)
86            .ok_or(ReadInstructionError::AddressOutOfRange(address))?
87            .try_into()
88            .unwrap();
89
90        Ok(Instruction::try_from(instruction_slice)?)
91    }
92
93    pub fn read_sprite(&self, address: usize, byte_count: usize) -> Option<BitSlicePixelView> {
94        let slice = self.raw_data.get(address..address + byte_count)?;
95
96        Some(BitSlicePixelView::new_from_byte_slice(slice, 8, byte_count))
97    }
98}