| /* |
| * Copyright 2010 Christoph Bumiller |
| * |
| * 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 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 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 "nvc0_pc.h" |
| |
| #define PRINT(args...) debug_printf(args) |
| |
| #ifndef ARRAY_SIZE |
| #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) |
| #endif |
| |
| static const char *norm = "\x1b[00m"; |
| static const char *gree = "\x1b[32m"; |
| static const char *blue = "\x1b[34m"; |
| static const char *cyan = "\x1b[36m"; |
| static const char *yllw = "\x1b[33m"; |
| static const char *mgta = "\x1b[35m"; |
| |
| static const char *nv_cond_names[] = |
| { |
| "never", "lt" , "eq" , "le" , "gt" , "ne" , "ge" , "", |
| "never", "ltu", "equ", "leu", "gtu", "neu", "geu", "", |
| "o", "c", "a", "s" |
| }; |
| |
| static const char *nv_modifier_strings[] = |
| { |
| "", |
| "neg", |
| "abs", |
| "neg abs", |
| "not", |
| "not neg" |
| "not abs", |
| "not neg abs", |
| "sat", |
| "BAD_MOD" |
| }; |
| |
| const char * |
| nvc0_opcode_name(uint opcode) |
| { |
| return nvc0_op_info_table[MIN2(opcode, NV_OP_COUNT)].name; |
| } |
| |
| static INLINE const char * |
| nv_type_name(ubyte type, ubyte size) |
| { |
| switch (type) { |
| case NV_TYPE_U16: return "u16"; |
| case NV_TYPE_S16: return "s16"; |
| case NV_TYPE_F32: return "f32"; |
| case NV_TYPE_U32: return "u32"; |
| case NV_TYPE_S32: return "s32"; |
| case NV_TYPE_P32: return "p32"; |
| case NV_TYPE_F64: return "f64"; |
| case NV_TYPE_ANY: |
| { |
| switch (size) { |
| case 1: return "b8"; |
| case 2: return "b16"; |
| case 4: return "b32"; |
| case 8: return "b64"; |
| case 12: return "b96"; |
| case 16: return "b128"; |
| default: |
| return "BAD_SIZE"; |
| } |
| } |
| default: |
| return "BAD_TYPE"; |
| } |
| } |
| |
| static INLINE const char * |
| nv_cond_name(ubyte cc) |
| { |
| return nv_cond_names[MIN2(cc, 19)]; |
| } |
| |
| static INLINE const char * |
| nv_modifier_string(ubyte mod) |
| { |
| return nv_modifier_strings[MIN2(mod, 9)]; |
| } |
| |
| static INLINE int |
| nv_value_id(struct nv_value *value) |
| { |
| if (value->join->reg.id >= 0) |
| return value->join->reg.id; |
| return value->n; |
| } |
| |
| static INLINE boolean |
| nv_value_allocated(struct nv_value *value) |
| { |
| return (value->reg.id >= 0) ? TRUE : FALSE; |
| } |
| |
| static INLINE void |
| nv_print_address(const char c, int buf, struct nv_value *a, int offset) |
| { |
| const char ac = (a && nv_value_allocated(a)) ? '$' : '%'; |
| char sg; |
| |
| if (offset < 0) { |
| sg = '-'; |
| offset = -offset; |
| } else { |
| sg = '+'; |
| } |
| |
| if (buf >= 0) |
| PRINT(" %s%c%i[", cyan, c, buf); |
| else |
| PRINT(" %s%c[", cyan, c); |
| if (a) |
| PRINT("%s%ca%i%s%c", mgta, ac, nv_value_id(a), cyan, sg); |
| PRINT("%s0x%x%s]", yllw, offset, cyan); |
| } |
| |
| static INLINE void |
| nv_print_value(struct nv_value *value, struct nv_value *indir, ubyte type) |
| { |
| char reg_pfx = nv_value_allocated(value->join) ? '$' : '%'; |
| |
| if (value->reg.file != NV_FILE_PRED) |
| PRINT(" %s%s", gree, nv_type_name(type, value->reg.size)); |
| |
| switch (value->reg.file) { |
| case NV_FILE_GPR: |
| PRINT(" %s%cr%i", blue, reg_pfx, nv_value_id(value)); |
| if (value->reg.size == 8) |
| PRINT("d"); |
| if (value->reg.size == 16) |
| PRINT("q"); |
| break; |
| case NV_FILE_PRED: |
| PRINT(" %s%cp%i", mgta, reg_pfx, nv_value_id(value)); |
| break; |
| case NV_FILE_COND: |
| PRINT(" %s%cc%i", mgta, reg_pfx, nv_value_id(value)); |
| break; |
| case NV_FILE_MEM_L: |
| nv_print_address('l', -1, indir, value->reg.address); |
| break; |
| case NV_FILE_MEM_G: |
| nv_print_address('g', -1, indir, value->reg.address); |
| break; |
| case NV_FILE_MEM_A: |
| nv_print_address('a', -1, indir, value->reg.address); |
| break; |
| case NV_FILE_MEM_V: |
| nv_print_address('v', -1, indir, value->reg.address); |
| break; |
| case NV_FILE_IMM: |
| switch (type) { |
| case NV_TYPE_U16: |
| case NV_TYPE_S16: |
| PRINT(" %s0x%04x", yllw, value->reg.imm.u32); |
| break; |
| case NV_TYPE_F32: |
| PRINT(" %s%f", yllw, value->reg.imm.f32); |
| break; |
| case NV_TYPE_F64: |
| PRINT(" %s%f", yllw, value->reg.imm.f64); |
| break; |
| case NV_TYPE_U32: |
| case NV_TYPE_S32: |
| case NV_TYPE_P32: |
| case NV_TYPE_ANY: |
| PRINT(" %s0x%08x", yllw, value->reg.imm.u32); |
| break; |
| } |
| break; |
| default: |
| if (value->reg.file >= NV_FILE_MEM_C(0) && |
| value->reg.file <= NV_FILE_MEM_C(15)) |
| nv_print_address('c', value->reg.file - NV_FILE_MEM_C(0), indir, |
| value->reg.address); |
| else |
| NOUVEAU_ERR(" BAD_FILE[%i]", nv_value_id(value)); |
| break; |
| } |
| } |
| |
| static INLINE void |
| nv_print_ref(struct nv_ref *ref, struct nv_value *indir, ubyte type) |
| { |
| nv_print_value(ref->value, indir, type); |
| } |
| |
| void |
| nvc0_print_instruction(struct nv_instruction *i) |
| { |
| int s; |
| |
| PRINT("%i: ", i->serial); |
| |
| if (i->predicate >= 0) { |
| PRINT("%s%s", gree, i->cc ? "fl" : "tr"); |
| nv_print_ref(i->src[i->predicate], NULL, NV_TYPE_U8); |
| PRINT(" "); |
| } |
| |
| PRINT("%s", gree); |
| if (NV_BASEOP(i->opcode) == NV_OP_SET) |
| PRINT("set %s", nv_cond_name(i->set_cond)); |
| else |
| if (i->saturate) |
| PRINT("sat %s", nvc0_opcode_name(i->opcode)); |
| else |
| PRINT("%s", nvc0_opcode_name(i->opcode)); |
| |
| if (i->opcode == NV_OP_CVT) |
| nv_print_value(i->def[0], NULL, i->ext.cvt.d); |
| else |
| if (i->def[0]) |
| nv_print_value(i->def[0], NULL, NV_OPTYPE(i->opcode)); |
| else |
| if (i->target) |
| PRINT(" %s(BB:%i)", yllw, i->target->id); |
| else |
| PRINT(" #"); |
| |
| for (s = 1; s < 4 && i->def[s]; ++s) |
| nv_print_value(i->def[s], NULL, NV_OPTYPE(i->opcode)); |
| if (s > 1) |
| PRINT("%s ,", norm); |
| |
| for (s = 0; s < 6 && i->src[s]; ++s) { |
| ubyte type; |
| if (s == i->indirect || s == i->predicate) |
| continue; |
| if (i->opcode == NV_OP_CVT) |
| type = i->ext.cvt.s; |
| else |
| type = NV_OPTYPE(i->opcode); |
| |
| if (i->src[s]->mod) |
| PRINT(" %s%s", gree, nv_modifier_string(i->src[s]->mod)); |
| |
| if (i->indirect >= 0 && |
| NV_IS_MEMORY_FILE(i->src[s]->value->reg.file)) |
| nv_print_ref(i->src[s], i->src[i->indirect]->value, type); |
| else |
| nv_print_ref(i->src[s], NULL, type); |
| } |
| PRINT(" %s\n", norm); |
| } |
| |
| #define NV_MOD_SGN NV_MOD_ABS | NV_MOD_NEG |
| |
| struct nv_op_info nvc0_op_info_table[NV_OP_COUNT + 1] = |
| { |
| { NV_OP_UNDEF, "undef", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 0, 0, 1, 0, 0 }, |
| { NV_OP_BIND, "bind", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 1, 0, 1, 0, 0 }, |
| { NV_OP_MERGE, "merge", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 1, 0, 1, 0, 0 }, |
| { NV_OP_PHI, "phi", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 0, 0, 1, 0, 0 }, |
| { NV_OP_SELECT, "select", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 0, 0, 1, 0, 0 }, |
| { NV_OP_NOP, "nop", NV_TYPE_ANY, 0, /* fcvpoi */ 0, 0, 0, 0, 0, 0, 0 }, |
| |
| { NV_OP_LD, "ld", NV_TYPE_ANY, 0, 0, 0, 0, 0, 0, 0, 0 }, |
| { NV_OP_ST, "st", NV_TYPE_ANY, 0, 0, 0, 0, 0, 0, 0, 0 }, |
| { NV_OP_MOV, "mov", NV_TYPE_ANY, 0, 0, 0, 0, 1, 0, 1, 0 }, |
| { NV_OP_AND, "and", NV_TYPE_U32, NV_MOD_NOT, 0, 1, 0, 1, 0, 1, 0 }, |
| { NV_OP_OR, "or", NV_TYPE_U32, NV_MOD_NOT, 0, 1, 0, 1, 0, 1, 0 }, |
| { NV_OP_XOR, "xor", NV_TYPE_U32, NV_MOD_NOT, 0, 1, 0, 1, 0, 1, 0 }, |
| { NV_OP_SHL, "shl", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 1, 0 }, |
| { NV_OP_SHR, "shr", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 1, 0 }, |
| { NV_OP_NOT, "not", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_SET, "set", NV_TYPE_ANY, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_ADD, "add", NV_TYPE_F32, NV_MOD_SGN, 0, 1, 0, 1, 0, 1, 2 }, |
| { NV_OP_SUB, "sub", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 1, 2 }, |
| { NV_OP_MUL, "mul", NV_TYPE_F32, NV_MOD_SGN, 0, 1, 0, 1, 0, 1, 2 }, |
| { NV_OP_MAD, "mad", NV_TYPE_F32, NV_MOD_SGN, 0, 1, 0, 1, 0, 0, 2 }, |
| { NV_OP_ABS, "abs", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_NEG, "neg", NV_TYPE_F32, NV_MOD_ABS, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_MAX, "max", NV_TYPE_F32, NV_MOD_SGN, 0, 1, 0, 1, 0, 0, 2 }, |
| { NV_OP_MIN, "min", NV_TYPE_F32, NV_MOD_SGN, 0, 1, 0, 1, 0, 0, 2 }, |
| { NV_OP_CVT, "cvt", NV_TYPE_ANY, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_CEIL, "ceil", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_FLOOR, "floor", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_TRUNC, "floor", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_SAD, "sad", NV_TYPE_S32, 0, 0, 1, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_VFETCH, "vfetch", NV_TYPE_ANY, 0, 0, 0, 1, 1, 0, 0, 0 }, |
| { NV_OP_PFETCH, "pfetch", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_EXPORT, "export", NV_TYPE_ANY, 0, 0, 0, 1, 1, 0, 0, 0 }, |
| { NV_OP_LINTERP, "linterp", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_PINTERP, "pinterp", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_EMIT, "emit", NV_TYPE_ANY, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_RESTART, "restart", NV_TYPE_ANY, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_TEX, "tex", NV_TYPE_F32, 0, 0, 0, 1, 1, 0, 0, 0 }, |
| { NV_OP_TXB, "texbias", NV_TYPE_F32, 0, 0, 0, 1, 1, 0, 0, 0 }, |
| { NV_OP_TXL, "texlod", NV_TYPE_F32, 0, 0, 0, 1, 1, 0, 0, 0 }, |
| { NV_OP_TXF, "texfetch", NV_TYPE_U32, 0, 0, 0, 1, 1, 0, 0, 0 }, |
| { NV_OP_TXQ, "texquery", NV_TYPE_U32, 0, 0, 0, 1, 1, 0, 0, 0 }, |
| |
| { NV_OP_QUADOP, "quadop", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_DFDX, "dfdx", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_DFDY, "dfdy", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_KIL, "kil", NV_TYPE_ANY, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_BRA, "bra", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_CALL, "call", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_RET, "ret", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_RET, "exit", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_NOP, "ud", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_NOP, "ud", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_JOINAT, "joinat", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_JOIN, "join", NV_TYPE_ANY, 0, 1, 0, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_ADD, "add", NV_TYPE_S32, 0, 0, 1, 0, 1, 0, 1, 0 }, |
| { NV_OP_MUL, "mul", NV_TYPE_S32, 0, 0, 1, 0, 1, 0, 1, 0 }, |
| { NV_OP_ABS, "abs", NV_TYPE_S32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_NEG, "neg", NV_TYPE_S32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_MAX, "max", NV_TYPE_S32, 0, 0, 1, 0, 1, 0, 0, 0 }, |
| { NV_OP_MIN, "max", NV_TYPE_U32, 0, 0, 1, 0, 1, 0, 0, 0 }, |
| { NV_OP_MAX, "min", NV_TYPE_S32, 0, 0, 1, 0, 1, 0, 0, 0 }, |
| { NV_OP_MIN, "min", NV_TYPE_U32, 0, 0, 1, 0, 1, 0, 0, 0 }, |
| { NV_OP_SET, "set", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 2 }, |
| { NV_OP_SET, "set", NV_TYPE_S32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_SET, "set", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_SHR, "sar", NV_TYPE_S32, 0, 0, 0, 0, 1, 0, 1, 0 }, |
| { NV_OP_RCP, "rcp", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 0, 0, 0, 0 }, |
| { NV_OP_RSQ, "rsqrt", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 0, 0, 0, 0 }, |
| { NV_OP_LG2, "lg2", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 0, 0, 0, 0 }, |
| { NV_OP_SIN, "sin", NV_TYPE_F32, 0, 0, 0, 0, 0, 0, 0, 0 }, |
| { NV_OP_COS, "cos", NV_TYPE_F32, 0, 0, 0, 0, 0, 0, 0, 0 }, |
| { NV_OP_EX2, "ex2", NV_TYPE_F32, 0, 0, 0, 0, 0, 0, 0, 0 }, |
| { NV_OP_PRESIN, "presin", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 0, 0, 0, 0 }, |
| { NV_OP_PREEX2, "preex2", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 0, 0, 0, 0 }, |
| { NV_OP_SAT, "sat", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_SET_F32_AND, "and set", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_SET_F32_OR, "or set", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_SET_F32_XOR, "xor set", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_SELP, "selp", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_SLCT_F32, "slct", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_SLCT_F32, "slct", NV_TYPE_S32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| { NV_OP_SLCT_F32, "slct", NV_TYPE_U32, 0, 0, 0, 0, 1, 0, 0, 0 }, |
| |
| { NV_OP_ADD, "sub", NV_TYPE_F32, 0, 0, 0, 0, 1, 0, 1, 0 }, |
| |
| { NV_OP_FSET_F32, "fset", NV_TYPE_F32, NV_MOD_SGN, 0, 0, 0, 1, 0, 0, 2 }, |
| |
| { NV_OP_UNDEF, "BAD_OP", NV_TYPE_ANY, 0, 0, 0, 0, 0, 0, 0, 0 } |
| }; |