auto_cast: Move out of bus module
This commit is contained in:
parent
beab7c968b
commit
f4d7e514bc
@ -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(),
|
||||
})?;
|
||||
|
@ -125,7 +125,7 @@ impl CPU {
|
||||
///
|
||||
/// Corresponds to [Insn::scr]
|
||||
#[inline(always)]
|
||||
pub(super) fn scroll_right(&mut self, screen: &mut impl ReadWrite<u128>) {
|
||||
pub(super) fn scroll_right(&mut self, screen: &mut impl AutoCast<u128>) {
|
||||
// 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<u128>) {
|
||||
pub(super) fn scroll_left(&mut self, screen: &mut impl AutoCast<u128>) {
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
@ -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<u8> for Bus {
|
||||
impl Grab<u8> for Bus {
|
||||
/// Gets a slice of [Bus] memory
|
||||
/// # Examples
|
||||
/// ```rust
|
||||
@ -51,7 +44,7 @@ impl Get<u8> for Bus {
|
||||
///# }
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[u8]>>::Output>
|
||||
fn grab<I>(&self, index: I) -> Option<&<I as SliceIndex<[u8]>>::Output>
|
||||
where
|
||||
I: SliceIndex<[u8]>,
|
||||
{
|
||||
@ -70,7 +63,7 @@ impl Get<u8> for Bus {
|
||||
///# }
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
fn get_mut<I>(&mut self, index: I) -> Option<&mut <I as SliceIndex<[u8]>>::Output>
|
||||
fn grab_mut<I>(&mut self, index: I) -> Option<&mut <I as SliceIndex<[u8]>>::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
|
||||
|
@ -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();
|
||||
|
@ -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)]
|
||||
|
6
src/traits.rs
Normal file
6
src/traits.rs
Normal file
@ -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;
|
@ -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]`<u8>` 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<T> {
|
||||
pub trait Grab<T> {
|
||||
/// Gets the slice of Self at [SliceIndex] I
|
||||
fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
|
||||
fn grab<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
|
||||
where
|
||||
I: SliceIndex<[T]>;
|
||||
|
||||
/// Gets a mutable slice of Self at [SliceIndex] I
|
||||
fn get_mut<I>(&mut self, index: I) -> Option<&mut <I as SliceIndex<[T]>>::Output>
|
||||
fn grab_mut<I>(&mut self, index: I) -> Option<&mut <I as SliceIndex<[T]>>::Output>
|
||||
where
|
||||
I: SliceIndex<[T]>;
|
||||
}
|
||||
|
||||
/// Read or Write a T at address `addr`
|
||||
pub trait ReadWrite<T>: FallibleReadWrite<T> {
|
||||
pub trait AutoCast<T>: FallibleAutoCast<T> {
|
||||
/// Reads a T from address `addr`
|
||||
///
|
||||
/// # May Panic
|
||||
@ -41,7 +43,7 @@ pub trait ReadWrite<T>: FallibleReadWrite<T> {
|
||||
}
|
||||
|
||||
/// Read a T from address `addr`, and return the value as a [Result]
|
||||
pub trait FallibleReadWrite<T>: Get<u8> {
|
||||
pub trait FallibleAutoCast<T>: Grab<u8> {
|
||||
/// 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<T>: Get<u8> {
|
||||
macro_rules! impl_rw {($($t:ty) ,* $(,)?) =>{
|
||||
$(
|
||||
#[doc = concat!("Read or Write [", stringify!($t), "] at address `addr`")]
|
||||
impl<T: Get<u8> + FallibleReadWrite<$t>> ReadWrite<$t> for T {
|
||||
impl<T: Grab<u8> + FallibleAutoCast<$t>> AutoCast<$t> for T {
|
||||
#[inline(always)]
|
||||
fn read(&self, addr: impl Into<usize>) -> $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<T: Get<u8>> FallibleReadWrite<$t> for T {
|
||||
impl<T: Grab<u8>> FallibleAutoCast<$t> for T {
|
||||
type Error = $crate::error::Error;
|
||||
#[inline(always)]
|
||||
fn read_fallible(&self, addr: impl Into<usize>) -> $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<usize>, 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);
|
Loading…
Reference in New Issue
Block a user