From 67416900b444ae2748afcd2d14ee47957cbbdc9f Mon Sep 17 00:00:00 2001 From: Bradford Lamson-Scribner Date: Thu, 4 Jun 2020 20:47:35 -0600 Subject: [PATCH] =?UTF-8?q?internal/vm:=20update=20Appleone=20and=20all=20?= =?UTF-8?q?it=E2=80=99s=20`a`=20handlers=20to=20VM=20with=20`vm`=20handler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...{exec_funcs.go => instruction_handlers.go} | 474 +++++++++--------- internal/vm/opcodes.go | 4 +- internal/vm/vm.go | 202 +++++--- main.go | 8 +- 4 files changed, 367 insertions(+), 321 deletions(-) rename internal/vm/{exec_funcs.go => instruction_handlers.go} (51%) diff --git a/internal/vm/exec_funcs.go b/internal/vm/instruction_handlers.go similarity index 51% rename from internal/vm/exec_funcs.go rename to internal/vm/instruction_handlers.go index 1735374..babeb91 100644 --- a/internal/vm/exec_funcs.go +++ b/internal/vm/instruction_handlers.go @@ -2,538 +2,538 @@ package vm // interrupt, N Z C I D V // push PC+2, push SR - - - 1 - - -func execBRK(a *Appleone, o operation) error { +func execBRK(vm *VM, o operation) error { // set processer status flag to BRK - a.cpu.ps = flagBreak + vm.cpu.ps = flagBreak - a.pushDWordToStack(a.cpu.pc + 1) - a.pushWordToStack(a.cpu.ps) + vm.pushDWordToStack(vm.cpu.pc + 1) + vm.pushWordToStack(vm.cpu.ps) - a.cpu.ps |= flagDisableInterrupts - a.cpu.pc = uint16(a.mem[0xFFFF])<<8 | uint16(a.mem[0xFFFE]) + vm.setFlag(flagDisableInterrupts) + vm.cpu.pc = uint16(vm.mem[0xFFFF])<<8 | uint16(vm.mem[0xFFFE]) return nil } // pull SR, pull PC N Z C I D V // from stack -func execRTI(a *Appleone, o operation) error { - a.cpu.ps = a.popStackWord() - a.cpu.pc = a.popStackDWord() +func execRTI(vm *VM, o operation) error { + vm.cpu.ps = vm.popStackWord() + vm.cpu.pc = vm.popStackDWord() return nil } // M - 1 -> M N Z C I D V // + + - - - - -func execDEC(a *Appleone, o operation) error { - addr, err := a.getAddr(o) +func execDEC(vm *VM, o operation) error { + addr, err := vm.getAddr(o) if err != nil { return err } - b := a.mem[addr] + b := vm.mem[addr] b-- - a.mem[addr] = b - a.maybeSetFlagZero(b) - a.maybeSetFlagOverflow(b) + vm.mem[addr] = b + vm.maybeSetFlagZero(b) + vm.maybeSetFlagOverflow(b) return nil } // M + 1 -> M N Z C I D V // + + - - - - -func execINC(a *Appleone, o operation) error { - addr, err := a.getAddr(o) +func execINC(vm *VM, o operation) error { + addr, err := vm.getAddr(o) if err != nil { return err } - b := a.mem[addr] + b := vm.mem[addr] b++ - a.mem[addr] = b - a.maybeSetFlagZero(b) - a.maybeSetFlagOverflow(b) + vm.mem[addr] = b + vm.maybeSetFlagZero(b) + vm.maybeSetFlagOverflow(b) return nil } // X + 1 -> X N Z C I D V // + + - - - - -func execINX(a *Appleone, o operation) error { - a.cpu.x++ - a.maybeSetFlagZero(a.cpu.x) - a.maybeSetFlagOverflow(a.cpu.x) +func execINX(vm *VM, o operation) error { + vm.cpu.x++ + vm.maybeSetFlagZero(vm.cpu.x) + vm.maybeSetFlagOverflow(vm.cpu.x) return nil } // Y + 1 -> Y N Z C I D V // + + - - - - -func execINY(a *Appleone, o operation) error { - a.cpu.y++ - a.maybeSetFlagZero(a.cpu.y) - a.maybeSetFlagOverflow(a.cpu.y) +func execINY(vm *VM, o operation) error { + vm.cpu.y++ + vm.maybeSetFlagZero(vm.cpu.y) + vm.maybeSetFlagOverflow(vm.cpu.y) return nil } // A -> X N Z C I D V // + + - - - - -func execTAX(a *Appleone, o operation) error { - a.cpu.x = a.cpu.a - a.maybeSetFlagZero(a.cpu.x) - a.maybeSetFlagOverflow(a.cpu.x) +func execTAX(vm *VM, o operation) error { + vm.cpu.x = vm.cpu.a + vm.maybeSetFlagZero(vm.cpu.x) + vm.maybeSetFlagOverflow(vm.cpu.x) return nil } // A -> Y N Z C I D V // + + - - - - -func execTAY(a *Appleone, o operation) error { - a.cpu.y = a.cpu.a - a.maybeSetFlagZero(a.cpu.y) - a.maybeSetFlagOverflow(a.cpu.y) +func execTAY(vm *VM, o operation) error { + vm.cpu.y = vm.cpu.a + vm.maybeSetFlagZero(vm.cpu.y) + vm.maybeSetFlagOverflow(vm.cpu.y) return nil } // X - 1 -> X N Z C I D V // + + - - - - -func execDEX(a *Appleone, o operation) error { - a.cpu.x-- - a.maybeSetFlagZero(a.cpu.x) - a.maybeSetFlagOverflow(a.cpu.x) +func execDEX(vm *VM, o operation) error { + vm.cpu.x-- + vm.maybeSetFlagZero(vm.cpu.x) + vm.maybeSetFlagOverflow(vm.cpu.x) return nil } // Y - 1 -> Y N Z C I D V // + + - - - - -func execDEY(a *Appleone, o operation) error { - a.cpu.y-- - a.maybeSetFlagZero(a.cpu.y) - a.maybeSetFlagOverflow(a.cpu.y) +func execDEY(vm *VM, o operation) error { + vm.cpu.y-- + vm.maybeSetFlagZero(vm.cpu.y) + vm.maybeSetFlagOverflow(vm.cpu.y) return nil } // M -> A N Z C I D V // + + - - - - -func execLDA(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execLDA(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - a.cpu.a = operand - a.maybeSetFlagZero(a.cpu.a) - a.maybeSetFlagOverflow(a.cpu.a) + vm.cpu.a = operand + vm.maybeSetFlagZero(vm.cpu.a) + vm.maybeSetFlagOverflow(vm.cpu.a) return nil } // M -> X N Z C I D V // + + - - - - -func execLDX(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execLDX(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - a.cpu.x = operand - a.maybeSetFlagZero(a.cpu.x) - a.maybeSetFlagOverflow(a.cpu.x) + vm.cpu.x = operand + vm.maybeSetFlagZero(vm.cpu.x) + vm.maybeSetFlagOverflow(vm.cpu.x) return nil } // M -> Y N Z C I D V // + + - - - - -func execLDY(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execLDY(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - a.cpu.y = operand - a.maybeSetFlagZero(a.cpu.y) - a.maybeSetFlagOverflow(a.cpu.y) + vm.cpu.y = operand + vm.maybeSetFlagZero(vm.cpu.y) + vm.maybeSetFlagOverflow(vm.cpu.y) return nil } // A + M + C -> A, C N Z C I D V // + + + - - + -func execADC(a *Appleone, o operation) error { - b, err := a.getOperand(o) +func execADC(vm *VM, o operation) error { + b, err := vm.getOperand(o) if err != nil { return err } operand := uint16(b) - regA := uint16(a.cpu.a) - sum := regA + operand + uint16(a.getFlag(flagCarry)) - a.cpu.a = byte(sum) + regA := uint16(vm.cpu.a) + sum := regA + operand + uint16(vm.getFlag(flagCarry)) + vm.cpu.a = byte(sum) - a.clearFlag(flagCarry) + vm.clearFlag(flagCarry) if sum > 255 { - a.setFlag(flagCarry) + vm.setFlag(flagCarry) } // http://www.righto.com/2012/12/the-6502-overflow-flag-explained.html - a.clearFlag(flagOverflow) + vm.clearFlag(flagOverflow) if (operand^sum)&(regA^sum)&0x80 != 0 { - a.setFlag(flagOverflow) + vm.setFlag(flagOverflow) } - a.maybeSetFlagZero(a.cpu.a) - a.maybeSetFlagOverflow(a.cpu.a) + vm.maybeSetFlagZero(vm.cpu.a) + vm.maybeSetFlagOverflow(vm.cpu.a) return nil } // A - M - C -> A N Z C I D V // + + + - - + -func execSBC(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execSBC(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - carry := uint16(1 - a.getFlag(flagCarry)) - regA := a.cpu.a + carry := uint16(1 - vm.getFlag(flagCarry)) + regA := vm.cpu.a sum := uint16(regA) - carry - uint16(operand) - a.cpu.a = byte(sum) - a.clearFlag(flagOverflow) + vm.cpu.a = byte(sum) + vm.clearFlag(flagOverflow) - if byte(regA)>>7 != a.cpu.a>>7 { - a.setFlag(flagOverflow) + if byte(regA)>>7 != vm.cpu.a>>7 { + vm.setFlag(flagOverflow) } if uint16(sum) < 256 { - a.setFlag(flagCarry) + vm.setFlag(flagCarry) } else { - a.clearFlag(flagCarry) + vm.clearFlag(flagCarry) } - a.clearFlag(flagOverflow) - if ((255-operand)^a.cpu.a)&(regA^a.cpu.a)&0x80 != 0 { - a.setFlag(flagOverflow) + vm.clearFlag(flagOverflow) + if ((255-operand)^vm.cpu.a)&(regA^vm.cpu.a)&0x80 != 0 { + vm.setFlag(flagOverflow) } - a.maybeSetFlagZero(a.cpu.a) - a.maybeSetFlagOverflow(a.cpu.a) + vm.maybeSetFlagZero(vm.cpu.a) + vm.maybeSetFlagOverflow(vm.cpu.a) return nil } // X -> M N Z C I D V // - - - - - - -func execSTX(a *Appleone, o operation) error { - addr, err := a.getAddr(o) +func execSTX(vm *VM, o operation) error { + addr, err := vm.getAddr(o) if err != nil { return err } - a.mem[addr] = a.cpu.x + vm.mem[addr] = vm.cpu.x return nil } // Y -> M N Z C I D V // - - - - - - -func execSTY(a *Appleone, o operation) error { - addr, err := a.getAddr(o) +func execSTY(vm *VM, o operation) error { + addr, err := vm.getAddr(o) if err != nil { return err } - a.mem[addr] = a.cpu.y + vm.mem[addr] = vm.cpu.y return nil } // A -> M N Z C I D V // - - - - - - -func execSTA(a *Appleone, o operation) error { - addr, err := a.getAddr(o) +func execSTA(vm *VM, o operation) error { + addr, err := vm.getAddr(o) if err != nil { return err } - a.mem[addr] = a.cpu.a + vm.mem[addr] = vm.cpu.a return nil } // branch on Z = 1 N Z C I D V // - - - - - - -func execBEQ(a *Appleone, o operation) error { - if a.getFlag(flagZero) == flagZero { - a.branch(o) +func execBEQ(vm *VM, o operation) error { + if vm.getFlag(flagZero) == flagZero { + vm.branch(o) } return nil } // branch on Z = 0 N Z C I D V // - - - - - - -func execBNE(a *Appleone, o operation) error { - if a.getFlag(flagZero) != flagZero { - a.branch(o) +func execBNE(vm *VM, o operation) error { + if vm.getFlag(flagZero) != flagZero { + vm.branch(o) } return nil } // branch on V = 0 N Z C I D V // - - - - - - -func execBVC(a *Appleone, o operation) error { - if a.getFlag(flagOverflow) == 0 { - a.branch(o) +func execBVC(vm *VM, o operation) error { + if vm.getFlag(flagOverflow) == 0 { + vm.branch(o) } return nil } // branch on V = 1 N Z C I D V // - - - - - - -func execBVS(a *Appleone, o operation) error { - if a.getFlag(flagOverflow) != 0 { - a.branch(o) +func execBVS(vm *VM, o operation) error { + if vm.getFlag(flagOverflow) != 0 { + vm.branch(o) } return nil } // bits 7 and 6 of operand are transfered to bit 7 and 6 of SR (N,V); // the zeroflag is set to the result of operand AND accumulator. -func execBIT(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execBIT(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - a.maybeSetFlagZero(a.cpu.a & operand) - a.clearFlag(flagOverflow) + vm.maybeSetFlagZero(vm.cpu.a & operand) + vm.clearFlag(flagOverflow) if operand&flagOverflow != 0 { - a.setFlag(flagOverflow) + vm.setFlag(flagOverflow) } - a.maybeSetFlagOverflow(operand) + vm.maybeSetFlagOverflow(operand) return nil } // branch on C = 0 N Z C I D V // - - - - - - -func execBCC(a *Appleone, o operation) error { - if a.getFlag(flagCarry) == 0 { - a.branch(o) +func execBCC(vm *VM, o operation) error { + if vm.getFlag(flagCarry) == 0 { + vm.branch(o) } return nil } // branch on N = 1 N Z C I D V // - - - - - - -func execBMI(a *Appleone, o operation) error { - if a.getFlag(flagNegative) == flagNegative { - a.branch(o) +func execBMI(vm *VM, o operation) error { + if vm.getFlag(flagNegative) == flagNegative { + vm.branch(o) } return nil } // branch on N = 0 N Z C I D V // - - - - - - -func execBPL(a *Appleone, o operation) error { - if a.getFlag(flagNegative) == 0 { - a.branch(o) +func execBPL(vm *VM, o operation) error { + if vm.getFlag(flagNegative) == 0 { + vm.branch(o) } return nil } // branch on C = 1 N Z C I D V // - - - - - - -func execBCS(a *Appleone, o operation) error { - if a.getFlag(flagCarry) != 0 { - a.branch(o) +func execBCS(vm *VM, o operation) error { + if vm.getFlag(flagCarry) != 0 { + vm.branch(o) } return nil } // X - M N Z C I D V // + + + - - - -func execCPX(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execCPX(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - a.compare(a.cpu.x, operand) + vm.compare(vm.cpu.x, operand) return nil } // A EOR M -> A N Z C I D V // + + - - - - -func execEOR(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execEOR(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - a.cpu.a ^= operand - a.maybeSetFlagOverflow(a.cpu.a) - a.maybeSetFlagZero(a.cpu.a) + vm.cpu.a ^= operand + vm.maybeSetFlagOverflow(vm.cpu.a) + vm.maybeSetFlagZero(vm.cpu.a) return nil } // A - M N Z C I D V // + + + - - - -func execCMP(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execCMP(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - a.compare(a.cpu.a, operand) + vm.compare(vm.cpu.a, operand) return nil } // Y - M N Z C I D V // + + + - - - -func execCPY(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execCPY(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - a.compare(a.cpu.y, operand) + vm.compare(vm.cpu.y, operand) return nil } // 0 -> C N Z C I D V // - - 0 - - - -func execCLC(a *Appleone, o operation) error { - a.clearFlag(flagCarry) +func execCLC(vm *VM, o operation) error { + vm.clearFlag(flagCarry) return nil } // 0 -> D N Z C I D V // - - - - 0 - -func execCLD(a *Appleone, o operation) error { - a.clearFlag(flagDecimalMode) +func execCLD(vm *VM, o operation) error { + vm.clearFlag(flagDecimalMode) return nil } // 0 -> I N Z C I D V // - - - 0 - - -func execCLI(a *Appleone, o operation) error { - a.clearFlag(flagDisableInterrupts) +func execCLI(vm *VM, o operation) error { + vm.clearFlag(flagDisableInterrupts) return nil } // 0 -> V N Z C I D V // - - - - - 0 -func execCLV(a *Appleone, o operation) error { - a.clearFlag(flagOverflow) +func execCLV(vm *VM, o operation) error { + vm.clearFlag(flagOverflow) return nil } // 1 -> C N Z C I D V // - - 1 - - - -func execSEC(a *Appleone, o operation) error { - a.setFlag(flagCarry) +func execSEC(vm *VM, o operation) error { + vm.setFlag(flagCarry) return nil } // 1 -> D N Z C I D V // - - - - 1 - -func execSED(a *Appleone, o operation) error { - a.setFlag(flagDecimalMode) +func execSED(vm *VM, o operation) error { + vm.setFlag(flagDecimalMode) return nil } // 1 -> I N Z C I D V // - - - 1 - - -func execSEI(a *Appleone, o operation) error { - a.setFlag(flagDisableInterrupts) +func execSEI(vm *VM, o operation) error { + vm.setFlag(flagDisableInterrupts) return nil } // --- N Z C I D V // - - - - - - -func execNOP(a *Appleone, o operation) error { +func execNOP(vm *VM, o operation) error { return nil } // (PC+1) -> PCL N Z C I D V // (PC+2) -> PCH - - - - - - -func execJMP(a *Appleone, o operation) error { +func execJMP(vm *VM, o operation) error { if o.addrMode == indirect { - addr, err := a.getAddr(o) + addr, err := vm.getAddr(o) if err != nil { return err } - a.cpu.pc = a.littleEndianToUint16(a.mem[addr+1], a.mem[addr]) + vm.cpu.pc = vm.littleEndianToUint16(vm.mem[addr+1], vm.mem[addr]) return nil } - addr, err := a.getAddr(o) + addr, err := vm.getAddr(o) if err != nil { return err } - a.cpu.pc = addr + vm.cpu.pc = addr return nil } // push A N Z C I D V // - - - - - - -func execPHA(a *Appleone, o operation) error { - a.pushWordToStack(a.cpu.a) +func execPHA(vm *VM, o operation) error { + vm.pushWordToStack(vm.cpu.a) return nil } // X -> A N Z C I D V // + + - - - - -func execTXA(a *Appleone, o operation) error { - a.cpu.a = a.cpu.x - a.maybeSetFlagOverflow(a.cpu.a) - a.maybeSetFlagZero(a.cpu.a) +func execTXA(vm *VM, o operation) error { + vm.cpu.a = vm.cpu.x + vm.maybeSetFlagOverflow(vm.cpu.a) + vm.maybeSetFlagZero(vm.cpu.a) return nil } // Y -> A N Z C I D V // + + - - - - -func execTYA(a *Appleone, o operation) error { - a.cpu.a = a.cpu.y - a.maybeSetFlagOverflow(a.cpu.a) - a.maybeSetFlagZero(a.cpu.a) +func execTYA(vm *VM, o operation) error { + vm.cpu.a = vm.cpu.y + vm.maybeSetFlagOverflow(vm.cpu.a) + vm.maybeSetFlagZero(vm.cpu.a) return nil } // SP -> X N Z C I D V // + + - - - - -func execTSX(a *Appleone, o operation) error { - a.cpu.x = a.cpu.sp - a.maybeSetFlagOverflow(a.cpu.x) - a.maybeSetFlagZero(a.cpu.x) +func execTSX(vm *VM, o operation) error { + vm.cpu.x = vm.cpu.sp + vm.maybeSetFlagOverflow(vm.cpu.x) + vm.maybeSetFlagZero(vm.cpu.x) return nil } // pull A N Z C I D V // + + - - - - -func execPLA(a *Appleone, o operation) error { - a.cpu.a = a.popStackWord() - a.maybeSetFlagOverflow(a.cpu.a) - a.maybeSetFlagZero(a.cpu.a) +func execPLA(vm *VM, o operation) error { + vm.cpu.a = vm.popStackWord() + vm.maybeSetFlagOverflow(vm.cpu.a) + vm.maybeSetFlagZero(vm.cpu.a) return nil } // pull SR from stack N Z C I D V -func execPLP(a *Appleone, o operation) error { - a.cpu.ps = a.popStackWord() | 0B_00110000 - a.maybeSetFlagOverflow(a.cpu.a) - a.maybeSetFlagZero(a.cpu.a) +func execPLP(vm *VM, o operation) error { + vm.cpu.ps = vm.popStackWord() | 0B_00110000 + vm.maybeSetFlagOverflow(vm.cpu.a) + vm.maybeSetFlagZero(vm.cpu.a) return nil } // push SR N Z C I D V // - - - - - - -func execPHP(a *Appleone, o operation) error { - a.pushWordToStack(a.cpu.ps) +func execPHP(vm *VM, o operation) error { + vm.pushWordToStack(vm.cpu.ps) return nil } // push (PC+2), N Z C I D V // (PC+1) -> PCL - - - - - - // (PC+2) -> PCH -func execJSR(a *Appleone, o operation) error { - a.pushDWordToStack(a.cpu.pc - 1) - addr, err := a.getAddr(o) +func execJSR(vm *VM, o operation) error { + vm.pushDWordToStack(vm.cpu.pc - 1) + addr, err := vm.getAddr(o) if err != nil { return err } - a.cpu.pc = addr + vm.cpu.pc = addr return nil } // pull PC, PC+1 -> PC N Z C I D V // - - - - - - -func execRTS(a *Appleone, o operation) error { - a.cpu.pc = a.popStackDWord() + 1 +func execRTS(vm *VM, o operation) error { + vm.cpu.pc = vm.popStackDWord() + 1 return nil } // 0 -> [76543210] -> C N Z C I D V // 0 + + - - - -func execLSR(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execLSR(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } @@ -542,20 +542,20 @@ func execLSR(a *Appleone, o operation) error { operand >>= 1 if bit { - a.setFlag(flagCarry) + vm.setFlag(flagCarry) } else { - a.clearFlag(flagCarry) + vm.clearFlag(flagCarry) } - a.maybeSetFlagZero(operand) - a.maybeSetFlagOverflow(operand) + vm.maybeSetFlagZero(operand) + vm.maybeSetFlagOverflow(operand) if o.addrMode == accumulator { - a.cpu.a = operand + vm.cpu.a = operand return nil } - if err := a.setMem(o, operand); err != nil { + if err := vm.setMem(o, operand); err != nil { return err } @@ -564,21 +564,21 @@ func execLSR(a *Appleone, o operation) error { // C <- [76543210] <- C N Z C I D V // + + + - - - -func execROL(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execROL(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } var carry bool - if a.getFlag(flagCarry) == flagCarry { + if vm.getFlag(flagCarry) == flagCarry { carry = true } if operand>>7 != 0 { - a.setFlag(flagCarry) + vm.setFlag(flagCarry) } else { - a.clearFlag(flagCarry) + vm.clearFlag(flagCarry) } operand <<= 1 @@ -587,15 +587,15 @@ func execROL(a *Appleone, o operation) error { operand |= flagCarry } - a.maybeSetFlagZero(operand) - a.maybeSetFlagOverflow(operand) + vm.maybeSetFlagZero(operand) + vm.maybeSetFlagOverflow(operand) if o.addrMode == accumulator { - a.cpu.a = operand + vm.cpu.a = operand return nil } - if err := a.setMem(o, operand); err != nil { + if err := vm.setMem(o, operand); err != nil { return err } @@ -604,31 +604,31 @@ func execROL(a *Appleone, o operation) error { // X -> SP N Z C I D V // - - - - - - -func execTXS(a *Appleone, o operation) error { - a.cpu.sp = a.cpu.x +func execTXS(vm *VM, o operation) error { + vm.cpu.sp = vm.cpu.x // TODO: needed? - // a.maybeSetFlagZero(a.cpu.sp) - // a.maybeSetFlagOverflow(a.cpu.sp) + // vm.maybeSetFlagZero(vm.cpu.sp) + // vm.maybeSetFlagOverflow(vm.cpu.sp) return nil } // C -> [76543210] -> C N Z C I D V // + + + - - - -func execROR(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execROR(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } var carry bool - if a.getFlag(flagCarry) == flagCarry { + if vm.getFlag(flagCarry) == flagCarry { carry = true } if operand&0x01 != 0 { - a.setFlag(flagCarry) + vm.setFlag(flagCarry) } else { - a.clearFlag(flagCarry) + vm.clearFlag(flagCarry) } operand >>= 1 @@ -637,15 +637,15 @@ func execROR(a *Appleone, o operation) error { operand |= flagNegative } - a.maybeSetFlagZero(operand) - a.maybeSetFlagOverflow(operand) + vm.maybeSetFlagZero(operand) + vm.maybeSetFlagOverflow(operand) if o.addrMode == accumulator { - a.cpu.a = operand + vm.cpu.a = operand return nil } - if err := a.setMem(o, operand); err != nil { + if err := vm.setMem(o, operand); err != nil { return err } @@ -654,29 +654,29 @@ func execROR(a *Appleone, o operation) error { // C <- [76543210] <- 0 N Z C I D V // + + + - - - -func execASL(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execASL(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } if operand>>7 == 1 { - a.setFlag(flagCarry) + vm.setFlag(flagCarry) } else { - a.clearFlag(flagCarry) + vm.clearFlag(flagCarry) } operand <<= 1 - a.maybeSetFlagZero(operand) - a.maybeSetFlagOverflow(operand) + vm.maybeSetFlagZero(operand) + vm.maybeSetFlagOverflow(operand) if o.addrMode == accumulator { - a.cpu.a = operand + vm.cpu.a = operand return nil } - if err := a.setMem(o, operand); err != nil { + if err := vm.setMem(o, operand); err != nil { return err } @@ -685,26 +685,26 @@ func execASL(a *Appleone, o operation) error { // A AND M -> A N Z C I D V // + + - - - - -func execAND(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execAND(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - a.cpu.a &= operand - a.maybeSetFlagZero(a.cpu.a) - a.maybeSetFlagOverflow(a.cpu.a) + vm.cpu.a &= operand + vm.maybeSetFlagZero(vm.cpu.a) + vm.maybeSetFlagOverflow(vm.cpu.a) return nil } // A OR M -> A N Z C I D V // + + - - - - -func execORA(a *Appleone, o operation) error { - operand, err := a.getOperand(o) +func execORA(vm *VM, o operation) error { + operand, err := vm.getOperand(o) if err != nil { return err } - a.cpu.a |= operand - a.maybeSetFlagZero(a.cpu.a) - a.maybeSetFlagOverflow(a.cpu.a) + vm.cpu.a |= operand + vm.maybeSetFlagZero(vm.cpu.a) + vm.maybeSetFlagOverflow(vm.cpu.a) return nil } diff --git a/internal/vm/opcodes.go b/internal/vm/opcodes.go index c2f74f8..d5564f8 100644 --- a/internal/vm/opcodes.go +++ b/internal/vm/opcodes.go @@ -11,10 +11,10 @@ type operation struct { opcode byte size byte addrMode addrMode - exec func(a *Appleone, op operation) error + exec func(a *VM, op operation) error } -func newOp(name string, opcode, size byte, addrMode addrMode, exec func(a *Appleone, op operation) error) operation { +func newOp(name string, opcode, size byte, addrMode addrMode, exec func(a *VM, op operation) error) operation { return operation{ name: name, opcode: opcode, diff --git a/internal/vm/vm.go b/internal/vm/vm.go index fc808d7..9c42ce8 100644 --- a/internal/vm/vm.go +++ b/internal/vm/vm.go @@ -3,42 +3,69 @@ package vm import ( "errors" "fmt" + "time" ) -// Appleone represents the virtual Apple 1 computer -type Appleone struct { - cpu *Mos6502 // virtual mos6502 cpu - mem block // available memory (64kiB) +const clockSpeed = 1 // 1 MHz + +// VM represents the Apple 1 virutal machine +type VM struct { + cpu *Mos6502 // virtual mos6502 cpu + mem block // available memory (64kiB) + clock *time.Ticker // the "cpu" clock + ShutdownC chan struct{} // } -// New returns a pointer to an initialized Appleone with a brand spankin new CPU -func New() *Appleone { - return &Appleone{ - cpu: newCPU(), - mem: newBlock(), +// New returns a pointer to an initialized VM with a brand spankin new CPU +func New() *VM { + return &VM{ + cpu: newCPU(), + mem: newBlock(), + clock: time.NewTicker(time.Second / time.Duration(clockSpeed)), } } -// load puts the provided data into the apple1's memory block starting at the provided address -func (a *Appleone) load(addr uint16, data []byte) { - a.mem.load(addr, data) - a.cpu.pc = addr +// Run starts the vm and emulates a clock that runs by default at 60MHz +// This can be changed with a flag. +func (vm *VM) Run() { + for { + select { + case <-vm.clock.C: + vm.emulateCycle() + continue + case <-vm.ShutdownC: + break + } + break + } + vm.sigTerm("gracefully shutting down...") } -func (a *Appleone) step() { - operation, err := operationByCode(a.mem[a.cpu.pc]) +func (vm *VM) emulateCycle() { + operation, err := operationByCode(vm.mem[vm.cpu.pc]) if err != nil { fmt.Println("TODO") } - a.cpu.pc += uint16(operation.size) + vm.cpu.pc += uint16(operation.size) - if err := operation.exec(a, operation); err != nil { + if err := operation.exec(vm, operation); err != nil { fmt.Println("TODO") } } -func (a *Appleone) getAddr(o operation) (uint16, error) { +func (vm *VM) sigTerm(msg string) { + fmt.Println(msg) + vm.ShutdownC <- struct{}{} +} + +// load puts the provided data into the apple1's memory block starting at the provided address +func (vm *VM) load(addr uint16, data []byte) { + vm.mem.load(addr, data) + vm.cpu.pc = addr +} + +func (vm *VM) getAddr(o operation) (uint16, error) { switch o.addrMode { // TODO: will these ever apply here? // case accumulator: @@ -46,153 +73,166 @@ func (a *Appleone) getAddr(o operation) (uint16, error) { // case implied: // case absolute: - return a.nextDWord(), nil + return vm.nextDWord(), nil case absoluteXIndexed: - return a.nextDWord() + uint16(a.cpu.x), nil + return vm.nextDWord() + uint16(vm.cpu.x), nil case absoluteYIndexed: - return a.nextDWord() + uint16(a.cpu.y), nil + return vm.nextDWord() + uint16(vm.cpu.y), nil case immediate: - return a.cpu.pc - 1, nil + return vm.cpu.pc - 1, nil case indirect: - return uint16(a.nextWord()), nil + return uint16(vm.nextWord()), nil case indirectXIndexed: - addr := (uint16(a.nextWord()) + uint16(a.cpu.x)) & 0xFF - return a.littleEndianToUint16(a.mem[addr+1], a.mem[addr]), nil + addr := (uint16(vm.nextWord()) + uint16(vm.cpu.x)) & 0xFF + return vm.littleEndianToUint16(vm.mem[addr+1], vm.mem[addr]), nil case indirectYIndexed: - addr := uint16(a.nextWord()) - val := a.littleEndianToUint16(a.mem[addr+1], a.mem[addr]) - return val + uint16(a.cpu.y), nil + addr := uint16(vm.nextWord()) + val := vm.littleEndianToUint16(vm.mem[addr+1], vm.mem[addr]) + return val + uint16(vm.cpu.y), nil case relative: - return a.cpu.pc - 1, nil + return vm.cpu.pc - 1, nil case zeroPage: - return uint16(a.nextWord()) & 0xFF, nil + return uint16(vm.nextWord()) & 0xFF, nil case zeroPageXIndexed: - return (uint16(a.nextWord()) + uint16(a.cpu.x)) & 0xFF, nil + return (uint16(vm.nextWord()) + uint16(vm.cpu.x)) & 0xFF, nil case zeroPageYIndexed: - return (uint16(a.nextWord()) + uint16(a.cpu.y)) & 0xFF, nil + return (uint16(vm.nextWord()) + uint16(vm.cpu.y)) & 0xFF, nil default: return 0, errors.New("unkown addressing mode") } } -func (a *Appleone) getOperand(o operation) (byte, error) { +func (vm *VM) getOperand(o operation) (byte, error) { if o.addrMode == accumulator { - return a.cpu.a, nil + return vm.cpu.a, nil } - b, err := a.getAddr(o) + b, err := vm.getAddr(o) if err != nil { return 0, err } - return a.mem[b], nil + return vm.mem[b], nil } -func (a *Appleone) littleEndianToUint16(big, little byte) uint16 { - return uint16(a.mem[big])<<8 | uint16(a.mem[little]) +func (vm *VM) littleEndianToUint16(big, little byte) uint16 { + return uint16(vm.mem[big])<<8 | uint16(vm.mem[little]) } // pushWordToStack pushes the given word (byte) into memory and sets the new stack pointer -func (a *Appleone) pushWordToStack(b byte) { - a.mem[StackBottom+uint16(a.cpu.sp)] = b - a.cpu.sp = byte((uint16(a.cpu.sp) - 1) & 0xFF) +func (vm *VM) pushWordToStack(b byte) { + vm.mem[StackBottom+uint16(vm.cpu.sp)] = b + vm.cpu.sp = byte((uint16(vm.cpu.sp) - 1) & 0xFF) } // pushWordToStack splits the high and low byte of the data passed in, and pushes them to the stack -func (a *Appleone) pushDWordToStack(data uint16) { +func (vm *VM) pushDWordToStack(data uint16) { h := byte((data >> 8) & 0xFF) l := byte(data & 0xFF) - a.pushWordToStack(h) - a.pushWordToStack(l) + vm.pushWordToStack(h) + vm.pushWordToStack(l) } // popStackWord sets the new stack pointer and returns the appropriate byte in memory -func (a *Appleone) popStackWord() byte { - a.cpu.sp = byte((uint16(a.cpu.sp) + 1) & 0xFF) - return a.mem[StackBottom+uint16(a.cpu.sp)] +func (vm *VM) popStackWord() byte { + vm.cpu.sp = byte((uint16(vm.cpu.sp) + 1) & 0xFF) + return vm.mem[StackBottom+uint16(vm.cpu.sp)] } // popStackDWord pops two stack words (a double word - uint16) off the stack -func (a *Appleone) popStackDWord() uint16 { - l := a.popStackWord() - h := a.popStackWord() +func (vm *VM) popStackDWord() uint16 { + l := vm.popStackWord() + h := vm.popStackWord() return (uint16(h) << 8) | uint16(l) } // nextWord returns the next byte in memory -func (a *Appleone) nextWord() byte { - return a.mem[a.cpu.pc-1] +func (vm *VM) nextWord() byte { + return vm.mem[vm.cpu.pc-1] } // nextDWord returns the next two bytes (double word) -func (a *Appleone) nextDWord() uint16 { - return a.littleEndianToUint16(a.mem[a.cpu.pc-1], a.mem[a.cpu.pc-2]) +func (vm *VM) nextDWord() uint16 { + return vm.littleEndianToUint16(vm.mem[vm.cpu.pc-1], vm.mem[vm.cpu.pc-2]) } // maybeSetFlagZero takes a single word (byte), clears flagZero, and sets flagZero if word is 0 -func (a *Appleone) maybeSetFlagZero(word byte) { - a.clearFlag(flagZero) +func (vm *VM) maybeSetFlagZero(word byte) { + vm.clearFlag(flagZero) if word == 0 { - a.setFlag(flagZero) + vm.setFlag(flagZero) } } -func (a *Appleone) getFlag(flag byte) byte { - return a.cpu.ps & flag +func (vm *VM) getFlag(flag byte) byte { + return vm.cpu.ps & flag } -func (a *Appleone) setFlag(flag byte) { - a.cpu.ps |= flag +func (vm *VM) setFlag(flag byte) { + vm.cpu.ps |= flag } -func (a *Appleone) clearFlag(flag byte) { - a.cpu.ps &^= flag +func (vm *VM) clearFlag(flag byte) { + vm.cpu.ps &^= flag } -func (a *Appleone) maybeSetFlagOverflow(word byte) { - a.clearFlag(flagNegative) +func (vm *VM) maybeSetFlagOverflow(word byte) { + vm.clearFlag(flagNegative) if word > 127 { - a.setFlag(flagNegative) + vm.setFlag(flagNegative) } } // Branch offsets are signed 8-bit values, -128 ... +127, negative offsets in two's // complement. Page transitions may occur and add an extra cycle to the exucution -func (a *Appleone) branch(o operation) error { - offset, err := a.getOperand(o) +func (vm *VM) branch(o operation) error { + offset, err := vm.getOperand(o) if err != nil { return err } if offset > 127 { - a.cpu.pc -= 256 - uint16(offset) + vm.cpu.pc -= 256 - uint16(offset) } else { - a.cpu.pc += uint16(offset) + vm.cpu.pc += uint16(offset) } return nil } // compare clears zero, carry, and negative flags, compares the two bytes, and sets the // appropriate flags based on the comparison between the bytes. -func (a *Appleone) compare(b1, b2 byte) { - a.clearFlag(flagZero) - a.clearFlag(flagCarry) - a.clearFlag(flagNegative) +func (vm *VM) compare(b1, b2 byte) { + vm.clearFlag(flagZero) + vm.clearFlag(flagCarry) + vm.clearFlag(flagNegative) if b1 == b2 { - a.setFlag(flagZero) - a.setFlag(flagCarry) + vm.setFlag(flagZero) + vm.setFlag(flagCarry) } if b1 > b2 { - a.setFlag(flagCarry) + vm.setFlag(flagCarry) } b := byte(uint16(b1) - uint16(b2)) - a.maybeSetFlagOverflow(b) + vm.maybeSetFlagOverflow(b) } -func (a *Appleone) setMem(o operation, operand byte) error { - addr, err := a.getAddr(o) +func (vm *VM) setMem(o operation, operand byte) error { + addr, err := vm.getAddr(o) if err != nil { return err } - a.mem[addr] = operand + vm.mem[addr] = operand return nil } + +// func (vm *VM) execBRK(o operation) error { +// // set processer status flag to BRK +// vm.cpu.ps = flagBreak + +// vm.pushDWordToStack(vm.cpu.pc + 1) +// vm.pushWordToStack(vm.cpu.ps) + +// vm.setFlag(flagDisableInterrupts) +// vm.cpu.pc = uint16(vm.mem[0xFFFF])<<8 | uint16(vm.mem[0xFFFE]) + +// return nil +// } diff --git a/main.go b/main.go index 38dd16d..5169447 100644 --- a/main.go +++ b/main.go @@ -1,3 +1,9 @@ package main -func main() {} +import "github.com/bradford-hamilton/apple-1/internal/vm" + +func main() { + vm := vm.New() + go vm.Run() + <-vm.ShutdownC +}