Line 1... |
Line 1... |
|
/*
|
|
Or1K instruction set-specific decoding and analysis functions.
|
|
|
|
Julius Baxter, julius.baxter@orsoc.se
|
|
|
|
*/
|
|
|
|
|
#include "stdio.h"
|
#include "stdio.h"
|
#include "stdint.h"
|
#include "stdint.h"
|
#include "stdlib.h"
|
#include "stdlib.h"
|
#include "string.h"
|
#include "string.h"
|
#include "or1k-32-insn.h"
|
#include "or1k-32-insn.h"
|
Line 114... |
Line 122... |
break;
|
break;
|
case 0xb:
|
case 0xb:
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown lv.all_xx insn");
|
printf("Unknown lv.all_xx insn");
|
|
return 1;
|
}
|
}
|
case 0x2:
|
case 0x2:
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
Line 144... |
Line 153... |
break;
|
break;
|
case 0xb:
|
case 0xb:
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown lv.any_xx insn");
|
printf("Unknown lv.any_xx insn");
|
|
return 1;
|
}
|
}
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
{
|
{
|
Line 173... |
Line 183... |
break;
|
break;
|
case 0xa:
|
case 0xa:
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown lv.add/and/avg_xx insn");
|
printf("Unknown lv.add/and/avg_xx insn");
|
|
return 1;
|
}
|
}
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
{
|
{
|
Line 204... |
Line 215... |
break;
|
break;
|
case 0xb:
|
case 0xb:
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown lv.cmp_xx insn");
|
printf("Unknown lv.cmp_xx insn");
|
|
return 1;
|
}
|
}
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
{
|
{
|
Line 235... |
Line 247... |
break;
|
break;
|
case 0xf:
|
case 0xf:
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown lv.alu_xx insn");
|
printf("Unknown lv.alu_xx insn");
|
|
return 1;
|
}
|
}
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
{
|
{
|
Line 274... |
Line 287... |
break;
|
break;
|
case 0xf:
|
case 0xf:
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown lv.pack_xx insn");
|
printf("Unknown lv.pack_xx insn");
|
|
return 1;
|
}
|
}
|
break;
|
break;
|
case 0x7:
|
case 0x7:
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
{
|
{
|
Line 305... |
Line 319... |
break;
|
break;
|
case 0xb:
|
case 0xb:
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown lv.sub/unpack/xor_xx insn");
|
printf("Unknown lv.sub/unpack/xor_xx insn");
|
|
return 1;
|
}
|
}
|
break;
|
break;
|
case 0xc:
|
case 0xc:
|
break;
|
break;
|
case 0xd:
|
case 0xd:
|
Line 317... |
Line 332... |
break;
|
break;
|
case 0xf:
|
case 0xf:
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown lv.xxx insn hi op");
|
printf("Unknown lv.xxx insn hi op");
|
|
return 1;
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
|
|
case 0x11:
|
case 0x11:
|
Line 468... |
Line 484... |
insn_props->insn_string="l.rori";
|
insn_props->insn_string="l.rori";
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown shift op (0x%x)",
|
printf("Unknown shift op (0x%x)",
|
insn_or1k_opcode_0x2e_get_op(insn));
|
insn_or1k_opcode_0x2e_get_op(insn));
|
|
return 1;
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
|
|
case 0x2f:
|
case 0x2f:
|
Line 509... |
Line 526... |
break;
|
break;
|
|
|
default:
|
default:
|
printf("Unknown set flag op (0x%x)",
|
printf("Unknown set flag op (0x%x)",
|
insn_or1k_opcode_0x2f_get_op(insn));
|
insn_or1k_opcode_0x2f_get_op(insn));
|
|
return 1;
|
break;
|
break;
|
}
|
}
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
Line 532... |
Line 550... |
insn_props->insn_string="l.msb";
|
insn_props->insn_string="l.msb";
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown mac op (0x%x)",
|
printf("Unknown mac op (0x%x)",
|
insn_or1k_opcode_0x31_get_op(insn));
|
insn_or1k_opcode_0x31_get_op(insn));
|
|
return 1;
|
}
|
}
|
break;
|
break;
|
|
|
case 0x32:
|
case 0x32:
|
switch(insn_or1k_opcode_0x32_get_op_hi(insn))
|
switch(insn_or1k_opcode_0x32_get_op_hi(insn))
|
Line 653... |
Line 672... |
break;
|
break;
|
|
|
default:
|
default:
|
printf("Unknown lf.xxx opcode hi (0x%x)",
|
printf("Unknown lf.xxx opcode hi (0x%x)",
|
insn_or1k_opcode_0x32_get_op_hi(insn));
|
insn_or1k_opcode_0x32_get_op_hi(insn));
|
|
return 1;
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
|
|
case 0x34:
|
case 0x34:
|
Line 674... |
Line 694... |
case 0x37:
|
case 0x37:
|
insn_props->insn_string="l.sh";
|
insn_props->insn_string="l.sh";
|
break;
|
break;
|
|
|
case 0x38:
|
case 0x38:
|
switch(insn_or1k_opcode_0x38_get_op_lo(insn))
|
|
{
|
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rB = 1;
|
insn_props->has_rB = 1;
|
|
switch(insn_or1k_opcode_0x38_get_op_lo(insn))
|
|
{
|
case 0x0:
|
case 0x0:
|
insn_props->insn_string="l.add";
|
insn_props->insn_string="l.add";
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
insn_props->insn_string="l.addc";
|
insn_props->insn_string="l.addc";
|
Line 718... |
Line 738... |
insn_props->insn_string="l.ror";
|
insn_props->insn_string="l.ror";
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown ALU op 0x8 hi op (0x%x)",
|
printf("Unknown ALU op 0x8 hi op (0x%x)",
|
insn_or1k_opcode_0x38_get_op_hi_4bit(insn));
|
insn_or1k_opcode_0x38_get_op_hi_4bit(insn));
|
|
return 1;
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
case 0x9:
|
case 0x9:
|
insn_props->insn_string="l.div";
|
insn_props->insn_string="l.div";
|
Line 769... |
Line 790... |
break;
|
break;
|
|
|
default:
|
default:
|
printf("Unknown ALU lo op (0x%x)",
|
printf("Unknown ALU lo op (0x%x)",
|
insn_or1k_opcode_0x38_get_op_lo(insn));
|
insn_or1k_opcode_0x38_get_op_lo(insn));
|
|
return 1;
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
|
|
case 0x39:
|
case 0x39:
|
|
insn_props->has_rA = 1;
|
|
insn_props->has_rB = 1;
|
switch (insn_or1k_opcode_0x39_get_op(insn))
|
switch (insn_or1k_opcode_0x39_get_op(insn))
|
{
|
{
|
insn_props->has_rA = 0;
|
|
insn_props->has_rB = 0;
|
|
case 0x0:
|
case 0x0:
|
insn_props->insn_string="l.sfeq";
|
insn_props->insn_string="l.sfeq";
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
insn_props->insn_string="l.sfne";
|
insn_props->insn_string="l.sfne";
|
Line 811... |
Line 833... |
insn_props->insn_string="l.sfles";
|
insn_props->insn_string="l.sfles";
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown opcode for l.sfxxx opcode (0x%x)",
|
printf("Unknown opcode for l.sfxxx opcode (0x%x)",
|
insn_or1k_opcode_0x39_get_op(insn));
|
insn_or1k_opcode_0x39_get_op(insn));
|
|
return 1;
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
|
|
default:
|
default:
|
Line 849... |
Line 872... |
{
|
{
|
|
|
#define OR1K_VALUE_MAX_ENTRIES 64
|
#define OR1K_VALUE_MAX_ENTRIES 64
|
int count;
|
int count;
|
// [value][occurances_of_value]
|
// [value][occurances_of_value]
|
int values[OR1K_VALUE_MAX_ENTRIES][2];
|
int32_t values[OR1K_VALUE_MAX_ENTRIES][2];
|
|
|
};
|
};
|
|
|
|
|
struct or1k_insn_info
|
struct or1k_insn_info
|
Line 940... |
Line 963... |
or1k_32_insns[num_unique_insns] = new_insn;;
|
or1k_32_insns[num_unique_insns] = new_insn;;
|
|
|
// Increment number of instructions we have
|
// Increment number of instructions we have
|
num_unique_insns++;
|
num_unique_insns++;
|
|
|
|
// Debugging:
|
|
//printf("Adding %dth instruction - %s\n",
|
|
//num_unique_insns, new_insn->insn_string);
|
|
|
// Return index of newly created instruction
|
// Return index of newly created instruction
|
return (num_unique_insns - 1);
|
return (num_unique_insns - 1);
|
|
|
}
|
}
|
|
|
// Add to, or increment incidences of, value in the value list
|
// Add to, or increment incidences of, value in the value list
|
void or1k_add_in_list(struct or1k_value_list * list, int value)
|
void or1k_add_in_list(struct or1k_value_list * list, int32_t value)
|
{
|
{
|
int i;
|
int i;
|
// See if it's already in the list
|
// See if it's already in the list
|
i=list->count;
|
i=list->count;
|
|
|
Line 961... |
Line 988... |
{
|
{
|
(list->values[i][1])++;
|
(list->values[i][1])++;
|
return;
|
return;
|
}
|
}
|
}
|
}
|
|
|
|
if (list->count < OR1K_VALUE_MAX_ENTRIES)
|
|
{
|
// Not found, add it to the list
|
// Not found, add it to the list
|
list->values[(list->count)][0] = value;
|
list->values[(list->count)][0] = value;
|
list->values[(list->count)][1] = 1;
|
list->values[(list->count)][1] = 1;
|
|
list->count++;
|
|
}
|
|
|
}
|
}
|
|
|
|
|
// Add stats for this instruction
|
// Add stats for this instruction
|
Line 982... |
Line 1014... |
// Add branch target value information, if instruction has it
|
// Add branch target value information, if instruction has it
|
if (insn_props->has_branchtarg)
|
if (insn_props->has_branchtarg)
|
{
|
{
|
(or1k_32_insns[index])->has_branchtarg = 1;
|
(or1k_32_insns[index])->has_branchtarg = 1;
|
or1k_add_in_list(&((or1k_32_insns[index])->branch_info),
|
or1k_add_in_list(&((or1k_32_insns[index])->branch_info),
|
(int)insn_or1k_opcode_0x03_get_branchoff(insn));
|
(int32_t)insn_or1k_opcode_0x03_get_branchoff(insn));
|
}
|
}
|
|
|
// Add immediate value if it's got one
|
// Add immediate value if it's got one
|
if (insn_props->has_imm)
|
if (insn_props->has_imm)
|
{
|
{
|
(or1k_32_insns[index])->has_imm = 1;
|
(or1k_32_insns[index])->has_imm = 1;
|
or1k_add_in_list(&((or1k_32_insns[index])->imm_info),
|
or1k_add_in_list(&((or1k_32_insns[index])->imm_info),
|
(int)insn_or1k_32_imm(insn));
|
(int32_t)insn_or1k_32_imm(insn));
|
}
|
}
|
|
|
// Add split immediate value if it's got one
|
// Add split immediate value if it's got one
|
if (insn_props->has_split_imm)
|
if (insn_props->has_split_imm)
|
{
|
{
|
(or1k_32_insns[index])->has_imm = 1;
|
(or1k_32_insns[index])->has_imm = 1;
|
or1k_add_in_list(&((or1k_32_insns[index])->imm_info),
|
or1k_add_in_list(&((or1k_32_insns[index])->imm_info),
|
(int)insn_or1k_32_split_imm(insn));
|
(int32_t)insn_or1k_32_split_imm(insn));
|
}
|
}
|
|
|
|
|
// Increment count of use for particular rD
|
// Increment count of use for particular rD
|
if (insn_props->has_rD)
|
if (insn_props->has_rD)
|
Line 1039... |
Line 1071... |
while (num_unique_insns)
|
while (num_unique_insns)
|
{
|
{
|
|
|
num_unique_insns--;
|
num_unique_insns--;
|
|
|
|
free((or1k_32_insns[num_unique_insns]->insn_string));
|
free(or1k_32_insns[num_unique_insns]);
|
free(or1k_32_insns[num_unique_insns]);
|
|
|
}
|
}
|
}
|
}
|
|
|
|
|
No newline at end of file
|
No newline at end of file
|
|
#define DISPLAY_STRING
|
|
//#define DISPLAY_CSV
|
|
|
|
void or1k_32_most_freq_insn(FILE * stream)
|
|
{
|
|
// Print out most frequent instruction
|
|
int i, largest, largest_index;
|
|
int instructions_to_print = num_unique_insns;
|
|
while (instructions_to_print)
|
|
{
|
|
--instructions_to_print;
|
|
largest=0;
|
|
// Go through the list, find the largest, print it, eliminate it
|
|
for(i=0;i<num_unique_insns;i++)
|
|
if(((or1k_32_insns[i])->count) > largest)
|
|
{
|
|
largest = ((or1k_32_insns[i])->count);
|
|
largest_index = i;
|
|
}
|
|
|
|
fprintf(stream,
|
|
#ifdef DISPLAY_STRING
|
|
"Insn:\t%s\t\tCount:\t\t%d\t(%f%%)\n",
|
|
#endif
|
|
#ifdef DISPLAY_CSV
|
|
// CSV format - "opcode string",frequency,percentage
|
|
"\"%s\",%d,%f\n",
|
|
#endif
|
|
((or1k_32_insns[largest_index])->insn_string),
|
|
((or1k_32_insns[largest_index])->count),
|
|
(float)(((float)((or1k_32_insns[largest_index])->count))/
|
|
((float)num_seen_insns))*100.f);
|
|
|
|
|
|
((or1k_32_insns[largest_index])->count) = -1; // Eliminate this one
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// Print out top x of each kept statistic for the requested instruction
|
|
void or1k_32_insn_top_x(char* insn_string, FILE * stream, int max_stats)
|
|
{
|
|
int i, j, largest, largest_i;
|
|
|
|
// Confect an instruction properties object to fish out the instruction
|
|
struct or1k_32_instruction_properties temp_insn_props;
|
|
// Struct we'll copy the info into
|
|
struct or1k_insn_info insn_info;
|
|
|
|
temp_insn_props.insn_string = insn_string;
|
|
|
|
int insn_index = or1k_32_insn_lists_check(0, &temp_insn_props);
|
|
if (insn_index == IS_UNIQUE)
|
|
{
|
|
fprintf(stream,"Insn: \"%s\" was not seen\n",insn_string);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
fprintf(stream,"Insn: \"%s\" statistics (%d times (%f%%)):\n", insn_string,
|
|
or1k_32_insns[insn_index]->count,
|
|
(float)(((float)((or1k_32_insns[insn_index])->count))/
|
|
((float)num_seen_insns))*100.f
|
|
);
|
|
}
|
|
|
|
// We have the instruction's index, copy it out (to make code neater!)
|
|
memcpy(&insn_info, or1k_32_insns[insn_index],
|
|
sizeof(struct or1k_insn_info));
|
|
|
|
// Print out top max_stats branch targets
|
|
|
|
if (insn_info.has_branchtarg)
|
|
{
|
|
fprintf(stream,"Branch values:\n");
|
|
i = 0;
|
|
while(i<insn_info.branch_info.count && i < max_stats)
|
|
{
|
|
largest_i=0;
|
|
for(j=0;j<insn_info.branch_info.count;j++)
|
|
largest_i = (insn_info.branch_info.values[j][1] >
|
|
insn_info.branch_info.values[largest_i][1]) ?
|
|
j : largest_i;
|
|
|
|
// largest_i has index of most frequent value
|
|
fprintf(stream,
|
|
"value:\t0x%x\tcount:\t%d\n",
|
|
insn_info.branch_info.values[largest_i][0],
|
|
insn_info.branch_info.values[largest_i][1]);
|
|
insn_info.branch_info.values[largest_i][1] = -1; // clear this one
|
|
i++;
|
|
}
|
|
}
|
|
if (insn_info.has_imm)
|
|
{
|
|
fprintf(stream,"Immediate values:\n");
|
|
i = 0;
|
|
while(i<insn_info.imm_info.count && i < max_stats)
|
|
{
|
|
largest_i=0;
|
|
for(j=0;j<insn_info.imm_info.count;j++)
|
|
largest_i = (insn_info.imm_info.values[j][1] >
|
|
insn_info.imm_info.values[largest_i][1]) ?
|
|
j : largest_i;
|
|
|
|
// largest_i has index of most frequent value
|
|
fprintf(stream,
|
|
"value:\t0x%x\tcount:\t%d\n",
|
|
insn_info.imm_info.values[largest_i][0],
|
|
insn_info.imm_info.values[largest_i][1]);
|
|
insn_info.imm_info.values[largest_i][1] = -1; // clear this one
|
|
i++;
|
|
}
|
|
}
|
|
if (insn_info.has_rD)
|
|
{
|
|
fprintf(stream,"rD usage:\n");
|
|
i = 0;
|
|
while(i<32 && i < max_stats)
|
|
{
|
|
largest_i=0;
|
|
for(j=0;j<32;j++)
|
|
largest_i = (insn_info.rD_use_freq[j] >
|
|
insn_info.rD_use_freq[largest_i]) ?
|
|
j : largest_i;
|
|
|
|
// No more interesting numbers
|
|
if (insn_info.rD_use_freq[largest_i] == 0)
|
|
break;
|
|
|
|
// largest_i has index of most frequent value
|
|
fprintf(stream,
|
|
"r%d\tcount:\t%d\n",
|
|
largest_i,
|
|
insn_info.rD_use_freq[largest_i]);
|
|
insn_info.rD_use_freq[largest_i] = -1; // clear this one
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (insn_info.has_rA)
|
|
{
|
|
fprintf(stream,"rA usage:\n");
|
|
i = 0;
|
|
while(i<32 && i < max_stats)
|
|
{
|
|
largest_i=0;
|
|
for(j=0;j<32;j++)
|
|
largest_i = (insn_info.rA_use_freq[j] >
|
|
insn_info.rA_use_freq[largest_i]) ?
|
|
j : largest_i;
|
|
|
|
// No more interesting numbers
|
|
if (insn_info.rA_use_freq[largest_i] == 0)
|
|
break;
|
|
|
|
|
|
// largest_i has index of most frequent value
|
|
fprintf(stream,
|
|
"r%d\tcount:\t%d\n",
|
|
largest_i,
|
|
insn_info.rA_use_freq[largest_i]);
|
|
insn_info.rA_use_freq[largest_i] = -1; // clear this one
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (insn_info.has_rB)
|
|
{
|
|
fprintf(stream,"rB usage:\n");
|
|
i = 0;
|
|
while(i<32 && i < max_stats)
|
|
{
|
|
largest_i=0;
|
|
for(j=0;j<32;j++)
|
|
largest_i = (insn_info.rB_use_freq[j] >
|
|
insn_info.rB_use_freq[largest_i]) ?
|
|
j : largest_i;
|
|
|
|
// No more interesting numbers
|
|
if (insn_info.rB_use_freq[largest_i] == 0)
|
|
break;
|
|
|
|
|
|
// largest_i has index of most frequent value
|
|
fprintf(stream,
|
|
"r%d\tcount:\t%d\n",
|
|
largest_i,
|
|
insn_info.rB_use_freq[largest_i]);
|
|
insn_info.rB_use_freq[largest_i] = -1; // clear this one
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void or1k_32_generate_stats(FILE * stream)
|
|
{
|
|
// Generate some useful things
|
|
fprintf(stream, "Analysis output:\n");
|
|
|
|
//
|
|
|
|
// Print out all stats for every instruction we saw!
|
|
int unique = num_unique_insns;
|
|
while (unique)
|
|
{
|
|
--unique;
|
|
or1k_32_insn_top_x(or1k_32_insns[unique]->insn_string,stream,10);
|
|
}
|
|
|
|
|
|
// Do most frequent instruction analysis -- note this trashes instruction
|
|
// frequency count - should be fixed
|
|
or1k_32_most_freq_insn(stream);
|
|
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|