1use std::{
2 env,
3 fs,
4 fs::File,
5 io::{Read, Seek, SeekFrom, Write},
6 ops::RangeInclusive,
7};
8
9use crate::core::bus::BusItem;
10
11pub struct RamFile {
12 address_range: RangeInclusive<u16>,
13 file: File,
14}
15
16impl RamFile {
17 pub fn new(address_range: RangeInclusive<u16>) -> Self {
18 let exe = env::current_exe().unwrap_or_default();
19 let exe_dir = exe.parent().unwrap();
20 let tmp_dir = exe_dir.join("tmp");
21 fs::create_dir_all(&tmp_dir).expect("failed to create tmp_dir");
22 let file_path = tmp_dir.join("ram");
23
24 let mut file = File::options()
25 .write(true)
26 .read(true)
27 .create(true)
28 .truncate(false)
29 .open(&file_path)
30 .unwrap();
31 let metadata = fs::metadata(&file_path).unwrap();
32
33 if metadata.len() == 0 {
34 file.set_len(address_range.len() as u64).unwrap();
35 for _ in address_range.clone() {
36 file.write_all(&[0]).unwrap();
37 }
38 }
39
40 file.sync_all().unwrap();
41
42 Self { address_range, file }
43 }
44
45 pub fn write_all(&mut self, address: u16, data: &[u8]) {
46 self.file.seek(SeekFrom::Start(address as u64)).unwrap();
47 self.file.write_all(data).unwrap();
48 }
49}
50
51impl BusItem for RamFile {
52 fn address_range(&self) -> &RangeInclusive<u16> {
53 &self.address_range
54 }
55
56 fn read(&mut self, address: u16, _read_only: bool) -> u8 {
57 let mut buffer = [0; 1];
58 self.file.seek(SeekFrom::Start(address as u64)).unwrap();
59 self.file.read_exact(&mut buffer).unwrap();
60 buffer[0]
61 }
62
63 fn write(&mut self, address: u16, value: u8) {
64 self.file.seek(SeekFrom::Start(address as u64)).unwrap();
65 self.file.write_all(&[value]).unwrap();
66 self.file.sync_all().unwrap();
67 }
68}