diff --git a/internal/vm/exec_funcs.go b/internal/vm/exec_funcs.go index 31b3385..169d6ce 100644 --- a/internal/vm/exec_funcs.go +++ b/internal/vm/exec_funcs.go @@ -117,11 +117,11 @@ func execDEY(a *Appleone, o op) error { // M -> A N Z C I D V // + + - - - - func execLDA(a *Appleone, o op) error { - b, err := o.getData(a) + operand, err := o.getOperand(a) if err != nil { return err } - a.cpu.a = b + a.cpu.a = operand a.setZeroIfNeeded(a.cpu.a) a.setNegativeIfOverflow(a.cpu.a) return nil @@ -130,11 +130,11 @@ func execLDA(a *Appleone, o op) error { // M -> X N Z C I D V // + + - - - - func execLDX(a *Appleone, o op) error { - b, err := o.getData(a) + operand, err := o.getOperand(a) if err != nil { return err } - a.cpu.x = b + a.cpu.x = operand a.setZeroIfNeeded(a.cpu.x) a.setNegativeIfOverflow(a.cpu.x) return nil @@ -143,11 +143,11 @@ func execLDX(a *Appleone, o op) error { // M -> Y N Z C I D V // + + - - - - func execLDY(a *Appleone, o op) error { - b, err := o.getData(a) + operand, err := o.getOperand(a) if err != nil { return err } - a.cpu.y = b + a.cpu.y = operand a.setZeroIfNeeded(a.cpu.y) a.setNegativeIfOverflow(a.cpu.y) return nil @@ -156,14 +156,14 @@ func execLDY(a *Appleone, o op) error { // A + M + C -> A, C N Z C I D V // + + + - - + func execADC(a *Appleone, o op) error { - b, err := o.getData(a) + b, err := o.getOperand(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.cpu.a = byte(sum) a.clearCarry() if sum > 255 { @@ -181,3 +181,536 @@ func execADC(a *Appleone, o op) error { return nil } + +// A - M - C -> A N Z C I D V +// + + + - - + +func execSBC(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + + carry := uint16(1 - a.getCarry()) + regA := a.cpu.a + sum := uint16(regA) - carry - uint16(operand) + a.cpu.a = byte(sum) + a.clearOverflow() + + if byte(regA)>>7 != a.cpu.a>>7 { + a.setOverflow() + } + + if uint16(sum) < 256 { + a.setCarry() + } else { + a.clearCarry() + } + + a.clearOverflow() + if ((255-operand)^a.cpu.a)&(regA^a.cpu.a)&0x80 != 0 { + a.setOverflow() + } + + a.setZeroIfNeeded(a.cpu.a) + a.setNegativeIfOverflow(a.cpu.a) + return nil +} + +// X -> M N Z C I D V +// - - - - - - +func execSTX(a *Appleone, o op) error { + addr, err := o.getAddr(a) + if err != nil { + return err + } + a.mem[addr] = a.cpu.x + return nil +} + +// Y -> M N Z C I D V +// - - - - - - +func execSTY(a *Appleone, o op) error { + addr, err := o.getAddr(a) + if err != nil { + return err + } + a.mem[addr] = a.cpu.y + return nil +} + +// A -> M N Z C I D V +// - - - - - - +func execSTA(a *Appleone, o op) error { + addr, err := o.getAddr(a) + if err != nil { + return err + } + a.mem[addr] = a.cpu.a + return nil +} + +// branch on Z = 1 N Z C I D V +// - - - - - - +func execBEQ(a *Appleone, o op) error { + if a.getZero() == flagZero { + a.branch(o) + } + return nil +} + +// branch on Z = 0 N Z C I D V +// - - - - - - +func execBNE(a *Appleone, o op) error { + if a.getZero() != flagZero { + a.branch(o) + } + return nil +} + +// branch on V = 0 N Z C I D V +// - - - - - - +func execBVC(a *Appleone, o op) error { + if a.getOverflow() == 0 { + a.branch(o) + } + return nil +} + +// branch on V = 1 N Z C I D V +// - - - - - - +func execBVS(a *Appleone, o op) error { + if a.getOverflow() != 0 { + a.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 op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + a.setZeroIfNeeded(a.cpu.a & operand) + a.clearOverflow() + + if operand&flagOverflow != 0 { + a.setOverflow() + } + + a.setNegativeIfOverflow(operand) + return nil +} + +// branch on C = 0 N Z C I D V +// - - - - - - +func execBCC(a *Appleone, o op) error { + if a.getCarry() == 0 { + a.branch(o) + } + return nil +} + +// branch on N = 1 N Z C I D V +// - - - - - - +func execBMI(a *Appleone, o op) error { + if a.getNegative() == flagNegative { + a.branch(o) + } + return nil +} + +// branch on N = 0 N Z C I D V +// - - - - - - +func execBPL(a *Appleone, o op) error { + if a.getNegative() == 0 { + a.branch(o) + } + return nil +} + +// X - M N Z C I D V +// + + + - - - +func execCPX(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + a.compare(a.cpu.x, operand) + return nil +} + +// A EOR M -> A N Z C I D V +// + + - - - - +func execEOR(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + a.cpu.a ^= operand + a.setNegativeIfOverflow(a.cpu.a) + a.setZeroIfNeeded(a.cpu.a) + return nil +} + +// A - M N Z C I D V +// + + + - - - +func execCMP(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + a.compare(a.cpu.a, operand) + return nil +} + +// Y - M N Z C I D V +// + + + - - - +func execCPY(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + a.compare(a.cpu.y, operand) + return nil +} + +// 0 -> C N Z C I D V +// - - 0 - - - +func execCLC(a *Appleone, o op) error { + a.clearCarry() + return nil +} + +// 0 -> D N Z C I D V +// - - - - 0 - +func execCLD(a *Appleone, o op) error { + a.clearDec() + return nil +} + +// 0 -> I N Z C I D V +// - - - 0 - - +func execCLI(a *Appleone, o op) error { + a.clearInterrupt() + return nil +} + +// 0 -> V N Z C I D V +// - - - - - 0 +func execCLV(a *Appleone, o op) error { + a.clearOverflow() + return nil +} + +// 1 -> C N Z C I D V +// - - 1 - - - +func execSEC(a *Appleone, o op) error { + a.setCarry() + return nil +} + +// 1 -> D N Z C I D V +// - - - - 1 - +func execSED(a *Appleone, o op) error { + a.setDec() + return nil +} + +// 1 -> I N Z C I D V +// - - - 1 - - +func execSEI(a *Appleone, o op) error { + a.setInterrupt() + return nil +} + +// --- N Z C I D V +// - - - - - - +func execNOP(a *Appleone, o op) error { + return nil +} + +// (PC+1) -> PCL N Z C I D V +// (PC+2) -> PCH - - - - - - +func execJMP(a *Appleone, o op) error { + if o.addrMode == indirect { + addr, err := o.getAddr(a) + if err != nil { + return err + } + a.cpu.pc = a.littleEndianToUint16(a.mem[addr+1], a.mem[addr]) + return nil + } + addr, err := o.getAddr(a) + if err != nil { + return err + } + a.cpu.pc = addr + return nil +} + +// push A N Z C I D V +// - - - - - - +func execPHA(a *Appleone, o op) error { + a.pushWordToStack(a.cpu.a) + return nil +} + +// X -> A N Z C I D V +// + + - - - - +func execTXA(a *Appleone, o op) error { + a.cpu.a = a.cpu.x + a.setNegativeIfOverflow(a.cpu.a) + a.setZeroIfNeeded(a.cpu.a) + return nil +} + +// Y -> A N Z C I D V +// + + - - - - +func execTYA(a *Appleone, o op) error { + a.cpu.a = a.cpu.y + a.setNegativeIfOverflow(a.cpu.a) + a.setZeroIfNeeded(a.cpu.a) + return nil +} + +// SP -> X N Z C I D V +// + + - - - - +func execTSX(a *Appleone, o op) error { + a.cpu.x = a.cpu.sp + a.setNegativeIfOverflow(a.cpu.x) + a.setZeroIfNeeded(a.cpu.x) + return nil +} + +// pull A N Z C I D V +// + + - - - - +func execPLA(a *Appleone, o op) error { + a.cpu.a = a.popStackWord() + a.setNegativeIfOverflow(a.cpu.a) + a.setZeroIfNeeded(a.cpu.a) + return nil +} + +// pull SR from stack N Z C I D V +func execPLP(a *Appleone, o op) error { + a.cpu.ps = a.popStackWord() | 0B_00110000 + a.setNegativeIfOverflow(a.cpu.a) + a.setZeroIfNeeded(a.cpu.a) + return nil +} + +// push SR N Z C I D V +// - - - - - - +func execPHP(a *Appleone, o op) error { + a.pushWordToStack(a.cpu.ps) + return nil +} + +// push (PC+2), N Z C I D V +// (PC+1) -> PCL - - - - - - +// (PC+2) -> PCH +func execJSR(a *Appleone, o op) error { + a.pushDWordToStack(a.cpu.pc - 1) + addr, err := o.getAddr(a) + if err != nil { + return err + } + a.cpu.pc = addr + return nil +} + +// pull PC, PC+1 -> PC N Z C I D V +// - - - - - - +func execRTS(a *Appleone, o op) error { + a.cpu.pc = a.popStackDWord() + 1 + return nil +} + +// 0 -> [76543210] -> C N Z C I D V +// 0 + + - - - +func execLSR(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + + bit := (operand << 7) > 0 + operand >>= 1 + + if bit { + a.setCarry() + } else { + a.clearCarry() + } + + a.setZeroIfNeeded(operand) + a.setNegativeIfOverflow(operand) + + if o.addrMode == accumulator { + a.cpu.a = operand + return nil + } + + addr, err := o.getAddr(a) + if err != nil { + return err + } + a.mem[addr] = operand + + return nil +} + +// C <- [76543210] <- C N Z C I D V +// + + + - - - +func execROL(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + + var carry bool + if a.getCarry() == flagCarry { + carry = true + } + + if operand>>7 != 0 { + a.setCarry() + } else { + a.clearCarry() + } + + operand <<= 1 + + if carry { + operand |= flagCarry + } + + a.setZeroIfNeeded(operand) + a.setNegativeIfOverflow(operand) + + if o.addrMode == accumulator { + a.cpu.a = operand + return nil + } + + addr, err := o.getAddr(a) + if err != nil { + return err + } + a.mem[addr] = operand + + return nil +} + +// X -> SP N Z C I D V +// - - - - - - +func execTXS(a *Appleone, o op) error { + a.cpu.sp = a.cpu.x + // TODO: needed? + // a.setZeroIfNeeded(a.cpu.sp) + // a.setNegativeIfOverflow(a.cpu.sp) + return nil +} + +// C -> [76543210] -> C N Z C I D V +// + + + - - - +func execROR(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + + var carry bool + if a.getCarry() == flagCarry { + carry = true + } + + if operand&0x01 != 0 { + a.setCarry() + } else { + a.clearCarry() + } + + operand >>= 1 + + if carry { + operand |= flagNegative + } + + a.setZeroIfNeeded(operand) + a.setNegativeIfOverflow(operand) + + if o.addrMode == accumulator { + a.cpu.a = operand + return nil + } + + addr, err := o.getAddr(a) + if err != nil { + return err + } + a.mem[addr] = operand + + return nil +} + +// C <- [76543210] <- 0 N Z C I D V +// + + + - - - +func execASL(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + + if operand>>7 == 1 { + a.setCarry() + } else { + a.clearCarry() + } + + operand <<= 1 + + a.setZeroIfNeeded(operand) + a.setNegativeIfOverflow(operand) + + if o.addrMode == accumulator { + a.cpu.a = operand + return nil + } + + addr, err := o.getAddr(a) + if err != nil { + return err + } + a.mem[addr] = operand + + return nil +} + +// A AND M -> A N Z C I D V +// + + - - - - +func execAND(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + a.cpu.a &= operand + a.setZeroIfNeeded(a.cpu.a) + a.setNegativeIfOverflow(a.cpu.a) + return nil +} + +// A OR M -> A N Z C I D V +// + + - - - - +func execORA(a *Appleone, o op) error { + operand, err := o.getOperand(a) + if err != nil { + return err + } + a.cpu.a |= operand + 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 53a2c7d..ea87c3c 100644 --- a/internal/vm/opcodes.go +++ b/internal/vm/opcodes.go @@ -70,7 +70,7 @@ func (o op) getAddr(a *Appleone) (uint16, error) { } } -func (o op) getData(a *Appleone) (uint8, error) { +func (o op) getOperand(a *Appleone) (uint8, error) { if o.addrMode == accumulator { return a.cpu.a, nil } @@ -235,14 +235,14 @@ var opcodes = map[uint8]op{ // absolute,Y SBC oper,Y F9 3 4* // (indirect,X) SBC (oper,X) E1 2 6 // (indirect),Y SBC (oper),Y F1 2 5* - 0xE9: newOp("SBC", 0xE9, 2, immediate, todo), - 0xE5: newOp("SBC", 0xE5, 2, zeroPage, todo), - 0xF5: newOp("SBC", 0xF5, 2, zeroPageXIndexed, todo), - 0xED: newOp("SBC", 0xED, 3, absolute, todo), - 0xFD: newOp("SBC", 0xFD, 3, absoluteXIndexed, todo), - 0xF9: newOp("SBC", 0xF9, 3, absoluteYIndexed, todo), - 0xE1: newOp("SBC", 0xE1, 2, indirectXIndexed, todo), - 0xF1: newOp("SBC", 0xF1, 2, indirectYIndexed, todo), + 0xE9: newOp("SBC", 0xE9, 2, immediate, execSBC), + 0xE5: newOp("SBC", 0xE5, 2, zeroPage, execSBC), + 0xF5: newOp("SBC", 0xF5, 2, zeroPageXIndexed, execSBC), + 0xED: newOp("SBC", 0xED, 3, absolute, execSBC), + 0xFD: newOp("SBC", 0xFD, 3, absoluteXIndexed, execSBC), + 0xF9: newOp("SBC", 0xF9, 3, absoluteYIndexed, execSBC), + 0xE1: newOp("SBC", 0xE1, 2, indirectXIndexed, execSBC), + 0xF1: newOp("SBC", 0xF1, 2, indirectYIndexed, execSBC), // STX Store Index X in Memory // addressing assembler opc bytes cyles @@ -250,9 +250,9 @@ var opcodes = map[uint8]op{ // zeropage STX oper 86 2 3 // zeropage,Y STX oper,Y 96 2 4 // absolute STX oper 8E 3 4 - 0x86: newOp("STX", 0x86, 2, zeroPage, todo), - 0x96: newOp("STX", 0x96, 2, zeroPageYIndexed, todo), - 0x8E: newOp("STX", 0x8E, 3, absolute, todo), + 0x86: newOp("STX", 0x86, 2, zeroPage, execSTX), + 0x96: newOp("STX", 0x96, 2, zeroPageYIndexed, execSTX), + 0x8E: newOp("STX", 0x8E, 3, absolute, execSTX), // STY Store Index Y in Memory // addressing assembler opc bytes cyles @@ -260,9 +260,9 @@ var opcodes = map[uint8]op{ // zeropage STY oper 84 2 3 // zeropage,X STY oper,X 94 2 4 // absolute STY oper 8C 3 4 - 0x84: newOp("STY", 0x84, 2, zeroPage, todo), - 0x94: newOp("STY", 0x94, 2, zeroPageXIndexed, todo), - 0x8C: newOp("STY", 0x8C, 3, absolute, todo), + 0x84: newOp("STY", 0x84, 2, zeroPage, execSTY), + 0x94: newOp("STY", 0x94, 2, zeroPageXIndexed, execSTY), + 0x8C: newOp("STY", 0x8C, 3, absolute, execSTY), // STA Store Accumulator in Memory // addressing assembler opc bytes cyles @@ -274,63 +274,63 @@ var opcodes = map[uint8]op{ // absolute,Y STA oper,Y 99 3 5 // (indirect,X) STA (oper,X) 81 2 6 // (indirect),Y STA (oper),Y 91 2 6 - 0x85: newOp("STA", 0x85, 2, zeroPage, todo), - 0x95: newOp("STA", 0x95, 2, zeroPageXIndexed, todo), - 0x8D: newOp("STA", 0x8D, 3, absolute, todo), - 0x9D: newOp("STA", 0x9D, 3, absoluteXIndexed, todo), - 0x99: newOp("STA", 0x99, 3, absoluteYIndexed, todo), - 0x81: newOp("STA", 0x81, 2, indirectXIndexed, todo), - 0x91: newOp("STA", 0x91, 2, indirectYIndexed, todo), + 0x85: newOp("STA", 0x85, 2, zeroPage, execSTA), + 0x95: newOp("STA", 0x95, 2, zeroPageXIndexed, execSTA), + 0x8D: newOp("STA", 0x8D, 3, absolute, execSTA), + 0x9D: newOp("STA", 0x9D, 3, absoluteXIndexed, execSTA), + 0x99: newOp("STA", 0x99, 3, absoluteYIndexed, execSTA), + 0x81: newOp("STA", 0x81, 2, indirectXIndexed, execSTA), + 0x91: newOp("STA", 0x91, 2, indirectYIndexed, execSTA), // BEQ Branch on Result Zero // addressing assembler opc bytes cyles // -------------------------------------------- // relative BEQ oper F0 2 2** - 0xF0: newOp("BEQ", 0xF0, 2, relative, todo), + 0xF0: newOp("BEQ", 0xF0, 2, relative, execBEQ), // BNE Branch on Result not Zero // addressing assembler opc bytes cyles // -------------------------------------------- // relative BNE oper D0 2 2** - 0xD0: newOp("BNE", 0xD0, 2, relative, todo), + 0xD0: newOp("BNE", 0xD0, 2, relative, execBNE), // BVC Branch on Overflow Clear // addressing assembler opc bytes cyles // -------------------------------------------- // relative BVC oper 50 2 2** - 0x50: newOp("BVC", 0x50, 2, relative, todo), + 0x50: newOp("BVC", 0x50, 2, relative, execBVC), // BVS Branch on Overflow Set // addressing assembler opc bytes cyles // -------------------------------------------- // relative BVC oper 70 2 2** - 0x70: newOp("BVS", 0x70, 2, relative, todo), + 0x70: newOp("BVS", 0x70, 2, relative, execBVS), // BIT Test Bits in Memory with Accumulator // addressing assembler opc bytes cyles // -------------------------------------------- // zeropage BIT oper 24 2 3 // absolute BIT oper 2C 3 4 - 0x24: newOp("BIT", 0x24, 2, zeroPage, todo), - 0x2C: newOp("BIT", 0x2C, 3, absolute, todo), + 0x24: newOp("BIT", 0x24, 2, zeroPage, execBIT), + 0x2C: newOp("BIT", 0x2C, 3, absolute, execBIT), // BCC Branch on Carry Clear // addressing assembler opc bytes cyles // -------------------------------------------- // relative BCC oper 90 2 2** - 0x90: newOp("BCC", 0x90, 2, relative, todo), + 0x90: newOp("BCC", 0x90, 2, relative, execBCC), // BMI Branch on Result Minus // addressing assembler opc bytes cyles // -------------------------------------------- // relative BMI oper 30 2 2** - 0x30: newOp("BMI", 0x30, 2, relative, todo), + 0x30: newOp("BMI", 0x30, 2, relative, execBMI), // BPL Branch on Result Plus // addressing assembler opc bytes cyles // -------------------------------------------- // relative BPL oper 10 2 2** - 0x10: newOp("BPL", 0x10, 2, relative, todo), + 0x10: newOp("BPL", 0x10, 2, relative, execBPL), // BCS Branch on Carry Set // addressing assembler opc bytes cyles @@ -344,9 +344,9 @@ var opcodes = map[uint8]op{ // immidiate CPX #oper E0 2 2 // zeropage CPX oper E4 2 3 // absolute CPX oper EC 3 4 - 0xE0: newOp("CPX", 0xE0, 2, immediate, todo), - 0xE4: newOp("CPX", 0xE4, 2, zeroPage, todo), - 0xEC: newOp("CPX", 0xEC, 3, absolute, todo), + 0xE0: newOp("CPX", 0xE0, 2, immediate, execCPX), + 0xE4: newOp("CPX", 0xE4, 2, zeroPage, execCPX), + 0xEC: newOp("CPX", 0xEC, 3, absolute, execCPX), // EOR Exclusive-OR Memory with Accumulator // addressing assembler opc bytes cyles @@ -359,14 +359,14 @@ var opcodes = map[uint8]op{ // absolute,Y EOR oper,Y 59 3 4* // (indirect,X) EOR (oper,X) 41 2 6 // (indirect),Y EOR (oper),Y 51 2 5* - 0x49: newOp("EOR", 0x49, 2, immediate, todo), - 0x45: newOp("EOR", 0x45, 2, zeroPage, todo), - 0x55: newOp("EOR", 0x55, 2, zeroPageXIndexed, todo), - 0x4D: newOp("EOR", 0x4D, 3, absolute, todo), - 0x5D: newOp("EOR", 0x5D, 3, absoluteXIndexed, todo), - 0x59: newOp("EOR", 0x59, 3, absoluteYIndexed, todo), - 0x41: newOp("EOR", 0x41, 2, indirectXIndexed, todo), - 0x51: newOp("EOR", 0x51, 2, indirectYIndexed, todo), + 0x49: newOp("EOR", 0x49, 2, immediate, execEOR), + 0x45: newOp("EOR", 0x45, 2, zeroPage, execEOR), + 0x55: newOp("EOR", 0x55, 2, zeroPageXIndexed, execEOR), + 0x4D: newOp("EOR", 0x4D, 3, absolute, execEOR), + 0x5D: newOp("EOR", 0x5D, 3, absoluteXIndexed, execEOR), + 0x59: newOp("EOR", 0x59, 3, absoluteYIndexed, execEOR), + 0x41: newOp("EOR", 0x41, 2, indirectXIndexed, execEOR), + 0x51: newOp("EOR", 0x51, 2, indirectYIndexed, execEOR), // CMP Compare Memory with Accumulator // addressing assembler opc bytes cyles @@ -379,14 +379,14 @@ var opcodes = map[uint8]op{ // absolute,Y CMP oper,Y D9 3 4* // (indirect,X) CMP (oper,X) C1 2 6 // (indirect),Y CMP (oper),Y D1 2 5* - 0xC9: newOp("CMP", 0xC9, 2, immediate, todo), - 0xC5: newOp("CMP", 0xC5, 2, zeroPage, todo), - 0xD5: newOp("CMP", 0xD5, 2, zeroPageXIndexed, todo), - 0xCD: newOp("CMP", 0xCD, 3, absolute, todo), - 0xDD: newOp("CMP", 0xDD, 3, absoluteXIndexed, todo), - 0xD9: newOp("CMP", 0xD9, 3, absoluteYIndexed, todo), - 0xC1: newOp("CMP", 0xC1, 2, indirectXIndexed, todo), - 0xD1: newOp("CMP", 0xD1, 2, indirectYIndexed, todo), + 0xC9: newOp("CMP", 0xC9, 2, immediate, execCMP), + 0xC5: newOp("CMP", 0xC5, 2, zeroPage, execCMP), + 0xD5: newOp("CMP", 0xD5, 2, zeroPageXIndexed, execCMP), + 0xCD: newOp("CMP", 0xCD, 3, absolute, execCMP), + 0xDD: newOp("CMP", 0xDD, 3, absoluteXIndexed, execCMP), + 0xD9: newOp("CMP", 0xD9, 3, absoluteYIndexed, execCMP), + 0xC1: newOp("CMP", 0xC1, 2, indirectXIndexed, execCMP), + 0xD1: newOp("CMP", 0xD1, 2, indirectYIndexed, execCMP), // CPY Compare Memory and Index Y // addressing assembler opc bytes cyles @@ -394,119 +394,119 @@ var opcodes = map[uint8]op{ // immidiate CPY #oper C0 2 2 // zeropage CPY oper C4 2 3 // absolute CPY oper CC 3 4 - 0xC0: newOp("CPY", 0xC0, 2, immediate, todo), - 0xC4: newOp("CPY", 0xC4, 2, zeroPage, todo), - 0xCC: newOp("CPY", 0xCC, 3, absolute, todo), + 0xC0: newOp("CPY", 0xC0, 2, immediate, execCPY), + 0xC4: newOp("CPY", 0xC4, 2, zeroPage, execCPY), + 0xCC: newOp("CPY", 0xCC, 3, absolute, execCPY), // CLC Clear Carry Flag // addressing assembler opc bytes cyles // -------------------------------------------- // implied CLC 18 1 2 - 0x18: newOp("CLC", 0x18, 1, implied, todo), + 0x18: newOp("CLC", 0x18, 1, implied, execCLC), // CLD Clear Decimal Mode // addressing assembler opc bytes cyles // -------------------------------------------- // implied CLD D8 1 2 - 0xD8: newOp("CLD", 0xD8, 1, implied, todo), + 0xD8: newOp("CLD", 0xD8, 1, implied, execCLD), // CLI Clear Interrupt Disable Bit // addressing assembler opc bytes cyles // -------------------------------------------- // implied CLI 58 1 2 - 0x58: newOp("CLI", 0x58, 1, implied, todo), + 0x58: newOp("CLI", 0x58, 1, implied, execCLI), // CLV Clear Overflow Flag // addressing assembler opc bytes cyles // -------------------------------------------- // implied CLV B8 1 2 - 0xB8: newOp("CLV", 0xB8, 1, implied, todo), + 0xB8: newOp("CLV", 0xB8, 1, implied, execCLV), // SEC Set Carry Flag // addressing assembler opc bytes cyles // -------------------------------------------- // implied SEC 38 1 2 - 0x38: newOp("SEC", 0x38, 1, implied, todo), + 0x38: newOp("SEC", 0x38, 1, implied, execSEC), // SED Set Decimal Flag // addressing assembler opc bytes cyles // -------------------------------------------- // implied SED F8 1 2 - 0xF8: newOp("SED", 0xF8, 1, implied, todo), + 0xF8: newOp("SED", 0xF8, 1, implied, execSED), // SEI Set Interrupt Disable Status // addressing assembler opc bytes cyles // -------------------------------------------- // implied SEI 78 1 2 - 0x78: newOp("SEI", 0x78, 1, implied, todo), + 0x78: newOp("SEI", 0x78, 1, implied, execSEI), // NOP No Operation // addressing assembler opc bytes cyles // -------------------------------------------- // implied NOP EA 1 2 - 0xEA: newOp("NOP", 0xEA, 1, implied, todo), + 0xEA: newOp("NOP", 0xEA, 1, implied, execNOP), // JMP Jump to New Location // addressing assembler opc bytes cyles // -------------------------------------------- // absolute JMP oper 4C 3 3 // indirect JMP (oper) 6C 3 5 - 0x4C: newOp("JMP", 0x4C, 3, absolute, todo), - 0x6C: newOp("JMP", 0x6C, 3, indirect, todo), + 0x4C: newOp("JMP", 0x4C, 3, absolute, execJMP), + 0x6C: newOp("JMP", 0x6C, 3, indirect, execJMP), // PHA Push Accumulator on Stack // addressing assembler opc bytes cyles // -------------------------------------------- // implied PHA 48 1 3 - 0x48: newOp("PHA", 0x48, 1, implied, todo), + 0x48: newOp("PHA", 0x48, 1, implied, execPHA), // TXA Transfer Index X to Accumulator // addressing assembler opc bytes cyles // -------------------------------------------- // implied TXA 8A 1 2 - 0x8A: newOp("TXA", 0x8A, 1, implied, todo), + 0x8A: newOp("TXA", 0x8A, 1, implied, execTXA), // TYA Transfer Index Y to Accumulator // addressing assembler opc bytes cyles // -------------------------------------------- // implied TYA 98 1 2 - 0x98: newOp("TYA", 0x98, 1, implied, todo), + 0x98: newOp("TYA", 0x98, 1, implied, execTYA), // TSX Transfer Stack Pointer to Index X // addressing assembler opc bytes cyles // -------------------------------------------- // implied TSX BA 1 2 - 0xBA: newOp("TSX", 0xBA, 1, implied, todo), + 0xBA: newOp("TSX", 0xBA, 1, implied, execTSX), // PLA Pull Accumulator from Stack // addressing assembler opc bytes cyles // -------------------------------------------- // implied PLA 68 1 4 - 0x68: newOp("PLA", 0x68, 1, implied, todo), + 0x68: newOp("PLA", 0x68, 1, implied, execPLA), // PLP Pull Processor Status from Stack // addressing assembler opc bytes cyles // -------------------------------------------- // implied PLP 28 1 4 - 0x28: newOp("PLP", 0x28, 1, implied, todo), + 0x28: newOp("PLP", 0x28, 1, implied, execPLP), // PHP Push Processor Status on Stack // addressing assembler opc bytes cyles // -------------------------------------------- // implied PHP 08 1 3 - 0x08: newOp("PHP", 0x08, 1, implied, todo), + 0x08: newOp("PHP", 0x08, 1, implied, execPHP), // JSR Jump to New Location Saving Return Address // addressing assembler opc bytes cyles // -------------------------------------------- // absolute JSR oper 20 3 6 - 0x20: newOp("JSR", 0x20, 3, absolute, todo), + 0x20: newOp("JSR", 0x20, 3, absolute, execJSR), // RTS Return from Subroutine // addressing assembler opc bytes cyles // -------------------------------------------- // implied RTS 60 1 6 - 0x60: newOp("RTS", 0x60, 1, implied, todo), + 0x60: newOp("RTS", 0x60, 1, implied, execRTS), // LSR Shift One Bit Right (Memory or Accumulator) // addressing assembler opc bytes cyles @@ -516,11 +516,11 @@ var opcodes = map[uint8]op{ // zeropage,X LSR oper,X 56 2 6 // absolute LSR oper 4E 3 6 // absolute,X LSR oper,X 5E 3 7 - 0x4A: newOp("LSR", 0x4A, 1, accumulator, todo), - 0x46: newOp("LSR", 0x46, 2, zeroPage, todo), - 0x56: newOp("LSR", 0x56, 2, zeroPageXIndexed, todo), - 0x4E: newOp("LSR", 0x4E, 3, absolute, todo), - 0x5E: newOp("LSR", 0x5E, 3, absoluteXIndexed, todo), + 0x4A: newOp("LSR", 0x4A, 1, accumulator, execLSR), + 0x46: newOp("LSR", 0x46, 2, zeroPage, execLSR), + 0x56: newOp("LSR", 0x56, 2, zeroPageXIndexed, execLSR), + 0x4E: newOp("LSR", 0x4E, 3, absolute, execLSR), + 0x5E: newOp("LSR", 0x5E, 3, absoluteXIndexed, execLSR), // ROL Rotate One Bit Left (Memory or Accumulator) // addressing assembler opc bytes cyles @@ -530,17 +530,17 @@ var opcodes = map[uint8]op{ // zeropage,X ROL oper,X 36 2 6 // absolute ROL oper 2E 3 6 // absolute,X ROL oper,X 3E 3 7 - 0x2A: newOp("ROL", 0x2A, 1, accumulator, todo), - 0x26: newOp("ROL", 0x26, 2, zeroPage, todo), - 0x36: newOp("ROL", 0x36, 2, zeroPageXIndexed, todo), - 0x2E: newOp("ROL", 0x2E, 3, absolute, todo), - 0x3E: newOp("ROL", 0x3E, 3, absoluteXIndexed, todo), + 0x2A: newOp("ROL", 0x2A, 1, accumulator, execROL), + 0x26: newOp("ROL", 0x26, 2, zeroPage, execROL), + 0x36: newOp("ROL", 0x36, 2, zeroPageXIndexed, execROL), + 0x2E: newOp("ROL", 0x2E, 3, absolute, execROL), + 0x3E: newOp("ROL", 0x3E, 3, absoluteXIndexed, execROL), // TXS Transfer Index X to Stack Register // addressing assembler opc bytes cyles // -------------------------------------------- // implied TXS 9A 1 2 - 0x9A: newOp("TXS", 0x9A, 1, implied, todo), + 0x9A: newOp("TXS", 0x9A, 1, implied, execTXS), // ROR Rotate One Bit Right (Memory or Accumulator) // addressing assembler opc bytes cyles @@ -550,11 +550,11 @@ var opcodes = map[uint8]op{ // zeropage,X ROR oper,X 76 2 6 // absolute ROR oper 6E 3 6 // absolute,X ROR oper,X 7E 3 7 - 0x6A: newOp("ROR", 0x6A, 1, accumulator, todo), - 0x66: newOp("ROR", 0x66, 2, zeroPage, todo), - 0x76: newOp("ROR", 0x76, 2, zeroPageXIndexed, todo), - 0x6E: newOp("ROR", 0x6E, 3, absolute, todo), - 0x7E: newOp("ROR", 0x7E, 3, absoluteXIndexed, todo), + 0x6A: newOp("ROR", 0x6A, 1, accumulator, execROR), + 0x66: newOp("ROR", 0x66, 2, zeroPage, execROR), + 0x76: newOp("ROR", 0x76, 2, zeroPageXIndexed, execROR), + 0x6E: newOp("ROR", 0x6E, 3, absolute, execROR), + 0x7E: newOp("ROR", 0x7E, 3, absoluteXIndexed, execROR), // ASL Shift Left One Bit (Memory or Accumulator) // addressing assembler opc bytes cyles @@ -564,11 +564,11 @@ var opcodes = map[uint8]op{ // zeropage,X ASL oper,X 16 2 6 // absolute ASL oper 0E 3 6 // absolute,X ASL oper,X 1E 3 7 - 0x0A: newOp("ASL", 0x0A, 1, accumulator, todo), - 0x06: newOp("ASL", 0x06, 2, zeroPage, todo), - 0x16: newOp("ASL", 0x16, 2, zeroPageXIndexed, todo), - 0x0E: newOp("ASL", 0x0E, 3, absolute, todo), - 0x1E: newOp("ASL", 0x1E, 3, absoluteXIndexed, todo), + 0x0A: newOp("ASL", 0x0A, 1, accumulator, execASL), + 0x06: newOp("ASL", 0x06, 2, zeroPage, execASL), + 0x16: newOp("ASL", 0x16, 2, zeroPageXIndexed, execASL), + 0x0E: newOp("ASL", 0x0E, 3, absolute, execASL), + 0x1E: newOp("ASL", 0x1E, 3, absoluteXIndexed, execASL), // AND AND Memory with Accumulator // addressing assembler opc bytes cyles @@ -581,14 +581,14 @@ var opcodes = map[uint8]op{ // absolute,Y AND oper,Y 39 3 4* // (indirect,X) AND (oper,X) 21 2 6 // (indirect),Y AND (oper),Y 31 2 5* - 0x29: newOp("AND", 0x29, 2, immediate, todo), - 0x25: newOp("AND", 0x25, 2, zeroPage, todo), - 0x35: newOp("AND", 0x35, 2, zeroPageXIndexed, todo), - 0x2D: newOp("AND", 0x2D, 3, absolute, todo), - 0x3D: newOp("AND", 0x3D, 3, absoluteXIndexed, todo), - 0x39: newOp("AND", 0x39, 3, absoluteYIndexed, todo), - 0x21: newOp("AND", 0x21, 2, indirectXIndexed, todo), - 0x31: newOp("AND", 0x31, 2, indirectYIndexed, todo), + 0x29: newOp("AND", 0x29, 2, immediate, execAND), + 0x25: newOp("AND", 0x25, 2, zeroPage, execAND), + 0x35: newOp("AND", 0x35, 2, zeroPageXIndexed, execAND), + 0x2D: newOp("AND", 0x2D, 3, absolute, execAND), + 0x3D: newOp("AND", 0x3D, 3, absoluteXIndexed, execAND), + 0x39: newOp("AND", 0x39, 3, absoluteYIndexed, execAND), + 0x21: newOp("AND", 0x21, 2, indirectXIndexed, execAND), + 0x31: newOp("AND", 0x31, 2, indirectYIndexed, execAND), // ORA OR Memory with Accumulator // addressing assembler opc bytes cyles @@ -601,12 +601,12 @@ var opcodes = map[uint8]op{ // absolute,Y ORA oper,Y 19 3 4* // (indirect,X) ORA (oper,X) 01 2 6 // (indirect),Y ORA (oper),Y 11 2 5* - 0x09: newOp("ORA", 0x09, 2, immediate, todo), - 0x05: newOp("ORA", 0x05, 2, zeroPage, todo), - 0x15: newOp("ORA", 0x15, 2, zeroPageXIndexed, todo), - 0x0D: newOp("ORA", 0x0D, 3, absolute, todo), - 0x1D: newOp("ORA", 0x1D, 3, absoluteXIndexed, todo), - 0x19: newOp("ORA", 0x19, 3, absoluteYIndexed, todo), - 0x01: newOp("ORA", 0x01, 2, indirectXIndexed, todo), - 0x11: newOp("ORA", 0x11, 2, indirectYIndexed, todo), + 0x09: newOp("ORA", 0x09, 2, immediate, execORA), + 0x05: newOp("ORA", 0x05, 2, zeroPage, execORA), + 0x15: newOp("ORA", 0x15, 2, zeroPageXIndexed, execORA), + 0x0D: newOp("ORA", 0x0D, 3, absolute, execORA), + 0x1D: newOp("ORA", 0x1D, 3, absoluteXIndexed, execORA), + 0x19: newOp("ORA", 0x19, 3, absoluteYIndexed, execORA), + 0x01: newOp("ORA", 0x01, 2, indirectXIndexed, execORA), + 0x11: newOp("ORA", 0x11, 2, indirectYIndexed, execORA), } diff --git a/internal/vm/vm.go b/internal/vm/vm.go index 2e98b07..ec19a46 100644 --- a/internal/vm/vm.go +++ b/internal/vm/vm.go @@ -18,7 +18,7 @@ func New() *Appleone { } } -func (a *Appleone) load(addr uint16, data []uint8) { +func (a *Appleone) load(addr uint16, data []byte) { a.mem.load(addr, data) a.cpu.pc = addr } @@ -36,27 +36,27 @@ func (a *Appleone) step() { } } -func (a *Appleone) littleEndianToUint16(big, little uint8) uint16 { +func (a *Appleone) littleEndianToUint16(big, little byte) uint16 { return uint16(a.mem[big])<<8 | uint16(a.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 = uint8((uint16(a.cpu.sp) - 1) & 0xFF) + a.cpu.sp = byte((uint16(a.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) { - h := uint8((data >> 8) & 0xFF) - l := uint8(data & 0xFF) + h := byte((data >> 8) & 0xFF) + l := byte(data & 0xFF) a.pushWordToStack(h) a.pushWordToStack(l) } // popStackWord sets the new stack pointer and returns the appropriate byte in memory -func (a *Appleone) popStackWord() uint8 { - a.cpu.sp = uint8((uint16(a.cpu.sp) + 1) & 0xFF) +func (a *Appleone) popStackWord() byte { + a.cpu.sp = byte((uint16(a.cpu.sp) + 1) & 0xFF) return a.mem[StackBottom+uint16(a.cpu.sp)] } @@ -68,7 +68,7 @@ func (a *Appleone) popStackDWord() uint16 { } // nextWord returns the next byte in memory -func (a *Appleone) nextWord() uint8 { +func (a *Appleone) nextWord() byte { return a.mem[a.cpu.pc-1] } @@ -77,7 +77,7 @@ func (a *Appleone) nextDWord() uint16 { return a.littleEndianToUint16(a.mem[a.cpu.pc-1], a.mem[a.cpu.pc-2]) } -func (a *Appleone) setZeroIfNeeded(word uint8) { +func (a *Appleone) setZeroIfNeeded(word byte) { a.clearZero() if word == 0 { a.setZero() @@ -92,7 +92,11 @@ func (a *Appleone) clearZero() { a.cpu.sp &^= flagZero } -func (a *Appleone) setNegativeIfOverflow(word uint8) { +func (a *Appleone) getNegative() byte { + return a.cpu.ps & flagNegative +} + +func (a *Appleone) setNegativeIfOverflow(word byte) { a.clearNegative() if word > 127 { a.setNegative() @@ -107,7 +111,7 @@ func (a *Appleone) clearNegative() { a.cpu.sp &^= flagZero } -func (a *Appleone) getCarry() uint8 { +func (a *Appleone) getCarry() byte { return a.cpu.sp & flagCarry } @@ -119,6 +123,10 @@ func (a *Appleone) clearCarry() { a.cpu.sp &^= flagCarry } +func (a *Appleone) getOverflow() byte { + return a.cpu.ps & flagOverflow +} + func (a *Appleone) setOverflow() { a.cpu.sp |= flagOverflow } @@ -126,3 +134,53 @@ func (a *Appleone) setOverflow() { func (a *Appleone) clearOverflow() { a.cpu.sp &^= flagOverflow } + +func (a *Appleone) getZero() byte { + return a.cpu.ps & flagZero +} + +func (a *Appleone) branch(o op) error { + offset, err := o.getOperand(a) + if err != nil { + return err + } + if offset > 127 { + a.cpu.pc -= 256 - uint16(offset) + } else { + a.cpu.pc += uint16(offset) + } + return nil +} + +func (a *Appleone) compare(b1, b2 byte) { + a.clearZero() + a.clearCarry() + a.clearNegative() + + if b1 == b2 { + a.setZero() + a.setCarry() + } + if b1 > b2 { + a.setCarry() + } + + sum := byte(uint16(b1) - uint16(b2)) + a.setNegativeIfOverflow(sum) +} + +func (a *Appleone) setDec() { + a.cpu.sp |= flagDecimalMode +} + +func (a *Appleone) clearDec() { + a.cpu.sp &^= flagDecimalMode +} + +func (a *Appleone) setInterrupt() { + a.cpu.sp |= flagDisableInterrupts +} + +func (a *Appleone) clearInterrupt() { + a.cpu.sp &^= flagDisableInterrupts +}