dg6502/
bus.rs

1use std::fs::{self};
2use std::io::{Error, ErrorKind};
3
4/// The [Cpu](crate::Cpu) takes in a struct with a CPUMemory trait for dealing with memory reads and writes. Implement
5/// this trait if you would like to customize how reading or writing works.
6/// If your memory is just a 64KB buffer with no mapping/mirroring, you may want to use [BasicCPUMemory](crate::BasicCPUMemory).
7pub trait CPUMemory {
8    /// Reading from an address.
9    fn read(&self, address: u16) -> u8;
10    /// Writing from an address.
11    fn write(&mut self, address: u16, data: u8);
12}
13
14/// Memory is one contiguous 64KB buffer with no mapping or mirroring.
15pub struct BasicCPUMemory {
16    buffer: Vec<u8>
17}
18
19impl BasicCPUMemory {
20    /// For creating a memory buffer from a file. Specify an offset if you would like
21    /// your data to be loaded in from a specific start point; if you set this to 0,
22    /// it will begin loading data at 0x0.
23    pub fn from_file(path: &String, offset: u16) -> Result<Self, std::io::Error> {
24        match fs::read(path) {
25            Ok(mut buffer) => {
26                if buffer.len() > (65536 - offset as usize) {
27                    Err(Error::new(ErrorKind::Other, "File is too large to be loaded into 64KB buffer with current offset."))
28                } else {
29                    let mut memory: Vec<u8> = vec![0; 65536];
30                    let start = offset;
31                    for i in 0..buffer.len() {
32                        memory[i + start as usize] = memory[i];
33                    }
34                    buffer.resize(65536, 0);
35                    Ok(BasicCPUMemory {
36                        buffer: memory
37                    })
38                }
39            },
40            Err(err) => {
41                Err(err)
42            }
43        }
44
45    }
46}
47impl Default for BasicCPUMemory {
48    fn default() -> Self {
49        BasicCPUMemory { buffer: vec![0; 65536] }
50    }
51}
52
53
54impl TryFrom<Vec<u8>> for BasicCPUMemory {
55    type Error = ();
56
57    /// If you already have an existing Vec<u8> and would like to use it for your CPU memory.
58    /// If your Vec<u8> is too large this will error. If your Vec<u8> is too small it will
59    /// upsize your vector and fill in the unused memory with 0.
60    fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
61        if value.len() > 65536 {
62            Err(())
63        } else {
64            let mut buffer: Vec<u8> = vec![0; 65536];
65            for (index, ele) in value.iter().enumerate() {
66                buffer[index] = *ele;
67            }
68            Ok(BasicCPUMemory { buffer })
69        }
70    }
71}
72
73impl CPUMemory for BasicCPUMemory {
74    fn read(&self, address: u16) -> u8 {
75        self.buffer[address as usize]
76    }
77
78    fn write(&mut self, address: u16, data: u8) {
79        self.buffer[address as usize] = data;
80    }
81}