diff --git a/.clang-format-include b/.clang-format-include index be36b4ffb33..63e032dc5d8 100644 --- a/.clang-format-include +++ b/.clang-format-include @@ -5,3 +5,4 @@ src/gallium/drivers/i915 src/amd/vulkan/**/* src/amd/compiler/**/* src/egl/**/* +src/etnaviv/isa/**/* diff --git a/.gitlab-ci/test-source-dep.yml b/.gitlab-ci/test-source-dep.yml index 4a2bed11b27..bee4d9c5772 100644 --- a/.gitlab-ci/test-source-dep.yml +++ b/.gitlab-ci/test-source-dep.yml @@ -253,6 +253,7 @@ - src/egl/**/* - src/amd/vulkan/**/* - src/amd/compiler/**/* + - src/etnaviv/isa/**/* when: on_success allow_failure: false # in other pipelines, formatting checks are allowed to fail diff --git a/src/etnaviv/ci/gitlab-ci.yml b/src/etnaviv/ci/gitlab-ci.yml index 947869d2c53..94c84cce6e9 100644 --- a/src/etnaviv/ci/gitlab-ci.yml +++ b/src/etnaviv/ci/gitlab-ci.yml @@ -13,6 +13,7 @@ - src/etnaviv/ci/$GPU_VERSION-skips.txt - src/etnaviv/drm/**/* - src/etnaviv/drm-shim/**/* + - src/etnaviv/isa/**/* - src/gallium/drivers/etnaviv/**/* - src/gallium/winsys/etnaviv/**/* - src/gallium/auxiliary/renderonly/**/* diff --git a/src/etnaviv/isa/.clang-format b/src/etnaviv/isa/.clang-format new file mode 100644 index 00000000000..b1a43d91fe2 --- /dev/null +++ b/src/etnaviv/isa/.clang-format @@ -0,0 +1,7 @@ + +BasedOnStyle: InheritParentConfig +DisableFormat: false + +AlignConsecutiveBitFields: true +ColumnLimit: 100 +BreakStringLiterals: false diff --git a/src/etnaviv/isa/disasm.c b/src/etnaviv/isa/disasm.c new file mode 100644 index 00000000000..88710f663c3 --- /dev/null +++ b/src/etnaviv/isa/disasm.c @@ -0,0 +1,33 @@ +/* + * Copyright © 2023 Igalia S.L. + * SPDX-License-Identifier: MIT + */ + +#include + +#include "util/os_file.h" + +#include "isa.h" + +static void +pre_instr_cb(void *d, unsigned n, void *instr) +{ + uint32_t *dwords = (uint32_t *)instr; + printf("%03d [%08x %08x %08x %08x] ", n, dwords[0], dwords[1], dwords[2], dwords[3]); +} + +int +main(int argc, char *argv[]) +{ + size_t sz; + void *raw = os_read_file(argv[1], &sz); + + isa_disasm(raw, sz, stdout, + &(struct isa_decode_options){ + .show_errors = true, + .branch_labels = true, + .pre_instr_cb = pre_instr_cb, + }); + + return 0; +} diff --git a/src/etnaviv/isa/etnaviv.xml b/src/etnaviv/isa/etnaviv.xml new file mode 100644 index 00000000000..b09c0a4609f --- /dev/null +++ b/src/etnaviv/isa/etnaviv.xml @@ -0,0 +1,1246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {DST_USE} == 0 + + + void + + + + + t{REG}{AMODE}{COMPS} + + + + + + + + + + + + + 00 + + + + {TYPE_BIT2} << 2 | {TYPE_BIT01} + + + + + + .{SWIZ_X}{SWIZ_Y}{SWIZ_Z}{SWIZ_W} + + + + + + + + + + + + + + + + + + + + + 00000 + + + + + + + + {HIGH_HALF} << 1 | {LOW_HALF} + + + + + + + 00000000 + + + + + {SRC_NEG}{SRC_ABS}{SRC_RGROUP}{SRC_REG}{SRC_AMODE}{SRC_SWIZ}{SRC_ABS} + + + + + + + + ({SRC_AMODE} >> 1) + + + + + (({SRC_RGROUP} == 7) & ({IMMED_TYPE} == 0)) + + + + {IMMED} + + + + + (((({SRC_AMODE} & 0x1) << 19) | + ({SRC_ABS} << 18) | + ({SRC_NEG} << 17) | + ({SRC_SWIZ} << 9) | + {SRC_REG}) << 12) + + + + + + + (({SRC_RGROUP} == 7) & ({IMMED_TYPE} == 1)) + + + + {IMMED} + + + + + ((({SRC_AMODE} & 0x1) << 19) | + ({SRC_ABS} << 18) | + ({SRC_NEG} << 17) | + ({SRC_SWIZ} << 9) | + {SRC_REG}) + + + + + + + (({SRC_RGROUP} == 7) & ({IMMED_TYPE} == 2)) + + + + {IMMED} + + + + + ((({SRC_AMODE} & 0x1) << 19) | + ({SRC_ABS} << 18) | + ({SRC_NEG} << 17) | + ({SRC_SWIZ} << 9) | + {SRC_REG}) + + + + + + + (({SRC_RGROUP} == 7) & ({IMMED_TYPE} == 3)) + + + + {IMMED} + + + + + ((({SRC_AMODE} & 0x1) << 19) | + ({SRC_ABS} << 18) | + ({SRC_NEG} << 17) | + ({SRC_SWIZ} << 9) | + {SRC_REG}) + + + + + + + + {INSTR_ALU} {DST:align=18}, {SRC0}, {SRC1}, {SRC2} + + + xxxxxxxx + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + + + {INSTR_ALU} {DST:align=18}, {SRC0}, {SRC1}, {SRC2} + + + xxxxxxxx + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + + + {NAME} {DST:align=18}{DST_FULL}, void, void, void + + + + 0 + 000000000 + 00000000 + 0 + 0 + 0 + 000 + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + + ({SRC0_USE} != 0) && ({SRC1_USE} != 0) + + + + Needed for texkill + + {NAME}{COND}{TYPE}{PMODE}{THREAD}{RMODE} {DST:align=18}{DST_FULL}, void, void, void + + + + + {NAME}{COND}{TYPE}{PMODE}{THREAD}{RMODE} {DST:align=18}, {SRC0}, {SRC1}, void + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + + + {INSTR_ALU} {DST:align=18}, {SRC0}, void, void + + + + 1 + + + + + + + + + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + + + {INSTR_ALU} {DST:align=18}, void, void, {SRC2} + + + + 0 + 000000000 + 00000000 + 0 + 0 + 0 + 000 + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + 1 + + + + + + + + + + + + + {INSTR_ALU} {DST:align=18}, {SRC0}, {SRC1}, void + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + + + {INSTR_ALU} {DST:align=18}, {SRC0}, void, {SRC2} + + + + 1 + + + + + + + + + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + 1 + + + + + + + + + + + + + {INSTR_ALU} {DST:align=18}, {SRC0}, {SRC1}, {SRC2} + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 0 + + + + + {INSTR_TEX} {DST:align=18}, tex{TEX_ID}, {SRC0}, void, void + + + + 1 + + + + + + + + + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + + + {INSTR_TEX} {DST:align=18}, tex{TEX_ID}, {SRC0}, {SRC1}, {SRC2} + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + + 00000000000000000000 + + 00 + x + 00000000 + + 0000 + + 0000000000 + + + + + {INSTR_CF} {:align=18}void, void, void, {TARGET} + + + 0000000000 + 0000000000 + + 0 + 0000000000000 + 0000000000000 + 000 + + + + + {INSTR_CF} {:align=18}void, {SRC0}, {SRC1}, {TARGET} + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + + ({LEFT_SHIFT} != 0) + + + + + + + + + + 00000 + 00 + + + 00 + + + 0 + + + + + + + {HIGH_HALF} << 1 | {LOW_HALF} + + + + + + {INSTR_LOAD_STORE} {DST:align=18}, {SRC0}, {SRC1}, void + + + + + {INSTR_LOAD_STORE_WITH_LEFT_SHIFT} {DST:align=18}, {SRC0}, {SRC1}, void + + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + 0 + 000000000 + 00000000 + 0 + 0 + 000 + 000 + + + + xxxxx + x + xxxxx + + xxxxx + xx + + + 00 + + + x + + + + + + + {HIGH_HALF} << 1 | {LOW_HALF} + + + + + + {INSTR_LOAD_STORE} {:align=18}mem{COMPS}, {SRC0}, {SRC1}, {SRC2} + + + + + {INSTR_LOAD_STORE_WITH_LEFT_SHIFT} {:align=18}mem{COMPS}, {SRC0}, {SRC1}, {SRC2} + + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + 1 + + + + + + + + + + + + + + 000000 + 0 + + + + 000001 + 0 + + + + 000010 + 0 + + + + 000011 + 0 + + + + + + 000100 + 0 + + + + 000101 + 0 + + + + 000110 + 0 + + + + + + + 001001 + 0 + + + + + + + 001100 + 0 + + + + 001101 + 0 + + + + + + 001111 + 0 + + + + 010000 + 0 + + + + 010001 + 0 + + + + 010010 + 0 + + + + + + 010100 + 0 + + + + 010101 + 0 + + + + 010110 + 0 + + + + 010110 + 0 + + + + 010111 + 0 + + + + 011000 + 0 + + + + + + + + + + + + + + + 100001 + 0 + + + + 100010 + 0 + + + + 100011 + 0 + + + + + + 100101 + 0 + + + + 100110 + 0 + + + + 100111 + 0 + + + + + + + 101010 + 0 + + + + + + 101100 + 0 + + + + 101101 + 0 + + + + 101110 + 0 + + + + 101111 + 0 + + + + + + 110001 + 0 + + + + 110010 + 0 + + + + 110011 + 0 + + + + 111011 + 0 + + + + 111100 + 0 + + + + + + + + 000000 + 1 + + + + + + 000100 + 1 + + + + 001000 + 1 + + + + 001100 + 1 + + + + 001110 + 1 + + + + 011100 + 1 + + + + 011101 + 1 + + + + 011110 + 1 + + + + 011111 + 1 + + + + 100001 + 1 + + + + 010111 + 1 + + + + 011000 + 1 + + + + 011001 + 1 + + + + 011010 + 1 + + + + 011011 + 1 + + + + 100101 + 1 + + + + 100110 + 1 + + + + 100111 + 1 + + + + 101000 + 1 + + + + 101001 + 1 + + + + 101010 + 1 + + + + 101011 + 1 + + + + 101100 + 1 + + + + 101111 + 1 + + + diff --git a/src/etnaviv/isa/isa.h b/src/etnaviv/isa/isa.h new file mode 100644 index 00000000000..6214bc154ec --- /dev/null +++ b/src/etnaviv/isa/isa.h @@ -0,0 +1,11 @@ +/* + * Copyright © 2023 Igalia S.L. + * SPDX-License-Identifier: MIT + */ + +#ifndef _ISA_H_ +#define _ISA_H_ + +#include "compiler/isaspec/isaspec.h" + +#endif /* _ISA_H_ */ diff --git a/src/etnaviv/isa/meson.build b/src/etnaviv/isa/meson.build new file mode 100644 index 00000000000..a191f76ac5d --- /dev/null +++ b/src/etnaviv/isa/meson.build @@ -0,0 +1,48 @@ +# +# Copyright © 2023 Igalia S.L. +# SPDX-License-Identifier: MIT +# + +isa_depend_files = [ + 'etnaviv.xml', +] + +etnaviv_isa = custom_target( + 'etnaviv-isa', + input: ['etnaviv.xml'], + output: ['etnaviv-isa.c', 'etnaviv-isa.h'], + command: [ + prog_isaspec_decode, '--xml', '@INPUT@', + '--out-c', '@OUTPUT0@', '--out-h', '@OUTPUT1@', + ], + depend_files: isa_depend_files, +) + +decode_files = [ + etnaviv_isa, + 'isa.h', +] + +libetnaviv_decode = static_library( + 'etnaviv_decode', + decode_files, + dependencies: [idep_mesautil, idep_isaspec_decode], + include_directories: [ + inc_include, + inc_src, + ], + gnu_symbol_visibility: 'hidden', +) + +disasm = executable( + 'etnaviv-disasm', + ['disasm.c'], + link_with: libetnaviv_decode, + build_by_default: with_tools.contains('etnaviv'), + include_directories: [ + inc_src, + ], + install: false, +) + +subdir('tests') diff --git a/src/etnaviv/isa/tests/disasm.cpp b/src/etnaviv/isa/tests/disasm.cpp new file mode 100644 index 00000000000..09f3b478d04 --- /dev/null +++ b/src/etnaviv/isa/tests/disasm.cpp @@ -0,0 +1,311 @@ +/* + * Copyright © 2023 Igalia S.L. + * SPDX-License-Identifier: MIT + */ + +/* Unit test for disassembly of instructions. + * + * The goal is to take instructions we've seen the blob produce, and test that + * we can disassemble them correctly. + */ + +#include "compiler/isaspec/isaspec.h" +#include + +struct disasm_state { + uint32_t bin[4]; + const char *disasm; + + friend std::ostream &operator<<(std::ostream &os, const disasm_state &obj) + { + // clang-format off + return os + << "binary: " + << std::showbase << std::internal << std::setfill('0') << std::setw(8) << std::hex << obj.bin[0] << " " + << std::showbase << std::internal << std::setfill('0') << std::setw(8) << std::hex << obj.bin[1] << " " + << std::showbase << std::internal << std::setfill('0') << std::setw(8) << std::hex << obj.bin[2] << " " + << std::showbase << std::internal << std::setfill('0') << std::setw(8) << std::hex << obj.bin[3] << " " + << "disasm: " << obj.disasm; + // clang-format on + } +}; + +struct DisasmTest : testing::Test, testing::WithParamInterface { + char *disasm_output; + + DisasmTest() + { + static const struct isa_decode_options options = {.show_errors = true, + .branch_labels = false}; + + constexpr int output_size = 4096; + disasm_output = (char *)malloc(output_size); + FILE *fdisasm = fmemopen(disasm_output, output_size, "w+"); + + if (!fdisasm) { + return; + } + + isa_disasm((void *)GetParam().bin, 16, fdisasm, &options); + fflush(fdisasm); + } +}; + +TEST_P(DisasmTest, basicOpCodes) +{ + auto as = GetParam(); + EXPECT_STREQ(as.disasm, disasm_output); +} + +// clang-format off +INSTANTIATE_TEST_SUITE_P(Default, DisasmTest, + testing::Values( + disasm_state{ {0x00000000, 0x00000000, 0x00000000, 0x00000000}, "nop void, void, void, void\n" }, + disasm_state{ {0x07811018, 0x15001f20, 0x00000000, 0x00000000}, "texld.xyzw t1, tex0, t1.xyyy, void, void\n" }, + disasm_state{ {0x07831018, 0x39003f20, 0x00000000, 0x00000000}, "texld.xyzw t3, tex0, t3.xyzw, void, void\n" }, + disasm_state{ {0x07811009, 0x00000000, 0x00000000, 0x20390008}, "mov.pack t1, void, void, u0.xyzw\n" }, + disasm_state{ {0x01821009, 0x00000000, 0x00000000, 0x00150028}, "mov.pack t2.xy__, void, void, t2.xyyy\n"}, + disasm_state{ {0x01821009, 0x00000000, 0x00000000, 0x00550028}, "mov.pack t2.xy__, void, void, -t2.xyyy\n"}, + disasm_state{ {0x01821009, 0x00000000, 0x00000000, 0x00950028}, "mov.pack t2.xy__, void, void, |t2.xyyy|\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(OperandTypes, DisasmTest, + testing::Values( + disasm_state{ {0x01821009, 0x00000000, 0x00000000, 0x00150028}, "mov.pack t2.xy__, void, void, t2.xyyy\n"}, + disasm_state{ {0x01821009, 0x00000000, 0x40000000, 0x00150028}, "mov.s32.pack t2.xy__, void, void, t2.xyyy\n"}, + disasm_state{ {0x01821009, 0x00000000, 0x80000000, 0x00150028}, "mov.s8.pack t2.xy__, void, void, t2.xyyy\n"}, + disasm_state{ {0x01821009, 0x00000000, 0xc0000000, 0x00150028}, "mov.u16.pack t2.xy__, void, void, t2.xyyy\n"}, + disasm_state{ {0x01821009, 0x00200000, 0x00000000, 0x00150028}, "mov.f16.pack t2.xy__, void, void, t2.xyyy\n"}, + disasm_state{ {0x01821009, 0x00200000, 0x40000000, 0x00150028}, "mov.s16.pack t2.xy__, void, void, t2.xyyy\n"}, + disasm_state{ {0x01821009, 0x00200000, 0x80000000, 0x00150028}, "mov.u32.pack t2.xy__, void, void, t2.xyyy\n"}, + disasm_state{ {0x01821009, 0x00200000, 0xc0000000, 0x00150028}, "mov.u8.pack t2.xy__, void, void, t2.xyyy\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(Opcodes, DisasmTest, + testing::Values( + // GC3000 + disasm_state{ {0x00000000, 0x00000000, 0x00000000, 0x00000000}, "nop void, void, void, void\n" }, + disasm_state{ {0x00801001, 0x00001804, 0x00000000, 0x00000008}, "add t0.x___, t1.xxxx, void, t0.xxxx\n" }, + disasm_state{ {0x07801002, 0x39002805, 0x01c800c0, 0x00390038}, "mad.rtz t0, t2.xyzw, t1.xyzw, t3.xyzw\n" }, + disasm_state{ {0x00801003, 0x00001804, 0x00000040, 0x00000000}, "mul t0.x___, t1.xxxx, t0.xxxx, void\n" }, + disasm_state{ {0x00801005, 0x09000802, 0x00000040, 0x00000002}, "dp3.pack.rtne t0.x___, t0.xyzx, u0.xxxx, void\n" }, + disasm_state{ {0x00801006, 0x39001804, 0x01c800c0, 0x00000000}, "dp4 t0.x___, t1.xyzw, t1.xyzw, void\n" }, + disasm_state{ {0x01821009, 0x00000000, 0x00000000, 0x00150028}, "mov.pack t2.xy__, void, void, t2.xyyy\n"}, + disasm_state{ {0x0081100c, 0x00000000, 0x00000000, 0x00000018}, "rcp.pack t1.x___, void, void, t1.xxxx\n" }, + disasm_state{ {0x0080100d, 0x00000004, 0x00000000, 0x00000008}, "rsq t0.x___, void, void, t0.xxxx\n" }, + disasm_state{ {0x0783108f, 0x39002800, 0x05c800c0, 0x00390028}, "select.lt.pack t3, t2.xyzw, |t1.xyzw|, t2.xyzw\n"}, + disasm_state{ {0x008010d0, 0x00000800, 0x00000040, 0x00000002}, "set.ge.pack t0.x___, t0.xxxx, u0.xxxx, void\n" }, + disasm_state{ {0x01001011, 0x00000004, 0x00000000, 0x00154008}, "exp t0._y__, void, void, t0.yyyy\n" }, + disasm_state{ {0x01801012, 0x00000005, 0x00000000, 0x00000008}, "log.rtz t0.xy__, void, void, t0.xxxx\n" }, + disasm_state{ {0x00000014, 0x00000000, 0x00000000, 0x00000380}, "call void, void, void, 7\n" }, + disasm_state{ {0x00000015, 0x00000000, 0x00000000, 0x00000000}, "ret void, void, void, void\n" }, + disasm_state{ {0x00000016, 0x00000000, 0x00000000, 0x00001080}, "branch void, void, void, 33\n"}, + disasm_state{ {0x00000017, 0x00000000, 0x00000000, 0x00000000}, "texkill.pack void, void, void, void\n" }, + disasm_state{ {0x00000057, 0x00002800, 0x00000040, 0x00000002}, "texkill.gt.pack void, t2.xxxx, u0.xxxx, void\n" }, + disasm_state{ {0x07811018, 0x15001f20, 0x00000000, 0x00000000}, "texld.xyzw t1, tex0, t1.xyyy, void, void\n" }, + disasm_state{ {0x00801021, 0x00000004, 0x00000000, 0x00000008}, "sqrt t0.x___, void, void, t0.xxxx\n" }, + disasm_state{ {0x03001022, 0x00000005, 0x00000000, 0x00154008}, "sin.rtz t0.zy, void, void, t0.yyyy\n" }, + disasm_state{ {0x01801023, 0x00000005, 0x00000000, 0x00000008}, "cos.rtz t0.xy__, void, void, t0.xxxx\n" }, + disasm_state{ {0x00801025, 0x00000004, 0x00000000, 0x00000008}, "floor t0.x___, void, void, t0.xxxx\n"}, + disasm_state{ {0x00801026, 0x00000004, 0x00000000, 0x00000008}, "ceil t0.x___, void, void, t0.xxxx\n"}, + disasm_state{ {0x00801027, 0x00000004, 0x00000000, 0x00000008}, "sign t0.x___, void, void, t0.xxxx\n" }, + disasm_state{ {0x0000002a, 0x00000000, 0x00000000, 0x00000000}, "barrier void, void, void, void\n" }, + disasm_state{ {0x0080102c, 0x00200804, 0x50001040, 0x00000007}, "i2i.s16 t0.x___, t0.xxxx, 32, void\n" }, + disasm_state{ {0x0381102d, 0x00201804, 0x40000000, 0x00000000}, "i2f.s16 t1.xyz_, t1.xxxx, void, void\n"}, + disasm_state{ {0x0101102e, 0x00201804, 0x80000020, 0x00002000}, "f2i.u32.t0 t1._y__, th1.xxxx, void, void\n"}, + disasm_state{ {0x0081102f, 0x00000806, 0x40000000, 0x00000000}, "f2irnd.s32.rtne t1.x___, t0.xxxx, void, void\n"}, + disasm_state{ {0x00811131, 0x80001800, 0x00aa0040, 0x202a800a}, "cmp.le.pack t1.x___, |t1.xxxx|, u0.yyyy, u0.zzzz\n"}, + disasm_state{ {0x00801032, 0x00000c04, 0x10000050, 0x00000007}, "load.denorm t0.x___, u0.xxxx, 0, void\n"}, + disasm_state{ {0x00800033, 0x00000c84, 0x10000050, 0x0000000f}, "store.skpHp.denorm mem.x___, u0.xxxx, 0, t0.xxxx\n"}, + disasm_state{ {0x0080103b, 0x00001804, 0x40000000, 0x00400028}, "iaddsat.s32 t0.x___, t1.xxxx, void, -t2.xxxx\n"}, + disasm_state{ {0x01001008, 0x15400804, 0xd00100c0, 0x00000007}, "imod.u16 t0._y__, t0.yyyy, 1, void\n"}, + disasm_state{ {0x0080103c, 0x00001804, 0x40000140, 0x00000000}, "imullo0.s32 t0.x___, t1.xxxx, t2.xxxx, void\n"}, + disasm_state{ {0x00801000, 0x00001804, 0x40010140, 0x00000000}, "imulhi0.s32 t0.x___, t1.xxxx, t2.xxxx, void\n"}, + disasm_state{ {0x00801004, 0x00201804, 0x40010040, 0x00000000}, "idiv0.s16 t0.x___, t1.xxxx, t0.xxxx, void\n"}, + disasm_state{ {0x0080100e, 0x00001804, 0x40010140, 0x00000038}, "imadlosat0.s32 t0.x___, t1.xxxx, t2.xxxx, t3.xxxx\n"}, + disasm_state{ {0x0082101c, 0x00001804, 0x40010000, 0x00000008}, "or.s32 t2.x___, t1.xxxx, void, t0.xxxx\n"}, + disasm_state{ {0x0082101d, 0x00001804, 0x40010000, 0x00000008}, "and.s32 t2.x___, t1.xxxx, void, t0.xxxx\n"}, + disasm_state{ {0x0080101e, 0x00001804, 0x40010000, 0x00000008}, "xor.s32 t0.x___, t1.xxxx, void, t0.xxxx\n"}, + disasm_state{ {0x0080101f, 0x00000004, 0x40010000, 0x00000018}, "not.s32 t0.x___, void, void, t1.xxxx\n"}, + disasm_state{ {0x00801021, 0x00000004, 0x00010000, 0x00000008}, "popcount t0.x___, void, void, t0.xxxx\n"}, + disasm_state{ {0x00801017, 0x00000004, 0x40010000, 0x00000018}, "iabs.s32 t0.x___, void, void, t1.xxxx\n"}, + disasm_state{ {0x00801018, 0x00000004, 0x40010000, 0x00000008}, "leadzero.s32 t0.x___, void, void, t0.xxxx\n"}, + disasm_state{ {0x00801019, 0x15400804, 0x40010000, 0x74000028}, "lshift.s32 t0.x___, t0.yyyy, void, 2\n"}, + disasm_state{ {0x0080101a, 0x00001804, 0x40010000, 0x78000018}, "rshift.s32 t0.x___, t1.xxxx, void, 1\n"}, + disasm_state{ {0x0080101b, 0x00001804, 0x40010000, 0x00000008}, "rotate.s32 t0.x___, t1.xxxx, void, t0.xxxx\n"}, + disasm_state{ {0x01061025, 0x2aa00804, 0xa0010050, 0x7800001f}, "atomic_add.u32 t6._y__, u0.zzzz, 0, 1\n"}, + disasm_state{ {0x00801025, 0x2a800884, 0x50010050, 0x0000000f}, "atomic_add.s32 t0.x___, u0.zzzz, 0, t0.xxxx\t; dontcare bits in atomic_add: 00000000000000000000008000000000\n"}, + disasm_state{ {0x00821026, 0x2a800884, 0x50010050, 0x0000001f}, "atomic_xchg.s32 t2.x___, u0.zzzz, 0, t1.xxxx\t; dontcare bits in atomic_xchg: 00000000000000000000008000000000\n"}, + disasm_state{ {0x00801027, 0x2a800884, 0x50010050, 0x0015000f}, "atomic_cmp_xchg.s32 t0.x___, u0.zzzz, 0, t0.xyyy\t; dontcare bits in atomic_cmp_xchg: 00000000000000000000008000000000\n"}, + disasm_state{ {0x00821028, 0x2a800884, 0x50010050, 0x0000001f}, "atomic_min.s32 t2.x___, u0.zzzz, 0, t1.xxxx\t; dontcare bits in atomic_min: 00000000000000000000008000000000\n"}, + disasm_state{ {0x00821029, 0x2a800884, 0x50010050, 0x0000000f}, "atomic_max.s32 t2.x___, u0.zzzz, 0, t0.xxxx\t; dontcare bits in atomic_max: 00000000000000000000008000000000\n"}, + disasm_state{ {0x0080102a, 0x2a800884, 0x50010050, 0x0000000f}, "atomic_or.s32 t0.x___, u0.zzzz, 0, t0.xxxx\t; dontcare bits in atomic_or: 00000000000000000000008000000000\n"}, + disasm_state{ {0x0082102b, 0x2a800884, 0x50010050, 0x0000001f}, "atomic_and.s32 t2.x___, u0.zzzz, 0, t1.xxxx\t; dontcare bits in atomic_and: 00000000000000000000008000000000\n"}, + disasm_state{ {0x0080102c, 0x2a800884, 0x50010050, 0x0000001f}, "atomic_xor.s32 t0.x___, u0.zzzz, 0, t1.xxxx\t; dontcare bits in atomic_xor: 00000000000000000000008000000000\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(Branch, DisasmTest, + testing::Values( + // taken from deqp2 run on GC2000 + disasm_state{ {0x00000016, 0x00000000, 0x00000000, 0x00001080}, "branch void, void, void, 33\n"}, + disasm_state{ {0x00000056, 0x00000800, 0x000000d0, 0x00000280}, "branch.gt void, u0.xxxx, t1.xxxx, 5\n"}, + disasm_state{ {0x00000056, 0x00000800, 0x000000d0, 0x00000280}, "branch.gt void, u0.xxxx, t1.xxxx, 5\n"}, + disasm_state{ {0x00000096, 0x15402800, 0x00000040, 0x00000082}, "branch.lt void, t2.yyyy, u0.xxxx, 1\n"}, + disasm_state{ {0x000000d6, 0x00001800, 0x01540250, 0x00000980}, "branch.ge void, u1.xxxx, t4.zzzz, 19\n"}, + disasm_state{ {0x00000116, 0x3fc01800, 0x000000c0, 0x00000482}, "branch.le void, t1.wwww, u1.xxxx, 9\n"}, + disasm_state{ {0x00000156, 0x39001800, 0x000002c0, 0x00001282}, "branch.eq void, t1.xyzw, u5.xxxx, 37\n"}, + disasm_state{ {0x00000196, 0x15401800, 0x00aa0040, 0x00000382}, "branch.ne void, t1.yyyy, u0.yyyy, 7\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(Abs, DisasmTest, + testing::Values( + // taken from deqp2 run on GC2000 + disasm_state{ {0x00811131, 0x80001800, 0x00aa0040, 0x202a800a}, "cmp.le.pack t1.x___, |t1.xxxx|, u0.yyyy, u0.zzzz\n"}, + disasm_state{ {0x0783108f, 0x39002800, 0x05c800c0, 0x00390028}, "select.lt.pack t3, t2.xyzw, |t1.xyzw|, t2.xyzw\n"}, + disasm_state{ {0x0383108f, 0xa9001800, 0x05480140, 0x00a90018}, "select.lt.pack t3.xyz_, |t1.xyzz|, |t2.xyzz|, |t1.xyzz|\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(Minus, DisasmTest, + testing::Values( + // taken from deqp2 run on GC2000 + disasm_state{ {0x01021001, 0x3fc00800, 0x00000010, 0x00554018}, "add.pack t2._y__, u0.wwww, void, -t1.yyyy\n"}, + disasm_state{ {0x00821001, 0x40001800, 0x00000000, 0x00554018}, "add.pack t2.x___, -t1.xxxx, void, -t1.yyyy\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(AddressRegister, DisasmTest, + testing::Values( + // taken from deqp2 run on GC2000 + disasm_state{ {0x00823009, 0x00000000, 0x00000000, 0x00000018}, "mov.pack t2[a.x].x___, void, void, t1.xxxx\n"}, + disasm_state{ {0x00825009, 0x00000000, 0x00000000, 0x00154028}, "mov.pack t2[a.y].x___, void, void, t2.yyyy\n"}, + disasm_state{ {0x00827009, 0x00000000, 0x00000000, 0x00000018}, "mov.pack t2[a.z].x___, void, void, t1.xxxx\n"}, + disasm_state{ {0x00829009, 0x00000000, 0x00000000, 0x00000018}, "mov.pack t2[a.w].x___, void, void, t1.xxxx\n"}, + disasm_state{ {0x00801009, 0x00000000, 0x00000000, 0x02000028}, "mov.pack t0.x___, void, void, t2[a.x].xxxx\n"}, + disasm_state{ {0x01031009, 0x00000000, 0x00000000, 0x043fc018}, "mov.pack t3._y__, void, void, t1[a.y].wwww\n"}, + disasm_state{ {0x02031009, 0x00000000, 0x00000000, 0x063fc018}, "mov.pack t3.__z_, void, void, t1[a.z].wwww\n"}, + disasm_state{ {0x01811001, 0x15001800, 0x00000000, 0x28150018}, "add.pack t1.xy__, t1.xyyy, void, u1[a.w].xyyy\n"}, + disasm_state{ {0x01011001, 0x00001800, 0x00000001, 0x04000018}, "add.pack t1._y__, t1[a.x].xxxx, void, t1[a.y].xxxx\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(Threads, DisasmTest, + testing::Values( + // taken from deqp3 run on GC3000 + disasm_state{ {0x01011001, 0x00001804, 0x00000020, 0xa0402008}, "add.t0 t1._y__, th1.xxxx, void, -u0.xxxx\n"}, + disasm_state{ {0x01021001, 0x00002804, 0x00000020, 0xa1400008}, "add.t1 t2._y__, th2.xxxx, void, -u0.xxxx\n"}, + + // full dual-16 shader from a deqp3 run on GC3000 + disasm_state{ {0x0101102e, 0x00201804, 0x80000020, 0x00002000}, "f2i.u32.t0 t1._y__, th1.xxxx, void, void\n"}, + disasm_state{ {0x0101102e, 0x00202804, 0x80000020, 0x01000000}, "f2i.u32.t1 t1._y__, th2.xxxx, void, void\n"}, + disasm_state{ {0x00811171, 0x15601804, 0x80000040, 0x76fffffa}, "cmp.eq.u32.t0 t1.x___, t1.yyyy, u0.xxxx, -1\n"}, + disasm_state{ {0x00811171, 0x15601804, 0x80000040, 0x77ffdffa}, "cmp.eq.u32.t1 t1.x___, t1.yyyy, u0.xxxx, -1\n"}, + disasm_state{ {0x0081158f, 0x00201804, 0x700000c0, 0x7c00000f}, "select.0x16.s16 t1.x___, t1.xxxx, 0.000000, 0.000000\n"}, + disasm_state{ {0x0381102d, 0x00201804, 0x40000000, 0x00000000}, "i2f.s16 t1.xyz_, t1.xxxx, void, void\n"}, + disasm_state{ {0x04011009, 0x00000004, 0x00000000, 0x20154008}, "mov t1.___w, void, void, u0.yyyy\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(ImmediateValues, DisasmTest, + testing::Values( + // taken from deqp3 run on GC3000 + disasm_state{ {0x00801001, 0x7e000805, 0x00000038, 0x00800008}, "add.rtz t0.x___, 0.500000, void, |t0.xxxx|\n"}, /* type: 0 */ + disasm_state{ {0x00811131, 0x95401804, 0x00aa0060, 0x76fffffa}, "cmp.le.t0 t1.x___, |th1.yyyy|, u0.yyyy, -1\n"}, /* type: 1 */ + disasm_state{ {0x0080101a, 0x00001804, 0x40010000, 0x78000018}, "rshift.s32 t0.x___, t1.xxxx, void, 1\n"}, /* type: 2*/ + disasm_state{ {0x020211b1, 0x00001804, 0x01fe0040, 0x7c1fdffa}, "cmp.ne t2.__z_, t1.xxxx, u0.wwww, -nan\n"} /* type: 3 */ + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(LoadStore, DisasmTest, + testing::Values( + // full opencl shader on GC3000 + disasm_state{ {0x00801032, 0x00000c04, 0x10000050, 0x00000007}, "load.denorm t0.x___, u0.xxxx, 0, void\n"}, + disasm_state{ {0x00811032, 0x15400c04, 0x10000050, 0x00000007}, "load.denorm t1.x___, u0.yyyy, 0, void\n"}, + disasm_state{ {0x00801001, 0x00001804, 0x00000000, 0x00000008}, "add t0.x___, t1.xxxx, void, t0.xxxx\n"}, + disasm_state{ {0x00800033, 0x00000c84, 0x10000050, 0x0000000f}, "store.skpHp.denorm mem.x___, u0.xxxx, 0, t0.xxxx\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(Rounding, DisasmTest, + testing::Values( + // taken from opencl shader on GC3000 + disasm_state{ {0x0081102f, 0x00000806, 0x40000000, 0x00000000}, "f2irnd.s32.rtne t1.x___, t0.xxxx, void, void\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(CLRoundShader, DisasmTest, + testing::Values( + // taken from opencl shader on GC3000 + disasm_state{ {0x00801032, 0x15400c04, 0x10000050, 0x00000007}, "load.denorm t0.x___, u0.yyyy, 0, void\n"}, + disasm_state{ {0x00811027, 0x00000004, 0x00000000, 0x00000008}, "sign t1.x___, void, void, t0.xxxx\n"}, + disasm_state{ {0x00801001, 0x7e000805, 0x00000038, 0x00800008}, "add.rtz t0.x___, 0.500000, void, |t0.xxxx|\n"}, + disasm_state{ {0x00801025, 0x00000004, 0x00000000, 0x00000008}, "floor t0.x___, void, void, t0.xxxx\n"}, + disasm_state{ {0x00801003, 0x00001805, 0x00000040, 0x00000000}, "mul.rtz t0.x___, t1.xxxx, t0.xxxx, void\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(TFShader, DisasmTest, + testing::Values( + // taken from transform shader on GC2000 + disasm_state{ {0x0081102e, 0x00000800, 0x40000020, 0x00000000}, "f2i.s32.pack t1.x___, th0.xxxx, void, void\n"}, + disasm_state{ {0x07821009, 0x00000000, 0x00000000, 0x00390008}, "mov.pack t2, void, void, t0.xyzw\n"}, + disasm_state{ {0x01831009, 0x00000000, 0x00000000, 0x00150008}, "mov.pack t3.xy__, void, void, t0.xyyy\n"}, + disasm_state{ {0x03841009, 0x00000000, 0x00000000, 0x00290008}, "mov.pack t4.xyz_, void, void, t0.xyzz\n"}, + disasm_state{ {0x0201102d, 0x00000800, 0x40000010, 0x00000000}, "i2f.s32.pack t1.__z_, u0.xxxx, void, void\n"}, + disasm_state{ {0x00000156, 0x2a801800, 0x01540040, 0x00000402}, "branch.eq void, t1.zzzz, u0.zzzz, 8\n"}, + disasm_state{ {0x0081100c, 0x3fc00800, 0x400100d0, 0x20154008}, "imadlo0.s32.pack t1.x___, u0.wwww, t1.xxxx, u0.yyyy\n"}, + disasm_state{ {0x07820033, 0x00001800, 0x01540040, 0x0039002a}, "store.pack mem, t1.xxxx, u0.zzzz, t2.xyzw\t; dontcare bits in store: 00000000000000000000000000020000\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(texldlpcf, DisasmTest, + testing::Values( + // taken from dEQP-GLES3.functional.shaders.texture_functions.texturelod.sampler2dshadow_vertex (GC7000) + disasm_state{ {0x04011809, 0x00000004, 0x00000000, 0x002a8018}, "mov.sat t1.___w, void, void, t1.zzzz\n"}, + disasm_state{ {0x0081102f, 0x29001800, 0x00010140, 0x003fc018}, "texldlpcf.xxxx t1.x___, tex0, t1.xyzz, t1.xxxx, t1.wwww\n"}, + disasm_state{ {0x07011009, 0x00000004, 0x00000000, 0x20390018}, "mov t1._yzw, void, void, u1.xyzw\n"} + ) +); +// clang-format on + +// clang-format off +INSTANTIATE_TEST_SUITE_P(LoadStoreVariants, DisasmTest, + testing::Values( + // seen on GC7000 + disasm_state{ {0x01001032, 0x15400c14, 0x00000050, 0x00000000}, "load.denorm.ls2 t0._y__, u0.yyyy, t0.xxxx, void\n"}, + disasm_state{ {0x01001032, 0x15400d14, 0x00000040, 0x00000000}, "load.denorm.local.ls2 t0._y__, t0.yyyy, t0.xxxx, void\n"}, + disasm_state{ {0x00800033, 0x00000c14, 0x00000050, 0x00154008}, "store.denorm.ls2 mem.x___, u0.xxxx, t0.xxxx, t0.yyyy\n"}, + disasm_state{ {0x00861033, 0x15400d04, 0x100efe40, 0x7085860f}, "store.denorm.local mem.x___, t0.yyyy, 4092, 99.000000\t; dontcare bits in store: 00000000000000000000000000061000\n"} + ) +); +// clang-format on diff --git a/src/etnaviv/isa/tests/meson.build b/src/etnaviv/isa/tests/meson.build new file mode 100644 index 00000000000..afb13bf5cec --- /dev/null +++ b/src/etnaviv/isa/tests/meson.build @@ -0,0 +1,14 @@ +# +# Copyright © 2023 Igalia S.L. +# SPDX-License-Identifier: MIT +# + +test( + 'etnaviv_isa_disasm', + executable( + 'etnaviv_disasm', 'disasm.cpp', + link_with: [libetnaviv_decode], + include_directories: [inc_etnaviv, inc_src], + dependencies : [idep_gtest], + ) +) diff --git a/src/etnaviv/meson.build b/src/etnaviv/meson.build index f2292c6dd12..2150aae1b3b 100644 --- a/src/etnaviv/meson.build +++ b/src/etnaviv/meson.build @@ -21,6 +21,7 @@ inc_etnaviv = include_directories(['.']) subdir('drm') +subdir('isa') if with_tools.contains('drm-shim') subdir('drm-shim')