From 99ff781d3df0c2b6a3e632585d393ea7d16e2953 Mon Sep 17 00:00:00 2001 From: Joey Pollack Date: Mon, 6 Nov 2023 19:58:26 -0500 Subject: [PATCH] simple addition working --- src/main.rs | 62 ++++++++++++++++++++++++++++++---- src/r6502/LICENSE | 37 ++++++++++++++++++++ src/r6502/addressing_modes.rs | 3 ++ src/r6502/instructions.rs | 63 +++++++++++++++++++++++++++-------- src/r6502/mod.rs | 4 ++- todo/todo.todo | 2 ++ 6 files changed, 150 insertions(+), 21 deletions(-) create mode 100644 src/r6502/LICENSE diff --git a/src/main.rs b/src/main.rs index e99ff6b..08ad611 100644 --- a/src/main.rs +++ b/src/main.rs @@ -42,11 +42,63 @@ fn main() cpu.clear_flag(Flags::I); println!("\nI Flag is: {}", cpu.check_flag(Flags::I)); + // run_simple_or_program(&mut cpu); + run_addition_test(&mut cpu); + + println!("\nFinished."); +} + +fn run_addition_test(cpu: &mut R6502) +{ + println!("\nRunning a simple addition test with no overflow or carry: 8 + 23"); + + ////////////////////////////////// + // Setup Bus with program address + ////////////////////////////////// + + 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 + + /////////////////////////////// + // write the program to memory + ////////////////////////////// + + // LDA #8 + bus.write(addr, 0xA9); // LDA - Immediate mode + bus.write(addr + 1, 0x08); // Argument + + // ADC #17 [23 dec] + bus.write(addr + 2, 0x69); // ADC - Immediate mode + bus.write(addr + 3, 0x17); // Argument + + //////////////////// + // Run the program! + //////////////////// + + // Restart cpu + cpu.reset(&mut bus); + + // Clock the cpu twice (Clock essentially runs one full instruction) + cpu.clock(&mut bus); + cpu.clock(&mut bus); + + println!("\nProgram result, A register: {}", cpu.a); + +} + +fn run_simple_or_program(cpu: &mut R6502) +{ println!("\nRunning a very simple test program:\n\tLDA #9\n\tORA #2\n Result should be 11 in the A register"); - ////////////////////////// - // Setup Bus with program - ////////////////////////// + ////////////////////////////////// + // Setup Bus with program address + ////////////////////////////////// let mut bus = RAMBus::new(); @@ -81,6 +133,4 @@ fn main() cpu.clock(&mut bus); println!("\nProgram result, A register: {}", cpu.a); - - println!("\nFinished."); -} +} \ No newline at end of file diff --git a/src/r6502/LICENSE b/src/r6502/LICENSE new file mode 100644 index 0000000..baf519e --- /dev/null +++ b/src/r6502/LICENSE @@ -0,0 +1,37 @@ + + +The code in the methods r6502::instructions::ADC and r6502::instructions::SDC +is adapted from code written by javidx9 (David Barr) and is subject to the following license: + + License (OLC-3) + ~~~~~~~~~~~~~~~ + + Copyright 2018-2019 OneLoneCoder.com + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions or derivations of source code must retain the above + copyright notice, this list of conditions and the following disclaimer. + + 2. Redistributions or derivative works in binary form must reproduce + the above copyright notice. This list of conditions and the following + disclaimer must be reproduced in the documentation and/or other + materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/src/r6502/addressing_modes.rs b/src/r6502/addressing_modes.rs index 3b0f86b..ea6f6c0 100644 --- a/src/r6502/addressing_modes.rs +++ b/src/r6502/addressing_modes.rs @@ -3,6 +3,8 @@ use super::{R6502, Bus}; +// Instruction decoding: +// https://llx.com/Neil/a2/opcodes.html // GROUP ONE ADDRESS MODES // 000 (zero page,X) IZX @@ -38,6 +40,7 @@ impl AddressingModes } + impl AddressingModes { // This is also the accumulator mode diff --git a/src/r6502/instructions.rs b/src/r6502/instructions.rs index e8bd287..033f201 100644 --- a/src/r6502/instructions.rs +++ b/src/r6502/instructions.rs @@ -4,20 +4,8 @@ use super::{R6502, Bus, Flags}; -// uint8_t ADC(); uint8_t AND(); uint8_t ASL(); uint8_t BCC(); -// uint8_t BCS(); uint8_t BEQ(); uint8_t BIT(); uint8_t BMI(); -// uint8_t BNE(); uint8_t BPL(); uint8_t BRK(); uint8_t BVC(); -// uint8_t BVS(); uint8_t CLC(); uint8_t CLD(); uint8_t CLI(); -// uint8_t CLV(); uint8_t CMP(); uint8_t CPX(); uint8_t CPY(); -// uint8_t DEC(); uint8_t DEX(); uint8_t DEY(); uint8_t EOR(); -// uint8_t INC(); uint8_t INX(); uint8_t INY(); uint8_t JMP(); -// uint8_t JSR(); uint8_t LDA(); uint8_t LDX(); uint8_t LDY(); -// uint8_t LSR(); uint8_t NOP(); uint8_t ORA(); uint8_t PHA(); -// uint8_t PHP(); uint8_t PLA(); uint8_t PLP(); uint8_t ROL(); -// uint8_t ROR(); uint8_t RTI(); uint8_t RTS(); uint8_t SBC(); -// uint8_t SEC(); uint8_t SED(); uint8_t SEI(); uint8_t STA(); -// uint8_t STX(); uint8_t STY(); uint8_t TAX(); uint8_t TAY(); -// uint8_t TSX(); uint8_t TXA(); uint8_t TXS(); uint8_t TYA(); +// Instruction decoding: +// https://llx.com/Neil/a2/opcodes.html // GROUP ONE // 000 ORA @@ -65,17 +53,64 @@ impl Instructions pub fn AND(cpu: &mut R6502, bus: &mut dyn Bus) { + cpu.a = cpu.a & cpu.working_data; + if cpu.a == 0 + { + cpu.set_flag(Flags::Z); + } + if cpu.a & 0x80 != 0 + { + cpu.set_flag(Flags::N); + } } pub fn EOR(cpu: &mut R6502, bus: &mut dyn Bus) { + cpu.a = cpu.a ^ cpu.working_data; + if cpu.a == 0 + { + cpu.set_flag(Flags::Z); + } + if cpu.a & 0x80 != 0 + { + cpu.set_flag(Flags::N); + } } + // Using a technique written javidx9 + // The code in this function falls under the License (OLC-3) SEE LICENSE FILE + // https://github.com/OneLoneCoder/olcNES/blob/master/Part%232%20-%20CPU/olc6502.cpp#L659 pub fn ADC(cpu: &mut R6502, bus: &mut dyn Bus) { + // 16 bit addition to capture the carry easier + let temp: u16 = cpu.a as u16 + cpu.working_data as u16; + + if temp > 255 + { + cpu.set_flag(Flags::C); + } + + if temp == 0 + { + cpu.set_flag(Flags::Z); + } + + let did_overflow = (!((cpu.a as u16) ^ (cpu.working_data as u16)) & ((cpu.a as u16) ^ temp)) & 0x0080; + cpu.clear_flag(Flags::V); + if did_overflow > 0 + { + cpu.set_flag(Flags::V); + } + + cpu.clear_flag(Flags::N); + if temp & 0x80 > 0 + { + cpu.set_flag(Flags::N); + } + cpu.a = (temp & 0x00FF) as u8; } pub fn STA(cpu: &mut R6502, bus: &mut dyn Bus) diff --git a/src/r6502/mod.rs b/src/r6502/mod.rs index 7ed51bf..141b97f 100644 --- a/src/r6502/mod.rs +++ b/src/r6502/mod.rs @@ -127,7 +127,9 @@ impl R6502 fn execute(instruction: u8, cpu: &mut R6502, bus: &mut dyn Bus) { - + // Instruction decoding: + // https://llx.com/Neil/a2/opcodes.html + let group_code = instruction & 0x03; // group one has a bit pattern of xxxxxx01 match group_code { diff --git a/todo/todo.todo b/todo/todo.todo index 9e3671d..d725a28 100644 --- a/todo/todo.todo +++ b/todo/todo.todo @@ -1,6 +1,8 @@ General: ☐ Fully implement clock cycle tracking + ☐ Add a disassembler for debugging + ☐ Debug data lookup for instructions Addressing modes: ☐ IMP - Implied