Signed-off-by: Nicolai Hähnle <nicolai.haeh...@amd.com>
---
 src/app/gui/commands.c      | 50 +++++++++++++++++++++++++++++++++++++
 src/app/gui/waves_panel.cpp | 40 +++++++++++++++++++++++++++++
 src/lib/scan_waves.c        |  2 +-
 src/umr.h                   |  2 ++
 4 files changed, 93 insertions(+), 1 deletion(-)

diff --git a/src/app/gui/commands.c b/src/app/gui/commands.c
index 38ae44d..fb6efa0 100644
--- a/src/app/gui/commands.c
+++ b/src/app/gui/commands.c
@@ -2036,20 +2036,70 @@ JSON_Value *umr_process_json_request(JSON_Object 
*request, void **raw_data, unsi
                answer = json_value_init_object();
 
                waves_to_json(asic, ring_is_halted, 1, json_object(answer));
 
                if (disable_gfxoff && asic->fd.gfxoff >= 0) {
                        uint32_t value = 1;
                        write(asic->fd.gfxoff, &value, sizeof(value));
                }
                if (resume_waves)
                        umr_sq_cmd_halt_waves(asic, UMR_SQ_CMD_RESUME);
+       } else if (strcmp(command, "singlestep") == 0) {
+               strcpy(asic->options.ring_name, json_object_get_string(request, 
"ring"));
+
+               unsigned se = (unsigned)json_object_get_number(request, "se");
+               unsigned sh = (unsigned)json_object_get_number(request, "sh");
+               unsigned wgp = (unsigned)json_object_get_number(request, "wgp");
+               unsigned simd_id = (unsigned)json_object_get_number(request, 
"simd_id");
+               unsigned wave_id = (unsigned)json_object_get_number(request, 
"wave_id");
+
+               asic->options.skip_gprs = 0;
+               asic->options.verbose = 0;
+
+               struct umr_wave_data wd;
+               memset(&wd, 0, sizeof(wd));
+
+               int r = umr_scan_wave_slot(asic, se, sh, wgp, simd_id, wave_id, 
&wd);
+               if (r < 0) {
+                       last_error = "failed to scan wave slot";
+                       goto error;
+               }
+
+               // Send the single-step command in a limited retry loop because 
a small number of
+               // single-step commands are required before an instruction is 
actually issued after
+               // a branch.
+               for (int retry = 0; r == 1 && retry < 5; ++retry) {
+                       umr_sq_cmd_singlestep(asic, se, sh, wgp, simd_id, 
wave_id);
+
+                       struct umr_wave_data new_wd;
+                       memset(&new_wd, 0, sizeof(new_wd));
+
+                       r = umr_scan_wave_slot(asic, se, sh, wgp, simd_id, 
wave_id, &new_wd);
+                       if (r < 0) {
+                               last_error = "failed to scan wave slot";
+                               goto error;
+                       }
+
+                       bool moved = new_wd.ws.pc_lo != wd.ws.pc_lo || 
new_wd.ws.pc_hi != wd.ws.pc_hi;
+                       memcpy(&wd, &new_wd, sizeof(wd));
+                       if (moved)
+                               break;
+               }
+
+               answer = json_value_init_object();
+
+               if (r == 1) {
+                       JSON_Value *shaders = json_value_init_object();
+                       JSON_Value *wave = wave_to_json(asic, &wd, 1, /* todo: 
stream */NULL, shaders);
+                       json_object_set_value(json_object(answer), "wave", 
wave);
+                       json_object_set_value(json_object(answer), "shaders", 
shaders);
+               }
        } else if (strcmp(command, "resume-waves") == 0) {
                strcpy(asic->options.ring_name, json_object_get_string(request, 
"ring"));
                umr_sq_cmd_halt_waves(asic, UMR_SQ_CMD_RESUME);
                answer = json_value_init_object();
        } else if (strcmp(command, "ring") == 0) {
                char *ring_name = (char*)json_object_get_string(request, 
"ring");
                uint32_t wptr, rptr, drv_wptr, ringsize, value, *ring_data;
                int halt_waves = json_object_get_boolean(request, "halt_waves");
                enum umr_ring_type rt;
                asic->options.halt_waves = halt_waves;
diff --git a/src/app/gui/waves_panel.cpp b/src/app/gui/waves_panel.cpp
index 7e13b48..68b06ea 100644
--- a/src/app/gui/waves_panel.cpp
+++ b/src/app/gui/waves_panel.cpp
@@ -106,21 +106,38 @@ public:
 
                        JSON_Array *waves_array = 
json_object_get_array(json_object(answer), "waves");
                        int wave_count = json_array_get_count(waves_array);
                        for (int i = 0; i < wave_count; ++i) {
                                JSON_Object *wave = 
json_object(json_value_deep_copy(json_array_get_value(waves_array, i)));
                                waves.emplace_back(get_wave_id(wave), wave);
                        }
 
                        JSON_Object *shaders_dict = 
json_object_get_object(json_object(answer), "shaders");
                        update_shaders(shaders_dict);
+               } else if (strcmp(command, "singlestep") == 0) {
+                       JSON_Object *wave = 
json_object(json_value_deep_copy(json_object_get_value(json_object(answer), 
"wave")));
+                       std::string id = get_wave_id(wave ? wave : request);
+                       size_t i = find_wave_by_id(id);
+                       if (i < waves.size()) {
+                               
json_value_free(json_object_get_wrapping_value(waves[i].wave));
+                               if (wave) {
+                                       waves[i].wave = wave;
+                               } else {
+                                       waves.erase(waves.begin() + i);
+                               }
+                       } else {
+                               if (wave)
+                                       waves.emplace_back(id, wave);
                        }
+
+                       JSON_Object *shaders_dict = 
json_object_get_object(json_object(answer), "shaders");
+                       update_shaders(shaders_dict);
                } else {
                        return; // should be handled by a different panel
                }
        }
 
        bool display(float dt, const ImVec2& avail, bool can_send_request) {
                ImGui::Checkbox("Disable gfxoff", &turn_off_gfxoff);
                ImGui::SameLine();
                ImGui::Checkbox("Halt waves", &halt);
                if (halt) {
@@ -185,20 +202,29 @@ public:
                                        ImGui::Columns(1);
                                        ImGui::Separator();
                                        ImGui::NextColumn();
                                        ImGui::Text("PC: #b589000x%" PRIx64, 
(uint64_t)json_object_get_number(wave, "PC"));
                                        if (shader_address_str) {
                                                ImGui::SameLine();
                                                if (ImGui::Button("View 
Shader")) {
                                                        active_shader_wave = 
waves[i].id;
                                                        force_scroll = true;
                                                }
+                                               if (asic->family >= FAMILY_NV) {
+                                                       ImGui::SameLine();
+                                                       
ImGui::BeginDisabled(!can_send_request);
+                                                       if 
(ImGui::Button("Single step")) {
+                                                               
active_shader_wave = waves[i].id;
+                                                               
send_singlestep_command(waves[i].wave);
+                                                       }
+                                                       ImGui::EndDisabled();
+                                               }
                                        } else {
                                        }
                                        ImGui::NextColumn();
                                        if (ImGui::TreeNodeEx("Status")) {
                                                ImGui::Columns(4);
                                                size_t n = 
json_object_get_count(status);
                                                for (size_t j = 0; j < n; j++) {
                                                        ImGui::Text("%s: 
#b58900%d", json_object_get_name(status, j),
                                                                                
                                 
(unsigned)json_number(json_object_get_value_at(status, j)));
                                                        ImGui::NextColumn();
@@ -436,20 +462,34 @@ public:
 private:
        void send_waves_command(bool halt_waves, bool resume_waves, bool 
disable_gfxoff) {
                JSON_Value *req = json_value_init_object();
                json_object_set_string(json_object(req), "command", "waves");
                json_object_set_boolean(json_object(req), "halt_waves", 
halt_waves);
                json_object_set_boolean(json_object(req), "resume_waves", 
halt_waves && resume_waves);
                json_object_set_boolean(json_object(req), "disable_gfxoff", 
disable_gfxoff);
                json_object_set_string(json_object(req), "ring", asic->family 
>= FAMILY_NV ? "gfx_0.0.0" : "gfx");
                send_request(req);
        }
+
+       void send_singlestep_command(JSON_Object *wave) {
+               assert(asic->family >= FAMILY_NV);
+               JSON_Value *req = json_value_init_object();
+               json_object_set_string(json_object(req), "command", 
"singlestep");
+               json_object_set_string(json_object(req), "ring", asic->family 
>= FAMILY_NV ? "gfx_0.0.0" : "gfx");
+               json_object_set_number(json_object(req), "se", 
json_object_get_number(wave, "se"));
+               json_object_set_number(json_object(req), "sh", 
json_object_get_number(wave, "sh"));
+               json_object_set_number(json_object(req), "wgp", 
json_object_get_number(wave, "wgp"));
+               json_object_set_number(json_object(req), "simd_id", 
json_object_get_number(wave, "simd_id"));
+               json_object_set_number(json_object(req), "wave_id", 
json_object_get_number(wave, "wave_id"));
+               send_request(req);
+       }
+
 private:
        struct Wave {
                std::string id; // "seN.saN.etc"
                JSON_Object *wave;
                bool vgpr_show[512] = {};
                int vgpr_view[512] = {};
 
                Wave(std::string id, JSON_Object *wave) : id(id), wave(wave) {}
        };
 
diff --git a/src/lib/scan_waves.c b/src/lib/scan_waves.c
index ca1d9fb..533c5d0 100644
--- a/src/lib/scan_waves.c
+++ b/src/lib/scan_waves.c
@@ -530,21 +530,21 @@ int umr_parse_wave_data_gfx(struct umr_asic *asic, struct 
umr_wave_status *ws, c
        else
                return umr_parse_wave_data_gfx_10_11(asic, ws, buf);
 }
 
 /**
  * Scan the given wave slot. Return true and fill in \p pwd if a wave is 
present.
  * Otherwise, return false.
  *
  * \param cu the CU on <=gfx9, the WGP on >=gfx10
  */
-static int umr_scan_wave_slot(struct umr_asic *asic, uint32_t se, uint32_t sh, 
uint32_t cu,
+int umr_scan_wave_slot(struct umr_asic *asic, uint32_t se, uint32_t sh, 
uint32_t cu,
                               uint32_t simd, uint32_t wave, struct 
umr_wave_data *pwd)
 {
        unsigned thread, num_threads;
        int r;
 
        if (asic->family <= FAMILY_AI)
                r = asic->wave_funcs.get_wave_status(asic, se, sh, cu, simd, 
wave, &pwd->ws);
        else
                r = asic->wave_funcs.get_wave_status(asic, se, sh, 
MANY_TO_INSTANCE(cu, simd), 0, wave, &pwd->ws);
 
diff --git a/src/umr.h b/src/umr.h
index 8981986..030124f 100644
--- a/src/umr.h
+++ b/src/umr.h
@@ -1392,20 +1392,22 @@ void umr_free_maps(struct umr_asic *asic);
 void umr_close_asic(struct umr_asic *asic); // call this to close a fully open 
asic
 int umr_query_drm(struct umr_asic *asic, int field, void *ret, int size);
 int umr_query_drm_vbios(struct umr_asic *asic, int field, int type, void *ret, 
int size);
 int umr_update(struct umr_asic *asic, char *script);
 int umr_update_string(struct umr_asic *asic, char *sdata);
 
 /* lib helpers */
 uint32_t umr_get_ip_revision(struct umr_asic *asic, const char *ipname);
 int umr_get_wave_status(struct umr_asic *asic, unsigned se, unsigned sh, 
unsigned cu, unsigned simd, unsigned wave, struct umr_wave_status *ws);
 struct umr_wave_data *umr_scan_wave_data(struct umr_asic *asic);
+int umr_scan_wave_slot(struct umr_asic *asic, uint32_t se, uint32_t sh, 
uint32_t cu,
+                      uint32_t simd, uint32_t wave, struct umr_wave_data *pwd);
 int umr_read_wave_status_via_mmio_gfx8_9(struct umr_asic *asic, uint32_t simd, 
uint32_t wave, uint32_t *dst, int *no_fields);
 int umr_read_wave_status_via_mmio_gfx_10_11(struct umr_asic *asic, uint32_t 
wave, uint32_t *dst, int *no_fields);
 int umr_parse_wave_data_gfx(struct umr_asic *asic, struct umr_wave_status *ws, 
const uint32_t *buf);
 int umr_get_wave_sq_info_vi(struct umr_asic *asic, unsigned se, unsigned sh, 
unsigned cu, struct umr_wave_status *ws);
 int umr_get_wave_sq_info(struct umr_asic *asic, unsigned se, unsigned sh, 
unsigned cu, struct umr_wave_status *ws);
 int umr_read_sgprs(struct umr_asic *asic, struct umr_wave_status *ws, uint32_t 
*dst);
 int umr_read_vgprs(struct umr_asic *asic, struct umr_wave_status *ws, uint32_t 
thread, uint32_t *dst);
 int umr_read_sensor(struct umr_asic *asic, int sensor, void *dst, int *size);
 
 /* mmio helpers */
-- 
2.40.0

Reply via email to