mirror of
https://github.com/mre/mos6502.git
synced 2024-11-28 22:51:26 +00:00
Merge pull request #32 from typelist/master
Fix the build for namespaced enums
This commit is contained in:
commit
aa7db5e623
@ -113,7 +113,7 @@ pub enum Instruction
|
||||
, TYA // Transfer Y to Accumulator..... | N. ...Z. A = Y
|
||||
}
|
||||
|
||||
pub enum AMOut {
|
||||
pub enum OpInput {
|
||||
UseImplied,
|
||||
UseImmediate(u8),
|
||||
UseRelative(i8),
|
||||
@ -149,24 +149,24 @@ fn arr_to_addr(arr: &[u8]) -> Address {
|
||||
impl AddressingMode {
|
||||
pub fn extra_bytes(self) -> AddressDiff {
|
||||
let x = match self {
|
||||
Accumulator => 0,
|
||||
Implied => 0,
|
||||
Immediate => 1,
|
||||
ZeroPage => 1,
|
||||
ZeroPageX => 1,
|
||||
ZeroPageY => 1,
|
||||
Relative => 1,
|
||||
Absolute => 2,
|
||||
AbsoluteX => 2,
|
||||
AbsoluteY => 2,
|
||||
Indirect => 2,
|
||||
IndexedIndirectX => 1,
|
||||
IndirectIndexedY => 1,
|
||||
AddressingMode::Accumulator => 0,
|
||||
AddressingMode::Implied => 0,
|
||||
AddressingMode::Immediate => 1,
|
||||
AddressingMode::ZeroPage => 1,
|
||||
AddressingMode::ZeroPageX => 1,
|
||||
AddressingMode::ZeroPageY => 1,
|
||||
AddressingMode::Relative => 1,
|
||||
AddressingMode::Absolute => 2,
|
||||
AddressingMode::AbsoluteX => 2,
|
||||
AddressingMode::AbsoluteY => 2,
|
||||
AddressingMode::Indirect => 2,
|
||||
AddressingMode::IndexedIndirectX => 1,
|
||||
AddressingMode::IndirectIndexedY => 1,
|
||||
};
|
||||
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();
|
||||
arr.len() == x as uint});
|
||||
@ -177,60 +177,60 @@ impl AddressingMode {
|
||||
let memory = &machine.memory;
|
||||
|
||||
match self {
|
||||
Accumulator | Implied => {
|
||||
AddressingMode::Accumulator | AddressingMode::Implied => {
|
||||
// Always the same -- no input
|
||||
UseImplied
|
||||
OpInput::UseImplied
|
||||
},
|
||||
Immediate => {
|
||||
AddressingMode::Immediate => {
|
||||
// Use [u8, ..1] specified in instruction as input
|
||||
UseImmediate(arr[0])
|
||||
OpInput::UseImmediate(arr[0])
|
||||
},
|
||||
ZeroPage => {
|
||||
AddressingMode::ZeroPage => {
|
||||
// Use [u8, ..1] from instruction
|
||||
// Interpret as 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
|
||||
// Add to X register (as u8 -- the final address is in 0-page)
|
||||
// (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
|
||||
// Add to Y register (as u8 -- the final address is in 0-page)
|
||||
// (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
|
||||
// (interpret as relative...)
|
||||
UseRelative(arr[0] as i8)
|
||||
OpInput::UseRelative(arr[0] as i8)
|
||||
},
|
||||
Absolute => {
|
||||
AddressingMode::Absolute => {
|
||||
// Use [u8, ..2] from instruction as 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
|
||||
// (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
|
||||
// (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
|
||||
// two bytes starting at that address as an address.
|
||||
// (Output: a 16-bit address)
|
||||
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
|
||||
// Add to X register with 0-page wraparound, like ZeroPageX.
|
||||
// This is where the absolute (16-bit) target address is stored.
|
||||
@ -238,9 +238,9 @@ impl AddressingMode {
|
||||
let start = arr[0] + x;
|
||||
let slice = memory.get_slice(Address(start as u16),
|
||||
AddressDiff(2));
|
||||
UseAddress(arr_to_addr(slice))
|
||||
OpInput::UseAddress(arr_to_addr(slice))
|
||||
},
|
||||
IndirectIndexedY => {
|
||||
AddressingMode::IndirectIndexedY => {
|
||||
// Use [u8, ..1] from instruction
|
||||
// This is where the absolute (16-bit) target address is stored.
|
||||
// Add Y register to this address to get the final address
|
||||
@ -248,270 +248,270 @@ impl AddressingMode {
|
||||
let start = arr[0];
|
||||
let slice = memory.get_slice(Address(start as u16),
|
||||
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] = [
|
||||
/*0x00*/ Some((BRK, Implied)),
|
||||
/*0x01*/ Some((ORA, IndexedIndirectX)),
|
||||
/*0x00*/ Some((Instruction::BRK, AddressingMode::Implied)),
|
||||
/*0x01*/ Some((Instruction::ORA, AddressingMode::IndexedIndirectX)),
|
||||
/*0x02*/ None,
|
||||
/*0x03*/ None,
|
||||
/*0x04*/ None,
|
||||
/*0x05*/ Some((ORA, ZeroPage)),
|
||||
/*0x06*/ Some((ASL, ZeroPage)),
|
||||
/*0x05*/ Some((Instruction::ORA, AddressingMode::ZeroPage)),
|
||||
/*0x06*/ Some((Instruction::ASL, AddressingMode::ZeroPage)),
|
||||
/*0x07*/ None,
|
||||
/*0x08*/ Some((PHP, Implied)),
|
||||
/*0x09*/ Some((ORA, Immediate)),
|
||||
/*0x0A*/ Some((ASL, Accumulator)),
|
||||
/*0x08*/ Some((Instruction::PHP, AddressingMode::Implied)),
|
||||
/*0x09*/ Some((Instruction::ORA, AddressingMode::Immediate)),
|
||||
/*0x0A*/ Some((Instruction::ASL, AddressingMode::Accumulator)),
|
||||
/*0x0B*/ None,
|
||||
/*0x0C*/ None,
|
||||
/*0x0D*/ Some((ORA, Absolute)),
|
||||
/*0x0E*/ Some((ASL, Absolute)),
|
||||
/*0x0D*/ Some((Instruction::ORA, AddressingMode::Absolute)),
|
||||
/*0x0E*/ Some((Instruction::ASL, AddressingMode::Absolute)),
|
||||
/*0x0F*/ None,
|
||||
/*0x10*/ Some((BPL, Relative)),
|
||||
/*0x11*/ Some((ORA, IndirectIndexedY)),
|
||||
/*0x10*/ Some((Instruction::BPL, AddressingMode::Relative)),
|
||||
/*0x11*/ Some((Instruction::ORA, AddressingMode::IndirectIndexedY)),
|
||||
/*0x12*/ None,
|
||||
/*0x13*/ None,
|
||||
/*0x14*/ None,
|
||||
/*0x15*/ Some((ORA, ZeroPageX)),
|
||||
/*0x16*/ Some((ASL, ZeroPageX)),
|
||||
/*0x15*/ Some((Instruction::ORA, AddressingMode::ZeroPageX)),
|
||||
/*0x16*/ Some((Instruction::ASL, AddressingMode::ZeroPageX)),
|
||||
/*0x17*/ None,
|
||||
/*0x18*/ Some((CLC, Implied)),
|
||||
/*0x19*/ Some((ORA, AbsoluteY)),
|
||||
/*0x18*/ Some((Instruction::CLC, AddressingMode::Implied)),
|
||||
/*0x19*/ Some((Instruction::ORA, AddressingMode::AbsoluteY)),
|
||||
/*0x1A*/ None,
|
||||
/*0x1B*/ None,
|
||||
/*0x1C*/ None,
|
||||
/*0x1D*/ Some((ORA, AbsoluteX)),
|
||||
/*0x1E*/ Some((ASL, AbsoluteX)),
|
||||
/*0x1D*/ Some((Instruction::ORA, AddressingMode::AbsoluteX)),
|
||||
/*0x1E*/ Some((Instruction::ASL, AddressingMode::AbsoluteX)),
|
||||
/*0x1F*/ None,
|
||||
/*0x20*/ Some((JSR, Absolute)),
|
||||
/*0x21*/ Some((AND, IndexedIndirectX)),
|
||||
/*0x20*/ Some((Instruction::JSR, AddressingMode::Absolute)),
|
||||
/*0x21*/ Some((Instruction::AND, AddressingMode::IndexedIndirectX)),
|
||||
/*0x22*/ None,
|
||||
/*0x23*/ None,
|
||||
/*0x24*/ Some((BIT, ZeroPage)),
|
||||
/*0x25*/ Some((AND, ZeroPage)),
|
||||
/*0x26*/ Some((ROL, ZeroPage)),
|
||||
/*0x24*/ Some((Instruction::BIT, AddressingMode::ZeroPage)),
|
||||
/*0x25*/ Some((Instruction::AND, AddressingMode::ZeroPage)),
|
||||
/*0x26*/ Some((Instruction::ROL, AddressingMode::ZeroPage)),
|
||||
/*0x27*/ None,
|
||||
/*0x28*/ Some((PLP, Implied)),
|
||||
/*0x29*/ Some((AND, Immediate)),
|
||||
/*0x2A*/ Some((ROL, Accumulator)),
|
||||
/*0x28*/ Some((Instruction::PLP, AddressingMode::Implied)),
|
||||
/*0x29*/ Some((Instruction::AND, AddressingMode::Immediate)),
|
||||
/*0x2A*/ Some((Instruction::ROL, AddressingMode::Accumulator)),
|
||||
/*0x2B*/ None,
|
||||
/*0x2C*/ Some((BIT, Absolute)),
|
||||
/*0x2D*/ Some((AND, Absolute)),
|
||||
/*0x2E*/ Some((ROL, Absolute)),
|
||||
/*0x2C*/ Some((Instruction::BIT, AddressingMode::Absolute)),
|
||||
/*0x2D*/ Some((Instruction::AND, AddressingMode::Absolute)),
|
||||
/*0x2E*/ Some((Instruction::ROL, AddressingMode::Absolute)),
|
||||
/*0x2F*/ None,
|
||||
/*0x30*/ Some((BMI, Relative)),
|
||||
/*0x31*/ Some((AND, IndirectIndexedY)),
|
||||
/*0x30*/ Some((Instruction::BMI, AddressingMode::Relative)),
|
||||
/*0x31*/ Some((Instruction::AND, AddressingMode::IndirectIndexedY)),
|
||||
/*0x32*/ None,
|
||||
/*0x33*/ None,
|
||||
/*0x34*/ None,
|
||||
/*0x35*/ Some((AND, ZeroPageX)),
|
||||
/*0x36*/ Some((ROL, ZeroPageX)),
|
||||
/*0x35*/ Some((Instruction::AND, AddressingMode::ZeroPageX)),
|
||||
/*0x36*/ Some((Instruction::ROL, AddressingMode::ZeroPageX)),
|
||||
/*0x37*/ None,
|
||||
/*0x38*/ Some((SEC, Implied)),
|
||||
/*0x39*/ Some((AND, AbsoluteY)),
|
||||
/*0x38*/ Some((Instruction::SEC, AddressingMode::Implied)),
|
||||
/*0x39*/ Some((Instruction::AND, AddressingMode::AbsoluteY)),
|
||||
/*0x3A*/ None,
|
||||
/*0x3B*/ None,
|
||||
/*0x3C*/ None,
|
||||
/*0x3D*/ Some((AND, AbsoluteX)),
|
||||
/*0x3E*/ Some((ROL, AbsoluteX)),
|
||||
/*0x3D*/ Some((Instruction::AND, AddressingMode::AbsoluteX)),
|
||||
/*0x3E*/ Some((Instruction::ROL, AddressingMode::AbsoluteX)),
|
||||
/*0x3F*/ None,
|
||||
/*0x40*/ Some((RTI, Implied)),
|
||||
/*0x41*/ Some((EOR, IndexedIndirectX)),
|
||||
/*0x40*/ Some((Instruction::RTI, AddressingMode::Implied)),
|
||||
/*0x41*/ Some((Instruction::EOR, AddressingMode::IndexedIndirectX)),
|
||||
/*0x42*/ None,
|
||||
/*0x43*/ None,
|
||||
/*0x44*/ None,
|
||||
/*0x45*/ Some((EOR, ZeroPage)),
|
||||
/*0x46*/ Some((LSR, ZeroPage)),
|
||||
/*0x45*/ Some((Instruction::EOR, AddressingMode::ZeroPage)),
|
||||
/*0x46*/ Some((Instruction::LSR, AddressingMode::ZeroPage)),
|
||||
/*0x47*/ None,
|
||||
/*0x48*/ Some((PHA, Implied)),
|
||||
/*0x49*/ Some((EOR, Immediate)),
|
||||
/*0x4A*/ Some((LSR, Accumulator)),
|
||||
/*0x48*/ Some((Instruction::PHA, AddressingMode::Implied)),
|
||||
/*0x49*/ Some((Instruction::EOR, AddressingMode::Immediate)),
|
||||
/*0x4A*/ Some((Instruction::LSR, AddressingMode::Accumulator)),
|
||||
/*0x4B*/ None,
|
||||
/*0x4C*/ Some((JMP, Absolute)),
|
||||
/*0x4D*/ Some((EOR, Absolute)),
|
||||
/*0x4E*/ Some((LSR, Absolute)),
|
||||
/*0x4C*/ Some((Instruction::JMP, AddressingMode::Absolute)),
|
||||
/*0x4D*/ Some((Instruction::EOR, AddressingMode::Absolute)),
|
||||
/*0x4E*/ Some((Instruction::LSR, AddressingMode::Absolute)),
|
||||
/*0x4F*/ None,
|
||||
/*0x50*/ Some((BVC, Relative)),
|
||||
/*0x51*/ Some((EOR, IndirectIndexedY)),
|
||||
/*0x50*/ Some((Instruction::BVC, AddressingMode::Relative)),
|
||||
/*0x51*/ Some((Instruction::EOR, AddressingMode::IndirectIndexedY)),
|
||||
/*0x52*/ None,
|
||||
/*0x53*/ None,
|
||||
/*0x54*/ None,
|
||||
/*0x55*/ Some((EOR, ZeroPageX)),
|
||||
/*0x56*/ Some((LSR, ZeroPageX)),
|
||||
/*0x55*/ Some((Instruction::EOR, AddressingMode::ZeroPageX)),
|
||||
/*0x56*/ Some((Instruction::LSR, AddressingMode::ZeroPageX)),
|
||||
/*0x57*/ None,
|
||||
/*0x58*/ None,
|
||||
/*0x59*/ Some((EOR, AbsoluteY)),
|
||||
/*0x59*/ Some((Instruction::EOR, AddressingMode::AbsoluteY)),
|
||||
/*0x5A*/ None,
|
||||
/*0x5B*/ None,
|
||||
/*0x5C*/ None,
|
||||
/*0x5D*/ Some((EOR, AbsoluteX)),
|
||||
/*0x5E*/ Some((LSR, AbsoluteX)),
|
||||
/*0x5D*/ Some((Instruction::EOR, AddressingMode::AbsoluteX)),
|
||||
/*0x5E*/ Some((Instruction::LSR, AddressingMode::AbsoluteX)),
|
||||
/*0x5F*/ None,
|
||||
/*0x60*/ Some((RTS, Implied)),
|
||||
/*0x61*/ Some((ADC, IndexedIndirectX)),
|
||||
/*0x60*/ Some((Instruction::RTS, AddressingMode::Implied)),
|
||||
/*0x61*/ Some((Instruction::ADC, AddressingMode::IndexedIndirectX)),
|
||||
/*0x62*/ None,
|
||||
/*0x63*/ None,
|
||||
/*0x64*/ None,
|
||||
/*0x65*/ Some((ADC, ZeroPage)),
|
||||
/*0x66*/ Some((ROR, ZeroPage)),
|
||||
/*0x65*/ Some((Instruction::ADC, AddressingMode::ZeroPage)),
|
||||
/*0x66*/ Some((Instruction::ROR, AddressingMode::ZeroPage)),
|
||||
/*0x67*/ None,
|
||||
/*0x68*/ Some((PLA, Implied)),
|
||||
/*0x69*/ Some((ADC, Immediate)),
|
||||
/*0x6A*/ Some((ROR, Accumulator)),
|
||||
/*0x68*/ Some((Instruction::PLA, AddressingMode::Implied)),
|
||||
/*0x69*/ Some((Instruction::ADC, AddressingMode::Immediate)),
|
||||
/*0x6A*/ Some((Instruction::ROR, AddressingMode::Accumulator)),
|
||||
/*0x6B*/ None,
|
||||
/*0x6C*/ Some((JMP, Indirect)),
|
||||
/*0x6D*/ Some((ADC, Absolute)),
|
||||
/*0x6E*/ Some((ROR, Absolute)),
|
||||
/*0x6C*/ Some((Instruction::JMP, AddressingMode::Indirect)),
|
||||
/*0x6D*/ Some((Instruction::ADC, AddressingMode::Absolute)),
|
||||
/*0x6E*/ Some((Instruction::ROR, AddressingMode::Absolute)),
|
||||
/*0x6F*/ None,
|
||||
/*0x70*/ Some((BVS, Relative)),
|
||||
/*0x71*/ Some((ADC, IndirectIndexedY)),
|
||||
/*0x70*/ Some((Instruction::BVS, AddressingMode::Relative)),
|
||||
/*0x71*/ Some((Instruction::ADC, AddressingMode::IndirectIndexedY)),
|
||||
/*0x72*/ None,
|
||||
/*0x73*/ None,
|
||||
/*0x74*/ None,
|
||||
/*0x75*/ Some((ADC, ZeroPageX)),
|
||||
/*0x76*/ Some((ROR, ZeroPageX)),
|
||||
/*0x75*/ Some((Instruction::ADC, AddressingMode::ZeroPageX)),
|
||||
/*0x76*/ Some((Instruction::ROR, AddressingMode::ZeroPageX)),
|
||||
/*0x77*/ None,
|
||||
/*0x78*/ Some((SEI, Implied)),
|
||||
/*0x79*/ Some((ADC, AbsoluteY)),
|
||||
/*0x78*/ Some((Instruction::SEI, AddressingMode::Implied)),
|
||||
/*0x79*/ Some((Instruction::ADC, AddressingMode::AbsoluteY)),
|
||||
/*0x7A*/ None,
|
||||
/*0x7B*/ None,
|
||||
/*0x7C*/ None,
|
||||
/*0x7D*/ Some((ADC, AbsoluteX)),
|
||||
/*0x7E*/ Some((ROR, AbsoluteX)),
|
||||
/*0x7D*/ Some((Instruction::ADC, AddressingMode::AbsoluteX)),
|
||||
/*0x7E*/ Some((Instruction::ROR, AddressingMode::AbsoluteX)),
|
||||
/*0x7F*/ None,
|
||||
/*0x80*/ None,
|
||||
/*0x81*/ Some((STA, IndexedIndirectX)),
|
||||
/*0x81*/ Some((Instruction::STA, AddressingMode::IndexedIndirectX)),
|
||||
/*0x82*/ None,
|
||||
/*0x83*/ None,
|
||||
/*0x84*/ Some((STY, ZeroPage)),
|
||||
/*0x85*/ Some((STA, ZeroPage)),
|
||||
/*0x86*/ Some((STX, ZeroPage)),
|
||||
/*0x84*/ Some((Instruction::STY, AddressingMode::ZeroPage)),
|
||||
/*0x85*/ Some((Instruction::STA, AddressingMode::ZeroPage)),
|
||||
/*0x86*/ Some((Instruction::STX, AddressingMode::ZeroPage)),
|
||||
/*0x87*/ None,
|
||||
/*0x88*/ Some((DEY, Implied)),
|
||||
/*0x88*/ Some((Instruction::DEY, AddressingMode::Implied)),
|
||||
/*0x89*/ None,
|
||||
/*0x8A*/ Some((TXA, Implied)),
|
||||
/*0x8A*/ Some((Instruction::TXA, AddressingMode::Implied)),
|
||||
/*0x8B*/ None,
|
||||
/*0x8C*/ Some((STY, Absolute)),
|
||||
/*0x8D*/ Some((STA, Absolute)),
|
||||
/*0x8E*/ Some((STX, Absolute)),
|
||||
/*0x8C*/ Some((Instruction::STY, AddressingMode::Absolute)),
|
||||
/*0x8D*/ Some((Instruction::STA, AddressingMode::Absolute)),
|
||||
/*0x8E*/ Some((Instruction::STX, AddressingMode::Absolute)),
|
||||
/*0x8F*/ None,
|
||||
/*0x90*/ Some((BCC, Relative)),
|
||||
/*0x91*/ Some((STA, IndirectIndexedY)),
|
||||
/*0x90*/ Some((Instruction::BCC, AddressingMode::Relative)),
|
||||
/*0x91*/ Some((Instruction::STA, AddressingMode::IndirectIndexedY)),
|
||||
/*0x92*/ None,
|
||||
/*0x93*/ None,
|
||||
/*0x94*/ Some((STY, ZeroPageX)),
|
||||
/*0x95*/ Some((STA, ZeroPageX)),
|
||||
/*0x96*/ Some((STX, ZeroPageY)),
|
||||
/*0x94*/ Some((Instruction::STY, AddressingMode::ZeroPageX)),
|
||||
/*0x95*/ Some((Instruction::STA, AddressingMode::ZeroPageX)),
|
||||
/*0x96*/ Some((Instruction::STX, AddressingMode::ZeroPageY)),
|
||||
/*0x97*/ None,
|
||||
/*0x98*/ Some((TYA, Implied)),
|
||||
/*0x99*/ Some((STA, AbsoluteY)),
|
||||
/*0x9A*/ Some((TXS, Implied)),
|
||||
/*0x98*/ Some((Instruction::TYA, AddressingMode::Implied)),
|
||||
/*0x99*/ Some((Instruction::STA, AddressingMode::AbsoluteY)),
|
||||
/*0x9A*/ Some((Instruction::TXS, AddressingMode::Implied)),
|
||||
/*0x9B*/ None,
|
||||
/*0x9C*/ None,
|
||||
/*0x9D*/ Some((STA, AbsoluteX)),
|
||||
/*0x9D*/ Some((Instruction::STA, AddressingMode::AbsoluteX)),
|
||||
/*0x9E*/ None,
|
||||
/*0x9F*/ None,
|
||||
/*0xA0*/ Some((LDY, Immediate)),
|
||||
/*0xA1*/ Some((LDA, IndexedIndirectX)),
|
||||
/*0xA2*/ Some((LDX, Immediate)),
|
||||
/*0xA0*/ Some((Instruction::LDY, AddressingMode::Immediate)),
|
||||
/*0xA1*/ Some((Instruction::LDA, AddressingMode::IndexedIndirectX)),
|
||||
/*0xA2*/ Some((Instruction::LDX, AddressingMode::Immediate)),
|
||||
/*0xA3*/ None,
|
||||
/*0xA4*/ Some((LDY, ZeroPage)),
|
||||
/*0xA5*/ Some((LDA, ZeroPage)),
|
||||
/*0xA6*/ Some((LDX, ZeroPage)),
|
||||
/*0xA4*/ Some((Instruction::LDY, AddressingMode::ZeroPage)),
|
||||
/*0xA5*/ Some((Instruction::LDA, AddressingMode::ZeroPage)),
|
||||
/*0xA6*/ Some((Instruction::LDX, AddressingMode::ZeroPage)),
|
||||
/*0xA7*/ None,
|
||||
/*0xA8*/ Some((TAY, Implied)),
|
||||
/*0xA9*/ Some((LDA, Immediate)),
|
||||
/*0xAA*/ Some((TAX, Implied)),
|
||||
/*0xA8*/ Some((Instruction::TAY, AddressingMode::Implied)),
|
||||
/*0xA9*/ Some((Instruction::LDA, AddressingMode::Immediate)),
|
||||
/*0xAA*/ Some((Instruction::TAX, AddressingMode::Implied)),
|
||||
/*0xAB*/ None,
|
||||
/*0xAC*/ Some((LDY, Absolute)),
|
||||
/*0xAD*/ Some((LDA, Absolute)),
|
||||
/*0xAE*/ Some((LDX, Absolute)),
|
||||
/*0xAC*/ Some((Instruction::LDY, AddressingMode::Absolute)),
|
||||
/*0xAD*/ Some((Instruction::LDA, AddressingMode::Absolute)),
|
||||
/*0xAE*/ Some((Instruction::LDX, AddressingMode::Absolute)),
|
||||
/*0xAF*/ None,
|
||||
/*0xB0*/ Some((BCS, Relative)),
|
||||
/*0xB1*/ Some((LDA, IndirectIndexedY)),
|
||||
/*0xB0*/ Some((Instruction::BCS, AddressingMode::Relative)),
|
||||
/*0xB1*/ Some((Instruction::LDA, AddressingMode::IndirectIndexedY)),
|
||||
/*0xB2*/ None,
|
||||
/*0xB3*/ None,
|
||||
/*0xB4*/ Some((LDY, ZeroPageX)),
|
||||
/*0xB5*/ Some((LDA, ZeroPageX)),
|
||||
/*0xB6*/ Some((LDX, ZeroPageY)),
|
||||
/*0xB4*/ Some((Instruction::LDY, AddressingMode::ZeroPageX)),
|
||||
/*0xB5*/ Some((Instruction::LDA, AddressingMode::ZeroPageX)),
|
||||
/*0xB6*/ Some((Instruction::LDX, AddressingMode::ZeroPageY)),
|
||||
/*0xB7*/ None,
|
||||
/*0xB8*/ Some((CLV, Implied)),
|
||||
/*0xB9*/ Some((LDA, AbsoluteY)),
|
||||
/*0xBA*/ Some((TSX, Implied)),
|
||||
/*0xB8*/ Some((Instruction::CLV, AddressingMode::Implied)),
|
||||
/*0xB9*/ Some((Instruction::LDA, AddressingMode::AbsoluteY)),
|
||||
/*0xBA*/ Some((Instruction::TSX, AddressingMode::Implied)),
|
||||
/*0xBB*/ None,
|
||||
/*0xBC*/ Some((LDY, AbsoluteX)),
|
||||
/*0xBD*/ Some((LDA, AbsoluteX)),
|
||||
/*0xBE*/ Some((LDX, AbsoluteY)),
|
||||
/*0xBC*/ Some((Instruction::LDY, AddressingMode::AbsoluteX)),
|
||||
/*0xBD*/ Some((Instruction::LDA, AddressingMode::AbsoluteX)),
|
||||
/*0xBE*/ Some((Instruction::LDX, AddressingMode::AbsoluteY)),
|
||||
/*0xBF*/ None,
|
||||
/*0xC0*/ Some((CPY, Immediate)),
|
||||
/*0xC1*/ Some((CMP, IndexedIndirectX)),
|
||||
/*0xC0*/ Some((Instruction::CPY, AddressingMode::Immediate)),
|
||||
/*0xC1*/ Some((Instruction::CMP, AddressingMode::IndexedIndirectX)),
|
||||
/*0xC2*/ None,
|
||||
/*0xC3*/ None,
|
||||
/*0xC4*/ Some((CPY, ZeroPage)),
|
||||
/*0xC5*/ Some((CMP, ZeroPage)),
|
||||
/*0xC6*/ Some((DEC, ZeroPage)),
|
||||
/*0xC4*/ Some((Instruction::CPY, AddressingMode::ZeroPage)),
|
||||
/*0xC5*/ Some((Instruction::CMP, AddressingMode::ZeroPage)),
|
||||
/*0xC6*/ Some((Instruction::DEC, AddressingMode::ZeroPage)),
|
||||
/*0xC7*/ None,
|
||||
/*0xC8*/ Some((INY, Implied)),
|
||||
/*0xC9*/ Some((CMP, Immediate)),
|
||||
/*0xCA*/ Some((DEX, Implied)),
|
||||
/*0xC8*/ Some((Instruction::INY, AddressingMode::Implied)),
|
||||
/*0xC9*/ Some((Instruction::CMP, AddressingMode::Immediate)),
|
||||
/*0xCA*/ Some((Instruction::DEX, AddressingMode::Implied)),
|
||||
/*0xCB*/ None,
|
||||
/*0xCC*/ Some((CPY, Absolute)),
|
||||
/*0xCD*/ Some((CMP, Absolute)),
|
||||
/*0xCE*/ Some((DEC, Absolute)),
|
||||
/*0xCC*/ Some((Instruction::CPY, AddressingMode::Absolute)),
|
||||
/*0xCD*/ Some((Instruction::CMP, AddressingMode::Absolute)),
|
||||
/*0xCE*/ Some((Instruction::DEC, AddressingMode::Absolute)),
|
||||
/*0xCF*/ None,
|
||||
/*0xD0*/ Some((BNE, Relative)),
|
||||
/*0xD1*/ Some((CMP, IndirectIndexedY)),
|
||||
/*0xD0*/ Some((Instruction::BNE, AddressingMode::Relative)),
|
||||
/*0xD1*/ Some((Instruction::CMP, AddressingMode::IndirectIndexedY)),
|
||||
/*0xD2*/ None,
|
||||
/*0xD3*/ None,
|
||||
/*0xD4*/ None,
|
||||
/*0xD5*/ Some((CMP, ZeroPageX)),
|
||||
/*0xD6*/ Some((DEC, ZeroPageX)),
|
||||
/*0xD5*/ Some((Instruction::CMP, AddressingMode::ZeroPageX)),
|
||||
/*0xD6*/ Some((Instruction::DEC, AddressingMode::ZeroPageX)),
|
||||
/*0xD7*/ None,
|
||||
/*0xD8*/ Some((CLD, Implied)),
|
||||
/*0xD9*/ Some((CMP, AbsoluteY)),
|
||||
/*0xD8*/ Some((Instruction::CLD, AddressingMode::Implied)),
|
||||
/*0xD9*/ Some((Instruction::CMP, AddressingMode::AbsoluteY)),
|
||||
/*0xDA*/ None,
|
||||
/*0xDB*/ None,
|
||||
/*0xDC*/ None,
|
||||
/*0xDD*/ Some((CMP, AbsoluteX)),
|
||||
/*0xDE*/ Some((DEC, AbsoluteX)),
|
||||
/*0xDD*/ Some((Instruction::CMP, AddressingMode::AbsoluteX)),
|
||||
/*0xDE*/ Some((Instruction::DEC, AddressingMode::AbsoluteX)),
|
||||
/*0xDF*/ None,
|
||||
/*0xE0*/ Some((CPX, Immediate)),
|
||||
/*0xE1*/ Some((SBC, IndexedIndirectX)),
|
||||
/*0xE0*/ Some((Instruction::CPX, AddressingMode::Immediate)),
|
||||
/*0xE1*/ Some((Instruction::SBC, AddressingMode::IndexedIndirectX)),
|
||||
/*0xE2*/ None,
|
||||
/*0xE3*/ None,
|
||||
/*0xE4*/ Some((CPX, ZeroPage)),
|
||||
/*0xE5*/ Some((SBC, ZeroPage)),
|
||||
/*0xE6*/ Some((INC, ZeroPage)),
|
||||
/*0xE4*/ Some((Instruction::CPX, AddressingMode::ZeroPage)),
|
||||
/*0xE5*/ Some((Instruction::SBC, AddressingMode::ZeroPage)),
|
||||
/*0xE6*/ Some((Instruction::INC, AddressingMode::ZeroPage)),
|
||||
/*0xE7*/ None,
|
||||
/*0xE8*/ Some((INX, Implied)),
|
||||
/*0xE9*/ Some((SBC, Immediate)),
|
||||
/*0xEA*/ Some((NOP, Implied)),
|
||||
/*0xE8*/ Some((Instruction::INX, AddressingMode::Implied)),
|
||||
/*0xE9*/ Some((Instruction::SBC, AddressingMode::Immediate)),
|
||||
/*0xEA*/ Some((Instruction::NOP, AddressingMode::Implied)),
|
||||
/*0xEB*/ None,
|
||||
/*0xEC*/ Some((CPX, Absolute)),
|
||||
/*0xED*/ Some((SBC, Absolute)),
|
||||
/*0xEE*/ Some((INC, Absolute)),
|
||||
/*0xEC*/ Some((Instruction::CPX, AddressingMode::Absolute)),
|
||||
/*0xED*/ Some((Instruction::SBC, AddressingMode::Absolute)),
|
||||
/*0xEE*/ Some((Instruction::INC, AddressingMode::Absolute)),
|
||||
/*0xEF*/ None,
|
||||
/*0xF0*/ Some((BEQ, Relative)),
|
||||
/*0xF1*/ Some((SBC, IndirectIndexedY)),
|
||||
/*0xF0*/ Some((Instruction::BEQ, AddressingMode::Relative)),
|
||||
/*0xF1*/ Some((Instruction::SBC, AddressingMode::IndirectIndexedY)),
|
||||
/*0xF2*/ None,
|
||||
/*0xF3*/ None,
|
||||
/*0xF4*/ None,
|
||||
/*0xF5*/ Some((SBC, ZeroPageX)),
|
||||
/*0xF6*/ Some((INC, ZeroPageX)),
|
||||
/*0xF5*/ Some((Instruction::SBC, AddressingMode::ZeroPageX)),
|
||||
/*0xF6*/ Some((Instruction::INC, AddressingMode::ZeroPageX)),
|
||||
/*0xF7*/ None,
|
||||
/*0xF8*/ Some((SED, Implied)),
|
||||
/*0xF9*/ Some((SBC, AbsoluteY)),
|
||||
/*0xF8*/ Some((Instruction::SED, AddressingMode::Implied)),
|
||||
/*0xF9*/ Some((Instruction::SBC, AddressingMode::AbsoluteY)),
|
||||
/*0xFA*/ None,
|
||||
/*0xFB*/ None,
|
||||
/*0xFC*/ None,
|
||||
/*0xFD*/ Some((SBC, AbsoluteX)),
|
||||
/*0xFE*/ Some((INC, AbsoluteX)),
|
||||
/*0xFD*/ Some((Instruction::SBC, AddressingMode::AbsoluteX)),
|
||||
/*0xFE*/ Some((Instruction::INC, AddressingMode::AbsoluteX)),
|
||||
/*0xFF*/ None,
|
||||
];
|
||||
|
||||
|
203
src/machine.rs
203
src/machine.rs
@ -29,7 +29,7 @@ use std;
|
||||
|
||||
use address::{Address, AddressDiff};
|
||||
use instruction;
|
||||
use instruction::{DecodedInstr};
|
||||
use instruction::{DecodedInstr, Instruction, OpInput};
|
||||
use memory::Memory;
|
||||
use registers::{ Registers, StackPointer, Status, StatusArgs };
|
||||
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) {
|
||||
match decoded_instr {
|
||||
(instruction::ADC, instruction::UseImmediate(val)) => {
|
||||
(Instruction::ADC, OpInput::UseImmediate(val)) => {
|
||||
debug!("add with carry immediate: {}", val);
|
||||
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;
|
||||
debug!("add with carry. address: {}. value: {}", addr, val);
|
||||
self.add_with_carry(val);
|
||||
}
|
||||
|
||||
(instruction::AND, instruction::UseImmediate(val)) => {
|
||||
(Instruction::AND, OpInput::UseImmediate(val)) => {
|
||||
self.and(val as i8);
|
||||
}
|
||||
(instruction::AND, instruction::UseAddress(addr)) => {
|
||||
(Instruction::AND, OpInput::UseAddress(addr)) => {
|
||||
let val = self.memory.get_byte(addr) as i8;
|
||||
self.and(val as i8);
|
||||
}
|
||||
|
||||
(instruction::ASL, instruction::UseImplied) => {
|
||||
(Instruction::ASL, OpInput::UseImplied) => {
|
||||
// Accumulator mode
|
||||
let mut val = self.registers.accumulator as u8;
|
||||
Machine::shift_left_with_flags(&mut val,
|
||||
@ -104,31 +104,31 @@ impl Machine {
|
||||
self.registers.accumulator = val as i8;
|
||||
|
||||
}
|
||||
(instruction::ASL, instruction::UseAddress(addr)) => {
|
||||
(Instruction::ASL, OpInput::UseAddress(addr)) => {
|
||||
Machine::shift_left_with_flags(
|
||||
self.memory.get_byte_mut_ref(addr),
|
||||
&mut self.registers.status);
|
||||
}
|
||||
|
||||
(instruction::BCC, instruction::UseRelative(rel)) => {
|
||||
(Instruction::BCC, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
self.branch_if_carry_clear(addr);
|
||||
}
|
||||
|
||||
(instruction::BCS, instruction::UseRelative(rel)) => {
|
||||
(Instruction::BCS, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
self.branch_if_carry_set(addr);
|
||||
}
|
||||
|
||||
(instruction::BEQ, instruction::UseRelative(rel)) => {
|
||||
(Instruction::BEQ, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
self.branch_if_equal(addr);
|
||||
}
|
||||
|
||||
(instruction::BIT, instruction::UseAddress(addr)) => {
|
||||
(Instruction::BIT, OpInput::UseAddress(addr)) => {
|
||||
let a: u8 = self.registers.accumulator as u8;
|
||||
let m: u8 = self.memory.get_byte(addr);
|
||||
let res = a & m;
|
||||
@ -150,163 +150,163 @@ impl Machine {
|
||||
..StatusArgs::none() } ));
|
||||
}
|
||||
|
||||
(instruction::BMI, instruction::UseRelative(rel)) => {
|
||||
(Instruction::BMI, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
debug!("branch if minus relative. address: {}", addr);
|
||||
self.branch_if_minus(addr);
|
||||
}
|
||||
|
||||
(instruction::BPL, instruction::UseRelative(rel)) => {
|
||||
(Instruction::BPL, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
self.branch_if_positive(addr);
|
||||
}
|
||||
|
||||
(instruction::BVC, instruction::UseRelative(rel)) => {
|
||||
(Instruction::BVC, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
self.branch_if_overflow_clear(addr);
|
||||
}
|
||||
|
||||
(instruction::BVS, instruction::UseRelative(rel)) => {
|
||||
(Instruction::BVS, OpInput::UseRelative(rel)) => {
|
||||
let addr = self.registers.program_counter
|
||||
+ AddressDiff(rel as i32);
|
||||
self.branch_if_overflow_set(addr);
|
||||
}
|
||||
|
||||
(instruction::CLC, instruction::UseImplied) => {
|
||||
(Instruction::CLC, OpInput::UseImplied) => {
|
||||
self.registers.status.and(!PS_CARRY);
|
||||
}
|
||||
(instruction::CLD, instruction::UseImplied) => {
|
||||
(Instruction::CLD, OpInput::UseImplied) => {
|
||||
self.registers.status.and(!PS_DECIMAL_MODE);
|
||||
}
|
||||
(instruction::CLI, instruction::UseImplied) => {
|
||||
(Instruction::CLI, OpInput::UseImplied) => {
|
||||
self.registers.status.and(!PS_DISABLE_INTERRUPTS);
|
||||
}
|
||||
(instruction::CLV, instruction::UseImplied) => {
|
||||
(Instruction::CLV, OpInput::UseImplied) => {
|
||||
self.registers.status.and(!PS_OVERFLOW);
|
||||
}
|
||||
|
||||
(instruction::CMP, instruction::UseImmediate(val)) => {
|
||||
(Instruction::CMP, OpInput::UseImmediate(val)) => {
|
||||
self.compare_with_a_register(val);
|
||||
}
|
||||
(instruction::CMP, instruction::UseAddress(addr)) => {
|
||||
(Instruction::CMP, OpInput::UseAddress(addr)) => {
|
||||
let val = self.memory.get_byte(addr);
|
||||
self.compare_with_a_register(val);
|
||||
}
|
||||
|
||||
(instruction::CPX, instruction::UseImmediate(val)) => {
|
||||
(Instruction::CPX, OpInput::UseImmediate(val)) => {
|
||||
self.compare_with_x_register(val);
|
||||
}
|
||||
(instruction::CPX, instruction::UseAddress(addr)) => {
|
||||
(Instruction::CPX, OpInput::UseAddress(addr)) => {
|
||||
let val = self.memory.get_byte(addr);
|
||||
self.compare_with_x_register(val);
|
||||
}
|
||||
|
||||
(instruction::CPY, instruction::UseImmediate(val)) => {
|
||||
(Instruction::CPY, OpInput::UseImmediate(val)) => {
|
||||
self.compare_with_y_register(val);
|
||||
}
|
||||
(instruction::CPY, instruction::UseAddress(addr)) => {
|
||||
(Instruction::CPY, OpInput::UseAddress(addr)) => {
|
||||
let val = self.memory.get_byte(addr);
|
||||
self.compare_with_y_register(val);
|
||||
}
|
||||
|
||||
(instruction::DEC, instruction::UseAddress(addr)) => {
|
||||
(Instruction::DEC, OpInput::UseAddress(addr)) => {
|
||||
self.decrement_memory(addr)
|
||||
}
|
||||
|
||||
(instruction::DEX, instruction::UseImplied) => {
|
||||
(Instruction::DEX, OpInput::UseImplied) => {
|
||||
self.dec_x();
|
||||
}
|
||||
|
||||
(instruction::EOR, instruction::UseImmediate(val)) => {
|
||||
(Instruction::EOR, OpInput::UseImmediate(val)) => {
|
||||
self.exclusive_or(val);
|
||||
}
|
||||
(instruction::EOR, instruction::UseAddress(addr)) => {
|
||||
(Instruction::EOR, OpInput::UseAddress(addr)) => {
|
||||
let val = self.memory.get_byte(addr);
|
||||
self.exclusive_or(val);
|
||||
}
|
||||
|
||||
(instruction::INC, instruction::UseAddress(addr)) => {
|
||||
(Instruction::INC, OpInput::UseAddress(addr)) => {
|
||||
let m = self.memory.get_byte(addr);
|
||||
let m = m + 1;
|
||||
self.memory.set_byte(addr, m);
|
||||
let i = m as i8;
|
||||
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;
|
||||
self.load_x_register(x);
|
||||
}
|
||||
(instruction::INY, instruction::UseImplied) => {
|
||||
(Instruction::INY, OpInput::UseImplied) => {
|
||||
let y = self.registers.index_y + 1;
|
||||
self.load_y_register(y);
|
||||
}
|
||||
|
||||
(instruction::JMP, instruction::UseAddress(addr)) => {
|
||||
(Instruction::JMP, OpInput::UseAddress(addr)) => {
|
||||
self.jump(addr)
|
||||
}
|
||||
|
||||
(instruction::LDA, instruction::UseImmediate(val)) => {
|
||||
(Instruction::LDA, OpInput::UseImmediate(val)) => {
|
||||
debug!("load A immediate: {}", val);
|
||||
self.load_accumulator(val as i8);
|
||||
}
|
||||
(instruction::LDA, instruction::UseAddress(addr)) => {
|
||||
(Instruction::LDA, OpInput::UseAddress(addr)) => {
|
||||
let val = self.memory.get_byte(addr);
|
||||
debug!("load A. address: {}. value: {}", addr, val);
|
||||
self.load_accumulator(val as i8);
|
||||
}
|
||||
|
||||
(instruction::LDX, instruction::UseImmediate(val)) => {
|
||||
(Instruction::LDX, OpInput::UseImmediate(val)) => {
|
||||
debug!("load X immediate: {}", val);
|
||||
self.load_x_register(val as i8);
|
||||
}
|
||||
(instruction::LDX, instruction::UseAddress(addr)) => {
|
||||
(Instruction::LDX, OpInput::UseAddress(addr)) => {
|
||||
let val = self.memory.get_byte(addr);
|
||||
debug!("load X. address: {}. value: {}", addr, val);
|
||||
self.load_x_register(val as i8);
|
||||
}
|
||||
|
||||
(instruction::LDY, instruction::UseImmediate(val)) => {
|
||||
(Instruction::LDY, OpInput::UseImmediate(val)) => {
|
||||
debug!("load Y immediate: {}", val);
|
||||
self.load_y_register(val as i8);
|
||||
}
|
||||
(instruction::LDY, instruction::UseAddress(addr)) => {
|
||||
(Instruction::LDY, OpInput::UseAddress(addr)) => {
|
||||
let val = self.memory.get_byte(addr);
|
||||
debug!("load Y. address: {}. value: {}", addr, val);
|
||||
self.load_y_register(val as i8);
|
||||
}
|
||||
|
||||
(instruction::LSR, instruction::UseImplied) => {
|
||||
(Instruction::LSR, OpInput::UseImplied) => {
|
||||
// Accumulator mode
|
||||
let mut val = self.registers.accumulator as u8;
|
||||
Machine::shift_right_with_flags(&mut val,
|
||||
&mut self.registers.status);
|
||||
self.registers.accumulator = val as i8;
|
||||
}
|
||||
(instruction::LSR, instruction::UseAddress(addr)) => {
|
||||
(Instruction::LSR, OpInput::UseAddress(addr)) => {
|
||||
Machine::shift_right_with_flags(
|
||||
self.memory.get_byte_mut_ref(addr),
|
||||
&mut self.registers.status);
|
||||
}
|
||||
|
||||
(instruction::PHA, instruction::UseImplied) => {
|
||||
(Instruction::PHA, OpInput::UseImplied) => {
|
||||
// Push accumulator
|
||||
let val = self.registers.accumulator as u8;
|
||||
self.push_on_stack(val);
|
||||
}
|
||||
(instruction::PHP, instruction::UseImplied) => {
|
||||
(Instruction::PHP, OpInput::UseImplied) => {
|
||||
// Push status
|
||||
let val = self.registers.status.bits();
|
||||
self.push_on_stack(val);
|
||||
}
|
||||
(instruction::PLA, instruction::UseImplied) => {
|
||||
(Instruction::PLA, OpInput::UseImplied) => {
|
||||
// Pull accumulator
|
||||
let val: u8 = self.pull_from_stack();
|
||||
self.registers.accumulator = val as i8;
|
||||
}
|
||||
(instruction::PLP, instruction::UseImplied) => {
|
||||
(Instruction::PLP, OpInput::UseImplied) => {
|
||||
// Pull status
|
||||
let val: u8 = self.pull_from_stack();
|
||||
// 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);
|
||||
}
|
||||
|
||||
(instruction::ROL, instruction::UseImplied) => {
|
||||
(Instruction::ROL, OpInput::UseImplied) => {
|
||||
// Accumulator mode
|
||||
let mut val = self.registers.accumulator as u8;
|
||||
Machine::rotate_left_with_flags(&mut val,
|
||||
&mut self.registers.status);
|
||||
self.registers.accumulator = val as i8;
|
||||
}
|
||||
(instruction::ROL, instruction::UseAddress(addr)) => {
|
||||
(Instruction::ROL, OpInput::UseAddress(addr)) => {
|
||||
Machine::rotate_left_with_flags(
|
||||
self.memory.get_byte_mut_ref(addr),
|
||||
&mut self.registers.status);
|
||||
}
|
||||
(instruction::ROR, instruction::UseImplied) => {
|
||||
(Instruction::ROR, OpInput::UseImplied) => {
|
||||
// Accumulator mode
|
||||
let mut val = self.registers.accumulator as u8;
|
||||
Machine::rotate_right_with_flags(&mut val,
|
||||
&mut self.registers.status);
|
||||
self.registers.accumulator = val as i8;
|
||||
}
|
||||
(instruction::ROR, instruction::UseAddress(addr)) => {
|
||||
(Instruction::ROR, OpInput::UseAddress(addr)) => {
|
||||
Machine::rotate_right_with_flags(
|
||||
self.memory.get_byte_mut_ref(addr),
|
||||
&mut self.registers.status);
|
||||
}
|
||||
|
||||
(instruction::SBC, instruction::UseImmediate(val)) => {
|
||||
(Instruction::SBC, OpInput::UseImmediate(val)) => {
|
||||
debug!("subtract with carry immediate: {}", val);
|
||||
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;
|
||||
debug!("subtract with carry. address: {}. value: {}",
|
||||
addr, val);
|
||||
self.subtract_with_carry(val);
|
||||
}
|
||||
|
||||
(instruction::SEC, instruction::UseImplied) => {
|
||||
(Instruction::SEC, OpInput::UseImplied) => {
|
||||
self.registers.status.or(PS_CARRY);
|
||||
}
|
||||
(instruction::SED, instruction::UseImplied) => {
|
||||
(Instruction::SED, OpInput::UseImplied) => {
|
||||
self.registers.status.or(PS_DECIMAL_MODE);
|
||||
}
|
||||
(instruction::SEI, instruction::UseImplied) => {
|
||||
(Instruction::SEI, OpInput::UseImplied) => {
|
||||
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);
|
||||
}
|
||||
(instruction::STX, instruction::UseAddress(addr)) => {
|
||||
(Instruction::STX, OpInput::UseAddress(addr)) => {
|
||||
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);
|
||||
}
|
||||
|
||||
(instruction::TAX, instruction::UseImplied) => {
|
||||
(Instruction::TAX, OpInput::UseImplied) => {
|
||||
let val = self.registers.accumulator;
|
||||
self.load_x_register(val);
|
||||
}
|
||||
(instruction::TAY, instruction::UseImplied) => {
|
||||
(Instruction::TAY, OpInput::UseImplied) => {
|
||||
let val = self.registers.accumulator;
|
||||
self.load_y_register(val);
|
||||
}
|
||||
(instruction::TSX, instruction::UseImplied) => {
|
||||
(Instruction::TSX, OpInput::UseImplied) => {
|
||||
let StackPointer(val) = self.registers.stack_pointer;
|
||||
let val = val as i8;
|
||||
self.load_x_register(val);
|
||||
}
|
||||
(instruction::TXA, instruction::UseImplied) => {
|
||||
(Instruction::TXA, OpInput::UseImplied) => {
|
||||
let val = self.registers.index_x;
|
||||
self.load_accumulator(val);
|
||||
}
|
||||
(instruction::TXS, instruction::UseImplied) => {
|
||||
(Instruction::TXS, OpInput::UseImplied) => {
|
||||
// Note that this is the only 'transfer' instruction that does
|
||||
// NOT set the zero and negative flags. (Because the target
|
||||
// is the stack pointer)
|
||||
let val = self.registers.index_x;
|
||||
self.registers.stack_pointer = StackPointer(val as u8);
|
||||
}
|
||||
(instruction::TYA, instruction::UseImplied) => {
|
||||
(Instruction::TYA, OpInput::UseImplied) => {
|
||||
let val = self.registers.index_y;
|
||||
self.load_accumulator(val);
|
||||
}
|
||||
|
||||
(instruction::NOP, instruction::UseImplied) => {
|
||||
(Instruction::NOP, OpInput::UseImplied) => {
|
||||
debug!("NOP instruction");
|
||||
}
|
||||
(_, _) => {
|
||||
@ -828,7 +828,7 @@ fn and_test() {
|
||||
fn subtract_with_carry_test() {
|
||||
let mut machine = Machine::new();
|
||||
|
||||
machine.execute_instruction((instruction::SEC, instruction::UseImplied));
|
||||
machine.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
machine.registers.accumulator = 0;
|
||||
|
||||
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_OVERFLOW), false);
|
||||
|
||||
machine.execute_instruction((instruction::SEC, instruction::UseImplied));
|
||||
machine.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
machine.registers.accumulator = -128;
|
||||
machine.subtract_with_carry(1);
|
||||
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_OVERFLOW), true);
|
||||
|
||||
machine.execute_instruction((instruction::SEC, instruction::UseImplied));
|
||||
machine.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
machine.registers.accumulator = 127;
|
||||
machine.subtract_with_carry(-1);
|
||||
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_OVERFLOW), true);
|
||||
|
||||
machine.execute_instruction((instruction::CLC, instruction::UseImplied));
|
||||
machine.execute_instruction((Instruction::CLC, OpInput::UseImplied));
|
||||
machine.registers.accumulator = -64;
|
||||
machine.subtract_with_carry(64);
|
||||
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_OVERFLOW), true);
|
||||
|
||||
machine.execute_instruction((instruction::SEC, instruction::UseImplied));
|
||||
machine.execute_instruction((Instruction::SEC, OpInput::UseImplied));
|
||||
machine.registers.accumulator = 0;
|
||||
machine.subtract_with_carry(-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_OVERFLOW), true);
|
||||
|
||||
machine.execute_instruction((instruction::CLC, instruction::UseImplied));
|
||||
machine.execute_instruction((Instruction::CLC, OpInput::UseImplied));
|
||||
machine.registers.accumulator = 0;
|
||||
machine.subtract_with_carry(127);
|
||||
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
|
||||
|
||||
let mut machine = Machine::new();
|
||||
machine.execute_instruction((instruction::LDA,
|
||||
instruction::UseImmediate(0)));
|
||||
machine.execute_instruction((instruction::LSR,
|
||||
instruction::UseImplied));
|
||||
machine.execute_instruction((Instruction::LDA,
|
||||
OpInput::UseImmediate(0)));
|
||||
machine.execute_instruction((Instruction::LSR,
|
||||
OpInput::UseImplied));
|
||||
assert_eq!(machine.registers.accumulator, 0);
|
||||
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_NEGATIVE), false);
|
||||
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
machine.execute_instruction((instruction::LDA,
|
||||
instruction::UseImmediate(1)));
|
||||
machine.execute_instruction((instruction::LSR,
|
||||
instruction::UseImplied));
|
||||
machine.execute_instruction((Instruction::LDA,
|
||||
OpInput::UseImmediate(1)));
|
||||
machine.execute_instruction((Instruction::LSR,
|
||||
OpInput::UseImplied));
|
||||
assert_eq!(machine.registers.accumulator, 0);
|
||||
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_NEGATIVE), false);
|
||||
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
machine.execute_instruction((instruction::LDA,
|
||||
instruction::UseImmediate(255)));
|
||||
machine.execute_instruction((instruction::LSR,
|
||||
instruction::UseImplied));
|
||||
machine.execute_instruction((Instruction::LDA,
|
||||
OpInput::UseImmediate(255)));
|
||||
machine.execute_instruction((Instruction::LSR,
|
||||
OpInput::UseImplied));
|
||||
assert_eq!(machine.registers.accumulator, 0x7F);
|
||||
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_NEGATIVE), false);
|
||||
assert_eq!(machine.registers.status.contains(PS_OVERFLOW), false);
|
||||
|
||||
machine.execute_instruction((instruction::LDA,
|
||||
instruction::UseImmediate(254)));
|
||||
machine.execute_instruction((instruction::LSR,
|
||||
instruction::UseImplied));
|
||||
machine.execute_instruction((Instruction::LDA,
|
||||
OpInput::UseImmediate(254)));
|
||||
machine.execute_instruction((Instruction::LSR,
|
||||
OpInput::UseImplied));
|
||||
assert_eq!(machine.registers.accumulator, 0x7F);
|
||||
assert_eq!(machine.registers.status.contains(PS_CARRY), false);
|
||||
assert_eq!(machine.registers.status.contains(PS_ZERO), false);
|
||||
@ -1018,11 +1018,11 @@ fn jump_test() {
|
||||
fn branch_if_carry_clear_test() {
|
||||
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));
|
||||
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));
|
||||
assert_eq!(machine.registers.program_counter, Address(0xABCD));
|
||||
}
|
||||
@ -1031,11 +1031,11 @@ fn branch_if_carry_clear_test() {
|
||||
fn branch_if_carry_set_test() {
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
fn compare_test_helper(
|
||||
compare: |&mut Machine, u8|,
|
||||
load_instruction: instruction::Instruction
|
||||
load_instruction: Instruction
|
||||
) {
|
||||
let mut machine = Machine::new();
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, instruction::UseImmediate(127))
|
||||
(load_instruction, OpInput::UseImmediate(127))
|
||||
);
|
||||
|
||||
compare(&mut machine, 127);
|
||||
@ -1130,7 +1131,7 @@ fn compare_test_helper(
|
||||
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, instruction::UseImmediate(127))
|
||||
(load_instruction, OpInput::UseImmediate(127))
|
||||
);
|
||||
|
||||
compare(&mut machine, 1);
|
||||
@ -1140,7 +1141,7 @@ fn compare_test_helper(
|
||||
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, instruction::UseImmediate(1))
|
||||
(load_instruction, OpInput::UseImmediate(1))
|
||||
);
|
||||
|
||||
compare(&mut machine, 2);
|
||||
@ -1150,7 +1151,7 @@ fn compare_test_helper(
|
||||
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, instruction::UseImmediate(20))
|
||||
(load_instruction, OpInput::UseImmediate(20))
|
||||
);
|
||||
|
||||
compare(&mut machine, -50);
|
||||
@ -1160,7 +1161,7 @@ fn compare_test_helper(
|
||||
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, instruction::UseImmediate(1))
|
||||
(load_instruction, OpInput::UseImmediate(1))
|
||||
);
|
||||
|
||||
compare(&mut machine, -1);
|
||||
@ -1170,7 +1171,7 @@ fn compare_test_helper(
|
||||
|
||||
|
||||
machine.execute_instruction(
|
||||
(load_instruction, instruction::UseImmediate(127))
|
||||
(load_instruction, OpInput::UseImmediate(127))
|
||||
);
|
||||
|
||||
compare(&mut machine, -128);
|
||||
@ -1185,7 +1186,7 @@ fn compare_with_a_register_test() {
|
||||
|machine: &mut Machine, val: u8| {
|
||||
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.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.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 val in range(0u8, 255u8) {
|
||||
machine.execute_instruction(
|
||||
(instruction::LDA, instruction::UseImmediate(a_before))
|
||||
(Instruction::LDA, OpInput::UseImmediate(a_before))
|
||||
);
|
||||
|
||||
machine.exclusive_or(val);
|
||||
|
Loading…
Reference in New Issue
Block a user