diff --git a/src/cpu.rs b/src/cpu.rs index f0d2339..4189218 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -14,7 +14,7 @@ pub mod mode; pub mod quirks; use self::{ - bus::{Bus, Get, ReadWrite, Region::*}, + bus::{Bus, Region::*}, flags::Flags, instruction::{ disassembler::{Dis, Disassembler}, @@ -26,6 +26,7 @@ use self::{ use crate::{ bus, error::{Error, Result}, + traits::auto_cast::{AutoCast, Grab}, }; use imperative_rs::InstructionSet; use owo_colors::OwoColorize; @@ -492,7 +493,7 @@ impl CPU { // Fetch slice of memory starting at pc, for var-width opcode 0xf000_iiii let opchunk = self .mem - .get(self.pc as usize..) + .grab(self.pc as usize..) .ok_or(Error::InvalidAddressRange { range: (self.pc as usize..).into(), })?; diff --git a/src/cpu/behavior.rs b/src/cpu/behavior.rs index 172a29a..603e113 100644 --- a/src/cpu/behavior.rs +++ b/src/cpu/behavior.rs @@ -125,7 +125,7 @@ impl CPU { /// /// Corresponds to [Insn::scr] #[inline(always)] - pub(super) fn scroll_right(&mut self, screen: &mut impl ReadWrite) { + pub(super) fn scroll_right(&mut self, screen: &mut impl AutoCast) { // Get a line from the bus for i in (0..16 * 64_usize).step_by(16) { //let line: u128 = bus.read(self.screen + i) >> 4; @@ -137,7 +137,7 @@ impl CPU { /// /// Corresponds to [Insn::scl] #[inline(always)] - pub(super) fn scroll_left(&mut self, screen: &mut impl ReadWrite) { + pub(super) fn scroll_left(&mut self, screen: &mut impl AutoCast) { // Get a line from the bus for i in (0..16 * 64_usize).step_by(16) { let line: u128 = u128::wrapping_shl(screen.read(i), 4); @@ -461,7 +461,7 @@ impl CPU { pub(super) fn draw_sprite(&mut self, x: u16, y: u16, n: Nib, w: u16, h: u16, screen: &mut Bus) { let w_bytes = w / 8; self.v[0xf] = 0; - if let Some(sprite) = self.mem.get(self.i as usize..(self.i + n as u16) as usize) { + if let Some(sprite) = self.mem.grab(self.i as usize..(self.i + n as u16) as usize) { for (line, &sprite) in sprite.iter().enumerate() { let line = line as u16; let sprite = ((sprite as u16) << (8 - (x % 8))).to_be_bytes(); @@ -511,7 +511,7 @@ impl CPU { pub(super) fn draw_schip_sprite(&mut self, x: u16, y: u16, w: u16, screen: &mut Bus) { self.v[0xf] = 0; let w_bytes = w / 8; - if let Some(sprite) = self.mem.get(self.i as usize..(self.i + 32) as usize) { + if let Some(sprite) = self.mem.grab(self.i as usize..(self.i + 32) as usize) { let sprite = sprite.to_owned(); for (line, sprite) in sprite.chunks_exact(2).enumerate() { let sprite = u16::from_be_bytes( @@ -656,7 +656,7 @@ impl CPU { let i = self.i as usize; for (reg, value) in self .mem - .get_mut(i..=i + x) + .grab_mut(i..=i + x) .unwrap_or_default() .iter_mut() .enumerate() @@ -679,7 +679,7 @@ impl CPU { let i = self.i as usize; for (reg, value) in self .mem - .get(i..=i + x) + .grab(i..=i + x) .unwrap_or_default() .iter() .enumerate() @@ -719,7 +719,7 @@ impl CPU { // TODO: Save these, maybe for (reg, value) in self .mem - .get_mut(0..=x) + .grab_mut(0..=x) .unwrap_or_default() .iter_mut() .enumerate() @@ -734,7 +734,7 @@ impl CPU { /// Corresponds to [Insn::flgi] #[inline(always)] pub(super) fn load_flags(&mut self, x: Reg) { - for (reg, value) in self.mem.get(0..=x).unwrap_or_default().iter().enumerate() { + for (reg, value) in self.mem.grab(0..=x).unwrap_or_default().iter().enumerate() { self.v[reg] = *value; } } diff --git a/src/cpu/bus.rs b/src/cpu/bus.rs index 9caad76..03a4e49 100644 --- a/src/cpu/bus.rs +++ b/src/cpu/bus.rs @@ -24,21 +24,14 @@ use std::{ #[macro_export] macro_rules! bus { ($($name:path $(:)? [$range:expr] $(= $data:expr)?) ,* $(,)?) => { - $crate::cpu::bus::Bus::default() - $( - .add_region_owned($name, $range) - $( - .load_region_owned($name, $data) - )? - )* + $crate::cpu::bus::Bus::default()$(.add_region_owned($name, $range)$(.load_region_owned($name, $data))?)* }; } -pub mod read; -pub use read::{Get, ReadWrite}; +pub use crate::traits::auto_cast::{AutoCast, Grab}; // Traits Read and Write are here purely to make implementing other things more bearable -impl Get for Bus { +impl Grab for Bus { /// Gets a slice of [Bus] memory /// # Examples /// ```rust @@ -51,7 +44,7 @@ impl Get for Bus { ///# } /// ``` #[inline(always)] - fn get(&self, index: I) -> Option<&>::Output> + fn grab(&self, index: I) -> Option<&>::Output> where I: SliceIndex<[u8]>, { @@ -70,7 +63,7 @@ impl Get for Bus { ///# } /// ``` #[inline(always)] - fn get_mut(&mut self, index: I) -> Option<&mut >::Output> + fn grab_mut(&mut self, index: I) -> Option<&mut >::Output> where I: SliceIndex<[u8]>, { @@ -294,7 +287,7 @@ impl Bus { #[inline(always)] pub fn get_region(&self, name: Region) -> Option<&[u8]> { debug_assert!(self.region.get(name as usize).is_some()); - self.get(self.region.get(name as usize)?.clone()?) + self.grab(self.region.get(name as usize)?.clone()?) } /// Gets a mutable slice of a named region of memory @@ -311,7 +304,7 @@ impl Bus { #[inline(always)] pub fn get_region_mut(&mut self, name: Region) -> Option<&mut [u8]> { debug_assert!(self.region.get(name as usize).is_some()); - self.get_mut(self.region.get(name as usize)?.clone()?) + self.grab_mut(self.region.get(name as usize)?.clone()?) } /// Prints the region of memory called `Screen` at 1bpp using box characters diff --git a/src/cpu/tests.rs b/src/cpu/tests.rs index 9c856a9..ba8c713 100644 --- a/src/cpu/tests.rs +++ b/src/cpu/tests.rs @@ -959,7 +959,7 @@ mod io { let addr = cpu.i as usize; assert_eq!( cpu.mem - .get(addr..addr.wrapping_add(5)) + .grab(addr..addr.wrapping_add(5)) .expect("Region at addr should exist!"), test.output, ); @@ -1004,7 +1004,10 @@ mod io { cpu.bcd_convert(5); - assert_eq!(cpu.mem.get(addr..addr.saturating_add(3)), Some(test.output)) + assert_eq!( + cpu.mem.grab(addr..addr.saturating_add(3)), + Some(test.output) + ) } } } @@ -1028,7 +1031,7 @@ mod io { // Check that bus grabbed the correct data let bus = cpu .mem - .get_mut(addr..addr + DATA.len()) + .grab_mut(addr..addr + DATA.len()) .expect("Getting a mutable slice at addr 0x0456 should not fail"); assert_eq!(bus[0..=len], DATA[0..=len]); assert_eq!(bus[len + 1..], [0; 16][len + 1..]); @@ -1046,7 +1049,7 @@ mod io { // Load some test data into memory let addr = 0x456; cpu.mem - .get_mut(addr..addr + DATA.len()) + .grab_mut(addr..addr + DATA.len()) .expect("Getting a mutable slice at addr 0x0456..0x0466 should not fail") .write_all(DATA) .unwrap(); diff --git a/src/lib.rs b/src/lib.rs index e8756b3..1c4763b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,10 +10,11 @@ pub mod cpu; pub mod error; +pub mod traits; // Common imports for Chirp pub use cpu::{ - bus::{Bus, Get, ReadWrite, Region::*}, + bus::{Bus, Region::*}, flags::Flags, instruction::disassembler::{Dis, Disassembler}, mode::Mode, @@ -21,6 +22,7 @@ pub use cpu::{ CPU, }; pub use error::{Error, Result}; +pub use traits::auto_cast::{AutoCast, Grab}; /// Holds the state of a Chip-8 #[derive(Clone, Debug, Default, PartialEq)] diff --git a/src/traits.rs b/src/traits.rs new file mode 100644 index 0000000..f333fac --- /dev/null +++ b/src/traits.rs @@ -0,0 +1,6 @@ +// (c) 2023 John A. Breaux +// This code is licensed under MIT license (see LICENSE for details) + +//! Traits useful for Chirp + +pub mod auto_cast; diff --git a/src/cpu/bus/read.rs b/src/traits/auto_cast.rs similarity index 79% rename from src/cpu/bus/read.rs rename to src/traits/auto_cast.rs index 2496fe5..c113361 100644 --- a/src/cpu/bus/read.rs +++ b/src/traits/auto_cast.rs @@ -1,7 +1,9 @@ // (c) 2023 John A. Breaux // This code is licensed under MIT license (see LICENSE for details) -//! Trait for getting a generic integer for a structure. +//! Traits for automatically serializing and deserializing Rust primitive types. +//! +//! Users of this module should impl [Get]`` for their type, which notably returns `&[u8]` and `&mut [u8]` #[allow(unused_imports)] use core::mem::size_of; @@ -11,20 +13,20 @@ use std::{fmt::Debug, slice::SliceIndex}; /// /// This is similar to the [SliceIndex] method `.get(...)`, however implementing this trait /// for [u8] will auto-impl [ReadWrite]<([i8], [u8], [i16], [u16] ... [i128], [u128])> -pub trait Get { +pub trait Grab { /// Gets the slice of Self at [SliceIndex] I - fn get(&self, index: I) -> Option<&>::Output> + fn grab(&self, index: I) -> Option<&>::Output> where I: SliceIndex<[T]>; /// Gets a mutable slice of Self at [SliceIndex] I - fn get_mut(&mut self, index: I) -> Option<&mut >::Output> + fn grab_mut(&mut self, index: I) -> Option<&mut >::Output> where I: SliceIndex<[T]>; } /// Read or Write a T at address `addr` -pub trait ReadWrite: FallibleReadWrite { +pub trait AutoCast: FallibleAutoCast { /// Reads a T from address `addr` /// /// # May Panic @@ -41,7 +43,7 @@ pub trait ReadWrite: FallibleReadWrite { } /// Read a T from address `addr`, and return the value as a [Result] -pub trait FallibleReadWrite: Get { +pub trait FallibleAutoCast: Grab { /// The [Err] type type Error: Debug; /// Read a T from address `addr`, returning the value as a [Result] @@ -58,7 +60,7 @@ pub trait FallibleReadWrite: Get { macro_rules! impl_rw {($($t:ty) ,* $(,)?) =>{ $( #[doc = concat!("Read or Write [", stringify!($t), "] at address `addr`")] - impl + FallibleReadWrite<$t>> ReadWrite<$t> for T { + impl + FallibleAutoCast<$t>> AutoCast<$t> for T { #[inline(always)] fn read(&self, addr: impl Into) -> $t { self.read_fallible(addr).ok().unwrap_or_default() @@ -68,13 +70,13 @@ macro_rules! impl_rw {($($t:ty) ,* $(,)?) =>{ self.write_fallible(addr, data).ok(); } } - impl> FallibleReadWrite<$t> for T { + impl> FallibleAutoCast<$t> for T { type Error = $crate::error::Error; #[inline(always)] fn read_fallible(&self, addr: impl Into) -> $crate::error::Result<$t> { let addr: usize = addr.into(); let range = addr..addr + core::mem::size_of::<$t>(); - if let Some(bytes) = self.get(range.clone()) { + if let Some(bytes) = self.grab(range.clone()) { // Chip-8 is a big-endian system Ok(<$t>::from_be_bytes(bytes.try_into()?)) } else { @@ -84,7 +86,7 @@ macro_rules! impl_rw {($($t:ty) ,* $(,)?) =>{ #[inline(always)] fn write_fallible(&mut self, addr: impl Into, data: $t) -> std::result::Result<(), Self::Error> { let addr: usize = addr.into(); - if let Some(slice) = self.get_mut(addr..addr + core::mem::size_of::<$t>()) { + if let Some(slice) = self.grab_mut(addr..addr + core::mem::size_of::<$t>()) { // Chip-8 is a big-endian system data.to_be_bytes().as_mut().swap_with_slice(slice); } @@ -94,6 +96,7 @@ macro_rules! impl_rw {($($t:ty) ,* $(,)?) =>{ )* }} +// Using macro to be "generic" over types without traits in common impl_rw!(i8, i16, i32, i64, i128); impl_rw!(u8, u16, u32, u64, u128); impl_rw!(f32, f64);