avremu/src/regs.rs
2018-02-17 00:18:03 +01:00

181 lines
4.3 KiB
Rust

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<u8> 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<Self, ()> {
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<Self, ()> {
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<u8> for GeneralPurposeRegister {
fn from(v: u8) -> Self {
if v > 31 {
unreachable!();
}
Self { 0: v }
}
}
impl Into<u8> for GeneralPurposeRegister {
fn into(self) -> u8 {
self.0
}
}
impl Into<usize> 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<u8> for GeneralPurposeRegisterPair {
fn from(v: u8) -> Self {
if v > 30 {
println!("v={}", v);
unreachable!();
}
Self { 0: v }
}
}
impl Into<u8> 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;