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");
|
let mut array: Box<[u8; SIZE_32KB]> = slice.try_into().expect("Unable to make rom in ram");
|
||||||
|
|
||||||
array[0] = 0xa9; // LDA #$ab
|
array[0] = 0xa9; // LDA #$ab
|
||||||
array[1] = 0xab;
|
array[1] = 0xab; // 1010 1011
|
||||||
|
|
||||||
// write the rom to disk
|
// write the rom to disk
|
||||||
fs::write("outputfile.bin", array.as_slice());
|
fs::write("outputfile.bin", array.as_slice());
|
||||||
|
|||||||
@ -166,7 +166,7 @@ impl Mos6502Cpu {
|
|||||||
let offset = self.pc as usize;
|
let offset = self.pc as usize;
|
||||||
// TODO: this calls opinfo 2x
|
// TODO: this calls opinfo 2x
|
||||||
self.oi = Instruction::opinfo(&self.memory[offset..offset + 4]).unwrap();
|
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;
|
self.microcode_step = self.oi.cycles;
|
||||||
println!("Decoded [[{:?}]]", self.ir);
|
println!("Decoded [[{:?}]]", self.ir);
|
||||||
self.advance_pc(self.oi.length as u16);
|
self.advance_pc(self.oi.length as u16);
|
||||||
@ -207,10 +207,10 @@ impl Mos6502Cpu {
|
|||||||
Operation::CPY => {}
|
Operation::CPY => {}
|
||||||
Operation::DEC => {}
|
Operation::DEC => {}
|
||||||
Operation::DEX => {
|
Operation::DEX => {
|
||||||
self.x -= 1;
|
(self.x, _) = self.x.overflowing_sub(1) ;
|
||||||
}
|
}
|
||||||
Operation::DEY => {
|
Operation::DEY => {
|
||||||
self.y -= 1;
|
(self.y, _) = self.y.overflowing_sub(1);
|
||||||
}
|
}
|
||||||
Operation::EOR => { }
|
Operation::EOR => { }
|
||||||
Operation::INC => { }
|
Operation::INC => { }
|
||||||
@ -234,13 +234,21 @@ impl Mos6502Cpu {
|
|||||||
AddressMode::Immediate => {
|
AddressMode::Immediate => {
|
||||||
match self.ir.operand {
|
match self.ir.operand {
|
||||||
Operand::Byte(value) => {
|
Operand::Byte(value) => {
|
||||||
println!("Loading {} into A", value);
|
println!("Loading 0x{value:02x} ({value}) into A");
|
||||||
self.a = value;
|
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::ZeroPageX => {}
|
||||||
AddressMode::ZeroPageY => {}
|
AddressMode::ZeroPageY => {}
|
||||||
AddressMode::Absolute => {}
|
AddressMode::Absolute => {}
|
||||||
@ -265,7 +273,9 @@ impl Mos6502Cpu {
|
|||||||
Operation::PHP => {}
|
Operation::PHP => {}
|
||||||
Operation::PLA => {}
|
Operation::PLA => {}
|
||||||
Operation::PLP => {}
|
Operation::PLP => {}
|
||||||
Operation::ROL => {}
|
Operation::ROL => {
|
||||||
|
self.a = self.a.rotate_left(1);
|
||||||
|
}
|
||||||
Operation::ROR => {
|
Operation::ROR => {
|
||||||
// rotate A
|
// rotate A
|
||||||
self.a = self.a.rotate_right(1);
|
self.a = self.a.rotate_right(1);
|
||||||
@ -280,9 +290,61 @@ impl Mos6502Cpu {
|
|||||||
self.flags.set_flag(Decimal);
|
self.flags.set_flag(Decimal);
|
||||||
}
|
}
|
||||||
Operation::SEI => {
|
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::STX => {}
|
||||||
Operation::STY => {}
|
Operation::STY => {}
|
||||||
Operation::TAX => {
|
Operation::TAX => {
|
||||||
@ -291,7 +353,8 @@ impl Mos6502Cpu {
|
|||||||
Operation::TAY => {
|
Operation::TAY => {
|
||||||
self.y = self.a;
|
self.y = self.a;
|
||||||
}
|
}
|
||||||
Operation::TSX => {}
|
Operation::TSX => {
|
||||||
|
}
|
||||||
Operation::TXA => {
|
Operation::TXA => {
|
||||||
self.a = self.x;
|
self.a = self.x;
|
||||||
}
|
}
|
||||||
@ -308,8 +371,8 @@ impl Mos6502Cpu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump(&self) {
|
pub fn dump(&self) {
|
||||||
println!("CPU State: PC: {:04x} / A: {:02x} / X: {:02x} / Y: {:02x} / ADDRESS: {:04x} / DATA: {:02x} / MICROSTEPS: {:02x}",
|
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.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) {
|
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,
|
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 {
|
impl Mos6502Flags {
|
||||||
|
|
||||||
pub fn set_flag(&mut self, flag_to_set: Mos6502Flag) {
|
pub fn set_flag(&mut self, flag_to_set: Mos6502Flag) {
|
||||||
|
|||||||
@ -38,7 +38,7 @@ impl RomChip for At28C256 {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::mos6502cpu::SIZE_1KB;
|
use crate::constants::constants_system::SIZE_1KB;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user