twoapple-reboot/src/d6502/base.d

141 lines
3.9 KiB
D

/+
+ d6502/base.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
+/
module d6502.base;
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
{
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;
final 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;
}
version(CycleAccuracy) void delegate() tick;
version(CumulativeCycles) void delegate(int cycles) ticks;
abstract void run(bool continuous);
abstract void stop();
version(CycleAccuracy) abstract bool checkFinalCycle();
abstract void resetLow();
abstract void nmiLow(bool signalLow);
abstract void irqLow(bool signalLow);
}