From b7d2356f783e703c08fa1b1f143aa48b52a9e38e Mon Sep 17 00:00:00 2001 From: edmccard Date: Fri, 6 Apr 2012 18:25:44 -0400 Subject: [PATCH 01/27] raw opcodes --- cmos.txt | 1401 +++++++++++++++++++++++++++++++++++++++++++++++ nmos.txt | 1609 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 3010 insertions(+) create mode 100644 cmos.txt create mode 100644 nmos.txt diff --git a/cmos.txt b/cmos.txt new file mode 100644 index 0000000..a2d670e --- /dev/null +++ b/cmos.txt @@ -0,0 +1,1401 @@ +override void opcode18() +{ +peek(programCounter); +flag.carry = false; +} + +override void opcode38() +{ +peek(programCounter); +flag.carry = true; +} + +override void opcode58() +{ +peek(programCounter); +flag.interrupt = false; +} + +override void opcode78() +{ +peek(programCounter); +flag.interrupt = true; +} + +override void opcodeB8() +{ +peek(programCounter); +flag.overflow = false; +} + +override void opcodeD8() +{ +peek(programCounter); +flag.decimal = false; +} + +override void opcodeF8() +{ +peek(programCounter); +flag.decimal = true; +} + +override void opcodeEA() +{ +peek(programCounter); + +} + +override void opcode08() +{ +peek(programCounter); +push(flag.toByte()); +} + +override void opcode28() +{ +peek(programCounter); +flag.fromByte(pull()); +} + +override void opcode48() +{ +peek(programCounter); +push(accumulator); +} + +override void opcode9A() +{ +peek(programCounter); +stackPointer = xIndex; +} + +override void opcode68() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = pull()); +} + +override void opcodeBA() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (xIndex = stackPointer); +} + +override void opcodeAA() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (xIndex = accumulator); +} + +override void opcode8A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = xIndex); +} + +override void opcodeCA() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (xIndex -= 1); +} + +override void opcodeE8() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (xIndex += 1); +} + +override void opcodeA8() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (yIndex = accumulator); +} + +override void opcode98() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = yIndex); +} + +override void opcode88() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (yIndex -= 1); +} + +override void opcodeC8() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (yIndex += 1); +} + +override void opcode10() +{ +readByteOperand(); +if (flag.negative_ < 0x80) addrRelative(cast(byte)operand1); +} + +override void opcode30() +{ +readByteOperand(); +if (flag.negative_ > 0x7F) addrRelative(cast(byte)operand1); +} + +override void opcode50() +{ +readByteOperand(); +if (!flag.overflow) addrRelative(cast(byte)operand1); +} + +override void opcode70() +{ +readByteOperand(); +if (flag.overflow) addrRelative(cast(byte)operand1); +} + +override void opcode90() +{ +readByteOperand(); +if (!flag.carry) addrRelative(cast(byte)operand1); +} + +override void opcodeB0() +{ +readByteOperand(); +if (flag.carry) addrRelative(cast(byte)operand1); +} + +override void opcodeD0() +{ +readByteOperand(); +if (flag.zero_ != 0) addrRelative(cast(byte)operand1); +} + +override void opcodeF0() +{ +readByteOperand(); +if (flag.zero_ == 0) addrRelative(cast(byte)operand1); +} + +override void opcode0A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = shiftLeft(accumulator)); +} + +override void opcode2A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = rotateLeft(accumulator)); +} + +override void opcode4A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = shiftRight(accumulator)); +} + +override void opcode6A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = rotateRight(accumulator)); +} + +override void opcodeA1() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeA5() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeA9() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcodeAD() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeB1() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeB5() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeB9() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeBD() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} + +override void opcode01() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode05() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode09() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcode0D() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode11() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode15() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode19() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode1D() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} + +override void opcode21() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode25() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode29() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcode2D() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode31() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode35() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode39() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode3D() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} + +override void opcode41() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode45() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode49() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcode4D() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode51() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode55() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode59() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode5D() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} + +override void opcode61() +{ +addrIndirectX(); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode65() +{ +addrZeropage(); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode69() +{ +primaryAddress = programCounter++; +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +operand1 = readVal; +} +override void opcode6D() +{ +addrAbsolute(); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode71() +{ +addrIndirectY(false); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode75() +{ +addrZeropageX(); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode79() +{ +addrAbsoluteY(false); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode7D() +{ +addrAbsoluteX(false); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} + +override void opcodeE1() +{ +addrIndirectX(); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeE5() +{ +addrZeropage(); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeE9() +{ +primaryAddress = programCounter++; +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +operand1 = readVal; +} +override void opcodeED() +{ +addrAbsolute(); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeF1() +{ +addrIndirectY(false); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeF5() +{ +addrZeropageX(); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeF9() +{ +addrAbsoluteY(false); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeFD() +{ +addrAbsoluteX(false); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} + +override void opcodeC1() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeC5() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeC9() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +operand1 = readVal; +} +override void opcodeCD() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeD1() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeD5() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeD9() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeDD() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} + +override void opcode81() +{ +addrIndirectX(); +writeFinal(primaryAddress, accumulator); +} +override void opcode85() +{ +addrZeropage(); +writeFinal(primaryAddress, accumulator); +} +override void opcode8D() +{ +addrAbsolute(); +writeFinal(primaryAddress, accumulator); +} +override void opcode91() +{ +addrIndirectY(true); +writeFinal(primaryAddress, accumulator); +} +override void opcode95() +{ +addrZeropageX(); +writeFinal(primaryAddress, accumulator); +} +override void opcode99() +{ +addrAbsoluteY(true); +writeFinal(primaryAddress, accumulator); +} +override void opcode9D() +{ +addrAbsoluteX(true); +writeFinal(primaryAddress, accumulator); +} + +override void opcodeA2() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (xIndex = (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcodeA6() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeAE() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeB6() +{ +addrZeropageY(); +flag.zero_ = flag.negative_ = (xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeBE() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (xIndex = (readVal = readFinal(primaryAddress))); +} + +override void opcodeA0() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (yIndex = (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcodeA4() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (yIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeAC() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (yIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeB4() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (yIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeBC() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (yIndex = (readVal = readFinal(primaryAddress))); +} + +override void opcodeE0() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (compare(xIndex, (readVal = readFinal(primaryAddress)))); +operand1 = readVal; +} +override void opcodeE4() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (compare(xIndex, (readVal = readFinal(primaryAddress)))); +} +override void opcodeEC() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (compare(xIndex, (readVal = readFinal(primaryAddress)))); +} + +override void opcodeC0() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (compare(yIndex, (readVal = readFinal(primaryAddress)))); +operand1 = readVal; +} +override void opcodeC4() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (compare(yIndex, (readVal = readFinal(primaryAddress)))); +} +override void opcodeCC() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (compare(yIndex, (readVal = readFinal(primaryAddress)))); +} + +override void opcode86() +{ +addrZeropage(); +writeFinal(primaryAddress, xIndex); +} +override void opcode8E() +{ +addrAbsolute(); +writeFinal(primaryAddress, xIndex); +} +override void opcode96() +{ +addrZeropageY(); +writeFinal(primaryAddress, xIndex); +} + +override void opcode84() +{ +addrZeropage(); +writeFinal(primaryAddress, yIndex); +} +override void opcode8C() +{ +addrAbsolute(); +writeFinal(primaryAddress, yIndex); +} +override void opcode94() +{ +addrZeropageX(); +writeFinal(primaryAddress, yIndex); +} + +override void opcode24() +{ +addrZeropage(); +bitTest(readVal = readFinal(primaryAddress)); +} +override void opcode2C() +{ +addrAbsolute(); +bitTest(readVal = readFinal(primaryAddress)); +} + +override void opcode06() +{ +addrZeropage(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = shiftLeft(readVal = read(primaryAddress)))); +} +override void opcode0E() +{ +addrAbsolute(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = shiftLeft(readVal = read(primaryAddress)))); +} +override void opcode16() +{ +addrZeropageX(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = shiftLeft(readVal = read(primaryAddress)))); +} +override void opcode1E() +{ +addrAbsoluteX(false); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = shiftLeft(readVal = read(primaryAddress)))); +} + +override void opcode46() +{ +addrZeropage(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = shiftRight(readVal = read(primaryAddress)))); +} +override void opcode4E() +{ +addrAbsolute(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = shiftRight(readVal = read(primaryAddress)))); +} +override void opcode56() +{ +addrZeropageX(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = shiftRight(readVal = read(primaryAddress)))); +} +override void opcode5E() +{ +addrAbsoluteX(false); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = shiftRight(readVal = read(primaryAddress)))); +} + +override void opcode26() +{ +addrZeropage(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = rotateLeft(readVal = read(primaryAddress)))); +} +override void opcode2E() +{ +addrAbsolute(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = rotateLeft(readVal = read(primaryAddress)))); +} +override void opcode36() +{ +addrZeropageX(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = rotateLeft(readVal = read(primaryAddress)))); +} +override void opcode3E() +{ +addrAbsoluteX(false); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = rotateLeft(readVal = read(primaryAddress)))); +} + +override void opcode66() +{ +addrZeropage(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = rotateRight(readVal = read(primaryAddress)))); +} +override void opcode6E() +{ +addrAbsolute(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = rotateRight(readVal = read(primaryAddress)))); +} +override void opcode76() +{ +addrZeropageX(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = rotateRight(readVal = read(primaryAddress)))); +} +override void opcode7E() +{ +addrAbsoluteX(false); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = rotateRight(readVal = read(primaryAddress)))); +} + +override void opcodeE6() +{ +addrZeropage(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = increment(readVal = read(primaryAddress)))); +} +override void opcodeEE() +{ +addrAbsolute(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = increment(readVal = read(primaryAddress)))); +} +override void opcodeF6() +{ +addrZeropageX(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = increment(readVal = read(primaryAddress)))); +} + +override void opcodeC6() +{ +addrZeropage(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = decrement(readVal = read(primaryAddress)))); +} +override void opcodeCE() +{ +addrAbsolute(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = decrement(readVal = read(primaryAddress)))); +} +override void opcodeD6() +{ +addrZeropageX(); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = decrement(readVal = read(primaryAddress)))); +} + +override void opcodeFE() +{ +addrAbsoluteX(true); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = increment(readVal = read(primaryAddress)))); +} + +override void opcodeDE() +{ +addrAbsoluteX(true); +peek(primaryAddress); +writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = decrement(readVal = read(primaryAddress)))); +} + +override void opcode34() +{ +addrZeropageX(); +bitTest(readVal = readFinal(primaryAddress)); +} +override void opcode3C() +{ +addrAbsoluteX(false); +bitTest(readVal = readFinal(primaryAddress)); +} + +override void opcode12() +{ +addrZeropageI(); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} + +override void opcode32() +{ +addrZeropageI(); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} + +override void opcode52() +{ +addrZeropageI(); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} + +override void opcodeB2() +{ +addrZeropageI(); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} + +override void opcodeD2() +{ +addrZeropageI(); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} + +override void opcode72() +{ +addrZeropageI(); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} + +override void opcodeF2() +{ +addrZeropageI(); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} + +override void opcode92() +{ +addrZeropageI(); +writeFinal(primaryAddress, accumulator); +} + +override void opcode3A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator -= 1); +} + +override void opcode1A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator += 1); +} + +override void opcodeDA() +{ +peek(programCounter); +push(xIndex); +} + +override void opcode5A() +{ +peek(programCounter); +push(yIndex); +} + +override void opcodeFA() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (xIndex = pull()); +} + +override void opcode7A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (yIndex = pull()); +} + +override void opcode80() +{ +readByteOperand(); +if (true) addrRelative(cast(byte)operand1); +} + +override void opcode14() +{ +addrZeropage(); +peek(primaryAddress); +writeFinal(primaryAddress, testReset(readVal = read(primaryAddress))); +} +override void opcode1C() +{ +addrAbsolute; +peek(primaryAddress); +writeFinal(primaryAddress, testReset(readVal = read(primaryAddress))); +} + +override void opcode04() +{ +addrZeropage(); +peek(primaryAddress); +writeFinal(primaryAddress, testSet(readVal = read(primaryAddress))); +} +override void opcode0C() +{ +addrAbsolute(); +peek(primaryAddress); +writeFinal(primaryAddress, testSet(readVal = read(primaryAddress))); +} + +override void opcode64() +{ +addrZeropage(); +writeFinal(primaryAddress, 0); +} +override void opcode74() +{ +addrZeropageX(); +writeFinal(primaryAddress, 0); +} +override void opcode9C() +{ +addrAbsolute(); +writeFinal(primaryAddress, 0); +} +override void opcode9E() +{ +addrAbsoluteX(true); +writeFinal(primaryAddress, 0); +} + +override void opcode02() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} +override void opcode22() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} +override void opcode42() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} +override void opcode62() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} +override void opcode82() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} +override void opcodeC2() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} +override void opcodeE2() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} + +override void opcode44() +{ +addrZeropage(); +readVal = readFinal(primaryAddress); +} + +override void opcode54() +{ +addrZeropageX(); +readVal = readFinal(primaryAddress); +} +override void opcodeD4() +{ +addrZeropageX(); +readVal = readFinal(primaryAddress); +} +override void opcodeF4() +{ +addrZeropageX(); +readVal = readFinal(primaryAddress); +} + +override void opcodeDC() +{ +addrAbsoluteX(false); +readVal = readFinal(primaryAddress); +} +override void opcodeFC() +{ +addrAbsoluteX(false); +readVal = readFinal(primaryAddress); +} + +override void opcode03() +{ +addrNone(); +} +override void opcode13() +{ +addrNone(); +} +override void opcode23() +{ +addrNone(); +} +override void opcode33() +{ +addrNone(); +} +override void opcode43() +{ +addrNone(); +} +override void opcode53() +{ +addrNone(); +} +override void opcode63() +{ +addrNone(); +} +override void opcode73() +{ +addrNone(); +} +override void opcode83() +{ +addrNone(); +} +override void opcode93() +{ +addrNone(); +} +override void opcodeA3() +{ +addrNone(); +} +override void opcodeB3() +{ +addrNone(); +} +override void opcodeC3() +{ +addrNone(); +} +override void opcodeD3() +{ +addrNone(); +} +override void opcodeE3() +{ +addrNone(); +} +override void opcodeF3() +{ +addrNone(); +} +override void opcode07() +{ +addrNone(); +} +override void opcode17() +{ +addrNone(); +} +override void opcode27() +{ +addrNone(); +} +override void opcode37() +{ +addrNone(); +} +override void opcode47() +{ +addrNone(); +} +override void opcode57() +{ +addrNone(); +} +override void opcode67() +{ +addrNone(); +} +override void opcode77() +{ +addrNone(); +} +override void opcode87() +{ +addrNone(); +} +override void opcode97() +{ +addrNone(); +} +override void opcodeA7() +{ +addrNone(); +} +override void opcodeB7() +{ +addrNone(); +} +override void opcodeC7() +{ +addrNone(); +} +override void opcodeD7() +{ +addrNone(); +} +override void opcodeE7() +{ +addrNone(); +} +override void opcodeF7() +{ +addrNone(); +} +override void opcode0B() +{ +addrNone(); +} +override void opcode1B() +{ +addrNone(); +} +override void opcode2B() +{ +addrNone(); +} +override void opcode3B() +{ +addrNone(); +} +override void opcode4B() +{ +addrNone(); +} +override void opcode5B() +{ +addrNone(); +} +override void opcode6B() +{ +addrNone(); +} +override void opcode7B() +{ +addrNone(); +} +override void opcode8B() +{ +addrNone(); +} +override void opcode9B() +{ +addrNone(); +} +override void opcodeAB() +{ +addrNone(); +} +override void opcodeBB() +{ +addrNone(); +} +override void opcodeCB() +{ +addrNone(); +} +override void opcodeDB() +{ +addrNone(); +} +override void opcodeEB() +{ +addrNone(); +} +override void opcodeFB() +{ +addrNone(); +} +override void opcode0F() +{ +addrNone(); +} +override void opcode1F() +{ +addrNone(); +} +override void opcode2F() +{ +addrNone(); +} +override void opcode3F() +{ +addrNone(); +} +override void opcode4F() +{ +addrNone(); +} +override void opcode5F() +{ +addrNone(); +} +override void opcode6F() +{ +addrNone(); +} +override void opcode7F() +{ +addrNone(); +} +override void opcode8F() +{ +addrNone(); +} +override void opcode9F() +{ +addrNone(); +} +override void opcodeAF() +{ +addrNone(); +} +override void opcodeBF() +{ +addrNone(); +} +override void opcodeCF() +{ +addrNone(); +} +override void opcodeDF() +{ +addrNone(); +} +override void opcodeEF() +{ +addrNone(); +} +override void opcodeFF() +{ +addrNone(); +} + + /* BRK */ + final override void opcode00() + { + peek(programCounter); + ++programCounter; + doInterrupt(IRQ_VECTOR, flag.toByte()); + } + + /* JSR */ + final override void opcode20() + { + ushort finalAddress = (operand1 = read(programCounter++)); + + peek(STACK_BASE + stackPointer); + pushWord(programCounter); + + finalAddress |= ((operand2 = read(programCounter)) << 8); + static if (cumulative) tick(totalCycles); + programCounter = finalAddress; + } + + /* RTI */ + final override void opcode40() + { + peek(programCounter); + flag.fromByte(pull()); + programCounter = readStack() | (readStack() << 8); + static if (cumulative) tick(totalCycles); + } + + /* JMP $$$$ */ + final override void opcode4C() + { + programCounter = readWordOperand(); + static if (cumulative) tick(totalCycles); + } + + /* RTS */ + final override void opcode60() + { + peek(programCounter); + programCounter = pullWord(); + peek(programCounter); + static if (cumulative) tick(totalCycles); + ++programCounter; + } + + /* NOP8 */ + void opcode5C() + { + readByteOperand(); + peek(programCounter++); + peek(0xFF00 | operand1); + peek(0xFFFF); + peek(0xFFFF); + peek(0xFFFF); + peek(0xFFFF); + static if (cumulative) tick(totalCycles); + } + + /* JMP ($$$$) */ + override void opcode6C() + { + ushort vector = readWordOperand(); + peek(programCounter); + programCounter = readWord(vector, cast(ushort)(vector + 1)); + static if (cumulative) tick(totalCycles); + } + + /* JMP ($$$$,X) */ + void opcode7C() + { + baseAddress = readWordOperand(); + peek(programCounter); + ushort vector = cast(ushort)(baseAddress + xIndex); + programCounter = readWord(vector, cast(ushort)(vector + 1)); + static if (cumulative) tick(totalCycles); + } + + /* BIT #$$ */ + void opcode89() + { + readVal = operand1 = readFinal(programCounter++); + flag.zero_ = accumulator & readVal; + } diff --git a/nmos.txt b/nmos.txt new file mode 100644 index 0000000..d2fa3cc --- /dev/null +++ b/nmos.txt @@ -0,0 +1,1609 @@ +override void opcode18() +{ +peek(programCounter); +flag.carry = false; +} + +override void opcode38() +{ +peek(programCounter); +flag.carry = true; +} + +override void opcode58() +{ +peek(programCounter); +flag.interrupt = false; +} + +override void opcode78() +{ +peek(programCounter); +flag.interrupt = true; +} + +override void opcodeB8() +{ +peek(programCounter); +flag.overflow = false; +} + +override void opcodeD8() +{ +peek(programCounter); +flag.decimal = false; +} + +override void opcodeF8() +{ +peek(programCounter); +flag.decimal = true; +} + +override void opcodeEA() +{ +peek(programCounter); + +} + +override void opcode08() +{ +peek(programCounter); +push(flag.toByte()); +} + +override void opcode28() +{ +peek(programCounter); +flag.fromByte(pull()); +} + +override void opcode48() +{ +peek(programCounter); +push(accumulator); +} + +override void opcode9A() +{ +peek(programCounter); +stackPointer = xIndex; +} + +override void opcode68() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = pull()); +} + +override void opcodeBA() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (xIndex = stackPointer); +} + +override void opcodeAA() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (xIndex = accumulator); +} + +override void opcode8A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = xIndex); +} + +override void opcodeCA() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (xIndex -= 1); +} + +override void opcodeE8() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (xIndex += 1); +} + +override void opcodeA8() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (yIndex = accumulator); +} + +override void opcode98() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = yIndex); +} + +override void opcode88() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (yIndex -= 1); +} + +override void opcodeC8() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (yIndex += 1); +} + +override void opcode10() +{ +readByteOperand(); +if (flag.negative_ < 0x80) addrRelative(cast(byte)operand1); +} + +override void opcode30() +{ +readByteOperand(); +if (flag.negative_ > 0x7F) addrRelative(cast(byte)operand1); +} + +override void opcode50() +{ +readByteOperand(); +if (!flag.overflow) addrRelative(cast(byte)operand1); +} + +override void opcode70() +{ +readByteOperand(); +if (flag.overflow) addrRelative(cast(byte)operand1); +} + +override void opcode90() +{ +readByteOperand(); +if (!flag.carry) addrRelative(cast(byte)operand1); +} + +override void opcodeB0() +{ +readByteOperand(); +if (flag.carry) addrRelative(cast(byte)operand1); +} + +override void opcodeD0() +{ +readByteOperand(); +if (flag.zero_ != 0) addrRelative(cast(byte)operand1); +} + +override void opcodeF0() +{ +readByteOperand(); +if (flag.zero_ == 0) addrRelative(cast(byte)operand1); +} + +override void opcode0A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = shiftLeft(accumulator)); +} + +override void opcode2A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = rotateLeft(accumulator)); +} + +override void opcode4A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = shiftRight(accumulator)); +} + +override void opcode6A() +{ +peek(programCounter); +flag.zero_ = flag.negative_ = (accumulator = rotateRight(accumulator)); +} + +override void opcodeA1() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeA5() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeA9() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcodeAD() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeB1() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeB5() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeB9() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} +override void opcodeBD() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (accumulator = (readVal = readFinal(primaryAddress))); +} + +override void opcode01() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode05() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode09() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcode0D() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode11() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode15() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode19() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} +override void opcode1D() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (accumulator |= (readVal = readFinal(primaryAddress))); +} + +override void opcode21() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode25() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode29() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcode2D() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode31() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode35() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode39() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} +override void opcode3D() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (accumulator &= (readVal = readFinal(primaryAddress))); +} + +override void opcode41() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode45() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode49() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcode4D() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode51() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode55() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode59() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} +override void opcode5D() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (accumulator ^= (readVal = readFinal(primaryAddress))); +} + +override void opcode61() +{ +addrIndirectX(); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode65() +{ +addrZeropage(); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode69() +{ +primaryAddress = programCounter++; +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +operand1 = readVal; +} +override void opcode6D() +{ +addrAbsolute(); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode71() +{ +addrIndirectY(false); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode75() +{ +addrZeropageX(); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode79() +{ +addrAbsoluteY(false); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcode7D() +{ +addrAbsoluteX(false); +if (flag.decimal) dec_addWithCarry(readVal = readFinal(primaryAddress)); +else hex_addWithCarry(readVal = readFinal(primaryAddress)); +} + +override void opcodeE1() +{ +addrIndirectX(); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeE5() +{ +addrZeropage(); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeE9() +{ +primaryAddress = programCounter++; +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +operand1 = readVal; +} +override void opcodeED() +{ +addrAbsolute(); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeF1() +{ +addrIndirectY(false); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeF5() +{ +addrZeropageX(); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeF9() +{ +addrAbsoluteY(false); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} +override void opcodeFD() +{ +addrAbsoluteX(false); +if (flag.decimal) dec_subWithCarry(readVal = readFinal(primaryAddress)); +else hex_subWithCarry(readVal = readFinal(primaryAddress)); +} + +override void opcodeC1() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeC5() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeC9() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +operand1 = readVal; +} +override void opcodeCD() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeD1() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeD5() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeD9() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} +override void opcodeDD() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (compare(accumulator, (readVal = readFinal(primaryAddress)))); +} + +override void opcode81() +{ +addrIndirectX(); +writeFinal(primaryAddress, accumulator); +} +override void opcode85() +{ +addrZeropage(); +writeFinal(primaryAddress, accumulator); +} +override void opcode8D() +{ +addrAbsolute(); +writeFinal(primaryAddress, accumulator); +} +override void opcode91() +{ +addrIndirectY(true); +writeFinal(primaryAddress, accumulator); +} +override void opcode95() +{ +addrZeropageX(); +writeFinal(primaryAddress, accumulator); +} +override void opcode99() +{ +addrAbsoluteY(true); +writeFinal(primaryAddress, accumulator); +} +override void opcode9D() +{ +addrAbsoluteX(true); +writeFinal(primaryAddress, accumulator); +} + +override void opcodeA2() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (xIndex = (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcodeA6() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeAE() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeB6() +{ +addrZeropageY(); +flag.zero_ = flag.negative_ = (xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeBE() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (xIndex = (readVal = readFinal(primaryAddress))); +} + +override void opcodeA0() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (yIndex = (readVal = readFinal(primaryAddress))); +operand1 = readVal; +} +override void opcodeA4() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (yIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeAC() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (yIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeB4() +{ +addrZeropageX(); +flag.zero_ = flag.negative_ = (yIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeBC() +{ +addrAbsoluteX(false); +flag.zero_ = flag.negative_ = (yIndex = (readVal = readFinal(primaryAddress))); +} + +override void opcodeE0() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (compare(xIndex, (readVal = readFinal(primaryAddress)))); +operand1 = readVal; +} +override void opcodeE4() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (compare(xIndex, (readVal = readFinal(primaryAddress)))); +} +override void opcodeEC() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (compare(xIndex, (readVal = readFinal(primaryAddress)))); +} + +override void opcodeC0() +{ +primaryAddress = programCounter++; +flag.zero_ = flag.negative_ = (compare(yIndex, (readVal = readFinal(primaryAddress)))); +operand1 = readVal; +} +override void opcodeC4() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (compare(yIndex, (readVal = readFinal(primaryAddress)))); +} +override void opcodeCC() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (compare(yIndex, (readVal = readFinal(primaryAddress)))); +} + +override void opcode86() +{ +addrZeropage(); +writeFinal(primaryAddress, xIndex); +} +override void opcode8E() +{ +addrAbsolute(); +writeFinal(primaryAddress, xIndex); +} +override void opcode96() +{ +addrZeropageY(); +writeFinal(primaryAddress, xIndex); +} + +override void opcode84() +{ +addrZeropage(); +writeFinal(primaryAddress, yIndex); +} +override void opcode8C() +{ +addrAbsolute(); +writeFinal(primaryAddress, yIndex); +} +override void opcode94() +{ +addrZeropageX(); +writeFinal(primaryAddress, yIndex); +} + +override void opcode24() +{ +addrZeropage(); +bitTest(readVal = readFinal(primaryAddress)); +} +override void opcode2C() +{ +addrAbsolute(); +bitTest(readVal = readFinal(primaryAddress)); +} + +override void opcode06() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = shiftLeft(readVal)); +} +override void opcode0E() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = shiftLeft(readVal)); +} +override void opcode16() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = shiftLeft(readVal)); +} +override void opcode1E() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = shiftLeft(readVal)); +} + +override void opcode46() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = shiftRight(readVal)); +} +override void opcode4E() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = shiftRight(readVal)); +} +override void opcode56() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = shiftRight(readVal)); +} +override void opcode5E() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = shiftRight(readVal)); +} + +override void opcode26() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = rotateLeft(readVal)); +} +override void opcode2E() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = rotateLeft(readVal)); +} +override void opcode36() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = rotateLeft(readVal)); +} +override void opcode3E() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = rotateLeft(readVal)); +} + +override void opcode66() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = rotateRight(readVal)); +} +override void opcode6E() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = rotateRight(readVal)); +} +override void opcode76() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = rotateRight(readVal)); +} +override void opcode7E() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = rotateRight(readVal)); +} + +override void opcodeE6() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = increment(readVal)); +} +override void opcodeEE() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = increment(readVal)); +} +override void opcodeF6() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = increment(readVal)); +} +override void opcodeFE() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = increment(readVal)); +} + +override void opcodeC6() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = decrement(readVal)); +} +override void opcodeCE() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = decrement(readVal)); +} +override void opcodeD6() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = decrement(readVal)); +} +override void opcodeDE() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = decrement(readVal)); +} + +override void opcode02() +{ +addrHalt(); + +} +override void opcode12() +{ +addrHalt(); + +} +override void opcode22() +{ +addrHalt(); + +} +override void opcode32() +{ +addrHalt(); + +} +override void opcode42() +{ +addrHalt(); + +} +override void opcode52() +{ +addrHalt(); + +} +override void opcode62() +{ +addrHalt(); + +} +override void opcode72() +{ +addrHalt(); + +} +override void opcode92() +{ +addrHalt(); + +} +override void opcodeB2() +{ +addrHalt(); + +} +override void opcodeD2() +{ +addrHalt(); + +} +override void opcodeF2() +{ +addrHalt(); + +} + +override void opcode1A() +{ +addrImplied(); +} +override void opcode3A() +{ +addrImplied(); +} +override void opcode5A() +{ +addrImplied(); +} +override void opcode7A() +{ +addrImplied(); +} +override void opcodeDA() +{ +addrImplied(); +} +override void opcodeFA() +{ +addrImplied(); +} + +override void opcode0C() +{ +addrAbsolute(); +readVal = readFinal(primaryAddress); +} + +override void opcode1C() +{ +addrAbsoluteX(false); +readVal = readFinal(primaryAddress); +} +override void opcode3C() +{ +addrAbsoluteX(false); +readVal = readFinal(primaryAddress); +} +override void opcode5C() +{ +addrAbsoluteX(false); +readVal = readFinal(primaryAddress); +} +override void opcode7C() +{ +addrAbsoluteX(false); +readVal = readFinal(primaryAddress); +} +override void opcodeDC() +{ +addrAbsoluteX(false); +readVal = readFinal(primaryAddress); +} +override void opcodeFC() +{ +addrAbsoluteX(false); +readVal = readFinal(primaryAddress); +} + +override void opcode80() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} +override void opcode82() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} +override void opcode89() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} +override void opcodeC2() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} +override void opcodeE2() +{ +primaryAddress = programCounter++; +readVal = readFinal(primaryAddress); +operand1 = readVal; +} + +override void opcode04() +{ +addrZeropage(); +readVal = readFinal(primaryAddress); +} +override void opcode44() +{ +addrZeropage(); +readVal = readFinal(primaryAddress); +} +override void opcode64() +{ +addrZeropage(); +readVal = readFinal(primaryAddress); +} + +override void opcode14() +{ +addrZeropageX(); +readVal = readFinal(primaryAddress); +} +override void opcode34() +{ +addrZeropageX(); +readVal = readFinal(primaryAddress); +} +override void opcode54() +{ +addrZeropageX(); +readVal = readFinal(primaryAddress); +} +override void opcode74() +{ +addrZeropageX(); +readVal = readFinal(primaryAddress); +} +override void opcodeD4() +{ +addrZeropageX(); +readVal = readFinal(primaryAddress); +} +override void opcodeF4() +{ +addrZeropageX(); +readVal = readFinal(primaryAddress); +} + +override void opcodeA3() +{ +addrIndirectX(); +flag.zero_ = flag.negative_ = (accumulator = xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeA7() +{ +addrZeropage(); +flag.zero_ = flag.negative_ = (accumulator = xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeAF() +{ +addrAbsolute(); +flag.zero_ = flag.negative_ = (accumulator = xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeB3() +{ +addrIndirectY(false); +flag.zero_ = flag.negative_ = (accumulator = xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeB7() +{ +addrZeropageY(); +flag.zero_ = flag.negative_ = (accumulator = xIndex = (readVal = readFinal(primaryAddress))); +} +override void opcodeBF() +{ +addrAbsoluteY(false); +flag.zero_ = flag.negative_ = (accumulator = xIndex = (readVal = readFinal(primaryAddress))); +} + +override void opcode83() +{ +addrIndirectX(); +writeFinal(primaryAddress, accumulator & xIndex); +} +override void opcode87() +{ +addrZeropage(); +writeFinal(primaryAddress, accumulator & xIndex); +} +override void opcode97() +{ +addrZeropageY(); +writeFinal(primaryAddress, accumulator & xIndex); +} +override void opcode8F() +{ +addrAbsolute(); +writeFinal(primaryAddress, accumulator & xIndex); +} + +override void opcode03() +{ +addrIndirectX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftLeft(readVal))); +accumulator |= writeVal; +} +override void opcode07() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftLeft(readVal))); +accumulator |= writeVal; +} +override void opcode0F() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftLeft(readVal))); +accumulator |= writeVal; +} +override void opcode13() +{ +addrIndirectY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftLeft(readVal))); +accumulator |= writeVal; +} +override void opcode17() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftLeft(readVal))); +accumulator |= writeVal; +} +override void opcode1B() +{ +addrAbsoluteY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftLeft(readVal))); +accumulator |= writeVal; +} +override void opcode1F() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftLeft(readVal))); +accumulator |= writeVal; +} + +override void opcode23() +{ +addrIndirectX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateLeft(readVal))); +accumulator &= writeVal; +} +override void opcode27() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateLeft(readVal))); +accumulator &= writeVal; +} +override void opcode2F() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateLeft(readVal))); +accumulator &= writeVal; +} +override void opcode33() +{ +addrIndirectY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateLeft(readVal))); +accumulator &= writeVal; +} +override void opcode37() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateLeft(readVal))); +accumulator &= writeVal; +} +override void opcode3B() +{ +addrAbsoluteY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateLeft(readVal))); +accumulator &= writeVal; +} +override void opcode3F() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateLeft(readVal))); +accumulator &= writeVal; +} + +override void opcode43() +{ +addrIndirectX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftRight(readVal))); +accumulator ^= writeVal; +} +override void opcode47() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftRight(readVal))); +accumulator ^= writeVal; +} +override void opcode4F() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftRight(readVal))); +accumulator ^= writeVal; +} +override void opcode53() +{ +addrIndirectY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftRight(readVal))); +accumulator ^= writeVal; +} +override void opcode57() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftRight(readVal))); +accumulator ^= writeVal; +} +override void opcode5B() +{ +addrAbsoluteY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftRight(readVal))); +accumulator ^= writeVal; +} +override void opcode5F() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = shiftRight(readVal))); +accumulator ^= writeVal; +} + +override void opcodeC3() +{ +addrIndirectX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, (writeVal = decrement(readVal))); +flag.zero_ = flag.negative_ = compare(accumulator, writeVal); +} +override void opcodeC7() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, (writeVal = decrement(readVal))); +flag.zero_ = flag.negative_ = compare(accumulator, writeVal); +} +override void opcodeCF() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, (writeVal = decrement(readVal))); +flag.zero_ = flag.negative_ = compare(accumulator, writeVal); +} +override void opcodeD3() +{ +addrIndirectY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, (writeVal = decrement(readVal))); +flag.zero_ = flag.negative_ = compare(accumulator, writeVal); +} +override void opcodeD7() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, (writeVal = decrement(readVal))); +flag.zero_ = flag.negative_ = compare(accumulator, writeVal); +} +override void opcodeDB() +{ +addrAbsoluteY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, (writeVal = decrement(readVal))); +flag.zero_ = flag.negative_ = compare(accumulator, writeVal); +} +override void opcodeDF() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, (writeVal = decrement(readVal))); +flag.zero_ = flag.negative_ = compare(accumulator, writeVal); +} + +override void opcode63() +{ +addrIndirectX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateRight(readVal))); +if (flag.decimal) dec_addWithCarry(writeVal); +else hex_addWithCarry(writeVal); +} +override void opcode67() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateRight(readVal))); +if (flag.decimal) dec_addWithCarry(writeVal); +else hex_addWithCarry(writeVal); +} +override void opcode6F() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateRight(readVal))); +if (flag.decimal) dec_addWithCarry(writeVal); +else hex_addWithCarry(writeVal); +} +override void opcode73() +{ +addrIndirectY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateRight(readVal))); +if (flag.decimal) dec_addWithCarry(writeVal); +else hex_addWithCarry(writeVal); +} +override void opcode77() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateRight(readVal))); +if (flag.decimal) dec_addWithCarry(writeVal); +else hex_addWithCarry(writeVal); +} +override void opcode7B() +{ +addrAbsoluteY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateRight(readVal))); +if (flag.decimal) dec_addWithCarry(writeVal); +else hex_addWithCarry(writeVal); +} +override void opcode7F() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = rotateRight(readVal))); +if (flag.decimal) dec_addWithCarry(writeVal); +else hex_addWithCarry(writeVal); +} + +override void opcodeE3() +{ +addrIndirectX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = increment(readVal))); +if (flag.decimal) dec_subWithCarry(writeVal); +else hex_subWithCarry(writeVal); +} +override void opcodeE7() +{ +addrZeropage(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = increment(readVal))); +if (flag.decimal) dec_subWithCarry(writeVal); +else hex_subWithCarry(writeVal); +} +override void opcodeEF() +{ +addrAbsolute(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = increment(readVal))); +if (flag.decimal) dec_subWithCarry(writeVal); +else hex_subWithCarry(writeVal); +} +override void opcodeF3() +{ +addrIndirectY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = increment(readVal))); +if (flag.decimal) dec_subWithCarry(writeVal); +else hex_subWithCarry(writeVal); +} +override void opcodeF7() +{ +addrZeropageX(); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = increment(readVal))); +if (flag.decimal) dec_subWithCarry(writeVal); +else hex_subWithCarry(writeVal); +} +override void opcodeFB() +{ +addrAbsoluteY(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = increment(readVal))); +if (flag.decimal) dec_subWithCarry(writeVal); +else hex_subWithCarry(writeVal); +} +override void opcodeFF() +{ +addrAbsoluteX(true); +poke(primaryAddress, (readVal = read(primaryAddress))); +writeFinal(primaryAddress, flag.zero_ = flag.negative_ = (writeVal = increment(readVal))); +if (flag.decimal) dec_subWithCarry(writeVal); +else hex_subWithCarry(writeVal); +} + + /* BRK */ + final override void opcode00() + { + peek(programCounter); + ++programCounter; + doInterrupt(IRQ_VECTOR, flag.toByte()); + } + + /* JSR */ + final override void opcode20() + { + ushort finalAddress = (operand1 = read(programCounter++)); + + peek(STACK_BASE + stackPointer); + pushWord(programCounter); + + finalAddress |= ((operand2 = read(programCounter)) << 8); + static if (cumulative) tick(totalCycles); + programCounter = finalAddress; + } + + /* RTI */ + final override void opcode40() + { + peek(programCounter); + flag.fromByte(pull()); + programCounter = readStack() | (readStack() << 8); + static if (cumulative) tick(totalCycles); + } + + /* JMP $$$$ */ + final override void opcode4C() + { + programCounter = readWordOperand(); + static if (cumulative) tick(totalCycles); + } + + /* RTS */ + final override void opcode60() + { + peek(programCounter); + programCounter = pullWord(); + peek(programCounter); + static if (cumulative) tick(totalCycles); + ++programCounter; + } + + /* JMP ($$$$) */ + override void opcode6C() + { + ushort vector = readWordOperand(); + programCounter = readWord(vector, + (vector & 0xFF00) | cast(ubyte)(vector + 1)); + static if (cumulative) tick(totalCycles); + } + /* ANC #$$ */ + override void opcode0B() + { + readVal = operand1 = readFinal(programCounter); + flag.zero_ = flag.negative_ = (accumulator = readVal); + flag.carry = (flag.negative_ > 0x7F); + } + + /* ANC #$$ */ + override void opcode2B() + { + readVal = operand1 = readFinal(programCounter); + flag.zero_ = flag.negative_ = (accumulator = readVal); + flag.carry = (flag.negative_ > 0x7F); + } + + /* ALR #$$ */ + override void opcode4B() + { + readVal = operand1 = readFinal(programCounter); + flag.zero_ = flag.negative_ = + (accumulator = shiftRight(accumulator & readVal)); + } + + /* ARR #$$ */ + override void opcode6B() + { + readVal = operand1 = readFinal(programCounter); + ubyte val = readVal & accumulator; + if (flag.decimal) { + ubyte temp = cast(ubyte)((val >> 1) + (flag.carry ? 0x80 : 0)); + flag.zero_ = flag.negative_ = temp; + flag.overflow = (((temp ^ val) & 0x40) != 0); + if ((readVal & 0x0F) + (val & 0x01) > 5) + temp = (temp & 0xF0) + ((temp + 0x6) & 0x0F); + if (val + (val & 0x10) >= 0x60) + { + temp += 0x60; + flag.carry = true; + } + else + flag.carry = false; + accumulator = temp; + } + else { + accumulator = cast(ubyte)((val >> 1) + (flag.carry ? 0x80 : 0)); + flag.zero_ = flag.negative_ = accumulator; + val >>= 7; + flag.carry = (val != 0); + flag.overflow = ((val ^ ((accumulator >> 5) & 1)) != 0); + } + } + + /* ANE #$$ */ + override void opcode8B() + { + // unstable + readVal = operand1 = readFinal(programCounter++); + + version(Atari8Bit) + { + flag.zero_ = flag.negative_ = + (accumulator & xIndex & readVal); + accumulator &= xIndex & (operand1 | 0xEF); + } + else + { + flag.zero_ = flag.negative_ = + (accumulator &= (xIndex & readVal)); + } + } + + /* SHA ($$),Y */ + void opcode93() + { + addrIndirectY(true); + strange(accumulator & xIndex); + } + + /* SHA $$$$,Y */ + void opcode9F() + { + addrAbsoluteY(true); + strange(accumulator & xIndex); + } + + /* SHS $$$$,Y */ + void opcode9B() + { + addrAbsoluteY(true); + strange(stackPointer = (accumulator & xIndex)); + } + + /* SHY $$$$,X */ + void opcode9C() + { + addrAbsoluteX(true); + strange(yIndex); + } + + /* SHX $$$$,Y */ + void opcode9E() + { + addrAbsoluteY(true); + strange(xIndex); + } + + /* LAX #$$ */ + override void opcodeAB() + { + readVal = operand1 = readFinal(programCounter); + + version(Commodore128) + { + // not unstable? + flag.zero_ = flag.negative_ = + (accumulator = readVal); + } + else + { + // unstable + version(Commodore64) + { + accumulator |= 0xEE; + } + flag.zero_ = flag.negative_ = + (accumulator &= readVal); + } + xIndex = accumulator; + } + + /* LAS $$$$,Y */ + override void opcodeBB() + { + addrAbsoluteY(false); + readVal = readFinal(primaryAddress); + + flag.zero_ = flag.negative_ = + (xIndex = accumulator = (stackPointer & readVal)); + } + + /* SBX #$$ */ + override void opcodeCB() + { + readVal = operand1 = readFinal(programCounter++); + xIndex &= accumulator; + flag.zero_ = flag.negative_ = compare(xIndex, readVal); + } + + /* SBC #$$ */ + override void opcodeEB() + { + readVal = operand1 = readFinal(programCounter++); + if (flag.decimal) dec_subWithCarry(readVal); + else hex_subWithCarry(readVal); + } From 9a758781b587117db8775d256a035d75d547e13b Mon Sep 17 00:00:00 2001 From: edmccard Date: Fri, 6 Apr 2012 23:48:37 -0400 Subject: [PATCH 02/27] New cpu --- src/cpu6502.d | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/cpu6502.d diff --git a/src/cpu6502.d b/src/cpu6502.d new file mode 100644 index 0000000..85c79bc --- /dev/null +++ b/src/cpu6502.d @@ -0,0 +1,45 @@ +module cpu6502; + + +enum Strict : bool +{ + no, yes +} + +enum Cumulative : bool +{ + no, yes +} + + +class Cpu(bool cumulative) +{ + struct _Mem + { + // Reads a value from system memory. + ubyte delegate(ushort addr) read; + + // Writes a value to system memory. + void delegate(ushort addr, ubyte val) write; + } + _Mem memory; + + struct _Clock + { + static if (cumulative) + /* + * Updates the number of cycles executed. Called just + * prior to the final read/write action of each opcode. + */ + void delegate(int cycles) tick; + else + /* + * Increments the number of cycles executed. Called prior + * to each read/write action. + */ + void delegate() tick; + } + _Clock clock; + + ubyte A, X, Y, S, P; +} From 700722c5de8a7359225ac8d7366a93e4e2ad4f10 Mon Sep 17 00:00:00 2001 From: edmccard Date: Fri, 6 Apr 2012 20:44:58 -0400 Subject: [PATCH 03/27] Playing with cpu/world interface --- src/d6502/base.d | 20 ++++++++++++++++---- src/d6502/cpu.d | 40 ++++++++++++++++++++-------------------- src/system/base.d | 6 +++--- test/cpu.d | 26 +++++++++++++------------- 4 files changed, 52 insertions(+), 40 deletions(-) diff --git a/src/d6502/base.d b/src/d6502/base.d index e33dce2..1085e19 100644 --- a/src/d6502/base.d +++ b/src/d6502/base.d @@ -135,14 +135,26 @@ class CpuBase(bool strict, bool cumulative) restore([0, 0, 0, 0, 0, 0xFF, 0, 0, 0, 0, 0, 1]); } - ubyte delegate(ushort addr) memoryRead; - void delegate(ushort addr, ubyte val) memoryWrite; + struct _Mem + { + ubyte delegate(ushort addr) read; + void delegate(ushort addr, ubyte val) write; + } + _Mem memory; + + struct _Clock + { + static if (cumulative) + void delegate(int cycles) tick; + else + void delegate() tick; + } + _Clock clock; + debug(disassemble) { string delegate(ushort addr) memoryName; } - static if (cumulative) void delegate(int cycles) tick; - else void delegate() tick; abstract void run(bool continuous); abstract void stop(); diff --git a/src/d6502/cpu.d b/src/d6502/cpu.d index 97895e5..a8e6356 100644 --- a/src/d6502/cpu.d +++ b/src/d6502/cpu.d @@ -60,8 +60,8 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) } final override void run(bool continuous) { - assert ((memoryRead !is null) && (memoryWrite !is null)); - assert (tick !is null); + assert ((memory.read !is null) && (memory.write !is null)); + assert (clock.tick !is null); continueExecution = continuous; do @@ -139,7 +139,7 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) push(statusByte); flag.interrupt = true; programCounter = readWord(vector, cast(ushort)(vector + 1)); - static if (cumulative) tick(totalCycles); + static if (cumulative) clock.tick(totalCycles); } void doReset() @@ -150,7 +150,7 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) } else { - tick(); tick(); + clock.tick(); clock.tick(); } peek(STACK_BASE + stackPointer); @@ -165,35 +165,35 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) signalActive = testSignals(); programCounter = readWord(RESET_VECTOR, RESET_VECTOR + 1); - static if (cumulative) tick(totalCycles); + static if (cumulative) clock.tick(totalCycles); } final ubyte read(ushort addr) { static if (cumulative) ++totalCycles; - else tick(); - return memoryRead(addr); + else clock.tick(); + return memory.read(addr); } final void write(ushort addr, ubyte val) { static if (cumulative) ++totalCycles; - else tick(); - memoryWrite(addr, val); + else clock.tick(); + memory.write(addr, val); } final void peek(ushort addr) { static if (cumulative) ++totalCycles; - else tick(); - static if (strict) memoryRead(addr); + else clock.tick(); + static if (strict) memory.read(addr); } final void poke(ushort addr, ubyte val) { static if (cumulative) ++totalCycles; - else tick(); - static if (strict) memoryWrite(addr, val); + else clock.tick(); + static if (strict) memory.write(addr, val); } final ubyte readFinal(ushort addr) @@ -461,7 +461,7 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) { string code = "peek(programCounter);\n"; code ~= (action == "") ? "" : (action ~ ";"); - static if (cumulative) code ~= "tick(totalCycles);\n"; + static if (cumulative) code ~= "clock.tick(totalCycles);\n"; return "override void opcode" ~ opcode ~ "()\n{\n" ~ code ~ "\n}\n"; } @@ -474,7 +474,7 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) { string code = "peek(programCounter);\n"; code ~= UpdateNZ(action); - static if (cumulative) code ~= "tick(totalCycles);\n"; + static if (cumulative) code ~= "clock.tick(totalCycles);\n"; return "override void opcode" ~ opcode ~ "()\n{\n" ~ code ~ "}\n"; } @@ -482,7 +482,7 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) { string code = "readByteOperand();\n" ~ "if (" ~ action ~ ") addrRelative(cast(byte)operand1);\n"; - static if (cumulative) code ~= "tick(totalCycles);\n"; + static if (cumulative) code ~= "clock.tick(totalCycles);\n"; return "override void opcode" ~ opcode ~ "()\n{\n" ~ code ~ "}\n"; } @@ -719,7 +719,7 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) pushWord(programCounter); finalAddress |= ((operand2 = read(programCounter)) << 8); - static if (cumulative) tick(totalCycles); + static if (cumulative) clock.tick(totalCycles); programCounter = finalAddress; } @@ -729,14 +729,14 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) peek(programCounter); flag.fromByte(pull()); programCounter = readStack() | (readStack() << 8); - static if (cumulative) tick(totalCycles); + static if (cumulative) clock.tick(totalCycles); } /* JMP $$$$ */ final override void opcode4C() { programCounter = readWordOperand(); - static if (cumulative) tick(totalCycles); + static if (cumulative) clock.tick(totalCycles); } /* RTS */ @@ -745,7 +745,7 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) peek(programCounter); programCounter = pullWord(); peek(programCounter); - static if (cumulative) tick(totalCycles); + static if (cumulative) clock.tick(totalCycles); ++programCounter; } } diff --git a/src/system/base.d b/src/system/base.d index b2ecda4..2e6328a 100644 --- a/src/system/base.d +++ b/src/system/base.d @@ -133,10 +133,10 @@ class System { cpu = newCpu(); debug(disassemble) cpu.memoryName = &decoder.memoryReadName; - cpu.tick = &timer.tick; + cpu.clock.tick = &timer.tick; timer.onPrimaryStop(&primaryStop); - cpu.memoryRead = &decoder.read; - cpu.memoryWrite = &decoder.write; + cpu.memory.read = &decoder.read; + cpu.memory.write = &decoder.write; } void initIO(ubyte[] vidRom) diff --git a/test/cpu.d b/test/cpu.d index 796c446..85f5bbd 100644 --- a/test/cpu.d +++ b/test/cpu.d @@ -80,9 +80,9 @@ if (isCpu!T) else void tick() {} - cpu.memoryRead = &mem.read; - cpu.memoryWrite = &mem.write; - cpu.tick = &tick; + cpu.memory.read = &mem.read; + cpu.memory.write = &mem.write; + cpu.clock.tick = &tick; } @@ -99,7 +99,7 @@ auto recordCycles(T)(T cpu) if (isCpu!T) { auto cycles = new int; - auto wrappedTick = cpu.tick; + auto wrappedTick = cpu.clock.tick; static if (isCumulative!T) { @@ -117,7 +117,7 @@ if (isCpu!T) wrappedTick(); } } - cpu.tick = &tick; + cpu.clock.tick = &tick; return constRef(cycles); } @@ -155,9 +155,9 @@ if (isCpu!T) auto record = new Bus[actions]; int c; - enforce(cpu.memoryRead !is null && cpu.memoryWrite !is null); - auto wrappedRead = cpu.memoryRead; - auto wrappedWrite = cpu.memoryWrite; + enforce(cpu.memory.read !is null && cpu.memory.write !is null); + auto wrappedRead = cpu.memory.read; + auto wrappedWrite = cpu.memory.write; ubyte read(ushort addr) { @@ -177,8 +177,8 @@ if (isCpu!T) wrappedWrite(addr, val); } - cpu.memoryRead = &read; - cpu.memoryWrite = &write; + cpu.memory.read = &read; + cpu.memory.write = &write; return record; } @@ -210,8 +210,8 @@ enum Action : ushort { NONE, READ, WRITE } void runUntilBRK(T)(T cpu) if (isCpu!T) { - assert(cpu.memoryRead !is null); - auto wrappedRead = cpu.memoryRead; + assert(cpu.memory.read !is null); + auto wrappedRead = cpu.memory.read; ubyte read(ushort addr) { @@ -219,7 +219,7 @@ if (isCpu!T) return wrappedRead(addr); } - cpu.memoryRead = &read; + cpu.memory.read = &read; try { cpu.run(true); } catch (StopException e) {} } From e5f3f190a81894a23f0f6757e90520e89b0e6f2a Mon Sep 17 00:00:00 2001 From: edmccard Date: Sun, 8 Apr 2012 00:30:17 -0400 Subject: [PATCH 04/27] new cpu skeleton --- src/cpu6502.d | 250 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 248 insertions(+), 2 deletions(-) diff --git a/src/cpu6502.d b/src/cpu6502.d index 85c79bc..c799e2a 100644 --- a/src/cpu6502.d +++ b/src/cpu6502.d @@ -1,6 +1,9 @@ module cpu6502; +import std.array, std.format; + + enum Strict : bool { no, yes @@ -12,8 +15,63 @@ enum Cumulative : bool } -class Cpu(bool cumulative) +template is6502(T) { + enum is6502 = __traits(getMember, T, "_chip") == "6502"; +} + +template is65C02(T) +{ + enum is65C02 = __traits(getMember, T, "_chip") == "65C02"; +} + + +// The following versions are mutually exclusive. + +// OpDelegates: each opcode is a method of the Cpu class. +version(OpDelegates) +{ + enum versionCheck = 1; + enum opArray = true; +} + +// OpFunctions: each opcode is a free function with a Cpu argument. +version(OpFunctions) +{ + enum versionCheck = 2; + enum opArray = true; +} + +// OpSwitch: each opcode is inlined in a 256-case switch. +version(OpSwitch) +{ + enum versionCheck = 3; + enum opArray = false; +} + +// OpNestedSwitch: each opcode is inlined in a nested switch. +// (The outer one switches on the high byte, with each case switching +// on the low byte.) +version(OpNestedSwitch) +{ + enum versionCheck = 4; + enum opArray = false; +} + + +// At least one of the previous versions must be specified. +static if (!__traits(compiles, { bool b = opArray; })) enum opArray = 0; +static assert (versionCheck); + + +final class Cpu(string chip, bool strict, bool cumulative) +{ + static assert(chip == "6502" || chip == "65C02" || chip == "65c02"); + enum _isCpu = true; + enum _chip = (chip == "6502" ? "6502" : "65C02"); + enum _isStrict = strict; + enum _isCumulative = cumulative; + struct _Mem { // Reads a value from system memory. @@ -41,5 +99,193 @@ class Cpu(bool cumulative) } _Clock clock; - ubyte A, X, Y, S, P; + ubyte A, X, Y, S; + ushort PC; + + ubyte N, Z; + bool V, D, I, C; + + static if (opArray) mixin(OpArrayDef()); + + // TODO: other methods for stopping cpu + bool keepRunning; + + this() + { + static if (opArray) mixin(OpArrayInit()); + } + + final void statusFromByte(ubyte p) + { + N = p; + V = ((p & 0x40) != 0); + D = ((p & 0x08) != 0); + I = ((p & 0x04) != 0); + Z = ((p & 0x02) ? 0 : 1); + C = ((val & 0x01) != 0); + } + + final ubyte statusToByte() + { + return (C ? 0x01 : 0) | + ((Z == 0) ? 0x02 : 0) | + (I ? 0x04 : 0) | + (D ? 0x08 : 0) | + 0x30 | // break and reserved both set + (V ? 0x40 : 0) | + (N & 0x80); + } + + final void run(bool continuous) + { + keepRunning = continuous; + // TODO debugging info? + ubyte opcode; + do { + // XXX check signals + // XXX figure out cumulative/final cycle stuff + static if (cumulative) {} + else + clock.tick(); + opcode = memory.read(PC++); + mixin(OpExecute(_chip)); + } while (keepRunning); + } + + version(OpDelegates) mixin (OpBodies(_chip)); +} + + +version(OpFunctions) mixin(OpBodies("6502")); +version(OpFunctions) mixin(OpBodies("65C02")); + + +string OpArrayDef() +{ + version(OpDelegates) + return q{void delegate()[256] opcodes;}; + else version(OpFunctions) + return q{void function(typeof(this))[256] opcodes;}; + else + return ""; +} + +string OpArrayInit() +{ + static if (!opArray) return ""; + else + { + string ret; + foreach (op; 0..256) + { + version(OpDelegates) + ret ~= "opcodes[0x" ~ Hex2(op) ~ "] = &opcode_" ~ Hex2(op) ~ + ";\n"; + version(OpFunctions) + ret ~= "opcodes[0x" ~ Hex2(op) ~ "] = &opcode_" ~ Hex2(op) ~ + "!(typeof(this));\n"; + } + return ret; + } +} + +string OpBodies(string chip) +{ + static if (!opArray) return ""; + else + { + string ret; + foreach (op; 0..256) + { + version(OpDelegates) + ret ~= "final void opcode_" ~ Hex2(op) ~ "()\n{\n" ~ + OpBody(op, chip) ~ "}\n"; + version(OpFunctions) + ret ~= "void opcode_" ~ Hex2(op) ~ + "(T)(T cpu) if (is" ~ chip ~ "!T)\n{\n" ~ + OpBody(op, chip) ~ "}\n"; + } + return ret; + } +} + +string OpExecute(string chip) +{ + version(OpDelegates) + return q{opcodes[opcode]();}; + version(OpFunctions) + return q{opcodes[opcode](this);}; + version(OpSwitch) + return Switch256(chip); + version(OpNestedSwitch) + return Switch16x16(chip); +} + +string Switch256(string chip) +{ + string ret = "final switch (opcode)\n{\n"; + foreach (op; 0..256) + ret ~= "case 0x" ~ Hex2(op) ~ ":\n" ~ OpBody(op, chip) ~ "break;\n\n"; + return ret ~ "}\n"; +} + +string Switch16x16(string chip) +{ + string ret = "final switch (opcode & 0xF0)\n{\n"; + foreach (opHi; 0..16) + { + ret ~= "case 0x" ~ Hex1(opHi) ~ "0:\n" ~ + "final switch(opcode & 0x0F)\n{\n"; + foreach (opLo; 0..16) + { + int op = opLo | (opHi << 4); + ret ~= "case 0x0" ~ Hex1(opLo) ~ ":\n" ~ OpBody(op, chip) ~ + "break;\n\n"; + } + ret ~= "}\nbreak;\n"; + } + return ret ~ "}\n"; +} + + +string OpBody(int op, string chip) +{ + return ""; +} + + +// Custom hex printing. +// (to!string(x, 16) uses uppercase, which makes "8" and "B" hard to +// tell apart, and format("%0.2x", x) can't be used in CTFE.) + +enum HEX_DIGITS = "0123456789abcdef"; + +string Hex1(int dec) +{ + return HEX_DIGITS[dec..dec+1]; +} + +string Hex2(int dec) +{ + int highNybble = (dec & 0xF0) >> 4; + int lowNybble = dec & 0x0F; + + return HEX_DIGITS[highNybble..highNybble+1] ~ + HEX_DIGITS[lowNybble..lowNybble+1]; +} + + +alias Cpu!("6502", false, false) T1; +alias Cpu!("6502", false, true) T2; +alias Cpu!("6502", true, false) T3; +alias Cpu!("6502", true, true) T4; +alias Cpu!("65C02", false, false) T5; +alias Cpu!("65C02", false, true) T6; +alias Cpu!("65C02", true, false) T7; +alias Cpu!("65C02", true, true) T8; + +void main() +{ + import std.stdio; + writeln(Switch16x16("6502")); } From d3a95c455d353871cd016f24d71a6ff2cb837403 Mon Sep 17 00:00:00 2001 From: edmccard Date: Sun, 8 Apr 2012 00:30:44 -0400 Subject: [PATCH 05/27] Make test framework work with new cpu --- test/cpu.d | 141 +++++++++++++++++++---------------------------------- 1 file changed, 50 insertions(+), 91 deletions(-) diff --git a/test/cpu.d b/test/cpu.d index 85f5bbd..3ba9e9a 100644 --- a/test/cpu.d +++ b/test/cpu.d @@ -8,38 +8,37 @@ module test.cpu; import std.conv, std.exception, std.random, std.string, std.traits; -public import d6502.nmosundoc : NmosUndoc; -public import d6502.cmos : Cmos; +public import cpu6502 : Cpu, is6502, is65C02; // True if T is the type of a cpu. template isCpu(T) { - enum isCpu = __traits(hasMember, T, "_isCpuBase"); + enum isCpu = __traits(hasMember, T, "_isCpu"); } // True if the cpu type T represents a 6502. template isNMOS(T) { - enum isNMOS = __traits(hasMember, T, "_isNMOS"); + enum isNMOS = is6502!T; } // True if the cpu type T represents a 65C02. template isCMOS(T) { - enum isCMOS = __traits(hasMember, T, "_isCMOS"); + enum isCMOS = is65C02!T; } // True if the cpu type T accesses memory on every cycle. template isStrict(T) { - enum isStrict = __traits(hasMember, T, "_isStrict"); + enum isStrict = isCpu!T && __traits(getMember, T, "_isStrict"); } // True if the cpu type T aggregates ticks. template isCumulative(T) { - enum isCumulative = __traits(hasMember, T, "_isCumulative"); + enum isCumulative = isCpu!T && __traits(getMember, T, "_isCumulative"); } @@ -50,11 +49,7 @@ template isCumulative(T) */ template CPU(string arch, bool strict, bool cumulative) { - static if (arch == "65c02" || arch == "65C02") - alias Cmos!(strict, cumulative) CPU; - else static if (arch == "6502") - alias NmosUndoc!(strict, cumulative) CPU; - else static assert(0); + alias Cpu!(arch, strict, cumulative) CPU; } @@ -62,12 +57,12 @@ auto makeCpu(T)(CpuInfo info) if (isCpu!T) { auto cpu = new T(); - cpu.programCounter = info.PC; - cpu.stackPointer = info.SP; - cpu.flag.fromByte(info.S); - cpu.accumulator = info.A; - cpu.xIndex = info.X; - cpu.yIndex = info.Y; + cpu.PC = info.PC; + cpu.S = info.SP; + cpu.statusFromByte(info.S); + cpu.A = info.A; + cpu.X = info.X; + cpu.Y = info.Y; return cpu; } @@ -251,25 +246,20 @@ struct CpuInfo static CpuInfo fromCpu(T)(T cpu) { CpuInfo info; - info.PC = cpu.programCounter; - info.SP = cpu.stackPointer; - info.A = cpu.accumulator; - info.X = cpu.xIndex; - info.Y = cpu.yIndex; - info.S = cpu.flag.toByte(); + info.PC = cpu.PC; + info.SP = cpu.S; + info.A = cpu.A; + info.X = cpu.X; + info.Y = cpu.Y; + info.S = cpu.statusToByte(); return info; } } // Sets the program counter. -void setPC(T)(T cpu, int addr) -if (isCpu!T) -{ - cpu.programCounter = cast(ushort)addr; -} - -void setPC(T : CpuInfo)(ref T cpu, int addr) +void setPC(T)(ref T cpu, int addr) +if (isCpu!T || is(T == CpuInfo)) { cpu.PC = cast(ushort)addr; } @@ -279,14 +269,10 @@ void incPC(T : CpuInfo)(ref T cpu, int amt = 1) cpu.PC = pageCrossAdd(cpu.PC, amt); } -// Returns the program counter. -ushort getPC(T)(T cpu) -if (isCpu!T) -{ - return cpu.programCounter; -} -ushort getPC(T : CpuInfo)(ref T cpu) +// Returns the program counter. +ushort getPC(T)(ref T cpu) +if (isCpu!T || is(T == CpuInfo)) { return cpu.PC; } @@ -302,7 +288,7 @@ void setSP(T)(T cpu, int val) if (isCpu!T) { assert(val < 0x0200); - cpu.stackPointer = cast(ubyte)val; + cpu.S = cast(ubyte)val; } void setSP(T : CpuInfo)(ref T cpu, int val) @@ -329,7 +315,7 @@ void decSP(T : CpuInfo)(ref T cpu, int amt = -1) ushort getSP(T)(T cpu) if (isCpu!T) { - return 0x100 | cpu.stackPointer; + return 0x100 | cpu.S; } ushort getSP(T : CpuInfo)(ref T cpu) @@ -369,75 +355,48 @@ if (isCpu!T || is(T == CpuInfo)) } // Sets the A register. -void setA(T)(T cpu, int val) -if (isCpu!T) -{ - cpu.accumulator = cast(ubyte)val; -} - -void setA(T : CpuInfo)(ref T cpu, int val) +void setA(T)(ref T cpu, int val) +if (isCpu!T || is(T == CpuInfo)) { cpu.A = cast(ubyte)val; } -// Returns the A register. -ubyte getA(T)(T cpu, int val) -if (isCpu!T) -{ - return cpu.accumulator; -} -ubyte getA(T : CpuInfo)(ref T cpu) +// Returns the A register. +ubyte getA(T)(ref T cpu) +if (isCpu!T || is(T == CpuInfo)) { return cpu.A; } // Sets the X register. -void setX(T)(T cpu, int val) -if (isCpu!T) -{ - cpu.xIndex = cast(ubyte)val; -} - -void setX(T : CpuInfo)(ref T cpu, int val) +void setX(T)(ref T cpu, int val) +if (isCpu!T || is(T == CpuInfo)) { cpu.X = cast(ubyte)val; } -// Returns the X register. -ubyte getX(T)(T cpu) -if (isCpu!T) -{ - return cpu.xIndex; -} -ubyte getX(T : CpuInfo)(ref T cpu) +// Returns the X register. +ubyte getX(T)(ref T cpu) +if (isCpu!T || is(T == CpuInfo)) { return cpu.X; } // Sets the Y register. -void setY(T)(T cpu, int val) -if (isCpu!T) -{ - cpu.yIndex = cast(ubyte)val; -} - -void setY(T : CpuInfo)(ref T cpu, int val) +void setY(T)(ref T cpu, int val) +if (isCpu!T || is(T == CpuInfo)) { cpu.Y = cast(ubyte)val; } -// Returns the Y register. -ubyte getY(T)(T cpu) -if (isCpu!T) -{ - return cpu.yIndex; -} -ubyte getY(T : CpuInfo)(ref T cpu) +// Returns the Y register. +ubyte getY(T)(ref T cpu) +if (isCpu!T || is(T == CpuInfo)) { return cpu.Y; } @@ -472,9 +431,9 @@ string flagToString(Flag f) void setFlag(T)(T cpu, Flag[] flags...) if (isCpu!T) { - auto reg = cpu.flag.toByte(); + auto reg = cpu.statusToByte(); foreach (flag; flags) reg |= flag; - cpu.flag.fromByte(reg); + cpu.statusFromByte(reg); } void setFlag(T : CpuInfo)(ref T cpu, Flag[] flags...) @@ -486,9 +445,9 @@ void setFlag(T : CpuInfo)(ref T cpu, Flag[] flags...) void clearFlag(T)(T cpu, Flag[] flags...) if (isCpu!T) { - auto reg = cpu.flag.toByte(); + auto reg = cpu.statusToByte(); foreach (flag; flags) reg &= ~flag; - cpu.flag.fromByte(reg); + cpu.statusFromByte(reg); } void clearFlag(T : CpuInfo)(ref T cpu, Flag[] flags...) @@ -500,7 +459,8 @@ void clearFlag(T : CpuInfo)(ref T cpu, Flag[] flags...) bool getFlag(T)(T cpu, Flag f) if (isCpu!T) { - return (cpu.flag.toByte() & f) != 0; + return (cpu.statusToByte() & f) != 0; + return false; } bool getFlag(T : CpuInfo)(ref T cpu, Flag f) @@ -513,7 +473,7 @@ bool getFlag(T : CpuInfo)(ref T cpu, Flag f) void setStatus(T)(T cpu, int val) if (isCpu!T) { - cpu.flag.fromByte(cast(ubyte)val); + cpu.statusFromByte(cast(ubyte)val); } void setStatus(T : CpuInfo)(ref T cpu, int val) @@ -525,7 +485,8 @@ void setStatus(T : CpuInfo)(ref T cpu, int val) ubyte getStatus(T)(T cpu) if (isCpu!T) { - return cpu.flag.toByte(); + return cpu.statusToByte(); + return 0; } ubyte getStatus(T : CpuInfo)(ref T cpu) @@ -604,8 +565,6 @@ if (isCpu!T || is(T == CpuInfo)) case /*BNE*/ 0xD0: setFlag(cpu, Flag.Z); break; case /*BEQ*/ 0xF0: clearFlag(cpu, Flag.Z); break; default: - if (isCMOS!T) - enforce(opcode != 0x80, "BRA can never not branch"); enforce(0, format("not a branching opcpde %0.2X", opcode)); } } From 04f05fbc9ab7bee68e522dd62ac62a2235ebc0a1 Mon Sep 17 00:00:00 2001 From: edmccard Date: Sun, 8 Apr 2012 16:25:35 -0400 Subject: [PATCH 06/27] Add opcodes to new cpu (BRK) --- src/cpu6502.d | 587 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 548 insertions(+), 39 deletions(-) diff --git a/src/cpu6502.d b/src/cpu6502.d index c799e2a..752fa41 100644 --- a/src/cpu6502.d +++ b/src/cpu6502.d @@ -40,6 +40,17 @@ version(OpFunctions) { enum versionCheck = 2; enum opArray = true; + + // With free functions, strict and cumulative need to be set by + // version. + version(Strict) + enum vStrict = true; + else + enum vStrict = false; + version(Cumulative) + enum vCumulative = true; + else + enum vCumulative = false; } // OpSwitch: each opcode is inlined in a 256-case switch. @@ -105,7 +116,10 @@ final class Cpu(string chip, bool strict, bool cumulative) ubyte N, Z; bool V, D, I, C; - static if (opArray) mixin(OpArrayDef()); + static if (opArray) + { + mixin(OpArrayDef()); + } // TODO: other methods for stopping cpu bool keepRunning; @@ -122,7 +136,7 @@ final class Cpu(string chip, bool strict, bool cumulative) D = ((p & 0x08) != 0); I = ((p & 0x04) != 0); Z = ((p & 0x02) ? 0 : 1); - C = ((val & 0x01) != 0); + C = ((p & 0x01) != 0); } final ubyte statusToByte() @@ -141,23 +155,33 @@ final class Cpu(string chip, bool strict, bool cumulative) keepRunning = continuous; // TODO debugging info? ubyte opcode; + static if (!opArray) + { + static if (cumulative) int cycles; + } do { - // XXX check signals - // XXX figure out cumulative/final cycle stuff - static if (cumulative) {} - else + static if (cumulative && !opArray) + cycles = 1; + // XXX figure out final cycle stuff + static if (!cumulative) clock.tick(); + // XXX check signals, NMI/IRQ delays, etc. opcode = memory.read(PC++); - mixin(OpExecute(_chip)); + mixin(OpExecute(_chip, strict, cumulative)); } while (keepRunning); } - version(OpDelegates) mixin (OpBodies(_chip)); + version(OpDelegates) mixin (OpBodies(_chip, strict, cumulative)); } -version(OpFunctions) mixin(OpBodies("6502")); -version(OpFunctions) mixin(OpBodies("65C02")); +enum ushort IRQ_VECTOR = 0xFFFE; + + +private: + +version(OpFunctions) mixin(OpBodies("6502", vStrict, vCumulative)); +version(OpFunctions) mixin(OpBodies("65C02", vStrict, vCumulative)); string OpArrayDef() @@ -189,7 +213,7 @@ string OpArrayInit() } } -string OpBodies(string chip) +string OpBodies(string chip, bool strict, bool cumulative) { static if (!opArray) return ""; else @@ -199,37 +223,40 @@ string OpBodies(string chip) { version(OpDelegates) ret ~= "final void opcode_" ~ Hex2(op) ~ "()\n{\n" ~ - OpBody(op, chip) ~ "}\n"; + If!(cumulative)("int cycles = 1;\n") ~ + OpBody(op, chip, strict, cumulative) ~ "}\n"; version(OpFunctions) ret ~= "void opcode_" ~ Hex2(op) ~ "(T)(T cpu) if (is" ~ chip ~ "!T)\n{\n" ~ - OpBody(op, chip) ~ "}\n"; + If!(cumulative)("int cycles = 1;\n") ~ + OpBody(op, chip, strict, cumulative) ~ "}\n"; } return ret; } } -string OpExecute(string chip) +string OpExecute(string chip, bool strict, bool cumulative) { version(OpDelegates) return q{opcodes[opcode]();}; version(OpFunctions) return q{opcodes[opcode](this);}; version(OpSwitch) - return Switch256(chip); + return Switch256(chip, strict, cumulative); version(OpNestedSwitch) - return Switch16x16(chip); + return Switch16x16(chip, strict, cumulative); } -string Switch256(string chip) +string Switch256(string chip, bool strict, bool cumulative) { string ret = "final switch (opcode)\n{\n"; foreach (op; 0..256) - ret ~= "case 0x" ~ Hex2(op) ~ ":\n" ~ OpBody(op, chip) ~ "break;\n\n"; + ret ~= "case 0x" ~ Hex2(op) ~ ":\n" ~ + OpBody(op, chip, strict, cumulative) ~ "break;\n"; return ret ~ "}\n"; } -string Switch16x16(string chip) +string Switch16x16(string chip, bool strict, bool cumulative) { string ret = "final switch (opcode & 0xF0)\n{\n"; foreach (opHi; 0..16) @@ -239,8 +266,9 @@ string Switch16x16(string chip) foreach (opLo; 0..16) { int op = opLo | (opHi << 4); - ret ~= "case 0x0" ~ Hex1(opLo) ~ ":\n" ~ OpBody(op, chip) ~ - "break;\n\n"; + ret ~= "case 0x0" ~ Hex1(opLo) ~ ":\n" ~ + OpBody(op, chip, strict, cumulative) ~ + "break;\n"; } ret ~= "}\nbreak;\n"; } @@ -248,12 +276,509 @@ string Switch16x16(string chip) } -string OpBody(int op, string chip) +string OpBody(int op, string chip, bool strict, bool cumulative) { - return ""; + final switch (opName(op, chip)) + { + case "BRK": + return Break(strict, cumulative); + case "RTI": + return ""; + case "JSR": + return ""; + case "RTS": + return ""; + case "JMP": + return ""; // address modes + case "KIL": + return ""; + case "BPL": + return ""; + case "BMI": + return ""; + case "BVC": + return ""; + case "BVS": + return ""; + case "BRA": + return ""; + case "BCC": + return ""; + case "BCS": + return ""; + case "BNE": + return ""; + case "BEQ": + return ""; + case "CLC": + return ""; + case "SEC": + return ""; + case "CLI": + return ""; + case "SEI": + return ""; + case "CLV": + return ""; + case "CLD": + return ""; + case "SED": + return ""; + case "NOP": + return ""; // address modes + case "TAX": + return ""; + case "TXA": + return ""; + case "TAY": + return ""; + case "TYA": + return ""; + case "TSX": + return ""; + case "TXS": + return ""; + case "DEX": + return ""; + case "DEY": + return ""; + case "INX": + return ""; + case "INY": + return ""; + case "PLP": + return ""; + case "PLA": + return ""; + case "PLX": + return ""; + case "PLY": + return ""; + case "PHP": + return ""; + case "PHA": + return ""; + case "PHX": + return ""; + case "PHY": + return ""; + case "LDA": + return ""; + case "LDX": + return ""; + case "LDY": + return ""; + case "STA": + return ""; + case "STX": + return ""; + case "STY": + return ""; + case "STZ": + return ""; + case "BIT": + return ""; // address modes + case "CMP": + return ""; + case "CPX": + return ""; + case "CPY": + return ""; + case "ORA": + return ""; + case "AND": + return ""; + case "EOR": + return ""; + case "ADC": + return ""; // n/c (op, cyc) + case "SBC": + return ""; // n/c (op, cyc) + case "ASL": + return ""; // n/c (op, cyc) + case "ROL": + return ""; // n/c (op, cyc) + case "LSR": + return ""; // n/c (op, cyc) + case "ROR": + return ""; // n/c (op, cyc) + case "INC": + return ""; // n/c (op, +ina) + case "DEC": + return ""; // n/c (op, +dea) + case "TRB": + return ""; + case "TSB": + return ""; + case "LAS": + return ""; + case "LAX": + return ""; // address modes + case "SAX": + return ""; + case "ANC": + return ""; + case "ALR": + return ""; + case "ARR": + return ""; + case "AXS": + return ""; + case "AHX": + return ""; + case "SHY": + return ""; + case "SHX": + return ""; + case "TAS": + return ""; + case "XAA": + return ""; + case "SLO": + return ""; + case "RLA": + return ""; + case "SRE": + return ""; + case "RRA": + return ""; + case "DCP": + return ""; + case "ISC": + return ""; + } } +string Break(bool s, bool c) +{ + return Peek(Attr("PC"), s, c) ~ + IncPC() ~ + PushPC(s, c) ~ + Push(Attr("statusToByte()"), s, c) ~ + Set(Attr("I")) ~ + ReadWord(Attr("PC"), "IRQ_VECTOR", c) ~ + Done(c); +} + + +string PreAccess(bool cumulative) +{ + return If!(cumulative)("++cycles;\n", Attr("clock") ~ ".tick();\n"); +} + +string Peek(string addr, bool strict, bool cumulative) +{ + return PreAccess(cumulative) ~ + If!(strict)(Attr("memory") ~ ".read(" ~ addr ~");\n"); +} + +string Read(string var, string addr, bool c) +{ + return PreAccess(c) ~ + var ~ " = " ~ Attr("memory") ~ ".read(" ~ addr ~");\n"; +} + +string Write(string addr, string val, bool cumulative) +{ + return If!(cumulative)("++cycles;\n", Attr("clock") ~ ".tick();\n") ~ + Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"; +} + +string ReadWord(string var, string addr, bool c) +{ + return PreAccess(c) ~ + var ~ " = " ~ Attr("memory") ~ ".read(" ~ addr ~");\n" ~ + PreAccess(c) ~ + var ~ " |= (" ~ Attr("memory") ~ + ".read(cast(ushort)((" ~ addr ~ ") + 1)) << 8);\n"; +} + + +string IncPC() +{ + return "++" ~ Attr("PC") ~ ";\n"; +} + + +string IncSP() +{ + return "++" ~ Attr("S") ~ ";\n"; +} + +string DecSP() +{ + return "--" ~ Attr("S") ~ ";\n"; +} + +string Push(string val, bool s, bool c) +{ + return Write("0x0100 + " ~ Attr("S"), val, c) ~ + DecSP(); +} + +string PushPC(bool s, bool c) +{ + return Push(HiByte(Attr("PC")), s, c) ~ + Push(LoByte(Attr("PC")), s, c); +} + + +string Set(string flag) +{ + return flag ~ " = true;\n"; +} + + +string Done(bool cumulative) +{ + return If!(cumulative)(Attr("clock") ~ ".tick(cycles);\n"); +} + + +string Attr(string var) +{ + version(OpFunctions) + return "cpu." ~ var; + else + return var; +} + + +string HiByte(string var) +{ + return var ~ " >> 8"; +} + +string LoByte(string var) +{ + return var ~ " & 0xff"; +} + + +string If(alias cond)(string yes, string no = "") +{ + if (cond) + return yes; + else + return no; +} + + +string opName(int op, string chip) +{ + if (chip == "6502") + return OP_NAMES_6502[op]; + else + return OP_NAMES_65C02[op]; +} + +int opMode(int op, string chip) +{ + if (chip == "6502") + return ADDR_MODES_6502[op]; + else + return ADDR_MODES_65C02[op]; +} + +int opExCyc(int op, string chip) +{ + if (chip == "6502") + return EXTRA_CYCLES_6502[op]; + else + return EXTRA_CYCLES_65C02[op]; +} + + +// Opcode names. +immutable OP_NAMES_6502 = [ + "BRK", "ORA", "KIL", "SLO", "NOP", "ORA", "ASL", "SLO", + "PHP", "ORA", "ASL", "ANC", "NOP", "ORA", "ASL", "SLO", + "BPL", "ORA", "KIL", "SLO", "NOP", "ORA", "ASL", "SLO", + "CLC", "ORA", "NOP", "SLO", "NOP", "ORA", "ASL", "SLO", + "JSR", "AND", "KIL", "RLA", "BIT", "AND", "ROL", "RLA", + "PLP", "AND", "ROL", "ANC", "BIT", "AND", "ROL", "RLA", + "BMI", "AND", "KIL", "RLA", "NOP", "AND", "ROL", "RLA", + "SEC", "AND", "NOP", "RLA", "NOP", "AND", "ROL", "RLA", + "RTI", "EOR", "KIL", "SRE", "NOP", "EOR", "LSR", "SRE", + "PHA", "EOR", "LSR", "ALR", "JMP", "EOR", "LSR", "SRE", + "BVC", "EOR", "KIL", "SRE", "NOP", "EOR", "LSR", "SRE", + "CLI", "EOR", "NOP", "SRE", "NOP", "EOR", "LSR", "SRE", + "RTS", "ADC", "KIL", "RRA", "NOP", "ADC", "ROR", "RRA", + "PLA", "ADC", "ROR", "ARR", "JMP", "ADC", "ROR", "RRA", + "BVS", "ADC", "KIL", "RRA", "NOP", "ADC", "ROR", "RRA", + "SEI", "ADC", "NOP", "RRA", "NOP", "ADC", "ROR", "RRA", + "NOP", "STA", "NOP", "SAX", "STY", "STA", "STX", "SAX", + "DEY", "NOP", "TXA", "XAA", "STY", "STA", "STX", "SAX", + "BCC", "STA", "KIL", "AHX", "STY", "STA", "STX", "SAX", + "TYA", "STA", "TXS", "TAS", "SHY", "STA", "SHX", "AHX", + "LDY", "LDA", "LDX", "LAX", "LDY", "LDA", "LDX", "LAX", + "TAY", "LDA", "TAX", "LAX", "LDY", "LDA", "LDX", "LAX", + "BCS", "LDA", "KIL", "LAX", "LDY", "LDA", "LDX", "LAX", + "CLV", "LDA", "TSX", "LAS", "LDY", "LDA", "LDX", "LAX", + "CPY", "CMP", "NOP", "DCP", "CPY", "CMP", "DEC", "DCP", + "INY", "CMP", "DEX", "AXS", "CPY", "CMP", "DEC", "DCP", + "BNE", "CMP", "KIL", "DCP", "NOP", "CMP", "DEC", "DCP", + "CLD", "CMP", "NOP", "DCP", "NOP", "CMP", "DEC", "DCP", + "CPX", "SBC", "NOP", "ISC", "CPX", "SBC", "INC", "ISC", + "INX", "SBC", "NOP", "SBC", "CPX", "SBC", "INC", "ISC", + "BEQ", "SBC", "KIL", "ISC", "NOP", "SBC", "INC", "ISC", + "SED", "SBC", "NOP", "ISC", "NOP", "SBC", "INC", "ISC" +]; + +immutable OP_NAMES_65C02 = [ + "BRK", "ORA", "NOP", "NOP", "TSB", "ORA", "ASL", "NOP", + "PHP", "ORA", "ASL", "NOP", "TSB", "ORA", "ASL", "NOP", + "BPL", "ORA", "ORA", "NOP", "TRB", "ORA", "ASL", "NOP", + "CLC", "ORA", "INC", "NOP", "TRB", "ORA", "ASL", "NOP", + "JSR", "AND", "NOP", "NOP", "BIT", "AND", "ROL", "NOP", + "PLP", "AND", "ROL", "NOP", "BIT", "AND", "ROL", "NOP", + "BMI", "AND", "AND", "NOP", "BIT", "AND", "ROL", "NOP", + "SEC", "AND", "DEC", "NOP", "BIT", "AND", "ROL", "NOP", + "RTI", "EOR", "NOP", "NOP", "NOP", "EOR", "LSR", "NOP", + "PHA", "EOR", "LSR", "NOP", "JMP", "EOR", "LSR", "NOP", + "BVC", "EOR", "EOR", "NOP", "NOP", "EOR", "LSR", "NOP", + "CLI", "EOR", "PHY", "NOP", "NOP", "EOR", "LSR", "NOP", + "RTS", "ADC", "NOP", "NOP", "STZ", "ADC", "ROR", "NOP", + "PLA", "ADC", "ROR", "NOP", "JMP", "ADC", "ROR", "NOP", + "BVS", "ADC", "ADC", "NOP", "STZ", "ADC", "ROR", "NOP", + "SEI", "ADC", "PLY", "NOP", "JMP", "ADC", "ROR", "NOP", + "BRA", "STA", "NOP", "NOP", "STY", "STA", "STX", "NOP", + "DEY", "BIT", "TXA", "NOP", "STY", "STA", "STX", "NOP", + "BCC", "STA", "STA", "NOP", "STY", "STA", "STX", "NOP", + "TYA", "STA", "TXS", "NOP", "STZ", "STA", "STZ", "NOP", + "LDY", "LDA", "LDX", "NOP", "LDY", "LDA", "LDX", "NOP", + "TAY", "LDA", "TAX", "NOP", "LDY", "LDA", "LDX", "NOP", + "BCS", "LDA", "LDA", "NOP", "LDY", "LDA", "LDX", "NOP", + "CLV", "LDA", "TSX", "NOP", "LDY", "LDA", "LDX", "NOP", + "CPY", "CMP", "NOP", "NOP", "CPY", "CMP", "DEC", "NOP", + "INY", "CMP", "DEX", "NOP", "CPY", "CMP", "DEC", "NOP", + "BNE", "CMP", "CMP", "NOP", "NOP", "CMP", "DEC", "NOP", + "CLD", "CMP", "PHX", "NOP", "NOP", "CMP", "DEC", "NOP", + "CPX", "SBC", "NOP", "NOP", "CPX", "SBC", "INC", "NOP", + "INX", "SBC", "NOP", "NOP", "CPX", "SBC", "INC", "NOP", + "BEQ", "SBC", "SBC", "NOP", "NOP", "SBC", "INC", "NOP", + "SED", "SBC", "PLX", "NOP", "NOP", "SBC", "INC", "NOP" +]; + + +// Addressing modes. + +enum { IMP, IMM, ZP, ZPX, ZPY, IZX, IZY, ABS, ABX, ABY, IND, REL, + ZPI, ABI, NP1, NP8, KIL } + +immutable ADDR_MODES_6502 = [ + IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, + ABS, IZX, KIL, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, + IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, + IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, IND, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, + IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPY, ZPY, + IMP, ABY, IMP, ABY, ABX, ABX, ABY, ABY, + IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPY, ZPY, + IMP, ABY, IMP, ABY, ABX, ABX, ABY, ABY, + IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, + IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX +]; + +immutable ADDR_MODES_65C02 = [ + IMP, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZP, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, ABS, ABX, ABX, NP1, + ABS, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1, + IMP, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, NP8, ABX, ABX, NP1, + IMP, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, IND, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, ABI, ABX, ABX, NP1, + REL, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPY, NP1, + IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1, + IMM, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPY, NP1, + IMP, ABY, IMP, NP1, ABX, ABX, ABY, NP1, + IMM, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1, + IMM, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1 +]; + + +// Page-crossing extra cycles. + +immutable EXTRA_CYCLES_6502 = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, +]; + +immutable EXTRA_CYCLES_65C02 = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, +]; + + // Custom hex printing. // (to!string(x, 16) uses uppercase, which makes "8" and "B" hard to // tell apart, and format("%0.2x", x) can't be used in CTFE.) @@ -273,19 +798,3 @@ string Hex2(int dec) return HEX_DIGITS[highNybble..highNybble+1] ~ HEX_DIGITS[lowNybble..lowNybble+1]; } - - -alias Cpu!("6502", false, false) T1; -alias Cpu!("6502", false, true) T2; -alias Cpu!("6502", true, false) T3; -alias Cpu!("6502", true, true) T4; -alias Cpu!("65C02", false, false) T5; -alias Cpu!("65C02", false, true) T6; -alias Cpu!("65C02", true, false) T7; -alias Cpu!("65C02", true, true) T8; - -void main() -{ - import std.stdio; - writeln(Switch16x16("6502")); -} From d343db0842e06d9bf1566cdce5c9d19772ac9d9a Mon Sep 17 00:00:00 2001 From: edmccard Date: Sun, 8 Apr 2012 21:28:44 -0400 Subject: [PATCH 07/27] Add tests for new cpu --- src/Makefile | 2 +- src/cpu6502.d | 10 ++++++++++ src/d6502/cpu.d | 12 ++++++------ test/test_new_cpu.d | 39 +++++++++++++++++++++++++++++++++++++++ test/test_new_cpu.sh | 20 ++++++++++++++++++++ 5 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 test/test_new_cpu.d create mode 100755 test/test_new_cpu.sh diff --git a/src/Makefile b/src/Makefile index de06db2..48e0a18 100644 --- a/src/Makefile +++ b/src/Makefile @@ -5,7 +5,7 @@ LINK_OPTS = -L-lpthread -L-lGL -L-ldl -L-lX11 \ -L-L$(GTKD) -L-lgtkd -L-lgtkdgl \ -L-L$(DERELICT)/lib -L-lDerelictSDL -L-lDerelictUtil \ -ALL_SRC = $(shell find -name "*.d") +ALL_SRC = $(shell find -name "*.d" \! -name "cpu6502.d") ALL_OBJS = $(ALL_SRC:%.d=%.o) all: ${ALL_OBJS} diff --git a/src/cpu6502.d b/src/cpu6502.d index 752fa41..86ed9c2 100644 --- a/src/cpu6502.d +++ b/src/cpu6502.d @@ -798,3 +798,13 @@ string Hex2(int dec) return HEX_DIGITS[highNybble..highNybble+1] ~ HEX_DIGITS[lowNybble..lowNybble+1]; } + + +//alias Cpu!("6502", false, false) T1; +//alias Cpu!("6502", false, true) T2; +//alias Cpu!("6502", true, false) T3; +//alias Cpu!("6502", true, true) T4; +//alias Cpu!("65C02", false, false) T5; +//alias Cpu!("65C02", false, true) T6; +//alias Cpu!("65C02", true, false) T7; +//alias Cpu!("65C02", true, true) T8; diff --git a/src/d6502/cpu.d b/src/d6502/cpu.d index a8e6356..e226afa 100644 --- a/src/d6502/cpu.d +++ b/src/d6502/cpu.d @@ -198,22 +198,22 @@ class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) final ubyte readFinal(ushort addr) { - static if (cumulative) tick(++totalCycles); + static if (cumulative) clock.tick(++totalCycles); else { - tick(); + clock.tick(); } - return memoryRead(addr); + return memory.read(addr); } final void writeFinal(ushort addr, ubyte val) { - static if (cumulative) tick(++totalCycles); + static if (cumulative) clock.tick(++totalCycles); else { - tick(); + clock.tick(); } - memoryWrite(addr, val); + memory.write(addr, val); } final ushort readWord(ushort addrLo, ushort addrHi) diff --git a/test/test_new_cpu.d b/test/test_new_cpu.d new file mode 100644 index 0000000..cebae41 --- /dev/null +++ b/test/test_new_cpu.d @@ -0,0 +1,39 @@ +version(Strict) + enum s1 = true; +else + enum s1 = false; +version(Cumulative) + enum c1 = true; +else + enum c1 = false; + +void main() +{ + import std.stdio; + import test.base, test.cpu; + + void test_func(ubyte op) + { + auto report = report_debug(); + auto report2 = report_timing_debug(); + + version(OpFunctions) writeln("(Functions)"); + version(OpDelegates) writeln("(Delegates)"); + version(OpSwitch) writeln("(Switch)"); + version(OpNestedSwitch) writeln("(NestedSwitch)"); + + alias Cpu!("6502", s1, c1) TX1; + writeln("NMOS ", s1, " ", c1, " func"); + test_one_opcode!TX1(op, report); + writeln("NMOS ", s1, " ", c1, " bus"); + test_opcode_timing!TX1(op, report2); + + alias Cpu!("65C02", s1, c1) TX2; + writeln("CMOS ", s1, " ", c1, " func"); + test_one_opcode!TX2(op, report); + writeln("CMOS ", s1, " ", c1, " bus"); + test_opcode_timing!TX2(op, report2); + } + + test_func(0x00); +} diff --git a/test/test_new_cpu.sh b/test/test_new_cpu.sh new file mode 100755 index 0000000..4f603cd --- /dev/null +++ b/test/test_new_cpu.sh @@ -0,0 +1,20 @@ +rdmd --force -version=OpDelegates -I.. -I../src test_new_cpu.d +rdmd --force -version=OpDelegates -version=Strict -I.. -I../src test_new_cpu.d +rdmd --force -version=OpDelegates -version=Cumulative -I.. -I../src test_new_cpu.d +rdmd --force -version=OpDelegates -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d + +rdmd --force -version=OpFunctions -I.. -I../src test_new_cpu.d +rdmd --force -version=OpFunctions -version=Strict -I.. -I../src test_new_cpu.d +rdmd --force -version=OpFunctions -version=Cumulative -I.. -I../src test_new_cpu.d +rdmd --force -version=OpFunctions -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d + +rdmd --force -version=OpSwitch -I.. -I../src test_new_cpu.d +rdmd --force -version=OpSwitch -version=Strict -I.. -I../src test_new_cpu.d +rdmd --force -version=OpSwitch -version=Cumulative -I.. -I../src test_new_cpu.d +rdmd --force -version=OpSwitch -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d + +rdmd --force -version=OpNestedSwitch -I.. -I../src test_new_cpu.d +rdmd --force -version=OpNestedSwitch -version=Strict -I.. -I../src test_new_cpu.d +rdmd --force -version=OpNestedSwitch -version=Cumulative -I.. -I../src test_new_cpu.d +rdmd --force -version=OpNestedSwitch -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d + From c5fb366184b17e4c210a8eca7d800415b3013b1a Mon Sep 17 00:00:00 2001 From: edmccard Date: Mon, 9 Apr 2012 09:52:42 -0400 Subject: [PATCH 08/27] Add opcodes to new cpu (enough to run benchmark) --- src/cpu6502.d | 602 ++++++++++++++++++++++++++++++++++++++----- test/test_new_cpu.d | 23 +- test/test_new_cpu.sh | 33 ++- 3 files changed, 563 insertions(+), 95 deletions(-) diff --git a/src/cpu6502.d b/src/cpu6502.d index 86ed9c2..3c7b136 100644 --- a/src/cpu6502.d +++ b/src/cpu6502.d @@ -60,9 +60,12 @@ version(OpSwitch) enum opArray = false; } -// OpNestedSwitch: each opcode is inlined in a nested switch. -// (The outer one switches on the high byte, with each case switching -// on the low byte.) +/* + * OpNestedSwitch: each opcode is inlined in a nested switch. + * + * (The outer one switches on the high byte, with each case switching + * on the low byte.) + */ version(OpNestedSwitch) { enum versionCheck = 4; @@ -75,6 +78,12 @@ static if (!__traits(compiles, { bool b = opArray; })) enum opArray = 0; static assert (versionCheck); +// This needs to be before any mixins which call any CTFE functions +// that make use of these constants. +enum { IMP, IMM, ZP, ZPX, ZPY, IZX, IZY, ABS, ABX, ABY, IND, REL, + ZPI, ABI, NP1, NP8, KIL } + + final class Cpu(string chip, bool strict, bool cumulative) { static assert(chip == "6502" || chip == "65C02" || chip == "65c02"); @@ -157,7 +166,10 @@ final class Cpu(string chip, bool strict, bool cumulative) ubyte opcode; static if (!opArray) { - static if (cumulative) int cycles; + static if (cumulative) { int cycles; } + ubyte op1; + ushort address, base; + ubyte data; } do { static if (cumulative && !opArray) @@ -203,11 +215,11 @@ string OpArrayInit() foreach (op; 0..256) { version(OpDelegates) - ret ~= "opcodes[0x" ~ Hex2(op) ~ "] = &opcode_" ~ Hex2(op) ~ - ";\n"; + ret ~= Fmt("opcodes[0x#] = &opcode_#;\n", + Hex2(op), Hex2(op)); version(OpFunctions) - ret ~= "opcodes[0x" ~ Hex2(op) ~ "] = &opcode_" ~ Hex2(op) ~ - "!(typeof(this));\n"; + ret ~= Fmt("opcodes[0x#] = &opcode_#!(typeof(this));\n", + Hex2(op), Hex2(op)); } return ret; } @@ -276,54 +288,82 @@ string Switch16x16(string chip, bool strict, bool cumulative) } -string OpBody(int op, string chip, bool strict, bool cumulative) +string OpBody(int op, string chip, bool s, bool c) { + bool nmos = (chip == "6502"); final switch (opName(op, chip)) { case "BRK": - return Break(strict, cumulative); + return Break(s, c) ~ + Done(c); case "RTI": return ""; case "JSR": - return ""; + return JumpSub(s, c) ~ + Done(c); case "RTS": - return ""; + return RetSub(s, c) ~ + Done(c); case "JMP": - return ""; // address modes + return Jump(op, chip, s, c) ~ + Done(c); case "KIL": return ""; case "BPL": - return ""; + return Branch("!(" ~ Attr("N") ~ " & 0x80)", nmos, s, c) ~ + Done(c); case "BMI": - return ""; + return Branch("(" ~ Attr("N") ~ " & 0x80)", nmos, s, c) ~ + Done(c); case "BVC": - return ""; + return Branch("!" ~ Attr("V"), nmos, s, c) ~ + Done(c); case "BVS": - return ""; + return Branch(Attr("V"), nmos, s, c) ~ + Done(c); case "BRA": - return ""; + return Branch("true", nmos, s, c) ~ + Done(c); case "BCC": - return ""; + return Branch("!" ~ Attr("C"), nmos, s, c) ~ + Done(c); case "BCS": - return ""; + return Branch(Attr("C"), nmos, s, c) ~ + Done(c); case "BNE": - return ""; + return Branch(Attr("Z"), nmos, s, c) ~ + Done(c); case "BEQ": - return ""; + return Branch("!" ~ Attr("Z"), nmos, s, c) ~ + Done(c); case "CLC": - return ""; + return AddrImplied(s, c) ~ + ClearFlag("C") ~ + Done(c); case "SEC": - return ""; + return AddrImplied(s, c) ~ + SetFlag("C") ~ + Done(c); case "CLI": - return ""; + return AddrImplied(s, c) ~ + ClearFlag("I") ~ + Done(c); case "SEI": - return ""; + return AddrImplied(s, c) ~ + SetFlag("I") ~ + Done(c); case "CLV": - return ""; + return AddrImplied(s, c) ~ + ClearFlag("V") ~ + Done(c); case "CLD": - return ""; + return AddrImplied(s, c) ~ + ClearFlag("D") ~ + Done(c); case "SED": - return ""; + return AddrImplied(s, c) ~ + SetFlag("D") ~ + Done(c); case "NOP": return ""; // address modes case "TAX": @@ -339,23 +379,34 @@ string OpBody(int op, string chip, bool strict, bool cumulative) case "TXS": return ""; case "DEX": - return ""; + return DecReg("X", s, c) ~ + Done(c); case "DEY": - return ""; + return DecReg("Y", s, c) ~ + Done(c); case "INX": - return ""; + return IncReg("X", s, c) ~ + Done(c); case "INY": - return ""; + return IncReg("Y", s, c) ~ + Done(c); + case "PHP": + return AddrImplied(s, c) ~ + Push(Attr("statusToByte()"), s, c) ~ + Done(c); case "PLP": - return ""; + return AddrImplied(s, c) ~ + PullStatus(s, c) ~ + Done(c); case "PLA": - return ""; + return AddrImplied(s, c) ~ + PullInto(Attr("A"), s, c) ~ + SetNZ(Attr("A")) ~ + Done(c); case "PLX": return ""; case "PLY": return ""; - case "PHP": - return ""; case "PHA": return ""; case "PHX": @@ -363,37 +414,51 @@ string OpBody(int op, string chip, bool strict, bool cumulative) case "PHY": return ""; case "LDA": - return ""; + return Load(op, "A", chip, s, c) ~ + Done(c); case "LDX": - return ""; + return Load(op, "X", chip, s, c) ~ + Done(c); case "LDY": - return ""; + return Load(op, "Y", chip, s, c) ~ + Done(c); case "STA": - return ""; + return Store(op, "A", chip, s, c) ~ + Done(c); case "STX": - return ""; + return Store(op, "X", chip, s, c) ~ + Done(c); case "STY": - return ""; + return Store(op, "Y", chip, s, c) ~ + Done(c); case "STZ": return ""; case "BIT": return ""; // address modes case "CMP": - return ""; + return Compare(op, "A", chip, s, c) ~ + Done(c); case "CPX": - return ""; + return Compare(op, "X", chip, s, c) ~ + Done(c); case "CPY": - return ""; + return Compare(op, "Y", chip, s, c) ~ + Done(c); case "ORA": - return ""; + return Logic(op, "|=", chip, s, c) ~ + Done(c); case "AND": - return ""; + return Logic(op, "&=", chip, s, c) ~ + Done(c); case "EOR": - return ""; + return Logic(op, "^=", chip, s, c) ~ + Done(c); case "ADC": - return ""; // n/c (op, cyc) + return Add(op, chip, s, c) ~ + Done(c); case "SBC": - return ""; // n/c (op, cyc) + return Sub(op, chip, s, c) ~ + Done(c); case "ASL": return ""; // n/c (op, cyc) case "ROL": @@ -403,9 +468,15 @@ string OpBody(int op, string chip, bool strict, bool cumulative) case "ROR": return ""; // n/c (op, cyc) case "INC": - return ""; // n/c (op, +ina) + if (op == 0x1a) + return IncReg("A", s, c) ~ Done(c); + else + return RMW(op, "data++;\n", chip, s, c) ~ Done(c); case "DEC": - return ""; // n/c (op, +dea) + if (op == 0x3a) + return DecReg("A", s, c) ~ Done(c); + else + return RMW(op, "data--;\n", chip, s, c) ~ Done(c); case "TRB": return ""; case "TSB": @@ -450,15 +521,309 @@ string OpBody(int op, string chip, bool strict, bool cumulative) } +string AddrImmediate(bool s, bool c) +{ + return Local("ushort", "address") ~ " = " ~ Attr("PC") ~ "++;\n"; +} + +string AddrImplied(bool s, bool c) +{ + return Peek(Attr("PC"), s, c); +} + + +string AddrAbsoluteIdx(int op, string reg, string chip, bool s, bool c) +{ + bool nmos = (chip == "6502"); + int exCyc = opExCyc(op, chip); + string IDX = Attr(reg); + + return ReadWordOpLocal("ushort", "base", c) ~ + Local("ushort","address")~" = cast(ushort)(base + " ~ IDX ~ ");\n" ~ + "ushort guess = (base & 0xFF00) | cast(ubyte)address;\n" ~ + "if (guess != address)\n{\n" ~ + If!(nmos)(Peek("guess", s, c), Peek(Attr("PC"), s, c)) ~ + "}\n" ~ + If!(exCyc)("else\n{\n" ~ Peek("address", s, c) ~ "}\n"); +} + + +string Branch(string check, bool nmos, bool s, bool c) +{ + string PC = Attr("PC"); + return ReadInto(Local("ubyte", "op1"), PC, c) ~ + IncPC() ~ + "if (" ~ check ~ ")\n{\n" ~ + Peek(PC, s, c) ~ + Local("ushort", "base") ~ " = " ~ PC ~ ";\n" ~ + PC ~ " = cast(ushort)(" ~ PC ~ " + cast(byte)op1);\n" ~ + "ushort guess = (base & 0xFF00) | cast(ubyte)" ~ PC ~ ";\n" ~ + "if (guess != " ~ PC ~ ")\n{\n" ~ + If!(nmos)(Peek("guess", s, c), Peek("base", s, c)) ~ + "}\n}\n"; +} + + string Break(bool s, bool c) { - return Peek(Attr("PC"), s, c) ~ + return AddrImplied(s, c) ~ IncPC() ~ PushPC(s, c) ~ Push(Attr("statusToByte()"), s, c) ~ - Set(Attr("I")) ~ - ReadWord(Attr("PC"), "IRQ_VECTOR", c) ~ - Done(c); + SetFlag("I") ~ + ReadWord(Attr("PC"), "IRQ_VECTOR", c); +} + + +string RetSub(bool s, bool c) +{ + string PC = Attr("PC"); + + return AddrImplied(s, c) ~ + PullPC(s, c) ~ + Peek(PC, s, c) ~ + IncPC(); +} + + +string JumpSub(bool s, bool c) +{ + string PC = Attr("PC"); + + return ReadInto(Local("ushort", "address"), PC ~ "++", c) ~ + Peek("0x0100 + " ~ Attr("S"), s, c) ~ + PushPC(s, c) ~ + PreAccess(c) ~ + "address |= (" ~ ReadRaw(PC ~ "++") ~ " << 8);\n" ~ + PC ~ " = address;\n"; +} + + +string Jump(int op, string chip, bool s, bool c) +{ + if (op == 0x4c) + return Address(op, chip, s, c) ~ + Attr("PC") ~ " = address;\n"; + else + return ""; +} + + +string Load(int op, string reg, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + ReadInto(Attr(reg), "address", c) ~ + SetNZ(Attr(reg)); +} + + +string Store(int op, string reg, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + Write("address", Attr(reg), c); +} + + +string Compare(int op, string reg, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + ReadInto(Local("ubyte", "data"), "address", c) ~ + UpdateFlag("C", Attr(reg) ~ " >= data") ~ + SetNZ("cast(ubyte)(" ~ Attr(reg) ~ " - data)"); +} + + +string Logic(int op, string action, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + ReadInto(Attr("A"), "address", c, action) ~ + SetNZ(Attr("A")); +} + + +string Add(int op, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + ReadInto(Local("ubyte", "data"), "address", c) ~ + "if (" ~ Attr("D") ~ ")\n{\n" ~ + DecAdd(chip, s, c) ~ + "}\nelse\n{\n" ~ + HexAdd(chip, s, c) ~ + "}\n"; +} + +string HexAdd(string chip, bool s, bool c) +{ + string A = Attr("A"), C = Attr("C"); + + return "uint sum = " ~ A ~ " + data + " ~ C ~ ";\n" ~ + Attr("V") ~ + " = (!((" ~ A ~ " ^ data) & 0x80)) && ((data ^ sum) & 0x80);\n" ~ + C ~ " = (sum > 0xFF);\n" ~ + SetNZ(A ~ " = cast(ubyte)sum"); +} + +string DecAdd(string chip, bool s, bool c) +{ + bool cmos = (chip != "6502"); + string A = Attr("A"), C = Attr("C"); + + return "int a = " ~ A ~ ";\n" ~ + "int al = (a & 0x0F) + (data & 0x0F) + " ~ C ~ ";\n" ~ + "if (al >= 0x0A)\n" ~ + "al = ((al + 0x06) & 0x0F) + 0x10;\n" ~ + "a = (a & 0xF0) + (data & 0xF0) + al;\n" ~ + If!(cmos)("", + Attr("N") ~ " = cast(ubyte)a;\n" ~ + Attr("Z") ~ " = cast(ubyte)(" ~ A ~ " + data + " ~ C ~ ");\n") ~ + Attr("V") ~ + " = (!((" ~ A ~ " ^ data) & 0x80)) && ((data ^ a) & 0x80);\n" ~ + "if (a >= 0xA0)\n" ~ + "a = a + 0x60;\n" ~ + C ~ " = (a >= 0x100);\n" ~ + If!(cmos)( + SetNZ(A ~ " = cast(ubyte)a") ~ Peek(Attr("PC"), s, c), + A ~ " = cast(ubyte)a;\n"); +} + + +string Sub(int op, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + ReadInto(Local("ubyte", "data"), "address", c) ~ + "if (" ~ Attr("D") ~ ")\n{\n" ~ + DecSub(chip, s, c) ~ + "}\nelse\n{\n" ~ + HexSub(chip, s, c) ~ + "}\n"; +} + +string HexSub(string chip, bool s, bool c) +{ + string A = Attr("A"), C = Attr("C"); + + return "uint diff = " ~ A ~ " - data - !" ~ C ~ ";\n" ~ + Attr("V") ~ + " = ((" ~ A ~ " ^ diff) & 0x80) && ((" ~ A ~ " ^ data) & 0x80);\n" ~ + C ~ " = (diff < 0x100);\n" ~ + SetNZ(A ~ " = cast(ubyte)diff"); +} + +string DecSub(string chip, bool s, bool c) +{ + return (chip == "6502" ? DecSubNMOS(s, c) : DecSubCMOS(s, c)); +} + +string DecSubNMOS(bool s, bool c) +{ + string A = Attr("A"), C = Attr("C"); + + return "int a = " ~ A ~ ";\n" ~ + "int al = (a & 0x0F) - (data & 0x0F) - !" ~ C ~ ";\n" ~ + "if (al < 0)\n" ~ + "al = ((al - 0x06) & 0x0F) - 0x10;\n" ~ + "a = (a & 0xF0) - (data & 0xF0) + al;\n" ~ + "if (a < 0)\n" ~ + "a = a - 0x60;\n" ~ + "uint diff = " ~ A ~ " - data - !" ~ C ~ ";\n" ~ + Attr("V") ~ + " = ((" ~ A ~ " ^ diff) & 0x80) && ((" ~ A ~ " ^ data) & 0x80);\n" ~ + C ~ " = (diff < 0x100);\n" ~ + SetNZ("cast(ubyte)diff") ~ + A ~ " = cast(ubyte)a;\n"; +} + +string DecSubCMOS(bool s, bool c) +{ + string A = Attr("A"), C = Attr("C"); + + return "int a = " ~ A ~ ";\n" ~ + "int al = (a & 0x0F) - (data & 0x0F) - !" ~ C ~ ";\n" ~ + "a = a - data - !" ~ C ~ ";\n" ~ + "if (a < 0) a = a - 0x60;\n" ~ + "if (al < 0) a = a - 0x06;\n" ~ + "uint diff = " ~ A ~ " - data - !" ~ C ~ ";\n" ~ + Attr("V") ~ + " = ((" ~ A ~ " ^ diff) & 0x80) && ((" ~ A ~ " ^ data) & 0x80);\n" ~ + C ~ " = (diff < 0x100);\n" ~ + Peek(Attr("PC"), s, c) ~ + SetNZ(A ~ " = cast(ubyte)a"); +} + + +string IncReg(string reg, bool s, bool c) +{ + return AddrImplied(s, c) ~ + Attr(reg) ~ "++;\n" ~ + SetNZ(Attr(reg)); +} + + +string DecReg(string reg, bool s, bool c) +{ + return AddrImplied(s, c) ~ + Attr(reg) ~ "--;\n" ~ + SetNZ(Attr(reg)); +} + + +string RMW(int op, string action, string chip, bool s, bool c) +{ + bool nmos = (chip == "6502"); + + return Address(op, chip, s, c) ~ + ReadInto(Local("ubyte", "data"), "address", c) ~ + If!(nmos)(Poke("address", "data", s, c), + Peek("address", s, c)) ~ + action ~ + SetNZ("data") ~ + Write("address", "data", c); +} + + +string Address(int op, string chip, bool s, bool c) +{ + auto EXTRA_CYCLE = opExCyc(op, chip); + auto PC = Attr("PC"); + + final switch (opMode(op, chip)) + { + case IMP: + return AddrImplied(s, c); + case IMM: + return AddrImmediate(s, c); + case ZP: + return Local("ushort", "address") ~ " = 0;"; + case ZPX: + return Local("ushort", "address") ~ " = 0;"; + case ZPY: + return Local("ushort", "address") ~ " = 0;"; + case IZX: + return Local("ushort", "address") ~ " = 0;"; + case IZY: + return Local("ushort", "address") ~ " = 0;"; + case ABS: + return ReadWordOpLocal("ushort", "address", c); + case ABX: + return AddrAbsoluteIdx(op, "X", chip, s, c); + case ABY: + return AddrAbsoluteIdx(op, "Y", chip, s, c); + case IND: + return Local("ushort", "address") ~ " = 0;"; + case REL: + return Local("ushort", "address") ~ " = 0;"; + case ZPI: + return Local("ushort", "address") ~ " = 0;"; + case ABI: + return Local("ushort", "address") ~ " = 0;"; + case NP1: + return Local("ushort", "address") ~ " = 0;"; + case NP8: + return Local("ushort", "address") ~ " = 0;"; + case KIL: + return Local("ushort", "address") ~ " = 0;"; + } + return ""; } @@ -473,25 +838,48 @@ string Peek(string addr, bool strict, bool cumulative) If!(strict)(Attr("memory") ~ ".read(" ~ addr ~");\n"); } -string Read(string var, string addr, bool c) +string Poke(string addr, string val, bool strict, bool cumulative) +{ + return PreAccess(cumulative) ~ + If!(strict)( + Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"); +} + +string ReadInto(string var, string addr, bool c, string action = "=") { return PreAccess(c) ~ - var ~ " = " ~ Attr("memory") ~ ".read(" ~ addr ~");\n"; + var ~ " " ~ action ~ " " ~ ReadRaw("(" ~ addr ~ ")") ~ ";\n"; +} + +string ReadRaw(string addr) +{ + return Attr("memory") ~ ".read(" ~ addr ~")"; } string Write(string addr, string val, bool cumulative) { - return If!(cumulative)("++cycles;\n", Attr("clock") ~ ".tick();\n") ~ + return PreAccess(cumulative) ~ Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"; } string ReadWord(string var, string addr, bool c) { return PreAccess(c) ~ - var ~ " = " ~ Attr("memory") ~ ".read(" ~ addr ~");\n" ~ + var ~ " = " ~ ReadRaw(addr) ~ ";\n" ~ PreAccess(c) ~ - var ~ " |= (" ~ Attr("memory") ~ - ".read(cast(ushort)((" ~ addr ~ ") + 1)) << 8);\n"; + var ~ " |= (" ~ ReadRaw("cast(ushort)((" ~ addr ~ ") + 1)") ~ + " << 8);\n"; +} + +string ReadWordOpLocal(string type, string var, bool c) +{ + string PC = Attr("PC"); + + return PreAccess(c) ~ + Local(type, var) ~ " = " ~ ReadRaw(PC ~ "++") ~ ";\n" ~ + PreAccess(c) ~ + var ~ " |= (" ~ ReadRaw(PC ~ "++") ~ + " << 8);\n"; } @@ -511,6 +899,22 @@ string DecSP() return "--" ~ Attr("S") ~ ";\n"; } +string PullStatus(bool s, bool c) +{ + return Peek("0x0100 + " ~ Attr("S"), s, c) ~ + IncSP() ~ + PreAccess(c) ~ + Attr("statusFromByte") ~ "(" ~ + ReadRaw("0x0100 + " ~ Attr("S")) ~ ");\n"; +} + +string PullInto(string var, bool s, bool c) +{ + return Peek("0x0100 + " ~ Attr("S"), s, c) ~ + IncSP() ~ + ReadInto(var, "0x0100 + " ~ Attr("S"), c); +} + string Push(string val, bool s, bool c) { return Write("0x0100 + " ~ Attr("S"), val, c) ~ @@ -524,11 +928,35 @@ string PushPC(bool s, bool c) } -string Set(string flag) +string PullPC(bool s, bool c) { - return flag ~ " = true;\n"; + string PC = Attr("PC"); + + return PullInto(PC, s, c) ~ + PreAccess(c) ~ + IncSP() ~ + PC ~ " |= (" ~ ReadRaw("0x0100 + " ~ Attr("S")) ~ " << 8);\n"; } +string SetFlag(string flag) +{ + return Attr(flag) ~ " = true;\n"; +} + +string ClearFlag(string flag) +{ + return Attr(flag) ~ " = false;\n"; +} + +string UpdateFlag(string flag, string val) +{ + return Attr(flag) ~ " = (" ~ val ~ ");\n"; +} + +string SetNZ(string var) +{ + return Attr("N") ~ " = " ~ Attr("Z") ~ " = (" ~ var ~ ");\n"; +} string Done(bool cumulative) { @@ -545,6 +973,17 @@ string Attr(string var) } +string Local(string type, string var) +{ + version(OpSwitch) + return var; + else version(OpNestedSwitch) + return var; + else + return type ~ " " ~ var; +} + + string HiByte(string var) { return var ~ " >> 8"; @@ -664,9 +1103,6 @@ immutable OP_NAMES_65C02 = [ // Addressing modes. -enum { IMP, IMM, ZP, ZPX, ZPY, IZX, IZY, ABS, ABX, ABY, IND, REL, - ZPI, ABI, NP1, NP8, KIL } - immutable ADDR_MODES_6502 = [ IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, @@ -779,9 +1215,7 @@ immutable EXTRA_CYCLES_65C02 = [ ]; -// Custom hex printing. -// (to!string(x, 16) uses uppercase, which makes "8" and "B" hard to -// tell apart, and format("%0.2x", x) can't be used in CTFE.) +// Custom string formatting. enum HEX_DIGITS = "0123456789abcdef"; @@ -799,6 +1233,24 @@ string Hex2(int dec) HEX_DIGITS[lowNybble..lowNybble+1]; } +string Fmt(string f, string[] p ...) +{ + if (!p.length) return "ERROR"; + string ret; + size_t last; + size_t other; + for (size_t i = 0; i < f.length; i++) + { + if (f[i] == '#') + { + if (other == p.length) return "ERROR"; + ret ~= f[last..i] ~ p[other++]; + last = i + 1; + } + } + return ret ~ f[last..$]; +} + //alias Cpu!("6502", false, false) T1; //alias Cpu!("6502", false, true) T2; @@ -808,3 +1260,11 @@ string Hex2(int dec) //alias Cpu!("65C02", false, true) T6; //alias Cpu!("65C02", true, false) T7; //alias Cpu!("65C02", true, true) T8; + +/+ +void main() +{ + import std.stdio; + writeln(OpBody(0x9d, "6502", true, false)); +} ++/ diff --git a/test/test_new_cpu.d b/test/test_new_cpu.d index cebae41..29d6003 100644 --- a/test/test_new_cpu.d +++ b/test/test_new_cpu.d @@ -12,7 +12,7 @@ void main() import std.stdio; import test.base, test.cpu; - void test_func(ubyte op) + void test_func(ubyte[] ops) { auto report = report_debug(); auto report2 = report_timing_debug(); @@ -24,16 +24,27 @@ void main() alias Cpu!("6502", s1, c1) TX1; writeln("NMOS ", s1, " ", c1, " func"); - test_one_opcode!TX1(op, report); + foreach (op; ops) + test_one_opcode!TX1(op, report); writeln("NMOS ", s1, " ", c1, " bus"); - test_opcode_timing!TX1(op, report2); + foreach(op; ops) + test_opcode_timing!TX1(op, report2); alias Cpu!("65C02", s1, c1) TX2; writeln("CMOS ", s1, " ", c1, " func"); - test_one_opcode!TX2(op, report); + foreach (op; ops) + test_one_opcode!TX2(op, report); writeln("CMOS ", s1, " ", c1, " bus"); - test_opcode_timing!TX2(op, report2); + foreach (op; ops) + test_opcode_timing!TX2(op, report2); } - test_func(0x00); + test_func([0x00, 0x08, 0x10, 0x18, 0x28, 0x30, 0x38, 0x50, 0x58, 0x68, + 0x70, 0x78, 0x90, 0xad, 0xb0, 0xb8, 0xd0, 0xd8, 0xf0, 0xf8, + 0xae, 0xac, 0x8d, 0x8e, 0x8c, 0xe8, 0xc8, 0xca, 0x88, 0xcd, + 0xec, 0xcc, 0x0d, 0x2d, 0x4d, 0xee, 0xce, 0x60, 0x6d, 0xed, + 0x4c, 0x09, 0x29, 0x49, 0x69, 0xe9, 0xc9, 0xe0, 0xc0, 0xa9, + 0xa2, 0xa0, 0x1d, 0x19, 0x3d, 0x39, 0x5d, 0x59, 0x7d, 0x79, + 0xfd, 0xf9, 0xdd, 0xd9, 0xde, 0xfe, 0xbd, 0xb9, 0x9d, 0x99, + 0xbe, 0xbc]); } diff --git a/test/test_new_cpu.sh b/test/test_new_cpu.sh index 4f603cd..939c316 100755 --- a/test/test_new_cpu.sh +++ b/test/test_new_cpu.sh @@ -1,20 +1,17 @@ -rdmd --force -version=OpDelegates -I.. -I../src test_new_cpu.d -rdmd --force -version=OpDelegates -version=Strict -I.. -I../src test_new_cpu.d -rdmd --force -version=OpDelegates -version=Cumulative -I.. -I../src test_new_cpu.d -rdmd --force -version=OpDelegates -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d - -rdmd --force -version=OpFunctions -I.. -I../src test_new_cpu.d -rdmd --force -version=OpFunctions -version=Strict -I.. -I../src test_new_cpu.d -rdmd --force -version=OpFunctions -version=Cumulative -I.. -I../src test_new_cpu.d -rdmd --force -version=OpFunctions -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d - -rdmd --force -version=OpSwitch -I.. -I../src test_new_cpu.d -rdmd --force -version=OpSwitch -version=Strict -I.. -I../src test_new_cpu.d -rdmd --force -version=OpSwitch -version=Cumulative -I.. -I../src test_new_cpu.d -rdmd --force -version=OpSwitch -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d - -rdmd --force -version=OpNestedSwitch -I.. -I../src test_new_cpu.d -rdmd --force -version=OpNestedSwitch -version=Strict -I.. -I../src test_new_cpu.d -rdmd --force -version=OpNestedSwitch -version=Cumulative -I.. -I../src test_new_cpu.d +rdmd --force -version=OpDelegates -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpDelegates -version=Strict -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpDelegates -version=Cumulative -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpDelegates -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpFunctions -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpFunctions -version=Strict -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpFunctions -version=Cumulative -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpFunctions -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpSwitch -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpSwitch -version=Strict -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpSwitch -version=Cumulative -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpSwitch -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpNestedSwitch -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpNestedSwitch -version=Strict -I.. -I../src test_new_cpu.d && +rdmd --force -version=OpNestedSwitch -version=Cumulative -I.. -I../src test_new_cpu.d && rdmd --force -version=OpNestedSwitch -version=Strict -version=Cumulative -I.. -I../src test_new_cpu.d From 0e330f828550733c9797a507e24bf20e4d03a6ef Mon Sep 17 00:00:00 2001 From: edmccard Date: Mon, 9 Apr 2012 23:32:24 -0400 Subject: [PATCH 09/27] Add all documented 6502 opcodes. --- src/cpu6502.d | 550 ++++++++++++++++++++++++++++++++------------ test/test_new_cpu.d | 9 +- 2 files changed, 405 insertions(+), 154 deletions(-) diff --git a/src/cpu6502.d b/src/cpu6502.d index 3c7b136..fed6329 100644 --- a/src/cpu6502.d +++ b/src/cpu6502.d @@ -1,3 +1,26 @@ +/+ + + cpu6502.d + + + + Copyright: 2012 Ed McCardell, 2007 Gerald Stocker + + + + This file is part of twoapple-reboot. + + + + twoapple-reboot is free software; you can redistribute it and/or modify + + it under the terms of the GNU General Public License as published by + + the Free Software Foundation; either version 2 of the License, or + + (at your option) any later version. + + + + twoapple-reboot is distributed in the hope that it will be useful, + + but WITHOUT ANY WARRANTY; without even the implied warranty of + + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public License + + along with twoapple-reboot; if not, write to the Free Software + + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +/ + + module cpu6502; @@ -78,12 +101,6 @@ static if (!__traits(compiles, { bool b = opArray; })) enum opArray = 0; static assert (versionCheck); -// This needs to be before any mixins which call any CTFE functions -// that make use of these constants. -enum { IMP, IMM, ZP, ZPX, ZPY, IZX, IZY, ABS, ABX, ABY, IND, REL, - ZPI, ABI, NP1, NP8, KIL } - - final class Cpu(string chip, bool strict, bool cumulative) { static assert(chip == "6502" || chip == "65C02" || chip == "65c02"); @@ -122,13 +139,11 @@ final class Cpu(string chip, bool strict, bool cumulative) ubyte A, X, Y, S; ushort PC; + // The status flags. ubyte N, Z; bool V, D, I, C; - static if (opArray) - { - mixin(OpArrayDef()); - } + static if (opArray) { mixin(OpArrayDef()); } // TODO: other methods for stopping cpu bool keepRunning; @@ -192,10 +207,6 @@ enum ushort IRQ_VECTOR = 0xFFFE; private: -version(OpFunctions) mixin(OpBodies("6502", vStrict, vCumulative)); -version(OpFunctions) mixin(OpBodies("65C02", vStrict, vCumulative)); - - string OpArrayDef() { version(OpDelegates) @@ -243,6 +254,18 @@ string OpBodies(string chip, bool strict, bool cumulative) If!(cumulative)("int cycles = 1;\n") ~ OpBody(op, chip, strict, cumulative) ~ "}\n"; } +/+ + foreach (op; 13..256) + version(OpDelegates) + ret ~= "final void opcode_" ~ Hex2(op) ~ "()\n{\n" ~ + If!(cumulative)("int cycles = 1;\n") ~ + "" ~ "}\n"; + version(OpFunctions) + ret ~= "void opcode_" ~ Hex2(op) ~ + "(T)(T cpu) if (is" ~ chip ~ "!T)\n{\n" ~ + If!(cumulative)("int cycles = 1;\n") ~ + "" ~ "}\n"; ++/ return ret; } } @@ -308,7 +331,8 @@ string OpBody(int op, string chip, bool s, bool c) return Jump(op, chip, s, c) ~ Done(c); case "KIL": - return ""; + return Attr("PC") ~ "--;\n" ~ + Done(c); case "BPL": return Branch("!(" ~ Attr("N") ~ " & 0x80)", nmos, s, c) ~ Done(c); @@ -337,82 +361,96 @@ string OpBody(int op, string chip, bool s, bool c) return Branch("!" ~ Attr("Z"), nmos, s, c) ~ Done(c); case "CLC": - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ ClearFlag("C") ~ Done(c); case "SEC": - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ SetFlag("C") ~ Done(c); case "CLI": - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ ClearFlag("I") ~ Done(c); case "SEI": - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ SetFlag("I") ~ Done(c); case "CLV": - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ ClearFlag("V") ~ Done(c); case "CLD": - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ ClearFlag("D") ~ Done(c); case "SED": - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ SetFlag("D") ~ Done(c); case "NOP": - return ""; // address modes + return Nop(op, chip, s, c) ~ + Done(c); case "TAX": - return ""; + return Transfer(op, "A", "X", s, c) ~ + Done(c); case "TXA": - return ""; + return Transfer(op, "X", "A", s, c) ~ + Done(c); case "TAY": - return ""; + return Transfer(op, "A", "Y", s, c) ~ + Done(c); case "TYA": - return ""; + return Transfer(op, "Y", "A", s, c) ~ + Done(c); case "TSX": - return ""; + return Transfer(op, "S", "X", s, c) ~ + Done(c); case "TXS": - return ""; + return Transfer(op, "X", "S", s, c) ~ + Done(c); case "DEX": - return DecReg("X", s, c) ~ + return AddrIMP(s, c) ~ + Dec(Attr("X")) ~ Done(c); case "DEY": - return DecReg("Y", s, c) ~ + return AddrIMP(s, c) ~ + Dec(Attr("Y")) ~ Done(c); case "INX": - return IncReg("X", s, c) ~ + return AddrIMP(s, c) ~ + Inc(Attr("X")) ~ Done(c); case "INY": - return IncReg("Y", s, c) ~ + return AddrIMP(s, c) ~ + Inc(Attr("Y")) ~ Done(c); case "PHP": - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ Push(Attr("statusToByte()"), s, c) ~ Done(c); case "PLP": - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ PullStatus(s, c) ~ Done(c); case "PLA": - return AddrImplied(s, c) ~ - PullInto(Attr("A"), s, c) ~ - SetNZ(Attr("A")) ~ + return PullReg("A", s, c) ~ Done(c); case "PLX": - return ""; + return PullReg("X", s, c) ~ + Done(c); case "PLY": - return ""; + return PullReg("Y", s, c) ~ + Done(c); case "PHA": - return ""; + return PushReg("A", s, c) ~ + Done(c); case "PHX": - return ""; + return PushReg("X", s, c) ~ + Done(c); case "PHY": - return ""; + return PushReg("Y", s, c) ~ + Done(c); case "LDA": return Load(op, "A", chip, s, c) ~ Done(c); @@ -434,7 +472,8 @@ string OpBody(int op, string chip, bool s, bool c) case "STZ": return ""; case "BIT": - return ""; // address modes + return Bit(op, chip, s, c) ~ + Done(c); case "CMP": return Compare(op, "A", chip, s, c) ~ Done(c); @@ -460,23 +499,35 @@ string OpBody(int op, string chip, bool s, bool c) return Sub(op, chip, s, c) ~ Done(c); case "ASL": - return ""; // n/c (op, cyc) + if (op == 0x0a) + return AddrIMP(s, c) ~ ShiftLeft(Attr("A")) ~ Done(c); + else + return RMW(op, ShiftLeft("data"), chip, s, c) ~ Done(c); case "ROL": - return ""; // n/c (op, cyc) + if (op == 0x2a) + return AddrIMP(s, c) ~ RotateLeft(Attr("A")) ~ Done(c); + else + return RMW(op, RotateLeft("data"), chip, s, c) ~ Done(c); case "LSR": - return ""; // n/c (op, cyc) + if (op == 0x4a) + return AddrIMP(s, c) ~ ShiftRight(Attr("A")) ~ Done(c); + else + return RMW(op, ShiftRight("data"), chip, s, c) ~ Done(c); case "ROR": - return ""; // n/c (op, cyc) + if (op == 0x6a) + return AddrIMP(s, c) ~ ShiftRight(Attr("A")) ~ Done(c); + else + return RMW(op, RotateRight("data"), chip, s, c) ~ Done(c); case "INC": if (op == 0x1a) - return IncReg("A", s, c) ~ Done(c); + return AddrIMP(s, c) ~ Inc(Attr("A")) ~ Done(c); else - return RMW(op, "data++;\n", chip, s, c) ~ Done(c); + return RMW(op, Inc("data"), chip, s, c) ~ Done(c); case "DEC": if (op == 0x3a) - return DecReg("A", s, c) ~ Done(c); + return AddrIMP(s, c) ~ Dec(Attr("A")) ~ Done(c); else - return RMW(op, "data--;\n", chip, s, c) ~ Done(c); + return RMW(op, Dec("data"), chip, s, c) ~ Done(c); case "TRB": return ""; case "TSB": @@ -521,52 +572,116 @@ string OpBody(int op, string chip, bool s, bool c) } -string AddrImmediate(bool s, bool c) +string AddrIMM(bool s, bool c) { - return Local("ushort", "address") ~ " = " ~ Attr("PC") ~ "++;\n"; + return Local("ushort") ~ "address = " ~ Attr("PC") ~ "++;\n"; } -string AddrImplied(bool s, bool c) +string AddrIMP(bool s, bool c) { return Peek(Attr("PC"), s, c); } +string AddrZP(bool s, bool c) +{ + return ReadOp(Local("ushort", "address"), c); +} -string AddrAbsoluteIdx(int op, string reg, string chip, bool s, bool c) +string AddrZPXY(string reg, string chip, bool s, bool c) +{ + bool nmos = (chip == "6502"); + + return ReadOp(Local("ushort", "base"), c) ~ + If!(nmos)( + Peek("base", s, c), + Peek(Attr("PC"), s, c)) ~ + Local("ushort") ~ + "address = cast(ubyte)(base + " ~ Attr(reg) ~ ");\n"; +} + +string AddrIZX(string chip, bool s, bool c) +{ + bool nmos = (chip == "6502"); + return ReadOp(Local("ushort", "base"), c) ~ + If!(nmos)( + Peek("base", s, c), + Peek(Attr("PC"), s, c)) ~ + ReadWordZP("ushort", "address", "base + " ~ Attr("X"), c); +} + +string AddrIZY(int op, string chip, bool s, bool c) +{ + int exCyc = opExCyc(op, chip); + bool nmos = (chip == "6502"); + + return ReadOp("ubyte vector", c) ~ + ReadWordZP("ushort", "base", "vector", c) ~ + Local("ushort") ~ + "address = cast(ushort)(base + " ~ Attr("Y") ~ ");\n" ~ + CheckShortcut("address", Attr("PC"), + exCyc, nmos, s, c); +} + +string AddrABS(bool s, bool c) +{ + return ReadWordOp("ushort", "address", c); +} + +string AddrABXY(int op, string reg, string chip, bool s, bool c) { bool nmos = (chip == "6502"); int exCyc = opExCyc(op, chip); string IDX = Attr(reg); - return ReadWordOpLocal("ushort", "base", c) ~ - Local("ushort","address")~" = cast(ushort)(base + " ~ IDX ~ ");\n" ~ - "ushort guess = (base & 0xFF00) | cast(ubyte)address;\n" ~ - "if (guess != address)\n{\n" ~ - If!(nmos)(Peek("guess", s, c), Peek(Attr("PC"), s, c)) ~ + return ReadWordOp("ushort", "base", c) ~ + Local("ushort") ~ "address = cast(ushort)(base + " ~ IDX ~ ");\n" ~ + CheckShortcut("address", Attr("PC"), exCyc, nmos, s, c); +} + +string AddrZPI(bool s, bool c) +{ + return ReadOp(Local("ushort", "base"), c) ~ + ReadWordZP("ushort", "address", "base", c); +} + +string Branch(string check, bool nmos, bool s, bool c) +{ + string PC = Attr("PC"); + return ReadOp(Local("ubyte", "op1"), c) ~ + "if (" ~ check ~ ")\n{\n" ~ + Peek(PC, s, c) ~ + Local("ushort", "base") ~ " = " ~ PC ~ ";\n" ~ + PC ~ " = cast(ushort)(" ~ PC ~ " + cast(byte)op1);\n" ~ + CheckShortcut(Attr("PC"), "base", 0, nmos, s, c) ~ + "}\n"; +} + +string CheckShortcut(string addr, string pc, int exCyc, bool nmos, bool s, + bool c) +{ + return "ushort guess = (base & 0xFF00) | cast(ubyte)" ~ addr ~ ";\n" ~ + "if (guess != " ~ addr ~ ")\n{\n" ~ + If!(nmos)(Peek("guess", s, c), + Peek(pc, s, c)) ~ "}\n" ~ If!(exCyc)("else\n{\n" ~ Peek("address", s, c) ~ "}\n"); } -string Branch(string check, bool nmos, bool s, bool c) +string Nop(int op, string chip, bool s, bool c) { - string PC = Attr("PC"); - return ReadInto(Local("ubyte", "op1"), PC, c) ~ - IncPC() ~ - "if (" ~ check ~ ")\n{\n" ~ - Peek(PC, s, c) ~ - Local("ushort", "base") ~ " = " ~ PC ~ ";\n" ~ - PC ~ " = cast(ushort)(" ~ PC ~ " + cast(byte)op1);\n" ~ - "ushort guess = (base & 0xFF00) | cast(ubyte)" ~ PC ~ ";\n" ~ - "if (guess != " ~ PC ~ ")\n{\n" ~ - If!(nmos)(Peek("guess", s, c), Peek("base", s, c)) ~ - "}\n}\n"; + auto mode = opMode(op, chip); + if (mode == IMP || mode == NP1 || mode == NP8) + return Address(op, chip, s, c); + else + return Address(op, chip, s, c) ~ + Peek("address", true, c); } string Break(bool s, bool c) { - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ IncPC() ~ PushPC(s, c) ~ Push(Attr("statusToByte()"), s, c) ~ @@ -577,11 +692,9 @@ string Break(bool s, bool c) string RetSub(bool s, bool c) { - string PC = Attr("PC"); - - return AddrImplied(s, c) ~ + return AddrIMP(s, c) ~ PullPC(s, c) ~ - Peek(PC, s, c) ~ + Peek(Attr("PC"), s, c) ~ IncPC(); } @@ -590,22 +703,149 @@ string JumpSub(bool s, bool c) { string PC = Attr("PC"); - return ReadInto(Local("ushort", "address"), PC ~ "++", c) ~ + return ReadOp(Local("ushort", "address"), c) ~ Peek("0x0100 + " ~ Attr("S"), s, c) ~ PushPC(s, c) ~ - PreAccess(c) ~ - "address |= (" ~ ReadRaw(PC ~ "++") ~ " << 8);\n" ~ + PreAccess(c) ~ "address |= (" ~ ReadRaw(PC ~ "++") ~ " << 8);\n" ~ PC ~ " = address;\n"; } string Jump(int op, string chip, bool s, bool c) { + bool nmos = (chip == "6502"); + string PC = Attr("PC"); + if (op == 0x4c) return Address(op, chip, s, c) ~ - Attr("PC") ~ " = address;\n"; - else + PC ~ " = address;\n"; + else if (op == 0x6c) + return ReadWordOp("ushort", "base", c) ~ + If!(nmos)( + "", + Peek(PC, s, c)) ~ + ReadWordBasic(PC, "base", + If!(nmos)( + "(base & 0xFF00) | cast(ubyte)(base + 1)", + "cast(ushort)(base + 1)"), c); + else if (op == 0x7c) + return ReadWordOp("ushort", "base", c) ~ + Peek(PC, s, c) ~ + ReadWord(PC, "cast(ushort)(base + " ~ Attr("X") ~ ")", c); + return ""; +} + + +string ReadInto(string var, string action, string addr, bool c) +{ + return PreAccess(c) ~ + var ~ " " ~ action ~ " " ~ ReadRaw("(" ~ addr ~ ")") ~ ";\n"; +} + +string ReadInto(string var, string addr, bool c) +{ + return ReadInto(var, "=", addr, c); +} + +string ReadOp(string var, bool c) +{ + return ReadInto(var, Attr("PC") ~ "++", c); +} + +string ReadRaw(string addr) +{ + return Attr("memory") ~ ".read(" ~ addr ~")"; +} + +string ReadWordBasic(string type, string var, string addr1, string addr2, + bool c) +{ + return PreAccess(c) ~ + Local(type, var) ~ " = " ~ ReadRaw(addr1) ~ ";\n" ~ + PreAccess(c) ~ + var ~ " |= ((" ~ ReadRaw(addr2) ~ ") << 8);\n"; +} + +string ReadWordBasic(string var, string addr1, string addr2, bool c) +{ + return ReadWordBasic("", var, addr1, addr2, c); +} + +string ReadWord(string type, string var, string addr, bool c) +{ + return ReadWordBasic(type, var, addr, "cast(ushort)(" ~ addr ~ " + 1)", c); +} + +string ReadWord(string var, string addr, bool c) +{ + return ReadWord("", var, addr, c); +} + +string ReadWordZP(string type, string var, string addr, bool c) +{ + return ReadWordBasic(type, var, "cast(ubyte)( " ~ addr ~ ")", + "cast(ubyte)(" ~ addr ~ " + 1)", c); +} + +string ReadWordZP(string var, string addr, bool c) +{ + return ReadWordZP("", var, addr, c); +} + +string ReadWordOp(string type, string var, bool c) +{ + string PC = Attr("PC"); + + return ReadWordBasic(type, var, PC ~ "++", PC ~ "++", c); +} + +string ReadWordOp(string var, bool c) +{ + return ReadWordOp("", var, c); +} + + +string Local(string type) +{ + version(OpSwitch) return ""; + else version(OpNestedSwitch) + return ""; + else + return type ~ " "; +} + +string Local(string type, string var) +{ + version(OpSwitch) + return var; + else version(OpNestedSwitch) + return var; + else + return type ~ " " ~ var; +} + + +string Transfer(int op, string source, string dest, bool s, bool c) +{ + return AddrIMP(s, c) ~ + Attr(dest) ~ " = " ~ Attr(source) ~ ";\n" ~ + ((op != 0x9a) ? SetNZ(Attr(dest)) : ""); +} + + +string PullReg(string reg, bool s, bool c) +{ + return AddrIMP(s, c) ~ + PullInto(Attr(reg), s, c) ~ + SetNZ(Attr(reg)); +} + + +string PushReg(string reg, bool s, bool c) +{ + return AddrIMP(s, c) ~ + Push(Attr(reg), s, c); } @@ -633,10 +873,23 @@ string Compare(int op, string reg, string chip, bool s, bool c) } +string Bit(int op, string chip, bool s, bool c) +{ + bool notImm = (opMode(op, chip) != IMM); + + return Address(op, chip, s, c) ~ + ReadInto(Local("ubyte", "data"), "address", c) ~ + If!(notImm)( + Attr("N") ~ " = data;\n" ~ + Attr("V") ~ " = ((data & 0x40) != 0);\n") ~ + Attr("Z") ~ " = (" ~ Attr("A") ~ " & data);\n"; +} + + string Logic(int op, string action, string chip, bool s, bool c) { return Address(op, chip, s, c) ~ - ReadInto(Attr("A"), "address", c, action) ~ + ReadInto(Attr("A"), action, "address", c) ~ SetNZ(Attr("A")); } @@ -646,9 +899,9 @@ string Add(int op, string chip, bool s, bool c) return Address(op, chip, s, c) ~ ReadInto(Local("ubyte", "data"), "address", c) ~ "if (" ~ Attr("D") ~ ")\n{\n" ~ - DecAdd(chip, s, c) ~ + DecAdd(chip, s, c) ~ "}\nelse\n{\n" ~ - HexAdd(chip, s, c) ~ + HexAdd(chip, s, c) ~ "}\n"; } @@ -692,9 +945,9 @@ string Sub(int op, string chip, bool s, bool c) return Address(op, chip, s, c) ~ ReadInto(Local("ubyte", "data"), "address", c) ~ "if (" ~ Attr("D") ~ ")\n{\n" ~ - DecSub(chip, s, c) ~ + DecSub(chip, s, c) ~ "}\nelse\n{\n" ~ - HexSub(chip, s, c) ~ + HexSub(chip, s, c) ~ "}\n"; } @@ -751,22 +1004,50 @@ string DecSubCMOS(bool s, bool c) } -string IncReg(string reg, bool s, bool c) +string Inc(string val) { - return AddrImplied(s, c) ~ - Attr(reg) ~ "++;\n" ~ - SetNZ(Attr(reg)); + return val ~ "++;\n" ~ + SetNZ(val); } -string DecReg(string reg, bool s, bool c) +string Dec(string val) { - return AddrImplied(s, c) ~ - Attr(reg) ~ "--;\n" ~ - SetNZ(Attr(reg)); + return val ~ "--;\n" ~ + SetNZ(val); } +string ShiftLeft(string val) +{ + return Attr("C") ~ " = (" ~ val ~ " > 0x7F);\n" ~ + SetNZ(val ~ " = cast(ubyte)(" ~ val ~ " << 1)"); +} + +string RotateLeft(string val) +{ + string C = Attr("C"); + + return "auto oldC = " ~ C ~ ";\n" ~ + C ~ " = (" ~ val ~ " > 0x7f);\n" ~ + SetNZ(val ~ " = cast(ubyte)(" ~ val ~ " << 1 | (oldC ? 1 : 0))"); +} + +string ShiftRight(string val) +{ + return Attr("C") ~ " = ((" ~ val ~ " & 0x01) != 0);\n" ~ + SetNZ(val ~ " = " ~ val ~ " >> 1"); +} + +string RotateRight(string val) +{ + string C = Attr("C"); + + return "auto oldC = " ~ C ~ ";\n" ~ + C ~ " = ((" ~ val ~ " & 0x01) != 0);\n" ~ + SetNZ(val ~ " = (" ~ val ~ " >> 1 | (oldC ? 0x80 : 0))"); +} + string RMW(int op, string action, string chip, bool s, bool c) { bool nmos = (chip == "6502"); @@ -776,7 +1057,6 @@ string RMW(int op, string action, string chip, bool s, bool c) If!(nmos)(Poke("address", "data", s, c), Peek("address", s, c)) ~ action ~ - SetNZ("data") ~ Write("address", "data", c); } @@ -789,35 +1069,35 @@ string Address(int op, string chip, bool s, bool c) final switch (opMode(op, chip)) { case IMP: - return AddrImplied(s, c); + return AddrIMP(s, c); case IMM: - return AddrImmediate(s, c); + return AddrIMM(s, c); case ZP: - return Local("ushort", "address") ~ " = 0;"; + return AddrZP(s, c); case ZPX: - return Local("ushort", "address") ~ " = 0;"; + return AddrZPXY("X", chip, s, c); case ZPY: - return Local("ushort", "address") ~ " = 0;"; + return AddrZPXY("Y", chip, s, c); case IZX: - return Local("ushort", "address") ~ " = 0;"; + return AddrIZX(chip, s, c); case IZY: - return Local("ushort", "address") ~ " = 0;"; + return AddrIZY(op, chip, s, c); case ABS: - return ReadWordOpLocal("ushort", "address", c); + return AddrABS(s, c); case ABX: - return AddrAbsoluteIdx(op, "X", chip, s, c); + return AddrABXY(op, "X", chip, s, c); case ABY: - return AddrAbsoluteIdx(op, "Y", chip, s, c); + return AddrABXY(op, "Y", chip, s, c); case IND: return Local("ushort", "address") ~ " = 0;"; case REL: return Local("ushort", "address") ~ " = 0;"; case ZPI: - return Local("ushort", "address") ~ " = 0;"; + return AddrZPI(s, c); case ABI: return Local("ushort", "address") ~ " = 0;"; case NP1: - return Local("ushort", "address") ~ " = 0;"; + return ""; case NP8: return Local("ushort", "address") ~ " = 0;"; case KIL: @@ -845,44 +1125,12 @@ string Poke(string addr, string val, bool strict, bool cumulative) Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"); } -string ReadInto(string var, string addr, bool c, string action = "=") -{ - return PreAccess(c) ~ - var ~ " " ~ action ~ " " ~ ReadRaw("(" ~ addr ~ ")") ~ ";\n"; -} - -string ReadRaw(string addr) -{ - return Attr("memory") ~ ".read(" ~ addr ~")"; -} - string Write(string addr, string val, bool cumulative) { return PreAccess(cumulative) ~ Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"; } -string ReadWord(string var, string addr, bool c) -{ - return PreAccess(c) ~ - var ~ " = " ~ ReadRaw(addr) ~ ";\n" ~ - PreAccess(c) ~ - var ~ " |= (" ~ ReadRaw("cast(ushort)((" ~ addr ~ ") + 1)") ~ - " << 8);\n"; -} - -string ReadWordOpLocal(string type, string var, bool c) -{ - string PC = Attr("PC"); - - return PreAccess(c) ~ - Local(type, var) ~ " = " ~ ReadRaw(PC ~ "++") ~ ";\n" ~ - PreAccess(c) ~ - var ~ " |= (" ~ ReadRaw(PC ~ "++") ~ - " << 8);\n"; -} - - string IncPC() { return "++" ~ Attr("PC") ~ ";\n"; @@ -973,17 +1221,6 @@ string Attr(string var) } -string Local(string type, string var) -{ - version(OpSwitch) - return var; - else version(OpNestedSwitch) - return var; - else - return type ~ " " ~ var; -} - - string HiByte(string var) { return var ~ " >> 8"; @@ -1103,6 +1340,9 @@ immutable OP_NAMES_65C02 = [ // Addressing modes. +enum { IMP, IMM, ZP, ZPX, ZPY, IZX, IZY, ABS, ABX, ABY, IND, REL, + ZPI, ABI, NP1, NP8, KIL } + immutable ADDR_MODES_6502 = [ IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, @@ -1252,6 +1492,10 @@ string Fmt(string f, string[] p ...) } +version(OpFunctions) mixin(OpBodies("6502", vStrict, vCumulative)); +version(OpFunctions) mixin(OpBodies("65C02", vStrict, vCumulative)); + + //alias Cpu!("6502", false, false) T1; //alias Cpu!("6502", false, true) T2; //alias Cpu!("6502", true, false) T3; @@ -1265,6 +1509,6 @@ string Fmt(string f, string[] p ...) void main() { import std.stdio; - writeln(OpBody(0x9d, "6502", true, false)); + writeln(OpBody(0x11, "6502", true, false)); } +/ diff --git a/test/test_new_cpu.d b/test/test_new_cpu.d index 29d6003..4b82f44 100644 --- a/test/test_new_cpu.d +++ b/test/test_new_cpu.d @@ -46,5 +46,12 @@ void main() 0x4c, 0x09, 0x29, 0x49, 0x69, 0xe9, 0xc9, 0xe0, 0xc0, 0xa9, 0xa2, 0xa0, 0x1d, 0x19, 0x3d, 0x39, 0x5d, 0x59, 0x7d, 0x79, 0xfd, 0xf9, 0xdd, 0xd9, 0xde, 0xfe, 0xbd, 0xb9, 0x9d, 0x99, - 0xbe, 0xbc]); + 0xbe, 0xbc, 0x6c, 0x7c, 0xb2, 0x72, 0x32, 0xd2, 0x52, 0x12, + 0xf2, 0x92, 0xaa, 0x8a, 0xa8, 0x98, 0xba, 0x9a, 0x0a, 0x0e, + 0x1e, 0x48, 0x2c, 0x05, 0x25, 0x45, 0x65, 0xe5, 0xc5, 0xe4, + 0xc4, 0xc6, 0xe6, 0x06, 0x26, 0x46, 0x66, 0xa5, 0x85, 0xa6, + 0x86, 0xa4, 0x84, 0x24, 0x15, 0x35, 0x55, 0x75, 0xf5, 0xd5, + 0xd6, 0xf6, 0x16, 0x36, 0x56, 0x76, 0xb5, 0x95, 0xb6, 0x96, + 0xb4, 0x94, 0x01, 0x21, 0x41, 0x61, 0xe1, 0xc1, 0xa1, 0x81, + 0x11, 0x31, 0x51, 0x71, 0xf1, 0xd1, 0xb1, 0x91]); } From 7e5c7131ef576e618eaf8d56de9609fc055c759f Mon Sep 17 00:00:00 2001 From: edmccard Date: Tue, 10 Apr 2012 17:58:26 -0400 Subject: [PATCH 10/27] Remove cpu dependency from peripherals --- src/system/base.d | 2 +- src/system/peripheral.d | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/system/base.d b/src/system/base.d index 2e6328a..417773b 100644 --- a/src/system/base.d +++ b/src/system/base.d @@ -92,7 +92,7 @@ class System decoder.nullRead = &video_.scanner.floatingBus; peripherals = newPeripherals(); - peripherals.install(cpu, decoder, memory_.mainRom); + peripherals.install(decoder, memory_.mainRom); ioMem.initialize(decoder, switches, timer, peripherals); input.onReset = &reset; diff --git a/src/system/peripheral.d b/src/system/peripheral.d index 2291e91..8dd3014 100644 --- a/src/system/peripheral.d +++ b/src/system/peripheral.d @@ -23,9 +23,6 @@ module system.peripheral; import memory; -import d6502.base; - -private alias d6502.base.CpuBase!(Strict.no, Cumulative.no) CpuBase; import peripheral.base; import peripheral.diskii; @@ -36,7 +33,7 @@ class Peripherals { Peripheral[8] cards; - abstract void install(CpuBase cpu, AddressDecoder decoder, Rom mainRom); + abstract void install(AddressDecoder decoder, Rom mainRom); void reboot() { @@ -59,7 +56,7 @@ class Peripherals class Peripherals_II : Peripherals { - void install(CpuBase cpu, AddressDecoder decoder, Rom mainRom) + void install(AddressDecoder decoder, Rom mainRom) { auto diskController = new Controller(); cards[6] = diskController; // XXX @@ -78,7 +75,7 @@ class Peripherals_II : Peripherals class Peripherals_IIe : Peripherals { - void install(CpuBase cpu, AddressDecoder decoder, Rom mainRom) + void install(AddressDecoder decoder, Rom mainRom) { auto diskController = new Controller(); cards[6] = diskController; // XXX From f3ebb822a6c08e7a086851b2205c05d53231ae48 Mon Sep 17 00:00:00 2001 From: edmccard Date: Tue, 10 Apr 2012 19:31:47 -0400 Subject: [PATCH 11/27] Split ctfe code from cpu code --- src/Makefile | 2 +- src/{cpu6502.d => cpu/ctfe_d6502.d} | 366 +--------------------------- src/cpu/d6502.d | 179 ++++++++++++++ src/cpu/data_d6502.d | 190 +++++++++++++++ test/cpu.d | 2 +- 5 files changed, 373 insertions(+), 366 deletions(-) rename src/{cpu6502.d => cpu/ctfe_d6502.d} (69%) create mode 100644 src/cpu/d6502.d create mode 100644 src/cpu/data_d6502.d diff --git a/src/Makefile b/src/Makefile index 48e0a18..7136c8f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -5,7 +5,7 @@ LINK_OPTS = -L-lpthread -L-lGL -L-ldl -L-lX11 \ -L-L$(GTKD) -L-lgtkd -L-lgtkdgl \ -L-L$(DERELICT)/lib -L-lDerelictSDL -L-lDerelictUtil \ -ALL_SRC = $(shell find -name "*.d" \! -name "cpu6502.d") +ALL_SRC = $(shell find -name "*.d" \! -path "./cpu/*") ALL_OBJS = $(ALL_SRC:%.d=%.o) all: ${ALL_OBJS} diff --git a/src/cpu6502.d b/src/cpu/ctfe_d6502.d similarity index 69% rename from src/cpu6502.d rename to src/cpu/ctfe_d6502.d index fed6329..df3e97e 100644 --- a/src/cpu6502.d +++ b/src/cpu/ctfe_d6502.d @@ -1,52 +1,7 @@ -/+ - + cpu6502.d - + - + Copyright: 2012 Ed McCardell, 2007 Gerald Stocker - + - + This file is part of twoapple-reboot. - + - + twoapple-reboot is free software; you can redistribute it and/or modify - + it under the terms of the GNU General Public License as published by - + the Free Software Foundation; either version 2 of the License, or - + (at your option) any later version. - + - + twoapple-reboot is distributed in the hope that it will be useful, - + but WITHOUT ANY WARRANTY; without even the implied warranty of - + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - + GNU General Public License for more details. - + - + You should have received a copy of the GNU General Public License - + along with twoapple-reboot; if not, write to the Free Software - + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - +/ +module cpu.ctfe_d6502; -module cpu6502; - - -import std.array, std.format; - - -enum Strict : bool -{ - no, yes -} - -enum Cumulative : bool -{ - no, yes -} - - -template is6502(T) -{ - enum is6502 = __traits(getMember, T, "_chip") == "6502"; -} - -template is65C02(T) -{ - enum is65C02 = __traits(getMember, T, "_chip") == "65C02"; -} +import cpu.data_d6502; // The following versions are mutually exclusive. @@ -101,112 +56,6 @@ static if (!__traits(compiles, { bool b = opArray; })) enum opArray = 0; static assert (versionCheck); -final class Cpu(string chip, bool strict, bool cumulative) -{ - static assert(chip == "6502" || chip == "65C02" || chip == "65c02"); - enum _isCpu = true; - enum _chip = (chip == "6502" ? "6502" : "65C02"); - enum _isStrict = strict; - enum _isCumulative = cumulative; - - struct _Mem - { - // Reads a value from system memory. - ubyte delegate(ushort addr) read; - - // Writes a value to system memory. - void delegate(ushort addr, ubyte val) write; - } - _Mem memory; - - struct _Clock - { - static if (cumulative) - /* - * Updates the number of cycles executed. Called just - * prior to the final read/write action of each opcode. - */ - void delegate(int cycles) tick; - else - /* - * Increments the number of cycles executed. Called prior - * to each read/write action. - */ - void delegate() tick; - } - _Clock clock; - - ubyte A, X, Y, S; - ushort PC; - - // The status flags. - ubyte N, Z; - bool V, D, I, C; - - static if (opArray) { mixin(OpArrayDef()); } - - // TODO: other methods for stopping cpu - bool keepRunning; - - this() - { - static if (opArray) mixin(OpArrayInit()); - } - - final void statusFromByte(ubyte p) - { - N = p; - V = ((p & 0x40) != 0); - D = ((p & 0x08) != 0); - I = ((p & 0x04) != 0); - Z = ((p & 0x02) ? 0 : 1); - C = ((p & 0x01) != 0); - } - - final ubyte statusToByte() - { - return (C ? 0x01 : 0) | - ((Z == 0) ? 0x02 : 0) | - (I ? 0x04 : 0) | - (D ? 0x08 : 0) | - 0x30 | // break and reserved both set - (V ? 0x40 : 0) | - (N & 0x80); - } - - final void run(bool continuous) - { - keepRunning = continuous; - // TODO debugging info? - ubyte opcode; - static if (!opArray) - { - static if (cumulative) { int cycles; } - ubyte op1; - ushort address, base; - ubyte data; - } - do { - static if (cumulative && !opArray) - cycles = 1; - // XXX figure out final cycle stuff - static if (!cumulative) - clock.tick(); - // XXX check signals, NMI/IRQ delays, etc. - opcode = memory.read(PC++); - mixin(OpExecute(_chip, strict, cumulative)); - } while (keepRunning); - } - - version(OpDelegates) mixin (OpBodies(_chip, strict, cumulative)); -} - - -enum ushort IRQ_VECTOR = 0xFFFE; - - -private: - string OpArrayDef() { version(OpDelegates) @@ -1266,195 +1115,6 @@ int opExCyc(int op, string chip) } -// Opcode names. -immutable OP_NAMES_6502 = [ - "BRK", "ORA", "KIL", "SLO", "NOP", "ORA", "ASL", "SLO", - "PHP", "ORA", "ASL", "ANC", "NOP", "ORA", "ASL", "SLO", - "BPL", "ORA", "KIL", "SLO", "NOP", "ORA", "ASL", "SLO", - "CLC", "ORA", "NOP", "SLO", "NOP", "ORA", "ASL", "SLO", - "JSR", "AND", "KIL", "RLA", "BIT", "AND", "ROL", "RLA", - "PLP", "AND", "ROL", "ANC", "BIT", "AND", "ROL", "RLA", - "BMI", "AND", "KIL", "RLA", "NOP", "AND", "ROL", "RLA", - "SEC", "AND", "NOP", "RLA", "NOP", "AND", "ROL", "RLA", - "RTI", "EOR", "KIL", "SRE", "NOP", "EOR", "LSR", "SRE", - "PHA", "EOR", "LSR", "ALR", "JMP", "EOR", "LSR", "SRE", - "BVC", "EOR", "KIL", "SRE", "NOP", "EOR", "LSR", "SRE", - "CLI", "EOR", "NOP", "SRE", "NOP", "EOR", "LSR", "SRE", - "RTS", "ADC", "KIL", "RRA", "NOP", "ADC", "ROR", "RRA", - "PLA", "ADC", "ROR", "ARR", "JMP", "ADC", "ROR", "RRA", - "BVS", "ADC", "KIL", "RRA", "NOP", "ADC", "ROR", "RRA", - "SEI", "ADC", "NOP", "RRA", "NOP", "ADC", "ROR", "RRA", - "NOP", "STA", "NOP", "SAX", "STY", "STA", "STX", "SAX", - "DEY", "NOP", "TXA", "XAA", "STY", "STA", "STX", "SAX", - "BCC", "STA", "KIL", "AHX", "STY", "STA", "STX", "SAX", - "TYA", "STA", "TXS", "TAS", "SHY", "STA", "SHX", "AHX", - "LDY", "LDA", "LDX", "LAX", "LDY", "LDA", "LDX", "LAX", - "TAY", "LDA", "TAX", "LAX", "LDY", "LDA", "LDX", "LAX", - "BCS", "LDA", "KIL", "LAX", "LDY", "LDA", "LDX", "LAX", - "CLV", "LDA", "TSX", "LAS", "LDY", "LDA", "LDX", "LAX", - "CPY", "CMP", "NOP", "DCP", "CPY", "CMP", "DEC", "DCP", - "INY", "CMP", "DEX", "AXS", "CPY", "CMP", "DEC", "DCP", - "BNE", "CMP", "KIL", "DCP", "NOP", "CMP", "DEC", "DCP", - "CLD", "CMP", "NOP", "DCP", "NOP", "CMP", "DEC", "DCP", - "CPX", "SBC", "NOP", "ISC", "CPX", "SBC", "INC", "ISC", - "INX", "SBC", "NOP", "SBC", "CPX", "SBC", "INC", "ISC", - "BEQ", "SBC", "KIL", "ISC", "NOP", "SBC", "INC", "ISC", - "SED", "SBC", "NOP", "ISC", "NOP", "SBC", "INC", "ISC" -]; - -immutable OP_NAMES_65C02 = [ - "BRK", "ORA", "NOP", "NOP", "TSB", "ORA", "ASL", "NOP", - "PHP", "ORA", "ASL", "NOP", "TSB", "ORA", "ASL", "NOP", - "BPL", "ORA", "ORA", "NOP", "TRB", "ORA", "ASL", "NOP", - "CLC", "ORA", "INC", "NOP", "TRB", "ORA", "ASL", "NOP", - "JSR", "AND", "NOP", "NOP", "BIT", "AND", "ROL", "NOP", - "PLP", "AND", "ROL", "NOP", "BIT", "AND", "ROL", "NOP", - "BMI", "AND", "AND", "NOP", "BIT", "AND", "ROL", "NOP", - "SEC", "AND", "DEC", "NOP", "BIT", "AND", "ROL", "NOP", - "RTI", "EOR", "NOP", "NOP", "NOP", "EOR", "LSR", "NOP", - "PHA", "EOR", "LSR", "NOP", "JMP", "EOR", "LSR", "NOP", - "BVC", "EOR", "EOR", "NOP", "NOP", "EOR", "LSR", "NOP", - "CLI", "EOR", "PHY", "NOP", "NOP", "EOR", "LSR", "NOP", - "RTS", "ADC", "NOP", "NOP", "STZ", "ADC", "ROR", "NOP", - "PLA", "ADC", "ROR", "NOP", "JMP", "ADC", "ROR", "NOP", - "BVS", "ADC", "ADC", "NOP", "STZ", "ADC", "ROR", "NOP", - "SEI", "ADC", "PLY", "NOP", "JMP", "ADC", "ROR", "NOP", - "BRA", "STA", "NOP", "NOP", "STY", "STA", "STX", "NOP", - "DEY", "BIT", "TXA", "NOP", "STY", "STA", "STX", "NOP", - "BCC", "STA", "STA", "NOP", "STY", "STA", "STX", "NOP", - "TYA", "STA", "TXS", "NOP", "STZ", "STA", "STZ", "NOP", - "LDY", "LDA", "LDX", "NOP", "LDY", "LDA", "LDX", "NOP", - "TAY", "LDA", "TAX", "NOP", "LDY", "LDA", "LDX", "NOP", - "BCS", "LDA", "LDA", "NOP", "LDY", "LDA", "LDX", "NOP", - "CLV", "LDA", "TSX", "NOP", "LDY", "LDA", "LDX", "NOP", - "CPY", "CMP", "NOP", "NOP", "CPY", "CMP", "DEC", "NOP", - "INY", "CMP", "DEX", "NOP", "CPY", "CMP", "DEC", "NOP", - "BNE", "CMP", "CMP", "NOP", "NOP", "CMP", "DEC", "NOP", - "CLD", "CMP", "PHX", "NOP", "NOP", "CMP", "DEC", "NOP", - "CPX", "SBC", "NOP", "NOP", "CPX", "SBC", "INC", "NOP", - "INX", "SBC", "NOP", "NOP", "CPX", "SBC", "INC", "NOP", - "BEQ", "SBC", "SBC", "NOP", "NOP", "SBC", "INC", "NOP", - "SED", "SBC", "PLX", "NOP", "NOP", "SBC", "INC", "NOP" -]; - - -// Addressing modes. - -enum { IMP, IMM, ZP, ZPX, ZPY, IZX, IZY, ABS, ABX, ABY, IND, REL, - ZPI, ABI, NP1, NP8, KIL } - -immutable ADDR_MODES_6502 = [ - IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, - IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, - REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, - IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, - ABS, IZX, KIL, IZX, ZP, ZP, ZP, ZP, - IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, - REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, - IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, - IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, - IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, - REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, - IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, - IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, - IMP, IMM, IMP, IMM, IND, ABS, ABS, ABS, - REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, - IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, - IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, - IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, - REL, IZY, KIL, IZY, ZPX, ZPX, ZPY, ZPY, - IMP, ABY, IMP, ABY, ABX, ABX, ABY, ABY, - IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, - IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, - REL, IZY, KIL, IZY, ZPX, ZPX, ZPY, ZPY, - IMP, ABY, IMP, ABY, ABX, ABX, ABY, ABY, - IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, - IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, - REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, - IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, - IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, - IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, - REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, - IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX -]; - -immutable ADDR_MODES_65C02 = [ - IMP, IZX, IMM, NP1, ZP, ZP, ZP, NP1, - IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, - REL, IZY, ZPI, NP1, ZP, ZPX, ZPX, NP1, - IMP, ABY, IMP, NP1, ABS, ABX, ABX, NP1, - ABS, IZX, IMM, NP1, ZP, ZP, ZP, NP1, - IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, - REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, - IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1, - IMP, IZX, IMM, NP1, ZP, ZP, ZP, NP1, - IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, - REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, - IMP, ABY, IMP, NP1, NP8, ABX, ABX, NP1, - IMP, IZX, IMM, NP1, ZP, ZP, ZP, NP1, - IMP, IMM, IMP, NP1, IND, ABS, ABS, NP1, - REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, - IMP, ABY, IMP, NP1, ABI, ABX, ABX, NP1, - REL, IZX, IMM, NP1, ZP, ZP, ZP, NP1, - IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, - REL, IZY, ZPI, NP1, ZPX, ZPX, ZPY, NP1, - IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1, - IMM, IZX, IMM, NP1, ZP, ZP, ZP, NP1, - IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, - REL, IZY, ZPI, NP1, ZPX, ZPX, ZPY, NP1, - IMP, ABY, IMP, NP1, ABX, ABX, ABY, NP1, - IMM, IZX, IMM, NP1, ZP, ZP, ZP, NP1, - IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, - REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, - IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1, - IMM, IZX, IMM, NP1, ZP, ZP, ZP, NP1, - IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, - REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, - IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1 -]; - - -// Page-crossing extra cycles. - -immutable EXTRA_CYCLES_6502 = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, -]; - -immutable EXTRA_CYCLES_65C02 = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, -]; - - // Custom string formatting. enum HEX_DIGITS = "0123456789abcdef"; @@ -1490,25 +1150,3 @@ string Fmt(string f, string[] p ...) } return ret ~ f[last..$]; } - - -version(OpFunctions) mixin(OpBodies("6502", vStrict, vCumulative)); -version(OpFunctions) mixin(OpBodies("65C02", vStrict, vCumulative)); - - -//alias Cpu!("6502", false, false) T1; -//alias Cpu!("6502", false, true) T2; -//alias Cpu!("6502", true, false) T3; -//alias Cpu!("6502", true, true) T4; -//alias Cpu!("65C02", false, false) T5; -//alias Cpu!("65C02", false, true) T6; -//alias Cpu!("65C02", true, false) T7; -//alias Cpu!("65C02", true, true) T8; - -/+ -void main() -{ - import std.stdio; - writeln(OpBody(0x11, "6502", true, false)); -} -+/ diff --git a/src/cpu/d6502.d b/src/cpu/d6502.d new file mode 100644 index 0000000..4d923ad --- /dev/null +++ b/src/cpu/d6502.d @@ -0,0 +1,179 @@ +/+ + + cpu/d6502.d + + + + Copyright: 2012 Ed McCardell, 2007 Gerald Stocker + + + + This file is part of twoapple-reboot. + + + + twoapple-reboot is free software; you can redistribute it and/or modify + + it under the terms of the GNU General Public License as published by + + the Free Software Foundation; either version 2 of the License, or + + (at your option) any later version. + + + + twoapple-reboot is distributed in the hope that it will be useful, + + but WITHOUT ANY WARRANTY; without even the implied warranty of + + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public License + + along with twoapple-reboot; if not, write to the Free Software + + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +/ + + +module cpu.d6502; + + +import std.array, std.format; + +import cpu.ctfe_d6502; + + +enum Strict : bool +{ + no, yes +} + +enum Cumulative : bool +{ + no, yes +} + + +template is6502(T) +{ + enum is6502 = __traits(getMember, T, "_chip") == "6502"; +} + +template is65C02(T) +{ + enum is65C02 = __traits(getMember, T, "_chip") == "65C02"; +} + + +final class Cpu(string chip, bool strict, bool cumulative) +{ + static assert(chip == "6502" || chip == "65C02" || chip == "65c02"); + enum _isCpu = true; + enum _chip = (chip == "6502" ? "6502" : "65C02"); + enum _isStrict = strict; + enum _isCumulative = cumulative; + + struct _Mem + { + // Reads a value from system memory. + ubyte delegate(ushort addr) read; + + // Writes a value to system memory. + void delegate(ushort addr, ubyte val) write; + } + _Mem memory; + + struct _Clock + { + static if (cumulative) + /* + * Updates the number of cycles executed. Called just + * prior to the final read/write action of each opcode. + */ + void delegate(int cycles) tick; + else + /* + * Increments the number of cycles executed. Called prior + * to each read/write action. + */ + void delegate() tick; + } + _Clock clock; + + ubyte A, X, Y, S; + ushort PC; + + // The status flags. + ubyte N, Z; + bool V, D, I, C; + + static if (opArray) { mixin(OpArrayDef()); } + + // TODO: other methods for stopping cpu + bool keepRunning; + + this() + { + static if (opArray) mixin(OpArrayInit()); + } + + final void statusFromByte(ubyte p) + { + N = p; + V = ((p & 0x40) != 0); + D = ((p & 0x08) != 0); + I = ((p & 0x04) != 0); + Z = ((p & 0x02) ? 0 : 1); + C = ((p & 0x01) != 0); + } + + final ubyte statusToByte() + { + return (C ? 0x01 : 0) | + ((Z == 0) ? 0x02 : 0) | + (I ? 0x04 : 0) | + (D ? 0x08 : 0) | + 0x30 | // break and reserved both set + (V ? 0x40 : 0) | + (N & 0x80); + } + + final void run(bool continuous) + { + keepRunning = continuous; + // TODO debugging info? + ubyte opcode; + static if (!opArray) + { + static if (cumulative) { int cycles; } + ubyte op1; + ushort address, base; + ubyte data; + } + do { + static if (cumulative && !opArray) + cycles = 1; + // XXX figure out final cycle stuff + static if (!cumulative) + clock.tick(); + // XXX check signals, NMI/IRQ delays, etc. + opcode = memory.read(PC++); + mixin(OpExecute(_chip, strict, cumulative)); + } while (keepRunning); + } + + version(OpDelegates) mixin (OpBodies(_chip, strict, cumulative)); +} + + +enum ushort IRQ_VECTOR = 0xFFFE; + + +private: + +version(OpFunctions) mixin(OpBodies("6502", vStrict, vCumulative)); +version(OpFunctions) mixin(OpBodies("65C02", vStrict, vCumulative)); + + +//alias Cpu!("6502", false, false) T1; +//alias Cpu!("6502", false, true) T2; +//alias Cpu!("6502", true, false) T3; +//alias Cpu!("6502", true, true) T4; +//alias Cpu!("65C02", false, false) T5; +//alias Cpu!("65C02", false, true) T6; +//alias Cpu!("65C02", true, false) T7; +//alias Cpu!("65C02", true, true) T8; + +/+ +void main() +{ + import std.stdio; + writeln(OpBody(0x11, "6502", true, false)); +} ++/ diff --git a/src/cpu/data_d6502.d b/src/cpu/data_d6502.d new file mode 100644 index 0000000..a9a2077 --- /dev/null +++ b/src/cpu/data_d6502.d @@ -0,0 +1,190 @@ +module cpu.data_d6502; + + +// Opcode names. +immutable OP_NAMES_6502 = [ + "BRK", "ORA", "KIL", "SLO", "NOP", "ORA", "ASL", "SLO", + "PHP", "ORA", "ASL", "ANC", "NOP", "ORA", "ASL", "SLO", + "BPL", "ORA", "KIL", "SLO", "NOP", "ORA", "ASL", "SLO", + "CLC", "ORA", "NOP", "SLO", "NOP", "ORA", "ASL", "SLO", + "JSR", "AND", "KIL", "RLA", "BIT", "AND", "ROL", "RLA", + "PLP", "AND", "ROL", "ANC", "BIT", "AND", "ROL", "RLA", + "BMI", "AND", "KIL", "RLA", "NOP", "AND", "ROL", "RLA", + "SEC", "AND", "NOP", "RLA", "NOP", "AND", "ROL", "RLA", + "RTI", "EOR", "KIL", "SRE", "NOP", "EOR", "LSR", "SRE", + "PHA", "EOR", "LSR", "ALR", "JMP", "EOR", "LSR", "SRE", + "BVC", "EOR", "KIL", "SRE", "NOP", "EOR", "LSR", "SRE", + "CLI", "EOR", "NOP", "SRE", "NOP", "EOR", "LSR", "SRE", + "RTS", "ADC", "KIL", "RRA", "NOP", "ADC", "ROR", "RRA", + "PLA", "ADC", "ROR", "ARR", "JMP", "ADC", "ROR", "RRA", + "BVS", "ADC", "KIL", "RRA", "NOP", "ADC", "ROR", "RRA", + "SEI", "ADC", "NOP", "RRA", "NOP", "ADC", "ROR", "RRA", + "NOP", "STA", "NOP", "SAX", "STY", "STA", "STX", "SAX", + "DEY", "NOP", "TXA", "XAA", "STY", "STA", "STX", "SAX", + "BCC", "STA", "KIL", "AHX", "STY", "STA", "STX", "SAX", + "TYA", "STA", "TXS", "TAS", "SHY", "STA", "SHX", "AHX", + "LDY", "LDA", "LDX", "LAX", "LDY", "LDA", "LDX", "LAX", + "TAY", "LDA", "TAX", "LAX", "LDY", "LDA", "LDX", "LAX", + "BCS", "LDA", "KIL", "LAX", "LDY", "LDA", "LDX", "LAX", + "CLV", "LDA", "TSX", "LAS", "LDY", "LDA", "LDX", "LAX", + "CPY", "CMP", "NOP", "DCP", "CPY", "CMP", "DEC", "DCP", + "INY", "CMP", "DEX", "AXS", "CPY", "CMP", "DEC", "DCP", + "BNE", "CMP", "KIL", "DCP", "NOP", "CMP", "DEC", "DCP", + "CLD", "CMP", "NOP", "DCP", "NOP", "CMP", "DEC", "DCP", + "CPX", "SBC", "NOP", "ISC", "CPX", "SBC", "INC", "ISC", + "INX", "SBC", "NOP", "SBC", "CPX", "SBC", "INC", "ISC", + "BEQ", "SBC", "KIL", "ISC", "NOP", "SBC", "INC", "ISC", + "SED", "SBC", "NOP", "ISC", "NOP", "SBC", "INC", "ISC" +]; + +immutable OP_NAMES_65C02 = [ + "BRK", "ORA", "NOP", "NOP", "TSB", "ORA", "ASL", "NOP", + "PHP", "ORA", "ASL", "NOP", "TSB", "ORA", "ASL", "NOP", + "BPL", "ORA", "ORA", "NOP", "TRB", "ORA", "ASL", "NOP", + "CLC", "ORA", "INC", "NOP", "TRB", "ORA", "ASL", "NOP", + "JSR", "AND", "NOP", "NOP", "BIT", "AND", "ROL", "NOP", + "PLP", "AND", "ROL", "NOP", "BIT", "AND", "ROL", "NOP", + "BMI", "AND", "AND", "NOP", "BIT", "AND", "ROL", "NOP", + "SEC", "AND", "DEC", "NOP", "BIT", "AND", "ROL", "NOP", + "RTI", "EOR", "NOP", "NOP", "NOP", "EOR", "LSR", "NOP", + "PHA", "EOR", "LSR", "NOP", "JMP", "EOR", "LSR", "NOP", + "BVC", "EOR", "EOR", "NOP", "NOP", "EOR", "LSR", "NOP", + "CLI", "EOR", "PHY", "NOP", "NOP", "EOR", "LSR", "NOP", + "RTS", "ADC", "NOP", "NOP", "STZ", "ADC", "ROR", "NOP", + "PLA", "ADC", "ROR", "NOP", "JMP", "ADC", "ROR", "NOP", + "BVS", "ADC", "ADC", "NOP", "STZ", "ADC", "ROR", "NOP", + "SEI", "ADC", "PLY", "NOP", "JMP", "ADC", "ROR", "NOP", + "BRA", "STA", "NOP", "NOP", "STY", "STA", "STX", "NOP", + "DEY", "BIT", "TXA", "NOP", "STY", "STA", "STX", "NOP", + "BCC", "STA", "STA", "NOP", "STY", "STA", "STX", "NOP", + "TYA", "STA", "TXS", "NOP", "STZ", "STA", "STZ", "NOP", + "LDY", "LDA", "LDX", "NOP", "LDY", "LDA", "LDX", "NOP", + "TAY", "LDA", "TAX", "NOP", "LDY", "LDA", "LDX", "NOP", + "BCS", "LDA", "LDA", "NOP", "LDY", "LDA", "LDX", "NOP", + "CLV", "LDA", "TSX", "NOP", "LDY", "LDA", "LDX", "NOP", + "CPY", "CMP", "NOP", "NOP", "CPY", "CMP", "DEC", "NOP", + "INY", "CMP", "DEX", "NOP", "CPY", "CMP", "DEC", "NOP", + "BNE", "CMP", "CMP", "NOP", "NOP", "CMP", "DEC", "NOP", + "CLD", "CMP", "PHX", "NOP", "NOP", "CMP", "DEC", "NOP", + "CPX", "SBC", "NOP", "NOP", "CPX", "SBC", "INC", "NOP", + "INX", "SBC", "NOP", "NOP", "CPX", "SBC", "INC", "NOP", + "BEQ", "SBC", "SBC", "NOP", "NOP", "SBC", "INC", "NOP", + "SED", "SBC", "PLX", "NOP", "NOP", "SBC", "INC", "NOP" +]; + + +// Addressing modes. + +enum { IMP, IMM, ZP, ZPX, ZPY, IZX, IZY, ABS, ABX, ABY, IND, REL, + ZPI, ABI, NP1, NP8, KIL } + +immutable ADDR_MODES_6502 = [ + IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, + ABS, IZX, KIL, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, + IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, + IMP, IZX, KIL, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, IND, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, + IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPY, ZPY, + IMP, ABY, IMP, ABY, ABX, ABX, ABY, ABY, + IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPY, ZPY, + IMP, ABY, IMP, ABY, ABX, ABX, ABY, ABY, + IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX, + IMM, IZX, IMM, IZX, ZP, ZP, ZP, ZP, + IMP, IMM, IMP, IMM, ABS, ABS, ABS, ABS, + REL, IZY, KIL, IZY, ZPX, ZPX, ZPX, ZPX, + IMP, ABY, IMP, ABY, ABX, ABX, ABX, ABX +]; + +immutable ADDR_MODES_65C02 = [ + IMP, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZP, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, ABS, ABX, ABX, NP1, + ABS, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1, + IMP, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, NP8, ABX, ABX, NP1, + IMP, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, IND, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, ABI, ABX, ABX, NP1, + REL, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPY, NP1, + IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1, + IMM, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPY, NP1, + IMP, ABY, IMP, NP1, ABX, ABX, ABY, NP1, + IMM, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1, + IMM, IZX, IMM, NP1, ZP, ZP, ZP, NP1, + IMP, IMM, IMP, NP1, ABS, ABS, ABS, NP1, + REL, IZY, ZPI, NP1, ZPX, ZPX, ZPX, NP1, + IMP, ABY, IMP, NP1, ABX, ABX, ABX, NP1 +]; + + +// Page-crossing extra cycles. + +immutable EXTRA_CYCLES_6502 = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, +]; + +immutable EXTRA_CYCLES_65C02 = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, +]; diff --git a/test/cpu.d b/test/cpu.d index 3ba9e9a..dd22535 100644 --- a/test/cpu.d +++ b/test/cpu.d @@ -8,7 +8,7 @@ module test.cpu; import std.conv, std.exception, std.random, std.string, std.traits; -public import cpu6502 : Cpu, is6502, is65C02; +public import cpu.d6502 : Cpu, is6502, is65C02; // True if T is the type of a cpu. From c81ff27bae8741aca18092d0a9fbaa0b85f8b2a6 Mon Sep 17 00:00:00 2001 From: edmccard Date: Wed, 11 Apr 2012 04:52:15 -0400 Subject: [PATCH 12/27] Add RTI and extra 65C02 opcodes. --- src/cpu/ctfe_d6502.d | 1051 ++++++++++++++++++++++-------------------- test/test_new_cpu.d | 4 +- 2 files changed, 545 insertions(+), 510 deletions(-) diff --git a/src/cpu/ctfe_d6502.d b/src/cpu/ctfe_d6502.d index df3e97e..ffb8f2a 100644 --- a/src/cpu/ctfe_d6502.d +++ b/src/cpu/ctfe_d6502.d @@ -160,6 +160,20 @@ string Switch16x16(string chip, bool strict, bool cumulative) } +enum _PC = Attr("PC"); +enum _A = Attr("A"); +enum _X = Attr("X"); +enum _Y = Attr("Y"); +enum _N = Attr("N"); +enum _V = Attr("V"); +enum _D = Attr("D"); +enum _I = Attr("I"); +enum _Z = Attr("Z"); +enum _C = Attr("C"); +enum _S = Attr("S"); +enum STACK = "0x0100 + " ~ _S; + + string OpBody(int op, string chip, bool s, bool c) { bool nmos = (chip == "6502"); @@ -169,7 +183,8 @@ string OpBody(int op, string chip, bool s, bool c) return Break(s, c) ~ Done(c); case "RTI": - return ""; + return RetInt(s, c) ~ + Done(c); case "JSR": return JumpSub(s, c) ~ Done(c); @@ -180,99 +195,99 @@ string OpBody(int op, string chip, bool s, bool c) return Jump(op, chip, s, c) ~ Done(c); case "KIL": - return Attr("PC") ~ "--;\n" ~ + return _PC ~ "--;\n" ~ Done(c); case "BPL": - return Branch("!(" ~ Attr("N") ~ " & 0x80)", nmos, s, c) ~ + return Branch("!(" ~ _N ~ " & 0x80)", nmos, s, c) ~ Done(c); case "BMI": - return Branch("(" ~ Attr("N") ~ " & 0x80)", nmos, s, c) ~ + return Branch("(" ~ _N ~ " & 0x80)", nmos, s, c) ~ Done(c); case "BVC": - return Branch("!" ~ Attr("V"), nmos, s, c) ~ + return Branch("!" ~ _V, nmos, s, c) ~ Done(c); case "BVS": - return Branch(Attr("V"), nmos, s, c) ~ + return Branch(_V, nmos, s, c) ~ Done(c); case "BRA": return Branch("true", nmos, s, c) ~ Done(c); case "BCC": - return Branch("!" ~ Attr("C"), nmos, s, c) ~ + return Branch("!" ~ _C, nmos, s, c) ~ Done(c); case "BCS": - return Branch(Attr("C"), nmos, s, c) ~ + return Branch(_C, nmos, s, c) ~ Done(c); case "BNE": - return Branch(Attr("Z"), nmos, s, c) ~ + return Branch(_Z, nmos, s, c) ~ Done(c); case "BEQ": - return Branch("!" ~ Attr("Z"), nmos, s, c) ~ + return Branch("!" ~ _Z, nmos, s, c) ~ Done(c); case "CLC": return AddrIMP(s, c) ~ - ClearFlag("C") ~ + ClearFlag(_C) ~ Done(c); case "SEC": return AddrIMP(s, c) ~ - SetFlag("C") ~ + SetFlag(_C) ~ Done(c); case "CLI": return AddrIMP(s, c) ~ - ClearFlag("I") ~ + ClearFlag(_I) ~ Done(c); case "SEI": return AddrIMP(s, c) ~ - SetFlag("I") ~ + SetFlag(_I) ~ Done(c); case "CLV": return AddrIMP(s, c) ~ - ClearFlag("V") ~ + ClearFlag(_V) ~ Done(c); case "CLD": return AddrIMP(s, c) ~ - ClearFlag("D") ~ + ClearFlag(_D) ~ Done(c); case "SED": return AddrIMP(s, c) ~ - SetFlag("D") ~ + SetFlag(_D) ~ Done(c); case "NOP": return Nop(op, chip, s, c) ~ Done(c); case "TAX": - return Transfer(op, "A", "X", s, c) ~ + return Transfer(op, _A, _X, s, c) ~ Done(c); case "TXA": - return Transfer(op, "X", "A", s, c) ~ + return Transfer(op, _X, _A, s, c) ~ Done(c); case "TAY": - return Transfer(op, "A", "Y", s, c) ~ + return Transfer(op, _A, _Y, s, c) ~ Done(c); case "TYA": - return Transfer(op, "Y", "A", s, c) ~ + return Transfer(op, _Y, _A, s, c) ~ Done(c); case "TSX": - return Transfer(op, "S", "X", s, c) ~ + return Transfer(op, _S, _X, s, c) ~ Done(c); case "TXS": - return Transfer(op, "X", "S", s, c) ~ + return Transfer(op, _X, _S, s, c) ~ Done(c); case "DEX": return AddrIMP(s, c) ~ - Dec(Attr("X")) ~ + Dec(_X) ~ Done(c); case "DEY": return AddrIMP(s, c) ~ - Dec(Attr("Y")) ~ + Dec(_Y) ~ Done(c); case "INX": return AddrIMP(s, c) ~ - Inc(Attr("X")) ~ + Inc(_X) ~ Done(c); case "INY": return AddrIMP(s, c) ~ - Inc(Attr("Y")) ~ + Inc(_Y) ~ Done(c); case "PHP": return AddrIMP(s, c) ~ @@ -283,54 +298,55 @@ string OpBody(int op, string chip, bool s, bool c) PullStatus(s, c) ~ Done(c); case "PLA": - return PullReg("A", s, c) ~ + return PullReg(_A, s, c) ~ Done(c); case "PLX": - return PullReg("X", s, c) ~ + return PullReg(_X, s, c) ~ Done(c); case "PLY": - return PullReg("Y", s, c) ~ + return PullReg(_Y, s, c) ~ Done(c); case "PHA": - return PushReg("A", s, c) ~ + return PushReg(_A, s, c) ~ Done(c); case "PHX": - return PushReg("X", s, c) ~ + return PushReg(_X, s, c) ~ Done(c); case "PHY": - return PushReg("Y", s, c) ~ + return PushReg(_Y, s, c) ~ Done(c); case "LDA": - return Load(op, "A", chip, s, c) ~ + return Load(op, _A, chip, s, c) ~ Done(c); case "LDX": - return Load(op, "X", chip, s, c) ~ + return Load(op, _X, chip, s, c) ~ Done(c); case "LDY": - return Load(op, "Y", chip, s, c) ~ + return Load(op, _Y, chip, s, c) ~ Done(c); case "STA": - return Store(op, "A", chip, s, c) ~ + return Store(op, _A, chip, s, c) ~ Done(c); case "STX": - return Store(op, "X", chip, s, c) ~ + return Store(op, _X, chip, s, c) ~ Done(c); case "STY": - return Store(op, "Y", chip, s, c) ~ + return Store(op, _Y, chip, s, c) ~ Done(c); case "STZ": - return ""; - case "BIT": - return Bit(op, chip, s, c) ~ + return Store(op, "0", chip, s, c) ~ Done(c); case "CMP": - return Compare(op, "A", chip, s, c) ~ + return Compare(op, _A, chip, s, c) ~ Done(c); case "CPX": - return Compare(op, "X", chip, s, c) ~ + return Compare(op, _X, chip, s, c) ~ Done(c); case "CPY": - return Compare(op, "Y", chip, s, c) ~ + return Compare(op, _Y, chip, s, c) ~ + Done(c); + case "BIT": + return Bit(op, chip, s, c) ~ Done(c); case "ORA": return Logic(op, "|=", chip, s, c) ~ @@ -347,40 +363,40 @@ string OpBody(int op, string chip, bool s, bool c) case "SBC": return Sub(op, chip, s, c) ~ Done(c); - case "ASL": - if (op == 0x0a) - return AddrIMP(s, c) ~ ShiftLeft(Attr("A")) ~ Done(c); - else - return RMW(op, ShiftLeft("data"), chip, s, c) ~ Done(c); - case "ROL": - if (op == 0x2a) - return AddrIMP(s, c) ~ RotateLeft(Attr("A")) ~ Done(c); - else - return RMW(op, RotateLeft("data"), chip, s, c) ~ Done(c); - case "LSR": - if (op == 0x4a) - return AddrIMP(s, c) ~ ShiftRight(Attr("A")) ~ Done(c); - else - return RMW(op, ShiftRight("data"), chip, s, c) ~ Done(c); - case "ROR": - if (op == 0x6a) - return AddrIMP(s, c) ~ ShiftRight(Attr("A")) ~ Done(c); - else - return RMW(op, RotateRight("data"), chip, s, c) ~ Done(c); case "INC": if (op == 0x1a) - return AddrIMP(s, c) ~ Inc(Attr("A")) ~ Done(c); + return AddrIMP(s, c) ~ Inc(_A) ~ Done(c); else return RMW(op, Inc("data"), chip, s, c) ~ Done(c); case "DEC": if (op == 0x3a) - return AddrIMP(s, c) ~ Dec(Attr("A")) ~ Done(c); + return AddrIMP(s, c) ~ Dec(_A) ~ Done(c); else return RMW(op, Dec("data"), chip, s, c) ~ Done(c); + case "ASL": + if (op == 0x0a) + return AddrIMP(s, c) ~ ShiftLeft(_A) ~ Done(c); + else + return RMW(op, ShiftLeft("data"), chip, s, c) ~ Done(c); + case "ROL": + if (op == 0x2a) + return AddrIMP(s, c) ~ RotateLeft(_A) ~ Done(c); + else + return RMW(op, RotateLeft("data"), chip, s, c) ~ Done(c); + case "LSR": + if (op == 0x4a) + return AddrIMP(s, c) ~ ShiftRight(_A) ~ Done(c); + else + return RMW(op, ShiftRight("data"), chip, s, c) ~ Done(c); + case "ROR": + if (op == 0x6a) + return AddrIMP(s, c) ~ ShiftRight(_A) ~ Done(c); + else + return RMW(op, RotateRight("data"), chip, s, c) ~ Done(c); case "TRB": - return ""; + return RMW(op, TestReset(), chip, s, c) ~ Done(c); case "TSB": - return ""; + return RMW(op, TestSet(), chip, s, c) ~ Done(c); case "LAS": return ""; case "LAX": @@ -421,101 +437,80 @@ string OpBody(int op, string chip, bool s, bool c) } -string AddrIMM(bool s, bool c) +string Break(bool s, bool c) { - return Local("ushort") ~ "address = " ~ Attr("PC") ~ "++;\n"; + return AddrIMP(s, c) ~ + IncPC() ~ + PushPC(s, c) ~ + Push(Attr("statusToByte()"), s, c) ~ + SetFlag(_I) ~ + ReadWord(_PC, "IRQ_VECTOR", c); } -string AddrIMP(bool s, bool c) + +string JumpSub(bool s, bool c) { - return Peek(Attr("PC"), s, c); + return ReadOp(Local("ushort", "address"), c) ~ + Peek(STACK, s, c) ~ + PushPC(s, c) ~ + LoadHiByte("address", _PC ~ "++", c) ~ + _PC ~ " = address;\n"; } -string AddrZP(bool s, bool c) + +string RetSub(bool s, bool c) { - return ReadOp(Local("ushort", "address"), c); + return AddrIMP(s, c) ~ + Peek(STACK, s, c) ~ + PullPC(s, c) ~ + Peek(_PC, s, c) ~ + IncPC(); } -string AddrZPXY(string reg, string chip, bool s, bool c) + +string RetInt(bool s, bool c) +{ + return AddrIMP(s, c) ~ + PullStatus(s, c) ~ + PullPC(s, c); +} + + +string Jump(int op, string chip, bool s, bool c) { bool nmos = (chip == "6502"); - return ReadOp(Local("ushort", "base"), c) ~ - If!(nmos)( - Peek("base", s, c), - Peek(Attr("PC"), s, c)) ~ - Local("ushort") ~ - "address = cast(ubyte)(base + " ~ Attr(reg) ~ ");\n"; + if (op == 0x4c) + return Address(op, chip, s, c) ~ + _PC ~ " = address;\n"; + else if (op == 0x6c) + return ReadWordOp("ushort", "base", c) ~ + If!(nmos)( + "", + Peek(_PC, s, c)) ~ + ReadWordBasic(_PC, "base", + If!(nmos)( + "(base & 0xFF00) | cast(ubyte)(base + 1)", + "cast(ushort)(base + 1)"), c); + else if (op == 0x7c) + return ReadWordOp("ushort", "base", c) ~ + Peek(_PC, s, c) ~ + ReadWord(_PC, "cast(ushort)(base + " ~ _X ~ ")", c); + return ""; } -string AddrIZX(string chip, bool s, bool c) -{ - bool nmos = (chip == "6502"); - return ReadOp(Local("ushort", "base"), c) ~ - If!(nmos)( - Peek("base", s, c), - Peek(Attr("PC"), s, c)) ~ - ReadWordZP("ushort", "address", "base + " ~ Attr("X"), c); -} - -string AddrIZY(int op, string chip, bool s, bool c) -{ - int exCyc = opExCyc(op, chip); - bool nmos = (chip == "6502"); - - return ReadOp("ubyte vector", c) ~ - ReadWordZP("ushort", "base", "vector", c) ~ - Local("ushort") ~ - "address = cast(ushort)(base + " ~ Attr("Y") ~ ");\n" ~ - CheckShortcut("address", Attr("PC"), - exCyc, nmos, s, c); -} - -string AddrABS(bool s, bool c) -{ - return ReadWordOp("ushort", "address", c); -} - -string AddrABXY(int op, string reg, string chip, bool s, bool c) -{ - bool nmos = (chip == "6502"); - int exCyc = opExCyc(op, chip); - string IDX = Attr(reg); - - return ReadWordOp("ushort", "base", c) ~ - Local("ushort") ~ "address = cast(ushort)(base + " ~ IDX ~ ");\n" ~ - CheckShortcut("address", Attr("PC"), exCyc, nmos, s, c); -} - -string AddrZPI(bool s, bool c) -{ - return ReadOp(Local("ushort", "base"), c) ~ - ReadWordZP("ushort", "address", "base", c); -} string Branch(string check, bool nmos, bool s, bool c) { - string PC = Attr("PC"); return ReadOp(Local("ubyte", "op1"), c) ~ "if (" ~ check ~ ")\n{\n" ~ - Peek(PC, s, c) ~ - Local("ushort", "base") ~ " = " ~ PC ~ ";\n" ~ - PC ~ " = cast(ushort)(" ~ PC ~ " + cast(byte)op1);\n" ~ - CheckShortcut(Attr("PC"), "base", 0, nmos, s, c) ~ + Peek(_PC, s, c) ~ + Local("ushort", "base") ~ " = " ~ _PC ~ ";\n" ~ + _PC ~ " = cast(ushort)(" ~ _PC ~ " + cast(byte)op1);\n" ~ + CheckShortcut(_PC, "base", 0, nmos, s, c) ~ "}\n"; } -string CheckShortcut(string addr, string pc, int exCyc, bool nmos, bool s, - bool c) -{ - return "ushort guess = (base & 0xFF00) | cast(ubyte)" ~ addr ~ ";\n" ~ - "if (guess != " ~ addr ~ ")\n{\n" ~ - If!(nmos)(Peek("guess", s, c), - Peek(pc, s, c)) ~ - "}\n" ~ - If!(exCyc)("else\n{\n" ~ Peek("address", s, c) ~ "}\n"); -} - string Nop(int op, string chip, bool s, bool c) { @@ -528,63 +523,400 @@ string Nop(int op, string chip, bool s, bool c) } -string Break(bool s, bool c) +string Transfer(int op, string source, string dest, bool s, bool c) { return AddrIMP(s, c) ~ - IncPC() ~ - PushPC(s, c) ~ - Push(Attr("statusToByte()"), s, c) ~ - SetFlag("I") ~ - ReadWord(Attr("PC"), "IRQ_VECTOR", c); + dest ~ " = " ~ source ~ ";\n" ~ + ((op != 0x9a) ? SetNZ(dest) : ""); } -string RetSub(bool s, bool c) +string PullReg(string reg, bool s, bool c) { return AddrIMP(s, c) ~ - PullPC(s, c) ~ - Peek(Attr("PC"), s, c) ~ - IncPC(); + Peek(STACK, s, c) ~ + PullInto(reg, s, c) ~ + SetNZ(reg); } -string JumpSub(bool s, bool c) +string PushReg(string reg, bool s, bool c) { - string PC = Attr("PC"); - - return ReadOp(Local("ushort", "address"), c) ~ - Peek("0x0100 + " ~ Attr("S"), s, c) ~ - PushPC(s, c) ~ - PreAccess(c) ~ "address |= (" ~ ReadRaw(PC ~ "++") ~ " << 8);\n" ~ - PC ~ " = address;\n"; + return AddrIMP(s, c) ~ + Push(reg, s, c); } -string Jump(int op, string chip, bool s, bool c) +string Load(int op, string reg, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + ReadInto(reg, "address", c) ~ + SetNZ(reg); +} + + +string Store(int op, string reg, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + Write("address", reg, c); +} + + +string Compare(int op, string reg, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + ReadInto(Local("ubyte", "data"), "address", c) ~ + UpdateFlag(_C, reg ~ " >= data") ~ + SetNZ("cast(ubyte)(" ~ reg ~ " - data)"); +} + + +string Bit(int op, string chip, bool s, bool c) +{ + bool notImm = (opMode(op, chip) != IMM); + + return Address(op, chip, s, c) ~ + ReadInto(Local("ubyte", "data"), "address", c) ~ + If!(notImm)( + _N ~ " = data;\n" ~ + _V ~ " = ((data & 0x40) != 0);\n") ~ + _Z ~ " = (" ~ _A ~ " & data);\n"; +} + + +string Logic(int op, string action, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + ReadInto(_A, action, "address", c) ~ + SetNZ(_A); +} + + +string Add(int op, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + ReadInto(Local("ubyte", "data"), "address", c) ~ + "if (" ~ _D ~ ")\n{\n" ~ + DecAdd(chip, s, c) ~ + "}\nelse\n{\n" ~ + HexAdd(chip, s, c) ~ + "}\n"; +} + +string HexAdd(string chip, bool s, bool c) +{ + return "uint sum = " ~ _A ~ " + data + " ~ _C ~ ";\n" ~ + _V ~ + " = (!((" ~ _A ~ " ^ data) & 0x80)) && ((data ^ sum) & 0x80);\n" ~ + _C ~ " = (sum > 0xFF);\n" ~ + SetNZ(_A ~ " = cast(ubyte)sum"); +} + +string DecAdd(string chip, bool s, bool c) +{ + bool cmos = (chip != "6502"); + + return "int a = " ~ _A ~ ";\n" ~ + "int al = (a & 0x0F) + (data & 0x0F) + " ~ _C ~ ";\n" ~ + "if (al >= 0x0A)\n" ~ + "al = ((al + 0x06) & 0x0F) + 0x10;\n" ~ + "a = (a & 0xF0) + (data & 0xF0) + al;\n" ~ + If!(cmos)("", + _N ~ " = cast(ubyte)a;\n" ~ + _Z ~ " = cast(ubyte)(" ~ _A ~ " + data + " ~ _C ~ ");\n") ~ + _V ~ + " = (!((" ~ _A ~ " ^ data) & 0x80)) && ((data ^ a) & 0x80);\n" ~ + "if (a >= 0xA0)\n" ~ + "a = a + 0x60;\n" ~ + _C ~ " = (a >= 0x100);\n" ~ + If!(cmos)( + SetNZ(_A ~ " = cast(ubyte)a") ~ Peek(_PC, s, c), + _A ~ " = cast(ubyte)a;\n"); +} + + +string Sub(int op, string chip, bool s, bool c) +{ + return Address(op, chip, s, c) ~ + ReadInto(Local("ubyte", "data"), "address", c) ~ + "if (" ~ _D ~ ")\n{\n" ~ + DecSub(chip, s, c) ~ + "}\nelse\n{\n" ~ + HexSub(chip, s, c) ~ + "}\n"; +} + +string HexSub(string chip, bool s, bool c) +{ + return "uint diff = " ~ _A ~ " - data - !" ~ _C ~ ";\n" ~ + _V ~ + " = ((" ~ _A ~ " ^ diff) & 0x80) && ((" ~ + _A ~ " ^ data) & 0x80);\n" ~ + _C ~ " = (diff < 0x100);\n" ~ + SetNZ(_A ~ " = cast(ubyte)diff"); +} + +string DecSub(string chip, bool s, bool c) +{ + return (chip == "6502" ? DecSubNMOS(s, c) : DecSubCMOS(s, c)); +} + +string DecSubNMOS(bool s, bool c) +{ + return "int a = " ~ _A ~ ";\n" ~ + "int al = (a & 0x0F) - (data & 0x0F) - !" ~ _C ~ ";\n" ~ + "if (al < 0)\n" ~ + "al = ((al - 0x06) & 0x0F) - 0x10;\n" ~ + "a = (a & 0xF0) - (data & 0xF0) + al;\n" ~ + "if (a < 0)\n" ~ + "a = a - 0x60;\n" ~ + "uint diff = " ~ _A ~ " - data - !" ~ _C ~ ";\n" ~ + _V ~ + " = ((" ~ _A ~ " ^ diff) & 0x80) && ((" ~ + _A ~ " ^ data) & 0x80);\n" ~ + _C ~ " = (diff < 0x100);\n" ~ + SetNZ("cast(ubyte)diff") ~ + _A ~ " = cast(ubyte)a;\n"; +} + +string DecSubCMOS(bool s, bool c) +{ + return "int a = " ~ _A ~ ";\n" ~ + "int al = (a & 0x0F) - (data & 0x0F) - !" ~ _C ~ ";\n" ~ + "a = a - data - !" ~ _C ~ ";\n" ~ + "if (a < 0) a = a - 0x60;\n" ~ + "if (al < 0) a = a - 0x06;\n" ~ + "uint diff = " ~ _A ~ " - data - !" ~ _C ~ ";\n" ~ + _V ~ + " = ((" ~ _A ~ " ^ diff) & 0x80) && ((" ~ + _A ~ " ^ data) & 0x80);\n" ~ + _C ~ " = (diff < 0x100);\n" ~ + Peek(_PC, s, c) ~ + SetNZ(_A ~ " = cast(ubyte)a"); +} + + +string Inc(string val) +{ + return val ~ "++;\n" ~ + SetNZ(val); +} + + +string Dec(string val) +{ + return val ~ "--;\n" ~ + SetNZ(val); +} + + +string ShiftLeft(string val) +{ + return _C ~ " = (" ~ val ~ " > 0x7F);\n" ~ + SetNZ(val ~ " = cast(ubyte)(" ~ val ~ " << 1)"); +} + + +string RotateLeft(string val) +{ + return "auto oldC = " ~ _C ~ ";\n" ~ + _C ~ " = (" ~ val ~ " > 0x7f);\n" ~ + SetNZ(val ~ " = cast(ubyte)(" ~ val ~ " << 1 | (oldC ? 1 : 0))"); +} + + +string ShiftRight(string val) +{ + return _C ~ " = ((" ~ val ~ " & 0x01) != 0);\n" ~ + SetNZ(val ~ " = " ~ val ~ " >> 1"); +} + + +string RotateRight(string val) +{ + return "auto oldC = " ~ _C ~ ";\n" ~ + _C ~ " = ((" ~ val ~ " & 0x01) != 0);\n" ~ + SetNZ(val ~ " = (" ~ val ~ " >> 1 | (oldC ? 0x80 : 0))"); +} + + +string TestReset() +{ + return _Z ~ " = data & " ~ _A ~ ";\n" ~ + "data &= (~" ~ _A ~ ");\n"; +} + + +string TestSet() +{ + return _Z ~ " = data & " ~ _A ~ ";\n" ~ + "data |= " ~ _A ~ ";\n"; +} + + +string RMW(int op, string action, string chip, bool s, bool c) { bool nmos = (chip == "6502"); - string PC = Attr("PC"); - if (op == 0x4c) - return Address(op, chip, s, c) ~ - PC ~ " = address;\n"; - else if (op == 0x6c) - return ReadWordOp("ushort", "base", c) ~ - If!(nmos)( - "", - Peek(PC, s, c)) ~ - ReadWordBasic(PC, "base", - If!(nmos)( - "(base & 0xFF00) | cast(ubyte)(base + 1)", - "cast(ushort)(base + 1)"), c); - else if (op == 0x7c) - return ReadWordOp("ushort", "base", c) ~ - Peek(PC, s, c) ~ - ReadWord(PC, "cast(ushort)(base + " ~ Attr("X") ~ ")", c); + return Address(op, chip, s, c) ~ + ReadInto(Local("ubyte", "data"), "address", c) ~ + If!(nmos)(Poke("address", "data", s, c), + Peek("address", s, c)) ~ + action ~ + Write("address", "data", c); +} + + +string Local(string type) +{ + version(OpSwitch) + return ""; + else version(OpNestedSwitch) + return ""; + else + return type ~ " "; +} + +string Local(string type, string var) +{ + version(OpSwitch) + return var; + else version(OpNestedSwitch) + return var; + else + return type ~ " " ~ var; +} + + +string Address(int op, string chip, bool s, bool c) +{ + auto EXTRA_CYCLE = opExCyc(op, chip); + auto PC = Attr("PC"); + + final switch (opMode(op, chip)) + { + case IMP: + return AddrIMP(s, c); + case IMM: + return AddrIMM(s, c); + case ZP: + return AddrZP(s, c); + case ZPX: + return AddrZPXY(_X, chip, s, c); + case ZPY: + return AddrZPXY(_Y, chip, s, c); + case IZX: + return AddrIZX(chip, s, c); + case IZY: + return AddrIZY(op, chip, s, c); + case ABS: + return AddrABS(s, c); + case ABX: + return AddrABXY(op, _X, chip, s, c); + case ABY: + return AddrABXY(op, _Y, chip, s, c); + case IND: + return Local("ushort", "address") ~ " = 0;"; + case REL: + return Local("ushort", "address") ~ " = 0;"; + case ZPI: + return AddrZPI(s, c); + case ABI: + return Local("ushort", "address") ~ " = 0;"; + case NP1: + return ""; + case NP8: + return Local("ushort", "address") ~ " = 0;"; + case KIL: + return Local("ushort", "address") ~ " = 0;"; + } return ""; } +string AddrIMM(bool s, bool c) +{ + return Local("ushort") ~ "address = " ~ _PC ~ "++;\n"; +} + +string AddrIMP(bool s, bool c) +{ + return Peek(_PC, s, c); +} + +string AddrZP(bool s, bool c) +{ + return ReadOp(Local("ushort", "address"), c); +} + +string AddrZPXY(string reg, string chip, bool s, bool c) +{ + bool nmos = (chip == "6502"); + + return ReadOp(Local("ushort", "base"), c) ~ + If!(nmos)( + Peek("base", s, c), + Peek(_PC, s, c)) ~ + Local("ushort") ~ + "address = cast(ubyte)(base + " ~ reg ~ ");\n"; +} + +string AddrIZX(string chip, bool s, bool c) +{ + bool nmos = (chip == "6502"); + return ReadOp(Local("ushort", "base"), c) ~ + If!(nmos)( + Peek("base", s, c), + Peek(_PC, s, c)) ~ + ReadWordZP("ushort", "address", "base + " ~ _X, c); +} + +string AddrIZY(int op, string chip, bool s, bool c) +{ + int exCyc = opExCyc(op, chip); + bool nmos = (chip == "6502"); + + return ReadOp("ubyte vector", c) ~ + ReadWordZP("ushort", "base", "vector", c) ~ + Local("ushort") ~ + "address = cast(ushort)(base + " ~ _Y ~ ");\n" ~ + CheckShortcut("address", _PC, + exCyc, nmos, s, c); +} + +string AddrABS(bool s, bool c) +{ + return ReadWordOp("ushort", "address", c); +} + +string AddrABXY(int op, string reg, string chip, bool s, bool c) +{ + bool nmos = (chip == "6502"); + int exCyc = opExCyc(op, chip); + + return ReadWordOp("ushort", "base", c) ~ + Local("ushort") ~ "address = cast(ushort)(base + " ~ reg ~ ");\n" ~ + CheckShortcut("address", _PC, exCyc, nmos, s, c); +} + +string AddrZPI(bool s, bool c) +{ + return ReadOp(Local("ushort", "base"), c) ~ + ReadWordZP("ushort", "address", "base", c); +} + +string CheckShortcut(string addr, string pc, int exCyc, bool nmos, bool s, + bool c) +{ + return "ushort guess = (base & 0xFF00) | cast(ubyte)" ~ addr ~ ";\n" ~ + "if (guess != " ~ addr ~ ")\n{\n" ~ + If!(nmos)(Peek("guess", s, c), + Peek(pc, s, c)) ~ + "}\n" ~ + If!(exCyc)("else\n{\n" ~ Peek("address", s, c) ~ "}\n"); +} + + string ReadInto(string var, string action, string addr, bool c) { return PreAccess(c) ~ @@ -598,7 +930,7 @@ string ReadInto(string var, string addr, bool c) string ReadOp(string var, bool c) { - return ReadInto(var, Attr("PC") ~ "++", c); + return ReadInto(var, _PC ~ "++", c); } string ReadRaw(string addr) @@ -609,10 +941,8 @@ string ReadRaw(string addr) string ReadWordBasic(string type, string var, string addr1, string addr2, bool c) { - return PreAccess(c) ~ - Local(type, var) ~ " = " ~ ReadRaw(addr1) ~ ";\n" ~ - PreAccess(c) ~ - var ~ " |= ((" ~ ReadRaw(addr2) ~ ") << 8);\n"; + return LoadLoByte(type, var, addr1, c) ~ + LoadHiByte(var, addr2, c); } string ReadWordBasic(string var, string addr1, string addr2, bool c) @@ -643,9 +973,7 @@ string ReadWordZP(string var, string addr, bool c) string ReadWordOp(string type, string var, bool c) { - string PC = Attr("PC"); - - return ReadWordBasic(type, var, PC ~ "++", PC ~ "++", c); + return ReadWordBasic(type, var, _PC ~ "++", _PC ~ "++", c); } string ReadWordOp(string var, bool c) @@ -653,309 +981,6 @@ string ReadWordOp(string var, bool c) return ReadWordOp("", var, c); } - -string Local(string type) -{ - version(OpSwitch) - return ""; - else version(OpNestedSwitch) - return ""; - else - return type ~ " "; -} - -string Local(string type, string var) -{ - version(OpSwitch) - return var; - else version(OpNestedSwitch) - return var; - else - return type ~ " " ~ var; -} - - -string Transfer(int op, string source, string dest, bool s, bool c) -{ - return AddrIMP(s, c) ~ - Attr(dest) ~ " = " ~ Attr(source) ~ ";\n" ~ - ((op != 0x9a) ? SetNZ(Attr(dest)) : ""); -} - - -string PullReg(string reg, bool s, bool c) -{ - return AddrIMP(s, c) ~ - PullInto(Attr(reg), s, c) ~ - SetNZ(Attr(reg)); -} - - -string PushReg(string reg, bool s, bool c) -{ - return AddrIMP(s, c) ~ - Push(Attr(reg), s, c); -} - - -string Load(int op, string reg, string chip, bool s, bool c) -{ - return Address(op, chip, s, c) ~ - ReadInto(Attr(reg), "address", c) ~ - SetNZ(Attr(reg)); -} - - -string Store(int op, string reg, string chip, bool s, bool c) -{ - return Address(op, chip, s, c) ~ - Write("address", Attr(reg), c); -} - - -string Compare(int op, string reg, string chip, bool s, bool c) -{ - return Address(op, chip, s, c) ~ - ReadInto(Local("ubyte", "data"), "address", c) ~ - UpdateFlag("C", Attr(reg) ~ " >= data") ~ - SetNZ("cast(ubyte)(" ~ Attr(reg) ~ " - data)"); -} - - -string Bit(int op, string chip, bool s, bool c) -{ - bool notImm = (opMode(op, chip) != IMM); - - return Address(op, chip, s, c) ~ - ReadInto(Local("ubyte", "data"), "address", c) ~ - If!(notImm)( - Attr("N") ~ " = data;\n" ~ - Attr("V") ~ " = ((data & 0x40) != 0);\n") ~ - Attr("Z") ~ " = (" ~ Attr("A") ~ " & data);\n"; -} - - -string Logic(int op, string action, string chip, bool s, bool c) -{ - return Address(op, chip, s, c) ~ - ReadInto(Attr("A"), action, "address", c) ~ - SetNZ(Attr("A")); -} - - -string Add(int op, string chip, bool s, bool c) -{ - return Address(op, chip, s, c) ~ - ReadInto(Local("ubyte", "data"), "address", c) ~ - "if (" ~ Attr("D") ~ ")\n{\n" ~ - DecAdd(chip, s, c) ~ - "}\nelse\n{\n" ~ - HexAdd(chip, s, c) ~ - "}\n"; -} - -string HexAdd(string chip, bool s, bool c) -{ - string A = Attr("A"), C = Attr("C"); - - return "uint sum = " ~ A ~ " + data + " ~ C ~ ";\n" ~ - Attr("V") ~ - " = (!((" ~ A ~ " ^ data) & 0x80)) && ((data ^ sum) & 0x80);\n" ~ - C ~ " = (sum > 0xFF);\n" ~ - SetNZ(A ~ " = cast(ubyte)sum"); -} - -string DecAdd(string chip, bool s, bool c) -{ - bool cmos = (chip != "6502"); - string A = Attr("A"), C = Attr("C"); - - return "int a = " ~ A ~ ";\n" ~ - "int al = (a & 0x0F) + (data & 0x0F) + " ~ C ~ ";\n" ~ - "if (al >= 0x0A)\n" ~ - "al = ((al + 0x06) & 0x0F) + 0x10;\n" ~ - "a = (a & 0xF0) + (data & 0xF0) + al;\n" ~ - If!(cmos)("", - Attr("N") ~ " = cast(ubyte)a;\n" ~ - Attr("Z") ~ " = cast(ubyte)(" ~ A ~ " + data + " ~ C ~ ");\n") ~ - Attr("V") ~ - " = (!((" ~ A ~ " ^ data) & 0x80)) && ((data ^ a) & 0x80);\n" ~ - "if (a >= 0xA0)\n" ~ - "a = a + 0x60;\n" ~ - C ~ " = (a >= 0x100);\n" ~ - If!(cmos)( - SetNZ(A ~ " = cast(ubyte)a") ~ Peek(Attr("PC"), s, c), - A ~ " = cast(ubyte)a;\n"); -} - - -string Sub(int op, string chip, bool s, bool c) -{ - return Address(op, chip, s, c) ~ - ReadInto(Local("ubyte", "data"), "address", c) ~ - "if (" ~ Attr("D") ~ ")\n{\n" ~ - DecSub(chip, s, c) ~ - "}\nelse\n{\n" ~ - HexSub(chip, s, c) ~ - "}\n"; -} - -string HexSub(string chip, bool s, bool c) -{ - string A = Attr("A"), C = Attr("C"); - - return "uint diff = " ~ A ~ " - data - !" ~ C ~ ";\n" ~ - Attr("V") ~ - " = ((" ~ A ~ " ^ diff) & 0x80) && ((" ~ A ~ " ^ data) & 0x80);\n" ~ - C ~ " = (diff < 0x100);\n" ~ - SetNZ(A ~ " = cast(ubyte)diff"); -} - -string DecSub(string chip, bool s, bool c) -{ - return (chip == "6502" ? DecSubNMOS(s, c) : DecSubCMOS(s, c)); -} - -string DecSubNMOS(bool s, bool c) -{ - string A = Attr("A"), C = Attr("C"); - - return "int a = " ~ A ~ ";\n" ~ - "int al = (a & 0x0F) - (data & 0x0F) - !" ~ C ~ ";\n" ~ - "if (al < 0)\n" ~ - "al = ((al - 0x06) & 0x0F) - 0x10;\n" ~ - "a = (a & 0xF0) - (data & 0xF0) + al;\n" ~ - "if (a < 0)\n" ~ - "a = a - 0x60;\n" ~ - "uint diff = " ~ A ~ " - data - !" ~ C ~ ";\n" ~ - Attr("V") ~ - " = ((" ~ A ~ " ^ diff) & 0x80) && ((" ~ A ~ " ^ data) & 0x80);\n" ~ - C ~ " = (diff < 0x100);\n" ~ - SetNZ("cast(ubyte)diff") ~ - A ~ " = cast(ubyte)a;\n"; -} - -string DecSubCMOS(bool s, bool c) -{ - string A = Attr("A"), C = Attr("C"); - - return "int a = " ~ A ~ ";\n" ~ - "int al = (a & 0x0F) - (data & 0x0F) - !" ~ C ~ ";\n" ~ - "a = a - data - !" ~ C ~ ";\n" ~ - "if (a < 0) a = a - 0x60;\n" ~ - "if (al < 0) a = a - 0x06;\n" ~ - "uint diff = " ~ A ~ " - data - !" ~ C ~ ";\n" ~ - Attr("V") ~ - " = ((" ~ A ~ " ^ diff) & 0x80) && ((" ~ A ~ " ^ data) & 0x80);\n" ~ - C ~ " = (diff < 0x100);\n" ~ - Peek(Attr("PC"), s, c) ~ - SetNZ(A ~ " = cast(ubyte)a"); -} - - -string Inc(string val) -{ - return val ~ "++;\n" ~ - SetNZ(val); -} - - -string Dec(string val) -{ - return val ~ "--;\n" ~ - SetNZ(val); -} - - -string ShiftLeft(string val) -{ - return Attr("C") ~ " = (" ~ val ~ " > 0x7F);\n" ~ - SetNZ(val ~ " = cast(ubyte)(" ~ val ~ " << 1)"); -} - -string RotateLeft(string val) -{ - string C = Attr("C"); - - return "auto oldC = " ~ C ~ ";\n" ~ - C ~ " = (" ~ val ~ " > 0x7f);\n" ~ - SetNZ(val ~ " = cast(ubyte)(" ~ val ~ " << 1 | (oldC ? 1 : 0))"); -} - -string ShiftRight(string val) -{ - return Attr("C") ~ " = ((" ~ val ~ " & 0x01) != 0);\n" ~ - SetNZ(val ~ " = " ~ val ~ " >> 1"); -} - -string RotateRight(string val) -{ - string C = Attr("C"); - - return "auto oldC = " ~ C ~ ";\n" ~ - C ~ " = ((" ~ val ~ " & 0x01) != 0);\n" ~ - SetNZ(val ~ " = (" ~ val ~ " >> 1 | (oldC ? 0x80 : 0))"); -} - -string RMW(int op, string action, string chip, bool s, bool c) -{ - bool nmos = (chip == "6502"); - - return Address(op, chip, s, c) ~ - ReadInto(Local("ubyte", "data"), "address", c) ~ - If!(nmos)(Poke("address", "data", s, c), - Peek("address", s, c)) ~ - action ~ - Write("address", "data", c); -} - - -string Address(int op, string chip, bool s, bool c) -{ - auto EXTRA_CYCLE = opExCyc(op, chip); - auto PC = Attr("PC"); - - final switch (opMode(op, chip)) - { - case IMP: - return AddrIMP(s, c); - case IMM: - return AddrIMM(s, c); - case ZP: - return AddrZP(s, c); - case ZPX: - return AddrZPXY("X", chip, s, c); - case ZPY: - return AddrZPXY("Y", chip, s, c); - case IZX: - return AddrIZX(chip, s, c); - case IZY: - return AddrIZY(op, chip, s, c); - case ABS: - return AddrABS(s, c); - case ABX: - return AddrABXY(op, "X", chip, s, c); - case ABY: - return AddrABXY(op, "Y", chip, s, c); - case IND: - return Local("ushort", "address") ~ " = 0;"; - case REL: - return Local("ushort", "address") ~ " = 0;"; - case ZPI: - return AddrZPI(s, c); - case ABI: - return Local("ushort", "address") ~ " = 0;"; - case NP1: - return ""; - case NP8: - return Local("ushort", "address") ~ " = 0;"; - case KIL: - return Local("ushort", "address") ~ " = 0;"; - } - return ""; -} - - string PreAccess(bool cumulative) { return If!(cumulative)("++cycles;\n", Attr("clock") ~ ".tick();\n"); @@ -982,77 +1007,85 @@ string Write(string addr, string val, bool cumulative) string IncPC() { - return "++" ~ Attr("PC") ~ ";\n"; + return "++" ~ _PC ~ ";\n"; } string IncSP() { - return "++" ~ Attr("S") ~ ";\n"; + return "++" ~ _S ~ ";\n"; } string DecSP() { - return "--" ~ Attr("S") ~ ";\n"; + return "--" ~ _S ~ ";\n"; } string PullStatus(bool s, bool c) { - return Peek("0x0100 + " ~ Attr("S"), s, c) ~ + return Peek(STACK, s, c) ~ IncSP() ~ PreAccess(c) ~ Attr("statusFromByte") ~ "(" ~ - ReadRaw("0x0100 + " ~ Attr("S")) ~ ");\n"; + ReadRaw(STACK) ~ ");\n"; } string PullInto(string var, bool s, bool c) { - return Peek("0x0100 + " ~ Attr("S"), s, c) ~ - IncSP() ~ - ReadInto(var, "0x0100 + " ~ Attr("S"), c); + return IncSP() ~ + ReadInto(var, STACK, c); } string Push(string val, bool s, bool c) { - return Write("0x0100 + " ~ Attr("S"), val, c) ~ + return Write(STACK, val, c) ~ DecSP(); } string PushPC(bool s, bool c) { - return Push(HiByte(Attr("PC")), s, c) ~ - Push(LoByte(Attr("PC")), s, c); + return Push(HiByte(_PC), s, c) ~ + Push(LoByte(_PC), s, c); } string PullPC(bool s, bool c) { - string PC = Attr("PC"); - - return PullInto(PC, s, c) ~ - PreAccess(c) ~ + return PullInto(_PC, s, c) ~ IncSP() ~ - PC ~ " |= (" ~ ReadRaw("0x0100 + " ~ Attr("S")) ~ " << 8);\n"; + LoadHiByte(_PC, STACK, c); +} + +string LoadLoByte(string type, string var, string addr, bool c) +{ + return PreAccess(c) ~ + Local(type, var) ~ " = " ~ ReadRaw(addr) ~ ";\n"; +} + +string LoadHiByte(string var, string addr, bool c) +{ + return PreAccess(c) ~ + var ~ " |= (" ~ ReadRaw(addr) ~ " << 8);\n"; } string SetFlag(string flag) { - return Attr(flag) ~ " = true;\n"; + return flag ~ " = true;\n"; } string ClearFlag(string flag) { - return Attr(flag) ~ " = false;\n"; + return flag ~ " = false;\n"; } string UpdateFlag(string flag, string val) { - return Attr(flag) ~ " = (" ~ val ~ ");\n"; + return flag ~ " = (" ~ val ~ ");\n"; } string SetNZ(string var) { - return Attr("N") ~ " = " ~ Attr("Z") ~ " = (" ~ var ~ ");\n"; + return _N ~ " = " ~ _Z ~ " = (" ~ var ~ ");\n"; } string Done(bool cumulative) diff --git a/test/test_new_cpu.d b/test/test_new_cpu.d index 4b82f44..5cf5c6e 100644 --- a/test/test_new_cpu.d +++ b/test/test_new_cpu.d @@ -53,5 +53,7 @@ void main() 0x86, 0xa4, 0x84, 0x24, 0x15, 0x35, 0x55, 0x75, 0xf5, 0xd5, 0xd6, 0xf6, 0x16, 0x36, 0x56, 0x76, 0xb5, 0x95, 0xb6, 0x96, 0xb4, 0x94, 0x01, 0x21, 0x41, 0x61, 0xe1, 0xc1, 0xa1, 0x81, - 0x11, 0x31, 0x51, 0x71, 0xf1, 0xd1, 0xb1, 0x91]); + 0x11, 0x31, 0x51, 0x71, 0xf1, 0xd1, 0xb1, 0x91, 0xda, 0x5a, + 0x7a, 0xfa, 0x89, 0x34, 0x3c, 0x1a, 0x3a, 0x80, 0x64, 0x74, + 0x14, 0x1c, 0x04, 0x0c, 0x40]); } From 3c9c14364ffc230a71464825e3061ac65f936254 Mon Sep 17 00:00:00 2001 From: edmccard Date: Wed, 11 Apr 2012 09:27:46 -0400 Subject: [PATCH 13/27] CTFE tweaks --- src/cpu/ctfe_d6502.d | 755 ++++++++++++++++++++++--------------------- src/cpu/d6502.d | 10 +- 2 files changed, 395 insertions(+), 370 deletions(-) diff --git a/src/cpu/ctfe_d6502.d b/src/cpu/ctfe_d6502.d index ffb8f2a..441c5db 100644 --- a/src/cpu/ctfe_d6502.d +++ b/src/cpu/ctfe_d6502.d @@ -173,230 +173,247 @@ enum _C = Attr("C"); enum _S = Attr("S"); enum STACK = "0x0100 + " ~ _S; +struct Env +{ + int op; + string chip; + bool s, c; + bool nmos, cmos; + int mode; + int exCyc; + + this(int op, string chip, bool s, bool c) + { + this.op = op; + this.chip = chip; + this.s = s; + this.c = c; + nmos = (chip == "6502"); + cmos = !nmos; + mode = opMode(op, chip); + exCyc = opExCyc(op, chip); + } +} string OpBody(int op, string chip, bool s, bool c) { - bool nmos = (chip == "6502"); + auto env = Env(op, chip, s, c); + string ret = ((env.mode == IMP) ? AddrIMP(env) : ""); final switch (opName(op, chip)) { case "BRK": - return Break(s, c) ~ - Done(c); + ret ~= Break(env); + break; case "RTI": - return RetInt(s, c) ~ - Done(c); + ret ~= RetInt(env); + break; case "JSR": - return JumpSub(s, c) ~ - Done(c); + ret ~= JumpSub(env); + break; case "RTS": - return RetSub(s, c) ~ - Done(c); + ret ~= RetSub(env); + break; case "JMP": - return Jump(op, chip, s, c) ~ - Done(c); + ret ~= Jump(env); + break; case "KIL": - return _PC ~ "--;\n" ~ - Done(c); + ret ~= _PC ~ "--;\n"; + break; case "BPL": - return Branch("!(" ~ _N ~ " & 0x80)", nmos, s, c) ~ - Done(c); + ret ~= Branch("!(" ~ _N ~ " & 0x80)", env); + break; case "BMI": - return Branch("(" ~ _N ~ " & 0x80)", nmos, s, c) ~ - Done(c); + ret ~= Branch("(" ~ _N ~ " & 0x80)", env); + break; case "BVC": - return Branch("!" ~ _V, nmos, s, c) ~ - Done(c); + ret ~= Branch("!" ~ _V, env); + break; case "BVS": - return Branch(_V, nmos, s, c) ~ - Done(c); + ret ~= Branch(_V, env); + break; case "BRA": - return Branch("true", nmos, s, c) ~ - Done(c); + ret ~= Branch("true", env); + break; case "BCC": - return Branch("!" ~ _C, nmos, s, c) ~ - Done(c); + ret ~= Branch("!" ~ _C, env); + break; case "BCS": - return Branch(_C, nmos, s, c) ~ - Done(c); + ret ~= Branch(_C, env); + break; case "BNE": - return Branch(_Z, nmos, s, c) ~ - Done(c); + ret ~= Branch(_Z, env); + break; case "BEQ": - return Branch("!" ~ _Z, nmos, s, c) ~ - Done(c); + ret ~= Branch("!" ~ _Z, env); + break; case "CLC": - return AddrIMP(s, c) ~ - ClearFlag(_C) ~ - Done(c); + ret ~= ClearFlag(_C); + break; case "SEC": - return AddrIMP(s, c) ~ - SetFlag(_C) ~ - Done(c); + ret ~= SetFlag(_C); + break; case "CLI": - return AddrIMP(s, c) ~ - ClearFlag(_I) ~ - Done(c); + ret ~= ClearFlag(_I); + break; case "SEI": - return AddrIMP(s, c) ~ - SetFlag(_I) ~ - Done(c); + ret ~= SetFlag(_I); + break; case "CLV": - return AddrIMP(s, c) ~ - ClearFlag(_V) ~ - Done(c); + ret ~= ClearFlag(_V); + break; case "CLD": - return AddrIMP(s, c) ~ - ClearFlag(_D) ~ - Done(c); + ret ~= ClearFlag(_D); + break; case "SED": - return AddrIMP(s, c) ~ - SetFlag(_D) ~ - Done(c); + ret ~= SetFlag(_D); + break; case "NOP": - return Nop(op, chip, s, c) ~ - Done(c); + ret ~= Nop(env); + break; case "TAX": - return Transfer(op, _A, _X, s, c) ~ - Done(c); + ret ~= Transfer(_A, _X, env); + break; case "TXA": - return Transfer(op, _X, _A, s, c) ~ - Done(c); + ret ~= Transfer(_X, _A, env); + break; case "TAY": - return Transfer(op, _A, _Y, s, c) ~ - Done(c); + ret ~= Transfer(_A, _Y, env); + break; case "TYA": - return Transfer(op, _Y, _A, s, c) ~ - Done(c); + ret ~= Transfer(_Y, _A, env); + break; case "TSX": - return Transfer(op, _S, _X, s, c) ~ - Done(c); + ret ~= Transfer(_S, _X, env); + break; case "TXS": - return Transfer(op, _X, _S, s, c) ~ - Done(c); + ret ~= Transfer(_X, _S, env); + break; case "DEX": - return AddrIMP(s, c) ~ - Dec(_X) ~ - Done(c); + ret ~= Dec(_X); + break; case "DEY": - return AddrIMP(s, c) ~ - Dec(_Y) ~ - Done(c); + ret ~= Dec(_Y); + break; case "INX": - return AddrIMP(s, c) ~ - Inc(_X) ~ - Done(c); + ret ~= Inc(_X); + break; case "INY": - return AddrIMP(s, c) ~ - Inc(_Y) ~ - Done(c); + ret ~= Inc(_Y); + break; case "PHP": - return AddrIMP(s, c) ~ - Push(Attr("statusToByte()"), s, c) ~ - Done(c); + ret ~= Push(Attr("statusToByte()"), env); + break; case "PLP": - return AddrIMP(s, c) ~ - PullStatus(s, c) ~ - Done(c); + ret ~= PullStatus(env); + break; case "PLA": - return PullReg(_A, s, c) ~ - Done(c); + ret ~= PullReg(_A, env); + break; case "PLX": - return PullReg(_X, s, c) ~ - Done(c); + ret ~= PullReg(_X, env); + break; case "PLY": - return PullReg(_Y, s, c) ~ - Done(c); + ret ~= PullReg(_Y, env); + break; case "PHA": - return PushReg(_A, s, c) ~ - Done(c); + ret ~= PushReg(_A, env); + break; case "PHX": - return PushReg(_X, s, c) ~ - Done(c); + ret ~= PushReg(_X, env); + break; case "PHY": - return PushReg(_Y, s, c) ~ - Done(c); + ret ~= PushReg(_Y, env); + break; case "LDA": - return Load(op, _A, chip, s, c) ~ - Done(c); + ret ~= Load(_A, env); + break; case "LDX": - return Load(op, _X, chip, s, c) ~ - Done(c); + ret ~= Load(_X, env); + break; case "LDY": - return Load(op, _Y, chip, s, c) ~ - Done(c); + ret ~= Load(_Y, env); + break; case "STA": - return Store(op, _A, chip, s, c) ~ - Done(c); + ret ~= Store(_A, env); + break; case "STX": - return Store(op, _X, chip, s, c) ~ - Done(c); + ret ~= Store(_X, env); + break; case "STY": - return Store(op, _Y, chip, s, c) ~ - Done(c); + ret ~= Store(_Y, env); + break; case "STZ": - return Store(op, "0", chip, s, c) ~ - Done(c); + ret ~= Store("0", env); + break; case "CMP": - return Compare(op, _A, chip, s, c) ~ - Done(c); + ret ~= Compare(_A, env); + break; case "CPX": - return Compare(op, _X, chip, s, c) ~ - Done(c); + ret ~= Compare(_X, env); + break; case "CPY": - return Compare(op, _Y, chip, s, c) ~ - Done(c); + ret ~= Compare(_Y, env); + break; case "BIT": - return Bit(op, chip, s, c) ~ - Done(c); + ret ~= Bit(env); + break; case "ORA": - return Logic(op, "|=", chip, s, c) ~ - Done(c); + ret ~= Logic("|=", env); + break; case "AND": - return Logic(op, "&=", chip, s, c) ~ - Done(c); + ret ~= Logic("&=", env); + break; case "EOR": - return Logic(op, "^=", chip, s, c) ~ - Done(c); + ret ~= Logic("^=", env); + break; case "ADC": - return Add(op, chip, s, c) ~ - Done(c); + ret ~= Add(env); + break; case "SBC": - return Sub(op, chip, s, c) ~ - Done(c); + ret ~= Sub(env); + break; case "INC": if (op == 0x1a) - return AddrIMP(s, c) ~ Inc(_A) ~ Done(c); + ret ~= Inc(_A); else - return RMW(op, Inc("data"), chip, s, c) ~ Done(c); + ret ~= RMW(Inc("data"), env); + break; case "DEC": if (op == 0x3a) - return AddrIMP(s, c) ~ Dec(_A) ~ Done(c); + ret ~= Dec(_A); else - return RMW(op, Dec("data"), chip, s, c) ~ Done(c); + ret ~= RMW(Dec("data"), env); + break; case "ASL": if (op == 0x0a) - return AddrIMP(s, c) ~ ShiftLeft(_A) ~ Done(c); + ret ~= ShiftLeft(_A); else - return RMW(op, ShiftLeft("data"), chip, s, c) ~ Done(c); + ret ~= RMW(ShiftLeft("data"), env); + break; case "ROL": if (op == 0x2a) - return AddrIMP(s, c) ~ RotateLeft(_A) ~ Done(c); + ret ~= RotateLeft(_A); else - return RMW(op, RotateLeft("data"), chip, s, c) ~ Done(c); + ret ~= RMW(RotateLeft("data"), env); + break; case "LSR": if (op == 0x4a) - return AddrIMP(s, c) ~ ShiftRight(_A) ~ Done(c); + ret ~= ShiftRight(_A); else - return RMW(op, ShiftRight("data"), chip, s, c) ~ Done(c); + ret ~= RMW(ShiftRight("data"), env); + break; case "ROR": if (op == 0x6a) - return AddrIMP(s, c) ~ ShiftRight(_A) ~ Done(c); + ret ~= ShiftRight(_A); else - return RMW(op, RotateRight("data"), chip, s, c) ~ Done(c); + ret ~= RMW(RotateRight("data"), env); + break; case "TRB": - return RMW(op, TestReset(), chip, s, c) ~ Done(c); + ret ~= RMW(TestReset(), env); + break; case "TSB": - return RMW(op, TestSet(), chip, s, c) ~ Done(c); + ret ~= RMW(TestSet(), env); + break; case "LAS": return ""; case "LAX": @@ -434,149 +451,145 @@ string OpBody(int op, string chip, bool s, bool c) case "ISC": return ""; } + return ret ~ Done(env); } -string Break(bool s, bool c) +string Break(Env env) { - return AddrIMP(s, c) ~ - IncPC() ~ - PushPC(s, c) ~ - Push(Attr("statusToByte()"), s, c) ~ + return IncPC() ~ + PushPC(env) ~ + Push(Attr("statusToByte()"), env) ~ SetFlag(_I) ~ - ReadWord(_PC, "IRQ_VECTOR", c); + ReadWord(_PC, "IRQ_VECTOR", env); } -string JumpSub(bool s, bool c) +string JumpSub(Env env) { - return ReadOp(Local("ushort", "address"), c) ~ - Peek(STACK, s, c) ~ - PushPC(s, c) ~ - LoadHiByte("address", _PC ~ "++", c) ~ + return ReadOp(Local("ushort", "address"), env) ~ + Peek(STACK, env) ~ + PushPC(env) ~ + LoadHiByte("address", _PC ~ "++", env) ~ _PC ~ " = address;\n"; } -string RetSub(bool s, bool c) +string RetSub(Env env) { - return AddrIMP(s, c) ~ - Peek(STACK, s, c) ~ - PullPC(s, c) ~ - Peek(_PC, s, c) ~ + return Peek(STACK, env) ~ + PullPC(env) ~ + Peek(_PC, env) ~ IncPC(); } -string RetInt(bool s, bool c) +string RetInt(Env env) { - return AddrIMP(s, c) ~ - PullStatus(s, c) ~ - PullPC(s, c); + return PullStatus(env) ~ + PullPC(env); } -string Jump(int op, string chip, bool s, bool c) +string Jump(Env env) { - bool nmos = (chip == "6502"); + bool cmos = env.cmos; + bool nmos = env.nmos; - if (op == 0x4c) - return Address(op, chip, s, c) ~ + if (env.op == 0x4c) + return Address(env) ~ _PC ~ " = address;\n"; - else if (op == 0x6c) - return ReadWordOp("ushort", "base", c) ~ - If!(nmos)( - "", - Peek(_PC, s, c)) ~ + else if (env.op == 0x6c) + return ReadWordOp("ushort", "base", env) ~ + If!(cmos)( + Peek(_PC, env)) ~ ReadWordBasic(_PC, "base", If!(nmos)( "(base & 0xFF00) | cast(ubyte)(base + 1)", - "cast(ushort)(base + 1)"), c); - else if (op == 0x7c) - return ReadWordOp("ushort", "base", c) ~ - Peek(_PC, s, c) ~ - ReadWord(_PC, "cast(ushort)(base + " ~ _X ~ ")", c); + "cast(ushort)(base + 1)"), env); + else if (env.op == 0x7c) + return ReadWordOp("ushort", "base", env) ~ + Peek(_PC, env) ~ + ReadWord(_PC, "cast(ushort)(base + " ~ _X ~ ")", env); return ""; } -string Branch(string check, bool nmos, bool s, bool c) +string Branch(string check, Env env) { - return ReadOp(Local("ubyte", "op1"), c) ~ + return ReadOp(Local("ushort", "base"), env) ~ "if (" ~ check ~ ")\n{\n" ~ - Peek(_PC, s, c) ~ - Local("ushort", "base") ~ " = " ~ _PC ~ ";\n" ~ - _PC ~ " = cast(ushort)(" ~ _PC ~ " + cast(byte)op1);\n" ~ - CheckShortcut(_PC, "base", 0, nmos, s, c) ~ + Peek(_PC, env) ~ + Local("ushort", "address") ~ + " = cast(ushort)(" ~ _PC ~ " + cast(byte)base);\n" ~ + CheckShortcut(_PC, "address", env) ~ + _PC ~ " = address;\n" ~ "}\n"; } -string Nop(int op, string chip, bool s, bool c) +string Nop(Env env) { - auto mode = opMode(op, chip); - if (mode == IMP || mode == NP1 || mode == NP8) - return Address(op, chip, s, c); + if (env.mode == IMP || env.mode == NP1 || env.mode == NP8) + return Address(env); else - return Address(op, chip, s, c) ~ - Peek("address", true, c); + return Address(env) ~ + PreAccess(env) ~ + ReadRaw("address") ~ ";\n"; } -string Transfer(int op, string source, string dest, bool s, bool c) +string Transfer(string source, string dest, Env env) { - return AddrIMP(s, c) ~ - dest ~ " = " ~ source ~ ";\n" ~ - ((op != 0x9a) ? SetNZ(dest) : ""); + return dest ~ " = " ~ source ~ ";\n" ~ + ((env.op != 0x9a) ? SetNZ(dest) : ""); } -string PullReg(string reg, bool s, bool c) +string PullReg(string reg, Env env) { - return AddrIMP(s, c) ~ - Peek(STACK, s, c) ~ - PullInto(reg, s, c) ~ + return Peek(STACK, env) ~ + PullInto(reg, env) ~ SetNZ(reg); } -string PushReg(string reg, bool s, bool c) +string PushReg(string reg, Env env) { - return AddrIMP(s, c) ~ - Push(reg, s, c); + return Push(reg, env); } -string Load(int op, string reg, string chip, bool s, bool c) +string Load(string reg, Env env) { - return Address(op, chip, s, c) ~ - ReadInto(reg, "address", c) ~ + return Address(env) ~ + ReadInto(reg, "address", env) ~ SetNZ(reg); } -string Store(int op, string reg, string chip, bool s, bool c) +string Store(string reg, Env env) { - return Address(op, chip, s, c) ~ - Write("address", reg, c); + return Address(env) ~ + Write("address", reg, env); } -string Compare(int op, string reg, string chip, bool s, bool c) +string Compare(string reg, Env env) { - return Address(op, chip, s, c) ~ - ReadInto(Local("ubyte", "data"), "address", c) ~ + return Address(env) ~ + ReadInto(Local("ubyte", "data"), "address", env) ~ UpdateFlag(_C, reg ~ " >= data") ~ SetNZ("cast(ubyte)(" ~ reg ~ " - data)"); } -string Bit(int op, string chip, bool s, bool c) +string Bit(Env env) { - bool notImm = (opMode(op, chip) != IMM); + bool notImm = (env.mode != IMM); - return Address(op, chip, s, c) ~ - ReadInto(Local("ubyte", "data"), "address", c) ~ + return Address(env) ~ + ReadInto(Local("ubyte", "data"), "address", env) ~ If!(notImm)( _N ~ " = data;\n" ~ _V ~ " = ((data & 0x40) != 0);\n") ~ @@ -584,26 +597,26 @@ string Bit(int op, string chip, bool s, bool c) } -string Logic(int op, string action, string chip, bool s, bool c) +string Logic(string action, Env env) { - return Address(op, chip, s, c) ~ - ReadInto(_A, action, "address", c) ~ + return Address(env) ~ + ReadInto(_A, action, "address", env) ~ SetNZ(_A); } -string Add(int op, string chip, bool s, bool c) +string Add(Env env) { - return Address(op, chip, s, c) ~ - ReadInto(Local("ubyte", "data"), "address", c) ~ + return Address(env) ~ + ReadInto(Local("ubyte", "data"), "address", env) ~ "if (" ~ _D ~ ")\n{\n" ~ - DecAdd(chip, s, c) ~ + DecAdd(env) ~ "}\nelse\n{\n" ~ - HexAdd(chip, s, c) ~ + HexAdd(env) ~ "}\n"; } -string HexAdd(string chip, bool s, bool c) +string HexAdd(Env env) { return "uint sum = " ~ _A ~ " + data + " ~ _C ~ ";\n" ~ _V ~ @@ -612,9 +625,9 @@ string HexAdd(string chip, bool s, bool c) SetNZ(_A ~ " = cast(ubyte)sum"); } -string DecAdd(string chip, bool s, bool c) +string DecAdd(Env env) { - bool cmos = (chip != "6502"); + bool cmos = env.cmos; return "int a = " ~ _A ~ ";\n" ~ "int al = (a & 0x0F) + (data & 0x0F) + " ~ _C ~ ";\n" ~ @@ -630,23 +643,25 @@ string DecAdd(string chip, bool s, bool c) "a = a + 0x60;\n" ~ _C ~ " = (a >= 0x100);\n" ~ If!(cmos)( - SetNZ(_A ~ " = cast(ubyte)a") ~ Peek(_PC, s, c), + SetNZ(_A ~ " = cast(ubyte)a") ~ Peek(_PC, env), _A ~ " = cast(ubyte)a;\n"); } -string Sub(int op, string chip, bool s, bool c) +string Sub(Env env) { - return Address(op, chip, s, c) ~ - ReadInto(Local("ubyte", "data"), "address", c) ~ + bool nmos = env.nmos; + + return Address(env) ~ + ReadInto(Local("ubyte", "data"), "address", env) ~ "if (" ~ _D ~ ")\n{\n" ~ - DecSub(chip, s, c) ~ + If!(nmos)(DecSubNMOS(), DecSubCMOS(env)) ~ "}\nelse\n{\n" ~ - HexSub(chip, s, c) ~ + HexSub() ~ "}\n"; } -string HexSub(string chip, bool s, bool c) +string HexSub() { return "uint diff = " ~ _A ~ " - data - !" ~ _C ~ ";\n" ~ _V ~ @@ -656,12 +671,7 @@ string HexSub(string chip, bool s, bool c) SetNZ(_A ~ " = cast(ubyte)diff"); } -string DecSub(string chip, bool s, bool c) -{ - return (chip == "6502" ? DecSubNMOS(s, c) : DecSubCMOS(s, c)); -} - -string DecSubNMOS(bool s, bool c) +string DecSubNMOS() { return "int a = " ~ _A ~ ";\n" ~ "int al = (a & 0x0F) - (data & 0x0F) - !" ~ _C ~ ";\n" ~ @@ -679,7 +689,7 @@ string DecSubNMOS(bool s, bool c) _A ~ " = cast(ubyte)a;\n"; } -string DecSubCMOS(bool s, bool c) +string DecSubCMOS(Env env) { return "int a = " ~ _A ~ ";\n" ~ "int al = (a & 0x0F) - (data & 0x0F) - !" ~ _C ~ ";\n" ~ @@ -691,7 +701,7 @@ string DecSubCMOS(bool s, bool c) " = ((" ~ _A ~ " ^ diff) & 0x80) && ((" ~ _A ~ " ^ data) & 0x80);\n" ~ _C ~ " = (diff < 0x100);\n" ~ - Peek(_PC, s, c) ~ + Peek(_PC, env) ~ SetNZ(_A ~ " = cast(ubyte)a"); } @@ -754,183 +764,196 @@ string TestSet() } -string RMW(int op, string action, string chip, bool s, bool c) +string RMW(string action, Env env) { - bool nmos = (chip == "6502"); + bool nmos = env.nmos; - return Address(op, chip, s, c) ~ - ReadInto(Local("ubyte", "data"), "address", c) ~ - If!(nmos)(Poke("address", "data", s, c), - Peek("address", s, c)) ~ + return Address(env) ~ + ReadInto(Local("ubyte", "data"), "address", env) ~ + If!(nmos)(Poke("address", "data", env), + Peek("address", env)) ~ action ~ - Write("address", "data", c); + Write("address", "data", env); } string Local(string type) { + version(OpFunctions) + return type ~ " "; + else + return ""; +/+ version(OpSwitch) return ""; else version(OpNestedSwitch) return ""; else - return type ~ " "; + return type ~ " "; ++/ } string Local(string type, string var) { + version(OpFunctions) + return type ~ " " ~ var; + else + return var; +/+ version(OpSwitch) return var; else version(OpNestedSwitch) return var; else return type ~ " " ~ var; ++/ +} + +string Attr(string var) +{ + version(OpFunctions) + return "cpu." ~ var; + else + return var; } -string Address(int op, string chip, bool s, bool c) +string Address(Env env) { - auto EXTRA_CYCLE = opExCyc(op, chip); - auto PC = Attr("PC"); - - final switch (opMode(op, chip)) + final switch (env.mode) { case IMP: - return AddrIMP(s, c); + return ""; case IMM: - return AddrIMM(s, c); + return AddrIMM(env); case ZP: - return AddrZP(s, c); + return AddrZP(env); case ZPX: - return AddrZPXY(_X, chip, s, c); + return AddrZPXY(_X, env); case ZPY: - return AddrZPXY(_Y, chip, s, c); + return AddrZPXY(_Y, env); case IZX: - return AddrIZX(chip, s, c); + return AddrIZX(env); case IZY: - return AddrIZY(op, chip, s, c); + return AddrIZY(env); case ABS: - return AddrABS(s, c); + return AddrABS(env); case ABX: - return AddrABXY(op, _X, chip, s, c); + return AddrABXY(_X, env); case ABY: - return AddrABXY(op, _Y, chip, s, c); + return AddrABXY(_Y, env); case IND: - return Local("ushort", "address") ~ " = 0;"; + return ""; case REL: - return Local("ushort", "address") ~ " = 0;"; + return ""; case ZPI: - return AddrZPI(s, c); + return AddrZPI(env); case ABI: - return Local("ushort", "address") ~ " = 0;"; + return ""; case NP1: return ""; case NP8: return Local("ushort", "address") ~ " = 0;"; case KIL: - return Local("ushort", "address") ~ " = 0;"; + return ""; } return ""; } -string AddrIMM(bool s, bool c) +string AddrIMM(Env env) { return Local("ushort") ~ "address = " ~ _PC ~ "++;\n"; } -string AddrIMP(bool s, bool c) +string AddrIMP(Env env) { - return Peek(_PC, s, c); + return Peek(_PC, env); } -string AddrZP(bool s, bool c) +string AddrZP(Env env) { - return ReadOp(Local("ushort", "address"), c); + return ReadOp(Local("ushort", "address"), env); } -string AddrZPXY(string reg, string chip, bool s, bool c) +string AddrZPXY(string reg, Env env) { - bool nmos = (chip == "6502"); + bool nmos = env.nmos; - return ReadOp(Local("ushort", "base"), c) ~ + return ReadOp(Local("ushort", "base"), env) ~ If!(nmos)( - Peek("base", s, c), - Peek(_PC, s, c)) ~ + Peek("base", env), + Peek(_PC, env)) ~ Local("ushort") ~ "address = cast(ubyte)(base + " ~ reg ~ ");\n"; } -string AddrIZX(string chip, bool s, bool c) +string AddrIZX(Env env) { - bool nmos = (chip == "6502"); - return ReadOp(Local("ushort", "base"), c) ~ + bool nmos = env.nmos; + + return ReadOp(Local("ushort", "base"), env) ~ If!(nmos)( - Peek("base", s, c), - Peek(_PC, s, c)) ~ - ReadWordZP("ushort", "address", "base + " ~ _X, c); + Peek("base", env), + Peek(_PC, env)) ~ + ReadWordZP("ushort", "address", "base + " ~ _X, env); } -string AddrIZY(int op, string chip, bool s, bool c) +string AddrIZY(Env env) { - int exCyc = opExCyc(op, chip); - bool nmos = (chip == "6502"); - - return ReadOp("ubyte vector", c) ~ - ReadWordZP("ushort", "base", "vector", c) ~ + return ReadOp("ubyte vector", env) ~ + ReadWordZP("ushort", "base", "vector", env) ~ Local("ushort") ~ "address = cast(ushort)(base + " ~ _Y ~ ");\n" ~ - CheckShortcut("address", _PC, - exCyc, nmos, s, c); + CheckShortcut("base", "address", env); } -string AddrABS(bool s, bool c) +string AddrABS(Env env) { - return ReadWordOp("ushort", "address", c); + return ReadWordOp("ushort", "address", env); } -string AddrABXY(int op, string reg, string chip, bool s, bool c) +string AddrABXY(string reg, Env env) { - bool nmos = (chip == "6502"); - int exCyc = opExCyc(op, chip); - - return ReadWordOp("ushort", "base", c) ~ + return ReadWordOp("ushort", "base", env) ~ Local("ushort") ~ "address = cast(ushort)(base + " ~ reg ~ ");\n" ~ - CheckShortcut("address", _PC, exCyc, nmos, s, c); + CheckShortcut("base", "address", env); } -string AddrZPI(bool s, bool c) +string AddrZPI(Env env) { - return ReadOp(Local("ushort", "base"), c) ~ - ReadWordZP("ushort", "address", "base", c); + return ReadOp(Local("ushort", "base"), env) ~ + ReadWordZP("ushort", "address", "base", env); } -string CheckShortcut(string addr, string pc, int exCyc, bool nmos, bool s, - bool c) +string CheckShortcut(string base, string addr, Env env) { - return "ushort guess = (base & 0xFF00) | cast(ubyte)" ~ addr ~ ";\n" ~ + bool nmos = env.nmos; + int exCyc = env.exCyc; + + return "ushort guess = (" ~ base ~ " & 0xFF00) | cast(ubyte)" ~ addr ~ ";\n" ~ "if (guess != " ~ addr ~ ")\n{\n" ~ - If!(nmos)(Peek("guess", s, c), - Peek(pc, s, c)) ~ + If!(nmos)(Peek("guess", env), + Peek(_PC, env)) ~ "}\n" ~ - If!(exCyc)("else\n{\n" ~ Peek("address", s, c) ~ "}\n"); + If!(exCyc)("else\n{\n" ~ Peek("address", env) ~ "}\n"); } -string ReadInto(string var, string action, string addr, bool c) +string ReadInto(string var, string action, string addr, Env env) { - return PreAccess(c) ~ + return PreAccess(env) ~ var ~ " " ~ action ~ " " ~ ReadRaw("(" ~ addr ~ ")") ~ ";\n"; } -string ReadInto(string var, string addr, bool c) +string ReadInto(string var, string addr, Env env) { - return ReadInto(var, "=", addr, c); + return ReadInto(var, "=", addr, env); } -string ReadOp(string var, bool c) +string ReadOp(string var, Env env) { - return ReadInto(var, _PC ~ "++", c); + return ReadInto(var, _PC ~ "++", env); } string ReadRaw(string addr) @@ -939,69 +962,73 @@ string ReadRaw(string addr) } string ReadWordBasic(string type, string var, string addr1, string addr2, - bool c) + Env env) { - return LoadLoByte(type, var, addr1, c) ~ - LoadHiByte(var, addr2, c); + return LoadLoByte(type, var, addr1, env) ~ + LoadHiByte(var, addr2, env); } -string ReadWordBasic(string var, string addr1, string addr2, bool c) +string ReadWordBasic(string var, string addr1, string addr2, Env env) { - return ReadWordBasic("", var, addr1, addr2, c); + return ReadWordBasic("", var, addr1, addr2, env); } -string ReadWord(string type, string var, string addr, bool c) +string ReadWord(string type, string var, string addr, Env env) { - return ReadWordBasic(type, var, addr, "cast(ushort)(" ~ addr ~ " + 1)", c); + return ReadWordBasic(type, var, addr, "cast(ushort)(" ~ addr ~ " + 1)", + env); } -string ReadWord(string var, string addr, bool c) +string ReadWord(string var, string addr, Env env) { - return ReadWord("", var, addr, c); + return ReadWord("", var, addr, env); } -string ReadWordZP(string type, string var, string addr, bool c) +string ReadWordZP(string type, string var, string addr, Env env) { return ReadWordBasic(type, var, "cast(ubyte)( " ~ addr ~ ")", - "cast(ubyte)(" ~ addr ~ " + 1)", c); + "cast(ubyte)(" ~ addr ~ " + 1)", env); } -string ReadWordZP(string var, string addr, bool c) +string ReadWordZP(string var, string addr, Env env) { - return ReadWordZP("", var, addr, c); + return ReadWordZP("", var, addr, env); } -string ReadWordOp(string type, string var, bool c) +string ReadWordOp(string type, string var, Env env) { - return ReadWordBasic(type, var, _PC ~ "++", _PC ~ "++", c); + return ReadWordBasic(type, var, _PC ~ "++", _PC ~ "++", env); } -string ReadWordOp(string var, bool c) +string ReadWordOp(string var, Env env) { - return ReadWordOp("", var, c); + return ReadWordOp("", var, env); } -string PreAccess(bool cumulative) +string PreAccess(Env env) { - return If!(cumulative)("++cycles;\n", Attr("clock") ~ ".tick();\n"); + bool c = env.c; + return If!(c)("++cycles;\n", Attr("clock") ~ ".tick();\n"); } -string Peek(string addr, bool strict, bool cumulative) +string Peek(string addr, Env env) { - return PreAccess(cumulative) ~ - If!(strict)(Attr("memory") ~ ".read(" ~ addr ~");\n"); + bool s = env.s; + return PreAccess(env) ~ + If!(s)(Attr("memory") ~ ".read(" ~ addr ~");\n"); } -string Poke(string addr, string val, bool strict, bool cumulative) +string Poke(string addr, string val, Env env) { - return PreAccess(cumulative) ~ - If!(strict)( + bool s = env.s; + return PreAccess(env) ~ + If!(s)( Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"); } -string Write(string addr, string val, bool cumulative) +string Write(string addr, string val, Env env) { - return PreAccess(cumulative) ~ + return PreAccess(env) ~ Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"; } @@ -1021,50 +1048,50 @@ string DecSP() return "--" ~ _S ~ ";\n"; } -string PullStatus(bool s, bool c) +string PullStatus(Env env) { - return Peek(STACK, s, c) ~ + return Peek(STACK, env) ~ IncSP() ~ - PreAccess(c) ~ + PreAccess(env) ~ Attr("statusFromByte") ~ "(" ~ ReadRaw(STACK) ~ ");\n"; } -string PullInto(string var, bool s, bool c) +string PullInto(string var, Env env) { return IncSP() ~ - ReadInto(var, STACK, c); + ReadInto(var, STACK, env); } -string Push(string val, bool s, bool c) +string Push(string val, Env env) { - return Write(STACK, val, c) ~ + return Write(STACK, val, env) ~ DecSP(); } -string PushPC(bool s, bool c) +string PushPC(Env env) { - return Push(HiByte(_PC), s, c) ~ - Push(LoByte(_PC), s, c); + return Push(HiByte(_PC), env) ~ + Push(LoByte(_PC), env); } -string PullPC(bool s, bool c) +string PullPC(Env env) { - return PullInto(_PC, s, c) ~ + return PullInto(_PC, env) ~ IncSP() ~ - LoadHiByte(_PC, STACK, c); + LoadHiByte(_PC, STACK, env); } -string LoadLoByte(string type, string var, string addr, bool c) +string LoadLoByte(string type, string var, string addr, Env env) { - return PreAccess(c) ~ + return PreAccess(env) ~ Local(type, var) ~ " = " ~ ReadRaw(addr) ~ ";\n"; } -string LoadHiByte(string var, string addr, bool c) +string LoadHiByte(string var, string addr, Env env) { - return PreAccess(c) ~ + return PreAccess(env) ~ var ~ " |= (" ~ ReadRaw(addr) ~ " << 8);\n"; } @@ -1088,18 +1115,10 @@ string SetNZ(string var) return _N ~ " = " ~ _Z ~ " = (" ~ var ~ ");\n"; } -string Done(bool cumulative) +string Done(Env env) { - return If!(cumulative)(Attr("clock") ~ ".tick(cycles);\n"); -} - - -string Attr(string var) -{ - version(OpFunctions) - return "cpu." ~ var; - else - return var; + bool c = env.c; + return If!(c)(Attr("clock") ~ ".tick(cycles);\n"); } diff --git a/src/cpu/d6502.d b/src/cpu/d6502.d index 4d923ad..0aef333 100644 --- a/src/cpu/d6502.d +++ b/src/cpu/d6502.d @@ -94,6 +94,13 @@ final class Cpu(string chip, bool strict, bool cumulative) bool V, D, I, C; static if (opArray) { mixin(OpArrayDef()); } + version(OpFunctions) {} + else + { + static if (cumulative) { int cycles; } + ushort address, base; + ubyte data; + } // TODO: other methods for stopping cpu bool keepRunning; @@ -132,7 +139,6 @@ final class Cpu(string chip, bool strict, bool cumulative) static if (!opArray) { static if (cumulative) { int cycles; } - ubyte op1; ushort address, base; ubyte data; } @@ -174,6 +180,6 @@ version(OpFunctions) mixin(OpBodies("65C02", vStrict, vCumulative)); void main() { import std.stdio; - writeln(OpBody(0x11, "6502", true, false)); + writeln(OpBody(0x11, "65C02", true, false)); } +/ From 8085dc61a03823969036e90efc4d390cb818c6fb Mon Sep 17 00:00:00 2001 From: edmccard Date: Wed, 11 Apr 2012 22:04:18 -0400 Subject: [PATCH 14/27] Fix undoc RMW tests; better status printing in tests --- test/base.d | 3 +++ test/cpu.d | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/base.d b/test/base.d index aa4f153..ebbe4d1 100644 --- a/test/base.d +++ b/test/base.d @@ -2115,6 +2115,7 @@ auto expect_ASO() setA(expected.cpu, getA(expected.cpu) | val); expect_rmw(false, val, expected, info); + setNZ(expected.cpu, getA(expected.cpu)); } return &expect; } @@ -2131,6 +2132,7 @@ auto expect_RLA() setA(expected.cpu, getA(expected.cpu) & val); expect_rmw(false, val, expected, info); + setNZ(expected.cpu, getA(expected.cpu)); } return &expect; } @@ -2146,6 +2148,7 @@ auto expect_LSE() setA(expected.cpu, getA(expected.cpu) ^ val); expect_rmw(false, val, expected, info); + setNZ(expected.cpu, getA(expected.cpu)); } return &expect; } diff --git a/test/cpu.d b/test/cpu.d index dd22535..ee6f3f1 100644 --- a/test/cpu.d +++ b/test/cpu.d @@ -239,7 +239,7 @@ struct CpuInfo string toString() const { - return format("PC %0.4X SP %0.2X S %0.2X A %0.2X X %0.2X Y %0.2X", + return format("PC %0.4X SP %0.2X S %0.8b A %0.2X X %0.2X Y %0.2X", PC, SP, S, A, X, Y); } From 216ba9b6f30bfe4816c87ac42521cfda3301907b Mon Sep 17 00:00:00 2001 From: edmccard Date: Wed, 11 Apr 2012 22:05:29 -0400 Subject: [PATCH 15/27] Implement stable undocumented opcodes --- src/cpu/ctfe_d6502.d | 185 +++++++++++++++++++++++++++++++++---------- src/cpu/d6502.d | 2 +- test/test_new_cpu.d | 8 +- 3 files changed, 153 insertions(+), 42 deletions(-) diff --git a/src/cpu/ctfe_d6502.d b/src/cpu/ctfe_d6502.d index 441c5db..ced851d 100644 --- a/src/cpu/ctfe_d6502.d +++ b/src/cpu/ctfe_d6502.d @@ -198,7 +198,8 @@ struct Env string OpBody(int op, string chip, bool s, bool c) { auto env = Env(op, chip, s, c); - string ret = ((env.mode == IMP) ? AddrIMP(env) : ""); + string ret = ((op == 0x20) ? "" : Address(env)); + final switch (opName(op, chip)) { case "BRK": @@ -415,19 +416,29 @@ string OpBody(int op, string chip, bool s, bool c) ret ~= RMW(TestSet(), env); break; case "LAS": - return ""; + ret ~= LAS_Undoc(env); + break; case "LAX": - return ""; // address modes + if (op != 0xAB) + ret ~= Load(_A ~ " = " ~ _X, env); + else + return ""; + break; case "SAX": - return ""; + ret ~= Store(_A ~ " & " ~ _X, env); + break; case "ANC": - return ""; + ret ~= ANC_Undoc(env); + break; case "ALR": - return ""; + ret ~= ALR_Undoc(env); + break; case "ARR": - return ""; + ret ~= ARR_Undoc(env); + break; case "AXS": - return ""; + ret ~= AXS_Undoc(env); + break; case "AHX": return ""; case "SHY": @@ -439,17 +450,26 @@ string OpBody(int op, string chip, bool s, bool c) case "XAA": return ""; case "SLO": - return ""; + ret ~= RMW_Undoc(ShiftLeft("data"), + SetNZ(_A ~ " |= data"), env); + break; case "RLA": - return ""; + ret ~= RMW_Undoc(RotateLeft("data"), + SetNZ(_A ~ " &= data"), env); + break; case "SRE": - return ""; + ret ~= RMW_Undoc(ShiftRight("data"), + SetNZ(_A ~ " ^= data"), env); + break; case "RRA": - return ""; + ret ~= RMW_Undoc(RotateRight("data"), AddBase(env), env); + break; case "DCP": - return ""; + ret ~= RMW_Undoc(Dec("data"), CompareBase(_A, env), env); + break; case "ISC": - return ""; + ret ~= RMW_Undoc(Inc("data"), SubBase(env), env); + break; } return ret ~ Done(env); } @@ -497,8 +517,7 @@ string Jump(Env env) bool nmos = env.nmos; if (env.op == 0x4c) - return Address(env) ~ - _PC ~ " = address;\n"; + return _PC ~ " = address;\n"; else if (env.op == 0x6c) return ReadWordOp("ushort", "base", env) ~ If!(cmos)( @@ -531,10 +550,9 @@ string Branch(string check, Env env) string Nop(Env env) { if (env.mode == IMP || env.mode == NP1 || env.mode == NP8) - return Address(env); + return ""; // XXX add np1/np8 stuff else - return Address(env) ~ - PreAccess(env) ~ + return PreAccess(env) ~ ReadRaw("address") ~ ";\n"; } @@ -562,24 +580,26 @@ string PushReg(string reg, Env env) string Load(string reg, Env env) { - return Address(env) ~ - ReadInto(reg, "address", env) ~ + return ReadInto(reg, "address", env) ~ SetNZ(reg); } string Store(string reg, Env env) { - return Address(env) ~ - Write("address", reg, env); + return Write("address", reg, env); } string Compare(string reg, Env env) { - return Address(env) ~ - ReadInto(Local("ubyte", "data"), "address", env) ~ - UpdateFlag(_C, reg ~ " >= data") ~ + return ReadInto(Local("ubyte", "data"), "address", env) ~ + CompareBase(reg, env); +} + +string CompareBase(string reg, Env env) +{ + return UpdateFlag(_C, reg ~ " >= data") ~ SetNZ("cast(ubyte)(" ~ reg ~ " - data)"); } @@ -588,8 +608,7 @@ string Bit(Env env) { bool notImm = (env.mode != IMM); - return Address(env) ~ - ReadInto(Local("ubyte", "data"), "address", env) ~ + return ReadInto(Local("ubyte", "data"), "address", env) ~ If!(notImm)( _N ~ " = data;\n" ~ _V ~ " = ((data & 0x40) != 0);\n") ~ @@ -599,17 +618,20 @@ string Bit(Env env) string Logic(string action, Env env) { - return Address(env) ~ - ReadInto(_A, action, "address", env) ~ + return ReadInto(_A, action, "address", env) ~ SetNZ(_A); } string Add(Env env) { - return Address(env) ~ - ReadInto(Local("ubyte", "data"), "address", env) ~ - "if (" ~ _D ~ ")\n{\n" ~ + return ReadInto(Local("ubyte", "data"), "address", env) ~ + AddBase(env); +} + +string AddBase(Env env) +{ + return "if (" ~ _D ~ ")\n{\n" ~ DecAdd(env) ~ "}\nelse\n{\n" ~ HexAdd(env) ~ @@ -649,12 +671,16 @@ string DecAdd(Env env) string Sub(Env env) +{ + return ReadInto(Local("ubyte", "data"), "address", env) ~ + SubBase(env); +} + +string SubBase(Env env) { bool nmos = env.nmos; - return Address(env) ~ - ReadInto(Local("ubyte", "data"), "address", env) ~ - "if (" ~ _D ~ ")\n{\n" ~ + return "if (" ~ _D ~ ")\n{\n" ~ If!(nmos)(DecSubNMOS(), DecSubCMOS(env)) ~ "}\nelse\n{\n" ~ HexSub() ~ @@ -768,8 +794,7 @@ string RMW(string action, Env env) { bool nmos = env.nmos; - return Address(env) ~ - ReadInto(Local("ubyte", "data"), "address", env) ~ + return ReadInto(Local("ubyte", "data"), "address", env) ~ If!(nmos)(Poke("address", "data", env), Peek("address", env)) ~ action ~ @@ -777,6 +802,74 @@ string RMW(string action, Env env) } +string RMW_Undoc(string action1, string action2, Env env) +{ + return ReadInto(Local("ubyte", "data"), "address", env) ~ + Poke("address", "data", env) ~ + action1 ~ + Write("address", "data", env) ~ + action2; +} + + +string LAS_Undoc(Env env) +{ + return ReadInto(Local("ubyte", "data"), "address", env) ~ + SetNZ(_X ~ " = " ~ _A ~ " = (" ~ _S ~ " & data)"); +} + + +string ARR_Undoc(Env env) +{ + return ReadInto(Local("ubyte", "data"), "address", env) ~ + "ubyte tmp1 = data & " ~ _A ~ ";\n" ~ + "if (" ~ _D ~ ")\n{\n" ~ + "ubyte tmp2 = cast(ubyte)((tmp1 >> 1) + (" ~ + _C ~ " ? 0x80 : 0));\n" ~ + _N ~ " = " ~ _Z ~ " = tmp2;\n" ~ + _V ~ " = (((tmp2 ^ tmp1) & 0x40) != 0);\n" ~ + "if ((data & 0x0F) + (tmp1 & 0x01) > 5)\n" ~ + "tmp2 = (tmp2 & 0xF0) + ((tmp2 + 0x6) & 0x0F);\n" ~ + "if (tmp1 + (tmp1 & 0x10) >= 0x60)\n{\n" ~ + "tmp2 += 0x60;\n" ~ + SetFlag(_C) ~ + "}\nelse\n" ~ + ClearFlag(_C) ~ + _A ~ " = tmp2;\n" ~ + "}\nelse{\n" ~ + _A ~ " = cast(ubyte)((tmp1 >> 1) + (" ~ + _C ~ " ? 0x80 : 0));\n" ~ + _N ~ " = " ~ _Z ~ " = " ~_A ~ ";\n" ~ + "tmp1 >>= 7;\n" ~ + _C ~ " = (tmp1 != 0);\n" ~ + _V ~ " = ((tmp1 ^ ((" ~ _A ~ " >> 5) & 1)) != 0);\n}"; +} + + +string ANC_Undoc(Env env) +{ + return ReadInto(_A, "address", env) ~ + SetNZ(_A) ~ + _C ~ " = (" ~ _A ~ " > 0x7f);\n"; +} + + +string ALR_Undoc(Env env) +{ + return ReadInto(Local("ubyte", "data"), "address", env) ~ + _A ~ " &= data;\n" ~ + ShiftRight(_A); +} + + +string AXS_Undoc(Env env) +{ + return ReadInto(Local("ubyte", "data"), "address", env) ~ + _X ~ " &= " ~ _A ~ ";\n" ~ + CompareBase(_X, env); +} + + string Local(string type) { version(OpFunctions) @@ -823,7 +916,7 @@ string Address(Env env) final switch (env.mode) { case IMP: - return ""; + return AddrIMP(env); case IMM: return AddrIMM(env); case ZP: @@ -853,7 +946,7 @@ string Address(Env env) case NP1: return ""; case NP8: - return Local("ushort", "address") ~ " = 0;"; + return AddrNP8(env); case KIL: return ""; } @@ -926,6 +1019,18 @@ string AddrZPI(Env env) ReadWordZP("ushort", "address", "base", env); } +string AddrNP8(Env env) +{ + return ReadOp(Local("ushort", "base"), env) ~ + Peek(_PC, env) ~ + IncPC() ~ + Peek("0xff00 | base", env) ~ + Peek("0xffff", env) ~ + Peek("0xffff", env) ~ + Peek("0xffff", env) ~ + Peek("0xffff", env); +} + string CheckShortcut(string base, string addr, Env env) { bool nmos = env.nmos; diff --git a/src/cpu/d6502.d b/src/cpu/d6502.d index 0aef333..365675e 100644 --- a/src/cpu/d6502.d +++ b/src/cpu/d6502.d @@ -180,6 +180,6 @@ version(OpFunctions) mixin(OpBodies("65C02", vStrict, vCumulative)); void main() { import std.stdio; - writeln(OpBody(0x11, "65C02", true, false)); + writeln(OpBody(0x11, "6502", true, false)); } +/ diff --git a/test/test_new_cpu.d b/test/test_new_cpu.d index 5cf5c6e..7bfc9fa 100644 --- a/test/test_new_cpu.d +++ b/test/test_new_cpu.d @@ -55,5 +55,11 @@ void main() 0xb4, 0x94, 0x01, 0x21, 0x41, 0x61, 0xe1, 0xc1, 0xa1, 0x81, 0x11, 0x31, 0x51, 0x71, 0xf1, 0xd1, 0xb1, 0x91, 0xda, 0x5a, 0x7a, 0xfa, 0x89, 0x34, 0x3c, 0x1a, 0x3a, 0x80, 0x64, 0x74, - 0x14, 0x1c, 0x04, 0x0c, 0x40]); + 0x14, 0x1c, 0x04, 0x0c, 0x40, 0x03, 0x07, 0x0f, 0x13, 0x17, + 0x1b, 0x1f, 0x23, 0x27, 0x2f, 0x33, 0x37, 0x3b, 0x3f, 0x43, + 0x47, 0x4f, 0x53, 0x57, 0x5b, 0x5f, 0x5c, 0x63, 0x67, 0x6f, + 0x73, 0x77, 0x7b, 0x7f, 0xc3, 0xc7, 0xcf, 0xd3, 0xd7, 0xdb, + 0xdf, 0xe3, 0xe7, 0xe7, 0xf3, 0xf7, 0xfb, 0xff, 0xbb, 0x83, + 0x87, 0x8f, 0x97, 0xa3, 0xa7, 0xaf, 0xb3, 0xb7, 0xbf, 0x6b, + 0x0b, 0x2b, 0x4b, 0xeb, 0xcb]); } From b99e6819529f16a1727442157e8d1833ffd5f56a Mon Sep 17 00:00:00 2001 From: edmccard Date: Wed, 11 Apr 2012 23:32:16 -0400 Subject: [PATCH 16/27] Standardize opcode names between test and cpu --- test/base.d | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/test/base.d b/test/base.d index ebbe4d1..5b8b650 100644 --- a/test/base.d +++ b/test/base.d @@ -1232,8 +1232,8 @@ auto setup_op_LSR(bool isAcc) } -// For ASO. -auto setup_op_ASO() +// For SLO. +auto setup_op_SLO() { auto setup(ubyte opcode, CpuInfo cpu, Block[] data, OpInfo info, string msg, TestSetup* next) @@ -1249,7 +1249,7 @@ auto setup_op_ASO() callNext("acc 0x20 "); } return connect(TestSetup(&setup), - setup_rmw(false, "ASO ", setup_asl_data())); + setup_rmw(false, "SLO ", setup_asl_data())); } // For RLA. @@ -1270,8 +1270,8 @@ auto setup_op_RLA() } -// For LSE. -auto setup_op_LSE() +// For SRE. +auto setup_op_SRE() { auto setup(ubyte opcode, CpuInfo cpu, Block[] data, OpInfo info, string msg, TestSetup* next) @@ -1284,7 +1284,7 @@ auto setup_op_LSE() callNext("acc 0xFF "); } return connect(TestSetup(&setup), - setup_rmw(false, "LSE ", setup_right_data())); + setup_rmw(false, "SRE ", setup_right_data())); } @@ -1382,8 +1382,8 @@ auto setup_op_SBC(bool cmos) } -// For INS. -auto setup_op_INS() +// For ISC. +auto setup_op_ISC() { auto setup(ubyte opcode, CpuInfo cpu, Block[] data, OpInfo info, string msg, TestSetup* next) @@ -1400,7 +1400,7 @@ auto setup_op_INS() } return connect(TestSetup(&setup), setup_flag(Flag.C), setup_flag(Flag.D), - setup_rmw(false, "INS ", setup_inc_data())); + setup_rmw(false, "ISC ", setup_inc_data())); } @@ -1427,8 +1427,8 @@ auto setup_op_cmp(Reg reg) } -// For DCM. -auto setup_op_DCM() +// For DCP. +auto setup_op_DCP() { auto setup(ubyte opcode, CpuInfo cpu, Block[] data, OpInfo info, string msg, TestSetup* next) @@ -1445,7 +1445,7 @@ auto setup_op_DCM() } return connect(TestSetup(&setup), setup_flag(Flag.C), - setup_rmw(false, "DCM ", setup_dec_data())); + setup_rmw(false, "DCP ", setup_dec_data())); } @@ -2105,8 +2105,8 @@ auto expect_LSR(bool isAcc) } -// For ASO. -auto expect_ASO() +// For SLO. +auto expect_SLO() { void expect(ref Expected expected, const OpInfo info) { @@ -2138,8 +2138,8 @@ auto expect_RLA() } -// For LSE. -auto expect_LSE() +// For SRE. +auto expect_SRE() { void expect(ref Expected expected, const OpInfo info) { @@ -2306,8 +2306,8 @@ auto expect_SBC(bool cmos) } -// For INS. -auto expect_INS() +// For ISC. +auto expect_ISC() { void expect(ref Expected expected, const OpInfo info) { @@ -2342,8 +2342,8 @@ auto expect_cmp(Reg reg) } -// For DCM. -auto expect_DCM() +// For DCP. +auto expect_DCP() { void expect(ref Expected expected, const OpInfo info) { @@ -2510,12 +2510,12 @@ if (isCpu!T) get_expect([0x04, 0x44, 0x64], "NOP"); get_expect([0x14, 0x34, 0x54, 0x74, 0xD4, 0xF4], "NOP"); get_both([0x83, 0x87, 0x8F, 0x97], "SAX"); - get_both([0x03, 0x07, 0x0F, 0x13, 0x17, 0x1B, 0x1F], "ASO"); + get_both([0x03, 0x07, 0x0F, 0x13, 0x17, 0x1B, 0x1F], "SLO"); get_both([0x23, 0x27, 0x2F, 0x33, 0x37, 0x3B, 0x3F], "RLA"); - get_both([0x43, 0x47, 0x4F, 0x53, 0x57, 0x5B, 0x5F], "LSE"); + get_both([0x43, 0x47, 0x4F, 0x53, 0x57, 0x5B, 0x5F], "SRE"); get_both([0x63, 0x67, 0x6F, 0x73, 0x77, 0x7B, 0x7F], "RRA"); - get_both([0xE3, 0xE7, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF], "INS"); - get_both([0xC3, 0xC7, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF], "DCM"); + get_both([0xE3, 0xE7, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF], "ISC"); + get_both([0xC3, 0xC7, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF], "DCP"); get_both([0xEB], "SBC", "false"); // TODO: implement these opcode tests From 41a12c284a72c64e7d16ac8d99f39ed1d5523a08 Mon Sep 17 00:00:00 2001 From: edmccard Date: Thu, 12 Apr 2012 03:15:21 -0400 Subject: [PATCH 17/27] Implement the rest of the undocumented opcodes. --- src/cpu/ctfe_d6502.d | 61 +++++++++++++++++++++++++++++++++++++++----- test/test_new_cpu.d | 27 +++----------------- 2 files changed, 59 insertions(+), 29 deletions(-) diff --git a/src/cpu/ctfe_d6502.d b/src/cpu/ctfe_d6502.d index ced851d..34a1f41 100644 --- a/src/cpu/ctfe_d6502.d +++ b/src/cpu/ctfe_d6502.d @@ -422,7 +422,7 @@ string OpBody(int op, string chip, bool s, bool c) if (op != 0xAB) ret ~= Load(_A ~ " = " ~ _X, env); else - return ""; + ret ~= LAX_IMM_Undoc(env); break; case "SAX": ret ~= Store(_A ~ " & " ~ _X, env); @@ -440,15 +440,20 @@ string OpBody(int op, string chip, bool s, bool c) ret ~= AXS_Undoc(env); break; case "AHX": - return ""; + ret ~= Strange_Undoc(_A ~ " &" ~ _X, env); + break; case "SHY": - return ""; + ret ~= Strange_Undoc(_Y, env); + break; case "SHX": - return ""; + ret ~= Strange_Undoc(_X, env); + break; case "TAS": - return ""; + ret ~= Strange_Undoc(_S ~ " = " ~ _A ~ " & " ~ _X, env); + break; case "XAA": - return ""; + ret ~= XAA_Undoc(env); + break; case "SLO": ret ~= RMW_Undoc(ShiftLeft("data"), SetNZ(_A ~ " |= data"), env); @@ -870,6 +875,50 @@ string AXS_Undoc(Env env) } +/* + * This opcode is unstable on certain machines; see + * http://visual6502.org/wiki/index.php?title=6502_Opcode_8B_(XAA,ANE) + */ +string XAA_Undoc(Env env) +{ + /* + * As far as I can tell, the only programs in the wild that depend + * on this opcode are certain C64 Mastertronic tape loaders; this + * magic value is used in the VICE emulator to make them work. + */ + string MAGIC = "0xff"; + + return ReadInto(Local("ubyte", "data"), "address", env) ~ + _A ~ " = ((" ~ _A ~ " | " ~ MAGIC ~ ") & " ~ _X ~ " & data);\n" ~ + SetNZ(_A); +} + + +/* + * This opcode is unstable on certain machines. + */ +string LAX_IMM_Undoc(Env env) +{ + // From the VICE emulator. + string MAGIC = "0xee"; + + return ReadInto(Local("ubyte", "data"), "address", env) ~ + _A ~ " = ((" ~ _A ~ " | " ~ MAGIC ~ ") & " ~ _X ~ " & data);\n" ~ + SetNZ(_A); +} + + +// TODO: these are affected by DMA on the C64. +string Strange_Undoc(string val, Env env) +{ + return "ubyte addrHi = cast(ubyte)((address >> 8) + 1);\n" ~ + Local("ubyte", "data") ~ " = " ~ val ~ " & addrHi;\n" ~ + "address = (guess == address) ? address : " ~ + "((data << 8) | (address & 0xff));\n" ~ + Write("address", "data", env); +} + + string Local(string type) { version(OpFunctions) diff --git a/test/test_new_cpu.d b/test/test_new_cpu.d index 7bfc9fa..876518e 100644 --- a/test/test_new_cpu.d +++ b/test/test_new_cpu.d @@ -39,27 +39,8 @@ void main() test_opcode_timing!TX2(op, report2); } - test_func([0x00, 0x08, 0x10, 0x18, 0x28, 0x30, 0x38, 0x50, 0x58, 0x68, - 0x70, 0x78, 0x90, 0xad, 0xb0, 0xb8, 0xd0, 0xd8, 0xf0, 0xf8, - 0xae, 0xac, 0x8d, 0x8e, 0x8c, 0xe8, 0xc8, 0xca, 0x88, 0xcd, - 0xec, 0xcc, 0x0d, 0x2d, 0x4d, 0xee, 0xce, 0x60, 0x6d, 0xed, - 0x4c, 0x09, 0x29, 0x49, 0x69, 0xe9, 0xc9, 0xe0, 0xc0, 0xa9, - 0xa2, 0xa0, 0x1d, 0x19, 0x3d, 0x39, 0x5d, 0x59, 0x7d, 0x79, - 0xfd, 0xf9, 0xdd, 0xd9, 0xde, 0xfe, 0xbd, 0xb9, 0x9d, 0x99, - 0xbe, 0xbc, 0x6c, 0x7c, 0xb2, 0x72, 0x32, 0xd2, 0x52, 0x12, - 0xf2, 0x92, 0xaa, 0x8a, 0xa8, 0x98, 0xba, 0x9a, 0x0a, 0x0e, - 0x1e, 0x48, 0x2c, 0x05, 0x25, 0x45, 0x65, 0xe5, 0xc5, 0xe4, - 0xc4, 0xc6, 0xe6, 0x06, 0x26, 0x46, 0x66, 0xa5, 0x85, 0xa6, - 0x86, 0xa4, 0x84, 0x24, 0x15, 0x35, 0x55, 0x75, 0xf5, 0xd5, - 0xd6, 0xf6, 0x16, 0x36, 0x56, 0x76, 0xb5, 0x95, 0xb6, 0x96, - 0xb4, 0x94, 0x01, 0x21, 0x41, 0x61, 0xe1, 0xc1, 0xa1, 0x81, - 0x11, 0x31, 0x51, 0x71, 0xf1, 0xd1, 0xb1, 0x91, 0xda, 0x5a, - 0x7a, 0xfa, 0x89, 0x34, 0x3c, 0x1a, 0x3a, 0x80, 0x64, 0x74, - 0x14, 0x1c, 0x04, 0x0c, 0x40, 0x03, 0x07, 0x0f, 0x13, 0x17, - 0x1b, 0x1f, 0x23, 0x27, 0x2f, 0x33, 0x37, 0x3b, 0x3f, 0x43, - 0x47, 0x4f, 0x53, 0x57, 0x5b, 0x5f, 0x5c, 0x63, 0x67, 0x6f, - 0x73, 0x77, 0x7b, 0x7f, 0xc3, 0xc7, 0xcf, 0xd3, 0xd7, 0xdb, - 0xdf, 0xe3, 0xe7, 0xe7, 0xf3, 0xf7, 0xfb, 0xff, 0xbb, 0x83, - 0x87, 0x8f, 0x97, 0xa3, 0xa7, 0xaf, 0xb3, 0xb7, 0xbf, 0x6b, - 0x0b, 0x2b, 0x4b, 0xeb, 0xcb]); + ubyte[256] ops; + foreach (x; 0..256) ops[x] = cast(ubyte)x; + + test_func(ops); } From 71f7a46e2116cd506991c16b3dda051dabcf5a5b Mon Sep 17 00:00:00 2001 From: edmccard Date: Thu, 12 Apr 2012 03:18:33 -0400 Subject: [PATCH 18/27] Fix bug with ROR acting as LSR --- src/cpu/ctfe_d6502.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu/ctfe_d6502.d b/src/cpu/ctfe_d6502.d index 34a1f41..6e406b5 100644 --- a/src/cpu/ctfe_d6502.d +++ b/src/cpu/ctfe_d6502.d @@ -405,7 +405,7 @@ string OpBody(int op, string chip, bool s, bool c) break; case "ROR": if (op == 0x6a) - ret ~= ShiftRight(_A); + ret ~= RotateRight(_A); else ret ~= RMW(RotateRight("data"), env); break; From ed8dc37bb49992a4c09a6927afafdb9e64a38093 Mon Sep 17 00:00:00 2001 From: edmccard Date: Thu, 12 Apr 2012 18:42:55 -0400 Subject: [PATCH 19/27] Improve test runner. --- README.md | 9 +++ test/base.d | 71 +++++++++++++++++++++- test/runtests.d | 142 +++++++++++++++++++++++++++++++++++++++++++ test/test_bus.d | 39 +++--------- test/test_cpu_all.sh | 4 -- test/test_decimal.d | 23 ++----- test/test_func.d | 15 +++-- 7 files changed, 245 insertions(+), 58 deletions(-) create mode 100644 test/runtests.d delete mode 100755 test/test_cpu_all.sh diff --git a/README.md b/README.md index 934ce3a..3eba05b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,15 @@ Build by running `make` in the `src` directory; if the dependencies aren't insta make GTKD=/path/to/gtkd DERELICT=/path/to/Derelict2 ``` +### Testing + +There are tests for the 6502/65C02 emulation: + +``` +cd test +rdmd runtests.d --help +``` + ### Use For now, see README.orig diff --git a/test/base.d b/test/base.d index 5b8b650..34e6576 100644 --- a/test/base.d +++ b/test/base.d @@ -1,10 +1,11 @@ module test.base; -import std.algorithm, std.array, std.conv, std.exception, std.stdio, - std.string; +import std.algorithm, std.array, std.conv, std.exception, std.getopt, + std.stdio, std.string; import test.cpu, test.opcodes; +import cpu.data_d6502; /* @@ -3334,3 +3335,69 @@ void test_opcode_timing(T)(ubyte opcode, busreport report) auto run = connect(setup, run_timing_test!T(expected, report)); run.run(opcode); } + + +version(Strict) + enum testStrict = true; +else + enum testStrict = false; +version(Cumulative) + enum testCumulative = true; +else + enum testCumulative = false; + + +struct CheckOptions +{ + enum Addr + { + IMP, IMM, ZP, ZPX, ZPY, IZX, IZY, ABS, ABX, ABY, IND, REL, + ZPI, ABI, NP1, NP8, KIL + } + + string[] opcodes; + ubyte[] codes6502; + ubyte[] codes65C02; + Addr[] addr; + + this(string[] args) + { + getopt(args, "op", &opcodes, "addr", &addr); + foreach (op; opcodes) + { + if (op.startsWith("0x") || op.startsWith("0X")) + op = op[2..$]; + if (isNumeric(op)) + { + int code = to!int(op, 16); + if (code >= 0x00 && code <= 0xFF) + { + codes6502 ~= [cast(ubyte)code]; + codes65C02 ~= [cast(ubyte)code]; + } + } + else + { + foreach (code, name; OP_NAMES_6502) + if (name == op) codes6502 ~= [cast(ubyte)code]; + foreach (code, name; OP_NAMES_65C02) + if (name == op) codes65C02 ~= [cast(ubyte)code]; + } + } + foreach (a; addr) + { + foreach (code, mode; ADDR_MODES_6502) + if (a == mode) codes6502 ~= [cast(ubyte)code]; + foreach (code, mode; ADDR_MODES_65C02) + if (a == mode) codes65C02 ~= [cast(ubyte)code]; + } + if (opcodes.empty && addr.empty) + { + codes6502 = codes65C02 = new ubyte[256]; + foreach (code; 0..256) + { + codes6502[code] = cast(ubyte)code; + } + } + } +} diff --git a/test/runtests.d b/test/runtests.d new file mode 100644 index 0000000..7dbb6aa --- /dev/null +++ b/test/runtests.d @@ -0,0 +1,142 @@ +import std.array, std.exception, std.getopt, std.process, std.stdio, + std.traits; + + +enum OpDefs +{ + None, + Delegates = 1, + Functions = 2, + Switch = 4, + NestedSwitch = 8, + All = 15 +} + +enum Tests +{ + None, + Func = 1, + Bus = 2, + Dec = 4, + All = 7 +} + +string[OpDefs] defStrings; +string[Tests] fNames; + +static this() +{ + fNames = [ + Tests.Func:" test_func.d ", + Tests.Bus:" test_bus.d ", + Tests.Dec:" test_decimal.d " + ]; +} + +version(DigitalMars) +{ + static this() + { + defStrings = [ + OpDefs.Delegates:" -version=OpDelegates", + OpDefs.Functions:" -version=OpFunctions", + OpDefs.Switch:" -version=OpSwitch", + OpDefs.NestedSwitch:" -version=OpNestedSwitch" + ]; + } + string[] stStrings = [" ", " -version=Strict"]; + string[] cmStrings = [" ", " -version=Cumulative"]; +} +else version(GNU) +{ + static assert(false, "TODO: add support for GDC."); +} +else version(LDC) +{ + static assert(false, "TODO: add support for LDC."); +} +else + static assert(false, "Unknown compiler."); + + +OpDefs opdefs; +bool strict, cumulative; +Tests tests; +bool help; + +OpDefs[] deflist; +Tests[] testlist; + +void main(string[] args) +{ + if (args.length == 1) + writeln("(running default tests; use --help for options)"); + + getopt(args, + std.getopt.config.passThrough, + "def", &deflist, + "test", &testlist, + "help", &help); + + if (help) + { + writeln( +`Options: + --test=type Func, Bus, Dec, or All + --def=style Delegates, Functions, Switch, or NestedSwitch + --op=num test opcode 'num' (num is hex) + --op=name test all opcodes named 'name' + --addr=mode test all opcodes with addressing mode 'mode' + +(All options con be specified multiple times. +--op and --addr have no effect on decimal mode tests.)` + ); + return; + } + + foreach(def; deflist) opdefs |= def; + foreach(test; testlist) tests |= test; + + try + { + runTests(args); + } + catch (ErrnoException e) {} +} + +void runTests(string[] args) +{ + // If no opdef specified, use Delegates. + if (opdefs == OpDefs.None) opdefs = OpDefs.Delegates; + + int defcount; + foreach (def; EnumMembers!OpDefs) + if ((opdefs & def) && def != OpDefs.All) defcount++; + + // If no tests specified, run all (but exclude Dec by default if + // running with more than one opdef). + if (tests == Tests.None) + tests = Tests.Func | Tests.Bus; + if (!defcount) tests |= Tests.Dec; + + foreach (def; EnumMembers!OpDefs) + if ((opdefs & def) && def != OpDefs.All) + foreach (test; EnumMembers!Tests) + if ((tests & test) && test != Tests.All) + runTest(def, test, args[1..$]); +} + +void runTest(OpDefs def, Tests test, string[] args) +{ + writeln("Using ", defStrings[def]); + foreach (s; [false, true]) + { + foreach (c; [false, true]) + { + writeln("With strict=", s, " cumulative=", c); + string cmdline = defStrings[def] ~ stStrings[s] ~ cmStrings[c] ~ + fNames[test] ~ join(args, " "); + system("rdmd --force -I.. -I../src " ~ cmdline); + } + } +} diff --git a/test/test_bus.d b/test/test_bus.d index 909acb9..f49aedc 100644 --- a/test/test_bus.d +++ b/test/test_bus.d @@ -1,42 +1,23 @@ module test.test_bus; +import std.stdio; + import test.base, test.cpu; -void main() +void main(string[] args) { + auto opts = CheckOptions(args); auto report = report_timing_debug(); - alias CPU!("65C02", false, false) T1; - for (int op = 0x00; op < 0x100; op++) + alias CPU!("6502", testStrict, testCumulative) T1; + writeln("Testing bus/timing, 6502"); + foreach (op; opts.codes6502) test_opcode_timing!T1(cast(ubyte)op, report); - alias CPU!("65C02", true, false) T2; - for (int op = 0x00; op < 0x100; op++) + alias CPU!("65C02", testStrict, testCumulative) T2; + writeln("Testing bus/timing, 65C02"); + foreach (op; opts.codes65C02) test_opcode_timing!T2(cast(ubyte)op, report); - - alias CPU!("6502", false, false) T3; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T3(cast(ubyte)op, report); - - alias CPU!("6502", true, false) T4; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T4(cast(ubyte)op, report); - - alias CPU!("65C02", false, true) T5; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T5(cast(ubyte)op, report); - - alias CPU!("65C02", true, true) T6; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T6(cast(ubyte)op, report); - - alias CPU!("6502", false, true) T7; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T7(cast(ubyte)op, report); - - alias CPU!("6502", true, true) T8; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T8(cast(ubyte)op, report); } diff --git a/test/test_cpu_all.sh b/test/test_cpu_all.sh deleted file mode 100755 index b3a11df..0000000 --- a/test/test_cpu_all.sh +++ /dev/null @@ -1,4 +0,0 @@ -rdmd @testopts test_func.d -rdmd @testopts test_bus.d -rdmd @testopts test_decimal.d - diff --git a/test/test_decimal.d b/test/test_decimal.d index 731c187..322f8f3 100644 --- a/test/test_decimal.d +++ b/test/test_decimal.d @@ -228,6 +228,7 @@ if (isCpu!T) version(Benchmark) { + static assert(!testStrict && !testCumulative); import std.datetime, std.stdio; void f0() { @@ -246,24 +247,10 @@ else { void main() { - writeln("Testing decimal mode, NMOS(Strict.no, Cumulative.no)"); - testDecimalMode!(CPU!("6502", false, false))(); - writeln("Testing decimal mode, CMOS(Strict.no, Cumulative.no)"); - testDecimalMode!(CPU!("65C02", false, false))(); + writeln("Testing decimal mode, 6502"); + testDecimalMode!(CPU!("6502", testStrict, testCumulative))(); - writeln("Testing decimal mode, NMOS(Strict.no, Cumulative.yes)"); - testDecimalMode!(CPU!("6502", false, true))(); - writeln("Testing decimal mode, CMOS(Strict.no, Cumulative.yes)"); - testDecimalMode!(CPU!("65C02", false, true))(); - - writeln("Testing decimal mode, NMOS(Strict.yes, Cumulative.no)"); - testDecimalMode!(CPU!("6502", true, false))(); - writeln("Testing decimal mode, CMOS(Strict.yes, Cumulative.no)"); - testDecimalMode!(CPU!("65C02", true, false))(); - - writeln("Testing decimal mode, NMOS(Strict.yes, Cumulative.yes)"); - testDecimalMode!(CPU!("6502", true, true))(); - writeln("Testing decimal mode, CMOS(Strict.yes, Cumulative.yes)"); - testDecimalMode!(CPU!("65C02", true, true))(); + writeln("Testing decimal mode, 65C02"); + testDecimalMode!(CPU!("65C02", testStrict, testCumulative))(); } } diff --git a/test/test_func.d b/test/test_func.d index 8bb8fb6..1a39316 100644 --- a/test/test_func.d +++ b/test/test_func.d @@ -1,18 +1,23 @@ module test.test_func; +import std.stdio; + import test.base, test.cpu; -void main() +void main(string[] args) { + auto opts = CheckOptions(args); auto report = report_debug(); - alias CPU!("65C02", false, false) T1; - foreach (opcode; 0..255) + alias CPU!("6502", testStrict, testCumulative) T1; + writeln("Testing functionality, 6502"); + foreach (opcode; opts.codes6502) test_one_opcode!T1(cast(ubyte)opcode, report); - alias CPU!("6502", false, false) T2; - foreach (opcode; 0..255) + alias CPU!("65C02", testStrict, testCumulative) T2; + writeln("Testing functionality, 65C02"); + foreach (opcode; opts.codes65C02) test_one_opcode!T2(cast(ubyte)opcode, report); } From 76cfb27a7b1288da26f703ab0c532a5734ba0d20 Mon Sep 17 00:00:00 2001 From: edmccard Date: Fri, 13 Apr 2012 04:29:05 -0400 Subject: [PATCH 20/27] Compile all files at once. --- src/Makefile | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Makefile b/src/Makefile index 7136c8f..e8b8661 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,19 +1,16 @@ -COMPILE_OPTS = -c -op -Jdata -I$(GTKD)/src \ - -I$(GTKD)/srcgl -I$(DERELICT)/import +COMPILE_OPTS = -op -Jdata -I$(GTKD)/src \ + -I$(GTKD)/srcgl -I$(DERELICT)/import \ + -inline -release -O -noboundscheck LINK_OPTS = -L-lpthread -L-lGL -L-ldl -L-lX11 \ - -L-L$(GTKD) -L-lgtkd -L-lgtkdgl \ - -L-L$(DERELICT)/lib -L-lDerelictSDL -L-lDerelictUtil \ + -L-L$(GTKD) -L-lgtkd -L-lgtkdgl \ + -L-L$(DERELICT)/lib -L-lDerelictSDL -L-lDerelictUtil ALL_SRC = $(shell find -name "*.d" \! -path "./cpu/*") -ALL_OBJS = $(ALL_SRC:%.d=%.o) -all: ${ALL_OBJS} - dmd ${ALL_OBJS} -oftwoapple ${LINK_OPTS} +all: ${ALL_SRC} + dmd $(COMPILE_OPTS) ${ALL_SRC} -oftwoapple ${LINK_OPTS} clean: - rm -rf twoapple ${ALL_OBJS} - -%.o: %.d - dmd $(DFLAGS) -inline -release -O $(COMPILE_OPTS) $< + rm -rf twoapple twoapple.o From d12f793d9adf81c86f11146b51258a7a54eb5ff7 Mon Sep 17 00:00:00 2001 From: edmccard Date: Fri, 13 Apr 2012 07:03:22 -0400 Subject: [PATCH 21/27] Strict and cumulative modes are now set by version, instead of template parameters. --- src/cpu/ctfe_d6502.d | 643 +++++++++++++++++++++---------------------- src/cpu/d6502.d | 40 +-- test/base.d | 58 ++-- test/cpu.d | 34 +-- test/test_bus.d | 4 +- test/test_decimal.d | 7 +- test/test_func.d | 4 +- 7 files changed, 376 insertions(+), 414 deletions(-) diff --git a/src/cpu/ctfe_d6502.d b/src/cpu/ctfe_d6502.d index 6e406b5..4aa4918 100644 --- a/src/cpu/ctfe_d6502.d +++ b/src/cpu/ctfe_d6502.d @@ -4,6 +4,16 @@ module cpu.ctfe_d6502; import cpu.data_d6502; +version(Strict) + private enum strict = true; +else + private enum strict = false; +version(Cumulative) + private enum cumulative = true; +else + private enum cumulative = false; + + // The following versions are mutually exclusive. // OpDelegates: each opcode is a method of the Cpu class. @@ -18,17 +28,6 @@ version(OpFunctions) { enum versionCheck = 2; enum opArray = true; - - // With free functions, strict and cumulative need to be set by - // version. - version(Strict) - enum vStrict = true; - else - enum vStrict = false; - version(Cumulative) - enum vCumulative = true; - else - enum vCumulative = false; } // OpSwitch: each opcode is inlined in a 256-case switch. @@ -85,7 +84,7 @@ string OpArrayInit() } } -string OpBodies(string chip, bool strict, bool cumulative) +string OpBodies(string chip) { static if (!opArray) return ""; else @@ -96,12 +95,12 @@ string OpBodies(string chip, bool strict, bool cumulative) version(OpDelegates) ret ~= "final void opcode_" ~ Hex2(op) ~ "()\n{\n" ~ If!(cumulative)("int cycles = 1;\n") ~ - OpBody(op, chip, strict, cumulative) ~ "}\n"; + OpBody(op, chip) ~ "}\n"; version(OpFunctions) ret ~= "void opcode_" ~ Hex2(op) ~ "(T)(T cpu) if (is" ~ chip ~ "!T)\n{\n" ~ If!(cumulative)("int cycles = 1;\n") ~ - OpBody(op, chip, strict, cumulative) ~ "}\n"; + OpBody(op, chip) ~ "}\n"; } /+ foreach (op; 13..256) @@ -119,28 +118,28 @@ string OpBodies(string chip, bool strict, bool cumulative) } } -string OpExecute(string chip, bool strict, bool cumulative) +string OpExecute(string chip) { version(OpDelegates) return q{opcodes[opcode]();}; version(OpFunctions) return q{opcodes[opcode](this);}; version(OpSwitch) - return Switch256(chip, strict, cumulative); + return Switch256(chip); version(OpNestedSwitch) - return Switch16x16(chip, strict, cumulative); + return Switch16x16(chip); } -string Switch256(string chip, bool strict, bool cumulative) +string Switch256(string chip) { string ret = "final switch (opcode)\n{\n"; foreach (op; 0..256) ret ~= "case 0x" ~ Hex2(op) ~ ":\n" ~ - OpBody(op, chip, strict, cumulative) ~ "break;\n"; + OpBody(op, chip) ~ "break;\n"; return ret ~ "}\n"; } -string Switch16x16(string chip, bool strict, bool cumulative) +string Switch16x16(string chip) { string ret = "final switch (opcode & 0xF0)\n{\n"; foreach (opHi; 0..16) @@ -151,7 +150,7 @@ string Switch16x16(string chip, bool strict, bool cumulative) { int op = opLo | (opHi << 4); ret ~= "case 0x0" ~ Hex1(opLo) ~ ":\n" ~ - OpBody(op, chip, strict, cumulative) ~ + OpBody(op, chip) ~ "break;\n"; } ret ~= "}\nbreak;\n"; @@ -173,79 +172,59 @@ enum _C = Attr("C"); enum _S = Attr("S"); enum STACK = "0x0100 + " ~ _S; -struct Env -{ - int op; - string chip; - bool s, c; - bool nmos, cmos; - int mode; - int exCyc; - this(int op, string chip, bool s, bool c) - { - this.op = op; - this.chip = chip; - this.s = s; - this.c = c; - nmos = (chip == "6502"); - cmos = !nmos; - mode = opMode(op, chip); - exCyc = opExCyc(op, chip); - } -} - -string OpBody(int op, string chip, bool s, bool c) +string OpBody(int op, string chip) { - auto env = Env(op, chip, s, c); - string ret = ((op == 0x20) ? "" : Address(env)); + auto mode = opMode(op, chip); + auto exCyc = opExCyc(op, chip); + string ret = ((op == 0x20) ? "" : Address(mode, exCyc, chip)); final switch (opName(op, chip)) { case "BRK": - ret ~= Break(env); + ret ~= Break(); break; case "RTI": - ret ~= RetInt(env); + ret ~= RetInt(); break; case "JSR": - ret ~= JumpSub(env); + ret ~= JumpSub(); break; case "RTS": - ret ~= RetSub(env); + ret ~= RetSub(); break; case "JMP": - ret ~= Jump(env); + ret ~= Jump(op, chip); break; case "KIL": ret ~= _PC ~ "--;\n"; break; case "BPL": - ret ~= Branch("!(" ~ _N ~ " & 0x80)", env); + ret ~= Branch("!(" ~ _N ~ " & 0x80)", chip); break; case "BMI": - ret ~= Branch("(" ~ _N ~ " & 0x80)", env); + ret ~= Branch("(" ~ _N ~ " & 0x80)", chip); break; case "BVC": - ret ~= Branch("!" ~ _V, env); + ret ~= Branch("!" ~ _V, chip); break; case "BVS": - ret ~= Branch(_V, env); + ret ~= Branch(_V, chip); break; case "BRA": - ret ~= Branch("true", env); + ret ~= Branch("true", chip); break; case "BCC": - ret ~= Branch("!" ~ _C, env); + ret ~= Branch("!" ~ _C, chip); break; case "BCS": - ret ~= Branch(_C, env); + ret ~= Branch(_C, chip); break; case "BNE": - ret ~= Branch(_Z, env); + ret ~= Branch(_Z, chip); break; case "BEQ": - ret ~= Branch("!" ~ _Z, env); + ret ~= Branch("!" ~ _Z, chip); break; case "CLC": ret ~= ClearFlag(_C); @@ -269,25 +248,25 @@ string OpBody(int op, string chip, bool s, bool c) ret ~= SetFlag(_D); break; case "NOP": - ret ~= Nop(env); + ret ~= Nop(mode); break; case "TAX": - ret ~= Transfer(_A, _X, env); + ret ~= Transfer(_A, _X); break; case "TXA": - ret ~= Transfer(_X, _A, env); + ret ~= Transfer(_X, _A); break; case "TAY": - ret ~= Transfer(_A, _Y, env); + ret ~= Transfer(_A, _Y); break; case "TYA": - ret ~= Transfer(_Y, _A, env); + ret ~= Transfer(_Y, _A); break; case "TSX": - ret ~= Transfer(_S, _X, env); + ret ~= Transfer(_S, _X); break; case "TXS": - ret ~= Transfer(_X, _S, env); + ret ~= Transfer(_X, _S, false); break; case "DEX": ret ~= Dec(_X); @@ -302,318 +281,318 @@ string OpBody(int op, string chip, bool s, bool c) ret ~= Inc(_Y); break; case "PHP": - ret ~= Push(Attr("statusToByte()"), env); + ret ~= Push(Attr("statusToByte()")); break; case "PLP": - ret ~= PullStatus(env); + ret ~= PullStatus(); break; case "PLA": - ret ~= PullReg(_A, env); + ret ~= PullReg(_A); break; case "PLX": - ret ~= PullReg(_X, env); + ret ~= PullReg(_X); break; case "PLY": - ret ~= PullReg(_Y, env); + ret ~= PullReg(_Y); break; case "PHA": - ret ~= PushReg(_A, env); + ret ~= PushReg(_A); break; case "PHX": - ret ~= PushReg(_X, env); + ret ~= PushReg(_X); break; case "PHY": - ret ~= PushReg(_Y, env); + ret ~= PushReg(_Y); break; case "LDA": - ret ~= Load(_A, env); + ret ~= Load(_A); break; case "LDX": - ret ~= Load(_X, env); + ret ~= Load(_X); break; case "LDY": - ret ~= Load(_Y, env); + ret ~= Load(_Y); break; case "STA": - ret ~= Store(_A, env); + ret ~= Store(_A); break; case "STX": - ret ~= Store(_X, env); + ret ~= Store(_X); break; case "STY": - ret ~= Store(_Y, env); + ret ~= Store(_Y); break; case "STZ": - ret ~= Store("0", env); + ret ~= Store("0"); break; case "CMP": - ret ~= Compare(_A, env); + ret ~= Compare(_A); break; case "CPX": - ret ~= Compare(_X, env); + ret ~= Compare(_X); break; case "CPY": - ret ~= Compare(_Y, env); + ret ~= Compare(_Y); break; case "BIT": - ret ~= Bit(env); + ret ~= Bit(mode); break; case "ORA": - ret ~= Logic("|=", env); + ret ~= Logic("|="); break; case "AND": - ret ~= Logic("&=", env); + ret ~= Logic("&="); break; case "EOR": - ret ~= Logic("^=", env); + ret ~= Logic("^="); break; case "ADC": - ret ~= Add(env); + ret ~= Add(chip); break; case "SBC": - ret ~= Sub(env); + ret ~= Sub(chip); break; case "INC": if (op == 0x1a) ret ~= Inc(_A); else - ret ~= RMW(Inc("data"), env); + ret ~= RMW(Inc("data"), chip); break; case "DEC": if (op == 0x3a) ret ~= Dec(_A); else - ret ~= RMW(Dec("data"), env); + ret ~= RMW(Dec("data"), chip); break; case "ASL": if (op == 0x0a) ret ~= ShiftLeft(_A); else - ret ~= RMW(ShiftLeft("data"), env); + ret ~= RMW(ShiftLeft("data"), chip); break; case "ROL": if (op == 0x2a) ret ~= RotateLeft(_A); else - ret ~= RMW(RotateLeft("data"), env); + ret ~= RMW(RotateLeft("data"), chip); break; case "LSR": if (op == 0x4a) ret ~= ShiftRight(_A); else - ret ~= RMW(ShiftRight("data"), env); + ret ~= RMW(ShiftRight("data"), chip); break; case "ROR": if (op == 0x6a) ret ~= RotateRight(_A); else - ret ~= RMW(RotateRight("data"), env); + ret ~= RMW(RotateRight("data"), chip); break; case "TRB": - ret ~= RMW(TestReset(), env); + ret ~= RMW(TestReset(), chip); break; case "TSB": - ret ~= RMW(TestSet(), env); + ret ~= RMW(TestSet(), chip); break; case "LAS": - ret ~= LAS_Undoc(env); + ret ~= LAS_Undoc(); break; case "LAX": if (op != 0xAB) - ret ~= Load(_A ~ " = " ~ _X, env); + ret ~= Load(_A ~ " = " ~ _X); else - ret ~= LAX_IMM_Undoc(env); + ret ~= LAX_IMM_Undoc(); break; case "SAX": - ret ~= Store(_A ~ " & " ~ _X, env); + ret ~= Store(_A ~ " & " ~ _X); break; case "ANC": - ret ~= ANC_Undoc(env); + ret ~= ANC_Undoc(); break; case "ALR": - ret ~= ALR_Undoc(env); + ret ~= ALR_Undoc(); break; case "ARR": - ret ~= ARR_Undoc(env); + ret ~= ARR_Undoc(); break; case "AXS": - ret ~= AXS_Undoc(env); + ret ~= AXS_Undoc(); break; case "AHX": - ret ~= Strange_Undoc(_A ~ " &" ~ _X, env); + ret ~= Strange_Undoc(_A ~ " &" ~ _X); break; case "SHY": - ret ~= Strange_Undoc(_Y, env); + ret ~= Strange_Undoc(_Y); break; case "SHX": - ret ~= Strange_Undoc(_X, env); + ret ~= Strange_Undoc(_X); break; case "TAS": - ret ~= Strange_Undoc(_S ~ " = " ~ _A ~ " & " ~ _X, env); + ret ~= Strange_Undoc(_S ~ " = " ~ _A ~ " & " ~ _X); break; case "XAA": - ret ~= XAA_Undoc(env); + ret ~= XAA_Undoc(); break; case "SLO": ret ~= RMW_Undoc(ShiftLeft("data"), - SetNZ(_A ~ " |= data"), env); + SetNZ(_A ~ " |= data")); break; case "RLA": ret ~= RMW_Undoc(RotateLeft("data"), - SetNZ(_A ~ " &= data"), env); + SetNZ(_A ~ " &= data")); break; case "SRE": ret ~= RMW_Undoc(ShiftRight("data"), - SetNZ(_A ~ " ^= data"), env); + SetNZ(_A ~ " ^= data")); break; case "RRA": - ret ~= RMW_Undoc(RotateRight("data"), AddBase(env), env); + ret ~= RMW_Undoc(RotateRight("data"), AddBase(chip)); break; case "DCP": - ret ~= RMW_Undoc(Dec("data"), CompareBase(_A, env), env); + ret ~= RMW_Undoc(Dec("data"), CompareBase(_A)); break; case "ISC": - ret ~= RMW_Undoc(Inc("data"), SubBase(env), env); + ret ~= RMW_Undoc(Inc("data"), SubBase(chip)); break; } - return ret ~ Done(env); + return ret ~ Done(); } -string Break(Env env) +string Break() { return IncPC() ~ - PushPC(env) ~ - Push(Attr("statusToByte()"), env) ~ + PushPC() ~ + Push(Attr("statusToByte()")) ~ SetFlag(_I) ~ - ReadWord(_PC, "IRQ_VECTOR", env); + ReadWord(_PC, "IRQ_VECTOR"); } -string JumpSub(Env env) +string JumpSub() { - return ReadOp(Local("ushort", "address"), env) ~ - Peek(STACK, env) ~ - PushPC(env) ~ - LoadHiByte("address", _PC ~ "++", env) ~ + return ReadOp(Local("ushort", "address")) ~ + Peek(STACK) ~ + PushPC() ~ + LoadHiByte("address", _PC ~ "++") ~ _PC ~ " = address;\n"; } -string RetSub(Env env) +string RetSub() { - return Peek(STACK, env) ~ - PullPC(env) ~ - Peek(_PC, env) ~ + return Peek(STACK) ~ + PullPC() ~ + Peek(_PC) ~ IncPC(); } -string RetInt(Env env) +string RetInt() { - return PullStatus(env) ~ - PullPC(env); + return PullStatus() ~ + PullPC(); } -string Jump(Env env) +string Jump(int op, string chip) { - bool cmos = env.cmos; - bool nmos = env.nmos; + bool nmos = (chip == "6502"); + bool cmos = !nmos; - if (env.op == 0x4c) + if (op == 0x4c) return _PC ~ " = address;\n"; - else if (env.op == 0x6c) - return ReadWordOp("ushort", "base", env) ~ + else if (op == 0x6c) + return ReadWordOp("ushort", "base") ~ If!(cmos)( - Peek(_PC, env)) ~ + Peek(_PC)) ~ ReadWordBasic(_PC, "base", If!(nmos)( "(base & 0xFF00) | cast(ubyte)(base + 1)", - "cast(ushort)(base + 1)"), env); - else if (env.op == 0x7c) - return ReadWordOp("ushort", "base", env) ~ - Peek(_PC, env) ~ - ReadWord(_PC, "cast(ushort)(base + " ~ _X ~ ")", env); + "cast(ushort)(base + 1)")); + else if (op == 0x7c) + return ReadWordOp("ushort", "base") ~ + Peek(_PC) ~ + ReadWord(_PC, "cast(ushort)(base + " ~ _X ~ ")"); return ""; } -string Branch(string check, Env env) +string Branch(string check, string chip) { - return ReadOp(Local("ushort", "base"), env) ~ + return ReadOp(Local("ushort", "base")) ~ "if (" ~ check ~ ")\n{\n" ~ - Peek(_PC, env) ~ + Peek(_PC) ~ Local("ushort", "address") ~ " = cast(ushort)(" ~ _PC ~ " + cast(byte)base);\n" ~ - CheckShortcut(_PC, "address", env) ~ + CheckShortcut(_PC, "address", chip, 0) ~ _PC ~ " = address;\n" ~ "}\n"; } -string Nop(Env env) +string Nop(int mode) { - if (env.mode == IMP || env.mode == NP1 || env.mode == NP8) - return ""; // XXX add np1/np8 stuff + if (mode == IMP || mode == NP1 || mode == NP8) + return ""; else - return PreAccess(env) ~ + return PreAccess() ~ ReadRaw("address") ~ ";\n"; } -string Transfer(string source, string dest, Env env) +string Transfer(string source, string dest, bool setNZ = true) { return dest ~ " = " ~ source ~ ";\n" ~ - ((env.op != 0x9a) ? SetNZ(dest) : ""); + (setNZ ? SetNZ(dest) : ""); } -string PullReg(string reg, Env env) +string PullReg(string reg) { - return Peek(STACK, env) ~ - PullInto(reg, env) ~ + return Peek(STACK) ~ + PullInto(reg) ~ SetNZ(reg); } -string PushReg(string reg, Env env) +string PushReg(string reg) { - return Push(reg, env); + return Push(reg); } -string Load(string reg, Env env) +string Load(string reg) { - return ReadInto(reg, "address", env) ~ + return ReadInto(reg, "address") ~ SetNZ(reg); } -string Store(string reg, Env env) +string Store(string reg,) { - return Write("address", reg, env); + return Write("address", reg); } -string Compare(string reg, Env env) +string Compare(string reg) { - return ReadInto(Local("ubyte", "data"), "address", env) ~ - CompareBase(reg, env); + return ReadInto(Local("ubyte", "data"), "address") ~ + CompareBase(reg); } -string CompareBase(string reg, Env env) +string CompareBase(string reg) { return UpdateFlag(_C, reg ~ " >= data") ~ SetNZ("cast(ubyte)(" ~ reg ~ " - data)"); } -string Bit(Env env) +string Bit(int mode) { - bool notImm = (env.mode != IMM); + bool notImm = (mode != IMM); - return ReadInto(Local("ubyte", "data"), "address", env) ~ + return ReadInto(Local("ubyte", "data"), "address") ~ If!(notImm)( _N ~ " = data;\n" ~ _V ~ " = ((data & 0x40) != 0);\n") ~ @@ -621,29 +600,29 @@ string Bit(Env env) } -string Logic(string action, Env env) +string Logic(string action) { - return ReadInto(_A, action, "address", env) ~ + return ReadInto(_A, action, "address") ~ SetNZ(_A); } -string Add(Env env) +string Add(string chip) { - return ReadInto(Local("ubyte", "data"), "address", env) ~ - AddBase(env); + return ReadInto(Local("ubyte", "data"), "address") ~ + AddBase(chip); } -string AddBase(Env env) +string AddBase(string chip) { return "if (" ~ _D ~ ")\n{\n" ~ - DecAdd(env) ~ + DecAdd(chip) ~ "}\nelse\n{\n" ~ - HexAdd(env) ~ + HexAdd() ~ "}\n"; } -string HexAdd(Env env) +string HexAdd() { return "uint sum = " ~ _A ~ " + data + " ~ _C ~ ";\n" ~ _V ~ @@ -652,9 +631,9 @@ string HexAdd(Env env) SetNZ(_A ~ " = cast(ubyte)sum"); } -string DecAdd(Env env) +string DecAdd(string chip) { - bool cmos = env.cmos; + bool cmos = (chip != "6502"); return "int a = " ~ _A ~ ";\n" ~ "int al = (a & 0x0F) + (data & 0x0F) + " ~ _C ~ ";\n" ~ @@ -670,23 +649,23 @@ string DecAdd(Env env) "a = a + 0x60;\n" ~ _C ~ " = (a >= 0x100);\n" ~ If!(cmos)( - SetNZ(_A ~ " = cast(ubyte)a") ~ Peek(_PC, env), + SetNZ(_A ~ " = cast(ubyte)a") ~ Peek(_PC), _A ~ " = cast(ubyte)a;\n"); } -string Sub(Env env) +string Sub(string chip) { - return ReadInto(Local("ubyte", "data"), "address", env) ~ - SubBase(env); + return ReadInto(Local("ubyte", "data"), "address") ~ + SubBase(chip); } -string SubBase(Env env) +string SubBase(string chip) { - bool nmos = env.nmos; + bool nmos = (chip == "6502"); return "if (" ~ _D ~ ")\n{\n" ~ - If!(nmos)(DecSubNMOS(), DecSubCMOS(env)) ~ + If!(nmos)(DecSubNMOS(), DecSubCMOS()) ~ "}\nelse\n{\n" ~ HexSub() ~ "}\n"; @@ -720,7 +699,7 @@ string DecSubNMOS() _A ~ " = cast(ubyte)a;\n"; } -string DecSubCMOS(Env env) +string DecSubCMOS() { return "int a = " ~ _A ~ ";\n" ~ "int al = (a & 0x0F) - (data & 0x0F) - !" ~ _C ~ ";\n" ~ @@ -732,7 +711,7 @@ string DecSubCMOS(Env env) " = ((" ~ _A ~ " ^ diff) & 0x80) && ((" ~ _A ~ " ^ data) & 0x80);\n" ~ _C ~ " = (diff < 0x100);\n" ~ - Peek(_PC, env) ~ + Peek(_PC) ~ SetNZ(_A ~ " = cast(ubyte)a"); } @@ -795,38 +774,38 @@ string TestSet() } -string RMW(string action, Env env) +string RMW(string action, string chip) { - bool nmos = env.nmos; + bool nmos = (chip == "6502"); - return ReadInto(Local("ubyte", "data"), "address", env) ~ - If!(nmos)(Poke("address", "data", env), - Peek("address", env)) ~ + return ReadInto(Local("ubyte", "data"), "address") ~ + If!(nmos)(Poke("address", "data"), + Peek("address")) ~ action ~ - Write("address", "data", env); + Write("address", "data"); } -string RMW_Undoc(string action1, string action2, Env env) +string RMW_Undoc(string action1, string action2) { - return ReadInto(Local("ubyte", "data"), "address", env) ~ - Poke("address", "data", env) ~ + return ReadInto(Local("ubyte", "data"), "address") ~ + Poke("address", "data") ~ action1 ~ - Write("address", "data", env) ~ + Write("address", "data") ~ action2; } -string LAS_Undoc(Env env) +string LAS_Undoc() { - return ReadInto(Local("ubyte", "data"), "address", env) ~ + return ReadInto(Local("ubyte", "data"), "address") ~ SetNZ(_X ~ " = " ~ _A ~ " = (" ~ _S ~ " & data)"); } -string ARR_Undoc(Env env) +string ARR_Undoc() { - return ReadInto(Local("ubyte", "data"), "address", env) ~ + return ReadInto(Local("ubyte", "data"), "address") ~ "ubyte tmp1 = data & " ~ _A ~ ";\n" ~ "if (" ~ _D ~ ")\n{\n" ~ "ubyte tmp2 = cast(ubyte)((tmp1 >> 1) + (" ~ @@ -851,27 +830,27 @@ string ARR_Undoc(Env env) } -string ANC_Undoc(Env env) +string ANC_Undoc() { - return ReadInto(_A, "address", env) ~ + return ReadInto(_A, "address") ~ SetNZ(_A) ~ _C ~ " = (" ~ _A ~ " > 0x7f);\n"; } -string ALR_Undoc(Env env) +string ALR_Undoc() { - return ReadInto(Local("ubyte", "data"), "address", env) ~ + return ReadInto(Local("ubyte", "data"), "address") ~ _A ~ " &= data;\n" ~ ShiftRight(_A); } -string AXS_Undoc(Env env) +string AXS_Undoc() { - return ReadInto(Local("ubyte", "data"), "address", env) ~ + return ReadInto(Local("ubyte", "data"), "address") ~ _X ~ " &= " ~ _A ~ ";\n" ~ - CompareBase(_X, env); + CompareBase(_X); } @@ -879,7 +858,7 @@ string AXS_Undoc(Env env) * This opcode is unstable on certain machines; see * http://visual6502.org/wiki/index.php?title=6502_Opcode_8B_(XAA,ANE) */ -string XAA_Undoc(Env env) +string XAA_Undoc() { /* * As far as I can tell, the only programs in the wild that depend @@ -888,7 +867,7 @@ string XAA_Undoc(Env env) */ string MAGIC = "0xff"; - return ReadInto(Local("ubyte", "data"), "address", env) ~ + return ReadInto(Local("ubyte", "data"), "address") ~ _A ~ " = ((" ~ _A ~ " | " ~ MAGIC ~ ") & " ~ _X ~ " & data);\n" ~ SetNZ(_A); } @@ -897,25 +876,25 @@ string XAA_Undoc(Env env) /* * This opcode is unstable on certain machines. */ -string LAX_IMM_Undoc(Env env) +string LAX_IMM_Undoc() { // From the VICE emulator. string MAGIC = "0xee"; - return ReadInto(Local("ubyte", "data"), "address", env) ~ + return ReadInto(Local("ubyte", "data"), "address") ~ _A ~ " = ((" ~ _A ~ " | " ~ MAGIC ~ ") & " ~ _X ~ " & data);\n" ~ SetNZ(_A); } // TODO: these are affected by DMA on the C64. -string Strange_Undoc(string val, Env env) +string Strange_Undoc(string val) { return "ubyte addrHi = cast(ubyte)((address >> 8) + 1);\n" ~ Local("ubyte", "data") ~ " = " ~ val ~ " & addrHi;\n" ~ "address = (guess == address) ? address : " ~ "((data << 8) | (address & 0xff));\n" ~ - Write("address", "data", env); + Write("address", "data"); } @@ -960,154 +939,158 @@ string Attr(string var) } -string Address(Env env) +string Address(int mode, int exCyc, string chip) { - final switch (env.mode) + final switch (mode) { case IMP: - return AddrIMP(env); + return AddrIMP(); case IMM: - return AddrIMM(env); + return AddrIMM(); case ZP: - return AddrZP(env); + return AddrZP(); case ZPX: - return AddrZPXY(_X, env); + return AddrZPXY(_X, chip); case ZPY: - return AddrZPXY(_Y, env); + return AddrZPXY(_Y, chip); case IZX: - return AddrIZX(env); + return AddrIZX(chip); case IZY: - return AddrIZY(env); + return AddrIZY(chip, exCyc); case ABS: - return AddrABS(env); + return AddrABS(); case ABX: - return AddrABXY(_X, env); + return AddrABXY(_X, chip, exCyc); case ABY: - return AddrABXY(_Y, env); + return AddrABXY(_Y, chip, exCyc); case IND: + // handled by Jump() return ""; case REL: + // handled by Branch() return ""; case ZPI: - return AddrZPI(env); + return AddrZPI(); case ABI: + // handled in Jump() return ""; case NP1: + // handled implicitly (the 1 cycle is the opcode fetch) return ""; case NP8: - return AddrNP8(env); + return AddrNP8(); case KIL: + // handled by case KIL in OpBody() return ""; } return ""; } -string AddrIMM(Env env) +string AddrIMM() { return Local("ushort") ~ "address = " ~ _PC ~ "++;\n"; } -string AddrIMP(Env env) +string AddrIMP() { - return Peek(_PC, env); + return Peek(_PC); } -string AddrZP(Env env) +string AddrZP() { - return ReadOp(Local("ushort", "address"), env); + return ReadOp(Local("ushort", "address")); } -string AddrZPXY(string reg, Env env) +string AddrZPXY(string reg, string chip) { - bool nmos = env.nmos; + bool nmos = (chip == "6502"); - return ReadOp(Local("ushort", "base"), env) ~ + return ReadOp(Local("ushort", "base")) ~ If!(nmos)( - Peek("base", env), - Peek(_PC, env)) ~ + Peek("base"), + Peek(_PC)) ~ Local("ushort") ~ "address = cast(ubyte)(base + " ~ reg ~ ");\n"; } -string AddrIZX(Env env) +string AddrIZX(string chip) { - bool nmos = env.nmos; + bool nmos = (chip == "6502"); - return ReadOp(Local("ushort", "base"), env) ~ + return ReadOp(Local("ushort", "base")) ~ If!(nmos)( - Peek("base", env), - Peek(_PC, env)) ~ - ReadWordZP("ushort", "address", "base + " ~ _X, env); + Peek("base"), + Peek(_PC)) ~ + ReadWordZP("ushort", "address", "base + " ~ _X); } -string AddrIZY(Env env) +string AddrIZY(string chip, int exCyc) { - return ReadOp("ubyte vector", env) ~ - ReadWordZP("ushort", "base", "vector", env) ~ + return ReadOp("ubyte vector") ~ + ReadWordZP("ushort", "base", "vector") ~ Local("ushort") ~ "address = cast(ushort)(base + " ~ _Y ~ ");\n" ~ - CheckShortcut("base", "address", env); + CheckShortcut("base", "address", chip, exCyc); } -string AddrABS(Env env) +string AddrABS() { - return ReadWordOp("ushort", "address", env); + return ReadWordOp("ushort", "address"); } -string AddrABXY(string reg, Env env) +string AddrABXY(string reg, string chip, int exCyc) { - return ReadWordOp("ushort", "base", env) ~ + return ReadWordOp("ushort", "base") ~ Local("ushort") ~ "address = cast(ushort)(base + " ~ reg ~ ");\n" ~ - CheckShortcut("base", "address", env); + CheckShortcut("base", "address", chip, exCyc); } -string AddrZPI(Env env) +string AddrZPI() { - return ReadOp(Local("ushort", "base"), env) ~ - ReadWordZP("ushort", "address", "base", env); + return ReadOp(Local("ushort", "base")) ~ + ReadWordZP("ushort", "address", "base"); } -string AddrNP8(Env env) +string AddrNP8() { - return ReadOp(Local("ushort", "base"), env) ~ - Peek(_PC, env) ~ + return ReadOp(Local("ushort", "base")) ~ + Peek(_PC) ~ IncPC() ~ - Peek("0xff00 | base", env) ~ - Peek("0xffff", env) ~ - Peek("0xffff", env) ~ - Peek("0xffff", env) ~ - Peek("0xffff", env); + Peek("0xff00 | base") ~ + Peek("0xffff") ~ + Peek("0xffff") ~ + Peek("0xffff") ~ + Peek("0xffff"); } -string CheckShortcut(string base, string addr, Env env) +string CheckShortcut(string base, string addr, string chip, int exCyc) { - bool nmos = env.nmos; - int exCyc = env.exCyc; + bool nmos = (chip == "6502"); return "ushort guess = (" ~ base ~ " & 0xFF00) | cast(ubyte)" ~ addr ~ ";\n" ~ "if (guess != " ~ addr ~ ")\n{\n" ~ - If!(nmos)(Peek("guess", env), - Peek(_PC, env)) ~ + If!(nmos)(Peek("guess"), + Peek(_PC)) ~ "}\n" ~ - If!(exCyc)("else\n{\n" ~ Peek("address", env) ~ "}\n"); + If!(exCyc)("else\n{\n" ~ Peek("address") ~ "}\n"); } -string ReadInto(string var, string action, string addr, Env env) +string ReadInto(string var, string action, string addr) { - return PreAccess(env) ~ + return PreAccess() ~ var ~ " " ~ action ~ " " ~ ReadRaw("(" ~ addr ~ ")") ~ ";\n"; } -string ReadInto(string var, string addr, Env env) +string ReadInto(string var, string addr) { - return ReadInto(var, "=", addr, env); + return ReadInto(var, "=", addr); } -string ReadOp(string var, Env env) +string ReadOp(string var) { - return ReadInto(var, _PC ~ "++", env); + return ReadInto(var, _PC ~ "++"); } string ReadRaw(string addr) @@ -1115,74 +1098,69 @@ string ReadRaw(string addr) return Attr("memory") ~ ".read(" ~ addr ~")"; } -string ReadWordBasic(string type, string var, string addr1, string addr2, - Env env) +string ReadWordBasic(string type, string var, string addr1, string addr2) { - return LoadLoByte(type, var, addr1, env) ~ - LoadHiByte(var, addr2, env); + return LoadLoByte(type, var, addr1) ~ + LoadHiByte(var, addr2); } -string ReadWordBasic(string var, string addr1, string addr2, Env env) +string ReadWordBasic(string var, string addr1, string addr2) { - return ReadWordBasic("", var, addr1, addr2, env); + return ReadWordBasic("", var, addr1, addr2); } -string ReadWord(string type, string var, string addr, Env env) +string ReadWord(string type, string var, string addr) { - return ReadWordBasic(type, var, addr, "cast(ushort)(" ~ addr ~ " + 1)", - env); + return ReadWordBasic(type, var, addr, "cast(ushort)(" ~ addr ~ " + 1)"); } -string ReadWord(string var, string addr, Env env) +string ReadWord(string var, string addr) { - return ReadWord("", var, addr, env); + return ReadWord("", var, addr); } -string ReadWordZP(string type, string var, string addr, Env env) +string ReadWordZP(string type, string var, string addr) { return ReadWordBasic(type, var, "cast(ubyte)( " ~ addr ~ ")", - "cast(ubyte)(" ~ addr ~ " + 1)", env); + "cast(ubyte)(" ~ addr ~ " + 1)"); } -string ReadWordZP(string var, string addr, Env env) +string ReadWordZP(string var, string addr) { - return ReadWordZP("", var, addr, env); + return ReadWordZP("", var, addr); } -string ReadWordOp(string type, string var, Env env) +string ReadWordOp(string type, string var) { - return ReadWordBasic(type, var, _PC ~ "++", _PC ~ "++", env); + return ReadWordBasic(type, var, _PC ~ "++", _PC ~ "++"); } -string ReadWordOp(string var, Env env) +string ReadWordOp(string var) { - return ReadWordOp("", var, env); + return ReadWordOp("", var); } -string PreAccess(Env env) +string PreAccess() { - bool c = env.c; - return If!(c)("++cycles;\n", Attr("clock") ~ ".tick();\n"); + return If!(cumulative)("++cycles;\n", Attr("clock") ~ ".tick();\n"); } -string Peek(string addr, Env env) +string Peek(string addr) { - bool s = env.s; - return PreAccess(env) ~ - If!(s)(Attr("memory") ~ ".read(" ~ addr ~");\n"); + return PreAccess() ~ + If!(strict)(Attr("memory") ~ ".read(" ~ addr ~");\n"); } -string Poke(string addr, string val, Env env) +string Poke(string addr, string val) { - bool s = env.s; - return PreAccess(env) ~ - If!(s)( + return PreAccess() ~ + If!(strict)( Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"); } -string Write(string addr, string val, Env env) +string Write(string addr, string val) { - return PreAccess(env) ~ + return PreAccess() ~ Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"; } @@ -1202,50 +1180,50 @@ string DecSP() return "--" ~ _S ~ ";\n"; } -string PullStatus(Env env) +string PullStatus() { - return Peek(STACK, env) ~ + return Peek(STACK) ~ IncSP() ~ - PreAccess(env) ~ + PreAccess() ~ Attr("statusFromByte") ~ "(" ~ ReadRaw(STACK) ~ ");\n"; } -string PullInto(string var, Env env) +string PullInto(string var) { return IncSP() ~ - ReadInto(var, STACK, env); + ReadInto(var, STACK); } -string Push(string val, Env env) +string Push(string val) { - return Write(STACK, val, env) ~ + return Write(STACK, val) ~ DecSP(); } -string PushPC(Env env) +string PushPC() { - return Push(HiByte(_PC), env) ~ - Push(LoByte(_PC), env); + return Push(HiByte(_PC)) ~ + Push(LoByte(_PC)); } -string PullPC(Env env) +string PullPC() { - return PullInto(_PC, env) ~ + return PullInto(_PC) ~ IncSP() ~ - LoadHiByte(_PC, STACK, env); + LoadHiByte(_PC, STACK); } -string LoadLoByte(string type, string var, string addr, Env env) +string LoadLoByte(string type, string var, string addr) { - return PreAccess(env) ~ + return PreAccess() ~ Local(type, var) ~ " = " ~ ReadRaw(addr) ~ ";\n"; } -string LoadHiByte(string var, string addr, Env env) +string LoadHiByte(string var, string addr) { - return PreAccess(env) ~ + return PreAccess() ~ var ~ " |= (" ~ ReadRaw(addr) ~ " << 8);\n"; } @@ -1269,10 +1247,9 @@ string SetNZ(string var) return _N ~ " = " ~ _Z ~ " = (" ~ var ~ ");\n"; } -string Done(Env env) +string Done() { - bool c = env.c; - return If!(c)(Attr("clock") ~ ".tick(cycles);\n"); + return If!(cumulative)(Attr("clock") ~ ".tick(cycles);\n"); } diff --git a/src/cpu/d6502.d b/src/cpu/d6502.d index 365675e..5f399b7 100644 --- a/src/cpu/d6502.d +++ b/src/cpu/d6502.d @@ -29,17 +29,6 @@ import std.array, std.format; import cpu.ctfe_d6502; -enum Strict : bool -{ - no, yes -} - -enum Cumulative : bool -{ - no, yes -} - - template is6502(T) { enum is6502 = __traits(getMember, T, "_chip") == "6502"; @@ -51,13 +40,11 @@ template is65C02(T) } -final class Cpu(string chip, bool strict, bool cumulative) +final class Cpu(string chip) { static assert(chip == "6502" || chip == "65C02" || chip == "65c02"); enum _isCpu = true; enum _chip = (chip == "6502" ? "6502" : "65C02"); - enum _isStrict = strict; - enum _isCumulative = cumulative; struct _Mem { @@ -71,7 +58,7 @@ final class Cpu(string chip, bool strict, bool cumulative) struct _Clock { - static if (cumulative) + version(Cumulative) /* * Updates the number of cycles executed. Called just * prior to the final read/write action of each opcode. @@ -97,7 +84,7 @@ final class Cpu(string chip, bool strict, bool cumulative) version(OpFunctions) {} else { - static if (cumulative) { int cycles; } + version(Cumulative) { int cycles; } ushort address, base; ubyte data; } @@ -138,23 +125,26 @@ final class Cpu(string chip, bool strict, bool cumulative) ubyte opcode; static if (!opArray) { - static if (cumulative) { int cycles; } + version(Cumulative) { int cycles; } ushort address, base; ubyte data; } do { - static if (cumulative && !opArray) - cycles = 1; - // XXX figure out final cycle stuff - static if (!cumulative) + version(Cumulative) + { + static if (!opArray) cycles = 1; + } + else + { clock.tick(); + } // XXX check signals, NMI/IRQ delays, etc. opcode = memory.read(PC++); - mixin(OpExecute(_chip, strict, cumulative)); + mixin(OpExecute(_chip)); } while (keepRunning); } - version(OpDelegates) mixin (OpBodies(_chip, strict, cumulative)); + version(OpDelegates) mixin (OpBodies(_chip)); } @@ -163,8 +153,8 @@ enum ushort IRQ_VECTOR = 0xFFFE; private: -version(OpFunctions) mixin(OpBodies("6502", vStrict, vCumulative)); -version(OpFunctions) mixin(OpBodies("65C02", vStrict, vCumulative)); +version(OpFunctions) mixin(OpBodies("6502")); +version(OpFunctions) mixin(OpBodies("65C02")); //alias Cpu!("6502", false, false) T1; diff --git a/test/base.d b/test/base.d index 34e6576..36357f2 100644 --- a/test/base.d +++ b/test/base.d @@ -8,6 +8,16 @@ import test.cpu, test.opcodes; import cpu.data_d6502; +version(Strict) + enum strict = true; +else + enum strict = false; +version(Cumulative) + enum cumulative = true; +else + enum cumulative = false; + + /* * Emulates zero page, stack, and 3 additional pages of "main memory" * starting at a user-defined address. Accesses outside the defined @@ -2672,7 +2682,7 @@ if (isCpu!T) cycles = 2; return [Bus(Action.READ, pc)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, pc+1)]); } @@ -2689,7 +2699,7 @@ if (isCpu!T) cycles = 3; return [Bus(Action.READ, pc)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, pc+1)]) ~ [Bus(Action.WRITE, sp)]; } @@ -2708,7 +2718,7 @@ if (isCpu!T) cycles = 4; return [Bus(Action.READ, pc)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, pc+1), Bus(Action.READ, sp)]) ~ [Bus(Action.READ, sp1)]; @@ -2729,7 +2739,7 @@ if (isCpu!T) cycles = 2 + decimal; return [Bus(Action.READ, pc), Bus(Action.READ, pc+1)] ~ - If!decimal(If!(isStrict!T)( + If!decimal(If!(strict)( [Bus(Action.READ, pc+2)])); } @@ -2751,7 +2761,7 @@ if (isCpu!T) cycles = 2 + branch + px; return [Bus(Action.READ, pc), Bus(Action.READ, pc+1)] ~ - If!branch(If!(isStrict!T)( + If!branch(If!(strict)( [Bus(Action.READ, pc+2)] ~ If!px( [Bus(Action.READ, wrongAddr)]))); @@ -2806,7 +2816,7 @@ if (isCpu!T) cycles = 3; // + accesses_end return [Bus(Action.READ, pc), Bus(Action.READ, pc+1)] ~ - If!(isStrict!T)( + If!(strict)( If!(isNMOS!T)( [Bus(Action.READ, op1)]) ~ If!(isCMOS!T)( @@ -2862,7 +2872,7 @@ if (isCpu!T) cycles = 5; // + accesses_end return [Bus(Action.READ, pc), Bus(Action.READ, pc+1)] ~ - If!(isStrict!T)( + If!(strict)( If!(isNMOS!T)( [Bus(Action.READ, op1)]) ~ If!(isCMOS!T)( @@ -2963,14 +2973,14 @@ if (isCpu!T) if (guess != right) { cycles += 1; - return If!(isStrict!T)( + return If!(strict)( If!(isNMOS!T)([Bus(Action.READ, guess)]) ~ If!(isCMOS!T)([Bus(Action.READ, pc + opLen)])); // XXX } else if (noShortcut) { cycles += 1; - return If!(isStrict!T)([Bus(Action.READ, guess)]); + return If!(strict)([Bus(Action.READ, guess)]); } else { @@ -2999,13 +3009,13 @@ if (isCpu!T) cycles += (rmw ? 3 : (write ? 1 : (1 + decimal))); return If!read( [Bus(Action.READ, addr)] ~ - If!decimal(If!(isStrict!T)( + If!decimal(If!(strict)( [Bus(Action.READ, pc + opLen)]))) ~ If!write( [Bus(Action.WRITE, addr)]) ~ If!rmw( [Bus(Action.READ, addr)] ~ - If!(isStrict!T)( + If!(strict)( If!(isNMOS!T)( [Bus(Action.WRITE, addr)]) ~ If!(isCMOS!T)( @@ -3029,12 +3039,12 @@ if (isCpu!T) cycles = 6; return [Bus(Action.READ, pc)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, pc+1), Bus(Action.READ, sp)]) ~ [Bus(Action.READ, sp1), Bus(Action.READ, sp2)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, ret)]); } @@ -3054,7 +3064,7 @@ if (isCpu!T) cycles = 6; return [Bus(Action.READ, pc)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, pc+1), Bus(Action.READ, sp)]) ~ [Bus(Action.READ, sp1), @@ -3077,7 +3087,7 @@ if (isCpu!T) cycles = 7; return [Bus(Action.READ, pc)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, pc+1)]) ~ [Bus(Action.WRITE, sp), Bus(Action.WRITE, sp1), @@ -3101,7 +3111,7 @@ if (isCpu!T) cycles = 6; return [Bus(Action.READ, pc), Bus(Action.READ, pc+1)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, sp)]) ~ [Bus(Action.WRITE, sp), Bus(Action.WRITE, sp1), @@ -3140,7 +3150,7 @@ if (isCpu!T) return [Bus(Action.READ, pc), Bus(Action.READ, pc+1), Bus(Action.READ, pc+2)] ~ - If!(isStrict!T)(If!(isCMOS!T)( + If!(strict)(If!(isCMOS!T)( [Bus(Action.READ, pc+3)])) ~ // XXX [Bus(Action.READ, ial), Bus(Action.READ, iah)]; @@ -3170,7 +3180,7 @@ if (isCpu!T && isCMOS!T) return [Bus(Action.READ, pc), Bus(Action.READ, pc+1), Bus(Action.READ, pc+2)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, pc+3)]) ~ // XXX [Bus(Action.READ, ial), Bus(Action.READ, iah)]; @@ -3196,7 +3206,7 @@ if (isCpu!T && isCMOS!T) cycles = 8; return [Bus(Action.READ, pc), Bus(Action.READ, pc+1)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, pc+2), Bus(Action.READ, weird), Bus(Action.READ, 0xFFFF), @@ -3337,16 +3347,6 @@ void test_opcode_timing(T)(ubyte opcode, busreport report) } -version(Strict) - enum testStrict = true; -else - enum testStrict = false; -version(Cumulative) - enum testCumulative = true; -else - enum testCumulative = false; - - struct CheckOptions { enum Addr diff --git a/test/cpu.d b/test/cpu.d index ee6f3f1..fde563f 100644 --- a/test/cpu.d +++ b/test/cpu.d @@ -11,6 +11,16 @@ import std.conv, std.exception, std.random, std.string, std.traits; public import cpu.d6502 : Cpu, is6502, is65C02; +version(Strict) + enum strict = true; +else + enum strict = false; +version(Cumulative) + enum cumulative = true; +else + enum cumulative = false; + + // True if T is the type of a cpu. template isCpu(T) { @@ -29,27 +39,13 @@ template isCMOS(T) enum isCMOS = is65C02!T; } -// True if the cpu type T accesses memory on every cycle. -template isStrict(T) -{ - enum isStrict = isCpu!T && __traits(getMember, T, "_isStrict"); -} - -// True if the cpu type T aggregates ticks. -template isCumulative(T) -{ - enum isCumulative = isCpu!T && __traits(getMember, T, "_isCumulative"); -} - /* - * The type of a cpu, based on its architecture (6502 or 65C02) and - * its timing characteristics (strict or not bus access, cumulative or - * not cycle reporting). + * The type of a cpu, based on its architecture (6502 or 65C02). */ -template CPU(string arch, bool strict, bool cumulative) +template CPU(string arch) { - alias Cpu!(arch, strict, cumulative) CPU; + alias Cpu!(arch) CPU; } @@ -70,7 +66,7 @@ if (isCpu!T) void connectMem(T, S)(T cpu, ref S mem) if (isCpu!T) { - static if (isCumulative!T) + static if (cumulative) void tick(int cycles) {} else void tick() {} @@ -96,7 +92,7 @@ if (isCpu!T) auto cycles = new int; auto wrappedTick = cpu.clock.tick; - static if (isCumulative!T) + static if (cumulative) { void tick(int cyc) { diff --git a/test/test_bus.d b/test/test_bus.d index f49aedc..d2b7272 100644 --- a/test/test_bus.d +++ b/test/test_bus.d @@ -11,12 +11,12 @@ void main(string[] args) auto opts = CheckOptions(args); auto report = report_timing_debug(); - alias CPU!("6502", testStrict, testCumulative) T1; + alias CPU!("6502") T1; writeln("Testing bus/timing, 6502"); foreach (op; opts.codes6502) test_opcode_timing!T1(cast(ubyte)op, report); - alias CPU!("65C02", testStrict, testCumulative) T2; + alias CPU!("65C02") T2; writeln("Testing bus/timing, 65C02"); foreach (op; opts.codes65C02) test_opcode_timing!T2(cast(ubyte)op, report); diff --git a/test/test_decimal.d b/test/test_decimal.d index 322f8f3..abd879a 100644 --- a/test/test_decimal.d +++ b/test/test_decimal.d @@ -228,11 +228,10 @@ if (isCpu!T) version(Benchmark) { - static assert(!testStrict && !testCumulative); import std.datetime, std.stdio; void f0() { - testDecimalMode!(CPU!("65C02", false, false))(); + testDecimalMode!(CPU!("65C02"))(); } void main() @@ -248,9 +247,9 @@ else void main() { writeln("Testing decimal mode, 6502"); - testDecimalMode!(CPU!("6502", testStrict, testCumulative))(); + testDecimalMode!(CPU!("6502"))(); writeln("Testing decimal mode, 65C02"); - testDecimalMode!(CPU!("65C02", testStrict, testCumulative))(); + testDecimalMode!(CPU!("65C02"))(); } } diff --git a/test/test_func.d b/test/test_func.d index 1a39316..74821e7 100644 --- a/test/test_func.d +++ b/test/test_func.d @@ -11,12 +11,12 @@ void main(string[] args) auto opts = CheckOptions(args); auto report = report_debug(); - alias CPU!("6502", testStrict, testCumulative) T1; + alias CPU!("6502") T1; writeln("Testing functionality, 6502"); foreach (opcode; opts.codes6502) test_one_opcode!T1(cast(ubyte)opcode, report); - alias CPU!("65C02", testStrict, testCumulative) T2; + alias CPU!("65C02") T2; writeln("Testing functionality, 65C02"); foreach (opcode; opts.codes65C02) test_one_opcode!T2(cast(ubyte)opcode, report); From a572ea91467f1639f7a50f5e5589051f04aa389b Mon Sep 17 00:00:00 2001 From: edmccard Date: Fri, 13 Apr 2012 21:35:40 -0400 Subject: [PATCH 22/27] Cpu speedup; removed OpFunctions option --- src/cpu/ctfe_d6502.d | 100 ++++++++----------------------------------- src/cpu/d6502.d | 52 +++++++++++----------- test/cpu.d | 26 +++++------ test/runtests.d | 12 +++--- test/test_decimal.d | 41 ++++++++++++++++-- 5 files changed, 102 insertions(+), 129 deletions(-) diff --git a/src/cpu/ctfe_d6502.d b/src/cpu/ctfe_d6502.d index 4aa4918..1bd0890 100644 --- a/src/cpu/ctfe_d6502.d +++ b/src/cpu/ctfe_d6502.d @@ -23,17 +23,10 @@ version(OpDelegates) enum opArray = true; } -// OpFunctions: each opcode is a free function with a Cpu argument. -version(OpFunctions) -{ - enum versionCheck = 2; - enum opArray = true; -} - // OpSwitch: each opcode is inlined in a 256-case switch. version(OpSwitch) { - enum versionCheck = 3; + enum versionCheck = 2; enum opArray = false; } @@ -45,7 +38,7 @@ version(OpSwitch) */ version(OpNestedSwitch) { - enum versionCheck = 4; + enum versionCheck = 3; enum opArray = false; } @@ -59,71 +52,37 @@ string OpArrayDef() { version(OpDelegates) return q{void delegate()[256] opcodes;}; - else version(OpFunctions) - return q{void function(typeof(this))[256] opcodes;}; else return ""; } string OpArrayInit() { - static if (!opArray) return ""; - else + string ret; + foreach (op; 0..256) { - string ret; - foreach (op; 0..256) - { - version(OpDelegates) - ret ~= Fmt("opcodes[0x#] = &opcode_#;\n", - Hex2(op), Hex2(op)); - version(OpFunctions) - ret ~= Fmt("opcodes[0x#] = &opcode_#!(typeof(this));\n", - Hex2(op), Hex2(op)); - } - return ret; + ret ~= Fmt("opcodes[0x#] = &opcode_#;\n", + Hex2(op), Hex2(op)); } + return ret; } -string OpBodies(string chip) +string OpMethods(string chip) { - static if (!opArray) return ""; - else + string ret; + foreach (op; 0..256) { - string ret; - foreach (op; 0..256) - { - version(OpDelegates) - ret ~= "final void opcode_" ~ Hex2(op) ~ "()\n{\n" ~ - If!(cumulative)("int cycles = 1;\n") ~ - OpBody(op, chip) ~ "}\n"; - version(OpFunctions) - ret ~= "void opcode_" ~ Hex2(op) ~ - "(T)(T cpu) if (is" ~ chip ~ "!T)\n{\n" ~ - If!(cumulative)("int cycles = 1;\n") ~ - OpBody(op, chip) ~ "}\n"; - } -/+ - foreach (op; 13..256) - version(OpDelegates) - ret ~= "final void opcode_" ~ Hex2(op) ~ "()\n{\n" ~ - If!(cumulative)("int cycles = 1;\n") ~ - "" ~ "}\n"; - version(OpFunctions) - ret ~= "void opcode_" ~ Hex2(op) ~ - "(T)(T cpu) if (is" ~ chip ~ "!T)\n{\n" ~ - If!(cumulative)("int cycles = 1;\n") ~ - "" ~ "}\n"; -+/ - return ret; + ret ~= "final void opcode_" ~ Hex2(op) ~ "()\n{\n" ~ + If!(cumulative)("int cycles = 1;\n") ~ + OpBody(op, chip) ~ "}\n"; } + return ret; } string OpExecute(string chip) { version(OpDelegates) return q{opcodes[opcode]();}; - version(OpFunctions) - return q{opcodes[opcode](this);}; version(OpSwitch) return Switch256(chip); version(OpNestedSwitch) @@ -900,42 +859,17 @@ string Strange_Undoc(string val) string Local(string type) { - version(OpFunctions) - return type ~ " "; - else - return ""; -/+ - version(OpSwitch) - return ""; - else version(OpNestedSwitch) - return ""; - else - return type ~ " "; -+/ + return ""; } string Local(string type, string var) { - version(OpFunctions) - return type ~ " " ~ var; - else - return var; -/+ - version(OpSwitch) - return var; - else version(OpNestedSwitch) - return var; - else - return type ~ " " ~ var; -+/ + return var; } string Attr(string var) { - version(OpFunctions) - return "cpu." ~ var; - else - return var; + return var; } diff --git a/src/cpu/d6502.d b/src/cpu/d6502.d index 5f399b7..cace916 100644 --- a/src/cpu/d6502.d +++ b/src/cpu/d6502.d @@ -40,18 +40,25 @@ template is65C02(T) } -final class Cpu(string chip) +final class Cpu(string chip, MEM, CLK) +if (__traits(compiles, { + MEM m; ubyte val; ushort addr; + val = m.read(addr); + m.write(addr, val); + CLK c; int cycles; + version(Cumulative) c.tick(cycles); + else c.tick(); +})) { static assert(chip == "6502" || chip == "65C02" || chip == "65c02"); enum _isCpu = true; enum _chip = (chip == "6502" ? "6502" : "65C02"); +version(RunTest) +{ struct _Mem { - // Reads a value from system memory. ubyte delegate(ushort addr) read; - - // Writes a value to system memory. void delegate(ushort addr, ubyte val) write; } _Mem memory; @@ -59,19 +66,17 @@ final class Cpu(string chip) struct _Clock { version(Cumulative) - /* - * Updates the number of cycles executed. Called just - * prior to the final read/write action of each opcode. - */ void delegate(int cycles) tick; else - /* - * Increments the number of cycles executed. Called prior - * to each read/write action. - */ void delegate() tick; } _Clock clock; +} +else +{ + MEM memory; + CLK clock; +} ubyte A, X, Y, S; ushort PC; @@ -80,10 +85,9 @@ final class Cpu(string chip) ubyte N, Z; bool V, D, I, C; - static if (opArray) { mixin(OpArrayDef()); } - version(OpFunctions) {} - else + version(OpDelegates) { + mixin(OpArrayDef()); version(Cumulative) { int cycles; } ushort address, base; ubyte data; @@ -92,9 +96,15 @@ final class Cpu(string chip) // TODO: other methods for stopping cpu bool keepRunning; - this() + this(MEM memory, CLK clock) { - static if (opArray) mixin(OpArrayInit()); + version(RunTest) {} + else + { + this.memory = memory; + this.clock = clock; + } + version(OpDelegates) mixin(OpArrayInit()); } final void statusFromByte(ubyte p) @@ -144,19 +154,13 @@ final class Cpu(string chip) } while (keepRunning); } - version(OpDelegates) mixin (OpBodies(_chip)); + version(OpDelegates) mixin (OpMethods(_chip)); } enum ushort IRQ_VECTOR = 0xFFFE; -private: - -version(OpFunctions) mixin(OpBodies("6502")); -version(OpFunctions) mixin(OpBodies("65C02")); - - //alias Cpu!("6502", false, false) T1; //alias Cpu!("6502", false, true) T2; //alias Cpu!("6502", true, false) T3; diff --git a/test/cpu.d b/test/cpu.d index fde563f..f8bc3cd 100644 --- a/test/cpu.d +++ b/test/cpu.d @@ -10,15 +10,7 @@ import std.conv, std.exception, std.random, std.string, std.traits; public import cpu.d6502 : Cpu, is6502, is65C02; - -version(Strict) - enum strict = true; -else - enum strict = false; -version(Cumulative) - enum cumulative = true; -else - enum cumulative = false; +import test.base : strict, cumulative; // True if T is the type of a cpu. @@ -40,19 +32,29 @@ template isCMOS(T) } +// Not used in test mode, but needed to instantiate a cpu. +class DummyMem +{ + ubyte read(ushort) { return 0; } + void write(ushort, ubyte) {} + static if (cumulative) { void tick(int) {} } + else { void tick() {} } +} + + /* * The type of a cpu, based on its architecture (6502 or 65C02). */ -template CPU(string arch) +template CPU(string arch, M = DummyMem, C = DummyMem) { - alias Cpu!(arch) CPU; + alias Cpu!(arch, M, C) CPU; } auto makeCpu(T)(CpuInfo info) if (isCpu!T) { - auto cpu = new T(); + auto cpu = new T(null, null); cpu.PC = info.PC; cpu.S = info.SP; cpu.statusFromByte(info.S); diff --git a/test/runtests.d b/test/runtests.d index 7dbb6aa..f2769da 100644 --- a/test/runtests.d +++ b/test/runtests.d @@ -6,10 +6,9 @@ enum OpDefs { None, Delegates = 1, - Functions = 2, - Switch = 4, - NestedSwitch = 8, - All = 15 + Switch = 2, + NestedSwitch = 4, + All = 7 } enum Tests @@ -39,7 +38,6 @@ version(DigitalMars) { defStrings = [ OpDefs.Delegates:" -version=OpDelegates", - OpDefs.Functions:" -version=OpFunctions", OpDefs.Switch:" -version=OpSwitch", OpDefs.NestedSwitch:" -version=OpNestedSwitch" ]; @@ -83,7 +81,7 @@ void main(string[] args) writeln( `Options: --test=type Func, Bus, Dec, or All - --def=style Delegates, Functions, Switch, or NestedSwitch + --def=style Delegates, Switch, or NestedSwitch --op=num test opcode 'num' (num is hex) --op=name test all opcodes named 'name' --addr=mode test all opcodes with addressing mode 'mode' @@ -136,7 +134,7 @@ void runTest(OpDefs def, Tests test, string[] args) writeln("With strict=", s, " cumulative=", c); string cmdline = defStrings[def] ~ stStrings[s] ~ cmStrings[c] ~ fNames[test] ~ join(args, " "); - system("rdmd --force -I.. -I../src " ~ cmdline); + system("rdmd --force -I.. -I../src -version=RunTest" ~ cmdline); } } } diff --git a/test/test_decimal.d b/test/test_decimal.d index abd879a..8c690b7 100644 --- a/test/test_decimal.d +++ b/test/test_decimal.d @@ -214,10 +214,20 @@ if (isCpu!T) mem.write(0x8055, 0x84); } - auto cpu = new T(); - connectMem(cpu, mem); +version(Benchmark) +{ + auto runner = new BreakRunner(mem); + auto cpu = new T(runner, runner); setPC(cpu, 0x8000); + try { cpu.run(true); } catch (StopException e) {} +} +else +{ + auto cpu = new T(null, null); + setPC(cpu, 0x8000); + connectMem(cpu, mem); runUntilBRK(cpu); +} if (mem[0x8003]) { // TODO: check data block to find out what failed exactly @@ -229,9 +239,34 @@ if (isCpu!T) version(Benchmark) { import std.datetime, std.stdio; + + final class BreakRunner + { + TestMemory* mem; + + this(ref TestMemory mem) + { + this.mem = &mem; + } + + final ubyte read(ushort addr) + { + if (addr == 0xFFFE) throw new StopException("BRK"); + return mem.read(addr); + } + + final void write(ushort addr, ubyte val) + { + mem.write(addr, val); + } + + static if (cumulative) { final void tick(int) {} } + else { final void tick() {} } + } + void f0() { - testDecimalMode!(CPU!("65C02"))(); + testDecimalMode!(CPU!("65C02", BreakRunner, BreakRunner))(); } void main() From cf369d4d2b676364a0f558bb25f9f4ea901f52d5 Mon Sep 17 00:00:00 2001 From: edmccard Date: Sat, 14 Apr 2012 02:43:03 -0400 Subject: [PATCH 23/27] WIP --- src/cpu/d6502.d | 9 ++++----- test/test_decimal.d | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/cpu/d6502.d b/src/cpu/d6502.d index cace916..da77b94 100644 --- a/src/cpu/d6502.d +++ b/src/cpu/d6502.d @@ -93,9 +93,6 @@ else ubyte data; } - // TODO: other methods for stopping cpu - bool keepRunning; - this(MEM memory, CLK clock) { version(RunTest) {} @@ -128,10 +125,11 @@ else (N & 0x80); } + bool keepRunning; + final void run(bool continuous) { keepRunning = continuous; - // TODO debugging info? ubyte opcode; static if (!opArray) { @@ -139,7 +137,8 @@ else ushort address, base; ubyte data; } - do { + do + { version(Cumulative) { static if (!opArray) cycles = 1; diff --git a/test/test_decimal.d b/test/test_decimal.d index 8c690b7..0f5c5f6 100644 --- a/test/test_decimal.d +++ b/test/test_decimal.d @@ -218,8 +218,9 @@ version(Benchmark) { auto runner = new BreakRunner(mem); auto cpu = new T(runner, runner); + runner.keepRunning = &cpu.keepRunning; setPC(cpu, 0x8000); - try { cpu.run(true); } catch (StopException e) {} + cpu.run(true); } else { @@ -243,6 +244,7 @@ version(Benchmark) final class BreakRunner { TestMemory* mem; + bool* keepRunning; this(ref TestMemory mem) { @@ -251,8 +253,16 @@ version(Benchmark) final ubyte read(ushort addr) { - if (addr == 0xFFFE) throw new StopException("BRK"); - return mem.read(addr); + if (addr == 0xfffe) + { + *keepRunning = false; + return 0x00; + } + else if (addr == 0xffff) + { + return 0x80; + } + else return mem.read(addr); } final void write(ushort addr, ubyte val) From a4af7191be0ae96dd5cbe346300fda1fdbc974f2 Mon Sep 17 00:00:00 2001 From: edmccard Date: Sat, 14 Apr 2012 03:07:02 -0400 Subject: [PATCH 24/27] Make testing use same memory/clock interface as normal operation. --- src/cpu/d6502.d | 30 +++--------------------- test/cpu.d | 56 +++++++++++++++++++++++++++------------------ test/runtests.d | 2 +- test/test_decimal.d | 2 +- 4 files changed, 39 insertions(+), 51 deletions(-) diff --git a/src/cpu/d6502.d b/src/cpu/d6502.d index da77b94..10178c8 100644 --- a/src/cpu/d6502.d +++ b/src/cpu/d6502.d @@ -54,29 +54,8 @@ if (__traits(compiles, { enum _isCpu = true; enum _chip = (chip == "6502" ? "6502" : "65C02"); -version(RunTest) -{ - struct _Mem - { - ubyte delegate(ushort addr) read; - void delegate(ushort addr, ubyte val) write; - } - _Mem memory; - - struct _Clock - { - version(Cumulative) - void delegate(int cycles) tick; - else - void delegate() tick; - } - _Clock clock; -} -else -{ MEM memory; CLK clock; -} ubyte A, X, Y, S; ushort PC; @@ -95,12 +74,9 @@ else this(MEM memory, CLK clock) { - version(RunTest) {} - else - { - this.memory = memory; - this.clock = clock; - } + this.memory = memory; + this.clock = clock; + version(OpDelegates) mixin(OpArrayInit()); } diff --git a/test/cpu.d b/test/cpu.d index f8bc3cd..063f8cb 100644 --- a/test/cpu.d +++ b/test/cpu.d @@ -32,29 +32,41 @@ template isCMOS(T) } -// Not used in test mode, but needed to instantiate a cpu. -class DummyMem +class TestIO { - ubyte read(ushort) { return 0; } - void write(ushort, ubyte) {} - static if (cumulative) { void tick(int) {} } - else { void tick() {} } + ubyte delegate(ushort) dread; + ubyte read(ushort addr) { return dread(addr); } + + void delegate(ushort, ubyte) dwrite; + void write(ushort addr, ubyte val) { dwrite(addr, val); } + + static if (cumulative) + { + void delegate(int) dtick; + void tick(int cycles) { dtick(cycles); } + } + else + { + void delegate() dtick; + void tick() { dtick(); } + } } /* * The type of a cpu, based on its architecture (6502 or 65C02). */ -template CPU(string arch, M = DummyMem, C = DummyMem) +template CPU(string arch, M = TestIO, C = TestIO) { alias Cpu!(arch, M, C) CPU; } -auto makeCpu(T)(CpuInfo info) +auto makeCpu(T)(CpuInfo info = CpuInfo()) if (isCpu!T) { - auto cpu = new T(null, null); + auto tio = new TestIO(); + auto cpu = new T(tio, tio); cpu.PC = info.PC; cpu.S = info.SP; cpu.statusFromByte(info.S); @@ -73,9 +85,9 @@ if (isCpu!T) else void tick() {} - cpu.memory.read = &mem.read; - cpu.memory.write = &mem.write; - cpu.clock.tick = &tick; + cpu.memory.dread = &mem.read; + cpu.memory.dwrite = &mem.write; + cpu.clock.dtick = &tick; } @@ -92,7 +104,7 @@ auto recordCycles(T)(T cpu) if (isCpu!T) { auto cycles = new int; - auto wrappedTick = cpu.clock.tick; + auto wrappedTick = cpu.clock.dtick; static if (cumulative) { @@ -110,7 +122,7 @@ if (isCpu!T) wrappedTick(); } } - cpu.clock.tick = &tick; + cpu.clock.dtick = &tick; return constRef(cycles); } @@ -148,9 +160,9 @@ if (isCpu!T) auto record = new Bus[actions]; int c; - enforce(cpu.memory.read !is null && cpu.memory.write !is null); - auto wrappedRead = cpu.memory.read; - auto wrappedWrite = cpu.memory.write; + enforce(cpu.memory.dread !is null && cpu.memory.dwrite !is null); + auto wrappedRead = cpu.memory.dread; + auto wrappedWrite = cpu.memory.dwrite; ubyte read(ushort addr) { @@ -170,8 +182,8 @@ if (isCpu!T) wrappedWrite(addr, val); } - cpu.memory.read = &read; - cpu.memory.write = &write; + cpu.memory.dread = &read; + cpu.memory.dwrite = &write; return record; } @@ -203,8 +215,8 @@ enum Action : ushort { NONE, READ, WRITE } void runUntilBRK(T)(T cpu) if (isCpu!T) { - assert(cpu.memory.read !is null); - auto wrappedRead = cpu.memory.read; + assert(cpu.memory.dread !is null); + auto wrappedRead = cpu.memory.dread; ubyte read(ushort addr) { @@ -212,7 +224,7 @@ if (isCpu!T) return wrappedRead(addr); } - cpu.memory.read = &read; + cpu.memory.dread = &read; try { cpu.run(true); } catch (StopException e) {} } diff --git a/test/runtests.d b/test/runtests.d index f2769da..32903a2 100644 --- a/test/runtests.d +++ b/test/runtests.d @@ -134,7 +134,7 @@ void runTest(OpDefs def, Tests test, string[] args) writeln("With strict=", s, " cumulative=", c); string cmdline = defStrings[def] ~ stStrings[s] ~ cmStrings[c] ~ fNames[test] ~ join(args, " "); - system("rdmd --force -I.. -I../src -version=RunTest" ~ cmdline); + system("rdmd --force -I.. -I../src -version=RunTest " ~ cmdline); } } } diff --git a/test/test_decimal.d b/test/test_decimal.d index 0f5c5f6..402680f 100644 --- a/test/test_decimal.d +++ b/test/test_decimal.d @@ -224,7 +224,7 @@ version(Benchmark) } else { - auto cpu = new T(null, null); + auto cpu = makeCpu!T(); setPC(cpu, 0x8000); connectMem(cpu, mem); runUntilBRK(cpu); From 581fe45c897faf10c9fa240000c21efe2d82ff99 Mon Sep 17 00:00:00 2001 From: edmccard Date: Sat, 14 Apr 2012 06:14:08 -0400 Subject: [PATCH 25/27] Begin documentation of test framework. --- test/base.d | 173 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 109 insertions(+), 64 deletions(-) diff --git a/test/base.d b/test/base.d index 36357f2..fd2251f 100644 --- a/test/base.d +++ b/test/base.d @@ -18,6 +18,115 @@ else enum cumulative = false; +/* + * A test is a combination of setups, an expectation, a runner, and a + * reporter. + */ + +/* + * A setup function for a given opcode puts cpu, data, info, and msg + * into the appropriate state and then calls the next function (see + * testCallNext) with the modified values. To setup multiple + * scenarios, just call the next function multiple times. + * + * Values for cpu registers are set up using the setXXX(cpu, val) + * functions; see testCallNext and OpInfo for descriptions of other + * types of information that may need to be set up. + * + * Example: + * + * // prepare the accumulator with a value different from expected + * setA(cpu, ~0x10); + * // prepare memory with LDA #$10 at address $1000 + * setPC(cpu, 0x1000); + * callNext("LDA immediate, positive", [Block(0x1000, [0xA9, 0x10])]); + */ +alias void delegate(ubyte opcode, CpuInfo cpu, Block[] data, OpInfo info, + string msg, TestSetup* next) + testsetup; + + +/* + * A mixin that simplifies calling the next setup function. + * + * newMsg will be appended to the current msg and passed to the next + * function. + * + * To place values in memory, pass an array of Blocks as the second + * parameter. It will be appended to the current data. + */ +template testCallNext() +{ + void callNext(string newMsg = "", Block[] newData = []) + { + if (*next !is null) + next.run(opcode, cpu, data ~ newData, info, msg ~ newMsg); + } +} + + +/* + * A block of memory with a given base address. + * + * For example, `Block(0x1000, [0xA9, 0x10])` + */ +struct Block +{ + const ushort base; + const(ubyte[]) data; + + string toString() const + { + return format("Block(%0.4X, [%s])", base, formatMemory(data)); + } +} + + +// Information about expected opcode execution. +struct OpInfo +{ + // The effective address, if any. + ushort addr; + // The data to be read or written, if any. + ubyte data; + // The length of the opcode + operands. + int len; +} + + +class TestSetup +{ + testsetup setup; + TestSetup next; + + auto static opCall(testsetup d) + { + auto obj = new TestSetup(); + obj.setup = d; + return obj; + } + + void run(ubyte opcode, CpuInfo cpu = CpuInfo(), Block[] data = [], + OpInfo info = OpInfo(), string msg = "") + { + setup(opcode, cpu, data, info, msg, &next); + } +} + + + +TestSetup connect(TestSetup first, TestSetup[] rest...) +{ + if (!(rest.empty)) + { + auto x = first; + while (x.next !is null) x = x.next; + x.next = connect(rest[0], rest[1..$]); + } + return first; +} + + /* * Emulates zero page, stack, and 3 additional pages of "main memory" * starting at a user-defined address. Accesses outside the defined @@ -115,19 +224,6 @@ public: } -// A block of memory with a given base address. -struct Block -{ - const ushort base; - const(ubyte[]) data; - - string toString() const - { - return format("Block(%0.4X, [%s])", base, formatMemory(data)); - } -} - - /* * Formats data as a string of 2-digit hex bytes, separated by spaces. * @@ -145,57 +241,6 @@ string formatMemory(const(ubyte[]) data, size_t max = 3) } -struct OpInfo -{ - ushort addr; - ubyte data; - int len; - bool write; -} - -alias void delegate(ubyte, CpuInfo, Block[], OpInfo, string, TestSetup*) - testsetup; - -class TestSetup -{ - testsetup setup; - TestSetup next; - - auto static opCall(testsetup d) - { - auto obj = new TestSetup(); - obj.setup = d; - return obj; - } - - void run(ubyte opcode, CpuInfo cpu = CpuInfo(), Block[] data = [], - OpInfo info = OpInfo(), string msg = "") - { - setup(opcode, cpu, data, info, msg, &next); - } -} - -TestSetup connect(TestSetup first, TestSetup[] rest...) -{ - if (!(rest.empty)) - { - auto x = first; - while (x.next !is null) x = x.next; - x.next = connect(rest[0], rest[1..$]); - } - return first; -} - -template testCallNext() -{ - void callNext(string newMsg = "", Block[] newData = []) - { - if (*next !is null) - next.run(opcode, cpu, data ~ newData, info, msg ~ newMsg); - } -} - - // Does nothing. auto setup_none() { From 23b0a96c1c3f3a4bba1c493b417d32fc726bea92 Mon Sep 17 00:00:00 2001 From: edmccard Date: Sat, 14 Apr 2012 06:33:56 -0400 Subject: [PATCH 26/27] Add cpu reset. --- src/cpu/ctfe_d6502.d | 18 +++++++++--------- src/cpu/d6502.d | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/cpu/ctfe_d6502.d b/src/cpu/ctfe_d6502.d index 1bd0890..e9eeb19 100644 --- a/src/cpu/ctfe_d6502.d +++ b/src/cpu/ctfe_d6502.d @@ -495,7 +495,7 @@ string Nop(int mode) if (mode == IMP || mode == NP1 || mode == NP8) return ""; else - return PreAccess() ~ + return Tick() ~ ReadRaw("address") ~ ";\n"; } @@ -1013,7 +1013,7 @@ string CheckShortcut(string base, string addr, string chip, int exCyc) string ReadInto(string var, string action, string addr) { - return PreAccess() ~ + return Tick() ~ var ~ " " ~ action ~ " " ~ ReadRaw("(" ~ addr ~ ")") ~ ";\n"; } @@ -1074,27 +1074,27 @@ string ReadWordOp(string var) return ReadWordOp("", var); } -string PreAccess() +string Tick() { return If!(cumulative)("++cycles;\n", Attr("clock") ~ ".tick();\n"); } string Peek(string addr) { - return PreAccess() ~ + return Tick() ~ If!(strict)(Attr("memory") ~ ".read(" ~ addr ~");\n"); } string Poke(string addr, string val) { - return PreAccess() ~ + return Tick() ~ If!(strict)( Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"); } string Write(string addr, string val) { - return PreAccess() ~ + return Tick() ~ Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"; } @@ -1118,7 +1118,7 @@ string PullStatus() { return Peek(STACK) ~ IncSP() ~ - PreAccess() ~ + Tick() ~ Attr("statusFromByte") ~ "(" ~ ReadRaw(STACK) ~ ");\n"; } @@ -1151,13 +1151,13 @@ string PullPC() string LoadLoByte(string type, string var, string addr) { - return PreAccess() ~ + return Tick() ~ Local(type, var) ~ " = " ~ ReadRaw(addr) ~ ";\n"; } string LoadHiByte(string var, string addr) { - return PreAccess() ~ + return Tick() ~ var ~ " |= (" ~ ReadRaw(addr) ~ " << 8);\n"; } diff --git a/src/cpu/d6502.d b/src/cpu/d6502.d index 10178c8..5cc5e2e 100644 --- a/src/cpu/d6502.d +++ b/src/cpu/d6502.d @@ -102,6 +102,8 @@ if (__traits(compiles, { } bool keepRunning; + bool signalActive; + bool resetLow; final void run(bool continuous) { @@ -115,25 +117,42 @@ if (__traits(compiles, { } do { - version(Cumulative) - { - static if (!opArray) cycles = 1; - } - else - { - clock.tick(); - } - // XXX check signals, NMI/IRQ delays, etc. + version(Cumulative) { static if (!opArray) cycles = 1; } + else { clock.tick(); } + if (signalActive) handleSignals(); opcode = memory.read(PC++); mixin(OpExecute(_chip)); } while (keepRunning); } + // TODO: irq/nmi + void handleSignals() + { + if (resetLow) doReset(); + // XXX fix when more than one signal + signalActive = resetLow; + } + + void doReset() + { + mixin(Tick() ~ Tick() ~ + Peek(STACK) ~ DecSP() ~ + Peek(STACK) ~ DecSP() ~ + Peek(STACK) ~ DecSP()); + + I = true; + resetLow = false; + + mixin(ReadWord(_PC, "RESET_VECTOR") ~ + Done()); + } + version(OpDelegates) mixin (OpMethods(_chip)); } enum ushort IRQ_VECTOR = 0xFFFE; +enum ushort RESET_VECTOR = 0xFFFC; //alias Cpu!("6502", false, false) T1; From d100f706fc92c8e7662c64e6d40b43aff58451a2 Mon Sep 17 00:00:00 2001 From: edmccard Date: Sat, 14 Apr 2012 07:28:11 -0400 Subject: [PATCH 27/27] Integrate new cpu --- src/Makefile | 5 +- src/d6502/base.d | 164 --------- src/d6502/cmos.d | 266 --------------- src/d6502/cpu.d | 751 ------------------------------------------ src/d6502/nmosbase.d | 71 ---- src/d6502/nmosundoc.d | 365 -------------------- src/system/base.d | 238 +++++-------- src/twoapple.d | 22 +- src/ui/mainwindow.d | 4 +- 9 files changed, 97 insertions(+), 1789 deletions(-) delete mode 100644 src/d6502/base.d delete mode 100644 src/d6502/cmos.d delete mode 100644 src/d6502/cpu.d delete mode 100644 src/d6502/nmosbase.d delete mode 100644 src/d6502/nmosundoc.d diff --git a/src/Makefile b/src/Makefile index e8b8661..74bd283 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,12 +1,13 @@ COMPILE_OPTS = -op -Jdata -I$(GTKD)/src \ -I$(GTKD)/srcgl -I$(DERELICT)/import \ - -inline -release -O -noboundscheck + -inline -release -O -noboundscheck \ + -version=OpNestedSwitch LINK_OPTS = -L-lpthread -L-lGL -L-ldl -L-lX11 \ -L-L$(GTKD) -L-lgtkd -L-lgtkdgl \ -L-L$(DERELICT)/lib -L-lDerelictSDL -L-lDerelictUtil -ALL_SRC = $(shell find -name "*.d" \! -path "./cpu/*") +ALL_SRC = $(shell find -name "*.d" \! -name "ctfe*") all: ${ALL_SRC} dmd $(COMPILE_OPTS) ${ALL_SRC} -oftwoapple ${LINK_OPTS} diff --git a/src/d6502/base.d b/src/d6502/base.d deleted file mode 100644 index 1085e19..0000000 --- a/src/d6502/base.d +++ /dev/null @@ -1,164 +0,0 @@ -/+ - + d6502/base.d - + - + Copyright: 2007 Gerald Stocker - + - + This file is part of twoapple-reboot. - + - + twoapple-reboot is free software; you can redistribute it and/or modify - + it under the terms of the GNU General Public License as published by - + the Free Software Foundation; either version 2 of the License, or - + (at your option) any later version. - + - + twoapple-reboot is distributed in the hope that it will be useful, - + but WITHOUT ANY WARRANTY; without even the implied warranty of - + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - + GNU General Public License for more details. - + - + You should have received a copy of the GNU General Public License - + along with twoapple-reboot; if not, write to the Free Software - + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - +/ - -module d6502.base; - -enum Strict : bool -{ - no, yes -} - -enum Cumulative : bool -{ - no, yes -} - -string hexByte(int decByte) -{ - int highNybble = (decByte & 0xF0) >> 4; - int lowNybble = decByte & 0x0F; - - string digits = "0123456789ABCDEF"; - - return digits[highNybble..(highNybble + 1)] ~ - digits[lowNybble..(lowNybble + 1)]; -} - -final class StatusRegister -{ - bool carry, decimal, interrupt, overflow; - ubyte zero_, negative_; - - ubyte toByte() - { - return (carry ? 0x01 : 0) | - ((zero_ == 0) ? 0x02 : 0) | - (interrupt ? 0x04 : 0) | - (decimal ? 0x08 : 0) | - 0x30 | // break and reserved both set - (overflow ? 0x40 : 0) | - (negative_ & 0x80); - } - - void fromByte(ubyte val) - { - carry = ((val & 0x01) != 0); - zero_ = ((val & 0x02) ? 0 : 1); - interrupt = ((val & 0x04) != 0); - decimal = ((val & 0x08) != 0); - overflow = ((val & 0x40) != 0); - negative_ = val; - } -} - -class CpuBase(bool strict, bool cumulative) -{ - enum _isCpuBase = true; - static if (strict) enum _isStrict = true; - static if (cumulative) enum _isCumulative = true; - - static string AbstractOpcodes() - { - string abstractOpcodes; - for (int op = 0; op < 256; ++op) - abstractOpcodes ~= "abstract void opcode" ~ hexByte(op) ~ "();\n"; - return abstractOpcodes; - } - - mixin(AbstractOpcodes()); - - ushort programCounter; - ubyte accumulator, xIndex, yIndex, stackPointer; - StatusRegister flag; - - bool signalActive, irqActive, resetActive, nmiActive, nmiArmed; - - ushort opcodePC; - ubyte opcode, operand1, operand2; - - final ubyte[] save() - { - ubyte[] data = new ubyte[12]; - data[0] = programCounter & 0xFF; - data[1] = programCounter >> 8; - data[2] = accumulator; - data[3] = xIndex; - data[4] = yIndex; - data[5] = stackPointer; - data[6] = flag.toByte(); - data[7] = (signalActive ? 1 : 0); - data[8] = (irqActive ? 1 : 0); - data[9] = (resetActive ? 1 : 0); - data[10] = (nmiActive ? 1 : 0); - data[11] = (nmiArmed ? 1 : 0); - return data; - } - - final void restore(ubyte[] data) - { - assert (data.length >= 12); - - programCounter = data[0] | (data[1] << 8); - accumulator = data[2]; - xIndex = data[3]; - yIndex = data[4]; - stackPointer = data[5]; - flag.fromByte(data[6]); - signalActive = ((data[7] == 0) ? false : true); - irqActive = ((data[8] == 0) ? false : true); - resetActive = ((data[9] == 0) ? false : true); - nmiActive = ((data[10] == 0) ? false : true); - nmiArmed = ((data[11] == 0) ? false : true); - } - - final void reboot() - { - restore([0, 0, 0, 0, 0, 0xFF, 0, 0, 0, 0, 0, 1]); - } - - struct _Mem - { - ubyte delegate(ushort addr) read; - void delegate(ushort addr, ubyte val) write; - } - _Mem memory; - - struct _Clock - { - static if (cumulative) - void delegate(int cycles) tick; - else - void delegate() tick; - } - _Clock clock; - - debug(disassemble) - { - string delegate(ushort addr) memoryName; - } - - abstract void run(bool continuous); - abstract void stop(); - abstract void resetLow(); - abstract void nmiLow(bool signalLow); - abstract void irqLow(bool signalLow); -} diff --git a/src/d6502/cmos.d b/src/d6502/cmos.d deleted file mode 100644 index f736676..0000000 --- a/src/d6502/cmos.d +++ /dev/null @@ -1,266 +0,0 @@ -/+ - + d6502/cmos.d - + - + Copyright: 2007 Gerald Stocker - + - + This file is part of twoapple-reboot. - + - + twoapple-reboot is free software; you can redistribute it and/or modify - + it under the terms of the GNU General Public License as published by - + the Free Software Foundation; either version 2 of the License, or - + (at your option) any later version. - + - + twoapple-reboot is distributed in the hope that it will be useful, - + but WITHOUT ANY WARRANTY; without even the implied warranty of - + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - + GNU General Public License for more details. - + - + You should have received a copy of the GNU General Public License - + along with twoapple-reboot; if not, write to the Free Software - + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - +/ - -module d6502.cmos; - -import d6502.base; -import d6502.cpu; - -class Cmos(bool strict, bool cumulative) : Cpu!(strict, cumulative) -{ - enum _isCMOS = true; - - this() - { - super(); - spuriousAddress = &programCounter; - } - - final override void do_IRQ_or_NMI(ushort vector) - { - super.do_IRQ_or_NMI(vector); - flag.decimal = false; - } - - final override void doReset() - { - super.doReset(); - flag.decimal = false; - } - - final override void dec_addWithCarry(ubyte val) - { - super.dec_addWithCarry(val); - peek(programCounter); - // TODO: fix this - static if (cumulative) tick(1); - flag.zero_ = flag.negative_ = accumulator; - } - - final override void dec_subWithCarry(ubyte val) - { - int a = accumulator; - int al = (a & 0x0F) - (val & 0x0F) - !flag.carry; - a = a - val - !flag.carry; - if (a < 0) - a = a - 0x60; - if (al < 0) - a = a - 0x06; - - uint diff = accumulator - val - !flag.carry; - flag.overflow = - ((accumulator ^ diff) & 0x80) && - ((accumulator ^ val) & 0x80); - flag.carry = (diff < 0x100); - - peek(programCounter); - // TODO: fix this - static if (cumulative) tick(1); - flag.zero_ = flag.negative_ = accumulator = cast(ubyte)a; - } - - final void addrZeropageI() - { - ubyte vector = readByteOperand(); - primaryAddress = readWord(vector, cast(ubyte)(vector + 1)); - } - - final void addrNone() - { - static if (cumulative) tick(totalCycles); - } - - final ubyte testSet(ubyte val) - { - flag.zero_ = val & accumulator; - return val | accumulator; - } - - final ubyte testReset(ubyte val) - { - flag.zero_ = val & accumulator; - return val & ~accumulator; - } - - static string RMW(string action) - { - return "peek(primaryAddress);\n" ~ - "writeFinal(primaryAddress, (flag.zero_ = flag.negative_ = " ~ - action ~ "(readVal = read(primaryAddress))));\n"; - } - - static string TestModify(string action) - { - return "peek(primaryAddress);\n" ~ - "writeFinal(primaryAddress, " ~ - action ~ "(readVal = read(primaryAddress)));\n"; - } - - static string ReadNOP() - { - return "readVal = readFinal(primaryAddress);\n"; - } - - static string ManualAddress(string name, int[] opcodes, - string mode) - { - string modes = "[[\"" ~ name ~ "\", \"NA\"], \n"; - for (int op = 0; op < opcodes.length; ++op) - { - int opcode = opcodes[op]; - modes ~= "[\"" ~ hexByte(opcode) ~ "\", \"" ~ mode ~ "\"]"; - if (op != (opcodes.length - 1)) modes ~= ", "; - modes ~= "\n"; - } - return modes ~ "]\n"; - } - - mixin(Opcode(mixin(Type2Address( - "ASL", "Read", [0x06, 0x0E, 0x16, 0x1E])), - RMW("shiftLeft"))); - mixin(Opcode(mixin(Type2Address( - "LSR", "Read", [0x46, 0x4E, 0x56, 0x5E])), - RMW("shiftRight"))); - mixin(Opcode(mixin(Type2Address( - "ROL", "Read", [0x26, 0x2E, 0x36, 0x3E])), - RMW("rotateLeft"))); - mixin(Opcode(mixin(Type2Address( - "ROR", "Read", [0x66, 0x6E, 0x76, 0x7E])), - RMW("rotateRight"))); - mixin(Opcode(mixin(Type2Address( - "INC", "Read", [0xE6, 0xEE, 0xF6])), - RMW("increment"))); - mixin(Opcode(mixin(Type2Address( - "DEC", "Read", [0xC6, 0xCE, 0xD6])), - RMW("decrement"))); - mixin(Opcode(mixin(Type2Address( - "INC", "Write", [0xFE])), - RMW("increment"))); - mixin(Opcode(mixin(Type2Address( - "DEC", "Write", [0xDE])), - RMW("decrement"))); - - - mixin(Opcode(mixin(Type2Address( - "BIT", "Read", [0x34, 0x3C])), - BitTest())); - mixin(Opcode([["ORA", "Read"], ["12", "ZeropageI()"]], - Read("accumulator |="))); - mixin(Opcode([["AND", "Read"], ["32", "ZeropageI()"]], - Read("accumulator &="))); - mixin(Opcode([["EOR", "Read"], ["52", "ZeropageI()"]], - Read("accumulator ^="))); - mixin(Opcode([["LDA", "Read"], ["B2", "ZeropageI()"]], - Read("accumulator ="))); - mixin(Opcode([["CMP", "Read"], ["D2", "ZeropageI()"]], - Compare("accumulator"))); - mixin(Opcode([["ADC", "Read"], ["72", "ZeropageI()"]], - Decimal("addWithCarry"))); - mixin(Opcode([["SBC", "Read"], ["F2", "ZeropageI()"]], - Decimal("subWithCarry"))); - mixin(Opcode([["STA", "Write"], ["92", "ZeropageI()"]], - Write("accumulator"))); - - mixin(RegisterOpcode("DEA", "3A", "accumulator -= 1")); - mixin(RegisterOpcode("INA", "1A", "accumulator += 1")); - mixin(SimpleOpcode("PHX", "DA", "push(xIndex)")); - mixin(SimpleOpcode("PHY", "5A", "push(yIndex)")); - mixin(RegisterOpcode("PLX", "FA", "xIndex = pull()")); - mixin(RegisterOpcode("PLY", "7A", "yIndex = pull()")); - mixin(BranchOpcode("BRA", "80", "true")); - - mixin(Opcode([["TRB", "Read"], - ["14", "Zeropage()"], ["1C", "Absolute"]], - TestModify("testReset"))); - mixin(Opcode(mixin(Type2Address( - "TSB", "Read", [0x04, 0x0C])), - TestModify("testSet"))); - mixin(Opcode([["STZ", "Write"], - ["64", "Zeropage()"], ["74", "ZeropageX()"], - ["9C", "Absolute()"], ["9E", "AbsoluteX(true)"]], - Write("0"))); - - mixin(Opcode(mixin(ManualAddress( - "NOP", [0x02, 0x22, 0x42, 0x62, 0x82, 0xC2, 0xE2], - "Immediate")), - ReadNOP())); - mixin(Opcode(mixin(ManualAddress( - "NOP", [0x44], - "Zeropage()")), - ReadNOP())); - mixin(Opcode(mixin(ManualAddress( - "NOP", [0x54, 0xD4, 0xF4], - "ZeropageX()")), - ReadNOP())); - mixin(Opcode(mixin(ManualAddress( - "NOP", [0xDC, 0xFC], - "AbsoluteX(false)")), - ReadNOP())); - mixin(Opcode(mixin(ManualAddress( - "NOP", [0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73, 0x83, 0x93, - 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3, 0x07, 0x17, 0x27, 0x37, - 0x47, 0x57, 0x67, 0x77, 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, - 0xE7, 0xF7, 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B, - 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB, 0x0F, 0x1F, - 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F, 0x8F, 0x9F, 0xAF, 0xBF, - 0xCF, 0xDF, 0xEF, 0xFF], "None()")), - "")); - - /* NOP8 */ - void opcode5C() - { - readByteOperand(); - peek(programCounter++); - peek(0xFF00 | operand1); - peek(0xFFFF); - peek(0xFFFF); - peek(0xFFFF); - peek(0xFFFF); - static if (cumulative) tick(totalCycles); - } - - /* JMP ($$$$) */ - override void opcode6C() - { - ushort vector = readWordOperand(); - peek(programCounter); - programCounter = readWord(vector, cast(ushort)(vector + 1)); - static if (cumulative) tick(totalCycles); - } - - /* JMP ($$$$,X) */ - void opcode7C() - { - baseAddress = readWordOperand(); - peek(programCounter); - ushort vector = cast(ushort)(baseAddress + xIndex); - programCounter = readWord(vector, cast(ushort)(vector + 1)); - static if (cumulative) tick(totalCycles); - } - - /* BIT #$$ */ - void opcode89() - { - readVal = operand1 = readFinal(programCounter++); - flag.zero_ = accumulator & readVal; - } -} diff --git a/src/d6502/cpu.d b/src/d6502/cpu.d deleted file mode 100644 index e226afa..0000000 --- a/src/d6502/cpu.d +++ /dev/null @@ -1,751 +0,0 @@ -/+ - + d6502/cpu.d - + - + Copyright: 2007 Gerald Stocker - + - + This file is part of twoapple-reboot. - + - + twoapple-reboot is free software; you can redistribute it and/or modify - + it under the terms of the GNU General Public License as published by - + the Free Software Foundation; either version 2 of the License, or - + (at your option) any later version. - + - + twoapple-reboot is distributed in the hope that it will be useful, - + but WITHOUT ANY WARRANTY; without even the implied warranty of - + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - + GNU General Public License for more details. - + - + You should have received a copy of the GNU General Public License - + along with twoapple-reboot; if not, write to the Free Software - + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - +/ - -module d6502.cpu; - -import d6502.base; - -class Cpu(bool strict, bool cumulative) : CpuBase!(strict, cumulative) -{ - static string InitOpcodes() - { - string initCalls; - for (int op = 0; op < 256; ++op) - { - initCalls ~= "opcodes[0x" ~ hexByte(op) ~ "] = &opcode" ~ - hexByte(op) ~ ";\n"; - } - return initCalls; - } - - this() - { - mixin(InitOpcodes()); - flag = new StatusRegister(); - } - - const ushort STACK_BASE = 0x0100; - const ushort NMI_VECTOR = 0xFFFA; - const ushort RESET_VECTOR = 0xFFFC; - const ushort IRQ_VECTOR = 0xFFFE; - - void delegate()[256] opcodes; - bool continueExecution; - static if (cumulative) int totalCycles; - - - debug(disassemble) - { - import hacking.debugger; - import std.stdio; - } - final override void run(bool continuous) - { - assert ((memory.read !is null) && (memory.write !is null)); - assert (clock.tick !is null); - - continueExecution = continuous; - do - { - if (signalActive) handleSignals(); - - static if (cumulative) totalCycles = 0; - opcodePC = programCounter; - opcode = read(programCounter++); - - /+ TODO: call sync delegate +/ - - opcodes[opcode](); - debug(disassemble) - { - writefln(Debugger.disassemble(this, cmosMap) - ~ Debugger.displayRegisters(this)); - } - } while (continueExecution); - } - - final override void stop() - { - continueExecution = false; - } - - final override void resetLow() - { - resetActive = signalActive = true; - } - - final override void nmiLow(bool signalLow) - { - nmiActive = signalLow; - if (!signalLow) nmiArmed = true; - signalActive = testSignals(); - } - - final override void irqLow(bool signalLow) - { - irqActive = signalLow; - signalActive = testSignals(); - } - - final bool testSignals() - { - return (resetActive || nmiActive || irqActive); - } - - final void handleSignals() - { - bool checkNMI() - { - if (nmiActive && nmiArmed) - { - nmiArmed = false; - return true; - } - return false; - } - - if (resetActive) doReset(); - else if (checkNMI()) do_IRQ_or_NMI(NMI_VECTOR); - else if ((!flag.interrupt) && irqActive) do_IRQ_or_NMI(IRQ_VECTOR); - } - - void do_IRQ_or_NMI(ushort vector) - { - doInterrupt(vector, (flag.toByte() & ~0x10)); - } - - final void doInterrupt(ushort vector, ubyte statusByte) - { - pushWord(programCounter); - push(statusByte); - flag.interrupt = true; - programCounter = readWord(vector, cast(ushort)(vector + 1)); - static if (cumulative) clock.tick(totalCycles); - } - - void doReset() - { - static if (cumulative) - { - totalCycles += 2; - } - else - { - clock.tick(); clock.tick(); - } - - peek(STACK_BASE + stackPointer); - --stackPointer; - peek(STACK_BASE + stackPointer); - --stackPointer; - peek(STACK_BASE + stackPointer); - --stackPointer; - - flag.interrupt = true; - resetActive = false; - signalActive = testSignals(); - - programCounter = readWord(RESET_VECTOR, RESET_VECTOR + 1); - static if (cumulative) clock.tick(totalCycles); - } - - final ubyte read(ushort addr) - { - static if (cumulative) ++totalCycles; - else clock.tick(); - return memory.read(addr); - } - - final void write(ushort addr, ubyte val) - { - static if (cumulative) ++totalCycles; - else clock.tick(); - memory.write(addr, val); - } - - final void peek(ushort addr) - { - static if (cumulative) ++totalCycles; - else clock.tick(); - static if (strict) memory.read(addr); - } - - final void poke(ushort addr, ubyte val) - { - static if (cumulative) ++totalCycles; - else clock.tick(); - static if (strict) memory.write(addr, val); - } - - final ubyte readFinal(ushort addr) - { - static if (cumulative) clock.tick(++totalCycles); - else - { - clock.tick(); - } - return memory.read(addr); - } - - final void writeFinal(ushort addr, ubyte val) - { - static if (cumulative) clock.tick(++totalCycles); - else - { - clock.tick(); - } - memory.write(addr, val); - } - - final ushort readWord(ushort addrLo, ushort addrHi) - { - ushort word = read(addrLo); - return word | (read(addrHi) << 8); - } - - final void push(ubyte val) - { - write((STACK_BASE + stackPointer), val); - --stackPointer; - /+ TODO: call stack overflow delegate +/ - } - - - final void pushWord(ushort val) - { - push(val >> 8); - push(val & 0xFF); - } - - final ubyte readStack() - { - ++stackPointer; - /+ TODO: call stack underflow delegate +/ - return read(STACK_BASE + stackPointer); - } - - final ubyte pull() - { - peek(STACK_BASE + stackPointer); - return readStack(); - } - - final ushort pullWord() - { - ushort word = pull(); - return word | (readStack() << 8); - } - - final ubyte readByteOperand() - { - return (operand1 = read(programCounter++)); - } - - final ushort readWordOperand() - { - operand1 = read(programCounter++); - operand2 = read(programCounter++); - return (operand1 | (operand2 << 8)); - } - - ushort* spuriousAddress; - ushort badAddress, baseAddress, primaryAddress; - ubyte readVal, writeVal; - - final ushort tryShortcut(bool noShortcut, ushort goodAddress) - { - badAddress = (baseAddress & 0xFF00) | cast(ubyte)goodAddress; - if (badAddress != goodAddress) - peek(*spuriousAddress); - else if (noShortcut) - peek(goodAddress); - return goodAddress; - } - - final void addrRelative(byte offset) - { - peek(programCounter); - baseAddress = programCounter; - programCounter = tryShortcut(false, - cast(ushort)(programCounter + offset)); - } - - final void addrZeropage() - { - primaryAddress = readByteOperand(); - } - - final void addrAbsolute() - { - primaryAddress = readWordOperand(); - } - - final void addrZeropageX() - { - baseAddress = badAddress = readByteOperand(); - peek(*spuriousAddress); - primaryAddress = cast(ubyte)(baseAddress + xIndex); - } - - final void addrZeropageY() - { - baseAddress = badAddress = readByteOperand(); - peek(*spuriousAddress); - primaryAddress = cast(ubyte)(baseAddress + yIndex); - } - - final void addrIndirectX() - { - baseAddress = badAddress = readByteOperand(); - peek(*spuriousAddress); - ushort vector = cast(ubyte)(baseAddress + xIndex); - primaryAddress = readWord(vector, cast(ubyte)(vector + 1)); - } - - final void addrAbsoluteX(bool write) - { - baseAddress = readWordOperand(); - primaryAddress = tryShortcut(write, - cast(ushort)(baseAddress + xIndex)); - } - - final void addrAbsoluteY(bool write) - { - baseAddress = readWordOperand(); - primaryAddress = tryShortcut(write, - cast(ushort)(baseAddress + yIndex)); - } - - final void addrIndirectY(bool write) - { - ubyte vector = readByteOperand(); - baseAddress = readWord(vector, cast(ubyte)(vector + 1)); - primaryAddress = tryShortcut(write, - cast(ushort)(baseAddress + yIndex)); - } - - void dec_addWithCarry(ubyte val) - { - int a = accumulator; - int al = (a & 0x0F) + (val & 0x0F) + flag.carry; - if (al >= 0x0A) - al = ((al + 0x06) & 0x0F) + 0x10; - a = (a & 0xF0) + (val & 0xF0) + al; - - flag.negative_ = cast(ubyte)a; - flag.zero_ = cast(ubyte)(accumulator + val + flag.carry); - flag.overflow = - (!((accumulator ^ val) & 0x80)) && ((val ^ a) & 0x80); - - if (a >= 0xA0) - a = a + 0x60; - - flag.carry = (a >= 0x100); - accumulator = cast(ubyte)a; - } - - void dec_subWithCarry(ubyte val) - { - int a = accumulator; - int al = (a & 0x0F) - (val & 0x0F) - !flag.carry; - if (al < 0) - al = ((al - 0x06) & 0x0F) - 0x10; - a = (a & 0xF0) - (val & 0xF0) + al; - if (a < 0) - a = a - 0x60; - - uint diff = accumulator - val - !flag.carry; - flag.overflow = - ((accumulator ^ diff) & 0x80) && - ((accumulator ^ val) & 0x80); - flag.carry = (diff < 0x100); - flag.zero_ = flag.negative_ = cast(ubyte)diff; - - accumulator = cast(ubyte)a; - } - - final void hex_addWithCarry(ubyte val) - { - uint sum = accumulator + val + flag.carry; - - flag.overflow = - (!((accumulator ^ val) & 0x80)) && ((val ^ sum) & 0x80); - flag.carry = (sum > 0xFF); - - flag.zero_ = flag.negative_ = (accumulator = cast(ubyte)sum); - } - - final void hex_subWithCarry(ubyte val) - { - uint diff = accumulator - val - (flag.carry ? 0 : 1); - - flag.overflow = - ((accumulator ^ diff) & 0x80) && - ((accumulator ^ val) & 0x80); - flag.carry = (diff < 0x100); - - flag.zero_ = flag.negative_ = (accumulator = cast(ubyte)diff); - } - - final ubyte compare(ubyte reg, ubyte val) - { - flag.carry = (reg >= val); - return cast(ubyte)(reg - val); - } - - final void bitTest(ubyte val) - { - flag.negative_ = val; - flag.zero_ = accumulator & val; - flag.overflow = ((val & 0x40) != 0); - } - - final ubyte shiftLeft(ubyte val) - { - flag.carry = (val > 0x7F); - return cast(ubyte)(val << 1); - } - - final ubyte rotateLeft(ubyte val) - { - bool oldCarry = flag.carry; - flag.carry = (val > 0x7F); - val = cast(ubyte)(val << 1 | (oldCarry ? 1 : 0)); - return val; - } - - final ubyte shiftRight(ubyte val) - { - flag.carry = ((val & 0x01) != 0); - return val >> 1; - } - - final ubyte rotateRight(ubyte val) - { - bool oldCarry = flag.carry; - flag.carry = ((val & 0x01) != 0); - val = (val >> 1 | (oldCarry ? 0x80 : 0)); - return val; - } - - final ubyte increment(ubyte val) - { - return cast(ubyte)(val + 1); - } - - final ubyte decrement(ubyte val) - { - return cast(ubyte)(val - 1); - } - - static string SimpleOpcode(string name, string opcode, string action) - { - string code = "peek(programCounter);\n"; - code ~= (action == "") ? "" : (action ~ ";"); - static if (cumulative) code ~= "clock.tick(totalCycles);\n"; - return "override void opcode" ~ opcode ~ "()\n{\n" ~ code ~ "\n}\n"; - } - - static string UpdateNZ(string action) - { - return "flag.zero_ = flag.negative_ = (" ~ action ~ ");" ~ "\n"; - } - - static string RegisterOpcode(string name, string opcode, string action) - { - string code = "peek(programCounter);\n"; - code ~= UpdateNZ(action); - static if (cumulative) code ~= "clock.tick(totalCycles);\n"; - return "override void opcode" ~ opcode ~ "()\n{\n" ~ code ~ "}\n"; - } - - static string BranchOpcode(string name, string opcode, string action) - { - string code = "readByteOperand();\n" ~ - "if (" ~ action ~ ") addrRelative(cast(byte)operand1);\n"; - static if (cumulative) code ~= "clock.tick(totalCycles);\n"; - return "override void opcode" ~ opcode ~ "()\n{\n" ~ code ~ "}\n"; - } - - static string Type1Address(string name, string rw, int[] opcodes) - { - string type = (rw == "Write") ? "true" : "false"; - string modes = "[[\"" ~ name ~ "\", \"" ~ rw ~ "\"], \n"; - for (int op = 0; op < opcodes.length; ++op) - { - int opcode = opcodes[op]; - modes ~= "[\"" ~ hexByte(opcode) ~ "\", \""; - final switch ((opcode & 0b00011100) >> 2) - { - case 0: - modes ~= "IndirectX()"; - break; - case 1: - modes ~= "Zeropage()"; - break; - case 2: - modes ~= "Immediate"; - break; - case 3: - modes ~= "Absolute()"; - break; - case 4: - modes ~= "IndirectY("~ type ~ ")"; - break; - case 5: - modes ~= "ZeropageX()"; - break; - case 6: - modes ~= "AbsoluteY(" ~ type ~ ")"; - break; - case 7: - modes ~= "AbsoluteX(" ~ type ~ ")"; - break; - } - modes ~= "\"]"; - if (op != (opcodes.length - 1)) modes ~= ", "; - modes ~= "\n"; - } - return modes ~ "]\n"; - } - - static string Type2Address(string name, string rw, int[] opcodes) - { - string type = (rw == "Write") ? "true" : "false"; - string index = (name[2] == 'X') ? "Y" : "X"; - string modes = "[[\"" ~ name ~ "\", \"" ~ rw ~ "\"], \n"; - for (int op = 0; op < opcodes.length; ++op) - { - int opcode = opcodes[op]; - modes ~= "[\"" ~ hexByte(opcode) ~ "\", \""; - final switch ((opcode & 0b00011100) >> 2) - { - case 0: - modes ~= "Immediate"; - break; - case 1: - modes ~= "Zeropage()"; - break; - case 3: - modes ~= "Absolute()"; - break; - case 5: - modes ~= "Zeropage" ~ index ~ "()"; - break; - case 7: - modes ~= "Absolute" ~ index ~ "(" ~ type ~ ")"; - break; - } - modes ~= "\"]"; - if (op != (opcodes.length - 1)) modes ~= ", "; - modes ~= "\n"; - } - return modes ~ "]\n"; - } - - static string Opcode(string[][] details, string action) - { - string methods; - for (int op = 1; op < details.length; ++op) - { - methods ~= "override void opcode" ~ details[op][0] ~ "()\n{\n"; - if (details[op][1] == "Immediate") - { - methods ~= "primaryAddress = programCounter++;\n" ~ - action ~ "operand1 = readVal;\n"; - } - else - { - methods ~= "addr" ~ details[op][1] ~ ";\n" ~ action; - } - methods ~= "}\n"; - } - return methods; - } - - static string Read(string action) - { - return UpdateNZ(action ~ " (readVal = readFinal(primaryAddress))"); - } - - static string Decimal(string action) - { - string code = action ~ "(readVal = readFinal(primaryAddress));\n"; - return "if (flag.decimal) dec_" ~ code ~ - "else hex_" ~ code; - } - - static string Compare(string action) - { - return UpdateNZ("compare(" ~ action ~ - ", (readVal = readFinal(primaryAddress)))"); - } - - static string Write(string action) - { - return "writeFinal(primaryAddress, " ~ action ~ ");\n"; - } - - static string BitTest() - { - return "bitTest(readVal = readFinal(primaryAddress));\n"; - } - - mixin(SimpleOpcode("CLC", "18", "flag.carry = false")); - mixin(SimpleOpcode("SEC", "38", "flag.carry = true")); - mixin(SimpleOpcode("CLI", "58", "flag.interrupt = false")); - mixin(SimpleOpcode("SEI", "78", "flag.interrupt = true")); - mixin(SimpleOpcode("CLV", "B8", "flag.overflow = false")); - mixin(SimpleOpcode("CLD", "D8", "flag.decimal = false")); - mixin(SimpleOpcode("SED", "F8", "flag.decimal = true")); - - mixin(SimpleOpcode("NOP", "EA", "")); - - mixin(SimpleOpcode("PHP", "08", "push(flag.toByte())")); - mixin(SimpleOpcode("PLP", "28", "flag.fromByte(pull())")); - mixin(SimpleOpcode("PHA", "48", "push(accumulator)")); - mixin(SimpleOpcode("TXS", "9A", "stackPointer = xIndex")); - - mixin(RegisterOpcode("PLA", "68", "accumulator = pull()")); - mixin(RegisterOpcode("TSX", "BA", "xIndex = stackPointer")); - - mixin(RegisterOpcode("TAX", "AA", "xIndex = accumulator")); - mixin(RegisterOpcode("TXA", "8A", "accumulator = xIndex")); - mixin(RegisterOpcode("DEX", "CA", "xIndex -= 1")); - mixin(RegisterOpcode("INX", "E8", "xIndex += 1")); - mixin(RegisterOpcode("TAY", "A8", "yIndex = accumulator")); - mixin(RegisterOpcode("TYA", "98", "accumulator = yIndex")); - mixin(RegisterOpcode("DEY", "88", "yIndex -= 1")); - mixin(RegisterOpcode("INY", "C8", "yIndex += 1")); - - mixin(BranchOpcode("BPL", "10", "flag.negative_ < 0x80")); - mixin(BranchOpcode("BMI", "30", "flag.negative_ > 0x7F")); - mixin(BranchOpcode("BVC", "50", "!flag.overflow")); - mixin(BranchOpcode("BVS", "70", "flag.overflow")); - mixin(BranchOpcode("BCC", "90", "!flag.carry")); - mixin(BranchOpcode("BCS", "B0", "flag.carry")); - mixin(BranchOpcode("BNE", "D0", "flag.zero_ != 0")); - mixin(BranchOpcode("BEQ", "F0", "flag.zero_ == 0")); - - mixin(RegisterOpcode("ASL A", "0A", - "accumulator = shiftLeft(accumulator)")); - mixin(RegisterOpcode("ROL A", "2A", - "accumulator = rotateLeft(accumulator)")); - mixin(RegisterOpcode("LSR A", "4A", - "accumulator = shiftRight(accumulator)")); - mixin(RegisterOpcode("ROR A", "6A", - "accumulator = rotateRight(accumulator)")); - - mixin(Opcode(mixin(Type1Address( - "LDA", "Read", [0xA1, 0xA5, 0xA9, 0xAD, 0xB1, 0xB5, 0xB9, 0xBD])), - Read("accumulator ="))); - mixin(Opcode(mixin(Type1Address( - "ORA", "Read", [0x01, 0x05, 0x09, 0x0D, 0x11, 0x15, 0x19, 0x1D])), - Read("accumulator |="))); - mixin(Opcode(mixin(Type1Address( - "AND", "Read", [0x21, 0x25, 0x29, 0x2D, 0x31, 0x35, 0x39, 0x3D])), - Read("accumulator &="))); - mixin(Opcode(mixin(Type1Address( - "EOR", "Read", [0x41, 0x45, 0x49, 0x4D, 0x51, 0x55, 0x59, 0x5D])), - Read("accumulator ^="))); - mixin(Opcode(mixin(Type1Address( - "ADC", "Read", [0x61, 0x65, 0x69, 0x6D, 0x71, 0x75, 0x79, 0x7D])), - Decimal("addWithCarry"))); - mixin(Opcode(mixin(Type1Address( - "SBC", "Read", [0xE1, 0xE5, 0xE9, 0xED, 0xF1, 0xF5, 0xF9, 0xFD])), - Decimal("subWithCarry"))); - mixin(Opcode(mixin(Type1Address( - "CMP", "Read", [0xC1, 0xC5, 0xC9, 0xCD, 0xD1, 0xD5, 0xD9, 0xDD])), - Compare("accumulator"))); - mixin(Opcode(mixin(Type1Address( - "STA", "Write", [0x81, 0x85, 0x8D, 0x91, 0x95, 0x99, 0x9D])), - Write("accumulator"))); - - mixin(Opcode(mixin(Type2Address( - "LDX", "Read", [0xA2, 0xA6, 0xAE, 0xB6, 0xBE])), - Read("xIndex ="))); - mixin(Opcode(mixin(Type2Address( - "LDY", "Read", [0xA0, 0xA4, 0xAC, 0xB4, 0xBC])), - Read("yIndex ="))); - mixin(Opcode(mixin(Type2Address( - "CPX", "Read", [0xE0, 0xE4, 0xEC])), - Compare("xIndex"))); - mixin(Opcode(mixin(Type2Address( - "CPY", "Read", [0xC0, 0xC4, 0xCC])), - Compare("yIndex"))); - mixin(Opcode(mixin(Type2Address( - "STX", "Write", [0x86, 0x8E, 0x96])), - Write("xIndex"))); - mixin(Opcode(mixin(Type2Address( - "STY", "Write", [0x84, 0x8C, 0x94])), - Write("yIndex"))); - mixin(Opcode(mixin(Type2Address( - "BIT", "Read", [0x24, 0x2C])), - BitTest())); - - /* BRK */ - final override void opcode00() - { - peek(programCounter); - ++programCounter; - doInterrupt(IRQ_VECTOR, flag.toByte()); - } - - /* JSR */ - final override void opcode20() - { - ushort finalAddress = (operand1 = read(programCounter++)); - - peek(STACK_BASE + stackPointer); - pushWord(programCounter); - - finalAddress |= ((operand2 = read(programCounter)) << 8); - static if (cumulative) clock.tick(totalCycles); - programCounter = finalAddress; - } - - /* RTI */ - final override void opcode40() - { - peek(programCounter); - flag.fromByte(pull()); - programCounter = readStack() | (readStack() << 8); - static if (cumulative) clock.tick(totalCycles); - } - - /* JMP $$$$ */ - final override void opcode4C() - { - programCounter = readWordOperand(); - static if (cumulative) clock.tick(totalCycles); - } - - /* RTS */ - final override void opcode60() - { - peek(programCounter); - programCounter = pullWord(); - peek(programCounter); - static if (cumulative) clock.tick(totalCycles); - ++programCounter; - } -} diff --git a/src/d6502/nmosbase.d b/src/d6502/nmosbase.d deleted file mode 100644 index 2a2e2b9..0000000 --- a/src/d6502/nmosbase.d +++ /dev/null @@ -1,71 +0,0 @@ -/+ - + d6502/nmosbase.d - + - + Copyright: 2007 Gerald Stocker - + - + This file is part of twoapple-reboot. - + - + twoapple-reboot is free software; you can redistribute it and/or modify - + it under the terms of the GNU General Public License as published by - + the Free Software Foundation; either version 2 of the License, or - + (at your option) any later version. - + - + twoapple-reboot is distributed in the hope that it will be useful, - + but WITHOUT ANY WARRANTY; without even the implied warranty of - + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - + GNU General Public License for more details. - + - + You should have received a copy of the GNU General Public License - + along with twoapple-reboot; if not, write to the Free Software - + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - +/ - -module d6502.nmosbase; - -import d6502.cpu; - -class NmosBase(bool strict, bool cumulative) : Cpu!(strict, cumulative) -{ - enum _isNMOS = true; - - this() - { - super(); - spuriousAddress = &badAddress; - } - - static string RMW(string action) - { - return "poke(primaryAddress, (readVal = read(primaryAddress)));\n" ~ - "writeFinal(primaryAddress, flag.zero_ = flag.negative_ = " ~ - action ~ "(readVal));\n"; - } - - mixin(Opcode(mixin(Type2Address( - "ASL", "Write", [0x06, 0x0E, 0x16, 0x1E])), - RMW("shiftLeft"))); - mixin(Opcode(mixin(Type2Address( - "LSR", "Write", [0x46, 0x4E, 0x56, 0x5E])), - RMW("shiftRight"))); - mixin(Opcode(mixin(Type2Address( - "ROL", "Write", [0x26, 0x2E, 0x36, 0x3E])), - RMW("rotateLeft"))); - mixin(Opcode(mixin(Type2Address( - "ROR", "Write", [0x66, 0x6E, 0x76, 0x7E])), - RMW("rotateRight"))); - mixin(Opcode(mixin(Type2Address( - "INC", "Write", [0xE6, 0xEE, 0xF6, 0xFE])), - RMW("increment"))); - mixin(Opcode(mixin(Type2Address( - "DEC", "Write", [0xC6, 0xCE, 0xD6, 0xDE])), - RMW("decrement"))); - - /* JMP ($$$$) */ - override void opcode6C() - { - ushort vector = readWordOperand(); - programCounter = readWord(vector, - (vector & 0xFF00) | cast(ubyte)(vector + 1)); - static if (cumulative) tick(totalCycles); - } -} diff --git a/src/d6502/nmosundoc.d b/src/d6502/nmosundoc.d deleted file mode 100644 index abea573..0000000 --- a/src/d6502/nmosundoc.d +++ /dev/null @@ -1,365 +0,0 @@ -/+ - + d6502/nmosundoc.d - + - + Copyright: 2007 Gerald Stocker - + - + This file is part of twoapple-reboot. - + - + twoapple-reboot is free software; you can redistribute it and/or modify - + it under the terms of the GNU General Public License as published by - + the Free Software Foundation; either version 2 of the License, or - + (at your option) any later version. - + - + twoapple-reboot is distributed in the hope that it will be useful, - + but WITHOUT ANY WARRANTY; without even the implied warranty of - + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - + GNU General Public License for more details. - + - + You should have received a copy of the GNU General Public License - + along with twoapple-reboot; if not, write to the Free Software - + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - +/ - -module d6502.nmosundoc; - -import d6502.base; -import d6502.nmosbase; - -class NmosUndoc(bool strict, bool cumulative) : NmosBase!(strict, cumulative) -{ - this() - { - super(); - } - - final void addrHalt() - { - programCounter--; - /* TODO: check with the timer how many ticks until it would - * stop me? */ - static if (cumulative) tick(totalCycles); - } - - final void addrImplied() - { - peek(programCounter); - static if (cumulative) tick(totalCycles); - } - - final void strange(ubyte val) - { - version(Commodore64) - { - ubyte hiAddr = cast(ubyte)((primaryAddress >> 8) + 1); - val = val & hiAddr; - ushort addr = (badAddress == primaryAddress) ? primaryAddress : - ((val << 8) | (primaryAddress & 0xFF)); - writeFinal(addr, val); - } - else - { - ubyte hiAddr = cast(ubyte)((baseAddress >> 8) + 1); - writeFinal(primaryAddress, val & hiAddr); - } - } - - static string UndocAddress(string name, string rw, int[] opcodes) - { - string type = (rw == "Write") ? "true" : "false"; - string modes = "[[\"" ~ name ~ "\", \"" ~ rw ~ "\"], \n"; - string index = (name[2] == 'X') ? "Y" : "X"; - for (int op = 0; op < opcodes.length; ++op) - { - int opcode = opcodes[op]; - modes ~= "[\"" ~ hexByte(opcode) ~ "\", \""; - final switch ((opcode & 0b00011100) >> 2) - { - case 0: - modes ~= "IndirectX()"; - break; - case 1: - modes ~= "Zeropage()"; - break; - case 3: - modes ~= "Absolute()"; - break; - case 4: - modes ~= "IndirectY("~ type ~ ")"; - break; - case 5: - modes ~= "Zeropage" ~ index ~ "()"; - break; - case 7: - modes ~= "AbsoluteY(" ~ type ~ ")"; - break; - } - modes ~= "\"]"; - if (op != (opcodes.length - 1)) modes ~= ", "; - modes ~= "\n"; - } - return modes ~ "]\n"; - } - - static string ManualAddress(string name, int[] opcodes, - string mode) - { - string modes = "[[\"" ~ name ~ "\", \"NA\"], \n"; - for (int op = 0; op < opcodes.length; ++op) - { - int opcode = opcodes[op]; - modes ~= "[\"" ~ hexByte(opcode) ~ "\", \"" ~ mode ~ "\"]"; - if (op != (opcodes.length - 1)) modes ~= ", "; - modes ~= "\n"; - } - return modes ~ "]\n"; - } - - static string Halt() - { - /+ TODO: have this do something useful +/ - return "\n"; - } - - static string ReadNOP() - { - return "readVal = readFinal(primaryAddress);\n"; - } - - static string RMW_Read(string action1, string action2) - { - return "poke(primaryAddress, (readVal = read(primaryAddress)));\n" ~ - "writeFinal(primaryAddress, flag.zero_ = flag.negative_ = " ~ - "(writeVal = " ~ action1 ~ "(readVal)));\n" ~ - action2 ~ " writeVal;\n"; - } - - static string RMW_Compare(string action1, string action2) - { - return "poke(primaryAddress, (readVal = read(primaryAddress)));\n" ~ - "writeFinal(primaryAddress, " ~ - "(writeVal = " ~ action1 ~ "(readVal)));\n" ~ - "flag.zero_ = flag.negative_ = " ~ - "compare(" ~ action2 ~ ", writeVal);\n"; - } - - static string RMW_Decimal(string action1, string action2) - { - return "poke(primaryAddress, (readVal = read(primaryAddress)));\n" ~ - "writeFinal(primaryAddress, flag.zero_ = flag.negative_ = " ~ - "(writeVal = " ~ action1 ~ "(readVal)));\n" ~ - "if (flag.decimal) dec_" ~ action2 ~ "(writeVal);\n" ~ - "else hex_" ~ action2 ~ "(writeVal);\n"; - } - - mixin(Opcode(mixin(ManualAddress( - "HLT", [0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 0x92, 0xB2, - 0xD2, 0xF2], "Halt()")), - Halt())); - - mixin(Opcode(mixin(ManualAddress( - "NOP", [0x1A, 0x3A, 0x5A, 0x7A, 0xDA, 0xFA], "Implied()")), - "")); - mixin(Opcode(mixin(ManualAddress( - "NOP", [0x0C], - "Absolute()")), - ReadNOP())); - mixin(Opcode(mixin(ManualAddress( - "NOP", [0x1C, 0x3C, 0x5C, 0x7C, 0xDC, 0xFC], - "AbsoluteX(false)")), - ReadNOP())); - mixin(Opcode(mixin(ManualAddress( - "NOP", [0x80, 0x82, 0x89, 0xC2, 0xE2], - "Immediate")), - ReadNOP())); - mixin(Opcode(mixin(ManualAddress( - "NOP", [0x04, 0x44, 0x64], - "Zeropage()")), - ReadNOP())); - mixin(Opcode(mixin(ManualAddress( - "NOP", [0x14, 0x34, 0x54, 0x74, 0xD4, 0xF4], - "ZeropageX()")), - ReadNOP())); - - mixin(Opcode(mixin(UndocAddress( - "LAX", "Read", [0xA3, 0xA7, 0xAF, 0xB3, 0xB7, 0xBF])), - Read("accumulator = xIndex ="))); - mixin(Opcode(mixin(UndocAddress( - "SAX", "Write", [0x83, 0x87, 0x97, 0x8F])), - Write("accumulator & xIndex"))); - - mixin(Opcode(mixin(Type1Address( - "ASO", "Write", [0x03, 0x07, 0x0F, 0x13, 0x17, 0x1B, 0x1F])), - RMW_Read("shiftLeft", "accumulator |="))); - mixin(Opcode(mixin(Type1Address( - "RLA", "Write", [0x23, 0x27, 0x2F, 0x33, 0x37, 0x3B, 0x3F])), - RMW_Read("rotateLeft", "accumulator &="))); - mixin(Opcode(mixin(Type1Address( - "LSE", "Write", [0x43, 0x47, 0x4F, 0x53, 0x57, 0x5B, 0x5F])), - RMW_Read("shiftRight", "accumulator ^="))); - mixin(Opcode(mixin(Type1Address( - "DCM", "Write", [0xC3, 0xC7, 0xCF, 0xD3, 0xD7, 0xDB, 0xDF])), - RMW_Compare("decrement", "accumulator"))); - mixin(Opcode(mixin(Type1Address( - "RRA", "Write", [0x63, 0x67, 0x6F, 0x73, 0x77, 0x7B, 0x7F])), - RMW_Decimal("rotateRight", "addWithCarry"))); - mixin(Opcode(mixin(Type1Address( - "INS", "Write", [0xE3, 0xE7, 0xEF, 0xF3, 0xF7, 0xFB, 0xFF])), - RMW_Decimal("increment", "subWithCarry"))); - - /* ANC #$$ */ - override void opcode0B() - { - readVal = operand1 = readFinal(programCounter); - flag.zero_ = flag.negative_ = (accumulator = readVal); - flag.carry = (flag.negative_ > 0x7F); - } - - /* ANC #$$ */ - override void opcode2B() - { - readVal = operand1 = readFinal(programCounter); - flag.zero_ = flag.negative_ = (accumulator = readVal); - flag.carry = (flag.negative_ > 0x7F); - } - - /* ALR #$$ */ - override void opcode4B() - { - readVal = operand1 = readFinal(programCounter); - flag.zero_ = flag.negative_ = - (accumulator = shiftRight(accumulator & readVal)); - } - - /* ARR #$$ */ - override void opcode6B() - { - readVal = operand1 = readFinal(programCounter); - ubyte val = readVal & accumulator; - if (flag.decimal) { - ubyte temp = cast(ubyte)((val >> 1) + (flag.carry ? 0x80 : 0)); - flag.zero_ = flag.negative_ = temp; - flag.overflow = (((temp ^ val) & 0x40) != 0); - if ((readVal & 0x0F) + (val & 0x01) > 5) - temp = (temp & 0xF0) + ((temp + 0x6) & 0x0F); - if (val + (val & 0x10) >= 0x60) - { - temp += 0x60; - flag.carry = true; - } - else - flag.carry = false; - accumulator = temp; - } - else { - accumulator = cast(ubyte)((val >> 1) + (flag.carry ? 0x80 : 0)); - flag.zero_ = flag.negative_ = accumulator; - val >>= 7; - flag.carry = (val != 0); - flag.overflow = ((val ^ ((accumulator >> 5) & 1)) != 0); - } - } - - /* ANE #$$ */ - override void opcode8B() - { - // unstable - readVal = operand1 = readFinal(programCounter++); - - version(Atari8Bit) - { - flag.zero_ = flag.negative_ = - (accumulator & xIndex & readVal); - accumulator &= xIndex & (operand1 | 0xEF); - } - else - { - flag.zero_ = flag.negative_ = - (accumulator &= (xIndex & readVal)); - } - } - - /* SHA ($$),Y */ - void opcode93() - { - addrIndirectY(true); - strange(accumulator & xIndex); - } - - /* SHA $$$$,Y */ - void opcode9F() - { - addrAbsoluteY(true); - strange(accumulator & xIndex); - } - - /* SHS $$$$,Y */ - void opcode9B() - { - addrAbsoluteY(true); - strange(stackPointer = (accumulator & xIndex)); - } - - /* SHY $$$$,X */ - void opcode9C() - { - addrAbsoluteX(true); - strange(yIndex); - } - - /* SHX $$$$,Y */ - void opcode9E() - { - addrAbsoluteY(true); - strange(xIndex); - } - - /* LAX #$$ */ - override void opcodeAB() - { - readVal = operand1 = readFinal(programCounter); - - version(Commodore128) - { - // not unstable? - flag.zero_ = flag.negative_ = - (accumulator = readVal); - } - else - { - // unstable - version(Commodore64) - { - accumulator |= 0xEE; - } - flag.zero_ = flag.negative_ = - (accumulator &= readVal); - } - xIndex = accumulator; - } - - /* LAS $$$$,Y */ - override void opcodeBB() - { - addrAbsoluteY(false); - readVal = readFinal(primaryAddress); - - flag.zero_ = flag.negative_ = - (xIndex = accumulator = (stackPointer & readVal)); - } - - /* SBX #$$ */ - override void opcodeCB() - { - readVal = operand1 = readFinal(programCounter++); - xIndex &= accumulator; - flag.zero_ = flag.negative_ = compare(xIndex, readVal); - } - - /* SBC #$$ */ - override void opcodeEB() - { - readVal = operand1 = readFinal(programCounter++); - if (flag.decimal) dec_subWithCarry(readVal); - else hex_subWithCarry(readVal); - } -} diff --git a/src/system/base.d b/src/system/base.d index 417773b..844cc77 100644 --- a/src/system/base.d +++ b/src/system/base.d @@ -24,9 +24,7 @@ module system.base; import timer; import memory; -import d6502.base; - -private alias d6502.base.CpuBase!(Strict.no, Cumulative.no) CpuBase; +import cpu.d6502; import ui.sound; import ui.inputevents; @@ -36,14 +34,31 @@ import system.video; import iomem; import video.base; import system.peripheral; +import ioummu; -class System + +class SystemBase +{ + Video video_; + + abstract void reboot(); + abstract void reset(); + abstract uint checkpoint(); + abstract uint sinceCheckpoint(uint cp); + abstract void execute(); +} + +class System(string chip) : SystemBase { Timer timer; Timer.Cycle deviceCycle; AddressDecoder decoder; SoftSwitchPage switches; - CpuBase cpu; + + Cpu!(chip, AddressDecoder, Timer) cpu; + // XXX + bool* cpuRun, signalActive, resetLow; + IOMem ioMem; Peripherals peripherals; @@ -73,15 +88,15 @@ class System } } - Video video_; Memory memory_; IO io_; - abstract IO newIO(); - abstract CpuBase newCpu(); - abstract Video newVideo(ubyte[] vidRom); - abstract IOMem newIOMem(); - abstract Peripherals newPeripherals(); + static if (chip == "65C02") + { + AuxiliaryCard auxCard; + MMU mmu; + IOU iou; + } this(ubyte[] romDump) { @@ -91,7 +106,10 @@ class System initIO(null); // XXX where is vidRom passed in? decoder.nullRead = &video_.scanner.floatingBus; - peripherals = newPeripherals(); + static if (chip == "6502") + peripherals = new Peripherals_II(); + else + peripherals = new Peripherals_IIe(); peripherals.install(decoder, memory_.mainRom); ioMem.initialize(decoder, switches, timer, peripherals); @@ -99,15 +117,22 @@ class System switches.setFloatingBus(&video_.scanner.floatingBus); } - void reboot() + override void reboot() { - cpu.reboot(); + // XXX replace + //cpu.reboot(); deviceCycle.restart(); memory_.reboot(); ioMem.reboot(); io_.reboot(); peripherals.reboot(); video_.reboot(); + + static if (chip == "65C02") + { + auxCard.reboot(); + mmu.reboot(); + } } void initTimer() @@ -120,56 +145,92 @@ class System void initMemory(ubyte[] romDump) { + static if (chip == "65C02") + { + mmu = new MMU(); + mmu.ioMem = new IOMem_IIe(); + mmu.ioMem.setRom(romDump); + } memory_ = new Memory(romDump); decoder = new AddressDecoder(); switches = new SoftSwitchPage(); decoder.installSwitches(switches); decoder.install(memory_.mainRam); decoder.install(memory_.mainRom); - ioMem = newIOMem(); + static if (chip == "6502") + ioMem = new IOMem(); + else + { + ioMem = mmu.ioMem; + auxCard = new Extended80ColumnCard(); + mmu.init(switches, auxCard, decoder, memory_.mainRam, + memory_.mainRom); + } } void initCpu() { - cpu = newCpu(); + cpu = new Cpu!(chip, AddressDecoder, Timer)(decoder, timer); + // XXX + cpuRun = &cpu.keepRunning; + signalActive = &cpu.signalActive; + resetLow = &cpu.resetLow; + debug(disassemble) cpu.memoryName = &decoder.memoryReadName; - cpu.clock.tick = &timer.tick; timer.onPrimaryStop(&primaryStop); - cpu.memory.read = &decoder.read; - cpu.memory.write = &decoder.write; } void initIO(ubyte[] vidRom) { - io_ = newIO(); - video_ = newVideo(vidRom); + static if (chip == "6502") + { + io_ = new IO_II(switches, timer, deviceCycle); + video_ = new Video_II(switches, memory_.vidPages, timer, vidRom, + &io_.kbd.peekLatch, decoder); + } + else + { + io_ = new IO_IIe(switches, timer, deviceCycle); + video_ = new Video_IIe(switches, memory_.vidPages, timer, vidRom, + &io_.kbd.peekLatch, auxCard.vidPages); + iou = new IOU(io_, video_.signal); + iou.initSwitches(switches); + mmu.initIO(video_.scanner, &io_.kbd.peekLatch); + } } bool primaryStop() { - cpu.stop(); + *cpuRun = false; return true; } - void reset() + override void reset() { + static if (chip == "65C02") + { + auxCard.reset(); + mmu.reset(); + } + peripherals.reset(); - cpu.resetLow(); + *signalActive = true; + *resetLow = true; } - uint checkpoint() + override uint checkpoint() { return timer.primaryCounter.currentLength; } - uint sinceCheckpoint(uint cp) + override uint sinceCheckpoint(uint cp) { uint currentLength = timer.primaryCounter.currentLength; return ((currentLength == timer.primaryCounter.startLength) ? cp : (cp - currentLength)); } - void execute() + override void execute() { cpu.run(true); @@ -181,126 +242,3 @@ class System // XXX peripherals get notification } } - -class II : System -{ - import d6502.nmosundoc : NmosUndoc; - - int revision; - - this(ubyte[] romDump) - { - // XXX FIXME XXX - revision = int.max; - super(romDump); - } - - CpuBase newCpu() - { - return new NmosUndoc!(Strict.no, Cumulative.no)(); - } - - IO newIO() - { - return new IO_II(switches, timer, deviceCycle); - } - - Video newVideo(ubyte[] vidRom) - { - return new Video_II(switches, memory_.vidPages, timer, vidRom, - &io_.kbd.peekLatch, decoder); - } - - IOMem newIOMem() - { - return new IOMem(); - } - - Peripherals newPeripherals() - { - return new Peripherals_II(); - } -} - -import ioummu; - -class IIe : System -{ - import d6502.cmos : Cmos; - - AuxiliaryCard auxCard; - MMU mmu; - IOU iou; - - this(ubyte[] romDump) - { - // XXX if different or no aux card? - //auxMemory = new Memory(); - super(romDump); - } - - void reboot() - { - super.reboot(); - auxCard.reboot(); - mmu.reboot(); - } - - void reset() - { - auxCard.reset(); - mmu.reset(); - super.reset(); - } - - CpuBase newCpu() - { - // XXX this is enhanced - return new Cmos!(Strict.no, Cumulative.no)(); - } - - IO newIO() - { - return new IO_IIe(switches, timer, deviceCycle); - } - - Video newVideo(ubyte[] vidRom) - { - return new Video_IIe(switches, memory_.vidPages, timer, vidRom, - &io_.kbd.peekLatch, auxCard.vidPages); - } - - IOMem newIOMem() - { - return mmu.ioMem; - } - - Peripherals newPeripherals() - { - return new Peripherals_IIe(); - } - - void initMemory(ubyte[] romDump) - { - mmu = new MMU(); - mmu.ioMem = new IOMem_IIe(); - mmu.ioMem.setRom(romDump); - - super.initMemory(romDump); - - // XXX XXX XXX - // allow for different card from config - auxCard = new Extended80ColumnCard(); - - mmu.init(switches, auxCard, decoder, memory_.mainRam, - memory_.mainRom); - } - - void initIO(ubyte[] vidRom) - { - super.initIO(vidRom); - iou = new IOU(io_, video_.signal); - iou.initSwitches(switches); - mmu.initIO(video_.scanner, &io_.kbd.peekLatch); - } -} diff --git a/src/twoapple.d b/src/twoapple.d index 80bbb18..68e4fa5 100644 --- a/src/twoapple.d +++ b/src/twoapple.d @@ -20,7 +20,7 @@ import std.stdio; -import d6502.base; +import cpu.d6502; import timer; import memory; import system.base; @@ -39,20 +39,6 @@ import peripheral.diskii; import peripheral.langcard; import peripheral.saturn128; -class TestSystem : II -{ - this(ubyte[] romDump) - { - super(romDump); - } - - void setRom(ubyte[] rom_data) - { - uint rom_len = cast(uint)rom_data.length; - memory_.mainRom.data_[0..12288] = rom_data[(rom_len - 12288)..rom_len]; - } -} - import std.file; import std.string; import device.speaker; @@ -86,11 +72,11 @@ void main(string[] args) TwoappleFile romFile = TwoappleFilePicker.open("ROM file", &checkRomFile); if (romFile is null) return; - System sys; + SystemBase sys; if ((args.length > 1) && (args[1] == "--iie")) - sys = new IIe(cast(ubyte[])std.file.read(romFile.fileName)); + sys = new System!"65C02"(cast(ubyte[])std.file.read(romFile.fileName)); else - sys = new II(cast(ubyte[])std.file.read(romFile.fileName)); + sys = new System!"6502"(cast(ubyte[])std.file.read(romFile.fileName)); appWindow.initSystem(sys); // XXX hack appWindow.configChanged = true; diff --git a/src/ui/mainwindow.d b/src/ui/mainwindow.d index 99982a5..f2f38be 100644 --- a/src/ui/mainwindow.d +++ b/src/ui/mainwindow.d @@ -54,7 +54,7 @@ class TwoappleMainWindow : MainWindow import gtk.Alignment; import peripheral.base; - System system; + SystemBase system; Label speedLabel; ToolItem speedItem; @@ -122,7 +122,7 @@ class TwoappleMainWindow : MainWindow } } - void initSystem(System sys) + void initSystem(SystemBase sys) { showAll(); system = sys;