All instructions implemented NOT TESTED

master
Joey Pollack 2 years ago
parent a07b784e5b
commit 48bfaf500a

@ -2,7 +2,8 @@
#![allow(dead_code, non_snake_case)] #![allow(dead_code, non_snake_case)]
use super::{R6502, Bus, Flags, addressing_modes::{AddressingModes, ModeID}}; use super::{R6502, Bus, Flags, addressing_modes::ModeID, stack_push, stack_pop};
//use super::{R6502, Bus, Flags, addressing_modes::{AddressingModes, ModeID}};
// Instruction decoding: // Instruction decoding:
// https://llx.com/Neil/a2/opcodes.html // https://llx.com/Neil/a2/opcodes.html
@ -65,6 +66,40 @@ impl Instructions
Instructions::BEQ, Instructions::BEQ,
]; ];
pub const GROUP_IRP_OPS: [fn(&mut R6502, &mut dyn Bus); 4] = [
Instructions::BRK,
Instructions::JSR,
Instructions::RTI,
Instructions::RTS,
];
pub const GROUP_SB1_OPS: [fn(&mut R6502, &mut dyn Bus); 16] = [
Instructions::PHP,
Instructions::CLC,
Instructions::PLP,
Instructions::SEC,
Instructions::PHA,
Instructions::CLI,
Instructions::PLA,
Instructions::SEI,
Instructions::DEY,
Instructions::TYA,
Instructions::TAY,
Instructions::CLV,
Instructions::INY,
Instructions::CLD,
Instructions::INX,
Instructions::SED,
];
pub const GROUP_SB2_OPS: [fn(&mut R6502, &mut dyn Bus); 6] = [
Instructions::TXA,
Instructions::TXS,
Instructions::TAX,
Instructions::TSX,
Instructions::DEX,
Instructions::NOP,
];
} }
@ -79,6 +114,8 @@ impl Instructions
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// GROUP ONE // GROUP ONE
///////////////////////////////////////////////////////////
pub fn ORA(cpu: &mut R6502, _bus: &mut dyn Bus) pub fn ORA(cpu: &mut R6502, _bus: &mut dyn Bus)
{ {
let data = cpu.working_data as u8; let data = cpu.working_data as u8;
@ -255,6 +292,8 @@ impl Instructions
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// GROUP TWO // GROUP TWO
///////////////////////////////////////////////////////////
pub fn ASL(cpu: &mut R6502, bus: &mut dyn Bus) pub fn ASL(cpu: &mut R6502, bus: &mut dyn Bus)
{ {
cpu.clear_flag(Flags::C); cpu.clear_flag(Flags::C);
@ -450,6 +489,8 @@ impl Instructions
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// GROUP THREE // GROUP THREE
///////////////////////////////////////////////////////////
pub fn BIT(cpu: &mut R6502, bus: &mut dyn Bus) pub fn BIT(cpu: &mut R6502, bus: &mut dyn Bus)
{ {
cpu.set_flag(Flags::Z); cpu.set_flag(Flags::Z);
@ -549,6 +590,8 @@ impl Instructions
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// BRANCHING // BRANCHING
///////////////////////////////////////////////////////////
fn BPL(cpu: &mut R6502, bus: &mut dyn Bus) fn BPL(cpu: &mut R6502, bus: &mut dyn Bus)
{ {
if cpu.check_flag(Flags::N) == 0 if cpu.check_flag(Flags::N) == 0
@ -615,8 +658,187 @@ impl Instructions
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// INTERRUPT AND SUBROUTINE // INTERRUPT AND SUBROUTINE
///////////////////////////////////////////////////////////
pub fn BRK(cpu: &mut R6502, bus: &mut dyn Bus)
{
let pc_hi = ((cpu.pc & 0xFF00) >> 8) as u8;
let pc_lo = (cpu.pc & 0x00FF) as u8;
stack_push(pc_hi, cpu, bus, );
stack_push(pc_lo, cpu, bus, );
stack_push(cpu.status, cpu, bus);
let addr_hi = bus.read(0xFFFE);
let addr_lo = bus.read(0xFFFF);
cpu.pc = ((addr_hi as u16) << 8) | (addr_lo as u16);
cpu.set_flag(Flags::B);
}
pub fn JSR(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.pc -= 1;
let pc_hi = ((cpu.pc & 0xFF00) >> 8) as u8;
let pc_lo = (cpu.pc & 0x00FF) as u8;
stack_push(pc_hi, cpu, bus);
stack_push(pc_lo, cpu, bus);
// NOTE: Not 100% sure this is the address and not
// the address of the address (i.e. working_data).
cpu.pc = cpu.working_addr;
}
pub fn RTI(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.status = stack_pop(cpu, bus);
let pc_lo = stack_pop(cpu, bus) as u16;
let pc_hi = stack_pop(cpu, bus) as u16;
cpu.pc = (pc_hi << 8) | pc_lo;
}
pub fn RTS(cpu: &mut R6502, bus: &mut dyn Bus)
{
let pc_lo = stack_pop(cpu, bus) as u16;
let pc_hi = stack_pop(cpu, bus) as u16;
cpu.pc = (pc_hi << 8) | pc_lo;
cpu.pc += 1;
}
/////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////
// SINGLE BYTE // SINGLE BYTE
pub fn PHP(cpu: &mut R6502, bus: &mut dyn Bus)
{
stack_push(cpu.status, cpu, bus);
}
pub fn CLC(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.clear_flag(Flags::C);
}
pub fn PLP(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.status = stack_pop(cpu, bus);
}
pub fn SEC(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.set_flag(Flags::C);
}
pub fn PHA(cpu: &mut R6502, bus: &mut dyn Bus)
{
stack_push(cpu.a, cpu, bus);
}
pub fn CLI(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.clear_flag(Flags::I);
}
pub fn PLA(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.a = stack_pop(cpu, bus);
cpu.set_zn_flags(cpu.a);
}
pub fn SEI(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.set_flag(Flags::I);
}
pub fn DEY(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.y -= 1;
cpu.set_zn_flags(cpu.y);
}
pub fn TYA(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.a = cpu.y;
cpu.set_zn_flags(cpu.a);
}
pub fn TAY(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.y = cpu.a;
cpu.set_zn_flags(cpu.y);
}
pub fn CLV(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.clear_flag(Flags::V);
}
pub fn INY(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.y += 1;
cpu.set_zn_flags(cpu.y);
}
pub fn CLD(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.clear_flag(Flags::D);
}
pub fn INX(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.x += 1;
cpu.set_zn_flags(cpu.x);
}
pub fn SED(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.set_flag(Flags::D);
}
pub fn TXA(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.a = cpu.x;
cpu.set_zn_flags(cpu.a);
}
pub fn TXS(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.sp = (cpu.x as u16) + 0x100;
}
pub fn TAX(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.x = cpu.a;
cpu.set_zn_flags(cpu.x);
}
pub fn TSX(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.x = (cpu.sp - 0x100) as u8;
}
pub fn DEX(cpu: &mut R6502, bus: &mut dyn Bus)
{
cpu.x -= 1;
cpu.set_zn_flags(cpu.x);
}
pub fn NOP(cpu: &mut R6502, bus: &mut dyn Bus)
{
}
} }

@ -110,6 +110,8 @@ impl R6502
self.pc += 1; self.pc += 1;
execute(opcode, self, bus); execute(opcode, self, bus);
// Addressing modes increment pc instead
//self.pc += 1; //self.pc += 1;
//} //}
@ -139,15 +141,55 @@ impl R6502
pub fn irq(&mut self, bus: &mut impl Bus) pub fn irq(&mut self, bus: &mut impl Bus)
{ {
if self.check_flag(Flags::I) != 0
{
return;
}
let pc_hi = ((self.pc & 0xFF00) >> 8) as u8;
let pc_lo = (self.pc & 0x00FF) as u8;
stack_push(pc_hi, self, bus, );
stack_push(pc_lo, self, bus, );
stack_push(self.status, self, bus);
self.set_flag(Flags::I);
let addr_lo = bus.read(0xFFFE) as u16;
let addr_hi = bus.read(0xFFFF) as u16;
self.pc = (addr_hi >> 8) | addr_lo;
} }
pub fn nmi(&mut self, bus: &mut impl Bus) pub fn nmi(&mut self, bus: &mut impl Bus)
{ {
let pc_hi = ((self.pc & 0xFF00) >> 8) as u8;
let pc_lo = (self.pc & 0x00FF) as u8;
stack_push(pc_hi, self, bus, );
stack_push(pc_lo, self, bus, );
stack_push(self.status, self, bus);
let addr_lo = bus.read(0xFFFA) as u16;
let addr_hi = bus.read(0xFFFB) as u16;
self.pc = (addr_hi >> 8) | addr_lo;
} }
// helpers // helpers
pub fn set_zn_flags(&mut self, val: u8)
{
self.clear_flag(Flags::Z);
if val == 0
{
self.set_flag(Flags::Z);
}
self.clear_flag(Flags::N);
if val & 0x80 != 0
{
self.set_flag(Flags::N);
}
}
pub fn set_flag(&mut self, bit: Flags) pub fn set_flag(&mut self, bit: Flags)
{ {
self.status |= bit as u8; self.status |= bit as u8;
@ -170,14 +212,14 @@ impl R6502
} }
fn stack_push(value: u8, cpu: &mut R6502, bus: &mut dyn Bus) pub(crate) fn stack_push(value: u8, cpu: &mut R6502, bus: &mut dyn Bus)
{ {
// TODO: Check for out of bounds errors // TODO: Check for out of bounds errors
bus.write(cpu.sp, value); bus.write(cpu.sp, value);
cpu.sp -= 1; cpu.sp -= 1;
} }
fn stack_pop(cpu: &mut R6502, bus: &mut dyn Bus) -> u8 pub(crate) fn stack_pop(cpu: &mut R6502, bus: &mut dyn Bus) -> u8
{ {
cpu.sp += 1; cpu.sp += 1;
bus.read(cpu.sp) bus.read(cpu.sp)
@ -202,8 +244,26 @@ fn execute(instruction: u8, cpu: &mut R6502, bus: &mut dyn Bus)
} }
// Interrupt and Subroutine // Interrupt and Subroutine
const BRK: u8 = 0x00;
const JSR: u8 = 0x20;
const RTI: u8 = 0x40;
const RTS: u8 = 0x60;
match instruction
{
BRK => {Instructions::BRK(cpu, bus); return; }
JSR => {Instructions::JSR(cpu, bus); return; }
RTI => {Instructions::RTI(cpu, bus); return; }
RTS => {Instructions::RTS(cpu, bus); return; }
_ => ()
}
// Single byte instructions // Single byte instructions
if exe_single_byte(instruction, cpu, bus)
{
return;
}
// Instructions with arguments // Instructions with arguments
const GROUP_ONE_OP: u8 = 0x01; const GROUP_ONE_OP: u8 = 0x01;
@ -217,8 +277,10 @@ fn execute(instruction: u8, cpu: &mut R6502, bus: &mut dyn Bus)
GROUP_TWO_OP => exe_group_two(instruction, cpu, bus), GROUP_TWO_OP => exe_group_two(instruction, cpu, bus),
GROUP_THREE_OP => exe_group_three(instruction, cpu, bus), GROUP_THREE_OP => exe_group_three(instruction, cpu, bus),
_ => panic!("UNKNOWN INSTRUCTION ADDRESS MODE: {}", group_code) _ => panic!("UNKNOWN INSTRUCTION: {:#02X}", instruction)
} }
} }
fn exe_group_one(instruction: u8, cpu: &mut R6502, bus: &mut dyn Bus) fn exe_group_one(instruction: u8, cpu: &mut R6502, bus: &mut dyn Bus)
@ -303,3 +365,38 @@ fn exe_branch(instruction: u8, cpu: &mut R6502, bus: &mut dyn Bus)
Instructions::GROUP_BRANCHING_OPS[idx](cpu, bus); Instructions::GROUP_BRANCHING_OPS[idx](cpu, bus);
} }
// Returns true if the insruction was handled
fn exe_single_byte(instruction: u8, cpu: &mut R6502, bus: &mut dyn Bus) -> bool
{
// Group of 8's
// PHP CLC PLP SEC PHA CLI PLA SEI DEY TYA TAY CLV INY CLD INX SED
// 08 18 28 38 48 58 68 78 88 98 A8 B8 C8 D8 E8 F8
// Index = (Value-8) / 16
const EIGHT_MASK: u8 = 0x0F;
if instruction & EIGHT_MASK == 0x08
{
let i = ((instruction - 0x08) / 0x10) as usize;
Instructions::GROUP_SB1_OPS[i](cpu, bus);
return true;
}
// Group of A's
// TXA TXS TAX TSX DEX NOP
// 8A 9A AA BA CA EA
// Index = (Value-8A) / 16
if instruction < 0x8A
{
return false;
}
const A_MASK: u8 = 0x05;
if instruction & A_MASK == 0xA
{
let i = ((instruction - 0x8A) / 0x10) as usize;
Instructions::GROUP_SB2_OPS[i](cpu, bus);
return true;
}
false
}
Loading…
Cancel
Save