Created
January 3, 2025 02:56
-
-
Save Enprogames/e3458f0ef0e0dfa2231c7e4ae02efbbb to your computer and use it in GitHub Desktop.
Example of Rust Two-Way Struct Communication by Passing in Closure
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::cell::RefCell; | |
| use std::rc::Rc; | |
| pub struct CPU { | |
| memory_bus: Rc<RefCell<MemoryBus>>, | |
| oam_dma_page: RefCell<u8>, | |
| } | |
| impl CPU { | |
| pub fn new(memory_bus: Rc<RefCell<MemoryBus>>) -> Self { | |
| Self { | |
| memory_bus, | |
| oam_dma_page: RefCell::new(0), | |
| } | |
| } | |
| pub fn enter_oam_dma(&self, data: u8) { | |
| println!( | |
| "[CPU] Entering OAM DMA mode with page: 0x{:02X} ({})", | |
| data, data | |
| ); | |
| // Update CPU state using interior mutability | |
| *self.oam_dma_page.borrow_mut() = data; | |
| } | |
| pub fn write(&self, address: u16, data: u8) { | |
| println!( | |
| "[CPU] Normal write to address: 0x{:04X} with data: 0x{:02X} ({})", | |
| address, data, data | |
| ); | |
| self.memory_bus.borrow_mut().write(address, data); | |
| } | |
| } | |
| // Define the MemoryBus structure | |
| pub struct MemoryBus { | |
| oam_dma_callback: Option<Box<dyn FnMut(u8)>>, | |
| } | |
| impl MemoryBus { | |
| pub fn new() -> Self { | |
| Self { | |
| oam_dma_callback: None, | |
| } | |
| } | |
| // Method to set the OAM DMA callback | |
| pub fn set_oam_dma_callback<F>(&mut self, callback: F) | |
| where | |
| F: FnMut(u8) + 'static, | |
| { | |
| self.oam_dma_callback = Some(Box::new(callback)); | |
| println!("[MemoryBus] OAM DMA callback has been set."); | |
| } | |
| pub fn write(&mut self, address: u16, data: u8) { | |
| println!( | |
| "[MemoryBus] Writing to address: 0x{:04X} with data: 0x{:02X} ({})", | |
| address, data, data | |
| ); | |
| if address == 0x4014 { | |
| println!("[MemoryBus] Detected write to OAM DMA register (0x4014). Triggering DMA..."); | |
| if let Some(ref mut callback) = self.oam_dma_callback { | |
| callback(data); | |
| } else { | |
| println!("[MemoryBus] No OAM DMA callback set!"); | |
| } | |
| } else { | |
| // Handle other memory writes | |
| println!("[MemoryBus] Handling normal memory write."); | |
| } | |
| } | |
| // The CPU should call this method every write cycle (odd cycles?) to write data for OAM DMA | |
| pub fn write_oam_dma(&self, address: u16, data: u8) { | |
| println!( | |
| "[MemoryBus] Writing to OAM DMA address: 0x{:04X} with data: 0x{:02X} ({})", | |
| address, data, data | |
| ); | |
| } | |
| } | |
| pub struct NES { | |
| pub cpu: Rc<RefCell<CPU>>, | |
| pub memory_bus: Rc<RefCell<MemoryBus>>, | |
| } | |
| impl NES { | |
| pub fn new() -> Self { | |
| let memory_bus = Rc::new(RefCell::new(MemoryBus::new())); | |
| let cpu = Rc::new(RefCell::new(CPU::new(memory_bus.clone()))); | |
| { | |
| // Clone the Rc to move into the closure | |
| let cpu_ref = Rc::clone(&cpu); | |
| memory_bus.borrow_mut().set_oam_dma_callback(move |dma_value| { | |
| println!("[Closure] OAM DMA callback invoked with value: 0x{:02X} ({})", dma_value, dma_value); | |
| cpu_ref.borrow().enter_oam_dma(dma_value); | |
| }); | |
| } | |
| Self { cpu, memory_bus } | |
| } | |
| pub fn run_example(&mut self) { | |
| println!("\n--- Running NES Example ---\n"); | |
| // Perform a normal write to a non-DMA address | |
| let normal_address = 0x2000; | |
| let normal_data = 0xAA; | |
| self.cpu.borrow().write(normal_address, normal_data); | |
| // Perform a write to the OAM DMA register | |
| let dma_address = 0x4014; | |
| let dma_data = 0x55; | |
| println!("\n[Main] Performing OAM DMA write:"); | |
| self.cpu.borrow().write(dma_address, dma_data); | |
| println!("\n--- NES Example Completed ---\n"); | |
| } | |
| } | |
| fn main() { | |
| let mut nes = NES::new(); | |
| nes.run_example(); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment