osiris-process 0.3.1

A processor implementation.
Documentation
//! This module describes ways to identify chunks in registers bank and wraps an integral and a floating-point implementation.

use std::ops::RangeInclusive;
use std::hash::{Hash, Hasher};
use std::fmt::{Debug, Display, Formatter};

use osiris_data::data::identification::Identifier;

/// A wide range.
pub const REGISTERS_IN_BANK: usize = 65536;

pub type RangeApplication<T> = fn(&[T]) -> T;

pub trait RegisterBank<T>: where Self: Sized {

    /// Create a new complete bank with register initialized at their default value.
    fn new() -> Self;
    
    /// Sets a specific register in the bank.
    fn set(&mut self, register: RegisterId, raw: T);
    
    /// Gets a specific register from the bank.
    fn get(&self, register: RegisterId) -> T;
    
    /// Apply the specified [RangeApplication] in the bank on the specified [RegisterRange].
    fn apply(&self, range: RegisterRange, function: RangeApplication<T>) -> T;

    /// Return a slice from the specified range in the bank.
    fn slice(&self, range: RegisterRange) -> &[T];

    /// Copy the specified slice into the bank to the specified [RegisterId] and nexts.
    ///
    /// Do not overflow. Only the fitting elements are copied. 
    fn copy(&mut self, to: RegisterId, slice: &[T]);
}

/// A type which always represents a valid register in a bank.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct RegisterId(u16);

impl RegisterId {
    /// Identify a register.
    pub const fn new(raw: u16) -> Self { Self(raw) }
    /// Returns the raw `u16` of this identifier.
    pub const fn to_u16(&self) -> u16 { self.0 }
}

impl Hash for RegisterId {
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_usize(self.to_usize());
    }
}

impl Identifier for RegisterId {
    fn to_usize(&self) -> usize { self.0 as usize }
}

/// Represents a range of registers in a bank.
/// 
/// A range is at least 1 register long (if `start == end`).
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct RegisterRange {
    /// The first register in the range.
    pub start: RegisterId,
    /// The last register in the range.
    pub end: RegisterId,
}

impl RegisterRange {
    /// Creates a range from a start and an end [RegisterId]s.
    ///
    /// May **panic** if `end < start`.
    pub fn new(start: RegisterId, end: RegisterId) -> Self {
        if end < start {
            panic!("End of a range cannot be lower to its start.")
        }
        Self { start, end }
    }

    /// Creates a range from a raw `u32`.
    pub fn from_u32(data: u32) -> Self {
        Self {
            start: RegisterId((data >> 16) as u16),
            end: RegisterId(data as u16),
        }
    }

    /// Returns a range usable to extract a slice notably.
    pub fn to_usize_range(&self) -> RangeInclusive<usize> { self.start.to_usize()..=self.end.to_usize() }

    /// Returns a raw `u32` representing the range.
    pub fn to_u32(&self) -> u32 { (self.start.to_u16() as u32) << 16 | self.end.to_u16() as u32 }

    /// Returns the number of registers included in the range.
    pub fn count(&self) -> usize { self.end.to_usize() - self.start.to_usize() + 1 }
}

impl Display for RegisterRange {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "[{:04x}:{:04x}]", self.start.to_u16(), self.end.to_u16())
    }
}

#[cfg(feature = "base-integral")]
pub mod integral;

#[cfg(feature = "state")]
pub mod state;

#[cfg(feature = "base-floating")]
pub mod floating_point;