Adds (Indirect, X) addressing mode

master
Joey Pollack 2 years ago
parent 7021dd1e56
commit 93e16f0d02

@ -168,9 +168,34 @@ impl AddressingModes
ModeID::IND
}
// Indexed Indirect Addressing (IND, X)
// In indexed indirect addressing (referred to as (Indirect, X)), the second byte of the
// instruction is added to the contents of the X register, discarding the carry.
// The result of the addition points to a memory location on the Zero Page which contains
// the low order byte of the effective address. The next memory location in page zero,
// contains the high order byte of the effective address. Both memory locations specifying
// the effective address must be in the Zero Page.
//
// Info from:
// https://web.archive.org/web/20221112231348if_/http://archive.6502.org/datasheets/rockwell_r650x_r651x.pdf
pub fn IZX(cpu: &mut R6502, bus: &mut dyn Bus) -> ModeID
{
let offset = bus.read(cpu.pc) as u16;
cpu.pc += 1;
let mut pointer = cpu.x as u16 + offset;
// discard the carry and wrap
// If the addition goes beyond the Zero Page
// it should wrap around back to the beginning
pointer = pointer & 0x00FF;
let lo_byte = bus.read(pointer) as u16;
let hi_byte = bus.read(pointer + 1) as u16;
cpu.working_addr = (hi_byte << 0x08) | lo_byte;
cpu.working_data = bus.read(cpu.working_addr) as u16 & 0x00FF;
ModeID::IZX
}

@ -211,6 +211,43 @@ fn ABX()
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0A in the A register?
assert_eq!(0x0A, cpu.debug_get_reg(Registers::A));
}
#[test]
fn IZX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x04 into memory
bus.write(0x010C, 0x04);
// Manually put 0x010C into the Zero Page
bus.write(0x00B, 0x0C);
bus.write(0x00C, 0x01);
// ADC $10C
bus.write(addr, 0x61); // ADC - Indirect, X mode
bus.write(addr + 1, 0x0A); // Argument pointer into the Zero Page
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x06);
cpu.debug_set_reg(Registers::X, 0x01); // Zero Page pointer offset
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0A in the A register?
assert_eq!(0x0A, cpu.debug_get_reg(Registers::A));
}

@ -202,6 +202,44 @@ fn ABY()
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x02 in the A register?
assert_eq!(0x02, cpu.debug_get_reg(Registers::A));
}
#[test]
fn IZX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x0A into memory
bus.write(0x010C, 0x03);
// Manually put 0x010C into the Zero Page
bus.write(0x000B, 0x0C);
bus.write(0x000C, 0x01);
// AND #3
bus.write(addr, 0x21); // AND - Indirect, X mode
bus.write(addr + 1, 0x0A); // Argument - Pointer into the Zero Page
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x0A);
cpu.debug_set_reg(Registers::X, 0x01); // Zero Page pointer offset
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x02 in the A register?
assert_eq!(0x02, cpu.debug_get_reg(Registers::A));
}

@ -562,6 +562,109 @@ fn ABY()
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// C Z Flags should be 0, N Flag should be 1
assert_eq!(0, cpu.check_flag(Flags::C));
assert_eq!(0, cpu.check_flag(Flags::Z));
assert_eq!(1, cpu.check_flag(Flags::N));
}
//////////////////////////////////////////////////////////////////////////////
/// IZX IZX IZX IZX IZX IZX IZX IZX IZX
//////////////////////////////////////////////////////////////////////////////
#[test]
fn IZX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
///////////////////////
// Parameter is less than A reg
// Manually put 0x05 into memory
bus.write(0x010B, 0x05);
// Manually put 0x010B into the Zero Page
bus.write(0x000B, 0x0B);
bus.write(0x000C, 0x01);
// Program to compare 0x05 to 0x10
bus.write(addr, 0xC1); // CMP - Indirect, X mode
bus.write(addr + 1, 0x0A); // Argument lo word
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x01);
cpu.debug_set_reg(Registers::A, 0x10);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// C Flag should be 1, Z N Flags should be 0
assert_eq!(1, cpu.check_flag(Flags::C));
assert_eq!(0, cpu.check_flag(Flags::Z));
assert_eq!(0, cpu.check_flag(Flags::N));
///////////////////////
// Parameter is equal to the A reg
// Manually put 0x10 into memory
bus.write(0x010B, 0x10);
// Manually put 0x010B into the Zero Page
bus.write(0x000B, 0x0B);
bus.write(0x000C, 0x01);
// Program to compare 0x05 to 0x10
bus.write(addr, 0xC1); // CMP - Indirect, X mode
bus.write(addr + 1, 0x0A); // Argument lo word
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x01);
cpu.debug_set_reg(Registers::A, 0x10);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// C Z Flags should be 1, N Flag should be 0
assert_eq!(1, cpu.check_flag(Flags::C));
assert_eq!(1, cpu.check_flag(Flags::Z));
assert_eq!(0, cpu.check_flag(Flags::N));
///////////////////////
// Parameter is greater than A reg
// Manually put 0x05 into memory
bus.write(0x010B, 0x10);
// Program to compare 0x05 to 0x10
bus.write(addr, 0xC1); // CMP - Indirect, X mode
bus.write(addr + 1, 0x0A); // Argument lo word
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x01);
cpu.debug_set_reg(Registers::A, 0x05);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// C Z Flags should be 0, N Flag should be 1
assert_eq!(0, cpu.check_flag(Flags::C));
assert_eq!(0, cpu.check_flag(Flags::Z));

