use std::fs::File; use std::io; use std::io::prelude::*; use std::ops::{Deref, DerefMut}; use std::path::Path; use std::ptr; use std::time; use super::bus::{Addr, Bus}; #[cfg(not(target_arch = "wasm32"))] type Instant = time::Instant; #[cfg(not(target_arch = "wasm32"))] fn now() -> Instant { time::Instant::now() } #[cfg(target_arch = "wasm32")] use instant; #[cfg(target_arch = "wasm32")] type Instant = instant::Instant; #[cfg(target_arch = "wasm32")] fn now() -> Instant { instant::Instant::now() } use crate::GameBoyAdvance; #[cfg(feature = "gdb")] use gdbstub; #[cfg(feature = "gdb")] use gdbstub::GdbStub; use std::fmt; #[cfg(feature = "gdb")] use std::net::TcpListener; use std::net::ToSocketAddrs; pub fn spawn_and_run_gdb_server( #[allow(unused)] target: &mut GameBoyAdvance, #[allow(unused)] addr: A, ) -> Result<(), Box> { #[cfg(feature = "gdb")] { info!("spawning gdbserver, listening on {}", addr); let sock = TcpListener::bind(addr)?; let (stream, addr) = sock.accept()?; info!("got connection from {}", addr); let mut gdb = GdbStub::new(stream); let result = match gdb.run(target) { Ok(state) => { info!("Disconnected from GDB. Target state: {:?}", state); Ok(()) } Err(gdbstub::Error::TargetError(e)) => Err(e), Err(e) => return Err(e.into()), }; info!("Debugger session ended, result={:?}", result); } #[cfg(not(feature = "gdb"))] { error!("failed. please compile me with 'gdb' feature") } Ok(()) } pub fn read_bin_file(filename: &Path) -> io::Result> { let mut buf = Vec::new(); let mut file = File::open(filename)?; file.read_to_end(&mut buf)?; Ok(buf) } pub fn write_bin_file(filename: &Path, data: &Vec) -> io::Result<()> { let mut f = File::create(filename)?; f.write_all(data)?; Ok(()) } pub struct FpsCounter { count: u32, timer: Instant, } const SECOND: time::Duration = time::Duration::from_secs(1); impl Default for FpsCounter { fn default() -> FpsCounter { FpsCounter { count: 0, timer: now(), } } } impl FpsCounter { pub fn tick(&mut self) -> Option { self.count += 1; if self.timer.elapsed() >= SECOND { let fps = self.count; self.timer = now(); self.count = 0; Some(fps) } else { None } } } #[macro_export] macro_rules! index2d { ($x:expr, $y:expr, $w:expr) => { $w * $y + $x }; ($t:ty, $x:expr, $y:expr, $w:expr) => { (($w as $t) * ($y as $t) + ($x as $t)) as $t }; } #[allow(unused_macros)] macro_rules! host_breakpoint { () => { #[cfg(debug_assertions)] unsafe { ::std::intrinsics::breakpoint() } }; } pub mod audio { use ringbuf::{Consumer, Producer, RingBuffer}; pub struct AudioRingBuffer { pub prod: Producer, pub cons: Consumer, } impl AudioRingBuffer { pub fn new() -> AudioRingBuffer { let rb = RingBuffer::new(4096 * 2); let (prod, cons) = rb.split(); AudioRingBuffer { prod, cons } } pub fn producer(&mut self) -> &mut Producer { &mut self.prod } pub fn consumer(&mut self) -> &mut Consumer { &mut self.cons } } } #[repr(transparent)] #[derive(Clone)] /// Wrapper for passing raw pointers around. /// Breaks compiler safety guaranties, so must be used with care. pub struct WeakPointer { ptr: *mut T, } impl WeakPointer { pub fn new(ptr: *mut T) -> Self { WeakPointer { ptr } } } impl Deref for WeakPointer { type Target = T; fn deref(&self) -> &T { unsafe { &(*self.ptr) } } } impl DerefMut for WeakPointer { fn deref_mut(&mut self) -> &mut T { unsafe { &mut (*self.ptr) } } } impl Default for WeakPointer { fn default() -> Self { WeakPointer { ptr: ptr::null_mut(), } } } #[derive(Serialize, Deserialize, Clone, Debug)] #[repr(transparent)] pub struct BoxedMemory { pub mem: Box<[u8]>, } impl BoxedMemory { pub fn new(boxed_slice: Box<[u8]>) -> BoxedMemory { BoxedMemory { mem: boxed_slice } } } impl Bus for BoxedMemory { fn read_8(&self, addr: Addr) -> u8 { unsafe { *self.mem.get_unchecked(addr as usize) } } fn write_8(&mut self, addr: Addr, value: u8) { unsafe { *self.mem.get_unchecked_mut(addr as usize) = value; } } }