devices6502 0.1.0

Helper library for cpu6502 implementing memory devices
Documentation
//! Read/write device router.
//!
//! This module provides the [`ReadWrite`] struct, which allows read and write operations to be routed
//! to different devices. This is useful for cases where reads and writes should be handled by separate
//! underlying devices, such as memory-mapped I/O or shadow RAM.

use super::device::Device;

/// A device that routes read and write operations to different underlying devices.
///
/// The `ReadWrite<TR, TW>` struct allows you to combine two devices: one for handling reads (`TR`)
/// and one for handling writes (`TW`). All read operations are forwarded to the `read` device,
/// and all write operations are forwarded to the `write` device.
///
/// # Type Parameters
/// - `TR`: The device type used for reads (must implement [`Device`] and [`Default`])
/// - `TW`: The device type used for writes (must implement [`Device`] and [`Default`])
#[derive(Default)]
pub struct ReadWrite<TR, TW> {
    read: TR,
    write: TW,
}

impl<TR, TW> ReadWrite<TR, TW>
where
    TR: Device + Default,
    TW: Device + Default,
{
    /// Creates a new `ReadWrite` device with both underlying devices initialized to their defaults.
    pub fn new() -> Self {
        Self::default()
    }
}

impl<TR, TW> Device for ReadWrite<TR, TW>
where
    TR: Device + Default,
    TW: Device + Default,
{
    /// Creates a new `ReadWrite` device with both underlying devices initialized from the provided data.
    ///
    /// # Arguments
    /// * `data` - A slice containing the initial data for both devices.
    fn with_data(data: &[u8]) -> Self {
        Self {
            read: TR::with_data(data),
            write: TW::with_data(data),
        }
    }

    /// Initializes the read device with the provided data.
    ///
    /// # Arguments
    /// * `data` - A slice containing the data to copy into the read device.
    fn init_data(&mut self, data: &[u8]) {
        self.read.init_data(data);
    }

    /// Copies the current contents of the read device into the provided buffer.
    ///
    /// # Arguments
    /// * `destination` - The buffer to copy the read device contents to.
    fn cache_current_read_data(&self, destination: &mut [u8]) {
        self.read.cache_current_read_data(destination);
    }

    /// Reads a byte from the read device.
    ///
    /// # Arguments
    /// * `addr` - The address to read from.
    fn read(&self, addr: u16) -> u8 {
        self.read.read(addr)
    }

    /// Writes a byte to the write device.
    ///
    /// # Arguments
    /// * `data` - The byte to write.
    /// * `addr` - The address to write to.
    fn write(&mut self, data: u8, addr: u16) {
        self.write.write(data, addr);
    }

    /// Returns the total size of the address space for the read device.
    fn addr_space_size() -> u32
    where
        Self: Sized,
    {
        TR::addr_space_size()
    }

    /// Returns the number of address bits needed to address the read device.
    fn addr_bits_count() -> u8
    where
        Self: Sized,
    {
        TR::addr_bits_count()
    }

    /// Returns the total size of the address space for the read device (dynamic version).
    fn addr_space_size_dyn(&self) -> u32 {
        self.read.addr_space_size_dyn()
    }

    /// Returns the number of address bits needed to address the read device (dynamic version).
    fn addr_bits_count_dyn(&self) -> u8 {
        self.read.addr_bits_count_dyn()
    }
}