diff --git a/src/freedreno/afuc/asm.c b/src/freedreno/afuc/asm.c index c90a91ef38a..b95c64802ba 100644 --- a/src/freedreno/afuc/asm.c +++ b/src/freedreno/afuc/asm.c @@ -37,16 +37,10 @@ #include "afuc.h" #include "asm.h" #include "parser.h" -#include "rnn.h" -#include "rnndec.h" +#include "util.h" int gpuver; -static struct rnndeccontext *ctx; -static struct rnndb *db; -static struct rnndomain *control_regs; -struct rnndomain *dom[2]; - /* bit lame to hard-code max but fw sizes are small */ static struct asm_instruction instructions[0x2000]; static unsigned num_instructions; @@ -329,52 +323,22 @@ emit_instructions(int outfd) } } -static int -find_enum_val(struct rnnenum *en, const char *name) -{ - int i; - - for (i = 0; i < en->valsnum; i++) - if (en->vals[i]->valvalid && !strcmp(name, en->vals[i]->name)) - return en->vals[i]->value; - - return -1; -} - -static int -find_reg(struct rnndomain *dom, const char *name) -{ - int i; - - for (i = 0; i < dom->subelemsnum; i++) - if (!strcmp(name, dom->subelems[i]->name)) - return dom->subelems[i]->offset; - - return -1; -} - unsigned parse_control_reg(const char *name) { /* skip leading "@" */ - int val = find_reg(control_regs, name + 1); - if (val < 0) { - printf("invalid control reg: %s\n", name); - exit(2); - } - return (unsigned)val; + return afuc_control_reg(name + 1); } static void emit_jumptable(int outfd) { - struct rnnenum *en = rnn_findenum(ctx->db, "adreno_pm4_type3_packets"); uint32_t jmptable[0x80] = {0}; int i; for (i = 0; i < num_labels; i++) { struct asm_label *label = &labels[i]; - int id = find_enum_val(en, label->label); + int id = afuc_pm4_id(label->label); /* if it doesn't match a known PM4 packet-id, try to match UNKN%d: */ if (id < 0) { @@ -403,7 +367,7 @@ int main(int argc, char **argv) { FILE *in; - char *file, *outfile, *name, *control_reg_name; + char *file, *outfile; int c, ret, outfd; /* Argument parsing: */ @@ -448,33 +412,11 @@ main(int argc, char **argv) } } - switch (gpuver) { - case 6: - name = "A6XX"; - control_reg_name = "A6XX_CONTROL_REG"; - break; - case 5: - name = "A5XX"; - control_reg_name = "A5XX_CONTROL_REG"; - break; - default: - fprintf(stderr, "unknown GPU version!\n"); + ret = afuc_util_init(gpuver, false); + if (ret < 0) { usage(); } - rnn_init(); - db = rnn_newdb(); - - ctx = rnndec_newcontext(db); - - rnn_parsefile(db, "adreno.xml"); - rnn_prepdb(db); - if (db->estatus) - errx(db->estatus, "failed to parse register database"); - dom[0] = rnn_finddomain(db, name); - dom[1] = rnn_finddomain(db, "AXXX"); - control_regs = rnn_finddomain(db, control_reg_name); - ret = yyparse(); if (ret) { fprintf(stderr, "parse failed: %d\n", ret); diff --git a/src/freedreno/afuc/disasm.c b/src/freedreno/afuc/disasm.c index cefb60222a4..cd5de77e236 100644 --- a/src/freedreno/afuc/disasm.c +++ b/src/freedreno/afuc/disasm.c @@ -38,17 +38,10 @@ #include "freedreno_pm4.h" #include "afuc.h" -#include "rnn.h" -#include "rnndec.h" +#include "util.h" static int gpuver; -static struct rnndeccontext *ctx; -static struct rnndb *db; -static struct rnndomain *control_regs; -struct rnndomain *dom[2]; -const char *variant; - /* non-verbose mode should output something suitable to feed back into * assembler.. verbose mode has additional output useful for debugging * (like unexpected bits that are set) @@ -58,40 +51,18 @@ static bool verbose = false; static void print_gpu_reg(uint32_t regbase) { - struct rnndomain *d = NULL; - if (regbase < 0x100) return; - if (rnndec_checkaddr(ctx, dom[0], regbase, 0)) - d = dom[0]; - else if (rnndec_checkaddr(ctx, dom[1], regbase, 0)) - d = dom[1]; - - if (d) { - struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, d, regbase, 0); - if (info) { - printf("\t; %s", info->name); - free(info->name); - free(info); - return; - } + char *name = afuc_gpu_reg_name(regbase); + if (name) { + printf("\t; %s", name); + free(name); } } -static void -printc(const char *c, const char *fmt, ...) -{ - va_list args; - printf("%s", c); - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); - printf("%s", ctx->colors->reset); -} - -#define printerr(fmt, ...) printc(ctx->colors->err, fmt, ##__VA_ARGS__) -#define printlbl(fmt, ...) printc(ctx->colors->btarg, fmt, ##__VA_ARGS__) +#define printerr(fmt, ...) afuc_printc(AFUC_ERR, fmt, ##__VA_ARGS__) +#define printlbl(fmt, ...) afuc_printc(AFUC_LBL, fmt, ##__VA_ARGS__) static void print_reg(unsigned reg) @@ -170,7 +141,7 @@ print_alu_name(afuc_opc opc, uint32_t instr) static const char * getpm4(uint32_t id) { - return rnndec_decode_enum(ctx, "adreno_pm4_type3_packets", id); + return afuc_pm_id_name(id); } static struct { @@ -290,11 +261,10 @@ fxn_name(uint32_t offset) static void print_control_reg(uint32_t id) { - if (rnndec_checkaddr(ctx, control_regs, id, 0)) { - struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, control_regs, id, 0); - printf("@%s", info->name); - free(info->name); - free(info); + char *name = afuc_control_reg_name(id); + if (name) { + printf("@%s", name); + free(name); } else { printf("0x%03x", id); } @@ -794,10 +764,10 @@ int main(int argc, char **argv) { uint32_t *buf; - char *file, *control_reg_name; + char *file; bool colors = false; size_t sz; - int c; + int c, ret; /* Argument parsing: */ while ((c = getopt(argc, argv, "g:vc")) != -1) { @@ -832,37 +802,12 @@ main(int argc, char **argv) } } - switch (gpuver) { - case 6: - printf("; a6xx microcode\n"); - variant = "A6XX"; - control_reg_name = "A6XX_CONTROL_REG"; - break; - case 5: - printf("; a5xx microcode\n"); - variant = "A5XX"; - control_reg_name = "A5XX_CONTROL_REG"; - break; - default: - fprintf(stderr, "unknown GPU version!\n"); + ret = afuc_util_init(gpuver, colors); + if (ret < 0) { usage(); } - rnn_init(); - db = rnn_newdb(); - - ctx = rnndec_newcontext(db); - ctx->colors = colors ? &envy_def_colors : &envy_null_colors; - - rnn_parsefile(db, "adreno.xml"); - rnn_prepdb(db); - if (db->estatus) - errx(db->estatus, "failed to parse register database"); - dom[0] = rnn_finddomain(db, variant); - dom[1] = rnn_finddomain(db, "AXXX"); - control_regs = rnn_finddomain(db, control_reg_name); - - rnndec_varadd(ctx, "chip", variant); + printf("; a%dxx microcode\n", gpuver); buf = (uint32_t *)os_read_file(file, &sz); diff --git a/src/freedreno/afuc/meson.build b/src/freedreno/afuc/meson.build index 54c19b3d83c..43c6153fde8 100644 --- a/src/freedreno/afuc/meson.build +++ b/src/freedreno/afuc/meson.build @@ -40,6 +40,8 @@ asm = executable( 'afuc-asm', [ 'asm.c', + 'util.c', + 'util.h', afuc_lexer, afuc_parser, ], @@ -56,7 +58,11 @@ asm = executable( disasm = executable( 'afuc-disasm', - 'disasm.c', + [ + 'disasm.c', + 'util.c', + 'util.h', + ], include_directories: [ inc_freedreno, inc_freedreno_rnn, diff --git a/src/freedreno/afuc/util.c b/src/freedreno/afuc/util.c new file mode 100644 index 00000000000..b48cc7a3087 --- /dev/null +++ b/src/freedreno/afuc/util.c @@ -0,0 +1,210 @@ +/* + * Copyright © 2021 Google, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include + +#include "rnn.h" +#include "rnndec.h" + +#include "util.h" + +static struct rnndeccontext *ctx; +static struct rnndb *db; +static struct rnndomain *control_regs; +struct rnndomain *dom[2]; +static struct rnnenum *pm4_packets; + +static int +find_reg(struct rnndomain *dom, const char *name) +{ + for (int i = 0; i < dom->subelemsnum; i++) + if (!strcmp(name, dom->subelems[i]->name)) + return dom->subelems[i]->offset; + + return -1; +} + +/** + * Map control reg name to offset. + */ +unsigned +afuc_control_reg(const char *name) +{ + int val = find_reg(control_regs, name); + if (val < 0) { + char *endptr = NULL; + val = strtol(name, &endptr, 0); + if (endptr) { + printf("invalid control reg: %s\n", name); + exit(2); + } + } + return (unsigned)val; +} + +/** + * Map offset to control reg name (or NULL), caller frees + */ +char * +afuc_control_reg_name(unsigned id) +{ + if (rnndec_checkaddr(ctx, control_regs, id, 0)) { + struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, control_regs, id, 0); + char *name = info->name; + free(info); + return name; + } else { + return NULL; + } +} + +/** + * Map GPU reg name to offset. + */ +unsigned +afuc_gpu_reg(const char *name) +{ + int val = find_reg(dom[0], name); + if (val < 0) + val = find_reg(dom[1], name); + if (val < 0) { + char *endptr = NULL; + val = strtol(name, &endptr, 0); + if (endptr) { + printf("invalid control reg: %s\n", name); + exit(2); + } + } + return (unsigned)val; +} + +/** + * Map offset to gpu reg name (or NULL), caller frees + */ +char * +afuc_gpu_reg_name(unsigned id) +{ + struct rnndomain *d = NULL; + + if (rnndec_checkaddr(ctx, dom[0], id, 0)) { + d = dom[0]; + } else if (rnndec_checkaddr(ctx, dom[1], id, 0)) { + d = dom[1]; + } + + if (d) { + struct rnndecaddrinfo *info = rnndec_decodeaddr(ctx, d, id, 0); + if (info) { + char *name = info->name; + free(info); + return name; + } + } + + return NULL; +} + +static int +find_enum_val(struct rnnenum *en, const char *name) +{ + int i; + + for (i = 0; i < en->valsnum; i++) + if (en->vals[i]->valvalid && !strcmp(name, en->vals[i]->name)) + return en->vals[i]->value; + + return -1; +} + +/** + * Map pm4 packet name to id + */ +int +afuc_pm4_id(const char *name) +{ + return find_enum_val(pm4_packets, name); +} + +const char * +afuc_pm_id_name(unsigned id) +{ + return rnndec_decode_enum(ctx, "adreno_pm4_type3_packets", id); +} + +void +afuc_printc(enum afuc_color c, const char *fmt, ...) +{ + va_list args; + if (c == AFUC_ERR) { + printf("%s", ctx->colors->err); + } else if (c == AFUC_LBL) { + printf("%s", ctx->colors->btarg); + } + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + printf("%s", ctx->colors->reset); +} + +int afuc_util_init(int gpuver, bool colors) +{ + char *name, *control_reg_name; + + switch (gpuver) { + case 6: + name = "A6XX"; + control_reg_name = "A6XX_CONTROL_REG"; + break; + case 5: + name = "A5XX"; + control_reg_name = "A5XX_CONTROL_REG"; + break; + default: + fprintf(stderr, "unknown GPU version!\n"); + return -1; + } + + rnn_init(); + db = rnn_newdb(); + + ctx = rnndec_newcontext(db); + ctx->colors = colors ? &envy_def_colors : &envy_null_colors; + + rnn_parsefile(db, "adreno.xml"); + rnn_prepdb(db); + if (db->estatus) + errx(db->estatus, "failed to parse register database"); + dom[0] = rnn_finddomain(db, name); + dom[1] = rnn_finddomain(db, "AXXX"); + control_regs = rnn_finddomain(db, control_reg_name); + + rnndec_varadd(ctx, "chip", name); + + pm4_packets = rnn_findenum(ctx->db, "adreno_pm4_type3_packets"); + + return 0; +} + diff --git a/src/freedreno/afuc/util.h b/src/freedreno/afuc/util.h new file mode 100644 index 00000000000..436bf63f435 --- /dev/null +++ b/src/freedreno/afuc/util.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2021 Google, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _UTIL_H_ +#define _UTIL_H_ + +#include + +/* + * AFUC disasm / asm helpers + */ + +unsigned afuc_control_reg(const char *name); +char * afuc_control_reg_name(unsigned id); + +unsigned afuc_gpu_reg(const char *name); +char * afuc_gpu_reg_name(unsigned id); + +int afuc_pm4_id(const char *name); +const char * afuc_pm_id_name(unsigned id); + +enum afuc_color { + AFUC_ERR, + AFUC_LBL, +}; + +void afuc_printc(enum afuc_color c, const char *fmt, ...); + +int afuc_util_init(int gpuver, bool colors); + +#endif /* _UTIL_H_ */