Skip to content

Commit 8727bb7

Browse files
committed
WIP
1 parent 11e4190 commit 8727bb7

File tree

7 files changed

+190
-58
lines changed

7 files changed

+190
-58
lines changed

src/cartridge_io.rs

Lines changed: 77 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,31 @@ use crate::utils::{rgb5_to_rgb8, HeapMemU8, NoHashMap};
55
use static_assertions::const_assert_eq;
66
use std::cmp::min;
77
use std::fs::File;
8+
use std::intrinsics::unlikely;
89
use std::io::{ErrorKind, Seek};
910
use std::ops::{Deref, DerefMut};
1011
use std::os::unix::fs::FileExt;
1112
use std::path::PathBuf;
12-
use std::sync::{Arc, Mutex};
13-
use std::time::Instant;
14-
use std::{io, mem};
13+
use std::sync::atomic::AtomicBool;
14+
use std::sync::{Arc, Condvar, Mutex};
15+
use std::time::{Duration, Instant};
16+
use std::{io, mem, thread};
1517

16-
#[repr(C, packed)]
18+
#[repr(C)]
1719
pub struct ArmValues {
1820
pub rom_offset: u32,
1921
pub entry_address: u32,
2022
pub ram_address: u32,
2123
pub size: u32,
2224
}
2325

24-
#[repr(C, packed)]
26+
#[repr(C)]
2527
pub struct ArmOverlay {
26-
overlay_offset: u32,
27-
overlay_size: u32,
28+
pub overlay_offset: u32,
29+
pub overlay_size: u32,
2830
}
2931

30-
#[repr(C, packed)]
32+
#[repr(C)]
3133
pub struct CartridgeHeader {
3234
game_title: [u8; 12],
3335
pub game_code: [u8; 4],
@@ -42,10 +44,8 @@ pub struct CartridgeHeader {
4244
autostart: u8,
4345
pub arm9_values: ArmValues,
4446
pub arm7_values: ArmValues,
45-
file_name_table_offset: u32,
46-
file_name_table_size: u32,
47-
file_allocation_table_offset: u32,
48-
file_allocation_table_size: u32,
47+
pub file_name_table: ArmOverlay,
48+
pub file_allocation_table: ArmOverlay,
4949
arm9_overlay: ArmOverlay,
5050
arm7_overlay: ArmOverlay,
5151
port_setting_normal_commands: u32,
@@ -162,16 +162,46 @@ impl CartridgePreview {
162162
}
163163
}
164164

165+
#[derive(Default)]
166+
struct CartridgeContent {
167+
content_pages: NoHashMap<u32, u16>,
168+
content_cache: HeapMemU8<MAX_CARTRIDGE_CACHE>,
169+
}
170+
171+
impl CartridgeContent {
172+
fn get_page(&mut self, file: &File, page_addr: u32) -> io::Result<*const [u8; CARTRIDGE_PAGE_SIZE]> {
173+
debug_assert_eq!(page_addr & (CARTRIDGE_PAGE_SIZE as u32 - 1), 0);
174+
match self.content_pages.get(&page_addr) {
175+
None => {
176+
if unlikely(self.content_pages.len() >= MAX_CARTRIDGE_CACHE / CARTRIDGE_PAGE_SIZE) {
177+
debug_println!("clear cartridge pages");
178+
self.content_pages.clear();
179+
}
180+
181+
let content_offset = self.content_pages.len() as u16;
182+
let start = content_offset as usize * CARTRIDGE_PAGE_SIZE;
183+
let buf = &mut self.content_cache[start..start + CARTRIDGE_PAGE_SIZE];
184+
file.read_at(buf, page_addr as u64)?;
185+
self.content_pages.insert(page_addr, content_offset);
186+
Ok(buf.as_ptr() as _)
187+
}
188+
Some(page) => Ok(self.content_cache[*page as usize * CARTRIDGE_PAGE_SIZE..].as_ptr() as _),
189+
}
190+
}
191+
}
192+
165193
pub struct CartridgeIo {
166194
file: File,
167195
pub file_name: String,
168196
pub file_size: u32,
169197
pub header: CartridgeHeader,
170-
content_pages: NoHashMap<u32, u16>,
171-
content_cache: HeapMemU8<MAX_CARTRIDGE_CACHE>,
198+
content: CartridgeContent,
172199
save_file_path: PathBuf,
173200
pub save_file_size: u32,
174201
save_buf: Mutex<(Vec<u8>, bool)>,
202+
async_cmd: Mutex<(u32, u32)>,
203+
async_cmd_condvar: Condvar,
204+
read_lock: Mutex<()>,
175205
}
176206

177207
unsafe impl Send for CartridgeIo {}
@@ -209,42 +239,25 @@ impl CartridgeIo {
209239
file_name: preview.file_name,
210240
file_size,
211241
header: preview.header,
212-
content_pages: NoHashMap::default(),
213-
content_cache: HeapMemU8::new(),
242+
content: CartridgeContent::default(),
214243
save_file_path,
215244
save_file_size,
216245
save_buf: Mutex::new((save_buf, false)),
246+
async_cmd: Mutex::new((0, 0)),
247+
async_cmd_condvar: Condvar::new(),
248+
read_lock: Mutex::new(()),
217249
})
218250
}
219251

