Adds the rest of group three instructions and begins work on branching

master
joeyrp 2 years ago
parent 03c0425165
commit b6029d0ef5

@ -152,11 +152,6 @@ impl AddressingModes
pub fn REL(cpu: &mut R6502, bus: &mut dyn Bus) -> ModeID pub fn REL(cpu: &mut R6502, bus: &mut dyn Bus) -> ModeID
{ {
// NOTE: Not sure if we can use the working_data variable for this.
// if any instruction using this address mode needs extra data read
// then we need another variable to store this address
//
// Use working_addr to just like the other modes
cpu.working_data = bus.read(cpu.pc) as u16; cpu.working_data = bus.read(cpu.pc) as u16;
cpu.pc += 1; cpu.pc += 1;

@ -53,6 +53,17 @@ impl Instructions
Instructions::CPY, // 110 CPY Instructions::CPY, // 110 CPY
Instructions::CPX, // 111 CPX Instructions::CPX, // 111 CPX
]; ];
pub const GROUP_BRANCHING_OPS: [fn(&mut R6502, &mut dyn Bus); 8] = [
Instructions::BPL,
Instructions::BMI,
Instructions::BVC,
Instructions::BVS,
Instructions::BCC,
Instructions::BCS,
Instructions::BNE,
Instructions::BEQ,
];
@ -474,26 +485,110 @@ impl Instructions
pub fn STY(cpu: &mut R6502, bus: &mut dyn Bus) pub fn STY(cpu: &mut R6502, bus: &mut dyn Bus)
{ {
bus.write(cpu.working_addr, cpu.y);
} }
pub fn LDY(cpu: &mut R6502, bus: &mut dyn Bus) pub fn LDY(cpu: &mut R6502, bus: &mut dyn Bus)
{ {
let data = cpu.working_data as u8;
cpu.y = data;
if cpu.y == 0
{
cpu.set_flag(Flags::Z);
}
if cpu.y & 0x80 != 0
{
cpu.set_flag(Flags::N);
}
} }
pub fn CPY(cpu: &mut R6502, bus: &mut dyn Bus) pub fn CPY(cpu: &mut R6502, bus: &mut dyn Bus)
{ {
cpu.clear_flag(Flags::C);
if cpu.y as u16 >= cpu.working_data
{
cpu.set_flag(Flags::C);
}
cpu.clear_flag(Flags::Z);
if cpu.y == cpu.working_data as u8
{
cpu.set_flag(Flags::Z);
}
cpu.clear_flag(Flags::N);
if (cpu.y as u16 - cpu.working_data) & 0x80 > 0
{
cpu.set_flag(Flags::N);
}
} }
pub fn CPX(cpu: &mut R6502, bus: &mut dyn Bus) pub fn CPX(cpu: &mut R6502, bus: &mut dyn Bus)
{ {
cpu.clear_flag(Flags::C);
if cpu.x as u16 >= cpu.working_data
{
cpu.set_flag(Flags::C);
}
cpu.clear_flag(Flags::Z);
if cpu.x == cpu.working_data as u8
{
cpu.set_flag(Flags::Z);
}
cpu.clear_flag(Flags::N);
if (cpu.x as u16 - cpu.working_data) & 0x80 > 0
{
cpu.set_flag(Flags::N);
}
} }
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// BRANCHING // BRANCHING
fn BPL(cpu: &mut R6502, bus: &mut dyn Bus)
{
}
fn BMI(cpu: &mut R6502, bus: &mut dyn Bus)
{
}
fn BVC(cpu: &mut R6502, bus: &mut dyn Bus)
{
}
fn BVS(cpu: &mut R6502, bus: &mut dyn Bus)
{
}
fn BCC(cpu: &mut R6502, bus: &mut dyn Bus)
{
}
fn BCS(cpu: &mut R6502, bus: &mut dyn Bus)
{
}
fn BNE(cpu: &mut R6502, bus: &mut dyn Bus)
{
}
fn BEQ(cpu: &mut R6502, bus: &mut dyn Bus)
{
}
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////

