Update the machine code decode algorithm using hash table.

This commit is contained in:
M R Swami Reddy 2008-05-05 09:19:42 +00:00
parent fcfb8b02aa
commit 052d9a542f

View file

@ -14,8 +14,8 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>. */
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <signal.h>
#include "sysdep.h"
@ -28,8 +28,6 @@
#include "gdb/signals.h"
#include "opcode/cr16.h"
enum _leftright { LEFT_FIRST, RIGHT_FIRST };
static char *myname;
static SIM_OPEN_KIND sim_kind;
int cr16_debug;
@ -52,8 +50,10 @@ asection *text;
bfd_vma text_start;
bfd_vma text_end;
static void get_operands PARAMS ((operand_desc *s, uint64 mcode, int isize));
static void do_run PARAMS ((inst *ins, uint64 mc));
static long hash PARAMS ((uint64 linsn, int));
static struct hash_entry *lookup_hash PARAMS ((uint64 ins, int size));
static void get_operands PARAMS ((operand_desc *s, uint64 mcode, int isize, int nops));
static int do_run PARAMS ((uint64 mc));
static char *add_commas PARAMS ((char *buf, int sizeof_buf, unsigned long value));
extern void sim_set_profile PARAMS ((int n));
extern void sim_set_profile_size PARAMS ((int n));
@ -77,9 +77,72 @@ extern int (*deprecated_ui_loop_hook) PARAMS ((int signo));
#define INLINE
#endif
#endif
#define MAX_HASH 16
struct hash_entry
{
struct hash_entry *next;
uint32 opcode;
uint32 mask;
int format;
int size;
struct simops *ops;
};
struct hash_entry hash_table[MAX_HASH+1];
INLINE static long
hash(unsigned long long insn, int format)
{
unsigned int i = 4, tmp;
if (format)
{
while ((insn >> i) != 0) i +=4;
return ((insn >> (i-4)) & 0xf); /* Use last 4 bits as hask key. */
}
return ((insn & 0xF)); /* Use last 4 bits as hask key. */
}
INLINE static struct hash_entry *
lookup_hash (uint64 ins, int size)
{
uint32 mask;
struct hash_entry *h;
h = &hash_table[hash(ins,1)];
mask = (((1 << (32 - h->mask)) -1) << h->mask);
/* Adjuest mask for branch with 2 word instructions. */
if ((h->ops->mnimonic != NULL) &&
((streq(h->ops->mnimonic,"b") && h->size == 2)))
mask = 0xff0f0000;
while ((ins & mask) != (BIN(h->opcode, h->mask)))
{
if (h->next == NULL)
{
State.exception = SIGILL;
State.pc_changed = 1; /* Don't increment the PC. */
return NULL;
}
h = h->next;
mask = (((1 << (32 - h->mask)) -1) << h->mask);
/* Adjuest mask for branch with 2 word instructions. */
if ((streq(h->ops->mnimonic,"b")) && h->size == 2)
mask = 0xff0f0000;
}
return (h);
}
INLINE static void
get_operands (operand_desc *s, uint64 ins, int isize)
get_operands (operand_desc *s, uint64 ins, int isize, int nops)
{
uint32 i, opn = 0, start_bit = 0, op_type = 0;
int32 op_size = 0, mask = 0;
@ -87,13 +150,11 @@ get_operands (operand_desc *s, uint64 ins, int isize)
if (isize == 1) /* Trunkcate the extra 16 bits of INS. */
ins = ins >> 16;
for (i=0; i < 3; ++i,++opn)
for (i=0; i < 4; ++i,++opn)
{
if ((s[opn].op_type == dummy) || (s[opn].op_type > cr16_num_optab))
break;
else
op_type = s[opn].op_type;
if (s[opn].op_type == dummy) break;
op_type = s[opn].op_type;
start_bit = s[opn].shift;
op_size = cr16_optab[op_type].bit_size;
@ -116,10 +177,16 @@ get_operands (operand_desc *s, uint64 ins, int isize)
break;
case uimm3: case uimm3_1: case uimm4_1:
if (isize == 1)
OP[i] = ((ins >> 4) & ((1 << op_size) -1));
else
OP[i] = ((ins >> (32 - start_bit)) & ((1 << op_size) -1));
switch (isize)
{
case 1:
OP[i] = ((ins >> 4) & ((1 << op_size) -1)); break;
case 2:
OP[i] = ((ins >> (32 - start_bit)) & ((1 << op_size) -1));break;
default: /* for case 3. */
OP[i] = ((ins >> (16 + start_bit)) & ((1 << op_size) -1)); break;
break;
}
break;
case uimm4:
@ -280,18 +347,18 @@ get_operands (operand_desc *s, uint64 ins, int isize)
default: break;
}
/* For ESC on uimm4_1 operand */
/* For ESC on uimm4_1 operand. */
if (op_type == uimm4_1)
if (OP[i] == 9)
OP[i] = -1;
/* For increment by 1. */
if ((op_type == pregr) || (op_type == pregrp))
OP[i] += 1;
}
/* FIXME: for tracing, update values that need to be updated each
instruction decode cycle */
#if 0 // DEBUG
(*cr16_callback->printf_filtered) (cr16_callback, "OP0=0x%X\t,OP1=0x%X\t,OP2=0x%X\t,OP3=0X%X\n",OP[0],OP[1],OP[2],OP[3]);
#endif
State.trace.psw = PSR;
}
bfd_vma
@ -316,35 +383,44 @@ decode_pc ()
static void
do_run(inst *instruction, uint64 mcode)
static int
do_run(uint64 mcode)
{
struct simops *s= Simops;
struct hash_entry *h;
char func[12]="\0";
uint8 *iaddr;
#ifdef DEBUG
if ((cr16_debug & DEBUG_INSTRUCTION) != 0)
(*cr16_callback->printf_filtered) (cr16_callback, "do_long 0x%x\n", instruction);
(*cr16_callback->printf_filtered) (cr16_callback, "do_long 0x%x\n", mcode);
#endif
/* Re-set OP list */
h = lookup_hash(mcode, 1);
if ((h == NULL) || (h->opcode == NULL)) return 0;
if (h->size == 3)
{
iaddr = imem_addr ((uint32)PC + 2);
mcode = (mcode << 16) | get_longword( iaddr );
}
/* Re-set OP list. */
OP[0] = OP[1] = OP[2] = OP[3] = sign_flag = 0;
/* for push/pop/pushrtn with RA instructions */
if ((INST_HAS_REG_LIST) && (mcode & 0x800000))
OP[2] = 1; /* Set 1 for RA operand */
/* for push/pop/pushrtn with RA instructions. */
if ((h->format & REG_LIST) && (mcode & 0x800000))
OP[2] = 1; /* Set 1 for RA operand. */
get_operands (&instruction->operands, mcode, instruction->size);
/* numops == 0 means, no operands. */
if (((h->ops) != NULL) && (((h->ops)->numops) != 0))
get_operands ((h->ops)->operands, mcode, h->size, (h->ops)->numops);
State.ins_type = instruction->flags;
//ins_type_counters[ (int)State.ins_type ]++;
sprintf(func,"OP_%X_%X",instruction->match,(32 - instruction->match_bits));
/* Check for appropriate opcode function */
for ( ;s->opcode!=0;s++)
{
if (strcmp(s->fname,func) == 0)
break;
}
(s->func)();
//State.ins_type = h->flags;
(h->ops->func)();
return h->size;
}
static char *
@ -600,10 +676,8 @@ sim_cr16_translate_imap_addr (unsigned long offset,
}
unsigned long
sim_cr16_translate_addr (unsigned long memaddr,
int nr_bytes,
unsigned long *targ_addr,
void *regcache,
sim_cr16_translate_addr (unsigned long memaddr, int nr_bytes,
unsigned long *targ_addr, void *regcache,
unsigned long (*dmap_register) (void *regcache,
int reg_nr),
unsigned long (*imap_register) (void *regcache,
@ -828,11 +902,11 @@ sim_read (sd, addr, buffer, size)
return xfer_mem( addr, buffer, size, 0);
}
SIM_DESC
sim_open (SIM_OPEN_KIND kind, struct host_callback_struct *callback, struct bfd *abfd, char **argv)
{
struct simops *s;
struct hash_entry *h;
static int init_p = 0;
char **p;
@ -860,6 +934,112 @@ sim_open (SIM_OPEN_KIND kind, struct host_callback_struct *callback, struct bfd
}
#endif
/* put all the opcodes in the hash table. */
if (!init_p++)
{
for (s = Simops; s->func; s++)
{
switch(32 - s->mask)
{
case 0x4:
h = &hash_table[hash(s->opcode, 0)];
break;
case 0x7:
if (((s->opcode << 1) >> 4) != 0)
h = &hash_table[hash((s->opcode << 1) >> 4, 0)];
else
h = &hash_table[hash((s->opcode << 1), 0)];
break;
case 0x8:
if ((s->opcode >> 4) != 0)
h = &hash_table[hash(s->opcode >> 4, 0)];
else
h = &hash_table[hash(s->opcode, 0)];
break;
case 0x9:
if (((s->opcode >> 1) >> 4) != 0)
h = &hash_table[hash((s->opcode >>1) >> 4, 0)];
else
h = &hash_table[hash((s->opcode >> 1), 0)];
break;
case 0xa:
if ((s->opcode >> 8) != 0)
h = &hash_table[hash(s->opcode >> 8, 0)];
else if ((s->opcode >> 4) != 0)
h = &hash_table[hash(s->opcode >> 4, 0)];
else
h = &hash_table[hash(s->opcode, 0)];
break;
case 0xc:
if ((s->opcode >> 8) != 0)
h = &hash_table[hash(s->opcode >> 8, 0)];
else if ((s->opcode >> 4) != 0)
h = &hash_table[hash(s->opcode >> 4, 0)];
else
h = &hash_table[hash(s->opcode, 0)];
break;
case 0xd:
if (((s->opcode >> 1) >> 8) != 0)
h = &hash_table[hash((s->opcode >>1) >> 8, 0)];
else if (((s->opcode >> 1) >> 4) != 0)
h = &hash_table[hash((s->opcode >>1) >> 4, 0)];
else
h = &hash_table[hash((s->opcode >>1), 0)];
break;
case 0x10:
if ((s->opcode >> 0xc) != 0)
h = &hash_table[hash(s->opcode >> 12, 0)];
else if ((s->opcode >> 8) != 0)
h = &hash_table[hash(s->opcode >> 8, 0)];
else if ((s->opcode >> 4) != 0)
h = &hash_table[hash(s->opcode >> 4, 0)];
else
h = &hash_table[hash(s->opcode, 0)];
break;
case 0x14:
if ((s->opcode >> 16) != 0)
h = &hash_table[hash(s->opcode >> 16, 0)];
else if ((s->opcode >> 12) != 0)
h = &hash_table[hash(s->opcode >> 12, 0)];
else if ((s->opcode >> 8) != 0)
h = &hash_table[hash(s->opcode >> 8, 0)];
else if ((s->opcode >> 4) != 0)
h = &hash_table[hash(s->opcode >> 4, 0)];
else
h = &hash_table[hash(s->opcode, 0)];
break;
default:
break;
}
/* go to the last entry in the chain. */
while (h->next)
h = h->next;
if (h->ops)
{
h->next = (struct hash_entry *) calloc(1,sizeof(struct hash_entry));
if (!h->next)
perror ("malloc failure");
h = h->next;
}
h->ops = s;
h->mask = s->mask;
h->opcode = s->opcode;
h->format = s->format;
h->size = s->size;
}
}
/* reset the processor state */
if (!State.mem.data[0])
sim_size (1);
@ -969,7 +1149,7 @@ sim_stop (sd)
void
sim_resume (SIM_DESC sd, int step, int siggnal)
{
uint32 mask = 0, ins_found = 0;
uint32 curr_ins_size = 0;
uint64 mcode = 0;
uint8 *iaddr;
@ -1009,7 +1189,6 @@ sim_resume (SIM_DESC sd, int step, int siggnal)
do
{
iaddr = imem_addr ((uint32)PC);
ins_found = 0;
if (iaddr == State.mem.fault)
{
State.exception = SIGBUS;
@ -1020,77 +1199,26 @@ sim_resume (SIM_DESC sd, int step, int siggnal)
State.pc_changed = 0;
/* Start searching from end of instruction table. */
const inst *instruction = &cr16_instruction[NUMOPCODES - 2];
/* Loop over instruction table until a full match is found. */
while (instruction >= cr16_instruction)
{
mask = (((1 << (32 - instruction->match_bits)) -1) <<
instruction->match_bits);
/* Adjuest mask for branch with 2 word instructions. */
if ((IS_INSN_MNEMONIC("b") && instruction->size == 2))
mask = 0xff0f0000;
if ((mcode & mask) == (BIN(instruction->match, instruction->match_bits)))
{
ins_found = 1;
break;
}
else
instruction--;
}
curr_ins_size = do_run(mcode);
#if CR16_DEBUG
(*cr16_callback->printf_filtered) (cr16_callback, "INS: PC=0x%X, mcode=0x%X\n",PC,mcode);
#endif
if ((mcode == 0x0L) /*|| (!ins_found )*/)
if (!State.pc_changed)
{
if (curr_ins_size == 0)
{
State.exception = SIG_CR16_EXIT; /* exit trap */
break;
}
/* Check if the ins_found is '0', then set illigel instruction trap */
if ( !ins_found )
State.exception = SIGILL;
else
{
/* For 3 word instructions only */
if (instruction->size == 3)
{
iaddr = imem_addr ((uint32)PC + 2);
mcode = (mcode << 16) | get_longword( iaddr );
}
do_run(instruction, mcode);
}
/* If the PC of the current instruction matches RPT_E then
schedule a branch to the loop start. If one of those
instructions happens to be a branch, than that instruction
will be ignored */
if (!State.pc_changed)
{
switch (instruction->size)
{
case 1:
SET_PC (PC + 2); /* For 1 word instructions */
break;
case 2:
SET_PC (PC + 4); /* For 2 word instructions */
break;
case 3:
SET_PC (PC + 6); /* For 3 word instructions */
break;
default: break;
}
SET_PC (PC + (curr_ins_size * 2)); /* For word instructions. */
}
#if 0
/* Check for a breakpoint trap on this instruction. This
overrides any pending branches or loops */
#if 0
if (PSR_DB && PC == DBS)
{
SET_BPC (PC);