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/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); + } 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/cpu/ctfe_d6502.d b/src/cpu/ctfe_d6502.d new file mode 100644 index 0000000..e9eeb19 --- /dev/null +++ b/src/cpu/ctfe_d6502.d @@ -0,0 +1,1269 @@ +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. +version(OpDelegates) +{ + enum versionCheck = 1; + enum opArray = true; +} + +// OpSwitch: each opcode is inlined in a 256-case switch. +version(OpSwitch) +{ + enum versionCheck = 2; + 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 = 3; + 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); + + +string OpArrayDef() +{ + version(OpDelegates) + return q{void delegate()[256] opcodes;}; + else + return ""; +} + +string OpArrayInit() +{ + string ret; + foreach (op; 0..256) + { + ret ~= Fmt("opcodes[0x#] = &opcode_#;\n", + Hex2(op), Hex2(op)); + } + return ret; +} + +string OpMethods(string chip) +{ + string ret; + foreach (op; 0..256) + { + 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(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"; + 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"; + } + ret ~= "}\nbreak;\n"; + } + return ret ~ "}\n"; +} + + +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) +{ + 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(); + break; + case "RTI": + ret ~= RetInt(); + break; + case "JSR": + ret ~= JumpSub(); + break; + case "RTS": + ret ~= RetSub(); + break; + case "JMP": + ret ~= Jump(op, chip); + break; + case "KIL": + ret ~= _PC ~ "--;\n"; + break; + case "BPL": + ret ~= Branch("!(" ~ _N ~ " & 0x80)", chip); + break; + case "BMI": + ret ~= Branch("(" ~ _N ~ " & 0x80)", chip); + break; + case "BVC": + ret ~= Branch("!" ~ _V, chip); + break; + case "BVS": + ret ~= Branch(_V, chip); + break; + case "BRA": + ret ~= Branch("true", chip); + break; + case "BCC": + ret ~= Branch("!" ~ _C, chip); + break; + case "BCS": + ret ~= Branch(_C, chip); + break; + case "BNE": + ret ~= Branch(_Z, chip); + break; + case "BEQ": + ret ~= Branch("!" ~ _Z, chip); + break; + case "CLC": + ret ~= ClearFlag(_C); + break; + case "SEC": + ret ~= SetFlag(_C); + break; + case "CLI": + ret ~= ClearFlag(_I); + break; + case "SEI": + ret ~= SetFlag(_I); + break; + case "CLV": + ret ~= ClearFlag(_V); + break; + case "CLD": + ret ~= ClearFlag(_D); + break; + case "SED": + ret ~= SetFlag(_D); + break; + case "NOP": + ret ~= Nop(mode); + break; + case "TAX": + ret ~= Transfer(_A, _X); + break; + case "TXA": + ret ~= Transfer(_X, _A); + break; + case "TAY": + ret ~= Transfer(_A, _Y); + break; + case "TYA": + ret ~= Transfer(_Y, _A); + break; + case "TSX": + ret ~= Transfer(_S, _X); + break; + case "TXS": + ret ~= Transfer(_X, _S, false); + break; + case "DEX": + ret ~= Dec(_X); + break; + case "DEY": + ret ~= Dec(_Y); + break; + case "INX": + ret ~= Inc(_X); + break; + case "INY": + ret ~= Inc(_Y); + break; + case "PHP": + ret ~= Push(Attr("statusToByte()")); + break; + case "PLP": + ret ~= PullStatus(); + break; + case "PLA": + ret ~= PullReg(_A); + break; + case "PLX": + ret ~= PullReg(_X); + break; + case "PLY": + ret ~= PullReg(_Y); + break; + case "PHA": + ret ~= PushReg(_A); + break; + case "PHX": + ret ~= PushReg(_X); + break; + case "PHY": + ret ~= PushReg(_Y); + break; + case "LDA": + ret ~= Load(_A); + break; + case "LDX": + ret ~= Load(_X); + break; + case "LDY": + ret ~= Load(_Y); + break; + case "STA": + ret ~= Store(_A); + break; + case "STX": + ret ~= Store(_X); + break; + case "STY": + ret ~= Store(_Y); + break; + case "STZ": + ret ~= Store("0"); + break; + case "CMP": + ret ~= Compare(_A); + break; + case "CPX": + ret ~= Compare(_X); + break; + case "CPY": + ret ~= Compare(_Y); + break; + case "BIT": + ret ~= Bit(mode); + break; + case "ORA": + ret ~= Logic("|="); + break; + case "AND": + ret ~= Logic("&="); + break; + case "EOR": + ret ~= Logic("^="); + break; + case "ADC": + ret ~= Add(chip); + break; + case "SBC": + ret ~= Sub(chip); + break; + case "INC": + if (op == 0x1a) + ret ~= Inc(_A); + else + ret ~= RMW(Inc("data"), chip); + break; + case "DEC": + if (op == 0x3a) + ret ~= Dec(_A); + else + ret ~= RMW(Dec("data"), chip); + break; + case "ASL": + if (op == 0x0a) + ret ~= ShiftLeft(_A); + else + ret ~= RMW(ShiftLeft("data"), chip); + break; + case "ROL": + if (op == 0x2a) + ret ~= RotateLeft(_A); + else + ret ~= RMW(RotateLeft("data"), chip); + break; + case "LSR": + if (op == 0x4a) + ret ~= ShiftRight(_A); + else + ret ~= RMW(ShiftRight("data"), chip); + break; + case "ROR": + if (op == 0x6a) + ret ~= RotateRight(_A); + else + ret ~= RMW(RotateRight("data"), chip); + break; + case "TRB": + ret ~= RMW(TestReset(), chip); + break; + case "TSB": + ret ~= RMW(TestSet(), chip); + break; + case "LAS": + ret ~= LAS_Undoc(); + break; + case "LAX": + if (op != 0xAB) + ret ~= Load(_A ~ " = " ~ _X); + else + ret ~= LAX_IMM_Undoc(); + break; + case "SAX": + ret ~= Store(_A ~ " & " ~ _X); + break; + case "ANC": + ret ~= ANC_Undoc(); + break; + case "ALR": + ret ~= ALR_Undoc(); + break; + case "ARR": + ret ~= ARR_Undoc(); + break; + case "AXS": + ret ~= AXS_Undoc(); + break; + case "AHX": + ret ~= Strange_Undoc(_A ~ " &" ~ _X); + break; + case "SHY": + ret ~= Strange_Undoc(_Y); + break; + case "SHX": + ret ~= Strange_Undoc(_X); + break; + case "TAS": + ret ~= Strange_Undoc(_S ~ " = " ~ _A ~ " & " ~ _X); + break; + case "XAA": + ret ~= XAA_Undoc(); + break; + case "SLO": + ret ~= RMW_Undoc(ShiftLeft("data"), + SetNZ(_A ~ " |= data")); + break; + case "RLA": + ret ~= RMW_Undoc(RotateLeft("data"), + SetNZ(_A ~ " &= data")); + break; + case "SRE": + ret ~= RMW_Undoc(ShiftRight("data"), + SetNZ(_A ~ " ^= data")); + break; + case "RRA": + ret ~= RMW_Undoc(RotateRight("data"), AddBase(chip)); + break; + case "DCP": + ret ~= RMW_Undoc(Dec("data"), CompareBase(_A)); + break; + case "ISC": + ret ~= RMW_Undoc(Inc("data"), SubBase(chip)); + break; + } + return ret ~ Done(); +} + + +string Break() +{ + return IncPC() ~ + PushPC() ~ + Push(Attr("statusToByte()")) ~ + SetFlag(_I) ~ + ReadWord(_PC, "IRQ_VECTOR"); +} + + +string JumpSub() +{ + return ReadOp(Local("ushort", "address")) ~ + Peek(STACK) ~ + PushPC() ~ + LoadHiByte("address", _PC ~ "++") ~ + _PC ~ " = address;\n"; +} + + +string RetSub() +{ + return Peek(STACK) ~ + PullPC() ~ + Peek(_PC) ~ + IncPC(); +} + + +string RetInt() +{ + return PullStatus() ~ + PullPC(); +} + + +string Jump(int op, string chip) +{ + bool nmos = (chip == "6502"); + bool cmos = !nmos; + + if (op == 0x4c) + return _PC ~ " = address;\n"; + else if (op == 0x6c) + return ReadWordOp("ushort", "base") ~ + If!(cmos)( + Peek(_PC)) ~ + ReadWordBasic(_PC, "base", + If!(nmos)( + "(base & 0xFF00) | cast(ubyte)(base + 1)", + "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, string chip) +{ + return ReadOp(Local("ushort", "base")) ~ + "if (" ~ check ~ ")\n{\n" ~ + Peek(_PC) ~ + Local("ushort", "address") ~ + " = cast(ushort)(" ~ _PC ~ " + cast(byte)base);\n" ~ + CheckShortcut(_PC, "address", chip, 0) ~ + _PC ~ " = address;\n" ~ + "}\n"; +} + + +string Nop(int mode) +{ + if (mode == IMP || mode == NP1 || mode == NP8) + return ""; + else + return Tick() ~ + ReadRaw("address") ~ ";\n"; +} + + +string Transfer(string source, string dest, bool setNZ = true) +{ + return dest ~ " = " ~ source ~ ";\n" ~ + (setNZ ? SetNZ(dest) : ""); +} + + +string PullReg(string reg) +{ + return Peek(STACK) ~ + PullInto(reg) ~ + SetNZ(reg); +} + + +string PushReg(string reg) +{ + return Push(reg); +} + + +string Load(string reg) +{ + return ReadInto(reg, "address") ~ + SetNZ(reg); +} + + +string Store(string reg,) +{ + return Write("address", reg); +} + + +string Compare(string reg) +{ + return ReadInto(Local("ubyte", "data"), "address") ~ + CompareBase(reg); +} + +string CompareBase(string reg) +{ + return UpdateFlag(_C, reg ~ " >= data") ~ + SetNZ("cast(ubyte)(" ~ reg ~ " - data)"); +} + + +string Bit(int mode) +{ + bool notImm = (mode != IMM); + + return ReadInto(Local("ubyte", "data"), "address") ~ + If!(notImm)( + _N ~ " = data;\n" ~ + _V ~ " = ((data & 0x40) != 0);\n") ~ + _Z ~ " = (" ~ _A ~ " & data);\n"; +} + + +string Logic(string action) +{ + return ReadInto(_A, action, "address") ~ + SetNZ(_A); +} + + +string Add(string chip) +{ + return ReadInto(Local("ubyte", "data"), "address") ~ + AddBase(chip); +} + +string AddBase(string chip) +{ + return "if (" ~ _D ~ ")\n{\n" ~ + DecAdd(chip) ~ + "}\nelse\n{\n" ~ + HexAdd() ~ + "}\n"; +} + +string HexAdd() +{ + 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 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), + _A ~ " = cast(ubyte)a;\n"); +} + + +string Sub(string chip) +{ + return ReadInto(Local("ubyte", "data"), "address") ~ + SubBase(chip); +} + +string SubBase(string chip) +{ + bool nmos = (chip == "6502"); + + return "if (" ~ _D ~ ")\n{\n" ~ + If!(nmos)(DecSubNMOS(), DecSubCMOS()) ~ + "}\nelse\n{\n" ~ + HexSub() ~ + "}\n"; +} + +string HexSub() +{ + 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 DecSubNMOS() +{ + 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() +{ + 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) ~ + 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(string action, string chip) +{ + bool nmos = (chip == "6502"); + + return ReadInto(Local("ubyte", "data"), "address") ~ + If!(nmos)(Poke("address", "data"), + Peek("address")) ~ + action ~ + Write("address", "data"); +} + + +string RMW_Undoc(string action1, string action2) +{ + return ReadInto(Local("ubyte", "data"), "address") ~ + Poke("address", "data") ~ + action1 ~ + Write("address", "data") ~ + action2; +} + + +string LAS_Undoc() +{ + return ReadInto(Local("ubyte", "data"), "address") ~ + SetNZ(_X ~ " = " ~ _A ~ " = (" ~ _S ~ " & data)"); +} + + +string ARR_Undoc() +{ + return ReadInto(Local("ubyte", "data"), "address") ~ + "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() +{ + return ReadInto(_A, "address") ~ + SetNZ(_A) ~ + _C ~ " = (" ~ _A ~ " > 0x7f);\n"; +} + + +string ALR_Undoc() +{ + return ReadInto(Local("ubyte", "data"), "address") ~ + _A ~ " &= data;\n" ~ + ShiftRight(_A); +} + + +string AXS_Undoc() +{ + return ReadInto(Local("ubyte", "data"), "address") ~ + _X ~ " &= " ~ _A ~ ";\n" ~ + CompareBase(_X); +} + + +/* + * This opcode is unstable on certain machines; see + * http://visual6502.org/wiki/index.php?title=6502_Opcode_8B_(XAA,ANE) + */ +string XAA_Undoc() +{ + /* + * 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") ~ + _A ~ " = ((" ~ _A ~ " | " ~ MAGIC ~ ") & " ~ _X ~ " & data);\n" ~ + SetNZ(_A); +} + + +/* + * This opcode is unstable on certain machines. + */ +string LAX_IMM_Undoc() +{ + // From the VICE emulator. + string MAGIC = "0xee"; + + 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) +{ + 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"); +} + + +string Local(string type) +{ + return ""; +} + +string Local(string type, string var) +{ + return var; +} + +string Attr(string var) +{ + return var; +} + + +string Address(int mode, int exCyc, string chip) +{ + final switch (mode) + { + case IMP: + return AddrIMP(); + case IMM: + return AddrIMM(); + case ZP: + return AddrZP(); + case ZPX: + return AddrZPXY(_X, chip); + case ZPY: + return AddrZPXY(_Y, chip); + case IZX: + return AddrIZX(chip); + case IZY: + return AddrIZY(chip, exCyc); + case ABS: + return AddrABS(); + case ABX: + return AddrABXY(_X, chip, exCyc); + case ABY: + return AddrABXY(_Y, chip, exCyc); + case IND: + // handled by Jump() + return ""; + case REL: + // handled by Branch() + return ""; + case ZPI: + return AddrZPI(); + case ABI: + // handled in Jump() + return ""; + case NP1: + // handled implicitly (the 1 cycle is the opcode fetch) + return ""; + case NP8: + return AddrNP8(); + case KIL: + // handled by case KIL in OpBody() + return ""; + } + return ""; +} + + +string AddrIMM() +{ + return Local("ushort") ~ "address = " ~ _PC ~ "++;\n"; +} + +string AddrIMP() +{ + return Peek(_PC); +} + +string AddrZP() +{ + return ReadOp(Local("ushort", "address")); +} + +string AddrZPXY(string reg, string chip) +{ + bool nmos = (chip == "6502"); + + return ReadOp(Local("ushort", "base")) ~ + If!(nmos)( + Peek("base"), + Peek(_PC)) ~ + Local("ushort") ~ + "address = cast(ubyte)(base + " ~ reg ~ ");\n"; +} + +string AddrIZX(string chip) +{ + bool nmos = (chip == "6502"); + + return ReadOp(Local("ushort", "base")) ~ + If!(nmos)( + Peek("base"), + Peek(_PC)) ~ + ReadWordZP("ushort", "address", "base + " ~ _X); +} + +string AddrIZY(string chip, int exCyc) +{ + return ReadOp("ubyte vector") ~ + ReadWordZP("ushort", "base", "vector") ~ + Local("ushort") ~ + "address = cast(ushort)(base + " ~ _Y ~ ");\n" ~ + CheckShortcut("base", "address", chip, exCyc); +} + +string AddrABS() +{ + return ReadWordOp("ushort", "address"); +} + +string AddrABXY(string reg, string chip, int exCyc) +{ + return ReadWordOp("ushort", "base") ~ + Local("ushort") ~ "address = cast(ushort)(base + " ~ reg ~ ");\n" ~ + CheckShortcut("base", "address", chip, exCyc); +} + +string AddrZPI() +{ + return ReadOp(Local("ushort", "base")) ~ + ReadWordZP("ushort", "address", "base"); +} + +string AddrNP8() +{ + return ReadOp(Local("ushort", "base")) ~ + Peek(_PC) ~ + IncPC() ~ + Peek("0xff00 | base") ~ + Peek("0xffff") ~ + Peek("0xffff") ~ + Peek("0xffff") ~ + Peek("0xffff"); +} + +string CheckShortcut(string base, string addr, string chip, int exCyc) +{ + bool nmos = (chip == "6502"); + + return "ushort guess = (" ~ base ~ " & 0xFF00) | cast(ubyte)" ~ addr ~ ";\n" ~ + "if (guess != " ~ addr ~ ")\n{\n" ~ + If!(nmos)(Peek("guess"), + Peek(_PC)) ~ + "}\n" ~ + If!(exCyc)("else\n{\n" ~ Peek("address") ~ "}\n"); +} + + +string ReadInto(string var, string action, string addr) +{ + return Tick() ~ + var ~ " " ~ action ~ " " ~ ReadRaw("(" ~ addr ~ ")") ~ ";\n"; +} + +string ReadInto(string var, string addr) +{ + return ReadInto(var, "=", addr); +} + +string ReadOp(string var) +{ + return ReadInto(var, _PC ~ "++"); +} + +string ReadRaw(string addr) +{ + return Attr("memory") ~ ".read(" ~ addr ~")"; +} + +string ReadWordBasic(string type, string var, string addr1, string addr2) +{ + return LoadLoByte(type, var, addr1) ~ + LoadHiByte(var, addr2); +} + +string ReadWordBasic(string var, string addr1, string addr2) +{ + return ReadWordBasic("", var, addr1, addr2); +} + +string ReadWord(string type, string var, string addr) +{ + return ReadWordBasic(type, var, addr, "cast(ushort)(" ~ addr ~ " + 1)"); +} + +string ReadWord(string var, string addr) +{ + return ReadWord("", var, addr); +} + +string ReadWordZP(string type, string var, string addr) +{ + return ReadWordBasic(type, var, "cast(ubyte)( " ~ addr ~ ")", + "cast(ubyte)(" ~ addr ~ " + 1)"); +} + +string ReadWordZP(string var, string addr) +{ + return ReadWordZP("", var, addr); +} + +string ReadWordOp(string type, string var) +{ + return ReadWordBasic(type, var, _PC ~ "++", _PC ~ "++"); +} + +string ReadWordOp(string var) +{ + return ReadWordOp("", var); +} + +string Tick() +{ + return If!(cumulative)("++cycles;\n", Attr("clock") ~ ".tick();\n"); +} + +string Peek(string addr) +{ + return Tick() ~ + If!(strict)(Attr("memory") ~ ".read(" ~ addr ~");\n"); +} + +string Poke(string addr, string val) +{ + return Tick() ~ + If!(strict)( + Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"); +} + +string Write(string addr, string val) +{ + return Tick() ~ + Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n"; +} + +string IncPC() +{ + return "++" ~ _PC ~ ";\n"; +} + + +string IncSP() +{ + return "++" ~ _S ~ ";\n"; +} + +string DecSP() +{ + return "--" ~ _S ~ ";\n"; +} + +string PullStatus() +{ + return Peek(STACK) ~ + IncSP() ~ + Tick() ~ + Attr("statusFromByte") ~ "(" ~ + ReadRaw(STACK) ~ ");\n"; +} + +string PullInto(string var) +{ + return IncSP() ~ + ReadInto(var, STACK); +} + +string Push(string val) +{ + return Write(STACK, val) ~ + DecSP(); +} + +string PushPC() +{ + return Push(HiByte(_PC)) ~ + Push(LoByte(_PC)); +} + + +string PullPC() +{ + return PullInto(_PC) ~ + IncSP() ~ + LoadHiByte(_PC, STACK); +} + +string LoadLoByte(string type, string var, string addr) +{ + return Tick() ~ + Local(type, var) ~ " = " ~ ReadRaw(addr) ~ ";\n"; +} + +string LoadHiByte(string var, string addr) +{ + return Tick() ~ + var ~ " |= (" ~ ReadRaw(addr) ~ " << 8);\n"; +} + +string SetFlag(string flag) +{ + return flag ~ " = true;\n"; +} + +string ClearFlag(string flag) +{ + return flag ~ " = false;\n"; +} + +string UpdateFlag(string flag, string val) +{ + return flag ~ " = (" ~ val ~ ");\n"; +} + +string SetNZ(string var) +{ + return _N ~ " = " ~ _Z ~ " = (" ~ var ~ ");\n"; +} + +string Done() +{ + return If!(cumulative)(Attr("clock") ~ ".tick(cycles);\n"); +} + + +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]; +} + + +// Custom string formatting. + +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]; +} + +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..$]; +} diff --git a/src/cpu/d6502.d b/src/cpu/d6502.d new file mode 100644 index 0000000..5cc5e2e --- /dev/null +++ b/src/cpu/d6502.d @@ -0,0 +1,173 @@ +/+ + + 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; + + +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, 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"); + + MEM memory; + CLK clock; + + ubyte A, X, Y, S; + ushort PC; + + // The status flags. + ubyte N, Z; + bool V, D, I, C; + + version(OpDelegates) + { + mixin(OpArrayDef()); + version(Cumulative) { int cycles; } + ushort address, base; + ubyte data; + } + + this(MEM memory, CLK clock) + { + this.memory = memory; + this.clock = clock; + + version(OpDelegates) 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); + } + + bool keepRunning; + bool signalActive; + bool resetLow; + + final void run(bool continuous) + { + keepRunning = continuous; + ubyte opcode; + static if (!opArray) + { + version(Cumulative) { int cycles; } + ushort address, base; + ubyte data; + } + do + { + 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; +//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/src/d6502/base.d b/src/d6502/base.d deleted file mode 100644 index e33dce2..0000000 --- a/src/d6502/base.d +++ /dev/null @@ -1,152 +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]); - } - - ubyte delegate(ushort addr) memoryRead; - void delegate(ushort addr, ubyte val) memoryWrite; - 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(); - 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 97895e5..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 ((memoryRead !is null) && (memoryWrite !is null)); - assert (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) tick(totalCycles); - } - - void doReset() - { - static if (cumulative) - { - totalCycles += 2; - } - else - { - tick(); 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) tick(totalCycles); - } - - final ubyte read(ushort addr) - { - static if (cumulative) ++totalCycles; - else tick(); - return memoryRead(addr); - } - - final void write(ushort addr, ubyte val) - { - static if (cumulative) ++totalCycles; - else tick(); - memoryWrite(addr, val); - } - - final void peek(ushort addr) - { - static if (cumulative) ++totalCycles; - else tick(); - static if (strict) memoryRead(addr); - } - - final void poke(ushort addr, ubyte val) - { - static if (cumulative) ++totalCycles; - else tick(); - static if (strict) memoryWrite(addr, val); - } - - final ubyte readFinal(ushort addr) - { - static if (cumulative) tick(++totalCycles); - else - { - tick(); - } - return memoryRead(addr); - } - - final void writeFinal(ushort addr, ubyte val) - { - static if (cumulative) tick(++totalCycles); - else - { - tick(); - } - memoryWrite(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 ~= "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 ~= "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 ~= "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) 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; - } -} 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 f0bf82a..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" ~ - "flag.zero_ = flag.negative_ = (" ~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 b2ecda4..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,23 +106,33 @@ class System initIO(null); // XXX where is vidRom passed in? decoder.nullRead = &video_.scanner.floatingBus; - peripherals = newPeripherals(); - peripherals.install(cpu, decoder, memory_.mainRom); + static if (chip == "6502") + peripherals = new Peripherals_II(); + else + peripherals = new Peripherals_IIe(); + peripherals.install(decoder, memory_.mainRom); ioMem.initialize(decoder, switches, timer, peripherals); input.onReset = &reset; 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.tick = &timer.tick; timer.onPrimaryStop(&primaryStop); - cpu.memoryRead = &decoder.read; - cpu.memoryWrite = &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/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 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; diff --git a/test/base.d b/test/base.d index ebbe4d1..fd2251f 100644 --- a/test/base.d +++ b/test/base.d @@ -1,10 +1,130 @@ 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; + + +version(Strict) + enum strict = true; +else + enum strict = false; +version(Cumulative) + enum cumulative = true; +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; +} /* @@ -104,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. * @@ -134,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() { @@ -1232,8 +1288,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 +1305,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 +1326,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 +1340,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 +1438,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 +1456,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 +1483,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 +1501,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 +2161,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 +2194,8 @@ auto expect_RLA() } -// For LSE. -auto expect_LSE() +// For SRE. +auto expect_SRE() { void expect(ref Expected expected, const OpInfo info) { @@ -2306,8 +2362,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 +2398,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 +2566,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 @@ -2671,7 +2727,7 @@ if (isCpu!T) cycles = 2; return [Bus(Action.READ, pc)] ~ - If!(isStrict!T)( + If!(strict)( [Bus(Action.READ, pc+1)]); } @@ -2688,7 +2744,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)]; } @@ -2707,7 +2763,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)]; @@ -2728,7 +2784,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)])); } @@ -2750,7 +2806,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)]))); @@ -2805,7 +2861,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)( @@ -2861,7 +2917,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)( @@ -2962,14 +3018,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 { @@ -2998,13 +3054,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)( @@ -3028,12 +3084,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)]); } @@ -3053,7 +3109,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), @@ -3076,7 +3132,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), @@ -3100,7 +3156,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), @@ -3139,7 +3195,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)]; @@ -3169,7 +3225,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)]; @@ -3195,7 +3251,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), @@ -3334,3 +3390,59 @@ void test_opcode_timing(T)(ubyte opcode, busreport report) auto run = connect(setup, run_timing_test!T(expected, report)); run.run(opcode); } + + +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/cpu.d b/test/cpu.d index 796c446..063f8cb 100644 --- a/test/cpu.d +++ b/test/cpu.d @@ -8,66 +8,71 @@ 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 cpu.d6502 : Cpu, is6502, is65C02; + +import test.base : strict, cumulative; // 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"); -} -// True if the cpu type T aggregates ticks. -template isCumulative(T) +class TestIO { - enum isCumulative = __traits(hasMember, T, "_isCumulative"); + 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) 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, M = TestIO, C = TestIO) { - 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, M, C) CPU; } -auto makeCpu(T)(CpuInfo info) +auto makeCpu(T)(CpuInfo info = CpuInfo()) 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; + auto tio = new TestIO(); + auto cpu = new T(tio, tio); + 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; } @@ -75,14 +80,14 @@ 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() {} - cpu.memoryRead = &mem.read; - cpu.memoryWrite = &mem.write; - cpu.tick = &tick; + cpu.memory.dread = &mem.read; + cpu.memory.dwrite = &mem.write; + cpu.clock.dtick = &tick; } @@ -99,9 +104,9 @@ auto recordCycles(T)(T cpu) if (isCpu!T) { auto cycles = new int; - auto wrappedTick = cpu.tick; + auto wrappedTick = cpu.clock.dtick; - static if (isCumulative!T) + static if (cumulative) { void tick(int cyc) { @@ -117,7 +122,7 @@ if (isCpu!T) wrappedTick(); } } - cpu.tick = &tick; + cpu.clock.dtick = &tick; return constRef(cycles); } @@ -155,9 +160,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.dread !is null && cpu.memory.dwrite !is null); + auto wrappedRead = cpu.memory.dread; + auto wrappedWrite = cpu.memory.dwrite; ubyte read(ushort addr) { @@ -177,8 +182,8 @@ if (isCpu!T) wrappedWrite(addr, val); } - cpu.memoryRead = &read; - cpu.memoryWrite = &write; + cpu.memory.dread = &read; + cpu.memory.dwrite = &write; return record; } @@ -210,8 +215,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.dread !is null); + auto wrappedRead = cpu.memory.dread; ubyte read(ushort addr) { @@ -219,7 +224,7 @@ if (isCpu!T) return wrappedRead(addr); } - cpu.memoryRead = &read; + cpu.memory.dread = &read; try { cpu.run(true); } catch (StopException e) {} } @@ -244,32 +249,27 @@ 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); } 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 +279,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 +298,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 +325,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 +365,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 +441,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 +455,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 +469,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 +483,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 +495,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 +575,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)); } } diff --git a/test/runtests.d b/test/runtests.d new file mode 100644 index 0000000..32903a2 --- /dev/null +++ b/test/runtests.d @@ -0,0 +1,140 @@ +import std.array, std.exception, std.getopt, std.process, std.stdio, + std.traits; + + +enum OpDefs +{ + None, + Delegates = 1, + Switch = 2, + NestedSwitch = 4, + All = 7 +} + +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.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, 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 -version=RunTest " ~ cmdline); + } + } +} diff --git a/test/test_bus.d b/test/test_bus.d index db236d7..c6f673b 100644 --- a/test/test_bus.d +++ b/test/test_bus.d @@ -1,39 +1,20 @@ +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") 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") 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 d4cd191..3df6c33 100644 --- a/test/test_decimal.d +++ b/test/test_decimal.d @@ -211,10 +211,21 @@ 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); + runner.keepRunning = &cpu.keepRunning; setPC(cpu, 0x8000); + cpu.run(true); +} +else +{ + auto cpu = makeCpu!T(); + setPC(cpu, 0x8000); + connectMem(cpu, mem); runUntilBRK(cpu); +} if (mem[0x8003]) { // TODO: check data block to find out what failed exactly @@ -226,9 +237,43 @@ if (isCpu!T) version(Benchmark) { import std.datetime, std.stdio; + + final class BreakRunner + { + TestMemory* mem; + bool* keepRunning; + + this(ref TestMemory mem) + { + this.mem = &mem; + } + + final ubyte read(ushort 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) + { + mem.write(addr, val); + } + + static if (cumulative) { final void tick(int) {} } + else { final void tick() {} } + } + void f0() { - testDecimalMode!(CPU!("65C02", false, false))(); + testDecimalMode!(CPU!("65C02", BreakRunner, BreakRunner))(); } void main() @@ -243,24 +288,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"))(); - 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"))(); } } diff --git a/test/test_func.d b/test/test_func.d index 0b75600..d16a715 100644 --- a/test/test_func.d +++ b/test/test_func.d @@ -1,15 +1,20 @@ +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") 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") T2; + writeln("Testing functionality, 65C02"); + foreach (opcode; opts.codes65C02) test_one_opcode!T2(cast(ubyte)opcode, report); }