From e8032b893d63b18a9813a45e96ffe81d48a8b414 Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Mon, 30 Jan 2023 20:12:06 -0600 Subject: [PATCH] nouveau/mme: Add some generic builder tests These don't need hardware and instead run entirely in the simulator. The goal is to have something that we can run in CI and which ensures consistency between the Turing and Fermi MMEs. Part-of: --- src/nouveau/mme/meson.build | 18 +++ src/nouveau/mme/tests/mme_builder_test.cpp | 179 +++++++++++++++++++++ src/nouveau/mme/tests/mme_runner.cpp | 75 +++++++++ src/nouveau/mme/tests/mme_runner.h | 30 ++++ 4 files changed, 302 insertions(+) create mode 100644 src/nouveau/mme/tests/mme_builder_test.cpp diff --git a/src/nouveau/mme/meson.build b/src/nouveau/mme/meson.build index f0db4730c16..74f853b6104 100644 --- a/src/nouveau/mme/meson.build +++ b/src/nouveau/mme/meson.build @@ -109,6 +109,24 @@ idep_nouveau_mme = declare_dependency( ) if with_tests and not with_platform_android + test('mme_builder', + executable( + 'mme_builder_test', + files('tests/mme_runner.cpp', 'tests/mme_builder_test.cpp'), + gnu_symbol_visibility : 'hidden', + include_directories : [inc_include, inc_src], + dependencies : [ + dep_libdrm, + idep_gtest, + idep_mesautil, + idep_nvidia_headers, + idep_nouveau_mme, + idep_nouveau_ws + ], + ), + suite : ['nouveau'], + ) + executable( 'mme_fermi_sim_hw_test', files('tests/mme_runner.cpp', 'tests/mme_fermi_sim_hw_test.cpp'), diff --git a/src/nouveau/mme/tests/mme_builder_test.cpp b/src/nouveau/mme/tests/mme_builder_test.cpp new file mode 100644 index 00000000000..48d720ff963 --- /dev/null +++ b/src/nouveau/mme/tests/mme_builder_test.cpp @@ -0,0 +1,179 @@ +#include "mme_runner.h" +#include "mme_tu104_sim.h" + +#include + +#include "nvk_clc597.h" + +class mme_builder_test : public ::testing::Test { +public: + mme_builder_test(); + ~mme_builder_test(); + + std::vector sims; + uint32_t expected[DATA_DWORDS]; + +private: + mme_fermi_sim_runner fermi_sim; + mme_tu104_sim_runner tu104_sim; +}; + +#define DATA_ADDR 0xc0ffee00 + +mme_builder_test::mme_builder_test() : + fermi_sim(DATA_ADDR), + tu104_sim(DATA_ADDR) +{ + memset(expected, 0, sizeof(expected)); + sims.push_back(&fermi_sim); + sims.push_back(&tu104_sim); +} + +mme_builder_test::~mme_builder_test() +{ } + +#define ASSERT_SIM_DATA(sim) do { \ + for (uint32_t i = 0; i < DATA_DWORDS; i++) \ + ASSERT_EQ((sim)->data[i], expected[i]); \ +} while (0) + +TEST_F(mme_builder_test, sanity) +{ + const uint32_t canary = 0xc0ffee01; + + expected[0] = canary; + + for (auto sim : sims) { + mme_builder b; + mme_builder_init(&b, sim->devinfo); + + sim->mme_store_data(&b, 0, mme_imm(canary)); + + auto macro = mme_builder_finish_vec(&b); + + std::vector params; + sim->run_macro(macro, params); + ASSERT_SIM_DATA(sim); + } +} + +static uint32_t +merge(uint32_t x, uint32_t y, + uint16_t dst_pos, uint16_t bits, uint16_t src_pos) +{ + x &= ~(BITFIELD_MASK(bits) << dst_pos); + y &= (BITFIELD_MASK(bits) << src_pos); + return x | ((y >> src_pos) << dst_pos); +} + +static const uint32_t add_cases[] = { + 0x00000001, + 0xffffffff, + 0x0000ffff, + 0x00008000, + 0x0001ffff, + 0xffff8000, + 0x00010000, + 0x00020000, + 0xfffc0000, + 0xfffe0000, +}; + +TEST_F(mme_builder_test, add) +{ + for (auto sim : sims) { + mme_builder b; + mme_builder_init(&b, sim->devinfo); + + mme_value x = mme_load(&b); + mme_value y = mme_load(&b); + + sim->mme_store_data(&b, 0, mme_add(&b, x, y)); + + auto macro = mme_builder_finish_vec(&b); + + for (uint32_t i = 0; i < ARRAY_SIZE(add_cases); i++) { + for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++) { + std::vector params; + params.push_back(add_cases[i]); + params.push_back(add_cases[j]); + + sim->run_macro(macro, params); + ASSERT_EQ(sim->data[0], add_cases[i] + add_cases[j]); + } + } + } +} + +TEST_F(mme_builder_test, add_imm) +{ + for (auto sim : sims) { + mme_builder b; + mme_builder_init(&b, sim->devinfo); + + mme_value x = mme_load(&b); + + for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++) { + mme_value y = mme_imm(add_cases[j]); + sim->mme_store_data(&b, j, mme_add(&b, x, y), true); + } + + auto macro = mme_builder_finish_vec(&b); + + for (uint32_t i = 0; i < ARRAY_SIZE(add_cases); i++) { + std::vector params; + params.push_back(add_cases[i]); + + sim->run_macro(macro, params); + + for (uint32_t j = 0; j < ARRAY_SIZE(add_cases); j++) + ASSERT_EQ(sim->data[j], add_cases[i] + add_cases[j]); + } + } +} + +TEST_F(mme_builder_test, merge) +{ + static const struct { + uint16_t dst_pos; + uint16_t bits; + uint16_t src_pos; + } cases[] = { + { 12, 12, 20 }, + { 12, 8, 20 }, + { 8, 12, 20 }, + { 12, 16, 8 }, + { 24, 12, 8 }, + }; + + static const uint32_t x = 0x0c406fe0; + static const uint32_t y = 0x76543210; + + for (uint32_t i = 0; i < ARRAY_SIZE(cases); i++) { + expected[i] = merge(x, y, cases[i].dst_pos, + cases[i].bits, cases[i].src_pos); + } + + for (auto sim : sims) { + mme_builder b; + mme_builder_init(&b, sim->devinfo); + + mme_value xv = mme_load(&b); + mme_value yv = mme_load(&b); + + for (uint32_t i = 0; i < ARRAY_SIZE(cases); i++) { + mme_value mv = mme_merge(&b, xv, yv, cases[i].dst_pos, + cases[i].bits, cases[i].src_pos); + sim->mme_store_data(&b, i, mv, true); + } + + auto macro = mme_builder_finish_vec(&b); + + std::vector params; + params.push_back(x); + params.push_back(y); + + sim->run_macro(macro, params); + ASSERT_SIM_DATA(sim); + } +} diff --git a/src/nouveau/mme/tests/mme_runner.cpp b/src/nouveau/mme/tests/mme_runner.cpp index 542c769b323..440d8a1f6b1 100644 --- a/src/nouveau/mme/tests/mme_runner.cpp +++ b/src/nouveau/mme/tests/mme_runner.cpp @@ -7,6 +7,8 @@ #include "mme_fermi_sim.h" #include "mme_tu104_sim.h" +#include "nvk_clc597.h" + #include "nouveau_bo.h" #include "nouveau_context.h" @@ -29,6 +31,13 @@ mme_hw_runner::mme_hw_runner() : memset(&push, 0, sizeof(push)); } +void +mme_runner::mme_store_data(mme_builder *b, uint32_t dw_idx, + mme_value data, bool free_reg) +{ + mme_store_imm_addr(b, data_addr + dw_idx * 4, data, free_reg); +} + mme_hw_runner::~mme_hw_runner() { if (push_bo) { @@ -178,3 +187,69 @@ mme_hw_runner::run_macro(const std::vector& macro, submit_push(); } + +mme_fermi_sim_runner::mme_fermi_sim_runner(uint64_t data_addr) +{ + memset(&info, 0, sizeof(info)); + info.cls_eng3d = FERMI_A; + + memset(data_store, 0, sizeof(data_store)); + + this->devinfo = &info; + this->data_addr = data_addr, + this->data = data_store; +} + +mme_fermi_sim_runner::~mme_fermi_sim_runner() +{ } + +void +mme_fermi_sim_runner::run_macro(const std::vector& macro, + const std::vector& params) +{ + std::vector insts(macro.size()); + mme_fermi_decode(&insts[0], ¯o[0], macro.size()); + + /* First, make a copy of the data and simulate the macro */ + mme_fermi_sim_mem sim_mem = { + .addr = data_addr, + .data = data, + .size = DATA_BO_SIZE, + }; + mme_fermi_sim(insts.size(), &insts[0], + params.size(), ¶ms[0], + 1, &sim_mem); +} + +mme_tu104_sim_runner::mme_tu104_sim_runner(uint64_t data_addr) +{ + memset(&info, 0, sizeof(info)); + info.cls_eng3d = TURING_A; + + memset(data_store, 0, sizeof(data_store)); + + this->devinfo = &info; + this->data_addr = data_addr, + this->data = data_store; +} + +mme_tu104_sim_runner::~mme_tu104_sim_runner() +{ } + +void +mme_tu104_sim_runner::run_macro(const std::vector& macro, + const std::vector& params) +{ + std::vector insts(macro.size()); + mme_tu104_decode(&insts[0], ¯o[0], macro.size()); + + /* First, make a copy of the data and simulate the macro */ + mme_tu104_sim_mem sim_mem = { + .addr = data_addr, + .data = data, + .size = DATA_BO_SIZE, + }; + mme_tu104_sim(insts.size(), &insts[0], + params.size(), ¶ms[0], + 1, &sim_mem); +} diff --git a/src/nouveau/mme/tests/mme_runner.h b/src/nouveau/mme/tests/mme_runner.h index 8f3cbd5ceb8..d57dda60249 100644 --- a/src/nouveau/mme/tests/mme_runner.h +++ b/src/nouveau/mme/tests/mme_runner.h @@ -11,6 +11,7 @@ struct nouveau_ws_device; #include "nvk_cl9097.h" #define DATA_BO_SIZE 4096 +#define DATA_DWORDS 1024 class mme_runner { public: @@ -20,6 +21,9 @@ public: virtual void run_macro(const std::vector& macro, const std::vector& params) = 0; + void mme_store_data(mme_builder *b, uint32_t dw_idx, + mme_value data, bool free_reg = false); + const nv_device_info *devinfo; uint64_t data_addr; uint32_t *data; @@ -49,6 +53,32 @@ private: struct nv_push push; }; +class mme_fermi_sim_runner : public mme_runner { +public: + mme_fermi_sim_runner(uint64_t data_addr); + virtual ~mme_fermi_sim_runner(); + + virtual void run_macro(const std::vector& macro, + const std::vector& params); + +private: + struct nv_device_info info; + uint32_t data_store[DATA_DWORDS]; +}; + +class mme_tu104_sim_runner : public mme_runner { +public: + mme_tu104_sim_runner(uint64_t data_addr); + virtual ~mme_tu104_sim_runner(); + + virtual void run_macro(const std::vector& macro, + const std::vector& params); + +private: + struct nv_device_info info; + uint32_t data_store[DATA_DWORDS]; +}; + inline std::vector mme_builder_finish_vec(mme_builder *b) {