crustacean_6502_emulator/src/emulator/components.rs

99 lines
2.3 KiB
Rust

use super::addressing_modes::Address;
/* #region Ram */
pub struct Ram(pub [u8; 0x10000]);
impl Ram {
pub fn load(&mut self, code: [u8; 0x10000]) {
self.0 = code;
}
}
impl std::ops::Index<Address> for Ram {
type Output = u8;
fn index(&self, idx: Address) -> &u8 {
let idx: usize = idx.into();
&self.0[idx]
}
}
impl std::ops::IndexMut<Address> for Ram {
fn index_mut(&mut self, idx: Address) -> &mut u8 {
let idx: usize = idx.into();
&mut self.0[idx]
}
}
impl std::ops::Deref for Ram {
type Target = [u8; 0x10000];
fn deref(&self) -> &[u8; 0x10000] {
&self.0
}
}
/* #endregion */
#[repr(u8)]
#[derive(PartialEq, Copy, Clone, Debug)]
pub enum Flags {
Negative = 128,
Overflow = 64,
AlwaysOne = 32,
Break = 16,
Decimal = 8,
Int = 4,
Zero = 2,
Carry = 1,
}
#[allow(non_snake_case)]
pub struct Registers {
pub A: u8,
pub X: u8,
pub Y: u8,
pub PC: Address,
pub flags: u8,
}
impl Registers {
pub fn test(&self, flag: Flags) -> bool {
(self.flags & flag as u8) != 0
}
pub fn set_flag(&mut self, flag: Flags, status: bool) {
if status {
self.flags |= flag as u8;
} else {
self.flags &= 0xFF - flag as u8;
}
}
pub fn add_a(&mut self, n: u8) {
let n = n as u16;
let a = self.A as u16;
let res = n + a;
if res > 0xFF {
self.set_flag(Flags::Carry, true);
} else {
self.set_flag(Flags::Carry, false);
}
self.set_a((res & 0xFF) as u8);
}
pub fn set_a(&mut self, value: u8) {
self.set_flag(Flags::Zero, value == 0x00); // Set Zero if A is zero
self.set_flag(Flags::Negative, value & 0x80 != 0); // Test sign bit
self.A = value;
}
}
impl std::default::Default for Registers {
fn default() -> Self {
Self {
A: 0x00,
X: 0x00,
Y: 0x00,
PC: 0x0000usize.into(),
flags: 0b_0010_0000,
}
}
}
impl std::fmt::Debug for Registers {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(
f,
"Registers: \n PC: {:04X}\n A: {:02X} X: {:02X} Y: {:02X}\nNV-BDIZC\n{:08b}",
*self.PC, self.A, self.X, self.Y, self.flags
)
}
}