URL
https://opencores.org/ocsvn/or2k/or2k/trunk
Subversion Repositories or2k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or2k/trunk/analysis-bin/insnanalysis
- from Rev 16 to Rev 17
- ↔ Reverse comparison
Rev 16 → Rev 17
/insn-lists.c
1,9 → 1,11
/* |
Instruction list-keeping functions, aiding analysis |
|
Julius Baxter, julius.baxter@orsoc.se |
|
*/ |
|
|
#include <stdio.h> // Needed for insnanalysis.h |
#include "insnanalysis.h" |
#include "insn-lists.h" |
|
30,7 → 32,7
void insn_lists_add(int index, instruction insn, |
instruction_properties *insn_props) |
{ |
or1k_32_insn_lists_add_unique_insn(insn, insn_props); |
or1k_32_insn_lists_add(index, insn, insn_props); |
} |
|
void insn_lists_free(void) |
/or1k-32-insn.c
1,3 → 1,11
/* |
Or1K instruction set-specific decoding and analysis functions. |
|
Julius Baxter, julius.baxter@orsoc.se |
|
*/ |
|
|
#include "stdio.h" |
#include "stdint.h" |
#include "stdlib.h" |
116,6 → 124,7
break; |
default: |
printf("Unknown lv.all_xx insn"); |
return 1; |
} |
case 0x2: |
switch(insn_or1k_opcode_0x0a_get_op_lo(insn)) |
146,6 → 155,7
break; |
default: |
printf("Unknown lv.any_xx insn"); |
return 1; |
} |
break; |
case 0x3: |
175,6 → 185,7
break; |
default: |
printf("Unknown lv.add/and/avg_xx insn"); |
return 1; |
} |
break; |
case 0x4: |
206,6 → 217,7
break; |
default: |
printf("Unknown lv.cmp_xx insn"); |
return 1; |
} |
break; |
case 0x5: |
237,6 → 249,7
break; |
default: |
printf("Unknown lv.alu_xx insn"); |
return 1; |
} |
break; |
case 0x6: |
276,6 → 289,7
break; |
default: |
printf("Unknown lv.pack_xx insn"); |
return 1; |
} |
break; |
case 0x7: |
307,6 → 321,7
break; |
default: |
printf("Unknown lv.sub/unpack/xor_xx insn"); |
return 1; |
} |
break; |
case 0xc: |
319,6 → 334,7
break; |
default: |
printf("Unknown lv.xxx insn hi op"); |
return 1; |
break; |
} |
break; |
470,6 → 486,7
default: |
printf("Unknown shift op (0x%x)", |
insn_or1k_opcode_0x2e_get_op(insn)); |
return 1; |
break; |
} |
break; |
511,6 → 528,7
default: |
printf("Unknown set flag op (0x%x)", |
insn_or1k_opcode_0x2f_get_op(insn)); |
return 1; |
break; |
} |
insn_props->has_rA = 1; |
534,6 → 552,7
default: |
printf("Unknown mac op (0x%x)", |
insn_or1k_opcode_0x31_get_op(insn)); |
return 1; |
} |
break; |
|
655,6 → 674,7
default: |
printf("Unknown lf.xxx opcode hi (0x%x)", |
insn_or1k_opcode_0x32_get_op_hi(insn)); |
return 1; |
break; |
} |
break; |
676,12 → 696,12
break; |
|
case 0x38: |
switch(insn_or1k_opcode_0x38_get_op_lo(insn)) |
{ |
insn_props->has_rD = 1; |
insn_props->has_rA = 1; |
insn_props->has_rB = 1; |
case 0x0: |
insn_props->has_rD = 1; |
insn_props->has_rA = 1; |
insn_props->has_rB = 1; |
switch(insn_or1k_opcode_0x38_get_op_lo(insn)) |
{ |
case 0x0: |
insn_props->insn_string="l.add"; |
break; |
case 0x1: |
720,6 → 740,7
default: |
printf("Unknown ALU op 0x8 hi op (0x%x)", |
insn_or1k_opcode_0x38_get_op_hi_4bit(insn)); |
return 1; |
break; |
} |
break; |
771,15 → 792,16
default: |
printf("Unknown ALU lo op (0x%x)", |
insn_or1k_opcode_0x38_get_op_lo(insn)); |
return 1; |
break; |
} |
break; |
|
case 0x39: |
insn_props->has_rA = 1; |
insn_props->has_rB = 1; |
switch (insn_or1k_opcode_0x39_get_op(insn)) |
{ |
insn_props->has_rA = 0; |
insn_props->has_rB = 0; |
case 0x0: |
insn_props->insn_string="l.sfeq"; |
break; |
813,6 → 835,7
default: |
printf("Unknown opcode for l.sfxxx opcode (0x%x)", |
insn_or1k_opcode_0x39_get_op(insn)); |
return 1; |
break; |
} |
break; |
851,7 → 874,7
#define OR1K_VALUE_MAX_ENTRIES 64 |
int count; |
// [value][occurances_of_value] |
int values[OR1K_VALUE_MAX_ENTRIES][2]; |
int32_t values[OR1K_VALUE_MAX_ENTRIES][2]; |
|
}; |
|
941,7 → 964,11
|
// Increment number of instructions we have |
num_unique_insns++; |
|
|
// Debugging: |
//printf("Adding %dth instruction - %s\n", |
//num_unique_insns, new_insn->insn_string); |
|
// Return index of newly created instruction |
return (num_unique_insns - 1); |
|
948,7 → 975,7
} |
|
// 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; |
// See if it's already in the list |
963,9 → 990,14
return; |
} |
} |
// Not found, add it to the list |
list->values[(list->count)][0] = value; |
list->values[(list->count)][1] = 1; |
|
if (list->count < OR1K_VALUE_MAX_ENTRIES) |
{ |
// Not found, add it to the list |
list->values[(list->count)][0] = value; |
list->values[(list->count)][1] = 1; |
list->count++; |
} |
|
} |
|
984,7 → 1016,7
{ |
(or1k_32_insns[index])->has_branchtarg = 1; |
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 |
992,15 → 1024,15
{ |
(or1k_32_insns[index])->has_imm = 1; |
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 |
if (insn_props->has_split_imm) |
{ |
{ |
(or1k_32_insns[index])->has_imm = 1; |
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)); |
} |
|
|
1041,8 → 1073,227
|
num_unique_insns--; |
|
free((or1k_32_insns[num_unique_insns]->insn_string)); |
free(or1k_32_insns[num_unique_insns]); |
|
} |
} |
|
|
#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); |
|
} |
/insn-lists.h
1,4 → 1,10
/* |
Instruction list-keeping functions, aiding analysis |
|
Julius Baxter, julius.baxter@orsoc.se |
|
*/ |
|
#define IS_UNIQUE -1 |
|
|
/or1k-32-insn.h
1,9 → 1,12
/* |
Or1K instruction set-specific decoding and analysis functions. |
|
// OpenRISC 1000 32-bit instruction defines, helping us |
// extract fields of the instructions |
Julius Baxter, julius.baxter@orsoc.se |
|
*/ |
|
|
|
// Struct for information about the register to be confugred |
// Set to 1 to enable |
struct or1k_32_instruction_properties |
22,6 → 25,9
|
}; |
|
// OpenRISC 1000 32-bit instruction defines, helping us |
// extract fields of the instructions |
|
// Instruction decode/set its options |
int or1k_32_analyse_insn(uint32_t insn, |
struct or1k_32_instruction_properties *insn_props); |
48,6 → 54,9
void or1k_32_insn_lists_add(int index, uint32_t insn, |
struct or1k_32_instruction_properties *insn_props); |
|
// Print out some useful information |
void or1k_32_generate_stats(FILE * stream); |
|
// Free lists |
void or1k_32_insn_lists_free(void); |
|
/insnanalysis.c
36,6 → 36,12
or1k_32_collect_stats(insn, insn_props); |
} |
|
|
void generate_stats(FILE * stream) |
{ |
or1k_32_generate_stats(stream); |
} |
|
int main(int argc, char *argv[]) |
{ |
FILE *fp; |
67,25 → 73,36
// or32-elf-objcopy, so swap; |
*insn = htonl(*insn); |
|
if (*insn == 0) // most probably dead space in binary, skip |
continue; |
|
reset_instruction_properties(&insn_props); |
|
analyse_insn(*insn, &insn_props); |
if (analyse_insn(*insn, &insn_props) == 0) |
{ |
/* |
print_insn(&insn_props); |
printf("\n"); |
*/ |
insns_seen_total++; |
|
collect_stats(*insn, &insn_props); |
} |
else |
{ |
printf("\n"); |
} |
|
print_insn(&insn_props); |
printf("\n"); |
|
insns_seen_total++; |
|
collect_stats(*insn, &insn_props); |
|
} |
|
insn_lists_free(); |
|
fclose(fp); |
|
printf("Saw %d instructions\n", insns_seen_total); |
|
printf("Saw %d instructions\n", insns_seen_total); |
generate_stats(stdout); |
|
insn_lists_free(); |
|
return 0; |
|
} |
/README
0,0 → 1,43
Instruction analysis program |
|
This application reads in a binary list of instructions, and analyses it with a |
set of functions looking at various parameters in each instruction. |
|
It has been designed so a different instruction set support can be added. |
|
Right now it's not so user friendly. Everything is hardcoded, and only support |
for the OR1K instruction set exists. |
|
Compile the program with: |
|
$ make all |
|
And run a test (it needs the or32-elf- toolchain) with: |
|
$ make test |
|
To run the program itself, just give it a binary blob of instructions (usually |
the output of objcopy -O binary). |
|
For instance the Linux kernel ELF can be prepared with the following command: |
|
$ or32-elf-objcopy -O binary -j .text -S vmlinux vmlinux.text.bin |
|
Run it in the program with |
|
$ ./insnanalysis vmlinux.text.bin > vmlinux.insnanalysis |
|
Currently the program will output all appropriate information for each |
instruction (ie. only ones with rA, or immediate fields in the instructions will |
have reports on those fields.) |
|
|
|
TODO: |
o Add a more flexible way of indicating the instructions to dump |
o Add an easy way to switch between human readable and CSV output |
o Figure out how to tack this thing onto a simulator (or1ksim maybe) to give |
results of execution when that finishes executing, or just how to get the |
simulator to output a binary dump of executed instructions to be fed through |
this |
o Instruction group analysis (pairs, triplets, etc.) |