blob: 9eac5ad900ad722d02805a0f4348c84ac7c4b729 [file] [log] [blame]
/*
* 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 }
};