use std::cmp::PartialEq; use std::fmt; // Sreg flags, ordered from bit 7 to bit 0. #[derive(Copy, Clone, Debug)] pub enum StatusFlag { // I GlobalInterruptEnable = 1 << 7, // T BitCopyStorage = 1 << 6, // H HalfCarry = 1 << 5, // S SignBit = 1 << 4, // V TwosComplementOverflow = 1 << 3, // N Negative = 1 << 2, // Z Zero = 1 << 1, // C Carry = 1 << 0, } impl fmt::Display for StatusFlag { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", match *self { StatusFlag::GlobalInterruptEnable => "I", StatusFlag::BitCopyStorage => "T", StatusFlag::HalfCarry => "H", StatusFlag::SignBit => "S", StatusFlag::TwosComplementOverflow => "V", StatusFlag::Negative => "N", StatusFlag::Zero => "Z", StatusFlag::Carry => "C", }) } } impl Into for StatusFlag { fn into(self) -> u8 { 1 << match self { StatusFlag::GlobalInterruptEnable => 7, StatusFlag::BitCopyStorage => 6, StatusFlag::HalfCarry => 5, StatusFlag::SignBit => 4, StatusFlag::TwosComplementOverflow => 3, StatusFlag::Negative => 2, StatusFlag::Zero => 1, StatusFlag::Carry => 0, } } } impl StatusFlag { // the try_from is unstable, so use our own here. pub fn try_from(i: u8) -> Result { match i { 0x80 => Ok(StatusFlag::GlobalInterruptEnable), 0x40 => Ok(StatusFlag::BitCopyStorage), 0x20 => Ok(StatusFlag::HalfCarry), 0x10 => Ok(StatusFlag::SignBit), 0x08 => Ok(StatusFlag::TwosComplementOverflow), 0x04 => Ok(StatusFlag::Negative), 0x02 => Ok(StatusFlag::Zero), 0x01 => Ok(StatusFlag::Carry), _ => Err(()), } } pub fn try_from_idx(i: u8) -> Result { if i > 7 { Err(()) } else { Ok([ StatusFlag::Carry, StatusFlag::Zero, StatusFlag::Negative, StatusFlag::TwosComplementOverflow, StatusFlag::SignBit, StatusFlag::HalfCarry, StatusFlag::BitCopyStorage, StatusFlag::GlobalInterruptEnable ][i as usize]) } } } // type GeneralPurposeRegister = struct(u8); #[derive(Debug)] pub struct GeneralPurposeRegister(u8); impl From for GeneralPurposeRegister { fn from(v: u8) -> Self { if v > 31 { unreachable!(); } Self{0: v} } } impl Into for GeneralPurposeRegister { fn into(self) -> u8 { self.0 } } impl Into for GeneralPurposeRegister { fn into(self) -> usize { self.0 as usize } } impl GeneralPurposeRegister { pub fn as_usize(&self) -> usize { self.0 as usize } } impl PartialEq for GeneralPurposeRegister { fn eq(&self, other: &GeneralPurposeRegister) -> bool { self.0 == other.0 } } impl fmt::Display for GeneralPurposeRegister { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "R{}", self.0) } } // Mostly the same as above, but we want to make it a different type. // type GeneralPurposeRegisterPair = struct(u8); #[derive(Debug)] pub struct GeneralPurposeRegisterPair(u8); impl From for GeneralPurposeRegisterPair { fn from(v: u8) -> Self { if v > 30 { println!("v={}", v); unreachable!(); } Self{0: v} } } impl Into for GeneralPurposeRegisterPair { fn into(self) -> u8 { self.0 } } impl PartialEq for GeneralPurposeRegisterPair { fn eq(&self, other: &GeneralPurposeRegisterPair) -> bool { self.0 == other.0 } } impl GeneralPurposeRegisterPair { pub fn low(&self) -> usize { self.0 as usize } pub fn high(&self) -> usize { self.0 as usize + 1 } } impl fmt::Display for GeneralPurposeRegisterPair { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "R{}:R{}", self.high(), self.low()) } } pub type PC = u32; // TODO: Struct :) pub type IORegister = u16;