diff --git a/src/emu/iomem.rs b/src/emu/iomem.rs index ae8f373..5f00411 100644 --- a/src/emu/iomem.rs +++ b/src/emu/iomem.rs @@ -1,23 +1,24 @@ +use std::cell::Cell; use crate::emu::mmu::Memory; use crate::emu::program_counter::ProgramCounter; use crate::misc::emulator_error::{DeviceType, EmulatorError}; use crate::misc::emulator_error::DeviceType::MMU; -use crate::misc::endian::{read_big_endian_u16, read_big_endian_u24}; +use crate::misc::endian::{read_big_endian_u16}; use crate::misc::result::EmulatorResult; #[derive(Debug)] pub struct MemoryMappedIO<'a> { //FIXME use a keyboard - keyboard_bytes: [u8; 2], - program_counter: &'a mut ProgramCounter, + keyboard_bytes: Cell<[u8; 2]>, + program_counter: &'a ProgramCounter, //FIXME use a device - pixel_reg: u8, + pixel_reg: Cell, //FIXME use a device - audio_sample_address_base: [u8; 2], + audio_sample_address_base: Cell<[u8; 2]>, } /// Represents the memory mapped segment of IO. Aggregates the mapping logic. -impl <'a> MemoryMappedIO<'a> { +impl<'a> MemoryMappedIO<'a> { // 2 byte keyboard bits pub const KEYBOARD_BIT_START: u32 = 0; const KEYBOARD_BIT_END: u32 = 1; @@ -35,24 +36,25 @@ impl <'a> MemoryMappedIO<'a> { pub const AUDIO_SAMPLE_BASE_LEN: u32 = 2; const AUDIO_SAMPLE_BASE_END: u32 = Self::AUDIO_SAMPLE_BASE_START + Self::AUDIO_SAMPLE_BASE_LEN - 1; - pub fn new(program_counter: &'a mut ProgramCounter) -> MemoryMappedIO<'a> { + pub fn new(program_counter: &'a ProgramCounter) -> MemoryMappedIO<'a> { MemoryMappedIO { - keyboard_bytes: [0, 0], + keyboard_bytes: Cell::new([0, 0]), program_counter, - pixel_reg: 0, - audio_sample_address_base: [0, 0], + pixel_reg: Cell::new(0), + audio_sample_address_base: Cell::new([0, 0]), } } } -impl <'a> Memory for MemoryMappedIO<'a> { +impl<'a> Memory for MemoryMappedIO<'a> { fn try_get_byte(&self, address: u32) -> EmulatorResult { let byte = match address { Self::KEYBOARD_BIT_START..=Self::KEYBOARD_BIT_END => { let addr_usize = address as usize; - let keyboard_byte = self.keyboard_bytes[addr_usize]; - log::trace!("Fetching keyboard({}) byte segment {} -> {}",read_big_endian_u16(&self.keyboard_bytes),address,keyboard_byte); + let keyboard_bytes = self.keyboard_bytes.get(); + let keyboard_byte = keyboard_bytes[addr_usize]; + log::trace!("Fetching keyboard({}) byte segment {} -> {}",read_big_endian_u16(&keyboard_bytes),address,keyboard_byte); Ok(keyboard_byte) } Self::PC_START_ADDR..=Self::PC_END_ADDR => { @@ -60,36 +62,40 @@ impl <'a> Memory for MemoryMappedIO<'a> { self.program_counter.try_get_byte(pc_index) } Self::PIXEL_BASE => { - log::trace!("Fetching pixel base reg {}",self.pixel_reg); - Ok(self.pixel_reg) + log::trace!("Fetching pixel base reg {}",self.pixel_reg.get()); + Ok(self.pixel_reg.get()) } - Self::AUDIO_SAMPLE_BASE_START => Ok(self.audio_sample_address_base[0]), - Self::AUDIO_SAMPLE_BASE_END => Ok(self.audio_sample_address_base[1]), + Self::AUDIO_SAMPLE_BASE_START => Ok(self.audio_sample_address_base.get()[0]), + Self::AUDIO_SAMPLE_BASE_END => Ok(self.audio_sample_address_base.get()[1]), address => { - Err(EmulatorError::UnreachableMemory(DeviceType::MMU, address)) + Err(EmulatorError::UnreachableMemory(MMU, address)) } }; byte } - fn try_set_byte(&mut self, address: u32, byte_value: u8) -> EmulatorResult<()> { + fn try_set_byte(&self, address: u32, byte_value: u8) -> EmulatorResult<()> { match address { Self::KEYBOARD_BIT_START..=Self::KEYBOARD_BIT_END => { - let addr_usize = address as usize; - let keyboard_byte = self.keyboard_bytes[addr_usize]; - log::trace!("Setting keyboard({}) byte segment {} -> {}",read_big_endian_u16(&self.keyboard_bytes),address,keyboard_byte); - self.keyboard_bytes[addr_usize] = byte_value; + let mut keyboard_bytes = self.keyboard_bytes.get(); + log::trace!("Setting keyboard({}) byte segment {} -> {}",read_big_endian_u16(&keyboard_bytes),address,byte_value); + keyboard_bytes[address as usize] = byte_value; + self.keyboard_bytes.set(keyboard_bytes); } Self::PC_START_ADDR..=Self::PC_END_ADDR => { let pc_index = address - Self::PC_START_ADDR; self.program_counter.try_set_byte(pc_index, byte_value)? } Self::PIXEL_BASE => { - log::trace!("Fetching pixel base reg {}",self.pixel_reg); - self.pixel_reg = byte_value + log::trace!("Setting pixel base reg to {}",byte_value); + self.pixel_reg.set(byte_value); + } + Self::AUDIO_SAMPLE_BASE_START..=Self::AUDIO_SAMPLE_BASE_END => { + let audio_reg_index = (address - Self::AUDIO_SAMPLE_BASE_START) as usize; + let mut audio_sample_address_base = self.audio_sample_address_base.get(); + audio_sample_address_base[audio_reg_index] = byte_value; + self.audio_sample_address_base.set(audio_sample_address_base); } - Self::AUDIO_SAMPLE_BASE_START => { self.audio_sample_address_base[0] = byte_value } - Self::AUDIO_SAMPLE_BASE_END => { self.audio_sample_address_base[1] = byte_value } _ => { return Err(EmulatorError::UnreachableMemory(MMU, address)); } }; Ok(()) diff --git a/src/emu/mmu.rs b/src/emu/mmu.rs index e96bf53..4d6ae08 100644 --- a/src/emu/mmu.rs +++ b/src/emu/mmu.rs @@ -17,17 +17,17 @@ pub trait Memory { /// Get the value (24bit) at the address(24bit) fn try_get_byte(&self, address: u32) -> EmulatorResult; /// Set the value at the 24bit address - fn try_set_byte(&mut self, address: u32, value: u8) -> EmulatorResult<()>; + fn try_set_byte(&self, address: u32, value: u8) -> EmulatorResult<()>; } #[derive(Debug)] pub struct MappedMemory<'a> { - memory_mapped_io: &'a mut MemoryMappedIO<'a>, - ram_memory: &'a mut RamMemory, + memory_mapped_io: &'a MemoryMappedIO<'a>, + ram_memory: &'a RamMemory, } impl <'a> MappedMemory<'a> { - pub fn new(memory_mapped_io: &'a mut MemoryMappedIO<'a>, ram_memory:&'a mut RamMemory) -> MappedMemory<'a> { + pub fn new(memory_mapped_io: &'a MemoryMappedIO<'a>, ram_memory:&'a RamMemory) -> MappedMemory<'a> { MappedMemory { memory_mapped_io, ram_memory, @@ -50,7 +50,7 @@ impl <'a> Memory for MappedMemory<'a> { Ok(byte_at_addr) } - fn try_set_byte(&mut self, address: u32, value: u8) -> EmulatorResult<()> { + fn try_set_byte(&self, address: u32, value: u8) -> EmulatorResult<()> { match address { 0..=MMAPPEDIO_END => { self.memory_mapped_io.try_set_byte(address,value) diff --git a/src/emu/program_counter.rs b/src/emu/program_counter.rs index d348f86..82e149d 100644 --- a/src/emu/program_counter.rs +++ b/src/emu/program_counter.rs @@ -1,3 +1,4 @@ +use std::cell::Cell; use crate::emu::mmu::{Memory, RAM_MEM_END}; use crate::misc::emulator_error::DeviceType::PC; use crate::misc::emulator_error::EmulatorError; @@ -8,26 +9,29 @@ use crate::misc::result::EmulatorResult; #[derive(Debug, Default, Clone)] pub struct ProgramCounter { /// 24bit location register - program_counter_register: [u8; 3], + program_counter_register: Cell<[u8; 3]>, } impl ProgramCounter { + const PROGRAM_COUNTER_ZERO:[u8;3] = [0;3]; pub fn new() -> ProgramCounter { ProgramCounter { - program_counter_register: [0; 3] + program_counter_register: Cell::new(Self::PROGRAM_COUNTER_ZERO) } } // get the current program counter as an address pub fn get_pc_value(&self) -> u32 { - read_big_endian_u24(&self.program_counter_register) + read_big_endian_u24(&self.program_counter_register.get()) } // assign a value of PC to start execution - pub fn set_address(&mut self, address: u32) -> EmulatorResult<()> { + pub fn set_address(&self, address: u32) -> EmulatorResult<()> { log::debug!("Setting PC as {}",address); if address >= (2 << 24) { return Err(EmulatorError::UnreachableMemory(PC, address)); } - write_big_endian_u24(address, &mut self.program_counter_register); + let mut data = self.program_counter_register.get(); + write_big_endian_u24(address, &mut data); + self.program_counter_register.set(data); Ok(()) } } @@ -35,15 +39,19 @@ impl ProgramCounter { /// Allow Using Program counter as mapped memory impl Memory for ProgramCounter { fn try_get_byte(&self, address: u32) -> EmulatorResult { - log::trace!("Fetching PC({}) byte segment index {}",read_big_endian_u24(&self.program_counter_register),address); - self.program_counter_register.get(address as usize) + log::trace!("Fetching PC({}) byte segment index {}",read_big_endian_u24(&self.program_counter_register.get()),address); + self.program_counter_register.get().get(address as usize) .map(|e| *e) .ok_or(EmulatorError::UnreachableMemory(PC, address)) } /// TODO: Set a byte of PC from the memory. - fn try_set_byte(&mut self, address: u32, value: u8) -> EmulatorResult<()> { + fn try_set_byte(&self, address: u32, value: u8) -> EmulatorResult<()> { match address { - 0..=2 => { self.program_counter_register[address as usize] = value } + 0..=2 => { + let mut data = self.program_counter_register.get(); + data[address as usize] = value; + self.program_counter_register.set(data); + } _ => { return Err(EmulatorError::UnreachableMemory(PC, address)); } } Ok(()) diff --git a/src/emu/ram.rs b/src/emu/ram.rs index 78f7476..5fd4fb7 100644 --- a/src/emu/ram.rs +++ b/src/emu/ram.rs @@ -1,3 +1,4 @@ +use std::cell::RefCell; use std::ops::Index; use crate::emu::mmu::Memory; use crate::misc::emulator_error::DeviceType::RAM; @@ -9,7 +10,7 @@ const MEM_LENGTH: usize = (2 << 24) - (MAPPED_MEMORY_NOT_REQUIRED as usize); #[derive(Clone, Debug)] pub struct RamMemory { - data: Box<[u8; MEM_LENGTH]>, + data: RefCell>, } impl RamMemory { @@ -18,8 +19,9 @@ impl RamMemory { let data = alloc_result.try_into().map_err(|err|{ EmulatorError::AllocationFailure(RAM, "Allocation failed") })?; + let data_refcell = RefCell::new(data); Ok(RamMemory { - data + data: data_refcell }) } } @@ -28,15 +30,17 @@ impl RamMemory { impl Memory for RamMemory { fn try_get_byte(&self, address: u32) -> EmulatorResult { log::trace!("Fetch RAM memory at address {}",address); - let x = *self.data.get(address as usize).ok_or(EmulatorError::UnreachableMemory(RAM, address))?; + let mut data = self.data.borrow_mut(); + let x = *data.get(address as usize).ok_or(EmulatorError::UnreachableMemory(RAM, address))?; Ok(x) } - fn try_set_byte(&mut self, address: u32, value: u8) -> EmulatorResult<()> { + fn try_set_byte(&self, address: u32, value: u8) -> EmulatorResult<()> { if address>= MEM_LENGTH as u32 { return Err(EmulatorError::UnreachableMemory(RAM, address)) } - self.data[address as usize] = value; + let mut data = self.data.borrow_mut(); + data[address as usize] = value; Ok(()) } } diff --git a/src/main.rs b/src/main.rs index 4d95aa4..8047a34 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,16 +17,10 @@ mod graphics; fn main() -> EmulatorResult<()> { SimpleLogger::new().env().init().unwrap(); - let mut program_counter = ProgramCounter::new(); - let mut mmio = MemoryMappedIO::new(&mut program_counter); - let mut ram = RamMemory::try_new()?; - let mut mmu = MappedMemory::new(&mut mmio,&mut ram); - // for i in 0..10 { - // log::info!("Memory at {} is {}",i,mmu.try_get_byte(i)?); - // } - mmu.try_set_byte(0x2,0x1)?; - let data = program_counter.try_get_byte(0x0)?; - log::info!("Computed data {}",data); + let program_counter = ProgramCounter::new(); + let mmio = MemoryMappedIO::new(&program_counter); + let ram = RamMemory::try_new()?; + let mmu = MappedMemory::new(&mmio,&ram); // let sdl_context = sdl2::init().unwrap();