|
|
nono 1.7.0
//
// nono
// Copyright (C) 2022 nono project
// Licensed under nono-license.txt
//
#include "hd64180disasm.h"
#include "debugger_memory.h"
#include "mpu64180.h"
#include "mystring.h"
#define T(inp, exp) { __LINE__, #inp, exp }
#define ILLEGAL "<illegal instruction>"
struct {
int line;
std::string inp;
std::string exp;
} table[] = {
// inst exp
T(00, "NOP"),
T(011234, "LD BC,3412H"),
T(02, "LD (BC),A"),
T(03, "INC BC"),
T(04, "INC B"),
T(05, "DEC B"),
T(0612, "LD B,12H"),
T(07, "RLCA"),
T(08, "EX AF,AF'"),
T(09, "ADD HL,BC"),
T(0a, "LD A,(BC)"),
T(0b, "DEC BC"),
T(0c, "INC C"),
T(0d, "DEC C"),
T(0e12, "LD C,12H"),
T(0f, "RRCA"),
T(1012, "DJNZ 0114H"),
T(111234, "LD DE,3412H"),
T(17, "RLA"),
T(1812, "JR 0114H"),
T(1f, "RRA"),
T(2012, "JR NZ,0114H"),
T(211234, "LD HL,3412H"),
T(221234, "LD (3412H),HL"),
T(27, "DAA"),
T(2812, "JR Z,0114H"),
T(2a1234, "LD HL,(3412H)"),
T(2f, "CPL"),
T(3012, "JR NC,0114H"),
T(311234, "LD SP,3412H"),
T(321234, "LD (3412H),A"),
T(37, "SCF"),
T(3812, "JR C,0114H"),
T(39, "ADD HL,SP"),
T(3a1234, "LD A,(3412H)"),
T(3f, "CCF"),
T(40, "LD B,B"),
T(46, "LD B,(HL)"),
T(48, "LD C,B"),
T(4e, "LD C,(HL)"),
T(70, "LD (HL),B"),
T(76, "HALT"),
T(77, "LD (HL),A"),
T(7e, "LD A,(HL)"),
T(80, "ADD A,B"),
T(89, "ADC A,C"),
T(92, "SUB D"),
T(9b, "SBC A,E"),
T(a4, "AND H"),
T(ad, "XOR L"),
T(b6, "OR (HL)"),
T(bf, "CP A"),
T(c0, "RET NZ"),
T(c1, "POP BC"),
T(c21234, "JP NZ,3412H"),
T(c31234, "JP 3412H"),
T(c41234, "CALL NZ,3412H"),
T(c5, "PUSH BC"),
T(c612, "ADD A,12H"),
T(c7, "RST 00H"),
T(c9, "RET"),
T(cd1234, "CALL 3412H"),
T(ce12, "ADC A,12H"),
T(d312, "OUT (12H),A"),
T(d612, "SUB 12H"),
T(d9, "EXX"),
T(db12, "IN A,(12H)"),
T(de12, "SBC A,12H"),
T(e3, "EX (SP),HL"),
T(e612, "AND 12H"),
T(e9, "JP (HL)"),
T(eb, "EX DE,HL"),
T(ee12, "XOR 12H"),
T(f3, "DI"),
T(f612, "OR 12H"),
T(f9, "LD SP,HL"),
T(fb, "EI"),
T(fe12, "CP 12H"),
// ww
T(13, "INC DE"),
T(23, "INC HL"),
T(33, "INC SP"),
// fff
T(c8, "RET Z"),
T(d0, "RET NC"),
T(d8, "RET C"),
T(e0, "RET PO"),
T(e8, "RET PE"),
T(f0, "RET P"),
T(f8, "RET M"),
// zzz
T(d1, "POP DE"),
T(e1, "POP HL"),
T(f1, "POP AF"),
// vvv
T(cf, "RST 08H"),
T(d7, "RST 10H"),
T(df, "RST 18H"),
T(e7, "RST 20H"),
T(ef, "RST 28H"),
T(f7, "RST 30H"),
T(ff, "RST 38H"),
//
// CB
//
T(cb00, "RLC B"),
T(cb08, "RRC B"),
T(cb10, "RL B"),
T(cb18, "RR B"),
T(cb20, "SLA B"),
T(cb28, "SRA B"),
T(cb38, "SRL B"),
T(cb7f, "BIT 7,A"),
T(cbbf, "RES 7,A"),
T(cbff, "SET 7,A"),
// bbb
T(cb41, "BIT 0,C"),
T(cb49, "BIT 1,C"),
T(cb51, "BIT 2,C"),
T(cb59, "BIT 3,C"),
T(cb61, "BIT 4,C"),
T(cb69, "BIT 5,C"),
T(cb71, "BIT 6,C"),
T(cb79, "BIT 7,C"),
//
// ED
//
T(ed0012, "IN0 B,(12H)"),
T(ed0112, "OUT0 (12H),B"),
T(ed04, "TST B"),
T(ed3012, "IN0 F,(12H)"), // 公式表記は不明だが定義動作
T(ed31, ILLEGAL), // OUT0 (HL),n はない
T(ed34, "TST (HL)"),
T(ed40, "IN B,(C)"),
T(ed41, "OUT (C),B"),
T(ed42, "SBC HL,BC"),
T(ed431234, "LD (3412H),BC"),
T(ed44, "NEG"),
T(ed45, "RETN"),
T(ed46, "IM 0"),
T(ed47, "LD I,A"),
T(ed4a, "ADC HL,BC"),
T(ed4b1234, "LD BC,(3412H)"),
T(ed4c, "MLT BC"),
T(ed4d, "RETI"),
T(ed4f, "LD R,A"),
T(ed56, "IM 1"),
T(ed57, "LD A,I"),
T(ed5e, "IM 2"),
T(ed5f, "LD A,R"),
T(ed6412, "TST 12H"),
T(ed67, "RRD"),
T(ed6f, "RLD"),
T(ed70, "IN F,(C)"), // 公式表記は不明だが定義動作
T(ed71, ILLEGAL), // OUT (C),(HL) はない
T(ed72, "SBC HL,SP"),
T(ed731234, "LD (3412H),SP"),
T(ed7412, "TSTIO 12H"),
T(ed76, "SLP"),
T(ed7c, "MLT SP"),
T(ed83, "OTIM"),
T(ed8b, "OTDM"),
T(ed93, "OTIMR"),
T(ed9b, "OTDMR"),
T(eda0, "LDI"),
T(eda1, "CPI"),
T(eda2, "INI"),
T(eda3, "OUTI"),
T(eda8, "LDD"),
T(eda9, "CPD"),
T(edaa, "IND"),
T(edab, "OUTD"),
T(edb0, "LDIR"),
T(edb1, "CPIR"),
T(edb2, "INIR"),
T(edb3, "OTIR"),
T(edb8, "LDDR"),
T(edb9, "CPDR"),
T(edba, "INDR"),
T(edbb, "OTDR"),
T(edc9, "MULUB A,C"), // R800
T(edc3, "MULUB HL,BC"), // R800
T(edf3, "MULUB HL,SP"), // R800
T(edff, "SYSCALL"),
//
// DD/FD
//
// XXX fd00 は nop になるかとか
// XXX ddfd23 とかどうなるかとか
T(fd09, "ADD IY,BC"),
T(fd29, "ADD IY,IY"),
T(fd0c, "INC C"), // Z80
T(fd2c, "INC IYL"), // Z80
T(fd0d, "DEC C"), // Z80
T(fd2d, "DEC IYL"), // Z80
T(fd211234, "LD IY,3412H"),
T(fd221234, "LD (3412H),IY"),
T(fd23, "INC IY"),
T(fd3412, "INC (IY+12H)"),
T(fd3512, "DEC (IY+12H)"),
T(fd361234, "LD (IY+12H),34H"),
T(fd4612, "LD B,(IY+12H)"),
T(fd7112, "LD (IY+12H),C"),
T(fd4a, "LD C,D"), // Z80
T(fd4d, "LD C,IYL"), // Z80
T(fd69, "LD IYL,C"), // Z80
T(fd8612, "ADD A,(IY+12H)"),
T(fd8e12, "ADC A,(IY+12H)"),
T(fd9612, "SUB (IY+12H)"),
T(fd9e12, "SBC A,(IY+12H)"),
T(fda612, "AND (IY+12H)"),
T(fdae12, "XOR (IY+12H)"),
T(fdb612, "OR (IY+12H)"),
T(fdbe12, "CP (IY+12H)"),
T(fd81, "ADD A,C"), // Z80
T(fd85, "ADD A,IYL"), // Z80
T(fd8d, "ADC A,IYL"), // Z80
T(fd95, "SUB IYL"), // Z80
T(fd9d, "SBC A,IYL"), // Z80
T(fda5, "AND IYL"), // Z80
T(fdad, "XOR IYL"), // Z80
T(fdb5, "OR IYL"), // Z80
T(fdbd, "CP IYL"), // Z80
T(fde1, "POP IY"),
T(fde3, "EX (SP),IY"), // EX (SP),HL は IX/IY 可
T(fde5, "PUSH IY"),
T(fde9, "JP (IY)"), // JP (HL) は (IX)/(IY) になる
T(fdeb, ILLEGAL), // EX DE,HL は IX/IY 不可
T(fdf9, "LD SP,IY"),
T(ddcb1206, "RLC (IX+12H)"),
T(ddcb12fe, "SET 7,(IX+12H)"),
// XXX ED 以下は DD/FD で HL が変化する?しない?
};
static uint8 ram[1024];
static int failed;
#include "test_debugger_memory.cpp"
// リンカを通すためのダミー
DisasmLine::~DisasmLine() { }
DebuggerMD::~DebuggerMD() { }
uint32 DebuggerMD::GetNextPC() { return 0; }
void DebuggerMD::PrintExceptionFrame(FILE *, busaddr) { }
int
main(int ac, char *av[])
{
busaddr saddr;
// DebuggerMD (の継承クラス)を用意するのは芋づる式に大変なので、
// 中でアクセスする変数だけ強引に用意する。
DebuggerMD *md = (DebuggerMD *)calloc(1, sizeof(DebuggerMD));
md->inst_bytes = 1;
for (int i = 0; i < countof(table); i++) {
int line = table[i].line;
std::string inp = table[i].inp;
std::string exp = table[i].exp;
// エラー表示用
std::string inst_str = string_format("%d: %s", line, inp.c_str());
// 入力ダンプ文字列を 16進数列にする
std::vector<uint8> bin;
for (int j = 0; j < inp.length(); j += 2) {
std::string hex = inp.substr(j, 2);
char *end;
errno = 0;
uint32 r = strtoul(hex.c_str(), &end, 16);
if (errno != 0) {
err(1, "strtoul");
}
bin.push_back(r);
}
// テーブルの期待値は入力手間を省くためタブ区切りだが実際は空白。
// ここでタブを空白に変換する。
std::string exp2;
for (int j = 0; j < exp.length(); j++) {
if (exp[j] == '\t') {
if (j < 8) {
exp2 += std::string(8 - j, ' ');
} else {
exp2 += ' ';
}
} else {
exp2 += exp[j];
}
}
exp = exp2;
// 全体を初期化
memset(ram, 0x99, sizeof(ram));
// 100番地から命令列を書き込む
for (int j = 0; j < bin.size(); j++) {
ram[HB(0x100 + j)] = bin[j];
}
// 検査
saddr = busaddr(0x100);
hd64180disasm dis;
DebuggerMemoryStream mem(NULL, saddr);
dis.Exec(&mem);
// 照合
if (dis.text != exp) {
printf("%s expects \"%s\" but \"%s\"\n", inst_str.c_str(),
exp.c_str(), dis.text.c_str());
failed++;
continue;
}
// PC を照合
uint32 exppc = 0x100 + bin.size();
if (mem.paddr != exppc) {
printf("%s expects PC +$%x but +$%x\n", inst_str.c_str(),
exppc - 0x100, mem.paddr - 0x100);
failed++;
continue;
}
}
int total = countof(table);
printf("%d tests, %d success", total, total - failed);
if (failed > 0) {
printf(", %d failed", failed);
}
printf("\n");
return 0;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.