twoapple-reboot/src/d6502/cmos.d

239 lines
7.2 KiB
D

/+
+ d6502/cmos.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.cpu;
class Cmos : Cpu
{
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);
flag.zero_ = flag.negative_ = accumulator;
}
final override void dec_subWithCarry(ubyte val)
{
super.dec_subWithCarry(val);
peek(programCounter);
flag.zero_ = flag.negative_ = accumulator;
}
final void addrZeropageI()
{
ubyte vector = readByteOperand();
primaryAddress = readWord(vector, cast(ubyte)(vector + 1));
}
final void addrNone()
{
version(CumulativeCycles) ticks(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, 0xFE])),
RMW("increment")));
mixin(Opcode(mixin(Type2Address(
"DEC", "Read", [0xC6, 0xCE, 0xD6, 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);
}
/* JMP ($$$$) */
override void opcode6C()
{
ushort vector = readWordOperand();
peek(programCounter);
programCounter = readWord(vector, vector + 1);
version(CumulativeCycles) ticks(totalCycles);
}
/* JMP ($$$$,X) */
void opcode7C()
{
baseAddress = readWordOperand();
peek(programCounter);
ushort vector = baseAddress + xIndex;
programCounter = readWord(vector, vector + 1);
version(CumulativeCycles) ticks(totalCycles);
}
/* BIT #$$ */
void opcode89()
{
readVal = operand1 = readFinal(programCounter++);
flag.zero_ = accumulator & readVal;
}
}