fox32+fox32rom: Remove the concept of "fast" and "shared" memory
Instead of having two banks of RAM, just have one bank. This requires the use of some cursed code, but it's fine :P Co-authored-by: Lua <lua@foxgirl.dev>
This commit is contained in:
parent
cb2712cbf4
commit
342c3e6061
14
src/bus.rs
14
src/bus.rs
|
@ -1,6 +1,6 @@
|
|||
// bus.rs
|
||||
|
||||
use crate::{DiskController, Memory, Mouse};
|
||||
use crate::{DiskController, Memory, Mouse, Overlay};
|
||||
|
||||
use std::io::{stdout, Write};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
@ -9,13 +9,14 @@ pub struct Bus {
|
|||
pub disk_controller: DiskController,
|
||||
pub memory: Memory,
|
||||
pub mouse: Arc<Mutex<Mouse>>,
|
||||
pub overlays: Arc<Mutex<Vec<Overlay>>>,
|
||||
}
|
||||
|
||||
impl Bus {
|
||||
pub fn read_io(&mut self, port: u32) -> u32 {
|
||||
match port {
|
||||
0x80000000..=0x8000031F => { // overlay port
|
||||
let overlay_lock = self.memory.overlays.lock().unwrap();
|
||||
let overlay_lock = self.overlays.lock().unwrap();
|
||||
let overlay_number = (port & 0x000000FF) as usize;
|
||||
let setting = (port & 0x0000FF00) >> 8;
|
||||
|
||||
|
@ -34,7 +35,7 @@ impl Bus {
|
|||
}
|
||||
0x02 => {
|
||||
// we're reading the framebuffer pointer of this overlay
|
||||
overlay_lock[overlay_number].framebuffer_pointer + 0x80000000
|
||||
overlay_lock[overlay_number].framebuffer_pointer
|
||||
}
|
||||
0x03 => {
|
||||
// we're reading the enable status of this overlay
|
||||
|
@ -106,7 +107,7 @@ impl Bus {
|
|||
stdout().flush().expect("could not flush stdout");
|
||||
}
|
||||
0x80000000..=0x8000031F => { // overlay port
|
||||
let mut overlay_lock = self.memory.overlays.lock().unwrap();
|
||||
let mut overlay_lock = self.overlays.lock().unwrap();
|
||||
let overlay_number = (port & 0x000000FF) as usize;
|
||||
let setting = (port & 0x0000FF00) >> 8;
|
||||
|
||||
|
@ -127,10 +128,7 @@ impl Bus {
|
|||
}
|
||||
0x02 => {
|
||||
// we're setting the framebuffer pointer of this overlay
|
||||
if word < 0x80000000 {
|
||||
panic!("overlay framebuffer must be within shared memory");
|
||||
}
|
||||
overlay_lock[overlay_number].framebuffer_pointer = word - 0x80000000;
|
||||
overlay_lock[overlay_number].framebuffer_pointer = word;
|
||||
}
|
||||
0x03 => {
|
||||
// we're setting the enable status of this overlay
|
||||
|
|
|
@ -24,10 +24,7 @@ impl std::convert::From<u8> for Flag {
|
|||
fn from(byte: u8) -> Self {
|
||||
let carry = ((byte >> 1) & 1) != 0;
|
||||
let zero = ((byte >> 0) & 1) != 0;
|
||||
Flag {
|
||||
carry,
|
||||
zero,
|
||||
}
|
||||
Flag { carry, zero }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
55
src/main.rs
55
src/main.rs
|
@ -8,7 +8,7 @@ pub mod mouse;
|
|||
use bus::Bus;
|
||||
use cpu::{Cpu, Interrupt};
|
||||
use disk::DiskController;
|
||||
use memory::Memory;
|
||||
use memory::{MEMORY_RAM_START, MEMORY_ROM_START, Memory, MemoryRam};
|
||||
use mouse::Mouse;
|
||||
|
||||
use std::env;
|
||||
|
@ -74,37 +74,25 @@ fn main() {
|
|||
let mut display = Display::new();
|
||||
let mouse = Arc::new(Mutex::new(Mouse::new()));
|
||||
|
||||
// 32 MiB of shared memory
|
||||
let shared_memory = Arc::new(Mutex::new(vec![0u8; 0x02000000]));
|
||||
let memory = Memory::new(read_rom().as_slice());
|
||||
let memory_cpu = memory.clone();
|
||||
let memory_eventloop = memory.clone();
|
||||
|
||||
let mut cpu = {
|
||||
// 32 MiB of fast memory
|
||||
let cpu_fast_memory = vec![0; 0x02000000];
|
||||
let cpu_shared_memory = Arc::clone(&shared_memory);
|
||||
let cpu_overlays = Arc::clone(&display.overlays);
|
||||
let cpu_read_only_memory = read_rom();
|
||||
let ram_size = memory_cpu.ram().len();
|
||||
let ram_bottom_address = MEMORY_RAM_START;
|
||||
let ram_top_address = ram_bottom_address + ram_size - 1;
|
||||
println!("RAM: {:.2} MiB mapped at {:#010X}-{:#010X}", ram_size / 1048576, ram_bottom_address, ram_top_address);
|
||||
|
||||
let fast_size = cpu_fast_memory.len();
|
||||
let fast_bottom_address = 0x00000000;
|
||||
let fast_top_address = fast_bottom_address + fast_size - 1;
|
||||
println!("Fast: {:.2} MiB mapped at {:#010X}-{:#010X}", fast_size / 1048576, fast_bottom_address, fast_top_address);
|
||||
|
||||
let shared_size = { cpu_shared_memory.lock().unwrap().len() };
|
||||
let shared_bottom_address = 0x80000000;
|
||||
let shared_top_address = shared_bottom_address + shared_size - 1;
|
||||
println!("Shared: {:.2} MiB mapped at {:#010X}-{:#010X}", shared_size / 1048576, shared_bottom_address, shared_top_address);
|
||||
|
||||
let rom_size = cpu_read_only_memory.len();
|
||||
let rom_bottom_address = 0xF0000000;
|
||||
let rom_size = memory_cpu.rom().len();
|
||||
let rom_bottom_address = MEMORY_ROM_START;
|
||||
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 memory = Memory::new(cpu_fast_memory, cpu_shared_memory, cpu_overlays, cpu_read_only_memory);
|
||||
|
||||
let cpu_mouse = Arc::clone(&mouse);
|
||||
println!("ROM: {:.2} KiB mapped at {:#010X}-{:#010X}", rom_size / 1024, rom_bottom_address, rom_top_address);
|
||||
|
||||
let bus_mouse = Arc::clone(&mouse);
|
||||
let bus_overlays = Arc::clone(&display.overlays);
|
||||
let disk_controller = DiskController::new();
|
||||
let bus = Bus { disk_controller, memory, mouse: cpu_mouse };
|
||||
let bus = Bus { disk_controller, memory: memory_cpu, mouse: bus_mouse, overlays: bus_overlays };
|
||||
Cpu::new(bus)
|
||||
};
|
||||
|
||||
|
@ -167,8 +155,6 @@ fn main() {
|
|||
if let Event::MainEventsCleared = event {
|
||||
// update internal state and request a redraw
|
||||
|
||||
let mut shared_memory_lock = shared_memory.lock().expect("failed to lock the shared memory mutex");
|
||||
//shared_memory_lock[0x01FFFFFF] = shared_memory_lock[0x01FFFFFF].overflowing_add(1).0; // increment vsync counter
|
||||
match interrupt_sender.send(Interrupt::Request(0xFF)) { // vsync interrupt
|
||||
Ok(_) => {},
|
||||
Err(_) => {
|
||||
|
@ -176,8 +162,7 @@ fn main() {
|
|||
return;
|
||||
}
|
||||
};
|
||||
display.update(&mut *shared_memory_lock);
|
||||
drop(shared_memory_lock);
|
||||
display.update(memory_eventloop.clone().ram());
|
||||
window.request_redraw();
|
||||
|
||||
display.draw(pixels.get_frame());
|
||||
|
@ -229,16 +214,16 @@ impl Display {
|
|||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, shared_memory: &mut [u8]) {
|
||||
fn update(&mut self, ram: &MemoryRam) {
|
||||
let overlay_lock = self.overlays.lock().unwrap();
|
||||
|
||||
for i in 0..(HEIGHT*WIDTH*4) as usize {
|
||||
self.background[i] = shared_memory[i];
|
||||
self.background[i] = ram[0x02000000 + i];
|
||||
}
|
||||
|
||||
for index in 0..=31 {
|
||||
if overlay_lock[index].enabled {
|
||||
blit_overlay(&mut self.background, &overlay_lock[index], shared_memory);
|
||||
blit_overlay(&mut self.background, &overlay_lock[index], ram);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,7 +242,7 @@ impl Display {
|
|||
}
|
||||
|
||||
// modified from https://github.com/parasyte/pixels/blob/main/examples/invaders/simple-invaders/src/sprites.rs
|
||||
fn blit_overlay(framebuffer: &mut [u8], overlay: &Overlay, shared_memory: &mut [u8]) {
|
||||
fn blit_overlay(framebuffer: &mut [u8], overlay: &Overlay, ram: &[u8]) {
|
||||
//assert!(overlay.x + overlay.width <= WIDTH);
|
||||
//assert!(overlay.y + overlay.height <= HEIGHT);
|
||||
|
||||
|
@ -277,7 +262,7 @@ fn blit_overlay(framebuffer: &mut [u8], overlay: &Overlay, shared_memory: &mut [
|
|||
//println!("height: {}, difference: {}", height, difference);
|
||||
}
|
||||
|
||||
let overlay_framebuffer = &shared_memory[overlay.framebuffer_pointer as usize..(overlay.framebuffer_pointer+((width as u32)*(height as u32))) as usize];
|
||||
let overlay_framebuffer = &ram[(overlay.framebuffer_pointer as usize)..((overlay.framebuffer_pointer+((width as u32)*(height as u32))) as usize)];
|
||||
|
||||
let mut overlay_framebuffer_index = 0;
|
||||
for y in 0..height {
|
||||
|
|
146
src/memory.rs
146
src/memory.rs
|
@ -1,99 +1,111 @@
|
|||
// memory.rs
|
||||
|
||||
use crate::{Overlay, warn};
|
||||
use crate::warn;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::cell::UnsafeCell;
|
||||
use std::sync::Arc;
|
||||
use std::io::Write;
|
||||
|
||||
pub struct Memory {
|
||||
pub fast_memory: Vec<u8>,
|
||||
fast_memory_size: usize,
|
||||
pub shared_memory: Arc<Mutex<Vec<u8>>>,
|
||||
shared_memory_size: usize,
|
||||
pub const MEMORY_RAM_SIZE: usize = 0x04000000; // 64 MiB
|
||||
pub const MEMORY_ROM_SIZE: usize = 0x00080000; // 512 KiB
|
||||
|
||||
pub overlays: Arc<Mutex<Vec<Overlay>>>,
|
||||
pub const MEMORY_RAM_START: usize = 0x00000000;
|
||||
pub const MEMORY_ROM_START: usize = 0xF0000000;
|
||||
|
||||
pub rom: Vec<u8>,
|
||||
rom_size: usize,
|
||||
pub type MemoryRam = [u8; MEMORY_RAM_SIZE];
|
||||
pub type MemoryRom = [u8; MEMORY_ROM_SIZE];
|
||||
|
||||
struct MemoryInner {
|
||||
ram: Box<MemoryRam>,
|
||||
rom: Box<MemoryRom>,
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
pub fn new(fast_memory: Vec<u8>, shared_memory: Arc<Mutex<Vec<u8>>>, overlays: Arc<Mutex<Vec<Overlay>>>, rom: Vec<u8>) -> Self {
|
||||
// 3 extra bytes at the end to allow for reading the last byte of memory as an immediate pointer
|
||||
let shared_memory_size = { shared_memory.lock().unwrap().len() };
|
||||
Memory {
|
||||
fast_memory_size: fast_memory.len(),
|
||||
fast_memory,
|
||||
shared_memory_size,
|
||||
shared_memory,
|
||||
overlays,
|
||||
rom_size: rom.len(),
|
||||
rom,
|
||||
}
|
||||
impl MemoryInner {
|
||||
pub fn new(rom: &[u8]) -> Self {
|
||||
let mut this = Self {
|
||||
ram: Box::new([0u8; MEMORY_RAM_SIZE]),
|
||||
rom: Box::new([0u8; MEMORY_ROM_SIZE]),
|
||||
};
|
||||
this.rom.as_mut_slice().write(rom).expect("failed to copy ROM to memory");
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
#[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))))
|
||||
}
|
||||
|
||||
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 read_8(&self, address: u32) -> u8 {
|
||||
let address = address as usize;
|
||||
|
||||
let fast_bottom_address = 0x00000000;
|
||||
let fast_top_address = fast_bottom_address + self.fast_memory_size - 1;
|
||||
|
||||
let shared_bottom_address = 0x80000000;
|
||||
let shared_top_address = shared_bottom_address + self.shared_memory_size - 1;
|
||||
|
||||
let rom_bottom_address = 0xF0000000;
|
||||
let rom_top_address = rom_bottom_address + self.rom_size - 1;
|
||||
|
||||
if address >= fast_bottom_address && address <= fast_top_address {
|
||||
self.fast_memory[address]
|
||||
} else if address >= shared_bottom_address && address <= shared_top_address {
|
||||
let shared_memory_lock = self.shared_memory.lock().unwrap();
|
||||
shared_memory_lock[address - shared_bottom_address]
|
||||
} else if address >= rom_bottom_address && address <= rom_top_address {
|
||||
self.rom[address - rom_bottom_address]
|
||||
let result = if address >= MEMORY_ROM_START && address < MEMORY_ROM_START + MEMORY_ROM_SIZE {
|
||||
self.rom().get(address - MEMORY_ROM_START)
|
||||
} else {
|
||||
warn(&format!("attempting to read unmapped memory address: {:#010X}", address));
|
||||
0
|
||||
self.ram().get(address - MEMORY_RAM_START)
|
||||
};
|
||||
|
||||
match result {
|
||||
Some(value) => {
|
||||
*value
|
||||
}
|
||||
None => {
|
||||
warn(&format!("attempting to read from unmapped memory address: {:#010X}", address));
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn read_16(&self, address: u32) -> u16 {
|
||||
(self.read_8(address + 1) as u16) << 8 |
|
||||
(self.read_8(address) as 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 + 3) as u32) << 24 |
|
||||
(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 + 1) as u32) << 8 |
|
||||
(self.read_8(address) as u32)
|
||||
(self.read_8(address + 3) as u32) << 24
|
||||
}
|
||||
pub fn write_8(&mut self, address: u32, byte: u8) {
|
||||
|
||||
pub fn write_8(&self, address: u32, byte: u8) {
|
||||
let address = address as usize;
|
||||
|
||||
let fast_bottom_address = 0x00000000;
|
||||
let fast_top_address = fast_bottom_address + self.fast_memory_size - 1;
|
||||
|
||||
let shared_bottom_address = 0x80000000;
|
||||
let shared_top_address = shared_bottom_address + self.shared_memory_size - 1;
|
||||
|
||||
let rom_bottom_address = 0xF0000000;
|
||||
let rom_top_address = rom_bottom_address + self.rom_size - 1;
|
||||
|
||||
if address >= fast_bottom_address && address <= fast_top_address {
|
||||
self.fast_memory[address] = byte;
|
||||
} else if address >= shared_bottom_address && address <= shared_top_address {
|
||||
let mut shared_memory_lock = self.shared_memory.lock().unwrap();
|
||||
shared_memory_lock[address - shared_bottom_address] = byte;
|
||||
} else if address >= rom_bottom_address && address <= rom_top_address {
|
||||
if address >= MEMORY_ROM_START && address < MEMORY_ROM_START + MEMORY_ROM_SIZE {
|
||||
warn(&format!("attempting to write to ROM address: {:#010X}", address));
|
||||
} else {
|
||||
warn(&format!("attempting to write to unmapped memory address: {:#010X}", address));
|
||||
return;
|
||||
}
|
||||
|
||||
match self.ram().get_mut(address - MEMORY_RAM_START) {
|
||||
Some(value) => {
|
||||
*value = byte;
|
||||
}
|
||||
None => {
|
||||
warn(&format!("attempting to write to unmapped memory address: {:#010X}", address));
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn write_16(&mut self, address: u32, half: u16) {
|
||||
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(&mut self, address: u32, word: u32) {
|
||||
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 + 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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user