looklook 0.9.0

Descriptive signal synthesiser.
// Copyright 2026 Gabriel Bjørnager Jensen.
//
// This file is part of LOOKLOOK.
//
// LOOKLOOK is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free Software
// Foundation, either version 3 of the License, or (at your option) any later ver-
// sion.
//
// LOOKLOOK is distributed in the hope that it will be useful, but WITHOUT ANY WAR-
// RANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
// PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License along
// with LOOKLOOK. If not, see <https://www.gnu.org/licenses/>.

//! The [`Regs`] type.

mod tests;

use crate::isa::{An, Long, Dn, Sr};

/// Regsisters.
#[derive(Debug)]
pub struct Regs {
	/// The data registers `D0` through `D7`.
	data: [Long; 8],

	/// The address registers `A0` through `A7`.
	address: [Long; 8],

	/// The `PC` programme counter.
	pc: Long,

	/// The `SR` status register.
	sr: Sr,
}

impl Regs {
	/// Constructs a new, default stack.
	#[inline]
	#[must_use]
	pub const fn new() -> Self {
		Self {
			data:    [Default::default(); _],
			address: [Default::default(); _],
			pc:      Default::default(),
			sr:      Default::default(),
		}
	}

	/// Prints the register values to standard error.
	pub fn print(&self) {
		eprintln!();
		eprintln!("d0: {}    a0: {}", self.dn(Dn::D0), self.an(An::A0));
		eprintln!("d1: {}    a1: {}", self.dn(Dn::D1), self.an(An::A1));
		eprintln!("d2: {}    a2: {}", self.dn(Dn::D2), self.an(An::A2));
		eprintln!("d3: {}    a3: {}", self.dn(Dn::D3), self.an(An::A3));
		eprintln!("d4: {}    a4: {}", self.dn(Dn::D4), self.an(An::A4));
		eprintln!("d5: {}    a5: {}", self.dn(Dn::D5), self.an(An::A5));
		eprintln!("d6: {}    fp: {}", self.dn(Dn::D6), self.an(An::Fp));
		eprintln!("d7: {}    sp: {}", self.dn(Dn::D7), self.an(An::Sp));
		eprintln!("pc: {}    sr: {:?}", self.pc(), self.sr());
	}

	/// Copies a data register.
	#[inline]
	#[must_use]
	pub const fn dn(&self, index: Dn) -> Long {
		self.data[index.as_usize()]
	}

	/// Mutably borrows a data register.
	#[inline]
	pub const fn dn_mut(&mut self, index: Dn) -> &mut Long {
		&mut self.data[index.as_usize()]
	}

	/// Copies an address register.
	#[inline]
	#[must_use]
	pub const fn an(&self, index: An) -> Long {
		self.address[index.as_usize()]
	}

	/// Mutably borrows an address register.
	#[inline]
	pub const fn an_mut(&mut self, index: An) -> &mut Long {
		&mut self.address[index.as_usize()]
	}

	/// Copies the programme counter.
	#[inline(always)]
	#[must_use]
	pub const fn pc(&self) -> Long {
		self.pc
	}

	/// Mutably borrows the programme counter.
	#[inline(always)]
	#[must_use]
	pub const fn pc_mut(&mut self) -> &mut Long {
		&mut self.pc
	}

	/// Increments the programme counter by a specific amount.
	///
	/// The result is truncated to fit `32` bits.
	#[inline]
	pub const fn inc_pc(&mut self, value: u32) {
		let result = self.pc.as_u32().wrapping_add(value);
		self.pc = Long::from_u32(result);
	}

	/// Copies the status register.
	#[inline(always)]
	#[must_use]
	pub const fn sr(&self) -> Sr {
		self.sr
	}

	/// Mutably borrows the status register.
	#[inline(always)]
	#[must_use]
	pub const fn sr_mut(&mut self) -> &mut Sr {
		&mut self.sr
	}

	/// Resets all entire registers.
	#[inline]
	pub const fn clear(&mut self) {
		*self = Self::new();
	}
}

const impl Default for Regs {
	#[inline(always)]
	fn default() -> Self {
		const { Self::new() }
	}
}