vcpu/core/
ram_file.rs

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}