OpenCores
URL https://opencores.org/ocsvn/or2k/or2k/trunk

Subversion Repositories or2k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 16 to Rev 17
    Reverse comparison

Rev 16 → Rev 17

/or2k/trunk/analysis-bin/insnanalysis/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)
/or2k/trunk/analysis-bin/insnanalysis/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);
}
/or2k/trunk/analysis-bin/insnanalysis/insn-lists.h
1,4 → 1,10
/*
Instruction list-keeping functions, aiding analysis
 
Julius Baxter, julius.baxter@orsoc.se
 
*/
 
#define IS_UNIQUE -1
 
 
/or2k/trunk/analysis-bin/insnanalysis/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);
 
/or2k/trunk/analysis-bin/insnanalysis/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;
 
}
/or2k/trunk/analysis-bin/insnanalysis/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.)

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.