Strict and cumulative modes are now set by version, instead of template parameters.

This commit is contained in:
edmccard 2012-04-13 07:03:22 -04:00
parent 76cfb27a7b
commit d12f793d9a
7 changed files with 376 additions and 414 deletions

File diff suppressed because it is too large Load Diff

View File

@ -29,17 +29,6 @@ import std.array, std.format;
import cpu.ctfe_d6502;
enum Strict : bool
{
no, yes
}
enum Cumulative : bool
{
no, yes
}
template is6502(T)
{
enum is6502 = __traits(getMember, T, "_chip") == "6502";
@ -51,13 +40,11 @@ template is65C02(T)
}
final class Cpu(string chip, bool strict, bool cumulative)
final class Cpu(string chip)
{
static assert(chip == "6502" || chip == "65C02" || chip == "65c02");
enum _isCpu = true;
enum _chip = (chip == "6502" ? "6502" : "65C02");
enum _isStrict = strict;
enum _isCumulative = cumulative;
struct _Mem
{
@ -71,7 +58,7 @@ final class Cpu(string chip, bool strict, bool cumulative)
struct _Clock
{
static if (cumulative)
version(Cumulative)
/*
* Updates the number of cycles executed. Called just
* prior to the final read/write action of each opcode.
@ -97,7 +84,7 @@ final class Cpu(string chip, bool strict, bool cumulative)
version(OpFunctions) {}
else
{
static if (cumulative) { int cycles; }
version(Cumulative) { int cycles; }
ushort address, base;
ubyte data;
}
@ -138,23 +125,26 @@ final class Cpu(string chip, bool strict, bool cumulative)
ubyte opcode;
static if (!opArray)
{
static if (cumulative) { int cycles; }
version(Cumulative) { int cycles; }
ushort address, base;
ubyte data;
}
do {
static if (cumulative && !opArray)
cycles = 1;
// XXX figure out final cycle stuff
static if (!cumulative)
version(Cumulative)
{
static if (!opArray) cycles = 1;
}
else
{
clock.tick();
}
// XXX check signals, NMI/IRQ delays, etc.
opcode = memory.read(PC++);
mixin(OpExecute(_chip, strict, cumulative));
mixin(OpExecute(_chip));
} while (keepRunning);
}
version(OpDelegates) mixin (OpBodies(_chip, strict, cumulative));
version(OpDelegates) mixin (OpBodies(_chip));
}
@ -163,8 +153,8 @@ enum ushort IRQ_VECTOR = 0xFFFE;
private:
version(OpFunctions) mixin(OpBodies("6502", vStrict, vCumulative));
version(OpFunctions) mixin(OpBodies("65C02", vStrict, vCumulative));
version(OpFunctions) mixin(OpBodies("6502"));
version(OpFunctions) mixin(OpBodies("65C02"));
//alias Cpu!("6502", false, false) T1;

View File

@ -8,6 +8,16 @@ 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;
/*
* Emulates zero page, stack, and 3 additional pages of "main memory"
* starting at a user-defined address. Accesses outside the defined
@ -2672,7 +2682,7 @@ if (isCpu!T)
cycles = 2;
return [Bus(Action.READ, pc)] ~
If!(isStrict!T)(
If!(strict)(
[Bus(Action.READ, pc+1)]);
}
@ -2689,7 +2699,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)];
}
@ -2708,7 +2718,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)];
@ -2729,7 +2739,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)]));
}
@ -2751,7 +2761,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)])));
@ -2806,7 +2816,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)(
@ -2862,7 +2872,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)(
@ -2963,14 +2973,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
{
@ -2999,13 +3009,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)(
@ -3029,12 +3039,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)]);
}
@ -3054,7 +3064,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),
@ -3077,7 +3087,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),
@ -3101,7 +3111,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),
@ -3140,7 +3150,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)];
@ -3170,7 +3180,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)];
@ -3196,7 +3206,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),
@ -3337,16 +3347,6 @@ void test_opcode_timing(T)(ubyte opcode, busreport report)
}
version(Strict)
enum testStrict = true;
else
enum testStrict = false;
version(Cumulative)
enum testCumulative = true;
else
enum testCumulative = false;
struct CheckOptions
{
enum Addr

View File

@ -11,6 +11,16 @@ import std.conv, std.exception, std.random, std.string, std.traits;
public import cpu.d6502 : Cpu, is6502, is65C02;
version(Strict)
enum strict = true;
else
enum strict = false;
version(Cumulative)
enum cumulative = true;
else
enum cumulative = false;
// True if T is the type of a cpu.
template isCpu(T)
{
@ -29,27 +39,13 @@ template isCMOS(T)
enum isCMOS = is65C02!T;
}
// True if the cpu type T accesses memory on every cycle.
template isStrict(T)
{
enum isStrict = isCpu!T && __traits(getMember, T, "_isStrict");
}
// True if the cpu type T aggregates ticks.
template isCumulative(T)
{
enum isCumulative = isCpu!T && __traits(getMember, T, "_isCumulative");
}
/*
* 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)
{
alias Cpu!(arch, strict, cumulative) CPU;
alias Cpu!(arch) CPU;
}
@ -70,7 +66,7 @@ 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() {}
@ -96,7 +92,7 @@ if (isCpu!T)
auto cycles = new int;
auto wrappedTick = cpu.clock.tick;
static if (isCumulative!T)
static if (cumulative)
{
void tick(int cyc)
{

View File

@ -11,12 +11,12 @@ void main(string[] args)
auto opts = CheckOptions(args);
auto report = report_timing_debug();
alias CPU!("6502", testStrict, testCumulative) T1;
alias CPU!("6502") T1;
writeln("Testing bus/timing, 6502");
foreach (op; opts.codes6502)
test_opcode_timing!T1(cast(ubyte)op, report);
alias CPU!("65C02", testStrict, testCumulative) T2;
alias CPU!("65C02") T2;
writeln("Testing bus/timing, 65C02");
foreach (op; opts.codes65C02)
test_opcode_timing!T2(cast(ubyte)op, report);

View File

@ -228,11 +228,10 @@ if (isCpu!T)
version(Benchmark)
{
static assert(!testStrict && !testCumulative);
import std.datetime, std.stdio;
void f0()
{
testDecimalMode!(CPU!("65C02", false, false))();
testDecimalMode!(CPU!("65C02"))();
}
void main()
@ -248,9 +247,9 @@ else
void main()
{
writeln("Testing decimal mode, 6502");
testDecimalMode!(CPU!("6502", testStrict, testCumulative))();
testDecimalMode!(CPU!("6502"))();
writeln("Testing decimal mode, 65C02");
testDecimalMode!(CPU!("65C02", testStrict, testCumulative))();
testDecimalMode!(CPU!("65C02"))();
}
}

View File

@ -11,12 +11,12 @@ void main(string[] args)
auto opts = CheckOptions(args);
auto report = report_debug();
alias CPU!("6502", testStrict, testCumulative) T1;
alias CPU!("6502") T1;
writeln("Testing functionality, 6502");
foreach (opcode; opts.codes6502)
test_one_opcode!T1(cast(ubyte)opcode, report);
alias CPU!("65C02", testStrict, testCumulative) T2;
alias CPU!("65C02") T2;
writeln("Testing functionality, 65C02");
foreach (opcode; opts.codes65C02)
test_one_opcode!T2(cast(ubyte)opcode, report);