2012-04-10 23:31:47 +00:00
|
|
|
module cpu.ctfe_d6502;
|
2012-04-07 03:48:37 +00:00
|
|
|
|
|
|
|
|
2012-04-10 23:31:47 +00:00
|
|
|
import cpu.data_d6502;
|
2012-04-08 04:30:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
// The following versions are mutually exclusive.
|
|
|
|
|
|
|
|
// OpDelegates: each opcode is a method of the Cpu class.
|
|
|
|
version(OpDelegates)
|
|
|
|
{
|
|
|
|
enum versionCheck = 1;
|
|
|
|
enum opArray = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpFunctions: each opcode is a free function with a Cpu argument.
|
|
|
|
version(OpFunctions)
|
|
|
|
{
|
|
|
|
enum versionCheck = 2;
|
|
|
|
enum opArray = true;
|
2012-04-08 20:25:35 +00:00
|
|
|
|
|
|
|
// With free functions, strict and cumulative need to be set by
|
|
|
|
// version.
|
|
|
|
version(Strict)
|
|
|
|
enum vStrict = true;
|
|
|
|
else
|
|
|
|
enum vStrict = false;
|
|
|
|
version(Cumulative)
|
|
|
|
enum vCumulative = true;
|
|
|
|
else
|
|
|
|
enum vCumulative = false;
|
2012-04-08 04:30:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// OpSwitch: each opcode is inlined in a 256-case switch.
|
|
|
|
version(OpSwitch)
|
|
|
|
{
|
|
|
|
enum versionCheck = 3;
|
|
|
|
enum opArray = false;
|
|
|
|
}
|
|
|
|
|
2012-04-09 13:52:42 +00:00
|
|
|
/*
|
|
|
|
* 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.)
|
|
|
|
*/
|
2012-04-08 04:30:17 +00:00
|
|
|
version(OpNestedSwitch)
|
|
|
|
{
|
|
|
|
enum versionCheck = 4;
|
|
|
|
enum opArray = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// At least one of the previous versions must be specified.
|
|
|
|
static if (!__traits(compiles, { bool b = opArray; })) enum opArray = 0;
|
|
|
|
static assert (versionCheck);
|
|
|
|
|
|
|
|
|
|
|
|
string OpArrayDef()
|
|
|
|
{
|
|
|
|
version(OpDelegates)
|
|
|
|
return q{void delegate()[256] opcodes;};
|
|
|
|
else version(OpFunctions)
|
|
|
|
return q{void function(typeof(this))[256] opcodes;};
|
|
|
|
else
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
string OpArrayInit()
|
|
|
|
{
|
|
|
|
static if (!opArray) return "";
|
|
|
|
else
|
|
|
|
{
|
|
|
|
string ret;
|
|
|
|
foreach (op; 0..256)
|
|
|
|
{
|
|
|
|
version(OpDelegates)
|
2012-04-09 13:52:42 +00:00
|
|
|
ret ~= Fmt("opcodes[0x#] = &opcode_#;\n",
|
|
|
|
Hex2(op), Hex2(op));
|
2012-04-08 04:30:17 +00:00
|
|
|
version(OpFunctions)
|
2012-04-09 13:52:42 +00:00
|
|
|
ret ~= Fmt("opcodes[0x#] = &opcode_#!(typeof(this));\n",
|
|
|
|
Hex2(op), Hex2(op));
|
2012-04-08 04:30:17 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-08 20:25:35 +00:00
|
|
|
string OpBodies(string chip, bool strict, bool cumulative)
|
2012-04-08 04:30:17 +00:00
|
|
|
{
|
|
|
|
static if (!opArray) return "";
|
|
|
|
else
|
|
|
|
{
|
|
|
|
string ret;
|
|
|
|
foreach (op; 0..256)
|
|
|
|
{
|
|
|
|
version(OpDelegates)
|
|
|
|
ret ~= "final void opcode_" ~ Hex2(op) ~ "()\n{\n" ~
|
2012-04-08 20:25:35 +00:00
|
|
|
If!(cumulative)("int cycles = 1;\n") ~
|
|
|
|
OpBody(op, chip, strict, cumulative) ~ "}\n";
|
2012-04-08 04:30:17 +00:00
|
|
|
version(OpFunctions)
|
|
|
|
ret ~= "void opcode_" ~ Hex2(op) ~
|
|
|
|
"(T)(T cpu) if (is" ~ chip ~ "!T)\n{\n" ~
|
2012-04-08 20:25:35 +00:00
|
|
|
If!(cumulative)("int cycles = 1;\n") ~
|
|
|
|
OpBody(op, chip, strict, cumulative) ~ "}\n";
|
2012-04-08 04:30:17 +00:00
|
|
|
}
|
2012-04-10 03:32:24 +00:00
|
|
|
/+
|
|
|
|
foreach (op; 13..256)
|
|
|
|
version(OpDelegates)
|
|
|
|
ret ~= "final void opcode_" ~ Hex2(op) ~ "()\n{\n" ~
|
|
|
|
If!(cumulative)("int cycles = 1;\n") ~
|
|
|
|
"" ~ "}\n";
|
|
|
|
version(OpFunctions)
|
|
|
|
ret ~= "void opcode_" ~ Hex2(op) ~
|
|
|
|
"(T)(T cpu) if (is" ~ chip ~ "!T)\n{\n" ~
|
|
|
|
If!(cumulative)("int cycles = 1;\n") ~
|
|
|
|
"" ~ "}\n";
|
|
|
|
+/
|
2012-04-08 04:30:17 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-08 20:25:35 +00:00
|
|
|
string OpExecute(string chip, bool strict, bool cumulative)
|
2012-04-08 04:30:17 +00:00
|
|
|
{
|
|
|
|
version(OpDelegates)
|
|
|
|
return q{opcodes[opcode]();};
|
|
|
|
version(OpFunctions)
|
|
|
|
return q{opcodes[opcode](this);};
|
|
|
|
version(OpSwitch)
|
2012-04-08 20:25:35 +00:00
|
|
|
return Switch256(chip, strict, cumulative);
|
2012-04-08 04:30:17 +00:00
|
|
|
version(OpNestedSwitch)
|
2012-04-08 20:25:35 +00:00
|
|
|
return Switch16x16(chip, strict, cumulative);
|
2012-04-08 04:30:17 +00:00
|
|
|
}
|
|
|
|
|
2012-04-08 20:25:35 +00:00
|
|
|
string Switch256(string chip, bool strict, bool cumulative)
|
2012-04-08 04:30:17 +00:00
|
|
|
{
|
|
|
|
string ret = "final switch (opcode)\n{\n";
|
|
|
|
foreach (op; 0..256)
|
2012-04-08 20:25:35 +00:00
|
|
|
ret ~= "case 0x" ~ Hex2(op) ~ ":\n" ~
|
|
|
|
OpBody(op, chip, strict, cumulative) ~ "break;\n";
|
2012-04-08 04:30:17 +00:00
|
|
|
return ret ~ "}\n";
|
|
|
|
}
|
|
|
|
|
2012-04-08 20:25:35 +00:00
|
|
|
string Switch16x16(string chip, bool strict, bool cumulative)
|
2012-04-08 04:30:17 +00:00
|
|
|
{
|
|
|
|
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);
|
2012-04-08 20:25:35 +00:00
|
|
|
ret ~= "case 0x0" ~ Hex1(opLo) ~ ":\n" ~
|
|
|
|
OpBody(op, chip, strict, cumulative) ~
|
|
|
|
"break;\n";
|
2012-04-08 04:30:17 +00:00
|
|
|
}
|
|
|
|
ret ~= "}\nbreak;\n";
|
|
|
|
}
|
|
|
|
return ret ~ "}\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 08:52:15 +00:00
|
|
|
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;
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
struct Env
|
|
|
|
{
|
|
|
|
int op;
|
|
|
|
string chip;
|
|
|
|
bool s, c;
|
|
|
|
bool nmos, cmos;
|
|
|
|
int mode;
|
|
|
|
int exCyc;
|
|
|
|
|
|
|
|
this(int op, string chip, bool s, bool c)
|
|
|
|
{
|
|
|
|
this.op = op;
|
|
|
|
this.chip = chip;
|
|
|
|
this.s = s;
|
|
|
|
this.c = c;
|
|
|
|
nmos = (chip == "6502");
|
|
|
|
cmos = !nmos;
|
|
|
|
mode = opMode(op, chip);
|
|
|
|
exCyc = opExCyc(op, chip);
|
|
|
|
}
|
|
|
|
}
|
2012-04-11 08:52:15 +00:00
|
|
|
|
2012-04-09 13:52:42 +00:00
|
|
|
string OpBody(int op, string chip, bool s, bool c)
|
2012-04-08 20:25:35 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
auto env = Env(op, chip, s, c);
|
2012-04-12 02:05:29 +00:00
|
|
|
string ret = ((op == 0x20) ? "" : Address(env));
|
|
|
|
|
2012-04-08 20:25:35 +00:00
|
|
|
final switch (opName(op, chip))
|
|
|
|
{
|
|
|
|
case "BRK":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Break(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "RTI":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RetInt(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "JSR":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= JumpSub(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "RTS":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RetSub(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "JMP":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Jump(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "KIL":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= _PC ~ "--;\n";
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "BPL":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Branch("!(" ~ _N ~ " & 0x80)", env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "BMI":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Branch("(" ~ _N ~ " & 0x80)", env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "BVC":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Branch("!" ~ _V, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "BVS":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Branch(_V, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "BRA":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Branch("true", env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "BCC":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Branch("!" ~ _C, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "BCS":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Branch(_C, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "BNE":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Branch(_Z, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "BEQ":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Branch("!" ~ _Z, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "CLC":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= ClearFlag(_C);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "SEC":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= SetFlag(_C);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "CLI":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= ClearFlag(_I);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "SEI":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= SetFlag(_I);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "CLV":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= ClearFlag(_V);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "CLD":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= ClearFlag(_D);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "SED":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= SetFlag(_D);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "NOP":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Nop(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "TAX":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Transfer(_A, _X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "TXA":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Transfer(_X, _A, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "TAY":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Transfer(_A, _Y, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "TYA":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Transfer(_Y, _A, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "TSX":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Transfer(_S, _X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "TXS":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Transfer(_X, _S, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "DEX":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Dec(_X);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "DEY":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Dec(_Y);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "INX":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Inc(_X);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "INY":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Inc(_Y);
|
|
|
|
break;
|
2012-04-09 13:52:42 +00:00
|
|
|
case "PHP":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Push(Attr("statusToByte()"), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "PLP":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= PullStatus(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "PLA":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= PullReg(_A, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "PLX":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= PullReg(_X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "PLY":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= PullReg(_Y, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "PHA":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= PushReg(_A, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "PHX":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= PushReg(_X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "PHY":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= PushReg(_Y, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "LDA":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Load(_A, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "LDX":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Load(_X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "LDY":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Load(_Y, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "STA":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Store(_A, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "STX":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Store(_X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "STY":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Store(_Y, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "STZ":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Store("0", env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "CMP":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Compare(_A, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "CPX":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Compare(_X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "CPY":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Compare(_Y, env);
|
|
|
|
break;
|
2012-04-11 08:52:15 +00:00
|
|
|
case "BIT":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Bit(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "ORA":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Logic("|=", env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "AND":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Logic("&=", env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "EOR":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Logic("^=", env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "ADC":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Add(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "SBC":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Sub(env);
|
|
|
|
break;
|
2012-04-11 08:52:15 +00:00
|
|
|
case "INC":
|
|
|
|
if (op == 0x1a)
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Inc(_A);
|
2012-04-11 08:52:15 +00:00
|
|
|
else
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RMW(Inc("data"), env);
|
|
|
|
break;
|
2012-04-11 08:52:15 +00:00
|
|
|
case "DEC":
|
|
|
|
if (op == 0x3a)
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= Dec(_A);
|
2012-04-11 08:52:15 +00:00
|
|
|
else
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RMW(Dec("data"), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "ASL":
|
2012-04-10 03:32:24 +00:00
|
|
|
if (op == 0x0a)
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= ShiftLeft(_A);
|
2012-04-10 03:32:24 +00:00
|
|
|
else
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RMW(ShiftLeft("data"), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "ROL":
|
2012-04-10 03:32:24 +00:00
|
|
|
if (op == 0x2a)
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RotateLeft(_A);
|
2012-04-10 03:32:24 +00:00
|
|
|
else
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RMW(RotateLeft("data"), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "LSR":
|
2012-04-10 03:32:24 +00:00
|
|
|
if (op == 0x4a)
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= ShiftRight(_A);
|
2012-04-10 03:32:24 +00:00
|
|
|
else
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RMW(ShiftRight("data"), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "ROR":
|
2012-04-10 03:32:24 +00:00
|
|
|
if (op == 0x6a)
|
2012-04-12 07:18:33 +00:00
|
|
|
ret ~= RotateRight(_A);
|
2012-04-10 03:32:24 +00:00
|
|
|
else
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RMW(RotateRight("data"), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "TRB":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RMW(TestReset(), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "TSB":
|
2012-04-11 13:27:46 +00:00
|
|
|
ret ~= RMW(TestSet(), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "LAS":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= LAS_Undoc(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "LAX":
|
2012-04-12 02:05:29 +00:00
|
|
|
if (op != 0xAB)
|
|
|
|
ret ~= Load(_A ~ " = " ~ _X, env);
|
|
|
|
else
|
2012-04-12 07:15:21 +00:00
|
|
|
ret ~= LAX_IMM_Undoc(env);
|
2012-04-12 02:05:29 +00:00
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "SAX":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= Store(_A ~ " & " ~ _X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "ANC":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= ANC_Undoc(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "ALR":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= ALR_Undoc(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "ARR":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= ARR_Undoc(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "AXS":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= AXS_Undoc(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "AHX":
|
2012-04-12 07:15:21 +00:00
|
|
|
ret ~= Strange_Undoc(_A ~ " &" ~ _X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "SHY":
|
2012-04-12 07:15:21 +00:00
|
|
|
ret ~= Strange_Undoc(_Y, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "SHX":
|
2012-04-12 07:15:21 +00:00
|
|
|
ret ~= Strange_Undoc(_X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "TAS":
|
2012-04-12 07:15:21 +00:00
|
|
|
ret ~= Strange_Undoc(_S ~ " = " ~ _A ~ " & " ~ _X, env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "XAA":
|
2012-04-12 07:15:21 +00:00
|
|
|
ret ~= XAA_Undoc(env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "SLO":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= RMW_Undoc(ShiftLeft("data"),
|
|
|
|
SetNZ(_A ~ " |= data"), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "RLA":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= RMW_Undoc(RotateLeft("data"),
|
|
|
|
SetNZ(_A ~ " &= data"), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "SRE":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= RMW_Undoc(ShiftRight("data"),
|
|
|
|
SetNZ(_A ~ " ^= data"), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "RRA":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= RMW_Undoc(RotateRight("data"), AddBase(env), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "DCP":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= RMW_Undoc(Dec("data"), CompareBase(_A, env), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
case "ISC":
|
2012-04-12 02:05:29 +00:00
|
|
|
ret ~= RMW_Undoc(Inc("data"), SubBase(env), env);
|
|
|
|
break;
|
2012-04-08 20:25:35 +00:00
|
|
|
}
|
2012-04-11 13:27:46 +00:00
|
|
|
return ret ~ Done(env);
|
2012-04-08 20:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Break(Env env)
|
2012-04-08 20:25:35 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return IncPC() ~
|
|
|
|
PushPC(env) ~
|
|
|
|
Push(Attr("statusToByte()"), env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
SetFlag(_I) ~
|
2012-04-11 13:27:46 +00:00
|
|
|
ReadWord(_PC, "IRQ_VECTOR", env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string JumpSub(Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadOp(Local("ushort", "address"), env) ~
|
|
|
|
Peek(STACK, env) ~
|
|
|
|
PushPC(env) ~
|
|
|
|
LoadHiByte("address", _PC ~ "++", env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
_PC ~ " = address;\n";
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string RetSub(Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return Peek(STACK, env) ~
|
|
|
|
PullPC(env) ~
|
|
|
|
Peek(_PC, env) ~
|
2012-04-09 13:52:42 +00:00
|
|
|
IncPC();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string RetInt(Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return PullStatus(env) ~
|
|
|
|
PullPC(env);
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Jump(Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool cmos = env.cmos;
|
|
|
|
bool nmos = env.nmos;
|
2012-04-10 03:32:24 +00:00
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
if (env.op == 0x4c)
|
2012-04-12 02:05:29 +00:00
|
|
|
return _PC ~ " = address;\n";
|
2012-04-11 13:27:46 +00:00
|
|
|
else if (env.op == 0x6c)
|
|
|
|
return ReadWordOp("ushort", "base", env) ~
|
|
|
|
If!(cmos)(
|
|
|
|
Peek(_PC, env)) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
ReadWordBasic(_PC, "base",
|
2012-04-10 03:32:24 +00:00
|
|
|
If!(nmos)(
|
|
|
|
"(base & 0xFF00) | cast(ubyte)(base + 1)",
|
2012-04-11 13:27:46 +00:00
|
|
|
"cast(ushort)(base + 1)"), env);
|
|
|
|
else if (env.op == 0x7c)
|
|
|
|
return ReadWordOp("ushort", "base", env) ~
|
|
|
|
Peek(_PC, env) ~
|
|
|
|
ReadWord(_PC, "cast(ushort)(base + " ~ _X ~ ")", env);
|
2012-04-10 03:32:24 +00:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Branch(string check, Env env)
|
2012-04-10 03:32:24 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadOp(Local("ushort", "base"), env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
"if (" ~ check ~ ")\n{\n" ~
|
2012-04-11 13:27:46 +00:00
|
|
|
Peek(_PC, env) ~
|
|
|
|
Local("ushort", "address") ~
|
|
|
|
" = cast(ushort)(" ~ _PC ~ " + cast(byte)base);\n" ~
|
|
|
|
CheckShortcut(_PC, "address", env) ~
|
|
|
|
_PC ~ " = address;\n" ~
|
2012-04-11 08:52:15 +00:00
|
|
|
"}\n";
|
2012-04-10 03:32:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Nop(Env env)
|
2012-04-10 03:32:24 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
if (env.mode == IMP || env.mode == NP1 || env.mode == NP8)
|
2012-04-12 02:05:29 +00:00
|
|
|
return ""; // XXX add np1/np8 stuff
|
2012-04-10 03:32:24 +00:00
|
|
|
else
|
2012-04-12 02:05:29 +00:00
|
|
|
return PreAccess(env) ~
|
2012-04-11 13:27:46 +00:00
|
|
|
ReadRaw("address") ~ ";\n";
|
2012-04-10 03:32:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Transfer(string source, string dest, Env env)
|
2012-04-10 03:32:24 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return dest ~ " = " ~ source ~ ";\n" ~
|
|
|
|
((env.op != 0x9a) ? SetNZ(dest) : "");
|
2012-04-10 03:32:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string PullReg(string reg, Env env)
|
2012-04-10 03:32:24 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return Peek(STACK, env) ~
|
|
|
|
PullInto(reg, env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
SetNZ(reg);
|
2012-04-10 03:32:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string PushReg(string reg, Env env)
|
2012-04-10 03:32:24 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return Push(reg, env);
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Load(string reg, Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-12 02:05:29 +00:00
|
|
|
return ReadInto(reg, "address", env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
SetNZ(reg);
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Store(string reg, Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-12 02:05:29 +00:00
|
|
|
return Write("address", reg, env);
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Compare(string reg, Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-12 02:05:29 +00:00
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
|
|
|
CompareBase(reg, env);
|
|
|
|
}
|
|
|
|
|
|
|
|
string CompareBase(string reg, Env env)
|
|
|
|
{
|
|
|
|
return UpdateFlag(_C, reg ~ " >= data") ~
|
2012-04-11 08:52:15 +00:00
|
|
|
SetNZ("cast(ubyte)(" ~ reg ~ " - data)");
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Bit(Env env)
|
2012-04-10 03:32:24 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool notImm = (env.mode != IMM);
|
2012-04-10 03:32:24 +00:00
|
|
|
|
2012-04-12 02:05:29 +00:00
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
2012-04-10 03:32:24 +00:00
|
|
|
If!(notImm)(
|
2012-04-11 08:52:15 +00:00
|
|
|
_N ~ " = data;\n" ~
|
|
|
|
_V ~ " = ((data & 0x40) != 0);\n") ~
|
|
|
|
_Z ~ " = (" ~ _A ~ " & data);\n";
|
2012-04-10 03:32:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Logic(string action, Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-12 02:05:29 +00:00
|
|
|
return ReadInto(_A, action, "address", env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
SetNZ(_A);
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Add(Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-12 02:05:29 +00:00
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
|
|
|
AddBase(env);
|
|
|
|
}
|
|
|
|
|
|
|
|
string AddBase(Env env)
|
|
|
|
{
|
|
|
|
return "if (" ~ _D ~ ")\n{\n" ~
|
2012-04-11 13:27:46 +00:00
|
|
|
DecAdd(env) ~
|
2012-04-09 13:52:42 +00:00
|
|
|
"}\nelse\n{\n" ~
|
2012-04-11 13:27:46 +00:00
|
|
|
HexAdd(env) ~
|
2012-04-09 13:52:42 +00:00
|
|
|
"}\n";
|
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string HexAdd(Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return "uint sum = " ~ _A ~ " + data + " ~ _C ~ ";\n" ~
|
|
|
|
_V ~
|
|
|
|
" = (!((" ~ _A ~ " ^ data) & 0x80)) && ((data ^ sum) & 0x80);\n" ~
|
|
|
|
_C ~ " = (sum > 0xFF);\n" ~
|
|
|
|
SetNZ(_A ~ " = cast(ubyte)sum");
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string DecAdd(Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool cmos = env.cmos;
|
2012-04-09 13:52:42 +00:00
|
|
|
|
2012-04-11 08:52:15 +00:00
|
|
|
return "int a = " ~ _A ~ ";\n" ~
|
|
|
|
"int al = (a & 0x0F) + (data & 0x0F) + " ~ _C ~ ";\n" ~
|
2012-04-09 13:52:42 +00:00
|
|
|
"if (al >= 0x0A)\n" ~
|
|
|
|
"al = ((al + 0x06) & 0x0F) + 0x10;\n" ~
|
|
|
|
"a = (a & 0xF0) + (data & 0xF0) + al;\n" ~
|
|
|
|
If!(cmos)("",
|
2012-04-11 08:52:15 +00:00
|
|
|
_N ~ " = cast(ubyte)a;\n" ~
|
|
|
|
_Z ~ " = cast(ubyte)(" ~ _A ~ " + data + " ~ _C ~ ");\n") ~
|
|
|
|
_V ~
|
|
|
|
" = (!((" ~ _A ~ " ^ data) & 0x80)) && ((data ^ a) & 0x80);\n" ~
|
2012-04-09 13:52:42 +00:00
|
|
|
"if (a >= 0xA0)\n" ~
|
|
|
|
"a = a + 0x60;\n" ~
|
2012-04-11 08:52:15 +00:00
|
|
|
_C ~ " = (a >= 0x100);\n" ~
|
2012-04-09 13:52:42 +00:00
|
|
|
If!(cmos)(
|
2012-04-11 13:27:46 +00:00
|
|
|
SetNZ(_A ~ " = cast(ubyte)a") ~ Peek(_PC, env),
|
2012-04-11 08:52:15 +00:00
|
|
|
_A ~ " = cast(ubyte)a;\n");
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Sub(Env env)
|
2012-04-12 02:05:29 +00:00
|
|
|
{
|
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
|
|
|
SubBase(env);
|
|
|
|
}
|
|
|
|
|
|
|
|
string SubBase(Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool nmos = env.nmos;
|
|
|
|
|
2012-04-12 02:05:29 +00:00
|
|
|
return "if (" ~ _D ~ ")\n{\n" ~
|
2012-04-11 13:27:46 +00:00
|
|
|
If!(nmos)(DecSubNMOS(), DecSubCMOS(env)) ~
|
2012-04-09 13:52:42 +00:00
|
|
|
"}\nelse\n{\n" ~
|
2012-04-11 13:27:46 +00:00
|
|
|
HexSub() ~
|
2012-04-09 13:52:42 +00:00
|
|
|
"}\n";
|
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string HexSub()
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return "uint diff = " ~ _A ~ " - data - !" ~ _C ~ ";\n" ~
|
|
|
|
_V ~
|
|
|
|
" = ((" ~ _A ~ " ^ diff) & 0x80) && ((" ~
|
|
|
|
_A ~ " ^ data) & 0x80);\n" ~
|
|
|
|
_C ~ " = (diff < 0x100);\n" ~
|
|
|
|
SetNZ(_A ~ " = cast(ubyte)diff");
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string DecSubNMOS()
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return "int a = " ~ _A ~ ";\n" ~
|
|
|
|
"int al = (a & 0x0F) - (data & 0x0F) - !" ~ _C ~ ";\n" ~
|
2012-04-09 13:52:42 +00:00
|
|
|
"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" ~
|
2012-04-11 08:52:15 +00:00
|
|
|
"uint diff = " ~ _A ~ " - data - !" ~ _C ~ ";\n" ~
|
|
|
|
_V ~
|
|
|
|
" = ((" ~ _A ~ " ^ diff) & 0x80) && ((" ~
|
|
|
|
_A ~ " ^ data) & 0x80);\n" ~
|
|
|
|
_C ~ " = (diff < 0x100);\n" ~
|
2012-04-09 13:52:42 +00:00
|
|
|
SetNZ("cast(ubyte)diff") ~
|
2012-04-11 08:52:15 +00:00
|
|
|
_A ~ " = cast(ubyte)a;\n";
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string DecSubCMOS(Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return "int a = " ~ _A ~ ";\n" ~
|
|
|
|
"int al = (a & 0x0F) - (data & 0x0F) - !" ~ _C ~ ";\n" ~
|
|
|
|
"a = a - data - !" ~ _C ~ ";\n" ~
|
2012-04-09 13:52:42 +00:00
|
|
|
"if (a < 0) a = a - 0x60;\n" ~
|
|
|
|
"if (al < 0) a = a - 0x06;\n" ~
|
2012-04-11 08:52:15 +00:00
|
|
|
"uint diff = " ~ _A ~ " - data - !" ~ _C ~ ";\n" ~
|
|
|
|
_V ~
|
|
|
|
" = ((" ~ _A ~ " ^ diff) & 0x80) && ((" ~
|
|
|
|
_A ~ " ^ data) & 0x80);\n" ~
|
|
|
|
_C ~ " = (diff < 0x100);\n" ~
|
2012-04-11 13:27:46 +00:00
|
|
|
Peek(_PC, env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
SetNZ(_A ~ " = cast(ubyte)a");
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-10 03:32:24 +00:00
|
|
|
string Inc(string val)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-10 03:32:24 +00:00
|
|
|
return val ~ "++;\n" ~
|
|
|
|
SetNZ(val);
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-10 03:32:24 +00:00
|
|
|
string Dec(string val)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-10 03:32:24 +00:00
|
|
|
return val ~ "--;\n" ~
|
|
|
|
SetNZ(val);
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-10 03:32:24 +00:00
|
|
|
string ShiftLeft(string val)
|
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return _C ~ " = (" ~ val ~ " > 0x7F);\n" ~
|
2012-04-10 03:32:24 +00:00
|
|
|
SetNZ(val ~ " = cast(ubyte)(" ~ val ~ " << 1)");
|
|
|
|
}
|
|
|
|
|
2012-04-11 08:52:15 +00:00
|
|
|
|
2012-04-10 03:32:24 +00:00
|
|
|
string RotateLeft(string val)
|
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return "auto oldC = " ~ _C ~ ";\n" ~
|
|
|
|
_C ~ " = (" ~ val ~ " > 0x7f);\n" ~
|
2012-04-10 03:32:24 +00:00
|
|
|
SetNZ(val ~ " = cast(ubyte)(" ~ val ~ " << 1 | (oldC ? 1 : 0))");
|
|
|
|
}
|
|
|
|
|
2012-04-11 08:52:15 +00:00
|
|
|
|
2012-04-10 03:32:24 +00:00
|
|
|
string ShiftRight(string val)
|
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return _C ~ " = ((" ~ val ~ " & 0x01) != 0);\n" ~
|
2012-04-10 03:32:24 +00:00
|
|
|
SetNZ(val ~ " = " ~ val ~ " >> 1");
|
|
|
|
}
|
|
|
|
|
2012-04-11 08:52:15 +00:00
|
|
|
|
2012-04-10 03:32:24 +00:00
|
|
|
string RotateRight(string val)
|
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return "auto oldC = " ~ _C ~ ";\n" ~
|
|
|
|
_C ~ " = ((" ~ val ~ " & 0x01) != 0);\n" ~
|
2012-04-10 03:32:24 +00:00
|
|
|
SetNZ(val ~ " = (" ~ val ~ " >> 1 | (oldC ? 0x80 : 0))");
|
|
|
|
}
|
|
|
|
|
2012-04-11 08:52:15 +00:00
|
|
|
|
|
|
|
string TestReset()
|
|
|
|
{
|
|
|
|
return _Z ~ " = data & " ~ _A ~ ";\n" ~
|
|
|
|
"data &= (~" ~ _A ~ ");\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string TestSet()
|
|
|
|
{
|
|
|
|
return _Z ~ " = data & " ~ _A ~ ";\n" ~
|
|
|
|
"data |= " ~ _A ~ ";\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string RMW(string action, Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool nmos = env.nmos;
|
2012-04-09 13:52:42 +00:00
|
|
|
|
2012-04-12 02:05:29 +00:00
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
2012-04-11 13:27:46 +00:00
|
|
|
If!(nmos)(Poke("address", "data", env),
|
|
|
|
Peek("address", env)) ~
|
2012-04-09 13:52:42 +00:00
|
|
|
action ~
|
2012-04-11 13:27:46 +00:00
|
|
|
Write("address", "data", env);
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-12 02:05:29 +00:00
|
|
|
string RMW_Undoc(string action1, string action2, Env env)
|
|
|
|
{
|
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
|
|
|
Poke("address", "data", env) ~
|
|
|
|
action1 ~
|
|
|
|
Write("address", "data", env) ~
|
|
|
|
action2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string LAS_Undoc(Env env)
|
|
|
|
{
|
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
|
|
|
SetNZ(_X ~ " = " ~ _A ~ " = (" ~ _S ~ " & data)");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string ARR_Undoc(Env env)
|
|
|
|
{
|
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
|
|
|
"ubyte tmp1 = data & " ~ _A ~ ";\n" ~
|
|
|
|
"if (" ~ _D ~ ")\n{\n" ~
|
|
|
|
"ubyte tmp2 = cast(ubyte)((tmp1 >> 1) + (" ~
|
|
|
|
_C ~ " ? 0x80 : 0));\n" ~
|
|
|
|
_N ~ " = " ~ _Z ~ " = tmp2;\n" ~
|
|
|
|
_V ~ " = (((tmp2 ^ tmp1) & 0x40) != 0);\n" ~
|
|
|
|
"if ((data & 0x0F) + (tmp1 & 0x01) > 5)\n" ~
|
|
|
|
"tmp2 = (tmp2 & 0xF0) + ((tmp2 + 0x6) & 0x0F);\n" ~
|
|
|
|
"if (tmp1 + (tmp1 & 0x10) >= 0x60)\n{\n" ~
|
|
|
|
"tmp2 += 0x60;\n" ~
|
|
|
|
SetFlag(_C) ~
|
|
|
|
"}\nelse\n" ~
|
|
|
|
ClearFlag(_C) ~
|
|
|
|
_A ~ " = tmp2;\n" ~
|
|
|
|
"}\nelse{\n" ~
|
|
|
|
_A ~ " = cast(ubyte)((tmp1 >> 1) + (" ~
|
|
|
|
_C ~ " ? 0x80 : 0));\n" ~
|
|
|
|
_N ~ " = " ~ _Z ~ " = " ~_A ~ ";\n" ~
|
|
|
|
"tmp1 >>= 7;\n" ~
|
|
|
|
_C ~ " = (tmp1 != 0);\n" ~
|
|
|
|
_V ~ " = ((tmp1 ^ ((" ~ _A ~ " >> 5) & 1)) != 0);\n}";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string ANC_Undoc(Env env)
|
|
|
|
{
|
|
|
|
return ReadInto(_A, "address", env) ~
|
|
|
|
SetNZ(_A) ~
|
|
|
|
_C ~ " = (" ~ _A ~ " > 0x7f);\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string ALR_Undoc(Env env)
|
|
|
|
{
|
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
|
|
|
_A ~ " &= data;\n" ~
|
|
|
|
ShiftRight(_A);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string AXS_Undoc(Env env)
|
|
|
|
{
|
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
|
|
|
_X ~ " &= " ~ _A ~ ";\n" ~
|
|
|
|
CompareBase(_X, env);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-12 07:15:21 +00:00
|
|
|
/*
|
|
|
|
* This opcode is unstable on certain machines; see
|
|
|
|
* http://visual6502.org/wiki/index.php?title=6502_Opcode_8B_(XAA,ANE)
|
|
|
|
*/
|
|
|
|
string XAA_Undoc(Env env)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* As far as I can tell, the only programs in the wild that depend
|
|
|
|
* on this opcode are certain C64 Mastertronic tape loaders; this
|
|
|
|
* magic value is used in the VICE emulator to make them work.
|
|
|
|
*/
|
|
|
|
string MAGIC = "0xff";
|
|
|
|
|
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
|
|
|
_A ~ " = ((" ~ _A ~ " | " ~ MAGIC ~ ") & " ~ _X ~ " & data);\n" ~
|
|
|
|
SetNZ(_A);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This opcode is unstable on certain machines.
|
|
|
|
*/
|
|
|
|
string LAX_IMM_Undoc(Env env)
|
|
|
|
{
|
|
|
|
// From the VICE emulator.
|
|
|
|
string MAGIC = "0xee";
|
|
|
|
|
|
|
|
return ReadInto(Local("ubyte", "data"), "address", env) ~
|
|
|
|
_A ~ " = ((" ~ _A ~ " | " ~ MAGIC ~ ") & " ~ _X ~ " & data);\n" ~
|
|
|
|
SetNZ(_A);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: these are affected by DMA on the C64.
|
|
|
|
string Strange_Undoc(string val, Env env)
|
|
|
|
{
|
|
|
|
return "ubyte addrHi = cast(ubyte)((address >> 8) + 1);\n" ~
|
|
|
|
Local("ubyte", "data") ~ " = " ~ val ~ " & addrHi;\n" ~
|
|
|
|
"address = (guess == address) ? address : " ~
|
|
|
|
"((data << 8) | (address & 0xff));\n" ~
|
|
|
|
Write("address", "data", env);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 08:52:15 +00:00
|
|
|
string Local(string type)
|
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
version(OpFunctions)
|
|
|
|
return type ~ " ";
|
|
|
|
else
|
|
|
|
return "";
|
|
|
|
/+
|
2012-04-11 08:52:15 +00:00
|
|
|
version(OpSwitch)
|
|
|
|
return "";
|
|
|
|
else version(OpNestedSwitch)
|
|
|
|
return "";
|
|
|
|
else
|
2012-04-11 13:27:46 +00:00
|
|
|
return type ~ " ";
|
|
|
|
+/
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string Local(string type, string var)
|
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
version(OpFunctions)
|
|
|
|
return type ~ " " ~ var;
|
|
|
|
else
|
|
|
|
return var;
|
|
|
|
/+
|
2012-04-11 08:52:15 +00:00
|
|
|
version(OpSwitch)
|
|
|
|
return var;
|
|
|
|
else version(OpNestedSwitch)
|
|
|
|
return var;
|
|
|
|
else
|
|
|
|
return type ~ " " ~ var;
|
2012-04-11 13:27:46 +00:00
|
|
|
+/
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Attr(string var)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
version(OpFunctions)
|
|
|
|
return "cpu." ~ var;
|
|
|
|
else
|
|
|
|
return var;
|
|
|
|
}
|
2012-04-09 13:52:42 +00:00
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
|
|
|
|
string Address(Env env)
|
|
|
|
{
|
|
|
|
final switch (env.mode)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
|
|
|
case IMP:
|
2012-04-12 02:05:29 +00:00
|
|
|
return AddrIMP(env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case IMM:
|
2012-04-11 13:27:46 +00:00
|
|
|
return AddrIMM(env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case ZP:
|
2012-04-11 13:27:46 +00:00
|
|
|
return AddrZP(env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case ZPX:
|
2012-04-11 13:27:46 +00:00
|
|
|
return AddrZPXY(_X, env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case ZPY:
|
2012-04-11 13:27:46 +00:00
|
|
|
return AddrZPXY(_Y, env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case IZX:
|
2012-04-11 13:27:46 +00:00
|
|
|
return AddrIZX(env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case IZY:
|
2012-04-11 13:27:46 +00:00
|
|
|
return AddrIZY(env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case ABS:
|
2012-04-11 13:27:46 +00:00
|
|
|
return AddrABS(env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case ABX:
|
2012-04-11 13:27:46 +00:00
|
|
|
return AddrABXY(_X, env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case ABY:
|
2012-04-11 13:27:46 +00:00
|
|
|
return AddrABXY(_Y, env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case IND:
|
2012-04-11 13:27:46 +00:00
|
|
|
return "";
|
2012-04-09 13:52:42 +00:00
|
|
|
case REL:
|
2012-04-11 13:27:46 +00:00
|
|
|
return "";
|
2012-04-09 13:52:42 +00:00
|
|
|
case ZPI:
|
2012-04-11 13:27:46 +00:00
|
|
|
return AddrZPI(env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case ABI:
|
2012-04-11 13:27:46 +00:00
|
|
|
return "";
|
2012-04-09 13:52:42 +00:00
|
|
|
case NP1:
|
2012-04-10 03:32:24 +00:00
|
|
|
return "";
|
2012-04-09 13:52:42 +00:00
|
|
|
case NP8:
|
2012-04-12 02:05:29 +00:00
|
|
|
return AddrNP8(env);
|
2012-04-09 13:52:42 +00:00
|
|
|
case KIL:
|
2012-04-11 13:27:46 +00:00
|
|
|
return "";
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
return "";
|
2012-04-08 20:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string AddrIMM(Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
|
|
|
return Local("ushort") ~ "address = " ~ _PC ~ "++;\n";
|
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string AddrIMP(Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return Peek(_PC, env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string AddrZP(Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadOp(Local("ushort", "address"), env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string AddrZPXY(string reg, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool nmos = env.nmos;
|
2012-04-11 08:52:15 +00:00
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadOp(Local("ushort", "base"), env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
If!(nmos)(
|
2012-04-11 13:27:46 +00:00
|
|
|
Peek("base", env),
|
|
|
|
Peek(_PC, env)) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
Local("ushort") ~
|
|
|
|
"address = cast(ubyte)(base + " ~ reg ~ ");\n";
|
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string AddrIZX(Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool nmos = env.nmos;
|
|
|
|
|
|
|
|
return ReadOp(Local("ushort", "base"), env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
If!(nmos)(
|
2012-04-11 13:27:46 +00:00
|
|
|
Peek("base", env),
|
|
|
|
Peek(_PC, env)) ~
|
|
|
|
ReadWordZP("ushort", "address", "base + " ~ _X, env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string AddrIZY(Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadOp("ubyte vector", env) ~
|
|
|
|
ReadWordZP("ushort", "base", "vector", env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
Local("ushort") ~
|
|
|
|
"address = cast(ushort)(base + " ~ _Y ~ ");\n" ~
|
2012-04-11 13:27:46 +00:00
|
|
|
CheckShortcut("base", "address", env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string AddrABS(Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadWordOp("ushort", "address", env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string AddrABXY(string reg, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadWordOp("ushort", "base", env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
Local("ushort") ~ "address = cast(ushort)(base + " ~ reg ~ ");\n" ~
|
2012-04-11 13:27:46 +00:00
|
|
|
CheckShortcut("base", "address", env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string AddrZPI(Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadOp(Local("ushort", "base"), env) ~
|
|
|
|
ReadWordZP("ushort", "address", "base", env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-12 02:05:29 +00:00
|
|
|
string AddrNP8(Env env)
|
|
|
|
{
|
|
|
|
return ReadOp(Local("ushort", "base"), env) ~
|
|
|
|
Peek(_PC, env) ~
|
|
|
|
IncPC() ~
|
|
|
|
Peek("0xff00 | base", env) ~
|
|
|
|
Peek("0xffff", env) ~
|
|
|
|
Peek("0xffff", env) ~
|
|
|
|
Peek("0xffff", env) ~
|
|
|
|
Peek("0xffff", env);
|
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string CheckShortcut(string base, string addr, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool nmos = env.nmos;
|
|
|
|
int exCyc = env.exCyc;
|
|
|
|
|
|
|
|
return "ushort guess = (" ~ base ~ " & 0xFF00) | cast(ubyte)" ~ addr ~ ";\n" ~
|
2012-04-11 08:52:15 +00:00
|
|
|
"if (guess != " ~ addr ~ ")\n{\n" ~
|
2012-04-11 13:27:46 +00:00
|
|
|
If!(nmos)(Peek("guess", env),
|
|
|
|
Peek(_PC, env)) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
"}\n" ~
|
2012-04-11 13:27:46 +00:00
|
|
|
If!(exCyc)("else\n{\n" ~ Peek("address", env) ~ "}\n");
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string ReadInto(string var, string action, string addr, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return PreAccess(env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
var ~ " " ~ action ~ " " ~ ReadRaw("(" ~ addr ~ ")") ~ ";\n";
|
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string ReadInto(string var, string addr, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadInto(var, "=", addr, env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string ReadOp(string var, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadInto(var, _PC ~ "++", env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string ReadRaw(string addr)
|
|
|
|
{
|
|
|
|
return Attr("memory") ~ ".read(" ~ addr ~")";
|
|
|
|
}
|
|
|
|
|
|
|
|
string ReadWordBasic(string type, string var, string addr1, string addr2,
|
2012-04-11 13:27:46 +00:00
|
|
|
Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return LoadLoByte(type, var, addr1, env) ~
|
|
|
|
LoadHiByte(var, addr2, env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string ReadWordBasic(string var, string addr1, string addr2, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadWordBasic("", var, addr1, addr2, env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string ReadWord(string type, string var, string addr, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadWordBasic(type, var, addr, "cast(ushort)(" ~ addr ~ " + 1)",
|
|
|
|
env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string ReadWord(string var, string addr, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadWord("", var, addr, env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string ReadWordZP(string type, string var, string addr, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
|
|
|
return ReadWordBasic(type, var, "cast(ubyte)( " ~ addr ~ ")",
|
2012-04-11 13:27:46 +00:00
|
|
|
"cast(ubyte)(" ~ addr ~ " + 1)", env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string ReadWordZP(string var, string addr, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadWordZP("", var, addr, env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string ReadWordOp(string type, string var, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadWordBasic(type, var, _PC ~ "++", _PC ~ "++", env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string ReadWordOp(string var, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return ReadWordOp("", var, env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string PreAccess(Env env)
|
2012-04-08 20:25:35 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool c = env.c;
|
|
|
|
return If!(c)("++cycles;\n", Attr("clock") ~ ".tick();\n");
|
2012-04-08 20:25:35 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Peek(string addr, Env env)
|
2012-04-08 20:25:35 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool s = env.s;
|
|
|
|
return PreAccess(env) ~
|
|
|
|
If!(s)(Attr("memory") ~ ".read(" ~ addr ~");\n");
|
2012-04-08 20:25:35 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Poke(string addr, string val, Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool s = env.s;
|
|
|
|
return PreAccess(env) ~
|
|
|
|
If!(s)(
|
2012-04-09 13:52:42 +00:00
|
|
|
Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n");
|
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Write(string addr, string val, Env env)
|
2012-04-08 20:25:35 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return PreAccess(env) ~
|
2012-04-08 20:25:35 +00:00
|
|
|
Attr("memory") ~ ".write(" ~ addr ~ ", " ~ val ~ ");\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
string IncPC()
|
2012-04-08 04:30:17 +00:00
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return "++" ~ _PC ~ ";\n";
|
2012-04-08 04:30:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-08 20:25:35 +00:00
|
|
|
string IncSP()
|
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return "++" ~ _S ~ ";\n";
|
2012-04-08 20:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string DecSP()
|
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return "--" ~ _S ~ ";\n";
|
2012-04-08 20:25:35 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string PullStatus(Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return Peek(STACK, env) ~
|
2012-04-09 13:52:42 +00:00
|
|
|
IncSP() ~
|
2012-04-11 13:27:46 +00:00
|
|
|
PreAccess(env) ~
|
2012-04-09 13:52:42 +00:00
|
|
|
Attr("statusFromByte") ~ "(" ~
|
2012-04-11 08:52:15 +00:00
|
|
|
ReadRaw(STACK) ~ ");\n";
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string PullInto(string var, Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return IncSP() ~
|
2012-04-11 13:27:46 +00:00
|
|
|
ReadInto(var, STACK, env);
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Push(string val, Env env)
|
2012-04-08 20:25:35 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return Write(STACK, val, env) ~
|
2012-04-08 20:25:35 +00:00
|
|
|
DecSP();
|
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string PushPC(Env env)
|
2012-04-08 20:25:35 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return Push(HiByte(_PC), env) ~
|
|
|
|
Push(LoByte(_PC), env);
|
2012-04-08 20:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string PullPC(Env env)
|
2012-04-09 13:52:42 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return PullInto(_PC, env) ~
|
2012-04-09 13:52:42 +00:00
|
|
|
IncSP() ~
|
2012-04-11 13:27:46 +00:00
|
|
|
LoadHiByte(_PC, STACK, env);
|
2012-04-11 08:52:15 +00:00
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string LoadLoByte(string type, string var, string addr, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return PreAccess(env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
Local(type, var) ~ " = " ~ ReadRaw(addr) ~ ";\n";
|
|
|
|
}
|
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string LoadHiByte(string var, string addr, Env env)
|
2012-04-11 08:52:15 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
return PreAccess(env) ~
|
2012-04-11 08:52:15 +00:00
|
|
|
var ~ " |= (" ~ ReadRaw(addr) ~ " << 8);\n";
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string SetFlag(string flag)
|
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return flag ~ " = true;\n";
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string ClearFlag(string flag)
|
2012-04-08 20:25:35 +00:00
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return flag ~ " = false;\n";
|
2012-04-08 20:25:35 +00:00
|
|
|
}
|
|
|
|
|
2012-04-09 13:52:42 +00:00
|
|
|
string UpdateFlag(string flag, string val)
|
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return flag ~ " = (" ~ val ~ ");\n";
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string SetNZ(string var)
|
|
|
|
{
|
2012-04-11 08:52:15 +00:00
|
|
|
return _N ~ " = " ~ _Z ~ " = (" ~ var ~ ");\n";
|
2012-04-09 13:52:42 +00:00
|
|
|
}
|
2012-04-08 20:25:35 +00:00
|
|
|
|
2012-04-11 13:27:46 +00:00
|
|
|
string Done(Env env)
|
2012-04-08 20:25:35 +00:00
|
|
|
{
|
2012-04-11 13:27:46 +00:00
|
|
|
bool c = env.c;
|
|
|
|
return If!(c)(Attr("clock") ~ ".tick(cycles);\n");
|
2012-04-08 20:25:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-04-09 13:52:42 +00:00
|
|
|
// Custom string formatting.
|
2012-04-08 04:30:17 +00:00
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
2012-04-09 01:28:44 +00:00
|
|
|
|
2012-04-09 13:52:42 +00:00
|
|
|
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..$];
|
|
|
|
}
|