mirror of
https://github.com/bradford-hamilton/apple-1.git
synced 2025-01-13 15:30:53 +00:00
internal/vm: update Appleone and all it’s a
handlers to VM with vm
handler
This commit is contained in:
parent
b7a3ec4a6c
commit
67416900b4
@ -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
|
||||
}
|
@ -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,
|
||||
|
@ -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
|
||||
// }
|
||||
|
Loading…
x
Reference in New Issue
Block a user