220-
fn get_page(&mut self, page_addr: u32) -> io::Result<*const [u8; CARTRIDGE_PAGE_SIZE]> {
221-
debug_assert_eq!(page_addr & (CARTRIDGE_PAGE_SIZE as u32 - 1), 0);
222-
match self.content_pages.get(&page_addr) {
223-
None => {
224-
if self.content_pages.len() >= MAX_CARTRIDGE_CACHE / CARTRIDGE_PAGE_SIZE {
225-
debug_println!("clear cartridge pages");
226-
self.content_pages.clear();
227-
}
228-
229-
let content_offset = self.content_pages.len() as u16;
230-
let start = content_offset as usize * CARTRIDGE_PAGE_SIZE;
231-
let buf = &mut self.content_cache[start..start + CARTRIDGE_PAGE_SIZE];
232-
self.file.read_at(buf, page_addr as u64)?;
233-
self.content_pages.insert(page_addr, content_offset);
234-
Ok(buf.as_ptr() as _)
235-
}
236-
Some(page) => Ok(self.content_cache[*page as usize * CARTRIDGE_PAGE_SIZE..].as_ptr() as _),
237-
}
238-
}
239-
240252
pub fn read_slice(&mut self, offset: u32, slice: &mut [u8]) -> io::Result<()> {
241253
let mut remaining = slice.len();
242254
while remaining > 0 {
243255
let slice_start = slice.len() - remaining;
244256

245257
let page_addr = (offset + slice_start as u32) & !(CARTRIDGE_PAGE_SIZE as u32 - 1);
246258
let page_offset = offset + slice_start as u32 - page_addr;
247-
let page = self.get_page(page_addr)?;
259+
let _read_lock = self.read_lock.lock().unwrap();
260+
let page = self.content.get_page(&self.file, page_addr)?;
248261
let page = unsafe { page.as_ref_unchecked() };
249262
let page_slice = &page[page_offset as usize..];
250263

@@ -324,6 +337,33 @@ impl CartridgeIo {
324337
*dirty = false;
325338
}
326339
}
340+
341+
pub fn async_cmd(&self, addr: u32, len: u32) {
342+
let mut async_cmd = self.async_cmd.lock().unwrap();
343+
*async_cmd = (addr, len);
344+
self.async_cmd_condvar.notify_one();
345+
}
346+
347+
pub fn async_read_rom(&mut self) {
348+
let async_cmd = self.async_cmd.lock().unwrap();
349+
let (mut async_cmd, timeout_result) = self
350+
.async_cmd_condvar
351+
.wait_timeout_while(async_cmd, Duration::from_millis(500), |(addr, offset)| *addr == 0 && *offset == 0)
352+
.unwrap();
353+
if timeout_result.timed_out() {
354+
return;
355+
}
356+
357+
let (addr, len) = *async_cmd;
358+
*async_cmd = (0, 0);
359+
360+
let aligned_addr = addr & !(CARTRIDGE_PAGE_SIZE as u32 - 1);
361+
let aligned_addr_end = (addr + len + CARTRIDGE_PAGE_SIZE as u32 - 1) & !(CARTRIDGE_PAGE_SIZE as u32 - 1);
362+
for addr in (aligned_addr..aligned_addr_end).step_by(CARTRIDGE_PAGE_SIZE) {
363+
let _read_lock = self.read_lock.lock().unwrap();
364+
self.content.get_page(&self.file, addr).unwrap();
365+
}
366+
}
327367
}
328368

329369
const KEY1_BUF_SIZE: usize = 0x412;

src/core/emu.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ pub struct Emu {
6363
pub jit: JitMemory,
6464
pub settings: Settings,
6565
pub nitro_sdk_version: NitroSdkVersion,
66+
pub nitro_read_rom_addr: u32,
67+
pub nitro_read_rom_last_src: u32,
68+
pub nitro_read_rom_hook_usable: bool,
6669
pub breakout_imm: bool,
6770
initialized: bool,
6871
}
@@ -89,6 +92,9 @@ impl Emu {
8992
jit,
9093
settings: DEFAULT_SETTINGS.clone(),
9194
nitro_sdk_version: NitroSdkVersion::default(),
95+
nitro_read_rom_addr: 0,
96+
nitro_read_rom_last_src: u32::MAX,
97+
nitro_read_rom_hook_usable: false,
9298
breakout_imm: false,
9399
initialized: true,
94100
}
@@ -113,8 +119,11 @@ impl Emu {
113119
self.dma = [Dma::new(), Dma::new()];
114120
self.timers = [Timers::new(), Timers::new()];
115121
self.wifi = Wifi::new();
122+
self.nitro_sdk_version = NitroSdkVersion::default();
123+
self.nitro_read_rom_addr = 0;
124+
self.nitro_read_rom_last_src = u32::MAX;
125+
self.nitro_read_rom_hook_usable = false;
116126
}
117-
self.nitro_sdk_version = NitroSdkVersion::default();
118127
self.initialized = false;
119128
}
120129
}

