Remove fox32core support
This works around the issue with building on Windows.
This commit is contained in:
parent
16b43cc87a
commit
bd7eba3ddb
6
.github/workflows/fox32-unstable-linux.yml
vendored
6
.github/workflows/fox32-unstable-linux.yml
vendored
|
@ -13,12 +13,6 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Check out fox32core
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: fox32-arch/fox32core
|
||||
path: ./fox32core
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
|
|
20
.github/workflows/fox32-unstable-windows.yml
vendored
20
.github/workflows/fox32-unstable-windows.yml
vendored
|
@ -7,34 +7,22 @@ on:
|
|||
name: fox32 Unstable - Windows
|
||||
|
||||
jobs:
|
||||
fox32-unstable-linux:
|
||||
fox32-unstable-windows:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Check out fox32core
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: fox32-arch/fox32core
|
||||
path: ./fox32core
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
target: x86_64-pc-windows-gnu
|
||||
|
||||
- name: Install libgtk-3-dev, libasound2-dev, and mingw-w64
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y libgtk-3-dev libasound2-dev mingw-w64
|
||||
|
||||
- name: Build
|
||||
run: cargo build --release --target x86_64-pc-windows-gnu
|
||||
run: cargo build --release
|
||||
|
||||
- name: Upload Artifact
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: fox32.exe
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,6 +1,4 @@
|
|||
**/.vscode/
|
||||
|
||||
**/fox32core/
|
||||
|
||||
**/debug/
|
||||
**/target/
|
||||
|
|
102
Cargo.lock
generated
102
Cargo.lock
generated
|
@ -51,15 +51,6 @@ dependencies = [
|
|||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.53"
|
||||
|
@ -199,17 +190,6 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
|
@ -225,18 +205,14 @@ dependencies = [
|
|||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -397,21 +373,6 @@ dependencies = [
|
|||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim 0.8.0",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "claxon"
|
||||
version = "0.4.3"
|
||||
|
@ -706,7 +667,7 @@ dependencies = [
|
|||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim 0.10.0",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
|
@ -815,19 +776,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.2"
|
||||
|
@ -920,7 +868,6 @@ name = "fox32"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"fox32core",
|
||||
"image",
|
||||
"log",
|
||||
"pixels",
|
||||
|
@ -932,15 +879,6 @@ dependencies = [
|
|||
"winit_input_helper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fox32core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.19"
|
||||
|
@ -1298,12 +1236,6 @@ version = "3.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
|
@ -2544,12 +2476,6 @@ version = "0.1.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
|
@ -2589,15 +2515,6 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.30"
|
||||
|
@ -2733,12 +2650,6 @@ version = "0.2.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "vergen"
|
||||
version = "6.0.2"
|
||||
|
@ -3045,17 +2956,6 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c4fb54e6113b6a8772ee41c3404fb0301ac79604489467e0a9ce1f3e97c24ae"
|
||||
dependencies = [
|
||||
"either",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wide"
|
||||
version = "0.6.5"
|
||||
|
|
|
@ -8,7 +8,6 @@ build = "build.rs"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
fox32core = { path = "./fox32core" }
|
||||
image = "0.24"
|
||||
log = "0.4"
|
||||
pixels = "0.9.0"
|
||||
|
|
|
@ -12,9 +12,7 @@
|
|||
|
||||
### Building
|
||||
|
||||
Clone this repository, `cd` into it, then clone the [fox32core](https://github.com/fox32-arch/fox32core) repository in a folder called `fox32core`.
|
||||
|
||||
After that, just run `cargo build --release`. The resulting binary will be saved as `target/release/fox32`
|
||||
Simply run `cargo build --release`. The resulting binary will be saved as `target/release/fox32`. You can also run `cargo run --release` if you want to run it directly.
|
||||
|
||||
### Usage
|
||||
|
||||
|
|
15
src/bus.rs
15
src/bus.rs
|
@ -6,7 +6,7 @@ use std::sync::{Arc, Mutex};
|
|||
use std::io::{Write, stdout};
|
||||
|
||||
pub struct Bus {
|
||||
pub memory: Box<dyn Memory>,
|
||||
pub memory: Memory,
|
||||
|
||||
pub disk_controller: DiskController,
|
||||
|
||||
|
@ -99,7 +99,7 @@ impl Bus {
|
|||
panic!("invalid disk ID");
|
||||
}
|
||||
match &self.disk_controller.disk[id as usize] {
|
||||
Some(disk) => disk.size() as u32, // return size if this disk is inserted
|
||||
Some(_) => self.disk_controller.get_size(id) as u32, // return size if this disk is inserted
|
||||
None => 0, // return 0 if this disk is not inserted
|
||||
}
|
||||
}
|
||||
|
@ -226,14 +226,3 @@ impl Bus {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fox32core::Bus for Bus {
|
||||
fn io_read(&mut self, port: u32) -> Option<u32> {
|
||||
Some(self.read_io(port))
|
||||
}
|
||||
|
||||
fn io_write(&mut self, port: u32, value: u32) -> Option<()> {
|
||||
self.write_io(port, value);
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
|
22
src/disk.rs
22
src/disk.rs
|
@ -20,10 +20,6 @@ impl Disk {
|
|||
current_sector: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> u64 {
|
||||
self.size
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DiskController {
|
||||
|
@ -33,7 +29,7 @@ pub struct DiskController {
|
|||
|
||||
impl DiskController {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
DiskController {
|
||||
disk: [None, None, None, None],
|
||||
buffer_pointer: 0x00000000
|
||||
}
|
||||
|
@ -60,24 +56,20 @@ impl DiskController {
|
|||
self.disk[disk_id as usize] = None;
|
||||
}
|
||||
|
||||
fn disk_mut(&mut self, disk_id: u8) -> &mut Disk {
|
||||
self.disk[disk_id as usize].as_mut().expect("attempted to access unmounted disk")
|
||||
pub fn get_size(&self, disk_id: u8) -> u64 {
|
||||
self.disk[disk_id as usize].as_ref().expect("attempted to access unmounted disk").size
|
||||
}
|
||||
|
||||
pub fn get_size(&mut self, disk_id: u8) -> u64 {
|
||||
self.disk_mut(disk_id).size
|
||||
}
|
||||
pub fn get_current_sector(&mut self, disk_id: u8) -> u32 {
|
||||
self.disk_mut(disk_id).current_sector
|
||||
pub fn get_current_sector(&self, disk_id: u8) -> u32 {
|
||||
self.disk[disk_id as usize].as_ref().expect("attempted to access unmounted disk").current_sector
|
||||
}
|
||||
pub fn set_current_sector(&mut self, disk_id: u8, sector: u32) {
|
||||
let disk = self.disk_mut(disk_id);
|
||||
let mut disk = self.disk[disk_id as usize].as_mut().expect("attempted to access unmounted disk");
|
||||
disk.current_sector = sector;
|
||||
disk.file.seek(SeekFrom::Start(sector as u64 * 512)).expect("attempted to seek to sector beyond edge of disk");
|
||||
}
|
||||
|
||||
pub fn read_into_memory(&mut self, disk_id: u8, ram: &mut MemoryRam) -> usize {
|
||||
let disk = self.disk_mut(disk_id);
|
||||
let disk = self.disk[disk_id as usize].as_mut().expect("attempted to access unmounted disk");
|
||||
let mut temp_buffer = [0u8; 512];
|
||||
|
||||
let number_of_bytes_read = disk.file.read(&mut temp_buffer).unwrap();
|
||||
|
|
64
src/main.rs
64
src/main.rs
|
@ -7,8 +7,6 @@ pub mod cpu;
|
|||
pub mod keyboard;
|
||||
pub mod mouse;
|
||||
pub mod disk;
|
||||
pub mod runtime;
|
||||
pub mod wrapped;
|
||||
|
||||
use audio::Audio;
|
||||
use bus::Bus;
|
||||
|
@ -16,13 +14,8 @@ use cpu::{Cpu, Interrupt};
|
|||
use keyboard::Keyboard;
|
||||
use mouse::Mouse;
|
||||
use disk::DiskController;
|
||||
use memory::{MEMORY_RAM_START, MEMORY_ROM_START, MemoryRam, Memory, MemoryStub, MemoryBuffer};
|
||||
use runtime::Runtime;
|
||||
use wrapped::*;
|
||||
use memory::{MEMORY_RAM_START, MEMORY_ROM_START, MemoryRam, Memory};
|
||||
|
||||
use std::io::Write;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, mpsc, Mutex};
|
||||
use std::thread;
|
||||
use std::time;
|
||||
|
@ -92,8 +85,9 @@ fn main() {
|
|||
|
||||
let audio = Arc::new(Mutex::new(Audio::new()));
|
||||
|
||||
let memory = Memory::new(read_rom().as_slice());
|
||||
let mut bus = Bus {
|
||||
memory: Box::new(MemoryStub()),
|
||||
memory: memory.clone(),
|
||||
audio: audio.clone(),
|
||||
disk_controller: DiskController::new(),
|
||||
keyboard: keyboard.clone(),
|
||||
|
@ -109,38 +103,6 @@ fn main() {
|
|||
}
|
||||
}
|
||||
|
||||
let (mut runtime, memory): (Box<dyn Runtime>, MemoryWrapped) = {
|
||||
if env::var("FOX32_RUNTIME").unwrap_or_default() == "core" {
|
||||
|
||||
println!("Using \"fox32core\" runtime");
|
||||
|
||||
let bus_wrapped = BusWrapped::new(bus);
|
||||
let state = fox32core::State::new(bus_wrapped.clone());
|
||||
*state.debug() = env::var("FOX32_DEBUG").is_ok();
|
||||
let state_wrapped = CoreWrapped::new(state);
|
||||
let state_memory_wrapped = MemoryWrapped::new(CoreMemoryWrapped::new(state_wrapped.clone()));
|
||||
|
||||
mem::drop(mem::replace(&mut bus_wrapped.deref().borrow_mut().memory, Box::new(state_memory_wrapped.clone())));
|
||||
|
||||
(Box::new(state_wrapped.clone()), state_memory_wrapped.clone())
|
||||
|
||||
} else {
|
||||
|
||||
println!("Using \"rust\" runtime");
|
||||
|
||||
let memory = MemoryWrapped::new(MemoryBuffer::new());
|
||||
|
||||
mem::drop(mem::replace(&mut bus.memory, Box::new(memory.clone())));
|
||||
|
||||
(Box::new(Cpu::new(bus)), memory)
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
memory.rom().as_mut_slice().write(read_rom().as_slice()).expect("failed to write ROM");
|
||||
|
||||
runtime.halted_set(false);
|
||||
|
||||
let memory_audio = memory.clone();
|
||||
let memory_cpu = memory.clone();
|
||||
let memory_eventloop = memory.clone();
|
||||
|
@ -155,6 +117,8 @@ fn main() {
|
|||
let rom_top_address = rom_bottom_address + rom_size - 1;
|
||||
println!("ROM: {:.2} KiB mapped at {:#010X}-{:#010X}", rom_size / 1024, rom_bottom_address, rom_top_address);
|
||||
|
||||
let mut cpu = Cpu::new(bus);
|
||||
|
||||
let event_loop = EventLoop::new();
|
||||
let mut input = WinitInputHelper::new();
|
||||
let icon = image::load_from_memory(include_bytes!("32.png")).unwrap();
|
||||
|
@ -177,26 +141,26 @@ fn main() {
|
|||
Pixels::new(WIDTH as u32, HEIGHT as u32, surface_texture).unwrap()
|
||||
};
|
||||
|
||||
let (interrupt_sender, interrupt_receiver) = mpsc::channel::<u16>();
|
||||
let (interrupt_sender, interrupt_receiver) = mpsc::channel::<Interrupt>();
|
||||
|
||||
let builder = thread::Builder::new().name("cpu".to_string());
|
||||
builder.spawn({
|
||||
move || {
|
||||
loop {
|
||||
while !runtime.halted_get() {
|
||||
while !cpu.halted {
|
||||
if let Ok(interrupt) = interrupt_receiver.try_recv() {
|
||||
runtime.raise(interrupt);
|
||||
cpu.interrupt(interrupt);
|
||||
}
|
||||
runtime.step();
|
||||
cpu.execute_memory_instruction();
|
||||
}
|
||||
if !runtime.flag_interrupt_get() {
|
||||
if !cpu.flag.interrupt {
|
||||
// the cpu was halted and interrupts are disabled
|
||||
// at this point, the cpu is dead and cannot resume, break out of the loop
|
||||
break;
|
||||
}
|
||||
if let Ok(interrupt) = interrupt_receiver.recv() {
|
||||
runtime.halted_set(false);
|
||||
runtime.raise(interrupt);
|
||||
cpu.halted = false;
|
||||
cpu.interrupt(interrupt);
|
||||
} else {
|
||||
// sender is closed, break
|
||||
break;
|
||||
|
@ -226,7 +190,7 @@ fn main() {
|
|||
let buffer = SamplesBuffer::new(1, 22050, current_buffer);
|
||||
sink.append(buffer);
|
||||
drop(audio_lock);
|
||||
interrupt_sender_audio.send(0xFE).unwrap(); // audio interrupt, swap audio buffers
|
||||
interrupt_sender_audio.send(Interrupt::Request(0xFE)).unwrap(); // audio interrupt, swap audio buffers
|
||||
thread::sleep(time::Duration::from_millis(500));
|
||||
}
|
||||
}
|
||||
|
@ -240,7 +204,7 @@ fn main() {
|
|||
if let Event::MainEventsCleared = event {
|
||||
// update internal state and request a redraw
|
||||
|
||||
match interrupt_sender.send(0xFF) { // vsync interrupt
|
||||
match interrupt_sender.send(Interrupt::Request(0xFF)) { // vsync interrupt
|
||||
Ok(_) => {},
|
||||
Err(_) => {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
|
|
174
src/memory.rs
174
src/memory.rs
|
@ -1,6 +1,7 @@
|
|||
// memory.rs
|
||||
|
||||
use std::alloc;
|
||||
use crate::error;
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::sync::Arc;
|
||||
use std::io::Write;
|
||||
|
@ -15,104 +16,103 @@ pub const MEMORY_ROM_START: usize = 0xF0000000;
|
|||
pub type MemoryRam = [u8; MEMORY_RAM_SIZE];
|
||||
pub type MemoryRom = [u8; MEMORY_ROM_SIZE];
|
||||
|
||||
pub trait Memory: Send {
|
||||
fn ram(&self) -> &mut MemoryRam;
|
||||
fn rom(&self) -> &mut MemoryRom;
|
||||
struct MemoryInner {
|
||||
ram: Box<MemoryRam>,
|
||||
rom: Box<MemoryRom>,
|
||||
}
|
||||
|
||||
impl dyn Memory {
|
||||
fn arrayslice<T, const ARRAY_LEN: usize, const SLICE_LEN: usize>(array: &mut [T; ARRAY_LEN], offset: usize) -> &mut [T; SLICE_LEN] {
|
||||
assert!(ARRAY_LEN >= SLICE_LEN + offset, "attempted slice [{}..{}] of array with length {}", offset, offset + SLICE_LEN, ARRAY_LEN);
|
||||
unsafe { &mut *array.as_mut_ptr().offset(offset as isize).cast() }
|
||||
}
|
||||
|
||||
fn find<const S: usize>(&self, address: u32) -> Option<&mut [u8; S]> {
|
||||
let head = address as usize;
|
||||
let tail = head.checked_add(S).expect("unexpected overflow computing tail address");
|
||||
if head >= MEMORY_RAM_START && tail - MEMORY_RAM_START <= MEMORY_RAM_SIZE {
|
||||
return Self::arrayslice(self.ram(), head - MEMORY_RAM_START).into()
|
||||
}
|
||||
if head >= MEMORY_ROM_START && tail - MEMORY_ROM_START <= MEMORY_ROM_SIZE {
|
||||
return Self::arrayslice(self.rom(), head - MEMORY_ROM_START).into()
|
||||
}
|
||||
return None
|
||||
}
|
||||
fn find_unwrapped<const S: usize>(&self, address: u32) -> &mut [u8; S] {
|
||||
self.find(address).unwrap_or_else(|| panic!("attempted to access unmapped memory at {:#010X}", address))
|
||||
}
|
||||
|
||||
pub fn read_8(&self, address: u32) -> u8 { u8::from_le_bytes(*self.find_unwrapped(address)) }
|
||||
pub fn read_16(&self, address: u32) -> u16 { u16::from_le_bytes(*self.find_unwrapped(address)) }
|
||||
pub fn read_32(&self, address: u32) -> u32 { u32::from_le_bytes(*self.find_unwrapped(address)) }
|
||||
|
||||
pub fn write_8(&self, address: u32, value: u8) { *self.find_unwrapped(address) = u8::to_le_bytes(value) }
|
||||
pub fn write_16(&self, address: u32, value: u16) { *self.find_unwrapped(address) = u16::to_le_bytes(value) }
|
||||
pub fn write_32(&self, address: u32, value: u32) { *self.find_unwrapped(address) = u32::to_le_bytes(value) }
|
||||
|
||||
pub fn dump(&self) {
|
||||
File::create("memory.dump")
|
||||
.expect("failed to open memory dump file")
|
||||
.write_all(self.ram())
|
||||
.expect("failed to write memory dump file");
|
||||
impl MemoryInner {
|
||||
pub fn new(rom: &[u8]) -> Self {
|
||||
let mut this = Self {
|
||||
// HACK: allocate directly on the heap to avoid a stack overflow
|
||||
// at runtime while trying to move around a 64MB array
|
||||
ram: unsafe { Box::from_raw(Box::into_raw(vec![0u8; MEMORY_RAM_SIZE].into_boxed_slice()) as *mut MemoryRam) },
|
||||
rom: unsafe { Box::from_raw(Box::into_raw(vec![0u8; MEMORY_ROM_SIZE].into_boxed_slice()) as *mut MemoryRom) },
|
||||
};
|
||||
this.rom.as_mut_slice().write(rom).expect("failed to copy ROM to memory");
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
struct MemoryBufferInner {
|
||||
ram: *mut MemoryRam,
|
||||
rom: *mut MemoryRom,
|
||||
#[derive(Clone)]
|
||||
pub struct Memory(Arc<UnsafeCell<MemoryInner>>);
|
||||
|
||||
// SAFETY: once MemoryInner is initialzed, there is no way to modify the Box
|
||||
// pointers it contains and it does not matter if contents of the byte
|
||||
// arrays are corrupted
|
||||
unsafe impl Send for Memory {}
|
||||
unsafe impl Sync for Memory {}
|
||||
|
||||
impl Memory {
|
||||
pub fn new(rom: &[u8]) -> Self {
|
||||
Self(Arc::new(UnsafeCell::new(MemoryInner::new(rom))))
|
||||
}
|
||||
|
||||
static MEMORY_RAM_LAYOUT: alloc::Layout = alloc::Layout::new::<MemoryRam>();
|
||||
static MEMORY_ROM_LAYOUT: alloc::Layout = alloc::Layout::new::<MemoryRom>();
|
||||
|
||||
impl Default for MemoryBufferInner {
|
||||
fn default() -> Self {
|
||||
unsafe {
|
||||
let ram = alloc::alloc_zeroed(MEMORY_RAM_LAYOUT);
|
||||
if ram.is_null() { alloc::handle_alloc_error(MEMORY_RAM_LAYOUT) }
|
||||
|
||||
let rom = alloc::alloc_zeroed(MEMORY_ROM_LAYOUT);
|
||||
if rom.is_null() { alloc::handle_alloc_error(MEMORY_ROM_LAYOUT) }
|
||||
|
||||
Self { ram: ram.cast(), rom: rom.cast() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for MemoryBufferInner {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
alloc::dealloc(self.ram.cast(), MEMORY_RAM_LAYOUT);
|
||||
alloc::dealloc(self.rom.cast(), MEMORY_ROM_LAYOUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub struct MemoryBuffer(Arc<UnsafeCell<MemoryBufferInner>>);
|
||||
|
||||
unsafe impl Send for MemoryBuffer {}
|
||||
unsafe impl Sync for MemoryBuffer {}
|
||||
|
||||
impl MemoryBuffer {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn inner(&self) -> &mut MemoryBufferInner {
|
||||
fn inner(&self) -> &mut MemoryInner {
|
||||
unsafe { &mut *self.0.get() }
|
||||
}
|
||||
|
||||
pub fn ram(&self) -> &mut MemoryRam { &mut self.inner().ram }
|
||||
pub fn rom(&self) -> &mut MemoryRom { &mut self.inner().rom }
|
||||
|
||||
pub fn dump(&self) {
|
||||
let mut file = File::create("memory.dump").expect("failed to open memory dump file");
|
||||
file.write_all(self.ram()).expect("failed to write memory dump file");
|
||||
}
|
||||
|
||||
impl Memory for MemoryBuffer {
|
||||
fn ram(&self) -> &mut MemoryRam { unsafe { &mut *self.inner().ram } }
|
||||
fn rom(&self) -> &mut MemoryRom { unsafe { &mut *self.inner().rom } }
|
||||
pub fn read_8(&self, address: u32) -> u8 {
|
||||
let address = address as usize;
|
||||
|
||||
let result = if address >= MEMORY_ROM_START && address < MEMORY_ROM_START + MEMORY_ROM_SIZE {
|
||||
self.rom().get(address - MEMORY_ROM_START)
|
||||
} else {
|
||||
self.ram().get(address - MEMORY_RAM_START)
|
||||
};
|
||||
|
||||
match result {
|
||||
Some(value) => {
|
||||
*value
|
||||
}
|
||||
None => {
|
||||
error(&format!("attempting to read from unmapped memory address: {:#010X}", address));
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn read_16(&self, address: u32) -> u16 {
|
||||
(self.read_8(address) as u16) |
|
||||
(self.read_8(address + 1) as u16) << 8
|
||||
}
|
||||
pub fn read_32(&self, address: u32) -> u32 {
|
||||
(self.read_8(address) as u32) |
|
||||
(self.read_8(address + 1) as u32) << 8 |
|
||||
(self.read_8(address + 2) as u32) << 16 |
|
||||
(self.read_8(address + 3) as u32) << 24
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct MemoryStub();
|
||||
pub fn write_8(&self, address: u32, byte: u8) {
|
||||
let address = address as usize;
|
||||
|
||||
impl Memory for MemoryStub {
|
||||
fn ram(&self) -> &mut MemoryRam { unimplemented!() }
|
||||
fn rom(&self) -> &mut MemoryRom { unimplemented!() }
|
||||
if address >= MEMORY_ROM_START && address < MEMORY_ROM_START + MEMORY_ROM_SIZE {
|
||||
error(&format!("attempting to write to ROM address: {:#010X}", address));
|
||||
}
|
||||
|
||||
match self.ram().get_mut(address - MEMORY_RAM_START) {
|
||||
Some(value) => {
|
||||
*value = byte;
|
||||
}
|
||||
None => {
|
||||
error(&format!("attempting to write to unmapped memory address: {:#010X}", address));
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn write_16(&self, address: u32, half: u16) {
|
||||
self.write_8(address, (half & 0x00FF) as u8);
|
||||
self.write_8(address + 1, (half >> 8) as u8);
|
||||
}
|
||||
pub fn write_32(&self, address: u32, word: u32) {
|
||||
self.write_8(address, (word & 0x000000FF) as u8);
|
||||
self.write_8(address + 1, ((word & 0x0000FF00) >> 8) as u8);
|
||||
self.write_8(address + 2, ((word & 0x00FF0000) >> 16) as u8);
|
||||
self.write_8(address + 3, ((word & 0xFF000000) >> 24) as u8);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
// runtime.rs
|
||||
|
||||
pub trait Runtime: Send {
|
||||
fn halted_get(&mut self) -> bool;
|
||||
fn halted_set(&mut self, halted: bool);
|
||||
|
||||
fn flag_interrupt_get(&mut self) -> bool;
|
||||
fn flag_interrupt_set(&mut self, flag_interrupt: bool);
|
||||
|
||||
fn raise(&mut self, vector: u16);
|
||||
|
||||
fn step(&mut self);
|
||||
}
|
||||
|
||||
impl Runtime for crate::Cpu {
|
||||
fn halted_get(&mut self) -> bool {
|
||||
self.halted
|
||||
}
|
||||
fn halted_set(&mut self, halted: bool) {
|
||||
self.halted = halted
|
||||
}
|
||||
|
||||
fn flag_interrupt_get(&mut self) -> bool {
|
||||
self.flag.interrupt
|
||||
}
|
||||
fn flag_interrupt_set(&mut self, flag_interrupt: bool) {
|
||||
self.flag.interrupt = flag_interrupt
|
||||
}
|
||||
|
||||
fn raise(&mut self, vector: u16) {
|
||||
self.interrupt(crate::Interrupt::Request(vector as u8));
|
||||
}
|
||||
|
||||
fn step(&mut self) {
|
||||
self.execute_memory_instruction();
|
||||
}
|
||||
}
|
||||
|
||||
impl Runtime for fox32core::State {
|
||||
fn halted_get(&mut self) -> bool {
|
||||
*self.halted()
|
||||
}
|
||||
fn halted_set(&mut self, halted: bool) {
|
||||
*self.halted() = halted;
|
||||
}
|
||||
|
||||
fn flag_interrupt_get(&mut self) -> bool {
|
||||
*self.flag_interrupt()
|
||||
}
|
||||
fn flag_interrupt_set(&mut self, flag_interrupt: bool) {
|
||||
*self.flag_interrupt() = flag_interrupt;
|
||||
}
|
||||
|
||||
fn raise(&mut self, vector: u16) {
|
||||
match fox32core::State::raise(self, vector) {
|
||||
Some(fox32core::Error::InterruptsDisabled) | None => {}
|
||||
Some(error) => {
|
||||
panic!("fox32core failed to raise interrupt {:#06X}: {}", vector, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn step(&mut self) {
|
||||
if let Some(error) = fox32core::State::step(self) {
|
||||
panic!("fox32core failed to execute next instruction: {}", error);
|
||||
}
|
||||
}
|
||||
}
|
116
src/wrapped.rs
116
src/wrapped.rs
|
@ -1,116 +0,0 @@
|
|||
// wrapped.rs
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::cell::RefCell;
|
||||
use std::cell::UnsafeCell;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::bus::Bus;
|
||||
use crate::memory::*;
|
||||
use crate::runtime::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct MemoryWrapped(Arc<dyn Memory>);
|
||||
|
||||
unsafe impl Send for MemoryWrapped {}
|
||||
unsafe impl Sync for MemoryWrapped {}
|
||||
|
||||
impl MemoryWrapped {
|
||||
pub fn new(memory: impl Memory + 'static) -> Self {
|
||||
Self(Arc::new(memory))
|
||||
}
|
||||
}
|
||||
|
||||
impl Memory for MemoryWrapped {
|
||||
fn ram(&self) -> &mut MemoryRam { self.0.ram() }
|
||||
fn rom(&self) -> &mut MemoryRom { self.0.rom() }
|
||||
}
|
||||
|
||||
impl Memory for fox32core::State {
|
||||
fn ram(&self) -> &mut MemoryRam { self.memory_ram() }
|
||||
fn rom(&self) -> &mut MemoryRom { self.memory_rom() }
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BusWrapped(Arc<RefCell<Bus>>);
|
||||
|
||||
impl BusWrapped {
|
||||
pub fn new(bus: Bus) -> Self {
|
||||
Self(Arc::new(RefCell::new(bus)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for BusWrapped {
|
||||
type Target = RefCell<Bus>;
|
||||
fn deref(&self) -> &Self::Target { &self.0 }
|
||||
}
|
||||
|
||||
impl fox32core::Bus for BusWrapped {
|
||||
fn io_read(&mut self, port: u32) -> Option<u32> {
|
||||
self.borrow_mut().io_read(port)
|
||||
}
|
||||
fn io_write(&mut self, port: u32, value: u32) -> Option<()> {
|
||||
self.borrow_mut().io_write(port, value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CoreWrapped(Arc<UnsafeCell<fox32core::State>>);
|
||||
|
||||
unsafe impl Send for CoreWrapped {}
|
||||
|
||||
impl CoreWrapped {
|
||||
pub fn new(state: fox32core::State) -> Self {
|
||||
Self(Arc::new(UnsafeCell::new(state)))
|
||||
}
|
||||
|
||||
fn inner(&self) -> *mut fox32core::State {
|
||||
self.0.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl Memory for CoreWrapped {
|
||||
fn ram(&self) -> &mut MemoryRam { unsafe { (*self.inner()).ram() } }
|
||||
fn rom(&self) -> &mut MemoryRom { unsafe { (*self.inner()).rom() } }
|
||||
}
|
||||
|
||||
impl Runtime for CoreWrapped {
|
||||
fn halted_get(&mut self) -> bool {
|
||||
unsafe { (*self.inner()).halted_get() }
|
||||
}
|
||||
fn halted_set(&mut self, halted: bool) {
|
||||
unsafe { (*self.inner()).halted_set(halted) }
|
||||
}
|
||||
|
||||
fn flag_interrupt_get(&mut self) -> bool {
|
||||
unsafe { (*self.inner()).flag_interrupt_get() }
|
||||
}
|
||||
fn flag_interrupt_set(&mut self, flag_interrupt: bool) {
|
||||
unsafe { (*self.inner()).flag_interrupt_set(flag_interrupt) }
|
||||
}
|
||||
|
||||
fn raise(&mut self, vector: u16) {
|
||||
unsafe { Runtime::raise(&mut *self.inner(), vector) }
|
||||
}
|
||||
|
||||
fn step(&mut self) {
|
||||
unsafe { Runtime::step(&mut *self.inner()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CoreMemoryWrapped(CoreWrapped);
|
||||
|
||||
unsafe impl Send for CoreMemoryWrapped {}
|
||||
unsafe impl Sync for CoreMemoryWrapped {}
|
||||
|
||||
impl CoreMemoryWrapped {
|
||||
pub fn new(state_wrapped: CoreWrapped) -> Self {
|
||||
Self(state_wrapped)
|
||||
}
|
||||
}
|
||||
|
||||
impl Memory for CoreMemoryWrapped {
|
||||
fn ram(&self) -> &mut MemoryRam { self.0.ram() }
|
||||
fn rom(&self) -> &mut MemoryRom { self.0.rom() }
|
||||
}
|
Loading…
Reference in New Issue
Block a user