From 24652de392b0dba27097b4a69c4d4d966ec29c38 Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Wed, 12 Feb 2020 22:58:24 +0100 Subject: [PATCH] Integrate disassembler tests. --- CMakeLists.txt | 1 + cpu/ppc/ppcdisasm.h | 2 + cpu/ppc/test/ppcdisasmtest.csv | 223 +++++++++++++++++++++++++++++++++ cpu/ppc/test/ppctests.cpp | 9 +- cpu/ppc/test/testdisasm.cpp | 106 ++++++++++++++++ 5 files changed, 338 insertions(+), 3 deletions(-) create mode 100644 cpu/ppc/test/ppcdisasmtest.csv create mode 100644 cpu/ppc/test/testdisasm.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 746204a..bf3ec01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ add_custom_command( TARGET testppc POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy "${PROJECT_SOURCE_DIR}/cpu/ppc/test/ppcinttests.csv" + "${PROJECT_SOURCE_DIR}/cpu/ppc/test/ppcdisasmtest.csv" $) install (TARGETS dingusppc DESTINATION ${EXECUTABLE_OUTPUT_PATH}) diff --git a/cpu/ppc/ppcdisasm.h b/cpu/ppc/ppcdisasm.h index 56d12fc..9da10b9 100644 --- a/cpu/ppc/ppcdisasm.h +++ b/cpu/ppc/ppcdisasm.h @@ -13,6 +13,8 @@ typedef struct PPCDisasmContext { std::string disassemble_single(PPCDisasmContext *ctx); +int test_ppc_disasm(void); + /** sign-extend an integer. */ #define SIGNEXT(x, sb) ((x) | (((x) & (1 << (sb))) ? ~((1 << (sb))-1) : 0)) diff --git a/cpu/ppc/test/ppcdisasmtest.csv b/cpu/ppc/test/ppcdisasmtest.csv new file mode 100644 index 0000000..2db4746 --- /dev/null +++ b/cpu/ppc/test/ppcdisasmtest.csv @@ -0,0 +1,223 @@ +# Test data for PowerPC disassembler supplied as comma-separated values +# Data format: +# instruction address (hex), instruction code (hex), expected disassembly: opcode, [operands...] +# (lines starting with "#" will be treated as comments and ignored) + +# unconditional branches +0xFFF03008,0x48000355,bl,0xFFF0335C +0xFFF03000,0x4280035C,b,0xFFF0335C + +# conditional branches with simplified mnemonics, primary opcode 0x10 +0xFFF0011C,0x409E2EE4,bne,cr7,0xFFF03000 +0xFFF00100,0x40A60098,bne+,cr1,0xFFF00198 +0xFFF00100,0x41820018,beq,0xFFF00118 +0xFFF03004,0x41200054,bdnzt+,lt,0xFFF03058 +0xFFF03004,0x40000054,bdnzf,lt,0xFFF03058 +0xFFF03000,0x4106FFF4,bdnzt,4*cr1+eq,0xFFF02FF4 + +# indexed load/store instructions, primary opcode 0x1F +0xFFF00100,0x7D49F02E,lwzx,r10,r9,r30 +0xFFF00100,0x7FAB806E,lwzux,r29,r11,r16 +0xFFF00100,0x7C0820AE,lbzx,r0,r8,r4 +0xFFF00100,0x7F47E8EE,lbzux,r26,r7,r29 +0xFFF00100,0x7C01612E,stwx,r0,r1,r12 +0xFFF00100,0x7FC3996E,stwux,r30,r3,r19 +0xFFF00100,0x7D2C09AE,stbx,r9,r12,r1 +0xFFF00100,0x7C8531EE,stbux,r4,r5,r6 +0xFFF00100,0x7C94DA2E,lhzx,r4,r20,r27 +0xFFF00100,0x7C833A6E,lhzux,r4,r3,r7 +0xFFF00100,0x7D8F62AE,lhax,r12,r15,r12 +0xFFF00100,0x7C98DAEE,lhaux,r4,r24,r27 +0xFFF00100,0x7C0C0B2E,sthx,r0,r12,r1 +0xFFF00100,0x7C032B6E,sthux,r0,r3,r5 +0xFFF00100,0x7C43242E,lfsx,fp2,r3,r4 +0xFFF00100,0x7C43246E,lfsux,fp2,r3,r4 +0xFFF00100,0x7D491CAE,lfdx,fp10,r9,r3 +0xFFF00100,0x7C4324EE,lfdux,fp2,r3,r4 +0xFFF00100,0x7C43252E,stfsx,fp2,r3,r4 +0xFFF00100,0x7C43256E,stfsux,fp2,r3,r4 +0xFFF00100,0x7C4325AE,stfdx,fp2,r3,r4 +0xFFF00100,0x7C4325EE,stfdux,fp2,r3,r4 + +# arithmetic instructions with immediate operand +0xFFF00100,0x1F00A81A,mulli,r24,r0,-0x57E6 +0xFFF00100,0x1D8A4CCC,mulli,r12,r10,0x4CCC +0xFFF00100,0x207CFEE0,subfic,r3,r28,-0x120 +0xFFF00100,0x20894E75,subfic,r4,r9,0x4E75 +0xFFF00100,0x38BE0000,addi,r5,r30,0x0 +0xFFF00100,0x3A2EFFF0,addi,r17,r14,-0x10 +0xFFF00100,0x307F005E,addic,r3,r31,0x5E +0xFFF00100,0x30C4FFFF,addic,r6,r4,-0x1 +0xFFF00100,0x34803012,addic.,r4,r0,0x3012 +0xFFF00100,0x3E1F4A47,addis,r16,r31,0x4A47 +0xFFF00100,0x3F3CFFF6,addis,r25,r28,-0xA + +# subtracts and friends, primary opcode 0x1F +0xFFF00100,0x7C03E810,subfc,r0,r3,r29 +0xFFF00100,0x7CE03011,subfc.,r7,r0,r6 +0xFFF00100,0x7CC47C10,subfco,r6,r4,r15 +0xFFF00100,0x7CC46C11,subfco.,r6,r4,r13 +0xFFF00100,0x7D800850,subf,r12,r0,r1 +0xFFF00100,0x7C966851,subf.,r4,r22,r13 +0xFFF00100,0x7C7B8C50,subfo,r3,r27,r17 +0xFFF00100,0x7D283C51,subfo.,r9,r8,r7 +0xFFF00100,0x7CE400D0,neg,r7,r4 +0xFFF00100,0x7CC900D1,neg.,r6,r9 +0xFFF00100,0x7C6B04D0,nego,r3,r11 +0xFFF00100,0x7FC004D1,nego.,r30,r0 +0xFFF00100,0x7D266110,subfe,r9,r6,r12 +0xFFF00100,0x7C693111,subfe.,r3,r9,r6 +0xFFF00100,0x7C642D10,subfeo,r3,r4,r5 +0xFFF00100,0x7C843511,subfeo.,r4,r4,r6 +0xFFF00100,0x7D6B0190,subfze,r11,r11 +0xFFF00100,0x7C430191,subfze.,r2,r3 +0xFFF00100,0x7C640590,subfzeo,r3,r4 +0xFFF00100,0x7C850591,subfzeo.,r4,r5 +0xFFF00100,0x7C4301D0,subfme,r2,r3 +0xFFF00100,0x7C4301D1,subfme.,r2,r3 +0xFFF00100,0x7D2A1A10,doz,r9,r10,r3 +0xFFF00100,0x7C642A11,doz.,r3,r4,r5 +0xFFF00100,0x7C851E10,dozo,r4,r5,r3 +0xFFF00100,0x7CA41E11,dozo.,r5,r4,r3 +0xFFF00100,0x7C1E02D0,abs,r0,r30 +0xFFF00100,0x7C3E02D1,abs.,r1,r30 +0xFFF00100,0x7FC306D0,abso,r30,r3 +0xFFF00100,0x7FC706D1,abso.,r30,r7 +0xFFF00100,0x7CE703D0,nabs,r7,r7 +0xFFF00100,0x7D0703D1,nabs.,r8,r7 +0xFFF00100,0x7D0907D0,nabso,r8,r9 +0xFFF00100,0x7D0A07D1,nabso.,r8,r10 + +# additions, primary opcode 0x1F +0xFFF00100,0x7C830014,addc,r4,r3,r0 +0xFFF00100,0x7FB8F015,addc.,r29,r24,r30 +0xFFF00100,0x7CDB0414,addco,r6,r27,r0 +0xFFF00100,0x7C880415,addco.,r4,r8,r0 +0xFFF00100,0x7D6BC914,adde,r11,r11,r25 +0xFFF00100,0x7D296115,adde.,r9,r9,r12 +0xFFF00100,0x7C842514,addeo,r4,r4,r4 +0xFFF00100,0x7C843515,addeo.,r4,r4,r6 +0xFFF00100,0x7CE80194,addze,r7,r8 +0xFFF00100,0x7C800195,addze.,r4,r0 +# FIXME addzeo +# FIXME addzeo. +# FIXME addme +# FIXME addme. +# FIXME addmeo +# FIXME addmeo. +0xFFF00100,0x7F03EA14,add,r24,r3,r29 +0xFFF00100,0x7ED6E215,add.,r22,r22,r28 +0xFFF00100,0x7D040614,addo,r8,r4,r0 +0xFFF00100,0x7DE40615,addo.,r15,r4,r0 + +# integer multiplications & divisions, primary opcode 0x1F +0xFFF00100,0x7C8C5016,mulhwu,r4,r12,r10 +0xFFF00100,0x7CA72017,mulhwu.,r5,r7,r4 +0xFFF00100,0x7CA72096,mulhw,r5,r7,r4 +0xFFF00100,0x7CA72097,mulhw.,r5,r7,r4 +0xFFF00100,0x7C9000D6,mul,r4,r16,r0 +0xFFF00100,0x7CA428D7,mul.,r5,r4,r5 +# FIXME mulo +# FIXME mulo. +0xFFF00100,0x7D0039D6,mullw,r8,r0,r7 +0xFFF00100,0x7C1DF1D7,mullw.,r0,r29,r30 +0xFFF00100,0x7CE725D6,mullwo,r7,r7,r4 +0xFFF00100,0x7CE725D7,mullwo.,r7,r7,r4 +0xFFF00100,0x7FEB2296,div,r31,r11,r4 +0xFFF00100,0x7C064297,div.,r0,r6,r8 +# FIXME divo +# FIXME divo. +0xFFF00100,0x7CA03AD6,divs,r5,r0,r7 +0xFFF00100,0x7C642AD7,divs.,r3,r4,r5 +# FIXME divso +# FIXME divso. +0xFFF00100,0x7F7C1B96,divwu,r27,r28,r3 +0xFFF00100,0x7C7B1B97,divwu.,r3,r27,r3 +0xFFF00100,0x7CE62796,divwuo,r7,r6,r4 +0xFFF00100,0x7CE62797,divwuo.,r7,r6,r4 +0xFFF00100,0x7C042BD6,divw,r0,r4,r5 +0xFFF00100,0x7C042BD7,divw.,r0,r4,r5 +0xFFF00100,0x7CA627D6,divwo,r5,r6,r4 +0xFFF00100,0x7CA627D7,divwo.,r5,r6,r4 + +# move to condition register, primary opcode 0x1F +0xFFF00100,0x7D818120,mtcrf,0x18,r12 +0xFFF00100,0x7D838120,mtcrf,0x38,r12 +0xFFF00100,0x7D080120,mtcrf,0x80,r8 +0xFFF00100,0x7E007120,mtcrf,0x07,r16 + +# logical instructions, primary opcode 0x1F +0xFFF00100,0x7FC32838,and,r3,r30,r5 +0xFFF00100,0x7C672039,and.,r7,r3,r4 +0xFFF00100,0x7D281878,andc,r8,r9,r3 +0xFFF00100,0x7DCE0079,andc.,r14,r14,r0 +0xFFF00100,0x7C8328F8,nor,r3,r4,r5 +0xFFF00100,0x7D4948F9,nor.,r9,r10,r9 +0xFFF00100,0x7ED53A38,eqv,r21,r22,r7 +0xFFF00100,0x7C622239,eqv.,r2,r3,r4 +0xFFF00100,0x7D645278,xor,r4,r11,r10 +0xFFF00100,0x7C600279,xor.,r0,r3,r0 +0xFFF00100,0x7C841B38,orc,r4,r4,r3 +0xFFF00100,0x7C841B39,orc.,r4,r4,r3 +0xFFF00100,0x7DE42378,or,r4,r15,r4 +0xFFF00100,0x7C632379,or.,r3,r3,r4 +0xFFF00100,0x7C6023B8,nand,r0,r3,r4 +0xFFF00100,0x7F8B63B9,nand.,r11,r28,r12 + +# trap instructions +0xFFF00100,0x7F800008,tw,28,r0,r0 + +# integer load and stores +0xFFF00100,0x80BF0808,lwz,r5,0x808(r31) +0xFFF00100,0x80A2FFB8,lwz,r5,-0x48(r2) +0xFFF00100,0x80002F3C,lwz,r0,0x2F3C +0xFFF00100,0x8506003C,lwzu,r8,0x3C(r6) +0xFFF00100,0x8403FFF8,lwzu,r0,-0x8(r3) +0xFFF00100,0x88FD00FA,lbz,r7,0xFA(r29) +0xFFF00100,0x889EFFF4,lbz,r4,-0xC(r30) +0xFFF00100,0x8D480001,lbzu,r10,0x1(r8) +0xFFF00100,0x8FC3FFFF,lbzu,r30,-0x1(r3) +0xFFF00100,0x90600AFC,stw,r3,0xAFC +0xFFF00100,0x9000F620,stw,r0,-0x9E0 +0xFFF00100,0x9146696E,stw,r10,0x696E(r6) +0xFFF00100,0x9317FFF0,stw,r24,-0x10(r23) +0xFFF00100,0x94050020,stwu,r0,0x20(r5) +0xFFF00100,0x9421FFA0,stwu,r1,-0x60(r1) +0xFFF00100,0x981F00FA,stb,r0,0xFA(r31) +0xFFF00100,0x98829882,stb,r4,-0x677E(r2) +0xFFF00100,0x9EFC000A,stbu,r23,0xA(r28) +0xFFF00100,0x9FAEFFFC,stbu,r29,-0x4(r14) +0xFFF00100,0xA22E6010,lhz,r17,0x6010(r14) +0xFFF00100,0xA0C6FFF8,lhz,r6,-0x8(r6) +0xFFF00100,0xA43C6010,lhzu,r1,0x6010(r28) +0xFFF00100,0xA7BFFFFE,lhzu,r29,-0x2(r31) +0xFFF00100,0xA820265F,lha,r1,0x265F +0xFFF00100,0xA8B5201F,lha,r5,0x201F(r21) +0xFFF00100,0xAAFEFE82,lha,r23,-0x17E(r30) +0xFFF00100,0xAC08003C,lhau,r0,0x3C(r8) +0xFFF00100,0xAC90FFFE,lhau,r4,-0x2(r16) +0xFFF00100,0xB3E40012,sth,r31,0x12(r4) +0xFFF00100,0xB02EFFFB,sth,r1,-0x5(r14) +0xFFF00100,0xB4B81EF4,sthu,r5,0x1EF4(r24) +0xFFF00100,0xB774FFFE,sthu,r27,-0x2(r20) +0xFFF00100,0xBB61006C,lmw,r27,0x6C(r1) +0xFFF00100,0xBB41FFE8,lmw,r26,-0x18(r1) +0xFFF00100,0xBC410008,stmw,r2,0x8(r1) +0xFFF00100,0xBFC1FFF8,stmw,r30,-0x8(r1) + +# various simplified (extended) mnemonics +0xFFF00100,0x60000000,nop +0xFFF00100,0x7C7C1B78,mr,r28,r3 +0xFFF00100,0x7C7C1B78,mr,r28,r3 +0xFFF00100,0x7DAA6B79,mr.,r10,r13 +0xFFF00100,0x38000000,li,r0,0x0 +0xFFF00100,0x3860FFCE,li,r3,-0x32 + +# invalid opcodes/instruction forms +0xFFF00100,0x7D49F02F,dc.l,0x7D49F02F +0xFFF00100,0x7F800009,dc.l,0x7F800009 +0xFFF00100,0x7C6B0CD0,dc.l,0x7C6B0CD0 +0xFFF00100,0x7C642D90,dc.l,0x7C642D90 + +# POWER/PPC601 specific instructions +#0xFFF00100,0x7E3EE43A,maskir,r30,r17,r28 diff --git a/cpu/ppc/test/ppctests.cpp b/cpu/ppc/test/ppctests.cpp index fb8fe28..ce4308d 100644 --- a/cpu/ppc/test/ppctests.cpp +++ b/cpu/ppc/test/ppctests.cpp @@ -5,6 +5,7 @@ #include #include #include "../ppcemu.h" +#include "../ppcdisasm.h" using namespace std; @@ -59,7 +60,7 @@ void xer_update_test() } /** testing vehicle */ -void read_test_data() +static void read_test_data() { string line, token; int i, lineno; @@ -165,7 +166,9 @@ int main() cout << "... completed." << endl; cout << "--> Tested instructions: " << dec << ntested << endl; - cout << "--> Failed: " << dec << nfailed << endl; + cout << "--> Failed: " << dec << nfailed << endl << endl; - return 0; + cout << "Running PPC disassembler tests..." << endl << endl; + + return test_ppc_disasm(); } diff --git a/cpu/ppc/test/testdisasm.cpp b/cpu/ppc/test/testdisasm.cpp new file mode 100644 index 0000000..a2b4896 --- /dev/null +++ b/cpu/ppc/test/testdisasm.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include "../ppcdisasm.h" + +using namespace std; + +/** testing vehicle */ +static vector read_test_data() +{ + string line, token; + int i, lineno; + PPCDisasmContext ctx; + vector tstvec; + + ifstream tfstream("ppcdisasmtest.csv"); + if (!tfstream.is_open()) { + cout << "Could not open tests CSV file. Exiting..." << endl; + return tstvec; + } + + lineno = 0; + + while(getline(tfstream, line)) { + lineno++; + + if (line.empty() || !line.rfind("#", 0)) + continue; // skip empty/comment lines + + istringstream lnstream(line); + + vector tokens; + + while(getline(lnstream, token, ',' )) { + //cout << "Token: " << token << endl; + tokens.push_back(token); + } + + if (tokens.size() < 3) { + cout << "Too few values in line " << lineno << ". Skipping..." << endl; + continue; + } + + ctx = {0}; + ctx.instr_addr = stoul(tokens[0], NULL, 16); + ctx.instr_code = stoul(tokens[1], NULL, 16); + + /* build disassembly string out of comma-separated parts */ + ostringstream idisasm; + + /* put instruction mnemonic padded with trailing spaces */ + idisasm << tokens[2]; + if (tokens.size() > 3) // don't pad operand-less instructions + idisasm << setw(8 - tokens[2].length()) << ""; + + /* now add comma-separated operands */ + for (i = 3; i < tokens.size(); i++) { + if (i > 3) + idisasm << ", "; + idisasm << tokens[i]; + } + + ctx.instr_str = idisasm.str(); + + //cout << idisasm.str() << endl; + + tstvec.push_back(ctx); + } + + return tstvec; +} + +int test_ppc_disasm() +{ + int i, nfailed; + PPCDisasmContext ctx; + + vector testdata = read_test_data(); + + cout << "Imported " << testdata.size() << " test instructions." << endl; + + nfailed = 0; + + for (i = 0; i < testdata.size(); i++) { + ctx = {0}; + ctx.instr_addr = testdata[i].instr_addr; + ctx.instr_code = testdata[i].instr_code; + ctx.simplified = true; + + std::string disas = disassemble_single(&ctx); + + if (disas != testdata[i].instr_str) { + cout << "Mismatch found, expected={" << testdata[i].instr_str << + "}, got={" << disas << "}" << endl; + nfailed++; + } + } + + cout << "Tested " << testdata.size() << " instructions. Failed: " << + nfailed << "." << endl; + + return 0; +}