From ed8dc37bb49992a4c09a6927afafdb9e64a38093 Mon Sep 17 00:00:00 2001 From: edmccard Date: Thu, 12 Apr 2012 18:42:55 -0400 Subject: [PATCH] Improve test runner. --- README.md | 9 +++ test/base.d | 71 +++++++++++++++++++++- test/runtests.d | 142 +++++++++++++++++++++++++++++++++++++++++++ test/test_bus.d | 39 +++--------- test/test_cpu_all.sh | 4 -- test/test_decimal.d | 23 ++----- test/test_func.d | 15 +++-- 7 files changed, 245 insertions(+), 58 deletions(-) create mode 100644 test/runtests.d delete mode 100755 test/test_cpu_all.sh diff --git a/README.md b/README.md index 934ce3a..3eba05b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,15 @@ Build by running `make` in the `src` directory; if the dependencies aren't insta make GTKD=/path/to/gtkd DERELICT=/path/to/Derelict2 ``` +### Testing + +There are tests for the 6502/65C02 emulation: + +``` +cd test +rdmd runtests.d --help +``` + ### Use For now, see README.orig diff --git a/test/base.d b/test/base.d index 5b8b650..34e6576 100644 --- a/test/base.d +++ b/test/base.d @@ -1,10 +1,11 @@ module test.base; -import std.algorithm, std.array, std.conv, std.exception, std.stdio, - std.string; +import std.algorithm, std.array, std.conv, std.exception, std.getopt, + std.stdio, std.string; import test.cpu, test.opcodes; +import cpu.data_d6502; /* @@ -3334,3 +3335,69 @@ void test_opcode_timing(T)(ubyte opcode, busreport report) auto run = connect(setup, run_timing_test!T(expected, report)); run.run(opcode); } + + +version(Strict) + enum testStrict = true; +else + enum testStrict = false; +version(Cumulative) + enum testCumulative = true; +else + enum testCumulative = false; + + +struct CheckOptions +{ + enum Addr + { + IMP, IMM, ZP, ZPX, ZPY, IZX, IZY, ABS, ABX, ABY, IND, REL, + ZPI, ABI, NP1, NP8, KIL + } + + string[] opcodes; + ubyte[] codes6502; + ubyte[] codes65C02; + Addr[] addr; + + this(string[] args) + { + getopt(args, "op", &opcodes, "addr", &addr); + foreach (op; opcodes) + { + if (op.startsWith("0x") || op.startsWith("0X")) + op = op[2..$]; + if (isNumeric(op)) + { + int code = to!int(op, 16); + if (code >= 0x00 && code <= 0xFF) + { + codes6502 ~= [cast(ubyte)code]; + codes65C02 ~= [cast(ubyte)code]; + } + } + else + { + foreach (code, name; OP_NAMES_6502) + if (name == op) codes6502 ~= [cast(ubyte)code]; + foreach (code, name; OP_NAMES_65C02) + if (name == op) codes65C02 ~= [cast(ubyte)code]; + } + } + foreach (a; addr) + { + foreach (code, mode; ADDR_MODES_6502) + if (a == mode) codes6502 ~= [cast(ubyte)code]; + foreach (code, mode; ADDR_MODES_65C02) + if (a == mode) codes65C02 ~= [cast(ubyte)code]; + } + if (opcodes.empty && addr.empty) + { + codes6502 = codes65C02 = new ubyte[256]; + foreach (code; 0..256) + { + codes6502[code] = cast(ubyte)code; + } + } + } +} diff --git a/test/runtests.d b/test/runtests.d new file mode 100644 index 0000000..7dbb6aa --- /dev/null +++ b/test/runtests.d @@ -0,0 +1,142 @@ +import std.array, std.exception, std.getopt, std.process, std.stdio, + std.traits; + + +enum OpDefs +{ + None, + Delegates = 1, + Functions = 2, + Switch = 4, + NestedSwitch = 8, + All = 15 +} + +enum Tests +{ + None, + Func = 1, + Bus = 2, + Dec = 4, + All = 7 +} + +string[OpDefs] defStrings; +string[Tests] fNames; + +static this() +{ + fNames = [ + Tests.Func:" test_func.d ", + Tests.Bus:" test_bus.d ", + Tests.Dec:" test_decimal.d " + ]; +} + +version(DigitalMars) +{ + static this() + { + defStrings = [ + OpDefs.Delegates:" -version=OpDelegates", + OpDefs.Functions:" -version=OpFunctions", + OpDefs.Switch:" -version=OpSwitch", + OpDefs.NestedSwitch:" -version=OpNestedSwitch" + ]; + } + string[] stStrings = [" ", " -version=Strict"]; + string[] cmStrings = [" ", " -version=Cumulative"]; +} +else version(GNU) +{ + static assert(false, "TODO: add support for GDC."); +} +else version(LDC) +{ + static assert(false, "TODO: add support for LDC."); +} +else + static assert(false, "Unknown compiler."); + + +OpDefs opdefs; +bool strict, cumulative; +Tests tests; +bool help; + +OpDefs[] deflist; +Tests[] testlist; + +void main(string[] args) +{ + if (args.length == 1) + writeln("(running default tests; use --help for options)"); + + getopt(args, + std.getopt.config.passThrough, + "def", &deflist, + "test", &testlist, + "help", &help); + + if (help) + { + writeln( +`Options: + --test=type Func, Bus, Dec, or All + --def=style Delegates, Functions, Switch, or NestedSwitch + --op=num test opcode 'num' (num is hex) + --op=name test all opcodes named 'name' + --addr=mode test all opcodes with addressing mode 'mode' + +(All options con be specified multiple times. +--op and --addr have no effect on decimal mode tests.)` + ); + return; + } + + foreach(def; deflist) opdefs |= def; + foreach(test; testlist) tests |= test; + + try + { + runTests(args); + } + catch (ErrnoException e) {} +} + +void runTests(string[] args) +{ + // If no opdef specified, use Delegates. + if (opdefs == OpDefs.None) opdefs = OpDefs.Delegates; + + int defcount; + foreach (def; EnumMembers!OpDefs) + if ((opdefs & def) && def != OpDefs.All) defcount++; + + // If no tests specified, run all (but exclude Dec by default if + // running with more than one opdef). + if (tests == Tests.None) + tests = Tests.Func | Tests.Bus; + if (!defcount) tests |= Tests.Dec; + + foreach (def; EnumMembers!OpDefs) + if ((opdefs & def) && def != OpDefs.All) + foreach (test; EnumMembers!Tests) + if ((tests & test) && test != Tests.All) + runTest(def, test, args[1..$]); +} + +void runTest(OpDefs def, Tests test, string[] args) +{ + writeln("Using ", defStrings[def]); + foreach (s; [false, true]) + { + foreach (c; [false, true]) + { + writeln("With strict=", s, " cumulative=", c); + string cmdline = defStrings[def] ~ stStrings[s] ~ cmStrings[c] ~ + fNames[test] ~ join(args, " "); + system("rdmd --force -I.. -I../src " ~ cmdline); + } + } +} diff --git a/test/test_bus.d b/test/test_bus.d index 909acb9..f49aedc 100644 --- a/test/test_bus.d +++ b/test/test_bus.d @@ -1,42 +1,23 @@ module test.test_bus; +import std.stdio; + import test.base, test.cpu; -void main() +void main(string[] args) { + auto opts = CheckOptions(args); auto report = report_timing_debug(); - alias CPU!("65C02", false, false) T1; - for (int op = 0x00; op < 0x100; op++) + alias CPU!("6502", testStrict, testCumulative) T1; + writeln("Testing bus/timing, 6502"); + foreach (op; opts.codes6502) test_opcode_timing!T1(cast(ubyte)op, report); - alias CPU!("65C02", true, false) T2; - for (int op = 0x00; op < 0x100; op++) + alias CPU!("65C02", testStrict, testCumulative) T2; + writeln("Testing bus/timing, 65C02"); + foreach (op; opts.codes65C02) test_opcode_timing!T2(cast(ubyte)op, report); - - alias CPU!("6502", false, false) T3; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T3(cast(ubyte)op, report); - - alias CPU!("6502", true, false) T4; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T4(cast(ubyte)op, report); - - alias CPU!("65C02", false, true) T5; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T5(cast(ubyte)op, report); - - alias CPU!("65C02", true, true) T6; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T6(cast(ubyte)op, report); - - alias CPU!("6502", false, true) T7; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T7(cast(ubyte)op, report); - - alias CPU!("6502", true, true) T8; - for (int op = 0x00; op < 0x100; op++) - test_opcode_timing!T8(cast(ubyte)op, report); } diff --git a/test/test_cpu_all.sh b/test/test_cpu_all.sh deleted file mode 100755 index b3a11df..0000000 --- a/test/test_cpu_all.sh +++ /dev/null @@ -1,4 +0,0 @@ -rdmd @testopts test_func.d -rdmd @testopts test_bus.d -rdmd @testopts test_decimal.d - diff --git a/test/test_decimal.d b/test/test_decimal.d index 731c187..322f8f3 100644 --- a/test/test_decimal.d +++ b/test/test_decimal.d @@ -228,6 +228,7 @@ if (isCpu!T) version(Benchmark) { + static assert(!testStrict && !testCumulative); import std.datetime, std.stdio; void f0() { @@ -246,24 +247,10 @@ else { void main() { - writeln("Testing decimal mode, NMOS(Strict.no, Cumulative.no)"); - testDecimalMode!(CPU!("6502", false, false))(); - writeln("Testing decimal mode, CMOS(Strict.no, Cumulative.no)"); - testDecimalMode!(CPU!("65C02", false, false))(); + writeln("Testing decimal mode, 6502"); + testDecimalMode!(CPU!("6502", testStrict, testCumulative))(); - writeln("Testing decimal mode, NMOS(Strict.no, Cumulative.yes)"); - testDecimalMode!(CPU!("6502", false, true))(); - writeln("Testing decimal mode, CMOS(Strict.no, Cumulative.yes)"); - testDecimalMode!(CPU!("65C02", false, true))(); - - writeln("Testing decimal mode, NMOS(Strict.yes, Cumulative.no)"); - testDecimalMode!(CPU!("6502", true, false))(); - writeln("Testing decimal mode, CMOS(Strict.yes, Cumulative.no)"); - testDecimalMode!(CPU!("65C02", true, false))(); - - writeln("Testing decimal mode, NMOS(Strict.yes, Cumulative.yes)"); - testDecimalMode!(CPU!("6502", true, true))(); - writeln("Testing decimal mode, CMOS(Strict.yes, Cumulative.yes)"); - testDecimalMode!(CPU!("65C02", true, true))(); + writeln("Testing decimal mode, 65C02"); + testDecimalMode!(CPU!("65C02", testStrict, testCumulative))(); } } diff --git a/test/test_func.d b/test/test_func.d index 8bb8fb6..1a39316 100644 --- a/test/test_func.d +++ b/test/test_func.d @@ -1,18 +1,23 @@ module test.test_func; +import std.stdio; + import test.base, test.cpu; -void main() +void main(string[] args) { + auto opts = CheckOptions(args); auto report = report_debug(); - alias CPU!("65C02", false, false) T1; - foreach (opcode; 0..255) + alias CPU!("6502", testStrict, testCumulative) T1; + writeln("Testing functionality, 6502"); + foreach (opcode; opts.codes6502) test_one_opcode!T1(cast(ubyte)opcode, report); - alias CPU!("6502", false, false) T2; - foreach (opcode; 0..255) + alias CPU!("65C02", testStrict, testCumulative) T2; + writeln("Testing functionality, 65C02"); + foreach (opcode; opts.codes65C02) test_one_opcode!T2(cast(ubyte)opcode, report); }