twoapple-reboot/src/d6502/nmosundoc.d

352 lines
10 KiB
D

/+
+ d6502/nmosundoc.d
+
+ Copyright: 2007 Gerald Stocker
+
+ This file is part of Twoapple.
+
+ Twoapple 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 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; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+/
import d6502.base;
import d6502.nmosbase;
class NmosUndoc : NmosBase
{
this()
{
super();
}
final void addrHalt() {}
final void addrImplied()
{
peek(programCounter);
version(CumulativeCycles) ticks(totalCycles);
}
final void strange(ubyte val)
{
version(Commodore64)
{
ubyte hiAddr = ((primaryAddress >> 8) + 1);
val = val & hiAddr;
ushort addr = (badAddress == primaryAddress) ? primaryAddress :
((val << 8) | (primaryAddress & 0xFF));
writeFinal(addr, val);
}
else
{
ubyte hiAddr = ((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";
for (int op = 0; op < opcodes.length; ++op)
{
int opcode = opcodes[op];
modes ~= "[\"" ~ hexByte(opcode) ~ "\", \"";
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 ~= "ZeropageX()";
break;
case 7:
modes ~= "AbsoluteY(" ~ type ~ ")";
break;
}
modes ~= "\"]";
if (op != (opcodes.length - 1)) modes ~= ", ";
modes ~= "\n";
}
return modes ~ "]\n";
}
static string ManualAddress(string name, int[] opcodes,
string mode)
{
string modes = "[[\"" ~ name ~ "\", \"NA\"], \n";
for (int op = 0; op < opcodes.length; ++op)
{
int opcode = opcodes[op];
modes ~= "[\"" ~ hexByte(opcode) ~ "\", \"" ~ mode ~ "\"]";
if (op != (opcodes.length - 1)) modes ~= ", ";
modes ~= "\n";
}
return modes ~ "]\n";
}
static string Halt()
{
/+ TODO: have this do something useful +/
return "\n";
}
static string ReadNOP()
{
return "readVal = readFinal(primaryAddress);\n";
}
static string RMW_Read(string action1, string action2)
{
return "poke(primaryAddress, (readVal = read(primaryAddress)));\n" ~
"writeFinal(primaryAddress, flag.zero_ = flag.negative_ = " ~
"(writeVal = " ~ action1 ~ "(readVal)));\n" ~
action2 ~ " writeVal;\n";
}
static string RMW_Compare(string action1, string action2)
{
return "poke(primaryAddress, (readVal = read(primaryAddress)));\n" ~
"writeFinal(primaryAddress, flag.zero_ = flag.negative_ = " ~
"(writeVal = " ~ action1 ~ "(readVal)));\n" ~
"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, 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, 0x8F, 0x97])),
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 = (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 = (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);
}
}