@ -175,15 +175,32 @@ fn execute(instruction: u8, cpu: &mut R6502, bus: &mut dyn Bus)
{ {
// Instruction decoding: // Instruction decoding:
// https://llx.com/Neil/a2/opcodes.html // https://llx.com/Neil/a2/opcodes.html
// Check if this is a branch instruction
// The conditional branch instructions all have the form xxy10000
// 0x1F == 11111
// 0x10 == 10000
const BRANCH_OP: u8 = 0x10;
const BRANCH_MASK: u8 = 0x1F;
if instruction & BRANCH_MASK == BRANCH_OP
{
exe_branch(instruction, cpu, bus);
return;
}
// Single byte instructions
// Instructions with arguments
const GROUP_ONE_OP: u8 = 0x01;
const GROUP_TWO_OP: u8 = 0x02;
const GROUP_THREE_OP: u8 = 0x00;
let group_code = instruction & 0x03; // group one has a bit pattern of xxxxxx01 let group_code = instruction & 0x03; // group one has a bit pattern of xxxxxx01
match group_code match group_code
{ {
0x01 => exe_group_one(instruction, cpu, bus), GROUP_ONE_OP => exe_group_one(instruction, cpu, bus),
0x02 => exe_group_two(instruction, cpu, bus), GROUP_TWO_OP => exe_group_two(instruction, cpu, bus),
0x00 => exe_group_three(instruction, cpu, bus), GROUP_THREE_OP => exe_group_three(instruction, cpu, bus),
// TODO: Conditionals and specially formatted instructions
_ => panic!("UNKNOWN INSTRUCTION ADDRESS MODE: {}", group_code) _ => panic!("UNKNOWN INSTRUCTION ADDRESS MODE: {}", group_code)
} }
@ -255,4 +272,15 @@ fn exe_group_three(instruction: u8, cpu: &mut R6502, bus: &mut dyn Bus)
} }
Instructions::GROUP_THREE_OPS[op_mask as usize](cpu, bus); Instructions::GROUP_THREE_OPS[op_mask as usize](cpu, bus);
}
fn exe_branch(instruction: u8, cpu: &mut R6502, bus: &mut dyn Bus)
{
let pc_offset = AddressingModes::REL(cpu, bus);
// TODO: Decode instruction
// Need to map: 10 30 50 70 90 B0 D0 F0 - op code
// to: 0 1 2 3 4 5 6 7 - method index
// ChatGPT says: Index = (Value16) / 32
} }

@ -534,4 +534,127 @@ fn JMP()
// Is the program counter now 0x1234? // Is the program counter now 0x1234?
assert_eq!(0x1234, cpu.debug_get_reg(Registers::PC)); assert_eq!(0x1234, cpu.debug_get_reg(Registers::PC));
}
#[test]
fn STY()
{
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
// STY $0A
bus.write(addr, 0x84); // STY - Zero Page mode
bus.write(addr + 1, 0x0A); // Argument
// Restart cpu
cpu.reset(&mut bus);
// manually setup the cpu registers
cpu.debug_set_reg(Registers::Y, 0x0F);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x0F at memory address 0x0A?
assert_eq!(0x0F, bus.read(0x0A));
}
#[test]
fn LDY()
{
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
// Program to load 0x08 into the Y Register
bus.write(addr, 0xA0); // LDY - Immediate mode
bus.write(addr + 1, 0x08); // Argument
// Restart cpu
cpu.reset(&mut bus);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is 0x08 in the Y register?
assert_eq!(0x08, cpu.debug_get_reg(Registers::Y));
}
#[test]
fn CPY()
{
// TODO: More tests for CPY and CPX
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
// Program to compare 0x10 and 0x10
bus.write(addr, 0xC0); // CPY - Immediate mode
bus.write(addr + 1, 0x10); // Argument
// Restart cpu
cpu.reset(&mut bus);
// Preload the Y register with value 0x10
cpu.debug_set_reg(Registers::Y, 0x10);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is the Z flag set?
assert_eq!(1, cpu.check_flag(Flags::Z));
}
#[test]
fn CPX()
{
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
// Program to compare 0x10 and 0x10
bus.write(addr, 0xE0); // CPX - Immediate mode
bus.write(addr + 1, 0x10); // Argument
// Restart cpu
cpu.reset(&mut bus);
// Preload the X register with value 0x10
cpu.debug_set_reg(Registers::X, 0x10);
// Clock the cpu to run the program (Clock essentially runs one full instruction)
cpu.clock(&mut bus);
// Is the Z flag set?
assert_eq!(1, cpu.check_flag(Flags::Z));
} }

@ -24,9 +24,9 @@ Addressing modes:
✔ ABS - Absolute @done(23-11-07 20:25) ✔ ABS - Absolute @done(23-11-07 20:25)
✔ ABX - Absolute, X @done(23-11-07 20:25) ✔ ABX - Absolute, X @done(23-11-07 20:25)
✔ ABY - Absolute, Y @done(23-11-07 20:25) ✔ ABY - Absolute, Y @done(23-11-07 20:25)
☐ IND - Indirect ✔ IND - Indirect @done(24-01-10 15:26)
☐ IZX - Indirect, X ✔ IZX - Indirect, X @done(24-01-10 15:26)
☐ IZY - Indirect, Y ✔ IZY - Indirect, Y @done(24-01-10 15:26)
Instructions: Instructions:
GROUP ONE: GROUP ONE:
@ -53,10 +53,10 @@ Instructions:
✔ 001 BIT @done(24-01-09 16:16) ✔ 001 BIT @done(24-01-09 16:16)
✔ 010 JMP @done(24-01-09 16:16) ✔ 010 JMP @done(24-01-09 16:16)
✔ 011 JMP (abs) @done(24-01-09 16:16) ✔ 011 JMP (abs) @done(24-01-09 16:16)
☐ 100 STY ✔ 100 STY @done(24-01-10 14:10)
☐ 101 LDY ✔ 101 LDY @done(24-01-10 14:10)
☐ 110 CPY ✔ 110 CPY @done(24-01-10 15:26)
☐ 111 CPX ✔ 111 CPX @done(24-01-10 15:26)
CONDITIONALS: CONDITIONALS:
☐ 10 BPL ☐ 10 BPL

Loading…
Cancel
Save