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:
Ry 2022-03-11 17:13:18 -08:00
parent cb2712cbf4
commit 342c3e6061
4 changed files with 106 additions and 114 deletions

View File

@ -1,6 +1,6 @@
// bus.rs // bus.rs
use crate::{DiskController, Memory, Mouse}; use crate::{DiskController, Memory, Mouse, Overlay};
use std::io::{stdout, Write}; use std::io::{stdout, Write};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -9,13 +9,14 @@ pub struct Bus {
pub disk_controller: DiskController, pub disk_controller: DiskController,
pub memory: Memory, pub memory: Memory,
pub mouse: Arc<Mutex<Mouse>>, pub mouse: Arc<Mutex<Mouse>>,
pub overlays: Arc<Mutex<Vec<Overlay>>>,
} }
impl Bus { impl Bus {
pub fn read_io(&mut self, port: u32) -> u32 { pub fn read_io(&mut self, port: u32) -> u32 {
match port { match port {
0x80000000..=0x8000031F => { // overlay 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 overlay_number = (port & 0x000000FF) as usize;
let setting = (port & 0x0000FF00) >> 8; let setting = (port & 0x0000FF00) >> 8;
@ -34,7 +35,7 @@ impl Bus {
} }
0x02 => { 0x02 => {
// we're reading the framebuffer pointer of this overlay // we're reading the framebuffer pointer of this overlay
overlay_lock[overlay_number].framebuffer_pointer + 0x80000000 overlay_lock[overlay_number].framebuffer_pointer
} }
0x03 => { 0x03 => {
// we're reading the enable status of this overlay // we're reading the enable status of this overlay
@ -106,7 +107,7 @@ impl Bus {
stdout().flush().expect("could not flush stdout"); stdout().flush().expect("could not flush stdout");
} }
0x80000000..=0x8000031F => { // overlay port 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 overlay_number = (port & 0x000000FF) as usize;
let setting = (port & 0x0000FF00) >> 8; let setting = (port & 0x0000FF00) >> 8;
@ -127,10 +128,7 @@ impl Bus {
} }
0x02 => { 0x02 => {
// we're setting the framebuffer pointer of this overlay // we're setting the framebuffer pointer of this overlay
if word < 0x80000000 { overlay_lock[overlay_number].framebuffer_pointer = word;
panic!("overlay framebuffer must be within shared memory");
}
overlay_lock[overlay_number].framebuffer_pointer = word - 0x80000000;
} }
0x03 => { 0x03 => {
// we're setting the enable status of this overlay // we're setting the enable status of this overlay

View File

@ -24,10 +24,7 @@ impl std::convert::From<u8> for Flag {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
let carry = ((byte >> 1) & 1) != 0; let carry = ((byte >> 1) & 1) != 0;
let zero = ((byte >> 0) & 1) != 0; let zero = ((byte >> 0) & 1) != 0;
Flag { Flag { carry, zero }
carry,
zero,
}
} }
} }

View File

@ -8,7 +8,7 @@ pub mod mouse;
use bus::Bus; use bus::Bus;
use cpu::{Cpu, Interrupt}; use cpu::{Cpu, Interrupt};
use disk::DiskController; use disk::DiskController;
use memory::Memory; use memory::{MEMORY_RAM_START, MEMORY_ROM_START, Memory, MemoryRam};
use mouse::Mouse; use mouse::Mouse;
use std::env; use std::env;
@ -74,37 +74,25 @@ fn main() {
let mut display = Display::new(); let mut display = Display::new();
let mouse = Arc::new(Mutex::new(Mouse::new())); let mouse = Arc::new(Mutex::new(Mouse::new()));
// 32 MiB of shared memory let memory = Memory::new(read_rom().as_slice());
let shared_memory = Arc::new(Mutex::new(vec![0u8; 0x02000000])); let memory_cpu = memory.clone();
let memory_eventloop = memory.clone();
let mut cpu = { let mut cpu = {
// 32 MiB of fast memory let ram_size = memory_cpu.ram().len();
let cpu_fast_memory = vec![0; 0x02000000]; let ram_bottom_address = MEMORY_RAM_START;
let cpu_shared_memory = Arc::clone(&shared_memory); let ram_top_address = ram_bottom_address + ram_size - 1;
let cpu_overlays = Arc::clone(&display.overlays); println!("RAM: {:.2} MiB mapped at {:#010X}-{:#010X}", ram_size / 1048576, ram_bottom_address, ram_top_address);
let cpu_read_only_memory = read_rom();
let fast_size = cpu_fast_memory.len(); let rom_size = memory_cpu.rom().len();
let fast_bottom_address = 0x00000000; let rom_bottom_address = MEMORY_ROM_START;
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_top_address = rom_bottom_address + rom_size - 1; 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); 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 bus_mouse = Arc::clone(&mouse);
let bus_overlays = Arc::clone(&display.overlays);
let cpu_mouse = Arc::clone(&mouse);
let disk_controller = DiskController::new(); 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) Cpu::new(bus)
}; };
@ -167,8 +155,6 @@ fn main() {
if let Event::MainEventsCleared = event { if let Event::MainEventsCleared = event {
// update internal state and request a redraw // 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 match interrupt_sender.send(Interrupt::Request(0xFF)) { // vsync interrupt
Ok(_) => {}, Ok(_) => {},
Err(_) => { Err(_) => {
@ -176,8 +162,7 @@ fn main() {
return; return;
} }
}; };
display.update(&mut *shared_memory_lock); display.update(memory_eventloop.clone().ram());
drop(shared_memory_lock);
window.request_redraw(); window.request_redraw();
display.draw(pixels.get_frame()); 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(); let overlay_lock = self.overlays.lock().unwrap();
for i in 0..(HEIGHT*WIDTH*4) as usize { 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 { for index in 0..=31 {
if overlay_lock[index].enabled { 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 // 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.x + overlay.width <= WIDTH);
//assert!(overlay.y + overlay.height <= HEIGHT); //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); //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; let mut overlay_framebuffer_index = 0;
for y in 0..height { for y in 0..height {

View File

@ -1,97 +1,109 @@
// memory.rs // 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 const MEMORY_RAM_SIZE: usize = 0x04000000; // 64 MiB
pub fast_memory: Vec<u8>, pub const MEMORY_ROM_SIZE: usize = 0x00080000; // 512 KiB
fast_memory_size: usize,
pub shared_memory: Arc<Mutex<Vec<u8>>>,
shared_memory_size: usize,
pub overlays: Arc<Mutex<Vec<Overlay>>>, pub const MEMORY_RAM_START: usize = 0x00000000;
pub const MEMORY_ROM_START: usize = 0xF0000000;
pub rom: Vec<u8>, pub type MemoryRam = [u8; MEMORY_RAM_SIZE];
rom_size: usize, pub type MemoryRom = [u8; MEMORY_ROM_SIZE];
struct MemoryInner {
ram: Box<MemoryRam>,
rom: Box<MemoryRom>,
} }
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 { impl Memory {
pub fn new(fast_memory: Vec<u8>, shared_memory: Arc<Mutex<Vec<u8>>>, overlays: Arc<Mutex<Vec<Overlay>>>, rom: Vec<u8>) -> Self { pub fn new(rom: &[u8]) -> Self {
// 3 extra bytes at the end to allow for reading the last byte of memory as an immediate pointer Self(Arc::new(UnsafeCell::new(MemoryInner::new(rom))))
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,
} }
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 { pub fn read_8(&self, address: u32) -> u8 {
let address = address as usize; let address = address as usize;
let fast_bottom_address = 0x00000000; let result = if address >= MEMORY_ROM_START && address < MEMORY_ROM_START + MEMORY_ROM_SIZE {
let fast_top_address = fast_bottom_address + self.fast_memory_size - 1; self.rom().get(address - MEMORY_ROM_START)
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]
} else { } else {
warn(&format!("attempting to read unmapped memory address: {:#010X}", address)); 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 0
} }
} }
}
pub fn read_16(&self, address: u32) -> u16 { 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 { 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 + 2) as u32) << 16 |
(self.read_8(address + 1) as u32) << 8 | (self.read_8(address + 1) as u32) << 8 |
(self.read_8(address) as u32) (self.read_8(address + 2) as u32) << 16 |
(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 address = address as usize;
let fast_bottom_address = 0x00000000; if address >= MEMORY_ROM_START && address < MEMORY_ROM_START + MEMORY_ROM_SIZE {
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 {
warn(&format!("attempting to write to ROM address: {:#010X}", address)); warn(&format!("attempting to write to ROM address: {:#010X}", address));
} else { 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)); 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, (half & 0x00FF) as u8);
self.write_8(address + 1, (half >> 8) 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, (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 + 2, ((word & 0x00FF0000) >> 16) as u8);