From ca699a78af63e1da1150bf82282c5cf4e0895108 Mon Sep 17 00:00:00 2001 From: Bradford Lamson-Scribner Date: Sun, 31 May 2020 09:59:58 -0600 Subject: [PATCH] internal/vm/{exec_funcs,opcodes,vm}: add support for executing LDX, LDY, and ADC --- internal/vm/exec_funcs.go | 85 +++++++++++++++++++++++++++++++-------- internal/vm/opcodes.go | 36 ++++++++--------- internal/vm/vm.go | 20 +++++++++ 3 files changed, 107 insertions(+), 34 deletions(-) diff --git a/internal/vm/exec_funcs.go b/internal/vm/exec_funcs.go index f736bef..31b3385 100644 --- a/internal/vm/exec_funcs.go +++ b/internal/vm/exec_funcs.go @@ -63,20 +63,18 @@ func execINC(a *Appleone, o op) error { // X + 1 -> X N Z C I D V // + + - - - - func execINX(a *Appleone, o op) error { - b := a.cpu.x + 1 - a.cpu.x = b - a.setZeroIfNeeded(b) - a.setNegativeIfOverflow(b) + a.cpu.x++ + a.setZeroIfNeeded(a.cpu.x) + a.setNegativeIfOverflow(a.cpu.x) return nil } // Y + 1 -> Y N Z C I D V // + + - - - - func execINY(a *Appleone, o op) error { - b := a.cpu.y + 1 - a.cpu.y = b - a.setZeroIfNeeded(b) - a.setNegativeIfOverflow(b) + a.cpu.y++ + a.setZeroIfNeeded(a.cpu.y) + a.setNegativeIfOverflow(a.cpu.y) return nil } @@ -101,20 +99,18 @@ func execTAY(a *Appleone, o op) error { // X - 1 -> X N Z C I D V // + + - - - - func execDEX(a *Appleone, o op) error { - b := a.cpu.x - 1 - a.cpu.x = b - a.setZeroIfNeeded(b) - a.setNegativeIfOverflow(b) + a.cpu.x-- + a.setZeroIfNeeded(a.cpu.x) + a.setNegativeIfOverflow(a.cpu.x) return nil } // Y - 1 -> Y N Z C I D V // + + - - - - func execDEY(a *Appleone, o op) error { - b := a.cpu.y - 1 - a.cpu.y = b - a.setZeroIfNeeded(b) - a.setNegativeIfOverflow(b) + a.cpu.y-- + a.setZeroIfNeeded(a.cpu.y) + a.setNegativeIfOverflow(a.cpu.y) return nil } @@ -126,5 +122,62 @@ func execLDA(a *Appleone, o op) error { return err } a.cpu.a = b + a.setZeroIfNeeded(a.cpu.a) + a.setNegativeIfOverflow(a.cpu.a) + return nil +} + +// M -> X N Z C I D V +// + + - - - - +func execLDX(a *Appleone, o op) error { + b, err := o.getData(a) + if err != nil { + return err + } + a.cpu.x = b + a.setZeroIfNeeded(a.cpu.x) + a.setNegativeIfOverflow(a.cpu.x) + return nil +} + +// M -> Y N Z C I D V +// + + - - - - +func execLDY(a *Appleone, o op) error { + b, err := o.getData(a) + if err != nil { + return err + } + a.cpu.y = b + a.setZeroIfNeeded(a.cpu.y) + a.setNegativeIfOverflow(a.cpu.y) + return nil +} + +// A + M + C -> A, C N Z C I D V +// + + + - - + +func execADC(a *Appleone, o op) error { + b, err := o.getData(a) + if err != nil { + return err + } + operand := uint16(b) + regA := uint16(a.cpu.a) + sum := regA + operand + uint16(a.getCarry()) + a.cpu.a = uint8(sum) + + a.clearCarry() + if sum > 255 { + a.setCarry() + } + + // http://www.righto.com/2012/12/the-6502-overflow-flag-explained.html + a.clearOverflow() + if (operand^sum)&(regA^sum)&0x80 != 0 { + a.setOverflow() + } + + a.setZeroIfNeeded(a.cpu.a) + a.setNegativeIfOverflow(a.cpu.a) + return nil } diff --git a/internal/vm/opcodes.go b/internal/vm/opcodes.go index 2b842c5..53a2c7d 100644 --- a/internal/vm/opcodes.go +++ b/internal/vm/opcodes.go @@ -184,11 +184,11 @@ var opcodes = map[uint8]op{ // zeropage,Y LDX oper,Y B6 2 4 // absolute LDX oper AE 3 4 // absolute,Y LDX oper,Y BE 3 4* - 0xA2: newOp("LDX", 0xA2, 2, immediate, todo), - 0xA6: newOp("LDX", 0xA6, 2, zeroPage, todo), - 0xB6: newOp("LDX", 0xB6, 2, zeroPageYIndexed, todo), - 0xAE: newOp("LDX", 0xAE, 3, absolute, todo), - 0xBE: newOp("LDX", 0xBE, 3, absoluteYIndexed, todo), + 0xA2: newOp("LDX", 0xA2, 2, immediate, execLDX), + 0xA6: newOp("LDX", 0xA6, 2, zeroPage, execLDX), + 0xB6: newOp("LDX", 0xB6, 2, zeroPageYIndexed, execLDX), + 0xAE: newOp("LDX", 0xAE, 3, absolute, execLDX), + 0xBE: newOp("LDX", 0xBE, 3, absoluteYIndexed, execLDX), // LDY Load Index Y with Memory // addressing assembler opc bytes cyles @@ -198,11 +198,11 @@ var opcodes = map[uint8]op{ // zeropage,X LDY oper,X B4 2 4 // absolute LDY oper AC 3 4 // absolute,X LDY oper,X BC 3 4* - 0xA0: newOp("LDY", 0xA0, 2, immediate, todo), - 0xA4: newOp("LDY", 0xA4, 2, zeroPage, todo), - 0xB4: newOp("LDY", 0xB4, 2, zeroPageXIndexed, todo), - 0xAC: newOp("LDY", 0xAC, 3, absolute, todo), - 0xBC: newOp("LDY", 0xBC, 3, absoluteXIndexed, todo), + 0xA0: newOp("LDY", 0xA0, 2, immediate, execLDY), + 0xA4: newOp("LDY", 0xA4, 2, zeroPage, execLDY), + 0xB4: newOp("LDY", 0xB4, 2, zeroPageXIndexed, execLDY), + 0xAC: newOp("LDY", 0xAC, 3, absolute, execLDY), + 0xBC: newOp("LDY", 0xBC, 3, absoluteXIndexed, execLDY), // ADC Add Memory to Accumulator with Carry // addressing assembler opc bytes cyles @@ -215,14 +215,14 @@ var opcodes = map[uint8]op{ // absolute,Y ADC oper,Y 79 3 4* // (indirect,X) ADC (oper,X) 61 2 6 // (indirect),Y ADC (oper),Y 71 2 5* - 0x69: newOp("ADC", 0x69, 2, immediate, todo), - 0x65: newOp("ADC", 0x65, 2, zeroPage, todo), - 0x75: newOp("ADC", 0x75, 2, zeroPageXIndexed, todo), - 0x6D: newOp("ADC", 0x6D, 3, absolute, todo), - 0x7D: newOp("ADC", 0x7D, 3, absoluteXIndexed, todo), - 0x79: newOp("ADC", 0x79, 3, absoluteYIndexed, todo), - 0x61: newOp("ADC", 0x61, 2, indirectXIndexed, todo), - 0x71: newOp("ADC", 0x71, 2, indirectYIndexed, todo), + 0x69: newOp("ADC", 0x69, 2, immediate, execADC), + 0x65: newOp("ADC", 0x65, 2, zeroPage, execADC), + 0x75: newOp("ADC", 0x75, 2, zeroPageXIndexed, execADC), + 0x6D: newOp("ADC", 0x6D, 3, absolute, execADC), + 0x7D: newOp("ADC", 0x7D, 3, absoluteXIndexed, execADC), + 0x79: newOp("ADC", 0x79, 3, absoluteYIndexed, execADC), + 0x61: newOp("ADC", 0x61, 2, indirectXIndexed, execADC), + 0x71: newOp("ADC", 0x71, 2, indirectYIndexed, execADC), // SBC Subtract Memory from Accumulator with Borrow // addressing assembler opc bytes cyles diff --git a/internal/vm/vm.go b/internal/vm/vm.go index e439a9d..2e98b07 100644 --- a/internal/vm/vm.go +++ b/internal/vm/vm.go @@ -106,3 +106,23 @@ func (a *Appleone) setNegative() { func (a *Appleone) clearNegative() { a.cpu.sp &^= flagZero } + +func (a *Appleone) getCarry() uint8 { + return a.cpu.sp & flagCarry +} + +func (a *Appleone) setCarry() { + a.cpu.sp |= flagCarry +} + +func (a *Appleone) clearCarry() { + a.cpu.sp &^= flagCarry +} + +func (a *Appleone) setOverflow() { + a.cpu.sp |= flagOverflow +} + +func (a *Appleone) clearOverflow() { + a.cpu.sp &^= flagOverflow +}