From 342c3e6061c1dab80371c89d8ace9bc894b36254 Mon Sep 17 00:00:00 2001 From: Ry Date: Fri, 11 Mar 2022 17:13:18 -0800 Subject: [PATCH] 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 --- src/bus.rs | 14 +++-- src/cpu.rs | 5 +- src/main.rs | 55 +++++++------------ src/memory.rs | 146 +++++++++++++++++++++++++++----------------------- 4 files changed, 106 insertions(+), 114 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index d86d816..9c38b63 100644 --- a/src/bus.rs +++ b/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>, + pub overlays: Arc>>, } 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 diff --git a/src/cpu.rs b/src/cpu.rs index 14978e8..d6dfaa3 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -24,10 +24,7 @@ impl std::convert::From 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 } } } diff --git a/src/main.rs b/src/main.rs index 660f438..a858863 100644 --- a/src/main.rs +++ b/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 { diff --git a/src/memory.rs b/src/memory.rs index 7e25702..6ed6be5 100644 --- a/src/memory.rs +++ b/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, - fast_memory_size: usize, - pub shared_memory: Arc>>, - 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>>, +pub const MEMORY_RAM_START: usize = 0x00000000; +pub const MEMORY_ROM_START: usize = 0xF0000000; - pub rom: Vec, - rom_size: usize, +pub type MemoryRam = [u8; MEMORY_RAM_SIZE]; +pub type MemoryRom = [u8; MEMORY_ROM_SIZE]; + +struct MemoryInner { + ram: Box, + rom: Box, } -impl Memory { - pub fn new(fast_memory: Vec, shared_memory: Arc>>, overlays: Arc>>, rom: Vec) -> 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>); + +// 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); }