some instructions have code and tests
This commit is contained in:
parent
9e0e8b5910
commit
d97774e97b
@ -9,7 +9,7 @@ fn main() {
|
||||
let mut array: Box<[u8; SIZE_32KB]> = slice.try_into().expect("Unable to make rom in ram");
|
||||
|
||||
array[0] = 0xa9; // LDA #$ab
|
||||
array[1] = 0xab;
|
||||
array[1] = 0xab; // 1010 1011
|
||||
|
||||
// write the rom to disk
|
||||
fs::write("outputfile.bin", array.as_slice());
|
||||
|
||||
@ -166,7 +166,7 @@ impl Mos6502Cpu {
|
||||
let offset = self.pc as usize;
|
||||
// TODO: this calls opinfo 2x
|
||||
self.oi = Instruction::opinfo(&self.memory[offset..offset + 4]).unwrap();
|
||||
self.ir = Instruction::decode(&self.memory[offset..offset + 2]).unwrap();
|
||||
self.ir = Instruction::decode(&self.memory[offset..offset + 4]).unwrap();
|
||||
self.microcode_step = self.oi.cycles;
|
||||
println!("Decoded [[{:?}]]", self.ir);
|
||||
self.advance_pc(self.oi.length as u16);
|
||||
@ -207,10 +207,10 @@ impl Mos6502Cpu {
|
||||
Operation::CPY => {}
|
||||
Operation::DEC => {}
|
||||
Operation::DEX => {
|
||||
self.x -= 1;
|
||||
(self.x, _) = self.x.overflowing_sub(1) ;
|
||||
}
|
||||
Operation::DEY => {
|
||||
self.y -= 1;
|
||||
(self.y, _) = self.y.overflowing_sub(1);
|
||||
}
|
||||
Operation::EOR => { }
|
||||
Operation::INC => { }
|
||||
@ -234,13 +234,21 @@ impl Mos6502Cpu {
|
||||
AddressMode::Immediate => {
|
||||
match self.ir.operand {
|
||||
Operand::Byte(value) => {
|
||||
println!("Loading {} into A", value);
|
||||
println!("Loading 0x{value:02x} ({value}) into A");
|
||||
self.a = value;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
AddressMode::ZeroPage => {}
|
||||
AddressMode::ZeroPage => {
|
||||
match self.ir.operand {
|
||||
Operand::Byte(value) => {
|
||||
println!("Loading from zero page at 0x{value:02x} ({value})");
|
||||
self.a = self.memory[value as usize];
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
AddressMode::ZeroPageX => {}
|
||||
AddressMode::ZeroPageY => {}
|
||||
AddressMode::Absolute => {}
|
||||
@ -265,7 +273,9 @@ impl Mos6502Cpu {
|
||||
Operation::PHP => {}
|
||||
Operation::PLA => {}
|
||||
Operation::PLP => {}
|
||||
Operation::ROL => {}
|
||||
Operation::ROL => {
|
||||
self.a = self.a.rotate_left(1);
|
||||
}
|
||||
Operation::ROR => {
|
||||
// rotate A
|
||||
self.a = self.a.rotate_right(1);
|
||||
@ -280,9 +290,61 @@ impl Mos6502Cpu {
|
||||
self.flags.set_flag(Decimal);
|
||||
}
|
||||
Operation::SEI => {
|
||||
self.flags.set_flag(Mos6502Flag::Interrupt);
|
||||
self.flags.set_flag(Interrupt);
|
||||
}
|
||||
Operation::STA => {
|
||||
match self.oi.mode {
|
||||
AddressMode::ZeroPage => {
|
||||
// write to the zero page.
|
||||
match self.ir.operand {
|
||||
Operand::Byte(target) => {
|
||||
self.memory[target as usize] = self.a;
|
||||
}
|
||||
_ => {
|
||||
// Invalid parameter
|
||||
}
|
||||
}
|
||||
}
|
||||
AddressMode::ZeroPageX => {
|
||||
match self.ir.operand {
|
||||
Operand::Byte(target) => {
|
||||
let x = self.x;
|
||||
self.memory[(x + target) as usize] = self.a;
|
||||
}
|
||||
_ => {
|
||||
// Invalid Parameter
|
||||
}
|
||||
}
|
||||
}
|
||||
AddressMode::Absolute => {
|
||||
// write from A to the specified memory location
|
||||
match self.ir.operand {
|
||||
Operand::Word(offset) => {
|
||||
self.memory[offset as usize] = self.a;
|
||||
}
|
||||
_ => {
|
||||
// Invalid Parameter
|
||||
}
|
||||
}
|
||||
}
|
||||
AddressMode::AbsoluteX => {
|
||||
match self.ir.operand {
|
||||
Operand::Word(offset) => {
|
||||
self.memory[(offset + self.x as u16) as usize] = self.a;
|
||||
}
|
||||
_ => {
|
||||
// Invalid Parameter
|
||||
}
|
||||
}
|
||||
}
|
||||
AddressMode::AbsoluteY => {}
|
||||
AddressMode::IndirectX => {}
|
||||
AddressMode::IndirectY => {}
|
||||
_ => {
|
||||
// invalid memory mode
|
||||
}
|
||||
}
|
||||
}
|
||||
Operation::STA => {}
|
||||
Operation::STX => {}
|
||||
Operation::STY => {}
|
||||
Operation::TAX => {
|
||||
@ -291,7 +353,8 @@ impl Mos6502Cpu {
|
||||
Operation::TAY => {
|
||||
self.y = self.a;
|
||||
}
|
||||
Operation::TSX => {}
|
||||
Operation::TSX => {
|
||||
}
|
||||
Operation::TXA => {
|
||||
self.a = self.x;
|
||||
}
|
||||
@ -308,8 +371,8 @@ impl Mos6502Cpu {
|
||||
}
|
||||
|
||||
pub fn dump(&self) {
|
||||
println!("CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x} / MICROSTEPS: {:02x}",
|
||||
self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus, self.microcode_step);
|
||||
println!("CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x} / MICROSTEPS: {:02x} / S: {}",
|
||||
self.pc, self.a, self.x, self.y, self.address_bus, self.data_bus, self.microcode_step, self.flags.dump());
|
||||
}
|
||||
|
||||
pub fn dump_data(&self) -> ( u16, u8, u8, u8, u16, u8, u8) {
|
||||
@ -320,3 +383,101 @@ impl Mos6502Cpu {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::constants::constants_isa_op::*;
|
||||
use crate::instruction_table::INSTRUCTION_TABLE;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn clc() {
|
||||
// setup the CPU for our test
|
||||
let mut cpu = Mos6502Cpu::default();
|
||||
cpu.flags.set_flag(Carry);
|
||||
// Load our 'test program'
|
||||
cpu.memory[0x6000] = ISA_OP_CLC;
|
||||
// Start the PC at our program
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
// Tick the CPU through the instruction
|
||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_CLC as usize].unwrap().cycles { cpu.tick(); }
|
||||
|
||||
assert!(!cpu.peek_flag(Carry));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cld() {
|
||||
let mut cpu = Mos6502Cpu::default();
|
||||
cpu.flags.set_flag(Decimal);
|
||||
cpu.memory[0x6000] = ISA_OP_CLD;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_CLD as usize].unwrap().cycles { cpu.tick(); }
|
||||
|
||||
assert!(!cpu.peek_flag(Decimal));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cli() {
|
||||
let mut cpu = Mos6502Cpu::default();
|
||||
cpu.flags.set_flag(Interrupt);
|
||||
cpu.memory[0x6000] = ISA_OP_CLI;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_CLI as usize].unwrap().cycles { cpu.tick(); }
|
||||
|
||||
assert!(!cpu.peek_flag(Interrupt));
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clv() {
|
||||
let mut cpu = Mos6502Cpu::default();
|
||||
cpu.flags.set_flag(Overflow);
|
||||
cpu.memory[0x6000] = ISA_OP_CLV;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_CLV as usize].unwrap().cycles { cpu.tick(); }
|
||||
|
||||
assert!(!cpu.peek_flag(Overflow));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lda_immediate() {
|
||||
let mut cpu = Mos6502Cpu::default();
|
||||
cpu.memory[0x6000] = ISA_OP_LDA_I;
|
||||
cpu.memory[0x6001] = 0xab;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_LDA_I as usize].unwrap().cycles { cpu.tick(); }
|
||||
|
||||
assert_eq!(cpu.a, 0xab);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lda_zeropage() {
|
||||
let mut cpu = Mos6502Cpu::default();
|
||||
cpu.memory[0x6000] = ISA_OP_LDA_Z;
|
||||
cpu.memory[0x6001] = 0xab;
|
||||
cpu.memory[0x00ab] = 0xbe;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_LDA_Z as usize].unwrap().cycles + 1 { cpu.tick(); }
|
||||
|
||||
assert_eq!(cpu.a, 0xbe);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dex() {
|
||||
let mut cpu = Mos6502Cpu::default();
|
||||
cpu.a = 0xab;
|
||||
cpu.memory[0x6000] = ISA_OP_DEX;
|
||||
cpu.pc = 0x6000;
|
||||
|
||||
for _ in 0..INSTRUCTION_TABLE[ISA_OP_DEX as usize].unwrap().cycles { cpu.tick(); }
|
||||
|
||||
assert_eq!(0xaa, cpu.a);
|
||||
}
|
||||
}
|
||||
@ -20,6 +20,20 @@ pub struct Mos6502Flags {
|
||||
negative: bool,
|
||||
}
|
||||
|
||||
impl Mos6502Flags {
|
||||
pub fn dump(&self) -> String {
|
||||
format!("{}{}{}{}{}{}{}",
|
||||
if self.carry { 'C' } else { 'c' },
|
||||
if self.zero { 'Z' } else { 'z' },
|
||||
if self.interrupt { 'I' } else { 'i' },
|
||||
if self.decimal { 'D' } else { 'd' },
|
||||
if self.break_flag { 'B' } else { 'b' },
|
||||
if self.overflow { 'O' } else { 'o' },
|
||||
if self.negative { 'N' } else { 'n' }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Mos6502Flags {
|
||||
|
||||
pub fn set_flag(&mut self, flag_to_set: Mos6502Flag) {
|
||||
|
||||
@ -38,7 +38,7 @@ impl RomChip for At28C256 {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::mos6502cpu::SIZE_1KB;
|
||||
use crate::constants::constants_system::SIZE_1KB;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user