src/core/graphics/gpu_renderer.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use std::sync::atomic::{AtomicBool, AtomicU16, Ordering};
1919
use std::sync::{Arc, Condvar, Mutex};
2020
use std::thread;
2121
use std::thread::Thread;
22-
use std::time::Instant;
22+
use std::time::{Duration, Instant};
2323

2424
pub struct GpuRendererCommon {
2525
pub mem_buf: GpuMemBuf,
@@ -330,10 +330,6 @@ impl GpuRenderer {
330330
pub fn unpause(&mut self, cpu_thread: &Thread) {
331331
self.pause = false;
332332
cpu_thread.unpark();
333-
334-
if self.quit {
335-
self.read_vram_condvar.notify_one();
336-
}
337333
}
338334

339335
pub fn blit_main_framebuffer(&self) {
@@ -356,13 +352,12 @@ impl GpuRenderer {
356352
}
357353

358354
pub fn read_vram(&mut self, vram: &[u8; vram::TOTAL_SIZE]) {
359-
if self.quit {
355+
let read_vram = self.read_vram.lock().unwrap();
356+
let (_read_vram, timeout_result) = self.read_vram_condvar.wait_timeout(read_vram, Duration::from_millis(500)).unwrap();
357+
if timeout_result.timed_out() {
360358
return;
361359
}
362360

363-
let read_vram = self.read_vram.lock().unwrap();
364-
let _read_vram = self.read_vram_condvar.wait(read_vram).unwrap();
365-
366361
self.common.mem_buf.read_vram(vram);
367362
}
368363
}

src/core/memory/cartridge.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ pub struct Cartridge {
100100
cmd_mode: CmdMode,
101101
inner: [CartridgeInner; 2],
102102
read_buf: HeapMemU8<{ 16 * 1024 }>,
103+
pub last_read_addr: u32,
104+
need_read: bool,
103105
}
104106

105107
impl Cartridge {
@@ -109,6 +111,8 @@ impl Cartridge {
109111
inner: [CartridgeInner::default(), CartridgeInner::default()],
110112
cmd_mode: CmdMode::None,
111113
read_buf: HeapMemU8::new(),
114+
last_read_addr: 0,
115+
need_read: false,
112116
}
113117
}
114118

@@ -171,6 +175,7 @@ impl Emu {
171175
CmdMode::Data => {
172176
let offset = inner.read_count as u32 - 4;
173177
if offset + 3 < inner.block_size as u32 {
178+
self.cartridge_read_rom(cpu);
174179
utils::read_from_mem(self.cartridge.read_buf.deref(), offset)
175180
} else {
176181
0xFFFFFFFF
@@ -365,7 +370,8 @@ impl Emu {
365370
if read_addr < 0x8000 {
366371
read_addr = 0x8000 + (read_addr & 0x1FF);
367372
}
368-
self.cartridge.io.read_slice(read_addr, &mut self.cartridge.read_buf[..inner.block_size as usize]).unwrap();
373+
self.cartridge.need_read = true;
374+
self.cartridge.last_read_addr = read_addr;
369375
} else if cmd != 0x9F00000000000000 {
370376
debug_println!("Unknown rom transfer command {:x}", cmd);
371377
}
@@ -382,8 +388,19 @@ impl Emu {
382388
}
383389
}
384390

391+
fn cartridge_read_rom(&mut self, cpu: CpuType) {
392+
if self.cartridge.need_read {
393+
self.cartridge
394+
.io
395+
.read_slice(self.cartridge.last_read_addr, &mut self.cartridge.read_buf[..self.cartridge.inner[cpu].block_size as usize])
396+
.unwrap();
397+
self.cartridge.need_read = false;
398+
}
399+
}
400+
385401
pub fn cartridge_on_word_read_event<const CPU: CpuType>(&mut self) {
386402
self.cartridge.inner[CPU].rom_ctrl.set_data_word_status(true);
403+
self.cartridge_read_rom(CPU);
387404
self.dma_trigger_imm(CPU, DmaTransferMode::DsCartSlot, 0xF);
388405
}
389406
}

0 commit comments

Comments
 (0)