|
/*
|
|
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"
|
|
|
// These should also be in insnanalysis.h insnanalysis.h
|
// These should also be in insnanalysis.h insnanalysis.h
|
typedef uint32_t instruction;
|
typedef uint32_t instruction;
|
typedef struct or1k_32_instruction_properties instruction_properties ;
|
typedef struct or1k_32_instruction_properties instruction_properties ;
|
|
|
#include "insn-lists.h"
|
#include "insn-lists.h"
|
|
|
|
|
int or1k_32_analyse_insn(uint32_t insn,
|
int or1k_32_analyse_insn(uint32_t insn,
|
struct or1k_32_instruction_properties * insn_props)
|
struct or1k_32_instruction_properties * insn_props)
|
{
|
{
|
|
|
switch(insn_or1k_opcode(insn))
|
switch(insn_or1k_opcode(insn))
|
{
|
{
|
case 0x00:
|
case 0x00:
|
insn_props->insn_string="l.j";
|
insn_props->insn_string="l.j";
|
insn_props->has_jumptarg = 1;
|
insn_props->has_jumptarg = 1;
|
break;
|
break;
|
|
|
case 0x01:
|
case 0x01:
|
insn_props->insn_string="l.jal";
|
insn_props->insn_string="l.jal";
|
insn_props->has_jumptarg = 1;
|
insn_props->has_jumptarg = 1;
|
break;
|
break;
|
|
|
case 0x03:
|
case 0x03:
|
insn_props->insn_string="l.bnf";
|
insn_props->insn_string="l.bnf";
|
insn_props->has_branchtarg = 1;
|
insn_props->has_branchtarg = 1;
|
break;
|
break;
|
|
|
case 0x04:
|
case 0x04:
|
insn_props->insn_string="l.bf";
|
insn_props->insn_string="l.bf";
|
insn_props->has_branchtarg = 1;
|
insn_props->has_branchtarg = 1;
|
break;
|
break;
|
|
|
case 0x05:
|
case 0x05:
|
insn_props->insn_string="l.nop";
|
insn_props->insn_string="l.nop";
|
break;
|
break;
|
|
|
case 0x06:
|
case 0x06:
|
if((insn_or1k_opcode_0x06_get_id(insn)))
|
if((insn_or1k_opcode_0x06_get_id(insn)))
|
insn_props->insn_string="l.macrc";
|
insn_props->insn_string="l.macrc";
|
else
|
else
|
{
|
{
|
insn_props->insn_string="l.movhi";
|
insn_props->insn_string="l.movhi";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
}
|
}
|
|
|
break;
|
break;
|
|
|
case 0x08:
|
case 0x08:
|
|
|
switch(insn_or1k_opcode_0x08_get_id(insn))
|
switch(insn_or1k_opcode_0x08_get_id(insn))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
insn_props->insn_string="l.sys";
|
insn_props->insn_string="l.sys";
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
insn_props->insn_string="l.trap";
|
insn_props->insn_string="l.trap";
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
insn_props->insn_string="l.msync";
|
insn_props->insn_string="l.msync";
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
insn_props->insn_string="l.psync";
|
insn_props->insn_string="l.psync";
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
insn_props->insn_string="l.csync";
|
insn_props->insn_string="l.csync";
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown id (0x%x) in opcode 0x8",
|
printf("Unknown id (0x%x) in opcode 0x8",
|
insn_or1k_opcode_0x08_get_id(insn) );
|
insn_or1k_opcode_0x08_get_id(insn) );
|
return 1;
|
return 1;
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
|
|
case 0x09:
|
case 0x09:
|
insn_props->insn_string="l.rfe";
|
insn_props->insn_string="l.rfe";
|
break;
|
break;
|
|
|
case 0x0a:
|
case 0x0a:
|
switch(insn_or1k_opcode_0x0a_get_op_hi(insn))
|
switch(insn_or1k_opcode_0x0a_get_op_hi(insn))
|
{
|
{
|
case 0x1:
|
case 0x1:
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
switch(insn_or1k_opcode_0x0a_get_op_lo(insn))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
break;
|
break;
|
case 0x7:
|
case 0x7:
|
break;
|
break;
|
case 0x8:
|
case 0x8:
|
break;
|
break;
|
case 0x9:
|
case 0x9:
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
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:
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
break;
|
break;
|
case 0x7:
|
case 0x7:
|
break;
|
break;
|
case 0x8:
|
case 0x8:
|
break;
|
break;
|
case 0x9:
|
case 0x9:
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
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))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
break;
|
break;
|
case 0x7:
|
case 0x7:
|
break;
|
break;
|
case 0x8:
|
case 0x8:
|
break;
|
break;
|
case 0x9:
|
case 0x9:
|
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))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
break;
|
break;
|
case 0x7:
|
case 0x7:
|
break;
|
break;
|
case 0x8:
|
case 0x8:
|
break;
|
break;
|
case 0x9:
|
case 0x9:
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
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))
|
{
|
{
|
case 0x4:
|
case 0x4:
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
break;
|
break;
|
case 0x7:
|
case 0x7:
|
break;
|
break;
|
case 0x8:
|
case 0x8:
|
break;
|
break;
|
case 0x9:
|
case 0x9:
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
break;
|
break;
|
case 0xb:
|
case 0xb:
|
break;
|
break;
|
case 0xc:
|
case 0xc:
|
break;
|
break;
|
case 0xd:
|
case 0xd:
|
break;
|
break;
|
case 0xe:
|
case 0xe:
|
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))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
break;
|
break;
|
case 0x7:
|
case 0x7:
|
break;
|
break;
|
case 0x8:
|
case 0x8:
|
break;
|
break;
|
case 0x9:
|
case 0x9:
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
break;
|
break;
|
case 0xb:
|
case 0xb:
|
break;
|
break;
|
case 0xc:
|
case 0xc:
|
break;
|
break;
|
case 0xd:
|
case 0xd:
|
break;
|
break;
|
case 0xe:
|
case 0xe:
|
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))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
break;
|
break;
|
case 0x7:
|
case 0x7:
|
break;
|
break;
|
case 0x8:
|
case 0x8:
|
break;
|
break;
|
case 0x9:
|
case 0x9:
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
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:
|
break;
|
break;
|
case 0xe:
|
case 0xe:
|
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:
|
insn_props->insn_string="l.jr";
|
insn_props->insn_string="l.jr";
|
insn_props->has_rB = 1;
|
insn_props->has_rB = 1;
|
break;
|
break;
|
|
|
case 0x12:
|
case 0x12:
|
insn_props->insn_string="l.jalr";
|
insn_props->insn_string="l.jalr";
|
insn_props->has_rB = 1;
|
insn_props->has_rB = 1;
|
break;
|
break;
|
|
|
case 0x13:
|
case 0x13:
|
insn_props->insn_string="l.maci";
|
insn_props->insn_string="l.maci";
|
break;
|
break;
|
|
|
case 0x1c:
|
case 0x1c:
|
insn_props->insn_string="l.cust1";
|
insn_props->insn_string="l.cust1";
|
break;
|
break;
|
|
|
case 0x1d:
|
case 0x1d:
|
insn_props->insn_string="l.cust2";
|
insn_props->insn_string="l.cust2";
|
break;
|
break;
|
|
|
case 0x1e:
|
case 0x1e:
|
insn_props->insn_string="l.cust3";
|
insn_props->insn_string="l.cust3";
|
break;
|
break;
|
|
|
case 0x1f:
|
case 0x1f:
|
insn_props->insn_string="l.cust4";
|
insn_props->insn_string="l.cust4";
|
break;
|
break;
|
|
|
case 0x20:
|
case 0x20:
|
insn_props->insn_string="l.ld";
|
insn_props->insn_string="l.ld";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x21:
|
case 0x21:
|
insn_props->insn_string="l.lwz";
|
insn_props->insn_string="l.lwz";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x22:
|
case 0x22:
|
insn_props->insn_string="l.lws";
|
insn_props->insn_string="l.lws";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x23:
|
case 0x23:
|
insn_props->insn_string="l.lbz";
|
insn_props->insn_string="l.lbz";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x24:
|
case 0x24:
|
insn_props->insn_string="l.lbs";
|
insn_props->insn_string="l.lbs";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x25:
|
case 0x25:
|
insn_props->insn_string="l.lhz";
|
insn_props->insn_string="l.lhz";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x26:
|
case 0x26:
|
insn_props->insn_string="l.lhs";
|
insn_props->insn_string="l.lhs";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
|
|
case 0x27:
|
case 0x27:
|
insn_props->insn_string="l.addi";
|
insn_props->insn_string="l.addi";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x28:
|
case 0x28:
|
insn_props->insn_string="l.addic";
|
insn_props->insn_string="l.addic";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x29:
|
case 0x29:
|
insn_props->insn_string="l.andi";
|
insn_props->insn_string="l.andi";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x2a:
|
case 0x2a:
|
insn_props->insn_string="l.ori";
|
insn_props->insn_string="l.ori";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x2b:
|
case 0x2b:
|
insn_props->insn_string="l.xori";
|
insn_props->insn_string="l.xori";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x2c:
|
case 0x2c:
|
insn_props->insn_string="l.muli";
|
insn_props->insn_string="l.muli";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x2d:
|
case 0x2d:
|
insn_props->insn_string="l.mfspr";
|
insn_props->insn_string="l.mfspr";
|
insn_props->has_rD = 1;
|
insn_props->has_rD = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_rA = 1;
|
insn_props->has_imm = 1;
|
insn_props->has_imm = 1;
|
break;
|
break;
|
|
|
case 0x2e:
|
case 0x2e:
|
switch(insn_or1k_opcode_0x2e_get_op(insn))
|
switch(insn_or1k_opcode_0x2e_get_op(insn))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
insn_props->insn_string="l.slli";
|
insn_props->insn_string="l.slli";
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
insn_props->insn_string="l.srli";
|
insn_props->insn_string="l.srli";
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
insn_props->insn_string="l.srai";
|
insn_props->insn_string="l.srai";
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
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:
|
switch(insn_or1k_opcode_0x2f_get_op(insn))
|
switch(insn_or1k_opcode_0x2f_get_op(insn))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
insn_props->insn_string="l.sfeqi";
|
insn_props->insn_string="l.sfeqi";
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
insn_props->insn_string="l.sfnei";
|
insn_props->insn_string="l.sfnei";
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
insn_props->insn_string="l.sfgtui";
|
insn_props->insn_string="l.sfgtui";
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
insn_props->insn_string="l.sfgeui";
|
insn_props->insn_string="l.sfgeui";
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
insn_props->insn_string="l.sfltui";
|
insn_props->insn_string="l.sfltui";
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
insn_props->insn_string="l.sfleui";
|
insn_props->insn_string="l.sfleui";
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
insn_props->insn_string="l.sfgtsi";
|
insn_props->insn_string="l.sfgtsi";
|
break;
|
break;
|
case 0xb:
|
case 0xb:
|
insn_props->insn_string="l.sfgesi";
|
insn_props->insn_string="l.sfgesi";
|
break;
|
break;
|
case 0xc:
|
case 0xc:
|
insn_props->insn_string="l.sfltsi";
|
insn_props->insn_string="l.sfltsi";
|
break;
|
break;
|
case 0xd:
|
case 0xd:
|
insn_props->insn_string="l.sflesi";
|
insn_props->insn_string="l.sflesi";
|
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;
|
|
|
|
|
case 0x30:
|
case 0x30:
|
insn_props->insn_string="l.mtspr";
|
insn_props->insn_string="l.mtspr";
|
break;
|
break;
|
|
|
case 0x31:
|
case 0x31:
|
switch (insn_or1k_opcode_0x31_get_op(insn))
|
switch (insn_or1k_opcode_0x31_get_op(insn))
|
{
|
{
|
case 0x1:
|
case 0x1:
|
insn_props->insn_string="l.mac";
|
insn_props->insn_string="l.mac";
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
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))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
switch(insn_or1k_opcode_0x32_get_op_lo(insn))
|
switch(insn_or1k_opcode_0x32_get_op_lo(insn))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
insn_props->insn_string="lf.add.s";
|
insn_props->insn_string="lf.add.s";
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
insn_props->insn_string="lf.sub.s";
|
insn_props->insn_string="lf.sub.s";
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
insn_props->insn_string="lf.mul.s";
|
insn_props->insn_string="lf.mul.s";
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
insn_props->insn_string="lf.div.s";
|
insn_props->insn_string="lf.div.s";
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
insn_props->insn_string="lf.itof.s";
|
insn_props->insn_string="lf.itof.s";
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
insn_props->insn_string="lf.ftoi.s";
|
insn_props->insn_string="lf.ftoi.s";
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
insn_props->insn_string="lf.rem.s";
|
insn_props->insn_string="lf.rem.s";
|
break;
|
break;
|
case 0x7:
|
case 0x7:
|
insn_props->insn_string="lf.madd.s";
|
insn_props->insn_string="lf.madd.s";
|
break;
|
break;
|
case 0x8:
|
case 0x8:
|
insn_props->insn_string="lf.sfeq.s";
|
insn_props->insn_string="lf.sfeq.s";
|
break;
|
break;
|
case 0x9:
|
case 0x9:
|
insn_props->insn_string="lf.sfne.s";
|
insn_props->insn_string="lf.sfne.s";
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
insn_props->insn_string="lf.sfgt.s";
|
insn_props->insn_string="lf.sfgt.s";
|
break;
|
break;
|
case 0xb:
|
case 0xb:
|
insn_props->insn_string="lf.sfge.s";
|
insn_props->insn_string="lf.sfge.s";
|
break;
|
break;
|
case 0xc:
|
case 0xc:
|
insn_props->insn_string="lf.sflt.s";
|
insn_props->insn_string="lf.sflt.s";
|
break;
|
break;
|
case 0xd:
|
case 0xd:
|
insn_props->insn_string="lf.sfle.s";
|
insn_props->insn_string="lf.sfle.s";
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown lf.xxx.s op (0x%x)",
|
printf("Unknown lf.xxx.s op (0x%x)",
|
insn_or1k_opcode_0x32_get_op_lo(insn));
|
insn_or1k_opcode_0x32_get_op_lo(insn));
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
|
|
case 0x1:
|
case 0x1:
|
switch(insn_or1k_opcode_0x32_get_op_lo(insn))
|
switch(insn_or1k_opcode_0x32_get_op_lo(insn))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
insn_props->insn_string="lf.add.d";
|
insn_props->insn_string="lf.add.d";
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
insn_props->insn_string="lf.sub.d";
|
insn_props->insn_string="lf.sub.d";
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
insn_props->insn_string="lf.mul.d";
|
insn_props->insn_string="lf.mul.d";
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
insn_props->insn_string="lf.div.d";
|
insn_props->insn_string="lf.div.d";
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
insn_props->insn_string="lf.itof.d";
|
insn_props->insn_string="lf.itof.d";
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
insn_props->insn_string="lf.ftoi.d";
|
insn_props->insn_string="lf.ftoi.d";
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
insn_props->insn_string="lf.rem.d";
|
insn_props->insn_string="lf.rem.d";
|
break;
|
break;
|
case 0x7:
|
case 0x7:
|
insn_props->insn_string="lf.madd.d";
|
insn_props->insn_string="lf.madd.d";
|
break;
|
break;
|
case 0x8:
|
case 0x8:
|
insn_props->insn_string="lf.sfeq.d";
|
insn_props->insn_string="lf.sfeq.d";
|
break;
|
break;
|
case 0x9:
|
case 0x9:
|
insn_props->insn_string="lf.sfne.d";
|
insn_props->insn_string="lf.sfne.d";
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
insn_props->insn_string="lf.sfgt.d";
|
insn_props->insn_string="lf.sfgt.d";
|
break;
|
break;
|
case 0xb:
|
case 0xb:
|
insn_props->insn_string="lf.sfge.d";
|
insn_props->insn_string="lf.sfge.d";
|
break;
|
break;
|
case 0xc:
|
case 0xc:
|
insn_props->insn_string="lf.sflt.d";
|
insn_props->insn_string="lf.sflt.d";
|
break;
|
break;
|
case 0xd:
|
case 0xd:
|
insn_props->insn_string="lf.sfle.d";
|
insn_props->insn_string="lf.sfle.d";
|
break;
|
break;
|
default:
|
default:
|
printf("Unknown lf.xxx.d op (0x%x)",
|
printf("Unknown lf.xxx.d op (0x%x)",
|
insn_or1k_opcode_0x32_get_op_lo(insn));
|
insn_or1k_opcode_0x32_get_op_lo(insn));
|
break;
|
break;
|
}
|
}
|
break;
|
break;
|
|
|
case 0xd:
|
case 0xd:
|
insn_props->insn_string="lf.cust1.s";
|
insn_props->insn_string="lf.cust1.s";
|
break;
|
break;
|
|
|
case 0xe:
|
case 0xe:
|
insn_props->insn_string="lf.cust1.d";
|
insn_props->insn_string="lf.cust1.d";
|
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:
|
insn_props->insn_string="l.sd";
|
insn_props->insn_string="l.sd";
|
break;
|
break;
|
|
|
case 0x35:
|
case 0x35:
|
insn_props->insn_string="l.sw";
|
insn_props->insn_string="l.sw";
|
break;
|
break;
|
|
|
case 0x36:
|
case 0x36:
|
insn_props->insn_string="l.sb";
|
insn_props->insn_string="l.sb";
|
break;
|
break;
|
|
|
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";
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
insn_props->insn_string="l.sub";
|
insn_props->insn_string="l.sub";
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
insn_props->insn_string="l.and";
|
insn_props->insn_string="l.and";
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
insn_props->insn_string="l.or";
|
insn_props->insn_string="l.or";
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
insn_props->insn_string="l.xor";
|
insn_props->insn_string="l.xor";
|
break;
|
break;
|
case 0x6:
|
case 0x6:
|
insn_props->insn_string="l.mul";
|
insn_props->insn_string="l.mul";
|
break;
|
break;
|
case 0x8:
|
case 0x8:
|
switch (insn_or1k_opcode_0x38_get_op_hi_4bit(insn))
|
switch (insn_or1k_opcode_0x38_get_op_hi_4bit(insn))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
insn_props->insn_string="l.sll";
|
insn_props->insn_string="l.sll";
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
insn_props->insn_string="l.srl";
|
insn_props->insn_string="l.srl";
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
insn_props->insn_string="l.sra";
|
insn_props->insn_string="l.sra";
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
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";
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
insn_props->insn_string="l.divu";
|
insn_props->insn_string="l.divu";
|
break;
|
break;
|
case 0xb:
|
case 0xb:
|
insn_props->insn_string="l.mulu";
|
insn_props->insn_string="l.mulu";
|
break;
|
break;
|
case 0xc:
|
case 0xc:
|
switch(insn_or1k_opcode_0x38_get_op_hi_4bit(insn))
|
switch(insn_or1k_opcode_0x38_get_op_hi_4bit(insn))
|
{
|
{
|
case 0x0:
|
case 0x0:
|
insn_props->insn_string="l.exths";
|
insn_props->insn_string="l.exths";
|
break;
|
break;
|
case 0x1:
|
case 0x1:
|
insn_props->insn_string="l.extbs";
|
insn_props->insn_string="l.extbs";
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
insn_props->insn_string="l.exthz";
|
insn_props->insn_string="l.exthz";
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
insn_props->insn_string="l.extbz";
|
insn_props->insn_string="l.extbz";
|
break;
|
break;
|
}
|
}
|
insn_props->has_rB = 0;
|
insn_props->has_rB = 0;
|
break;
|
break;
|
|
|
case 0xd:
|
case 0xd:
|
insn_props->insn_string="l.extws";
|
insn_props->insn_string="l.extws";
|
insn_props->has_rB = 0;
|
insn_props->has_rB = 0;
|
break;
|
break;
|
|
|
case 0xe:
|
case 0xe:
|
insn_props->insn_string="l.cmov";
|
insn_props->insn_string="l.cmov";
|
break;
|
break;
|
|
|
case 0xf:
|
case 0xf:
|
if (insn_or1k_opcode_0x38_get_op_hi_2bit(insn) & 0x1)
|
if (insn_or1k_opcode_0x38_get_op_hi_2bit(insn) & 0x1)
|
insn_props->insn_string="l.fl1";
|
insn_props->insn_string="l.fl1";
|
else
|
else
|
insn_props->insn_string="l.ff1";
|
insn_props->insn_string="l.ff1";
|
insn_props->has_rB = 0;
|
insn_props->has_rB = 0;
|
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";
|
break;
|
break;
|
case 0x2:
|
case 0x2:
|
insn_props->insn_string="l.sfgtu";
|
insn_props->insn_string="l.sfgtu";
|
break;
|
break;
|
case 0x3:
|
case 0x3:
|
insn_props->insn_string="l.sfgeu";
|
insn_props->insn_string="l.sfgeu";
|
break;
|
break;
|
case 0x4:
|
case 0x4:
|
insn_props->insn_string="l.sfltu";
|
insn_props->insn_string="l.sfltu";
|
break;
|
break;
|
case 0x5:
|
case 0x5:
|
insn_props->insn_string="l.sfleu";
|
insn_props->insn_string="l.sfleu";
|
break;
|
break;
|
case 0xa:
|
case 0xa:
|
insn_props->insn_string="l.sfgts";
|
insn_props->insn_string="l.sfgts";
|
break;
|
break;
|
case 0xb:
|
case 0xb:
|
insn_props->insn_string="l.sfges";
|
insn_props->insn_string="l.sfges";
|
break;
|
break;
|
case 0xc:
|
case 0xc:
|
insn_props->insn_string="l.sflts";
|
insn_props->insn_string="l.sflts";
|
break;
|
break;
|
case 0xd:
|
case 0xd:
|
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:
|
printf("Unknown opcode 0x%x",insn_or1k_opcode(insn));
|
printf("Unknown opcode 0x%x",insn_or1k_opcode(insn));
|
return 1;
|
return 1;
|
break;
|
break;
|
}
|
}
|
|
|
return 0;
|
return 0;
|
}
|
}
|
|
|
|
|
|
|
void or1k_32_collect_stats(uint32_t insn,
|
void or1k_32_collect_stats(uint32_t insn,
|
struct or1k_32_instruction_properties * insn_props)
|
struct or1k_32_instruction_properties * insn_props)
|
{
|
{
|
// First calculate frequency
|
// First calculate frequency
|
int index = insn_lists_check(insn, insn_props);
|
int index = insn_lists_check(insn, insn_props);
|
|
|
// Create new entry in list
|
// Create new entry in list
|
if (index == IS_UNIQUE)
|
if (index == IS_UNIQUE)
|
index = insn_lists_add_unique_insn(insn, insn_props);
|
index = insn_lists_add_unique_insn(insn, insn_props);
|
|
|
// Now count it
|
// Now count it
|
insn_lists_add(index, insn, insn_props);
|
insn_lists_add(index, insn, insn_props);
|
|
|
}
|
}
|
|
|
|
|
|
|
struct or1k_value_list
|
struct or1k_value_list
|
{
|
{
|
|
|
#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
|
{
|
{
|
char* insn_string;
|
char* insn_string;
|
|
|
int count;
|
int count;
|
|
|
int has_branchtarg;
|
int has_branchtarg;
|
struct or1k_value_list branch_info;
|
struct or1k_value_list branch_info;
|
|
|
int has_imm;
|
int has_imm;
|
|
|
struct or1k_value_list imm_info;
|
struct or1k_value_list imm_info;
|
|
|
int has_rD;
|
int has_rD;
|
int rD_use_freq[32];
|
int rD_use_freq[32];
|
int has_rA;
|
int has_rA;
|
int rA_use_freq[32];
|
int rA_use_freq[32];
|
int has_rB;
|
int has_rB;
|
int rB_use_freq[32];
|
int rB_use_freq[32];
|
|
|
};
|
};
|
|
|
#define OR1K_32_MAX_INSNS 120
|
#define OR1K_32_MAX_INSNS 120
|
struct or1k_insn_info * or1k_32_insns[OR1K_32_MAX_INSNS];
|
struct or1k_insn_info * or1k_32_insns[OR1K_32_MAX_INSNS];
|
|
|
|
|
// List management/analysis functions - accessed through insn_lists() set of
|
// List management/analysis functions - accessed through insn_lists() set of
|
// functions
|
// functions
|
|
|
// Variable to keep track of unique instructions we have
|
// Variable to keep track of unique instructions we have
|
int num_unique_insns;
|
int num_unique_insns;
|
int num_seen_insns;
|
int num_seen_insns;
|
|
|
|
|
void or1k_32_insn_lists_init(void)
|
void or1k_32_insn_lists_init(void)
|
{
|
{
|
num_unique_insns = 0;
|
num_unique_insns = 0;
|
num_seen_insns = 0;
|
num_seen_insns = 0;
|
}
|
}
|
|
|
// List management/analysis functions
|
// List management/analysis functions
|
int or1k_32_insn_lists_check(uint32_t insn,
|
int or1k_32_insn_lists_check(uint32_t insn,
|
struct or1k_32_instruction_properties *insn_props)
|
struct or1k_32_instruction_properties *insn_props)
|
{
|
{
|
|
|
int num_to_check = num_unique_insns;
|
int num_to_check = num_unique_insns;
|
int insn_strlen = strlen(insn_props->insn_string);
|
int insn_strlen = strlen(insn_props->insn_string);
|
while (num_to_check)
|
while (num_to_check)
|
{
|
{
|
|
|
--num_to_check;
|
--num_to_check;
|
|
|
if ((strncmp(insn_props->insn_string,
|
if ((strncmp(insn_props->insn_string,
|
or1k_32_insns[num_to_check]->insn_string, insn_strlen) == 0)
|
or1k_32_insns[num_to_check]->insn_string, insn_strlen) == 0)
|
&& (insn_strlen == strlen(or1k_32_insns[num_to_check]->insn_string)))
|
&& (insn_strlen == strlen(or1k_32_insns[num_to_check]->insn_string)))
|
{
|
{
|
// Found match by string
|
// Found match by string
|
return num_to_check;
|
return num_to_check;
|
}
|
}
|
}
|
}
|
|
|
return IS_UNIQUE;
|
return IS_UNIQUE;
|
}
|
}
|
|
|
// Add a unique instruction
|
// Add a unique instruction
|
int or1k_32_insn_lists_add_unique_insn(uint32_t insn,
|
int or1k_32_insn_lists_add_unique_insn(uint32_t insn,
|
struct or1k_32_instruction_properties *insn_props)
|
struct or1k_32_instruction_properties *insn_props)
|
{
|
{
|
// Add an instruction in or1k_32_insns[num_unique_instructions];
|
// Add an instruction in or1k_32_insns[num_unique_instructions];
|
// use calloc() so it clears it all first (hopefully!).. assumption!
|
// use calloc() so it clears it all first (hopefully!).. assumption!
|
struct or1k_insn_info * new_insn
|
struct or1k_insn_info * new_insn
|
= (struct or1k_insn_info *) calloc (sizeof(struct or1k_insn_info), 1);
|
= (struct or1k_insn_info *) calloc (sizeof(struct or1k_insn_info), 1);
|
|
|
// Calloc() space for the string
|
// Calloc() space for the string
|
new_insn->insn_string = (char *) calloc(strlen(insn_props->insn_string), 1);
|
new_insn->insn_string = (char *) calloc(strlen(insn_props->insn_string), 1);
|
|
|
// Copy in the instruction string
|
// Copy in the instruction string
|
strncpy(new_insn->insn_string, insn_props->insn_string,
|
strncpy(new_insn->insn_string, insn_props->insn_string,
|
strlen(insn_props->insn_string));
|
strlen(insn_props->insn_string));
|
|
|
// Install the pointer for this new instruction in the list
|
// Install the pointer for this new instruction in the list
|
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;
|
|
|
while(i)
|
while(i)
|
{
|
{
|
i--;
|
i--;
|
if(list->values[i][0] == value)
|
if(list->values[i][0] == value)
|
{
|
{
|
(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
|
void or1k_32_insn_lists_add(int index, uint32_t insn,
|
void or1k_32_insn_lists_add(int index, uint32_t insn,
|
struct or1k_32_instruction_properties *insn_props)
|
struct or1k_32_instruction_properties *insn_props)
|
{
|
{
|
// Add stats for this instruction
|
// Add stats for this instruction
|
|
|
// Increment count
|
// Increment count
|
((or1k_32_insns[index])->count)++;
|
((or1k_32_insns[index])->count)++;
|
|
|
// 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)
|
{
|
{
|
(or1k_32_insns[index])->has_rD = 1;
|
(or1k_32_insns[index])->has_rD = 1;
|
((or1k_32_insns[index])->rD_use_freq[insn_or1k_32_rD(insn)])++;
|
((or1k_32_insns[index])->rD_use_freq[insn_or1k_32_rD(insn)])++;
|
}
|
}
|
|
|
// Increment count of use for particular rA
|
// Increment count of use for particular rA
|
if (insn_props->has_rA)
|
if (insn_props->has_rA)
|
{
|
{
|
(or1k_32_insns[index])->has_rA = 1;
|
(or1k_32_insns[index])->has_rA = 1;
|
((or1k_32_insns[index])->rA_use_freq[insn_or1k_32_rA(insn)])++;
|
((or1k_32_insns[index])->rA_use_freq[insn_or1k_32_rA(insn)])++;
|
}
|
}
|
|
|
// Increment count of use for particular rB
|
// Increment count of use for particular rB
|
if (insn_props->has_rB)
|
if (insn_props->has_rB)
|
{
|
{
|
(or1k_32_insns[index])->has_rB = 1;
|
(or1k_32_insns[index])->has_rB = 1;
|
((or1k_32_insns[index])->rB_use_freq[insn_or1k_32_rB(insn)])++;
|
((or1k_32_insns[index])->rB_use_freq[insn_or1k_32_rB(insn)])++;
|
}
|
}
|
|
|
// Finished adding to stats for this instruction
|
// Finished adding to stats for this instruction
|
|
|
// Increment overall instructions "seen" counter
|
// Increment overall instructions "seen" counter
|
num_seen_insns++;
|
num_seen_insns++;
|
|
|
}
|
}
|
|
|
|
|
// Free up all added instruction statistic tracking structs
|
// Free up all added instruction statistic tracking structs
|
void or1k_32_insn_lists_free(void)
|
void or1k_32_insn_lists_free(void)
|
{
|
{
|
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
|