@ -202,6 +202,45 @@ fn ABY()
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x09 in the A register?
assert_eq!(0x09, cpu.debug_get_reg(Registers::A));
}
#[test]
fn IZX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x0A into memory in the zero page
bus.write(0x010C, 0x03);
// Manually put 0x010C in the Zero Page
bus.write(0x000B, 0x0C);
bus.write(0x000C, 0x01);
// AND #3
bus.write(addr, 0x41); // EOR - Indirect, X mode
bus.write(addr + 1, 0x0A); // Argument
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::A, 0x0A);
cpu.debug_set_reg(Registers::X, 0x01);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x09 in the A register?
assert_eq!(0x09, cpu.debug_get_reg(Registers::A));
}

@ -189,6 +189,43 @@ fn ABY()
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x08 in the A register?
assert_eq!(0x08, cpu.debug_get_reg(Registers::A));
}
#[test]
fn IZX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x08 into memory
bus.write(0x010B, 0x08);
// Manuall put 0x010B into the Zero page at 0x000A
bus.write(0x000A, 0x0B); // Pointer lo byte
bus.write(0x000B, 0x01); // Pointer hi byte
// Program to load 0x08 into the accumulator
bus.write(addr, 0xA1); // LDA - Indirect, X mode
bus.write(addr + 1, 0x09); // Argument - gets added to X reg
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x01);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x08 in the A register?
assert_eq!(0x08, cpu.debug_get_reg(Registers::A));
}

@ -218,6 +218,48 @@ fn ABY()
cpu.debug_set_reg(Registers::A, 0x09);
// Clock the cpu twice (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0B in the A register?
assert_eq!(0x0B, cpu.debug_get_reg(Registers::A));
}
#[test]
fn IZX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x02 into memory in the zero page
bus.write(0x010B, 0x02);
// Manually put 0x010B into the Zero Page
bus.write(0x000B, 0x0B);
bus.write(0x000C, 0x01);
// ORA #2
bus.write(addr, 0x01); // ORA - Indirect, X mode
bus.write(addr + 1, 0x0A); // Argument - Pointer to Zero Page
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x01); // Zero page pointer offset
cpu.debug_set_reg(Registers::A, 0x09);
// Clock the cpu twice (Clock essentially runs one full instruction)
cpu.clock(&mut bus);

@ -228,6 +228,48 @@ fn ABY()
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x04 in the A register?
assert_eq!(0x04, cpu.debug_get_reg(Registers::A));
}
//////////////////////////////////////////////////////////////////////////////
/// IZX IZX IZX IZX IZX IZX IZX IZX IZX
//////////////////////////////////////////////////////////////////////////////
#[test]
fn IZX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x08 into memory in the zero page
bus.write(0x010B, 0x06);
// Manually put 0x010B into the Zero page
bus.write(0x000B, 0x0B);
bus.write(0x000C, 0x01);
// Program to
bus.write(addr, 0xE1); // - Indirect, X mode
bus.write(addr + 1, 0x0A); // Argument - Pointer into the Zero Page
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x01); // Zero Page Pointer offset
cpu.debug_set_reg(Registers::A, 0x0A);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x04 in the A register?
assert_eq!(0x04, cpu.debug_get_reg(Registers::A));
}

@ -176,6 +176,47 @@ fn ABY()
cpu.debug_set_reg(Registers::A, 0x0F);
// Clock the cpu twice (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0F at memory address 0x010B?
assert_eq!(0x0F, bus.read(0x010B));
}
#[test]
fn IZX()
{
let mut cpu = R6502::new();
let mut bus = RAMBus::new();
// program address
let addr = 0x0020 as u16;
// Set the program counter address
bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte
bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte
// Manually put 0x02 into memory in the zero page
bus.write(0x010B, 0x02);
// Manuall put 0x010B into the Zero Page
bus.write(0x000B, 0x0B);
bus.write(0x000C, 0x01);
// STA
bus.write(addr, 0x81); // STA - Indirect, X mode
bus.write(addr + 1, 0x0A); // Argument - Pointer into the Zero page
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::X, 0x01); // Zero Page pointer offset
cpu.debug_set_reg(Registers::A, 0x0F);
// Clock the cpu twice (Clock essentially runs one full instruction)
cpu.clock(&mut bus);

Loading…
Cancel
Save