1
0
mirror of https://github.com/mre/mos6502.git synced 2024-06-25 22:29:35 +00:00

fix the build for namespaced enums

This commit is contained in:
Johannes Muenzel 2014-11-20 18:33:23 -05:00
parent 90b353e991
commit c01995ba55
2 changed files with 293 additions and 292 deletions

View File

@ -113,7 +113,7 @@ pub enum Instruction
, TYA // Transfer Y to Accumulator..... | N. ...Z. A = Y , TYA // Transfer Y to Accumulator..... | N. ...Z. A = Y
} }
pub enum AMOut { pub enum OpInput {
UseImplied, UseImplied,
UseImmediate(u8), UseImmediate(u8),
UseRelative(i8), UseRelative(i8),
@ -149,24 +149,24 @@ fn arr_to_addr(arr: &[u8]) -> Address {
impl AddressingMode { impl AddressingMode {
pub fn extra_bytes(self) -> AddressDiff { pub fn extra_bytes(self) -> AddressDiff {
let x = match self { let x = match self {
Accumulator => 0, AddressingMode::Accumulator => 0,
Implied => 0, AddressingMode::Implied => 0,
Immediate => 1, AddressingMode::Immediate => 1,
ZeroPage => 1, AddressingMode::ZeroPage => 1,
ZeroPageX => 1, AddressingMode::ZeroPageX => 1,
ZeroPageY => 1, AddressingMode::ZeroPageY => 1,
Relative => 1, AddressingMode::Relative => 1,
Absolute => 2, AddressingMode::Absolute => 2,
AbsoluteX => 2, AddressingMode::AbsoluteX => 2,
AbsoluteY => 2, AddressingMode::AbsoluteY => 2,
Indirect => 2, AddressingMode::Indirect => 2,
IndexedIndirectX => 1, AddressingMode::IndexedIndirectX => 1,
IndirectIndexedY => 1, AddressingMode::IndirectIndexedY => 1,
}; };
AddressDiff(x) AddressDiff(x)
} }
pub fn process(self, machine: &Machine, arr: &[u8]) -> AMOut { pub fn process(self, machine: &Machine, arr: &[u8]) -> OpInput {
debug_assert!({let AddressDiff(x) = self.extra_bytes(); debug_assert!({let AddressDiff(x) = self.extra_bytes();
arr.len() == x as uint}); arr.len() == x as uint});
@ -177,60 +177,60 @@ impl AddressingMode {
let memory = &machine.memory; let memory = &machine.memory;
match self { match self {
Accumulator | Implied => { AddressingMode::Accumulator | AddressingMode::Implied => {
// Always the same -- no input // Always the same -- no input
UseImplied OpInput::UseImplied
}, },
Immediate => { AddressingMode::Immediate => {
// Use [u8, ..1] specified in instruction as input // Use [u8, ..1] specified in instruction as input
UseImmediate(arr[0]) OpInput::UseImmediate(arr[0])
}, },
ZeroPage => { AddressingMode::ZeroPage => {
// Use [u8, ..1] from instruction // Use [u8, ..1] from instruction
// Interpret as zero page address // Interpret as zero page address
// (Output: an 8-bit zero-page address) // (Output: an 8-bit zero-page address)
UseAddress(Address(arr[0] as u16)) OpInput::UseAddress(Address(arr[0] as u16))
}, },
ZeroPageX => { AddressingMode::ZeroPageX => {
// Use [u8, ..1] from instruction // Use [u8, ..1] from instruction
// Add to X register (as u8 -- the final address is in 0-page) // Add to X register (as u8 -- the final address is in 0-page)
// (Output: an 8-bit zero-page address) // (Output: an 8-bit zero-page address)
UseAddress(Address((arr[0] + x) as u16)) OpInput::UseAddress(Address((arr[0] + x) as u16))
}, },
ZeroPageY => { AddressingMode::ZeroPageY => {
// Use [u8, ..1] from instruction // Use [u8, ..1] from instruction
// Add to Y register (as u8 -- the final address is in 0-page) // Add to Y register (as u8 -- the final address is in 0-page)
// (Output: an 8-bit zero-page address) // (Output: an 8-bit zero-page address)
UseAddress(Address((arr[0] + y) as u16)) OpInput::UseAddress(Address((arr[0] + y) as u16))
}, },
Relative => { AddressingMode::Relative => {
// Use [u8, ..1] from instruction // Use [u8, ..1] from instruction
// (interpret as relative...) // (interpret as relative...)
UseRelative(arr[0] as i8) OpInput::UseRelative(arr[0] as i8)
}, },
Absolute => { AddressingMode::Absolute => {
// Use [u8, ..2] from instruction as address // Use [u8, ..2] from instruction as address
// (Output: a 16-bit address) // (Output: a 16-bit address)
UseAddress(arr_to_addr(arr)) OpInput::UseAddress(arr_to_addr(arr))
}, },
AbsoluteX => { AddressingMode::AbsoluteX => {
// Use [u8, ..2] from instruction as address, add X // Use [u8, ..2] from instruction as address, add X
// (Output: a 16-bit address) // (Output: a 16-bit address)
UseAddress(arr_to_addr(arr) + AddressDiff(x as i32)) OpInput::UseAddress(arr_to_addr(arr) + AddressDiff(x as i32))
}, },
AbsoluteY => { AddressingMode::AbsoluteY => {
// Use [u8, ..2] from instruction as address, add Y // Use [u8, ..2] from instruction as address, add Y
// (Output: a 16-bit address) // (Output: a 16-bit address)
UseAddress(arr_to_addr(arr) + AddressDiff(y as i32)) OpInput::UseAddress(arr_to_addr(arr) + AddressDiff(y as i32))
}, },
Indirect => { AddressingMode::Indirect => {
// Use [u8, ..2] from instruction as an address. Interpret the // Use [u8, ..2] from instruction as an address. Interpret the
// two bytes starting at that address as an address. // two bytes starting at that address as an address.
// (Output: a 16-bit address) // (Output: a 16-bit address)
let slice = memory.get_slice(arr_to_addr(arr), AddressDiff(2)); let slice = memory.get_slice(arr_to_addr(arr), AddressDiff(2));
UseAddress(arr_to_addr(slice)) OpInput::UseAddress(arr_to_addr(slice))
}, },
IndexedIndirectX => { AddressingMode::IndexedIndirectX => {
// Use [u8, ..1] from instruction // Use [u8, ..1] from instruction
// Add to X register with 0-page wraparound, like ZeroPageX. // Add to X register with 0-page wraparound, like ZeroPageX.
// This is where the absolute (16-bit) target address is stored. // This is where the absolute (16-bit) target address is stored.
@ -238,9 +238,9 @@ impl AddressingMode {
let start = arr[0] + x; let start = arr[0] + x;
let slice = memory.get_slice(Address(start as u16), let slice = memory.get_slice(Address(start as u16),
AddressDiff(2)); AddressDiff(2));
UseAddress(arr_to_addr(slice)) OpInput::UseAddress(arr_to_addr(slice))
}, },
IndirectIndexedY => { AddressingMode::IndirectIndexedY => {
// Use [u8, ..1] from instruction // Use [u8, ..1] from instruction
// This is where the absolute (16-bit) target address is stored. // This is where the absolute (16-bit) target address is stored.
// Add Y register to this address to get the final address // Add Y register to this address to get the final address
@ -248,270 +248,270 @@ impl AddressingMode {
let start = arr[0]; let start = arr[0];
let slice = memory.get_slice(Address(start as u16), let slice = memory.get_slice(Address(start as u16),
AddressDiff(2)); AddressDiff(2));
UseAddress(arr_to_addr(slice) + AddressDiff(y as i32)) OpInput::UseAddress(arr_to_addr(slice) + AddressDiff(y as i32))
}, },
} }
} }
} }
pub type DecodedInstr = (Instruction, AMOut); pub type DecodedInstr = (Instruction, OpInput);
pub static OPCODES: [Option<(Instruction, AddressingMode)>, ..256] = [ pub static OPCODES: [Option<(Instruction, AddressingMode)>, ..256] = [
/*0x00*/ Some((BRK, Implied)), /*0x00*/ Some((Instruction::BRK, AddressingMode::Implied)),
/*0x01*/ Some((ORA, IndexedIndirectX)), /*0x01*/ Some((Instruction::ORA, AddressingMode::IndexedIndirectX)),
/*0x02*/ None, /*0x02*/ None,
/*0x03*/ None, /*0x03*/ None,
/*0x04*/ None, /*0x04*/ None,
/*0x05*/ Some((ORA, ZeroPage)), /*0x05*/ Some((Instruction::ORA, AddressingMode::ZeroPage)),
/*0x06*/ Some((ASL, ZeroPage)), /*0x06*/ Some((Instruction::ASL, AddressingMode::ZeroPage)),
/*0x07*/ None, /*0x07*/ None,
/*0x08*/ Some((PHP, Implied)), /*0x08*/ Some((Instruction::PHP, AddressingMode::Implied)),
/*0x09*/ Some((ORA, Immediate)), /*0x09*/ Some((Instruction::ORA, AddressingMode::Immediate)),
/*0x0A*/ Some((ASL, Accumulator)), /*0x0A*/ Some((Instruction::ASL, AddressingMode::Accumulator)),
/*0x0B*/ None, /*0x0B*/ None,
/*0x0C*/ None, /*0x0C*/ None,
/*0x0D*/ Some((ORA, Absolute)), /*0x0D*/ Some((Instruction::ORA, AddressingMode::Absolute)),
/*0x0E*/ Some((ASL, Absolute)), /*0x0E*/ Some((Instruction::ASL, AddressingMode::Absolute)),
/*0x0F*/ None, /*0x0F*/ None,
/*0x10*/ Some((BPL, Relative)), /*0x10*/ Some((Instruction::BPL, AddressingMode::Relative)),
/*0x11*/ Some((ORA, IndirectIndexedY)), /*0x11*/ Some((Instruction::ORA, AddressingMode::IndirectIndexedY)),
/*0x12*/ None, /*0x12*/ None,
/*0x13*/ None, /*0x13*/ None,
/*0x14*/ None, /*0x14*/ None,
/*0x15*/ Some((ORA, ZeroPageX)), /*0x15*/ Some((Instruction::ORA, AddressingMode::ZeroPageX)),
/*0x16*/ Some((ASL, ZeroPageX)), /*0x16*/ Some((Instruction::ASL, AddressingMode::ZeroPageX)),
/*0x17*/ None, /*0x17*/ None,
/*0x18*/ Some((CLC, Implied)), /*0x18*/ Some((Instruction::CLC, AddressingMode::Implied)),
/*0x19*/ Some((ORA, AbsoluteY)), /*0x19*/ Some((Instruction::ORA, AddressingMode::AbsoluteY)),
/*0x1A*/ None, /*0x1A*/ None,
/*0x1B*/ None, /*0x1B*/ None,
/*0x1C*/ None, /*0x1C*/ None,
/*0x1D*/ Some((ORA, AbsoluteX)), /*0x1D*/ Some((Instruction::ORA, AddressingMode::AbsoluteX)),
/*0x1E*/ Some((ASL, AbsoluteX)), /*0x1E*/ Some((Instruction::ASL, AddressingMode::AbsoluteX)),
/*0x1F*/ None, /*0x1F*/ None,
/*0x20*/ Some((JSR, Absolute)), /*0x20*/ Some((Instruction::JSR, AddressingMode::Absolute)),
/*0x21*/ Some((AND, IndexedIndirectX)), /*0x21*/ Some((Instruction::AND, AddressingMode::IndexedIndirectX)),
/*0x22*/ None, /*0x22*/ None,
/*0x23*/ None, /*0x23*/ None,
/*0x24*/ Some((BIT, ZeroPage)), /*0x24*/ Some((Instruction::BIT, AddressingMode::ZeroPage)),
/*0x25*/ Some((AND, ZeroPage)), /*0x25*/ Some((Instruction::AND, AddressingMode::ZeroPage)),
/*0x26*/ Some((ROL, ZeroPage)), /*0x26*/ Some((Instruction::ROL, AddressingMode::ZeroPage)),
/*0x27*/ None, /*0x27*/ None,
/*0x28*/ Some((PLP, Implied)), /*0x28*/ Some((Instruction::PLP, AddressingMode::Implied)),
/*0x29*/ Some((AND, Immediate)), /*0x29*/ Some((Instruction::AND, AddressingMode::Immediate)),
/*0x2A*/ Some((ROL, Accumulator)), /*0x2A*/ Some((Instruction::ROL, AddressingMode::Accumulator)),
/*0x2B*/ None, /*0x2B*/ None,
/*0x2C*/ Some((BIT, Absolute)), /*0x2C*/ Some((Instruction::BIT, AddressingMode::Absolute)),
/*0x2D*/ Some((AND, Absolute)), /*0x2D*/ Some((Instruction::AND, AddressingMode::Absolute)),
/*0x2E*/ Some((ROL, Absolute)), /*0x2E*/ Some((Instruction::ROL, AddressingMode::Absolute)),
/*0x2F*/ None, /*0x2F*/ None,
/*0x30*/ Some((BMI, Relative)), /*0x30*/ Some((Instruction::BMI, AddressingMode::Relative)),
/*0x31*/ Some((AND, IndirectIndexedY)), /*0x31*/ Some((Instruction::AND, AddressingMode::IndirectIndexedY)),
/*0x32*/ None, /*0x32*/ None,
/*0x33*/ None, /*0x33*/ None,
/*0x34*/ None, /*0x34*/ None,
/*0x35*/ Some((AND, ZeroPageX)), /*0x35*/ Some((Instruction::AND, AddressingMode::ZeroPageX)),
/*0x36*/ Some((ROL, ZeroPageX)), /*0x36*/ Some((Instruction::ROL, AddressingMode::ZeroPageX)),
/*0x37*/ None, /*0x37*/ None,
/*0x38*/ Some((SEC, Implied)), /*0x38*/ Some((Instruction::SEC, AddressingMode::Implied)),
/*0x39*/ Some((AND, AbsoluteY)), /*0x39*/ Some((Instruction::AND, AddressingMode::AbsoluteY)),
/*0x3A*/ None, /*0x3A*/ None,
/*0x3B*/ None, /*0x3B*/ None,
/*0x3C*/ None, /*0x3C*/ None,
/*0x3D*/ Some((AND, AbsoluteX)), /*0x3D*/ Some((Instruction::AND, AddressingMode::AbsoluteX)),
/*0x3E*/ Some((ROL, AbsoluteX)), /*0x3E*/ Some((Instruction::ROL, AddressingMode::AbsoluteX)),
/*0x3F*/ None, /*0x3F*/ None,
/*0x40*/ Some((RTI, Implied)), /*0x40*/ Some((Instruction::RTI, AddressingMode::Implied)),
/*0x41*/ Some((EOR, IndexedIndirectX)), /*0x41*/ Some((Instruction::EOR, AddressingMode::IndexedIndirectX)),
/*0x42*/ None, /*0x42*/ None,
/*0x43*/ None, /*0x43*/ None,
/*0x44*/ None, /*0x44*/ None,
/*0x45*/ Some((EOR, ZeroPage)), /*0x45*/ Some((Instruction::EOR, AddressingMode::ZeroPage)),
/*0x46*/ Some((LSR, ZeroPage)), /*0x46*/ Some((Instruction::LSR, AddressingMode::ZeroPage)),
/*0x47*/ None, /*0x47*/ None,
/*0x48*/ Some((PHA, Implied)), /*0x48*/ Some((Instruction::PHA, AddressingMode::Implied)),
/*0x49*/ Some((EOR, Immediate)), /*0x49*/ Some((Instruction::EOR, AddressingMode::Immediate)),
/*0x4A*/ Some((LSR, Accumulator)), /*0x4A*/ Some((Instruction::LSR, AddressingMode::Accumulator)),
/*0x4B*/ None, /*0x4B*/ None,
/*0x4C*/ Some((JMP, Absolute)), /*0x4C*/ Some((Instruction::JMP, AddressingMode::Absolute)),
/*0x4D*/ Some((EOR, Absolute)), /*0x4D*/ Some((Instruction::EOR, AddressingMode::Absolute)),
/*0x4E*/ Some((LSR, Absolute)), /*0x4E*/ Some((Instruction::LSR, AddressingMode::Absolute)),
/*0x4F*/ None, /*0x4F*/ None,
/*0x50*/ Some((BVC, Relative)), /*0x50*/ Some((Instruction::BVC, AddressingMode::Relative)),
/*0x51*/ Some((EOR, IndirectIndexedY)), /*0x51*/ Some((Instruction::EOR, AddressingMode::IndirectIndexedY)),
/*0x52*/ None, /*0x52*/ None,
/*0x53*/ None, /*0x53*/ None,
/*0x54*/ None, /*0x54*/ None,
/*0x55*/ Some((EOR, ZeroPageX)), /*0x55*/ Some((Instruction::EOR, AddressingMode::ZeroPageX)),
/*0x56*/ Some((LSR, ZeroPageX)), /*0x56*/ Some((Instruction::LSR, AddressingMode::ZeroPageX)),
/*0x57*/ None, /*0x57*/ None,
/*0x58*/ None, /*0x58*/ None,
/*0x59*/ Some((EOR, AbsoluteY)), /*0x59*/ Some((Instruction::EOR, AddressingMode::AbsoluteY)),
/*0x5A*/ None, /*0x5A*/ None,
/*0x5B*/ None, /*0x5B*/ None,
/*0x5C*/ None, /*0x5C*/ None,
/*0x5D*/ Some((EOR, AbsoluteX)), /*0x5D*/ Some((Instruction::EOR, AddressingMode::AbsoluteX)),
/*0x5E*/ Some((LSR, AbsoluteX)), /*0x5E*/ Some((Instruction::LSR, AddressingMode::AbsoluteX)),
/*0x5F*/ None, /*0x5F*/ None,
/*0x60*/ Some((RTS, Implied)), /*0x60*/ Some((Instruction::RTS, AddressingMode::Implied)),
/*0x61*/ Some((ADC, IndexedIndirectX)), /*0x61*/ Some((Instruction::ADC, AddressingMode::IndexedIndirectX)),
/*0x62*/ None, /*0x62*/ None,
/*0x63*/ None, /*0x63*/ None,
/*0x64*/ None, /*0x64*/ None,
/*0x65*/ Some((ADC, ZeroPage)), /*0x65*/ Some((Instruction::ADC, AddressingMode::ZeroPage)),
/*0x66*/ Some((ROR, ZeroPage)), /*0x66*/ Some((Instruction::ROR, AddressingMode::ZeroPage)),
/*0x67*/ None, /*0x67*/ None,
/*0x68*/ Some((PLA, Implied)), /*0x68*/ Some((Instruction::PLA, AddressingMode::Implied)),
/*0x69*/ Some((ADC, Immediate)), /*0x69*/ Some((Instruction::ADC, AddressingMode::Immediate)),
/*0x6A*/ Some((ROR, Accumulator)), /*0x6A*/ Some((Instruction::ROR, AddressingMode::Accumulator)),
/*0x6B*/ None, /*0x6B*/ None,
/*0x6C*/ Some((JMP, Indirect)), /*0x6C*/ Some((Instruction::JMP, AddressingMode::Indirect)),
/*0x6D*/ Some((ADC, Absolute)), /*0x6D*/ Some((Instruction::ADC, AddressingMode::Absolute)),
/*0x6E*/ Some((ROR, Absolute)), /*0x6E*/ Some((Instruction::ROR, AddressingMode::Absolute)),
/*0x6F*/ None, /*0x6F*/ None,
/*0x70*/ Some((BVS, Relative)), /*0x70*/ Some((Instruction::BVS, AddressingMode::Relative)),
/*0x71*/ Some((ADC, IndirectIndexedY)), /*0x71*/ Some((Instruction::ADC, AddressingMode::IndirectIndexedY)),
/*0x72*/ None, /*0x72*/ None,
/*0x73*/ None, /*0x73*/ None,
/*0x74*/ None, /*0x74*/ None,
/*0x75*/ Some((ADC, ZeroPageX)), /*0x75*/ Some((Instruction::ADC, AddressingMode::ZeroPageX)),
/*0x76*/ Some((ROR, ZeroPageX)), /*0x76*/ Some((Instruction::ROR, AddressingMode::ZeroPageX)),
/*0x77*/ None, /*0x77*/ None,
/*0x78*/ Some((SEI, Implied)), /*0x78*/ Some((Instruction::SEI, AddressingMode::Implied)),
/*0x79*/ Some((ADC, AbsoluteY)), /*0x79*/ Some((Instruction::ADC, AddressingMode::AbsoluteY)),
/*0x7A*/ None, /*0x7A*/ None,
/*0x7B*/ None, /*0x7B*/ None,
/*0x7C*/ None, /*0x7C*/ None,
/*0x7D*/ Some((ADC, AbsoluteX)), /*0x7D*/ Some((Instruction::ADC, AddressingMode::AbsoluteX)),
/*0x7E*/ Some((ROR, AbsoluteX)), /*0x7E*/ Some((Instruction::ROR, AddressingMode::AbsoluteX)),
/*0x7F*/ None, /*0x7F*/ None,
/*0x80*/ None, /*0x80*/ None,
/*0x81*/ Some((STA, IndexedIndirectX)), /*0x81*/ Some((Instruction::STA, AddressingMode::IndexedIndirectX)),
/*0x82*/ None, /*0x82*/ None,
/*0x83*/ None, /*0x83*/ None,
/*0x84*/ Some((STY, ZeroPage)), /*0x84*/ Some((Instruction::STY, AddressingMode::ZeroPage)),
/*0x85*/ Some((STA, ZeroPage)), /*0x85*/ Some((Instruction::STA, AddressingMode::ZeroPage)),
/*0x86*/ Some((STX, ZeroPage)), /*0x86*/ Some((Instruction::STX, AddressingMode::ZeroPage)),
/*0x87*/ None, /*0x87*/ None,
/*0x88*/ Some((DEY, Implied)), /*0x88*/ Some((Instruction::DEY, AddressingMode::Implied)),
/*0x89*/ None, /*0x89*/ None,
/*0x8A*/ Some((TXA, Implied)), /*0x8A*/ Some((Instruction::TXA, AddressingMode::Implied)),
/*0x8B*/ None, /*0x8B*/ None,
/*0x8C*/ Some((STY, Absolute)), /*0x8C*/ Some((Instruction::STY, AddressingMode::Absolute)),
/*0x8D*/ Some((STA, Absolute)), /*0x8D*/ Some((Instruction::STA, AddressingMode::Absolute)),
/*0x8E*/ Some((STX, Absolute)), /*0x8E*/ Some((Instruction::STX, AddressingMode::Absolute)),
/*0x8F*/ None, /*0x8F*/ None,
/*0x90*/ Some((BCC, Relative)), /*0x90*/ Some((Instruction::BCC, AddressingMode::Relative)),
/*0x91*/ Some((STA, IndirectIndexedY)), /*0x91*/ Some((Instruction::STA, AddressingMode::IndirectIndexedY)),
/*0x92*/ None, /*0x92*/ None,
/*0x93*/ None, /*0x93*/ None,
/*0x94*/ Some((STY, ZeroPageX)), /*0x94*/ Some((Instruction::STY, AddressingMode::ZeroPageX)),
/*0x95*/ Some((STA, ZeroPageX)), /*0x95*/ Some((Instruction::STA, AddressingMode::ZeroPageX)),
/*0x96*/ Some((STX, ZeroPageY)), /*0x96*/ Some((Instruction::STX, AddressingMode::ZeroPageY)),
/*0x97*/ None, /*0x97*/ None,
/*0x98*/ Some((TYA, Implied)), /*0x98*/ Some((Instruction::TYA, AddressingMode::Implied)),
/*0x99*/ Some((STA, AbsoluteY)), /*0x99*/ Some((Instruction::STA, AddressingMode::AbsoluteY)),
/*0x9A*/ Some((TXS, Implied)), /*0x9A*/ Some((Instruction::TXS, AddressingMode::Implied)),
/*0x9B*/ None, /*0x9B*/ None,
/*0x9C*/ None, /*0x9C*/ None,
/*0x9D*/ Some((STA, AbsoluteX)), /*0x9D*/ Some((Instruction::STA, AddressingMode::AbsoluteX)),
/*0x9E*/ None, /*0x9E*/ None,
/*0x9F*/ None, /*0x9F*/ None,
/*0xA0*/ Some((LDY, Immediate)), /*0xA0*/ Some((Instruction::LDY, AddressingMode::Immediate)),
/*0xA1*/ Some((LDA, IndexedIndirectX)), /*0xA1*/ Some((Instruction::LDA, AddressingMode::IndexedIndirectX)),
/*0xA2*/ Some((LDX, Immediate)), /*0xA2*/ Some((Instruction::LDX, AddressingMode::Immediate)),
/*0xA3*/ None, /*0xA3*/ None,
/*0xA4*/ Some((LDY, ZeroPage)), /*0xA4*/ Some((Instruction::LDY, AddressingMode::ZeroPage)),
/*0xA5*/ Some((LDA, ZeroPage)), /*0xA5*/ Some((Instruction::LDA, AddressingMode::ZeroPage)),
/*0xA6*/ Some((LDX, ZeroPage)), /*0xA6*/ Some((Instruction::LDX, AddressingMode::ZeroPage)),
/*0xA7*/ None, /*0xA7*/ None,
/*0xA8*/ Some((TAY, Implied)), /*0xA8*/ Some((Instruction::TAY, AddressingMode::Implied)),
/*0xA9*/ Some((LDA, Immediate)), /*0xA9*/ Some((Instruction::LDA, AddressingMode::Immediate)),
/*0xAA*/ Some((TAX, Implied)), /*0xAA*/ Some((Instruction::TAX, AddressingMode::Implied)),
/*0xAB*/ None, /*0xAB*/ None,
/*0xAC*/ Some((LDY, Absolute)), /*0xAC*/ Some((Instruction::LDY, AddressingMode::Absolute)),
/*0xAD*/ Some((LDA, Absolute)), /*0xAD*/ Some((Instruction::LDA, AddressingMode::Absolute)),
/*0xAE*/ Some((LDX, Absolute)), /*0xAE*/ Some((Instruction::LDX, AddressingMode::Absolute)),
/*0xAF*/ None, /*0xAF*/ None,
/*0xB0*/ Some((BCS, Relative)), /*0xB0*/ Some((Instruction::BCS, AddressingMode::Relative)),
/*0xB1*/ Some((LDA, IndirectIndexedY)), /*0xB1*/ Some((Instruction::LDA, AddressingMode::IndirectIndexedY)),
/*0xB2*/ None, /*0xB2*/ None,
/*0xB3*/ None, /*0xB3*/ None,
/*0xB4*/ Some((LDY, ZeroPageX)), /*0xB4*/ Some((Instruction::LDY, AddressingMode::ZeroPageX)),
/*0xB5*/ Some((LDA, ZeroPageX)), /*0xB5*/ Some((Instruction::LDA, AddressingMode::ZeroPageX)),
/*0xB6*/ Some((LDX, ZeroPageY)), /*0xB6*/ Some((Instruction::LDX, AddressingMode::ZeroPageY)),
/*0xB7*/ None, /*0xB7*/ None,
/*0xB8*/ Some((CLV, Implied)), /*0xB8*/ Some((Instruction::CLV, AddressingMode::Implied)),
/*0xB9*/ Some((LDA, AbsoluteY)), /*0xB9*/ Some((Instruction::LDA, AddressingMode::AbsoluteY)),
/*0xBA*/ Some((TSX, Implied)), /*0xBA*/ Some((Instruction::TSX, AddressingMode::Implied)),
/*0xBB*/ None, /*0xBB*/ None,
/*0xBC*/ Some((LDY, AbsoluteX)), /*0xBC*/ Some((Instruction::LDY, AddressingMode::AbsoluteX)),
/*0xBD*/ Some((LDA, AbsoluteX)), /*0xBD*/ Some((Instruction::LDA, AddressingMode::AbsoluteX)),
/*0xBE*/ Some((LDX, AbsoluteY)), /*0xBE*/ Some((Instruction::LDX, AddressingMode::AbsoluteY)),
/*0xBF*/ None, /*0xBF*/ None,
/*0xC0*/ Some((CPY, Immediate)), /*0xC0*/ Some((Instruction::CPY, AddressingMode::Immediate)),
/*0xC1*/ Some((CMP, IndexedIndirectX)), /*0xC1*/ Some((Instruction::CMP, AddressingMode::IndexedIndirectX)),
/*0xC2*/ None, /*0xC2*/ None,
/*0xC3*/ None, /*0xC3*/ None,
/*0xC4*/ Some((CPY, ZeroPage)), /*0xC4*/ Some((Instruction::CPY, AddressingMode::ZeroPage)),
/*0xC5*/ Some((CMP, ZeroPage)), /*0xC5*/ Some((Instruction::CMP, AddressingMode::ZeroPage)),
/*0xC6*/ Some((DEC, ZeroPage)), /*0xC6*/ Some((Instruction::DEC, AddressingMode::ZeroPage)),
/*0xC7*/ None, /*0xC7*/ None,
/*0xC8*/ Some((INY, Implied)), /*0xC8*/ Some((Instruction::INY, AddressingMode::Implied)),
/*0xC9*/ Some((CMP, Immediate)), /*0xC9*/ Some((Instruction::CMP, AddressingMode::Immediate)),
/*0xCA*/ Some((DEX, Implied)), /*0xCA*/ Some((Instruction::DEX, AddressingMode::Implied)),
/*0xCB*/ None, /*0xCB*/ None,
/*0xCC*/ Some((CPY, Absolute)), /*0xCC*/ Some((Instruction::CPY, AddressingMode::Absolute)),
/*0xCD*/ Some((CMP, Absolute)), /*0xCD*/ Some((Instruction::CMP, AddressingMode::Absolute)),
/*0xCE*/ Some((DEC, Absolute)), /*0xCE*/ Some((Instruction::DEC, AddressingMode::Absolute)),
/*0xCF*/ None, /*0xCF*/ None,
/*0xD0*/ Some((BNE, Relative)), /*0xD0*/ Some((Instruction::BNE, AddressingMode::Relative)),
/*0xD1*/ Some((CMP, IndirectIndexedY)), /*0xD1*/ Some((Instruction::CMP, AddressingMode::IndirectIndexedY)),
/*0xD2*/ None, /*0xD2*/ None,
/*0xD3*/ None, /*0xD3*/ None,
/*0xD4*/ None, /*0xD4*/ None,
/*0xD5*/ Some((CMP, ZeroPageX)), /*0xD5*/ Some((Instruction::CMP, AddressingMode::ZeroPageX)),
/*0xD6*/ Some((DEC, ZeroPageX)), /*0xD6*/ Some((Instruction::DEC, AddressingMode::ZeroPageX)),
/*0xD7*/ None, /*0xD7*/ None,
/*0xD8*/ Some((CLD, Implied)), /*0xD8*/ Some((Instruction::CLD, AddressingMode::Implied)),
/*0xD9*/ Some((CMP, AbsoluteY)), /*0xD9*/ Some((Instruction::CMP, AddressingMode::AbsoluteY)),
/*0xDA*/ None, /*0xDA*/ None,
/*0xDB*/ None, /*0xDB*/ None,
/*0xDC*/ None, /*0xDC*/ None,
/*0xDD*/ Some((CMP, AbsoluteX)), /*0xDD*/ Some((Instruction::CMP, AddressingMode::AbsoluteX)),
/*0xDE*/ Some((DEC, AbsoluteX)), /*0xDE*/ Some((Instruction::DEC, AddressingMode::AbsoluteX)),
/*0xDF*/ None, /*0xDF*/ None,
/*0xE0*/ Some((CPX, Immediate)), /*0xE0*/ Some((Instruction::CPX, AddressingMode::Immediate)),
/*0xE1*/ Some((SBC, IndexedIndirectX)), /*0xE1*/ Some((Instruction::SBC, AddressingMode::IndexedIndirectX)),
/*0xE2*/ None, /*0xE2*/ None,
/*0xE3*/ None, /*0xE3*/ None,
/*0xE4*/ Some((CPX, ZeroPage)), /*0xE4*/ Some((Instruction::CPX, AddressingMode::ZeroPage)),
/*0xE5*/ Some((SBC, ZeroPage)), /*0xE5*/ Some((Instruction::SBC, AddressingMode::ZeroPage)),
/*0xE6*/ Some((INC, ZeroPage)), /*0xE6*/ Some((Instruction::INC, AddressingMode::ZeroPage)),
/*0xE7*/ None, /*0xE7*/ None,
/*0xE8*/ Some((INX, Implied)), /*0xE8*/ Some((Instruction::INX, AddressingMode::Implied)),
/*0xE9*/ Some((SBC, Immediate)), /*0xE9*/ Some((Instruction::SBC, AddressingMode::Immediate)),
/*0xEA*/ Some((NOP, Implied)), /*0xEA*/ Some((Instruction::NOP, AddressingMode::Implied)),
/*0xEB*/ None, /*0xEB*/ None,
/*0xEC*/ Some((CPX, Absolute)), /*0xEC*/ Some((Instruction::CPX, AddressingMode::Absolute)),
/*0xED*/ Some((SBC, Absolute)), /*0xED*/ Some((Instruction::SBC, AddressingMode::Absolute)),
/*0xEE*/ Some((INC, Absolute)), /*0xEE*/ Some((Instruction::INC, AddressingMode::Absolute)),
/*0xEF*/ None, /*0xEF*/ None,
/*0xF0*/ Some((BEQ, Relative)), /*0xF0*/ Some((Instruction::BEQ, AddressingMode::Relative)),
/*0xF1*/ Some((SBC, IndirectIndexedY)), /*0xF1*/ Some((Instruction::SBC, AddressingMode::IndirectIndexedY)),
/*0xF2*/ None, /*0xF2*/ None,
/*0xF3*/ None, /*0xF3*/ None,
/*0xF4*/ None, /*0xF4*/ None,
/*0xF5*/ Some((SBC, ZeroPageX)), /*0xF5*/ Some((Instruction::SBC, AddressingMode::ZeroPageX)),
/*0xF6*/ Some((INC, ZeroPageX)), /*0xF6*/ Some((Instruction::INC, AddressingMode::ZeroPageX)),
/*0xF7*/ None, /*0xF7*/ None,
/*0xF8*/ Some((SED, Implied)), /*0xF8*/ Some((Instruction::SED, AddressingMode::Implied)),
/*0xF9*/ Some((SBC, AbsoluteY)), /*0xF9*/ Some((Instruction::SBC, AddressingMode::AbsoluteY)),
/*0xFA*/ None, /*0xFA*/ None,
/*0xFB*/ None, /*0xFB*/ None,
/*0xFC*/ None, /*0xFC*/ None,
/*0xFD*/ Some((SBC, AbsoluteX)), /*0xFD*/ Some((Instruction::SBC, AddressingMode::AbsoluteX)),
/*0xFE*/ Some((INC, AbsoluteX)), /*0xFE*/ Some((Instruction::INC, AddressingMode::AbsoluteX)),
/*0xFF*/ None, /*0xFF*/ None,
]; ];

View File

@ -29,7 +29,7 @@ use std;
use address::{Address, AddressDiff}; use address::{Address, AddressDiff};
use instruction; use instruction;
use instruction::{DecodedInstr}; use instruction::{DecodedInstr, Instruction, OpInput};
use memory::Memory; use memory::Memory;
use registers::{ Registers, StackPointer, Status, StatusArgs }; use registers::{ Registers, StackPointer, Status, StatusArgs };
use registers::{ PS_NEGATIVE, PS_DECIMAL_MODE, PS_OVERFLOW, PS_ZERO, PS_CARRY, use registers::{ PS_NEGATIVE, PS_DECIMAL_MODE, PS_OVERFLOW, PS_ZERO, PS_CARRY,
@ -78,25 +78,25 @@ impl Machine {
pub fn execute_instruction(&mut self, decoded_instr: DecodedInstr) { pub fn execute_instruction(&mut self, decoded_instr: DecodedInstr) {
match decoded_instr { match decoded_instr {
(instruction::ADC, instruction::UseImmediate(val)) => { (Instruction::ADC, OpInput::UseImmediate(val)) => {
debug!("add with carry immediate: {}", val); debug!("add with carry immediate: {}", val);
self.add_with_carry(val as i8); self.add_with_carry(val as i8);
} }
(instruction::ADC, instruction::UseAddress(addr)) => { (Instruction::ADC, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr) as i8; let val = self.memory.get_byte(addr) as i8;
debug!("add with carry. address: {}. value: {}", addr, val); debug!("add with carry. address: {}. value: {}", addr, val);
self.add_with_carry(val); self.add_with_carry(val);
} }
(instruction::AND, instruction::UseImmediate(val)) => { (Instruction::AND, OpInput::UseImmediate(val)) => {
self.and(val as i8); self.and(val as i8);
} }
(instruction::AND, instruction::UseAddress(addr)) => { (Instruction::AND, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr) as i8; let val = self.memory.get_byte(addr) as i8;
self.and(val as i8); self.and(val as i8);
} }
(instruction::ASL, instruction::UseImplied) => { (Instruction::ASL, OpInput::UseImplied) => {
// Accumulator mode // Accumulator mode
let mut val = self.registers.accumulator as u8; let mut val = self.registers.accumulator as u8;
Machine::shift_left_with_flags(&mut val, Machine::shift_left_with_flags(&mut val,
@ -104,31 +104,31 @@ impl Machine {
self.registers.accumulator = val as i8; self.registers.accumulator = val as i8;
} }
(instruction::ASL, instruction::UseAddress(addr)) => { (Instruction::ASL, OpInput::UseAddress(addr)) => {
Machine::shift_left_with_flags( Machine::shift_left_with_flags(
self.memory.get_byte_mut_ref(addr), self.memory.get_byte_mut_ref(addr),
&mut self.registers.status); &mut self.registers.status);
} }
(instruction::BCC, instruction::UseRelative(rel)) => { (Instruction::BCC, OpInput::UseRelative(rel)) => {
let addr = self.registers.program_counter let addr = self.registers.program_counter
+ AddressDiff(rel as i32); + AddressDiff(rel as i32);
self.branch_if_carry_clear(addr); self.branch_if_carry_clear(addr);
} }
(instruction::BCS, instruction::UseRelative(rel)) => { (Instruction::BCS, OpInput::UseRelative(rel)) => {
let addr = self.registers.program_counter let addr = self.registers.program_counter
+ AddressDiff(rel as i32); + AddressDiff(rel as i32);
self.branch_if_carry_set(addr); self.branch_if_carry_set(addr);
} }
(instruction::BEQ, instruction::UseRelative(rel)) => { (Instruction::BEQ, OpInput::UseRelative(rel)) => {
let addr = self.registers.program_counter let addr = self.registers.program_counter
+ AddressDiff(rel as i32); + AddressDiff(rel as i32);
self.branch_if_equal(addr); self.branch_if_equal(addr);
} }
(instruction::BIT, instruction::UseAddress(addr)) => { (Instruction::BIT, OpInput::UseAddress(addr)) => {
let a: u8 = self.registers.accumulator as u8; let a: u8 = self.registers.accumulator as u8;
let m: u8 = self.memory.get_byte(addr); let m: u8 = self.memory.get_byte(addr);
let res = a & m; let res = a & m;
@ -150,163 +150,163 @@ impl Machine {
..StatusArgs::none() } )); ..StatusArgs::none() } ));
} }
(instruction::BMI, instruction::UseRelative(rel)) => { (Instruction::BMI, OpInput::UseRelative(rel)) => {
let addr = self.registers.program_counter let addr = self.registers.program_counter
+ AddressDiff(rel as i32); + AddressDiff(rel as i32);
debug!("branch if minus relative. address: {}", addr); debug!("branch if minus relative. address: {}", addr);
self.branch_if_minus(addr); self.branch_if_minus(addr);
} }
(instruction::BPL, instruction::UseRelative(rel)) => { (Instruction::BPL, OpInput::UseRelative(rel)) => {
let addr = self.registers.program_counter let addr = self.registers.program_counter
+ AddressDiff(rel as i32); + AddressDiff(rel as i32);
self.branch_if_positive(addr); self.branch_if_positive(addr);
} }
(instruction::BVC, instruction::UseRelative(rel)) => { (Instruction::BVC, OpInput::UseRelative(rel)) => {
let addr = self.registers.program_counter let addr = self.registers.program_counter
+ AddressDiff(rel as i32); + AddressDiff(rel as i32);
self.branch_if_overflow_clear(addr); self.branch_if_overflow_clear(addr);
} }
(instruction::BVS, instruction::UseRelative(rel)) => { (Instruction::BVS, OpInput::UseRelative(rel)) => {
let addr = self.registers.program_counter let addr = self.registers.program_counter
+ AddressDiff(rel as i32); + AddressDiff(rel as i32);
self.branch_if_overflow_set(addr); self.branch_if_overflow_set(addr);
} }
(instruction::CLC, instruction::UseImplied) => { (Instruction::CLC, OpInput::UseImplied) => {
self.registers.status.and(!PS_CARRY); self.registers.status.and(!PS_CARRY);
} }
(instruction::CLD, instruction::UseImplied) => { (Instruction::CLD, OpInput::UseImplied) => {
self.registers.status.and(!PS_DECIMAL_MODE); self.registers.status.and(!PS_DECIMAL_MODE);
} }
(instruction::CLI, instruction::UseImplied) => { (Instruction::CLI, OpInput::UseImplied) => {
self.registers.status.and(!PS_DISABLE_INTERRUPTS); self.registers.status.and(!PS_DISABLE_INTERRUPTS);
} }
(instruction::CLV, instruction::UseImplied) => { (Instruction::CLV, OpInput::UseImplied) => {
self.registers.status.and(!PS_OVERFLOW); self.registers.status.and(!PS_OVERFLOW);
} }
(instruction::CMP, instruction::UseImmediate(val)) => { (Instruction::CMP, OpInput::UseImmediate(val)) => {
self.compare_with_a_register(val); self.compare_with_a_register(val);
} }
(instruction::CMP, instruction::UseAddress(addr)) => { (Instruction::CMP, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr); let val = self.memory.get_byte(addr);
self.compare_with_a_register(val); self.compare_with_a_register(val);
} }
(instruction::CPX, instruction::UseImmediate(val)) => { (Instruction::CPX, OpInput::UseImmediate(val)) => {
self.compare_with_x_register(val); self.compare_with_x_register(val);
} }
(instruction::CPX, instruction::UseAddress(addr)) => { (Instruction::CPX, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr); let val = self.memory.get_byte(addr);
self.compare_with_x_register(val); self.compare_with_x_register(val);
} }
(instruction::CPY, instruction::UseImmediate(val)) => { (Instruction::CPY, OpInput::UseImmediate(val)) => {
self.compare_with_y_register(val); self.compare_with_y_register(val);
} }
(instruction::CPY, instruction::UseAddress(addr)) => { (Instruction::CPY, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr); let val = self.memory.get_byte(addr);
self.compare_with_y_register(val); self.compare_with_y_register(val);
} }
(instruction::DEC, instruction::UseAddress(addr)) => { (Instruction::DEC, OpInput::UseAddress(addr)) => {
self.decrement_memory(addr) self.decrement_memory(addr)
} }
(instruction::DEX, instruction::UseImplied) => { (Instruction::DEX, OpInput::UseImplied) => {
self.dec_x(); self.dec_x();
} }
(instruction::EOR, instruction::UseImmediate(val)) => { (Instruction::EOR, OpInput::UseImmediate(val)) => {
self.exclusive_or(val); self.exclusive_or(val);
} }
(instruction::EOR, instruction::UseAddress(addr)) => { (Instruction::EOR, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr); let val = self.memory.get_byte(addr);
self.exclusive_or(val); self.exclusive_or(val);
} }
(instruction::INC, instruction::UseAddress(addr)) => { (Instruction::INC, OpInput::UseAddress(addr)) => {
let m = self.memory.get_byte(addr); let m = self.memory.get_byte(addr);
let m = m + 1; let m = m + 1;
self.memory.set_byte(addr, m); self.memory.set_byte(addr, m);
let i = m as i8; let i = m as i8;
Machine::set_flags_from_i8(&mut self.registers.status, i); Machine::set_flags_from_i8(&mut self.registers.status, i);
} }
(instruction::INX, instruction::UseImplied) => { (Instruction::INX, OpInput::UseImplied) => {
let x = self.registers.index_x + 1; let x = self.registers.index_x + 1;
self.load_x_register(x); self.load_x_register(x);
} }
(instruction::INY, instruction::UseImplied) => { (Instruction::INY, OpInput::UseImplied) => {
let y = self.registers.index_y + 1; let y = self.registers.index_y + 1;
self.load_y_register(y); self.load_y_register(y);
} }
(instruction::JMP, instruction::UseAddress(addr)) => { (Instruction::JMP, OpInput::UseAddress(addr)) => {
self.jump(addr) self.jump(addr)
} }
(instruction::LDA, instruction::UseImmediate(val)) => { (Instruction::LDA, OpInput::UseImmediate(val)) => {
debug!("load A immediate: {}", val); debug!("load A immediate: {}", val);
self.load_accumulator(val as i8); self.load_accumulator(val as i8);
} }
(instruction::LDA, instruction::UseAddress(addr)) => { (Instruction::LDA, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr); let val = self.memory.get_byte(addr);
debug!("load A. address: {}. value: {}", addr, val); debug!("load A. address: {}. value: {}", addr, val);
self.load_accumulator(val as i8); self.load_accumulator(val as i8);
} }
(instruction::LDX, instruction::UseImmediate(val)) => { (Instruction::LDX, OpInput::UseImmediate(val)) => {
debug!("load X immediate: {}", val); debug!("load X immediate: {}", val);
self.load_x_register(val as i8); self.load_x_register(val as i8);
} }
(instruction::LDX, instruction::UseAddress(addr)) => { (Instruction::LDX, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr); let val = self.memory.get_byte(addr);
debug!("load X. address: {}. value: {}", addr, val); debug!("load X. address: {}. value: {}", addr, val);
self.load_x_register(val as i8); self.load_x_register(val as i8);
} }
(instruction::LDY, instruction::UseImmediate(val)) => { (Instruction::LDY, OpInput::UseImmediate(val)) => {
debug!("load Y immediate: {}", val); debug!("load Y immediate: {}", val);
self.load_y_register(val as i8); self.load_y_register(val as i8);
} }
(instruction::LDY, instruction::UseAddress(addr)) => { (Instruction::LDY, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr); let val = self.memory.get_byte(addr);
debug!("load Y. address: {}. value: {}", addr, val); debug!("load Y. address: {}. value: {}", addr, val);
self.load_y_register(val as i8); self.load_y_register(val as i8);
} }
(instruction::LSR, instruction::UseImplied) => { (Instruction::LSR, OpInput::UseImplied) => {
// Accumulator mode // Accumulator mode
let mut val = self.registers.accumulator as u8; let mut val = self.registers.accumulator as u8;
Machine::shift_right_with_flags(&mut val, Machine::shift_right_with_flags(&mut val,
&mut self.registers.status); &mut self.registers.status);
self.registers.accumulator = val as i8; self.registers.accumulator = val as i8;
} }
(instruction::LSR, instruction::UseAddress(addr)) => { (Instruction::LSR, OpInput::UseAddress(addr)) => {
Machine::shift_right_with_flags( Machine::shift_right_with_flags(
self.memory.get_byte_mut_ref(addr), self.memory.get_byte_mut_ref(addr),
&mut self.registers.status); &mut self.registers.status);
} }
(instruction::PHA, instruction::UseImplied) => { (Instruction::PHA, OpInput::UseImplied) => {
// Push accumulator // Push accumulator
let val = self.registers.accumulator as u8; let val = self.registers.accumulator as u8;
self.push_on_stack(val); self.push_on_stack(val);
} }
(instruction::PHP, instruction::UseImplied) => { (Instruction::PHP, OpInput::UseImplied) => {
// Push status // Push status
let val = self.registers.status.bits(); let val = self.registers.status.bits();
self.push_on_stack(val); self.push_on_stack(val);
} }
(instruction::PLA, instruction::UseImplied) => { (Instruction::PLA, OpInput::UseImplied) => {
// Pull accumulator // Pull accumulator
let val: u8 = self.pull_from_stack(); let val: u8 = self.pull_from_stack();
self.registers.accumulator = val as i8; self.registers.accumulator = val as i8;
} }
(instruction::PLP, instruction::UseImplied) => { (Instruction::PLP, OpInput::UseImplied) => {
// Pull status // Pull status
let val: u8 = self.pull_from_stack(); let val: u8 = self.pull_from_stack();
// The `truncate` here won't do anything because we have a // The `truncate` here won't do anything because we have a
@ -315,92 +315,92 @@ impl Machine {
self.registers.status = Status::from_bits_truncate(val); self.registers.status = Status::from_bits_truncate(val);
} }
(instruction::ROL, instruction::UseImplied) => { (Instruction::ROL, OpInput::UseImplied) => {
// Accumulator mode // Accumulator mode
let mut val = self.registers.accumulator as u8; let mut val = self.registers.accumulator as u8;
Machine::rotate_left_with_flags(&mut val, Machine::rotate_left_with_flags(&mut val,
&mut self.registers.status); &mut self.registers.status);
self.registers.accumulator = val as i8; self.registers.accumulator = val as i8;
} }
(instruction::ROL, instruction::UseAddress(addr)) => { (Instruction::ROL, OpInput::UseAddress(addr)) => {
Machine::rotate_left_with_flags( Machine::rotate_left_with_flags(
self.memory.get_byte_mut_ref(addr), self.memory.get_byte_mut_ref(addr),
&mut self.registers.status); &mut self.registers.status);
} }
(instruction::ROR, instruction::UseImplied) => { (Instruction::ROR, OpInput::UseImplied) => {
// Accumulator mode // Accumulator mode
let mut val = self.registers.accumulator as u8; let mut val = self.registers.accumulator as u8;
Machine::rotate_right_with_flags(&mut val, Machine::rotate_right_with_flags(&mut val,
&mut self.registers.status); &mut self.registers.status);
self.registers.accumulator = val as i8; self.registers.accumulator = val as i8;
} }
(instruction::ROR, instruction::UseAddress(addr)) => { (Instruction::ROR, OpInput::UseAddress(addr)) => {
Machine::rotate_right_with_flags( Machine::rotate_right_with_flags(
self.memory.get_byte_mut_ref(addr), self.memory.get_byte_mut_ref(addr),
&mut self.registers.status); &mut self.registers.status);
} }
(instruction::SBC, instruction::UseImmediate(val)) => { (Instruction::SBC, OpInput::UseImmediate(val)) => {
debug!("subtract with carry immediate: {}", val); debug!("subtract with carry immediate: {}", val);
self.subtract_with_carry(val as i8); self.subtract_with_carry(val as i8);
} }
(instruction::SBC, instruction::UseAddress(addr)) => { (Instruction::SBC, OpInput::UseAddress(addr)) => {
let val = self.memory.get_byte(addr) as i8; let val = self.memory.get_byte(addr) as i8;
debug!("subtract with carry. address: {}. value: {}", debug!("subtract with carry. address: {}. value: {}",
addr, val); addr, val);
self.subtract_with_carry(val); self.subtract_with_carry(val);
} }
(instruction::SEC, instruction::UseImplied) => { (Instruction::SEC, OpInput::UseImplied) => {
self.registers.status.or(PS_CARRY); self.registers.status.or(PS_CARRY);
} }
(instruction::SED, instruction::UseImplied) => { (Instruction::SED, OpInput::UseImplied) => {
self.registers.status.or(PS_DECIMAL_MODE); self.registers.status.or(PS_DECIMAL_MODE);
} }
(instruction::SEI, instruction::UseImplied) => { (Instruction::SEI, OpInput::UseImplied) => {
self.registers.status.or(PS_DISABLE_INTERRUPTS); self.registers.status.or(PS_DISABLE_INTERRUPTS);
} }
(instruction::STA, instruction::UseAddress(addr)) => { (Instruction::STA, OpInput::UseAddress(addr)) => {
self.memory.set_byte(addr, self.registers.accumulator as u8); self.memory.set_byte(addr, self.registers.accumulator as u8);
} }
(instruction::STX, instruction::UseAddress(addr)) => { (Instruction::STX, OpInput::UseAddress(addr)) => {
self.memory.set_byte(addr, self.registers.index_x as u8); self.memory.set_byte(addr, self.registers.index_x as u8);
} }
(instruction::STY, instruction::UseAddress(addr)) => { (Instruction::STY, OpInput::UseAddress(addr)) => {
self.memory.set_byte(addr, self.registers.index_y as u8); self.memory.set_byte(addr, self.registers.index_y as u8);
} }
(instruction::TAX, instruction::UseImplied) => { (Instruction::TAX, OpInput::UseImplied) => {
let val = self.registers.accumulator; let val = self.registers.accumulator;
self.load_x_register(val); self.load_x_register(val);
} }
(instruction::TAY, instruction::UseImplied) => { (Instruction::TAY, OpInput::UseImplied) => {
let val = self.registers.accumulator; let val = self.registers.accumulator;
self.load_y_register(val); self.load_y_register(val);
} }
(instruction::TSX, instruction::UseImplied) => { (Instruction::TSX, OpInput::UseImplied) => {
let StackPointer(val) = self.registers.stack_pointer; let StackPointer(val) = self.registers.stack_pointer;
let val = val as i8; let val = val as i8;
self.load_x_register(val); self.load_x_register(val);
} }
(instruction::TXA, instruction::UseImplied) => { (Instruction::TXA, OpInput::UseImplied) => {
let val = self.registers.index_x; let val = self.registers.index_x;
self.load_accumulator(val); self.load_accumulator(val);
} }
(instruction::TXS, instruction::UseImplied) => { (Instruction::TXS, OpInput::UseImplied) => {
// Note that this is the only 'transfer' instruction that does // Note that this is the only 'transfer' instruction that does
// NOT set the zero and negative flags. (Because the target // NOT set the zero and negative flags. (Because the target
// is the stack pointer) // is the stack pointer)
let val = self.registers.index_x; let val = self.registers.index_x;
self.registers.stack_pointer = StackPointer(val as u8); self.registers.stack_pointer = StackPointer(val as u8);
} }
(instruction::TYA, instruction::UseImplied) => { (Instruction::TYA, OpInput::UseImplied) => {
let val = self.registers.index_y; let val = self.registers.index_y;
self.load_accumulator(val); self.load_accumulator(val);
} }
(instruction::NOP, instruction::UseImplied) => { (Instruction::NOP, OpInput::UseImplied) => {
debug!("NOP instruction"); debug!("NOP instruction");
} }
(_, _) => { (_, _) => {
@ -828,7 +828,7 @@ fn and_test() {
fn subtract_with_carry_test() { fn subtract_with_carry_test() {
let mut machine = Machine::new(); let mut machine = Machine::new();
machine.execute_instruction((instruction::SEC, instruction::UseImplied)); machine.execute_instruction((Instruction::SEC, OpInput::UseImplied));
machine.registers.accumulator = 0; machine.registers.accumulator = 0;
machine.subtract_with_carry(1); machine.subtract_with_carry(1);
@ -838,7 +838,7 @@ fn subtract_with_carry_test() {
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), true); assert_eq!(machine.registers.status.contains(PS_NEGATIVE), true);
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false); assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
machine.execute_instruction((instruction::SEC, instruction::UseImplied)); machine.execute_instruction((Instruction::SEC, OpInput::UseImplied));
machine.registers.accumulator = -128; machine.registers.accumulator = -128;
machine.subtract_with_carry(1); machine.subtract_with_carry(1);
assert_eq!(machine.registers.accumulator, 127); assert_eq!(machine.registers.accumulator, 127);
@ -847,7 +847,7 @@ fn subtract_with_carry_test() {
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false); assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), true); assert_eq!(machine.registers.status.contains(PS_OVERFLOW), true);
machine.execute_instruction((instruction::SEC, instruction::UseImplied)); machine.execute_instruction((Instruction::SEC, OpInput::UseImplied));
machine.registers.accumulator = 127; machine.registers.accumulator = 127;
machine.subtract_with_carry(-1); machine.subtract_with_carry(-1);
assert_eq!(machine.registers.accumulator, -128); assert_eq!(machine.registers.accumulator, -128);
@ -856,7 +856,7 @@ fn subtract_with_carry_test() {
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), true); assert_eq!(machine.registers.status.contains(PS_NEGATIVE), true);
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), true); assert_eq!(machine.registers.status.contains(PS_OVERFLOW), true);
machine.execute_instruction((instruction::CLC, instruction::UseImplied)); machine.execute_instruction((Instruction::CLC, OpInput::UseImplied));
machine.registers.accumulator = -64; machine.registers.accumulator = -64;
machine.subtract_with_carry(64); machine.subtract_with_carry(64);
assert_eq!(machine.registers.accumulator, 127); assert_eq!(machine.registers.accumulator, 127);
@ -865,7 +865,7 @@ fn subtract_with_carry_test() {
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false); assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), true); assert_eq!(machine.registers.status.contains(PS_OVERFLOW), true);
machine.execute_instruction((instruction::SEC, instruction::UseImplied)); machine.execute_instruction((Instruction::SEC, OpInput::UseImplied));
machine.registers.accumulator = 0; machine.registers.accumulator = 0;
machine.subtract_with_carry(-128); machine.subtract_with_carry(-128);
assert_eq!(machine.registers.accumulator, -128); assert_eq!(machine.registers.accumulator, -128);
@ -874,7 +874,7 @@ fn subtract_with_carry_test() {
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), true); assert_eq!(machine.registers.status.contains(PS_NEGATIVE), true);
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), true); assert_eq!(machine.registers.status.contains(PS_OVERFLOW), true);
machine.execute_instruction((instruction::CLC, instruction::UseImplied)); machine.execute_instruction((Instruction::CLC, OpInput::UseImplied));
machine.registers.accumulator = 0; machine.registers.accumulator = 0;
machine.subtract_with_carry(127); machine.subtract_with_carry(127);
assert_eq!(machine.registers.accumulator, -128); assert_eq!(machine.registers.accumulator, -128);
@ -919,40 +919,40 @@ fn logical_shift_right_test() {
// Testing UseImplied version (which targets the accumulator) only, for now // Testing UseImplied version (which targets the accumulator) only, for now
let mut machine = Machine::new(); let mut machine = Machine::new();
machine.execute_instruction((instruction::LDA, machine.execute_instruction((Instruction::LDA,
instruction::UseImmediate(0))); OpInput::UseImmediate(0)));
machine.execute_instruction((instruction::LSR, machine.execute_instruction((Instruction::LSR,
instruction::UseImplied)); OpInput::UseImplied));
assert_eq!(machine.registers.accumulator, 0); assert_eq!(machine.registers.accumulator, 0);
assert_eq!(machine.registers.status.contains(PS_CARRY), false); assert_eq!(machine.registers.status.contains(PS_CARRY), false);
assert_eq!(machine.registers.status.contains(PS_ZERO), true); assert_eq!(machine.registers.status.contains(PS_ZERO), true);
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false); assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false); assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
machine.execute_instruction((instruction::LDA, machine.execute_instruction((Instruction::LDA,
instruction::UseImmediate(1))); OpInput::UseImmediate(1)));
machine.execute_instruction((instruction::LSR, machine.execute_instruction((Instruction::LSR,
instruction::UseImplied)); OpInput::UseImplied));
assert_eq!(machine.registers.accumulator, 0); assert_eq!(machine.registers.accumulator, 0);
assert_eq!(machine.registers.status.contains(PS_CARRY), true); assert_eq!(machine.registers.status.contains(PS_CARRY), true);
assert_eq!(machine.registers.status.contains(PS_ZERO), true); assert_eq!(machine.registers.status.contains(PS_ZERO), true);
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false); assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false); assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
machine.execute_instruction((instruction::LDA, machine.execute_instruction((Instruction::LDA,
instruction::UseImmediate(255))); OpInput::UseImmediate(255)));
machine.execute_instruction((instruction::LSR, machine.execute_instruction((Instruction::LSR,
instruction::UseImplied)); OpInput::UseImplied));
assert_eq!(machine.registers.accumulator, 0x7F); assert_eq!(machine.registers.accumulator, 0x7F);
assert_eq!(machine.registers.status.contains(PS_CARRY), true); assert_eq!(machine.registers.status.contains(PS_CARRY), true);
assert_eq!(machine.registers.status.contains(PS_ZERO), false); assert_eq!(machine.registers.status.contains(PS_ZERO), false);
assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false); assert_eq!(machine.registers.status.contains(PS_NEGATIVE), false);
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false); assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
machine.execute_instruction((instruction::LDA, machine.execute_instruction((Instruction::LDA,
instruction::UseImmediate(254))); OpInput::UseImmediate(254)));
machine.execute_instruction((instruction::LSR, machine.execute_instruction((Instruction::LSR,
instruction::UseImplied)); OpInput::UseImplied));
assert_eq!(machine.registers.accumulator, 0x7F); assert_eq!(machine.registers.accumulator, 0x7F);
assert_eq!(machine.registers.status.contains(PS_CARRY), false); assert_eq!(machine.registers.status.contains(PS_CARRY), false);
assert_eq!(machine.registers.status.contains(PS_ZERO), false); assert_eq!(machine.registers.status.contains(PS_ZERO), false);
@ -1018,11 +1018,11 @@ fn jump_test() {
fn branch_if_carry_clear_test() { fn branch_if_carry_clear_test() {
let mut machine = Machine::new(); let mut machine = Machine::new();
machine.execute_instruction((instruction::SEC, instruction::UseImplied)); machine.execute_instruction((Instruction::SEC, OpInput::UseImplied));
machine.branch_if_carry_clear(Address(0xABCD)); machine.branch_if_carry_clear(Address(0xABCD));
assert_eq!(machine.registers.program_counter, Address(0)); assert_eq!(machine.registers.program_counter, Address(0));
machine.execute_instruction((instruction::CLC, instruction::UseImplied)); machine.execute_instruction((Instruction::CLC, OpInput::UseImplied));
machine.branch_if_carry_clear(Address(0xABCD)); machine.branch_if_carry_clear(Address(0xABCD));
assert_eq!(machine.registers.program_counter, Address(0xABCD)); assert_eq!(machine.registers.program_counter, Address(0xABCD));
} }
@ -1031,11 +1031,11 @@ fn branch_if_carry_clear_test() {
fn branch_if_carry_set_test() { fn branch_if_carry_set_test() {
let mut machine = Machine::new(); let mut machine = Machine::new();
machine.execute_instruction((instruction::CLC, instruction::UseImplied)); machine.execute_instruction((Instruction::CLC, OpInput::UseImplied));
machine.branch_if_carry_set(Address(0xABCD)); machine.branch_if_carry_set(Address(0xABCD));
assert_eq!(machine.registers.program_counter, Address(0)); assert_eq!(machine.registers.program_counter, Address(0));
machine.execute_instruction((instruction::SEC, instruction::UseImplied)); machine.execute_instruction((Instruction::SEC, OpInput::UseImplied));
machine.branch_if_carry_set(Address(0xABCD)); machine.branch_if_carry_set(Address(0xABCD));
assert_eq!(machine.registers.program_counter, Address(0xABCD)); assert_eq!(machine.registers.program_counter, Address(0xABCD));
} }
@ -1113,14 +1113,15 @@ fn branch_if_overflow_set_test() {
assert_eq!(machine.registers.program_counter, Address(0xABCD)); assert_eq!(machine.registers.program_counter, Address(0xABCD));
} }
#[cfg(test)]
fn compare_test_helper( fn compare_test_helper(
compare: |&mut Machine, u8|, compare: |&mut Machine, u8|,
load_instruction: instruction::Instruction load_instruction: Instruction
) { ) {
let mut machine = Machine::new(); let mut machine = Machine::new();
machine.execute_instruction( machine.execute_instruction(
(load_instruction, instruction::UseImmediate(127)) (load_instruction, OpInput::UseImmediate(127))
); );
compare(&mut machine, 127); compare(&mut machine, 127);
@ -1130,7 +1131,7 @@ fn compare_test_helper(
machine.execute_instruction( machine.execute_instruction(
(load_instruction, instruction::UseImmediate(127)) (load_instruction, OpInput::UseImmediate(127))
); );
compare(&mut machine, 1); compare(&mut machine, 1);
@ -1140,7 +1141,7 @@ fn compare_test_helper(
machine.execute_instruction( machine.execute_instruction(
(load_instruction, instruction::UseImmediate(1)) (load_instruction, OpInput::UseImmediate(1))
); );
compare(&mut machine, 2); compare(&mut machine, 2);
@ -1150,7 +1151,7 @@ fn compare_test_helper(
machine.execute_instruction( machine.execute_instruction(
(load_instruction, instruction::UseImmediate(20)) (load_instruction, OpInput::UseImmediate(20))
); );
compare(&mut machine, -50); compare(&mut machine, -50);
@ -1160,7 +1161,7 @@ fn compare_test_helper(
machine.execute_instruction( machine.execute_instruction(
(load_instruction, instruction::UseImmediate(1)) (load_instruction, OpInput::UseImmediate(1))
); );
compare(&mut machine, -1); compare(&mut machine, -1);
@ -1170,7 +1171,7 @@ fn compare_test_helper(
machine.execute_instruction( machine.execute_instruction(
(load_instruction, instruction::UseImmediate(127)) (load_instruction, OpInput::UseImmediate(127))
); );
compare(&mut machine, -128); compare(&mut machine, -128);
@ -1185,7 +1186,7 @@ fn compare_with_a_register_test() {
|machine: &mut Machine, val: u8| { |machine: &mut Machine, val: u8| {
machine.compare_with_a_register(val); machine.compare_with_a_register(val);
}, },
instruction::LDA Instruction::LDA
); );
} }
@ -1195,7 +1196,7 @@ fn compare_with_x_register_test() {
|machine: &mut Machine, val: u8| { |machine: &mut Machine, val: u8| {
machine.compare_with_x_register(val); machine.compare_with_x_register(val);
}, },
instruction::LDX Instruction::LDX
); );
} }
@ -1205,7 +1206,7 @@ fn compare_with_y_register_test() {
|machine: &mut Machine, val: u8| { |machine: &mut Machine, val: u8| {
machine.compare_with_y_register(val); machine.compare_with_y_register(val);
}, },
instruction::LDY Instruction::LDY
); );
} }
@ -1216,7 +1217,7 @@ fn exclusive_or_test() {
for a_before in range(0u8, 255u8) { for a_before in range(0u8, 255u8) {
for val in range(0u8, 255u8) { for val in range(0u8, 255u8) {
machine.execute_instruction( machine.execute_instruction(
(instruction::LDA, instruction::UseImmediate(a_before)) (Instruction::LDA, OpInput::UseImmediate(a_before))
); );
machine.exclusive_or(val); machine.exclusive_or(val);
@ -1237,4 +1238,4 @@ fn exclusive_or_test() {
} }
} }
} }
} }