void
disassembleCfALUInstruction(fmt::MemoryWriter &out,
                            const ControlFlowInst &inst)
{
   auto name = getInstructionName(inst.alu.word1.CF_INST());
   auto addr = inst.alu.word0.ADDR();
   auto count = inst.alu.word1.COUNT() + 1;

   out
      << name
      << " ADDR(" << addr << ")"
      << " CNT(" << count << ")";


   if (!inst.word1.BARRIER()) {
      out << " NO_BARRIER";
   }

   if (inst.word1.WHOLE_QUAD_MODE()) {
      out << " WHOLE_QUAD";
   }

   disassembleKcache(out, 0, inst.alu.word0.KCACHE_MODE0(), inst.alu.word0.KCACHE_BANK0(), inst.alu.word1.KCACHE_ADDR0());
   disassembleKcache(out, 1, inst.alu.word1.KCACHE_MODE1(), inst.alu.word0.KCACHE_BANK1(), inst.alu.word1.KCACHE_ADDR1());
}
Example #2
0
static void
insertPush(Shader &shader, uint32_t cfPC)
{
   auto push = new shadir::CfInstruction {};
   push->cfPC = cfPC;
   push->id = SQ_CF_INST_PUSH;
   push->name = getInstructionName(push->id);
   shader.linear.push_back(push);
   shader.custom.emplace_back(push);
}
Example #3
0
static void
insertElse(Shader &shader, uint32_t cfPC)
{
   auto elseIns = new shadir::CfInstruction {};
   elseIns->cfPC = cfPC;
   elseIns->id = SQ_CF_INST_ELSE;
   elseIns->name = getInstructionName(elseIns->id);
   elseIns->popCount = 1;
   shader.linear.push_back(elseIns);
   shader.custom.emplace_back(elseIns);
}
Example #4
0
static void
insertContinue(Shader &shader, uint32_t cfPC)
{
   auto loopContinue = new shadir::CfInstruction {};
   loopContinue->cfPC = cfPC;
   loopContinue->id = SQ_CF_INST_LOOP_CONTINUE;
   loopContinue->name = getInstructionName(loopContinue->id);
   loopContinue->popCount = 1;
   shader.linear.push_back(loopContinue);
   shader.custom.emplace_back(loopContinue);
}
Example #5
0
static void
insertBreak(Shader &shader, uint32_t cfPC)
{
   auto loopBreak = new shadir::CfInstruction {};
   loopBreak->cfPC = cfPC;
   loopBreak->id = SQ_CF_INST_LOOP_BREAK;
   loopBreak->name = getInstructionName(loopBreak->id);
   loopBreak->popCount = 1;
   shader.linear.push_back(loopBreak);
   shader.custom.emplace_back(loopBreak);
}
Example #6
0
static void
insertPop(Shader &shader, uint32_t cfPC)
{
   auto pop = new shadir::CfInstruction {};
   pop->cfPC = cfPC;
   pop->id = SQ_CF_INST_PUSH;
   pop->name = getInstructionName(pop->id);
   pop->popCount = 1;
   shader.linear.push_back(pop);
   shader.custom.emplace_back(pop);
}
static void
disassembleNormal(State &state, const ControlFlowInst &inst)
{
   auto id = inst.word1.CF_INST();
   auto name = getInstructionName(id);

   switch (id) {
   case SQ_CF_INST_WAIT_ACK:
   case SQ_CF_INST_TEX_ACK:
   case SQ_CF_INST_VTX_ACK:
   case SQ_CF_INST_VTX_TC_ACK:
      decaf_abort(fmt::format("Unable to decode instruction {} {}", id, name));
   }

   // Decode instruction clause
   state.out.write("{}{:02} ", state.indent, state.cfPC);
   disassembleCF(state.out, inst);
   state.out << "\n";

   switch (id) {
   case SQ_CF_INST_LOOP_START:
   case SQ_CF_INST_LOOP_START_DX10:
   case SQ_CF_INST_LOOP_START_NO_AL:
      increaseIndent(state);
      break;
   case SQ_CF_INST_LOOP_END:
      decreaseIndent(state);
      break;
   case SQ_CF_INST_TEX:
      disassembleTEXClause(state, inst);
      break;
   case SQ_CF_INST_VTX:
   case SQ_CF_INST_VTX_TC:
      disassembleVtxClause(state, inst);
      break;
   }
}
void
disassembleCF(fmt::MemoryWriter &out, const ControlFlowInst &inst)
{
   auto id = inst.word1.CF_INST();
   auto name = getInstructionName(id);
   out << name;

   switch (id) {
   case SQ_CF_INST_TEX:
      disassembleCfTEX(out, inst);
      break;
   case SQ_CF_INST_VTX:
   case SQ_CF_INST_VTX_TC:
      disassembleCfVTX(out, inst);
      break;
   case SQ_CF_INST_LOOP_START:
   case SQ_CF_INST_LOOP_START_DX10:
   case SQ_CF_INST_LOOP_START_NO_AL:
   case SQ_CF_INST_LOOP_END:
   case SQ_CF_INST_LOOP_CONTINUE:
   case SQ_CF_INST_LOOP_BREAK:
      disassembleLoop(out, inst);
      break;
   case SQ_CF_INST_JUMP:
   case SQ_CF_INST_ELSE:
   case SQ_CF_INST_CALL:
   case SQ_CF_INST_CALL_FS:
   case SQ_CF_INST_RETURN:
   case SQ_CF_INST_POP_JUMP:
      disassembleJump(out, inst);
      break;
   case SQ_CF_INST_EMIT_VERTEX:
   case SQ_CF_INST_EMIT_CUT_VERTEX:
   case SQ_CF_INST_CUT_VERTEX:
      if (!inst.word1.BARRIER()) {
         out << " NO_BARRIER";
      }
      break;
   case SQ_CF_INST_PUSH:
   case SQ_CF_INST_PUSH_ELSE:
   case SQ_CF_INST_KILL:
      disassembleCondition(out, inst);
      // switch case pass through
   case SQ_CF_INST_POP:
   case SQ_CF_INST_POP_PUSH:
   case SQ_CF_INST_POP_PUSH_ELSE:
      if (inst.word1.POP_COUNT()) {
         out << " POP_COUNT(" << inst.word1.POP_COUNT() << ")";
      }

      if (inst.word1.VALID_PIXEL_MODE()) {
         out << " VALID_PIX";
      }
      break;
   case SQ_CF_INST_END_PROGRAM:
   case SQ_CF_INST_NOP:
      break;
   case SQ_CF_INST_WAIT_ACK:
   case SQ_CF_INST_TEX_ACK:
   case SQ_CF_INST_VTX_ACK:
   case SQ_CF_INST_VTX_TC_ACK:
   default:
      out << " UNK_FORMAT";
      break;
   }
}
void
disassembleAluInstruction(fmt::MemoryWriter &out,
                          const ControlFlowInst &parent,
                          const AluInst &inst,
                          size_t groupPC,
                          SQ_CHAN unit,
                          const gsl::span<const uint32_t> &literals,
                          int namePad)
{
   const char *name = nullptr;
   SQ_ALU_FLAGS flags;
   auto srcCount = 0u;

   if (inst.word1.ENCODING() == SQ_ALU_ENCODING::OP2) {
      name = getInstructionName(inst.op2.ALU_INST());
      flags = getInstructionFlags(inst.op2.ALU_INST());
      srcCount = getInstructionNumSrcs(inst.op2.ALU_INST());
   } else {
      name = getInstructionName(inst.op3.ALU_INST());
      flags = getInstructionFlags(inst.op3.ALU_INST());
      srcCount = getInstructionNumSrcs(inst.op3.ALU_INST());
   }

   out << fmt::pad(name, namePad, ' ') << ' ';

   auto writeMask = true;

   if (inst.word1.ENCODING() == SQ_ALU_ENCODING::OP2) {
      writeMask = inst.op2.WRITE_MASK();
   }

   if (!writeMask) {
      out << "____";
   } else {
      disassembleAluSource(out,
                           parent,
                           groupPC,
                           inst.word0.INDEX_MODE(),
                           inst.word1.DST_GPR(),
                           inst.word1.DST_REL(),
                           inst.word1.DST_CHAN(),
                           0,
                           false,
                           false);
   }

   if (srcCount > 0) {
      auto literal = 0u;
      auto abs = false;

      if (inst.word0.SRC0_SEL() == SQ_ALU_SRC::LITERAL) {
         literal = literals[inst.word0.SRC0_CHAN()];
      }

      if (inst.word1.ENCODING() == SQ_ALU_ENCODING::OP2) {
         abs = !!inst.op2.SRC0_ABS();
      }

      out << ", ";
      disassembleAluSource(out,
                           parent,
                           groupPC,
                           inst.word0.INDEX_MODE(),
                           inst.word0.SRC0_SEL(),
                           inst.word0.SRC0_REL(),
                           inst.word0.SRC0_CHAN(),
                           literal,
                           inst.word0.SRC0_NEG(),
                           abs);
   }

   if (srcCount > 1) {
      auto literal = 0u;
      auto abs = false;

      if (inst.word0.SRC1_SEL() == SQ_ALU_SRC::LITERAL) {
         literal = literals[inst.word0.SRC1_CHAN()];
      }

      if (inst.word1.ENCODING() == SQ_ALU_ENCODING::OP2) {
         abs = !!inst.op2.SRC1_ABS();
      }

      out << ", ";
      disassembleAluSource(out,
                           parent,
                           groupPC,
                           inst.word0.INDEX_MODE(),
                           inst.word0.SRC1_SEL(),
                           inst.word0.SRC1_REL(),
                           inst.word0.SRC1_CHAN(),
                           literal,
                           inst.word0.SRC1_NEG(),
                           abs);
   }

   if (srcCount > 2) {
      auto literal = 0u;

      if (inst.op3.SRC2_SEL() == SQ_ALU_SRC::LITERAL) {
         literal = literals[inst.op3.SRC2_CHAN()];
      }

      out << ", ";
      disassembleAluSource(out,
                           parent,
                           groupPC,
                           inst.word0.INDEX_MODE(),
                           inst.op3.SRC2_SEL(),
                           inst.op3.SRC2_REL(),
                           inst.op3.SRC2_CHAN(),
                           literal,
                           inst.op3.SRC2_NEG(),
                           false);
   }

   if (inst.word1.CLAMP()) {
      out << " CLAMP";
   }

   if (isTranscendentalOnly(flags)) {
      switch (static_cast<SQ_ALU_SCL_BANK_SWIZZLE>(inst.word1.BANK_SWIZZLE())) {
      case SQ_ALU_SCL_BANK_SWIZZLE::SCL_210:
         out << " SCL_210";
         break;
      case SQ_ALU_SCL_BANK_SWIZZLE::SCL_122:
         out << " SCL_122";
         break;
      case SQ_ALU_SCL_BANK_SWIZZLE::SCL_212:
         out << " SCL_212";
         break;
      case SQ_ALU_SCL_BANK_SWIZZLE::SCL_221:
         out << " SCL_221";
         break;
      default:
         decaf_abort(fmt::format("Unexpected BANK_SWIZZLE {}", inst.word1.BANK_SWIZZLE()));
      }
   } else {
      switch (inst.word1.BANK_SWIZZLE()) {
      case SQ_ALU_VEC_BANK_SWIZZLE::VEC_012:
         // This is default, no need to print
         break;
      case SQ_ALU_VEC_BANK_SWIZZLE::VEC_021:
         out << " VEC_021";
         break;
      case SQ_ALU_VEC_BANK_SWIZZLE::VEC_120:
         out << " VEC_120";
         break;
      case SQ_ALU_VEC_BANK_SWIZZLE::VEC_102:
         out << " VEC_102";
         break;
      case SQ_ALU_VEC_BANK_SWIZZLE::VEC_201:
         out << " VEC_201";
         break;
      case SQ_ALU_VEC_BANK_SWIZZLE::VEC_210:
         out << " VEC_210";
         break;
      default:
         decaf_abort(fmt::format("Unexpected BANK_SWIZZLE {}", inst.word1.BANK_SWIZZLE()));
      }
   }

   switch (inst.word0.PRED_SEL()) {
   case SQ_PRED_SEL::OFF:
      break;
   case SQ_PRED_SEL::ZERO:
      out << " PRED_SEL_ZERO";
      break;
   case SQ_PRED_SEL::ONE:
      out << " PRED_SEL_ONE";
      break;
   default:
      decaf_abort(fmt::format("Unexpected PRED_SEL {}", inst.word0.PRED_SEL()));
   }

   if (inst.word1.ENCODING() == SQ_ALU_ENCODING::OP2) {
      if (inst.op2.UPDATE_EXECUTE_MASK()) {
         out << " UPDATE_EXECUTE_MASK";

         switch (inst.op2.EXECUTE_MASK_OP()) {
         case SQ_ALU_EXECUTE_MASK_OP::DEACTIVATE:
            out << " DEACTIVATE";
            break;
         case SQ_ALU_EXECUTE_MASK_OP::BREAK:
            out << " BREAK";
            break;
         case SQ_ALU_EXECUTE_MASK_OP::CONTINUE:
            out << " CONTINUE";
            break;
         case SQ_ALU_EXECUTE_MASK_OP::KILL:
            out << " KILL";
            break;
         default:
            decaf_abort(fmt::format("Unexpected EXECUTE_MASK_OP {}", inst.op2.EXECUTE_MASK_OP()));
         }
      } else {
         switch (inst.op2.OMOD()) {
         case SQ_ALU_OMOD::OFF:
            break;
         case SQ_ALU_OMOD::D2:
            out << " OMOD_D2";
            break;
         case SQ_ALU_OMOD::M2:
            out << " OMOD_M2";
            break;
         case SQ_ALU_OMOD::M4:
            out << " OMOD_M4";
            break;
         default:
            decaf_abort(fmt::format("Unexpected OMOD {}", inst.op2.OMOD()));
         }
      }

      if (inst.op2.UPDATE_PRED()) {
         out << " UPDATE_PRED";
      }
   }
}
Example #10
0
void pcode(Tinstruction inst[], int stack[], FILE *output){
	int base = 1;				// Points to the base address in the stack for the current invocation of a given procedure
    int top = 0; 				// Points to the current top of the stack
    int counter = 0;  			// Points to an instruction in the program area
	
	int aux;
	int stop = 0;
	
	do{
    	Tinstruction instruction = inst[counter];
    	counter++;
    	switch (instruction.operation){
    		case LIT:
    			top++;
    			stack[top] = instruction.argument;
    			break;
    		case OPR:
    			switch(instruction.argument){
    				case RTN:
    					top = base - 1;
    					counter = stack[top+3];
    					base = stack[top+2];
    					break;
    				case NEG:
    					stack[top]= -1*stack[top];
    					break;
    				case ADD:
    					top--;
    					stack[top] += stack[top+1];
    					break;
    				case SUB:
    					top--;
    					stack[top] -= stack[top+1];
    					break;
    				case MUL:
    					top--;
    					stack[top] *= stack[top+1];
    					break;
    				case DIV:
    					top--;
    					stack[top] /= stack[top+1];
    					break;
    				case MOD:
    					top--;
    					stack[top] %= stack[top+1]; 
    					break;
    				case ODD:
    					stack[top] = (stack[top]%2 == 1);
    					break;
    				case EQL:
    					top--;
    					stack[top] = (stack[top] == stack[top+1]);
    					break;
    				case NEQ:
    					top--;
    					stack[top] = (stack[top] != stack[top+1]);
    					break;
    				case LSS:
    					top--;
    					stack[top] = (stack[top] < stack[top+1]);
    					break;
    				case LEQ:
    					top--;
    					stack[top] = (stack[top] <= stack[top+1]);
    					break;
    				case GTR:
    					top--;
    					stack[top] = (stack[top] > stack[top+1]);
    					break;
    				case GEQ:
    					top--;
    					stack[top] = (stack[top] >= stack[top+1]);
    					break;
    				default:
    					printf("Unknown OPR subfunction");
    					break;
    				}
    			break;
    		case LOD:
    			top++;
    			stack[top] = stack[ getBase(instruction.level, base, stack) + instruction.argument ];
    			stack[ getBase(instruction.level, base, stack) + instruction.argument ] = -10;
    			break;
    		case STO:
    			stack[ getBase(instruction.level, base, stack) + instruction.argument ] = stack[top];
    			top--;
    			break;
    		case CAL:
    			stack[top+1] = getBase(instruction.level, base, stack);
    			stack[top+2] = base;
    			stack[top+3] = counter;
    			base = top+1;
    			counter = instruction.argument;
    			break;
    		case INT:
    			top += instruction.argument;
    			break;
    		case JMP:
    			counter = instruction.argument-1;
    			break;
    		case JPC:
    			if (stack[top] == 0){
    				counter = instruction.argument-1;
    			}
    			top--;	
    			break;
    		default:
    			printf("Unknown function");
    	}
    		
    	// PrintStackTrace
    	fprintf(output,"%-10s %-7d %-7d %-7d %-7d %-15d", getInstructionName(instruction.operation),instruction.level, instruction.argument, top, counter, base);
    
    	for (aux = base; aux<top+1 && top > 0;aux++){
    		if(stack[aux] == -10){
    			fprintf(output,"_ ");	
    		}else{
    			fprintf(output,"%d ", stack[aux]);
    		}
    	}
    	fprintf(output,"\n");
    	
    	// If RTN, stop
    	stop = (instruction.operation == 1 && instruction.argument == 0);
	}while(stop == 0);
}
void
disassembleVtxInstruction(fmt::MemoryWriter &out,
                          const latte::ControlFlowInst &parent,
                          const VertexFetchInst &vtx,
                          int namePad)
{
   auto id = vtx.word0.VTX_INST();
   auto name = getInstructionName(id);

   out << fmt::pad(name, namePad, ' ') << ' ';

   // dst
   auto dstSelX = vtx.word1.DST_SEL_X();
   auto dstSelY = vtx.word1.DST_SEL_Y();
   auto dstSelZ = vtx.word1.DST_SEL_Z();
   auto dstSelW = vtx.word1.DST_SEL_W();

   if (dstSelX != latte::SQ_SEL::SEL_MASK || dstSelY != latte::SQ_SEL::SEL_MASK || dstSelZ != latte::SQ_SEL::SEL_MASK || dstSelW != latte::SQ_SEL::SEL_MASK) {
      if (id == SQ_VTX_INST_SEMANTIC) {
         out << "SEM[" << vtx.sem.SEMANTIC_ID() << "]";
      } else {
         out << "R" << vtx.gpr.DST_GPR();

         if (vtx.gpr.DST_REL() == SQ_REL::REL) {
            out << "[AL]";
         }
      }

      out
         << '.'
         << disassembleDestMask(dstSelX)
         << disassembleDestMask(dstSelY)
         << disassembleDestMask(dstSelZ)
         << disassembleDestMask(dstSelW);
   } else {
      out << "____";
   }


   // src
   out << ", R" << vtx.word0.SRC_GPR();

   if (vtx.word0.SRC_REL() == SQ_REL::REL) {
      out << "[AL]";
   }

   out
      << '.'
      << disassembleDestMask(vtx.word0.SRC_SEL_X());

   out
      << ", b" << vtx.word0.BUFFER_ID();


   // fetch_type
   if (vtx.word0.FETCH_TYPE() == SQ_VTX_FETCH_TYPE::VERTEX_DATA) {
      out << " VERTEX_DATA";
   } else if (vtx.word0.FETCH_TYPE() == SQ_VTX_FETCH_TYPE::INSTANCE_DATA) {
      out << " INSTANCE_DATA";
   } else if(vtx.word0.FETCH_TYPE() == SQ_VTX_FETCH_TYPE::NO_INDEX_OFFSET) {
      out << " NO_INDEX_OFFSET";
   } else {
      out << " FETCH_TYPE(" << vtx.word0.FETCH_TYPE() << ")";
   }


   // format
   if (!vtx.word1.USE_CONST_FIELDS()) {
      out << " FORMAT(";

      out << " " << vtx.word1.DATA_FORMAT();

      if (vtx.word1.NUM_FORMAT_ALL() == 0) {
         out << " NORM";
      } else if (vtx.word1.NUM_FORMAT_ALL() == 1) {
         out << " INT";
      } else if (vtx.word1.NUM_FORMAT_ALL() == 2) {
         out << " SCALED";
      } else {
         out << vtx.word1.NUM_FORMAT_ALL();
      }

      if (vtx.word1.FORMAT_COMP_ALL()) {
         out << " SIGNED";
      } else {
         out << " UNSIGNED";
      }

      out << " " << vtx.word1.SRF_MODE_ALL();

      out << ")";
   } else {
      out << " FMT_FROM_FETCH_CONSTANT";
   }

   if (vtx.word2.MEGA_FETCH()) {
      out << " MEGA(" << (vtx.word0.MEGA_FETCH_COUNT() + 1) << ")";
   } else {
      out << " MINI(" << (vtx.word0.MEGA_FETCH_COUNT() + 1) << ")";
   }

   out << " OFFSET(" << vtx.word2.OFFSET() << ")";

   if (vtx.word0.FETCH_WHOLE_QUAD()) {
      out << " WHOLE_QUAD";
   }

   if (vtx.word2.ENDIAN_SWAP() == SQ_ENDIAN::SWAP_8IN16) {
      out << " ENDIAN_SWAP(8IN16)";
   } else if (vtx.word2.ENDIAN_SWAP() == SQ_ENDIAN::SWAP_8IN32) {
      out << " ENDIAN_SWAP(8IN32)";
   } else if (vtx.word2.ENDIAN_SWAP() != SQ_ENDIAN::NONE) {
      out << " ENDIAN_SWAP(" << vtx.word2.ENDIAN_SWAP() << ")";
   }

   if (vtx.word2.CONST_BUF_NO_STRIDE()) {
      out << " CONST_BUF_NO_STRIDE";
   }

   if (vtx.word2.ALT_CONST()) {
      out << " ALT_CONST";
   }
}