diff --git a/beneater/src/bin/make_rom.rs b/beneater/src/bin/make_rom.rs index cd2fb4d..5c2dba6 100644 --- a/beneater/src/bin/make_rom.rs +++ b/beneater/src/bin/make_rom.rs @@ -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()); diff --git a/core/src/mos6502cpu.rs b/core/src/mos6502cpu.rs index 6bbabcb..af3646d 100644 --- a/core/src/mos6502cpu.rs +++ b/core/src/mos6502cpu.rs @@ -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); + } +} \ No newline at end of file diff --git a/core/src/mos6502flags.rs b/core/src/mos6502flags.rs index d2bac36..815944b 100644 --- a/core/src/mos6502flags.rs +++ b/core/src/mos6502flags.rs @@ -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) { diff --git a/core/src/periph/at28c256.rs b/core/src/periph/at28c256.rs index 290009c..e84570e 100644 --- a/core/src/periph/at28c256.rs +++ b/core/src/periph/at28c256.rs @@ -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]