URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/or1k/tags/nog_patch_65/or1ksim/cpu/or32
- from Rev 1456 to Rev 1765
- ↔ Reverse comparison
Rev 1456 → Rev 1765
/op_comp_op.h
0,0 → 1,151
/* op_comp_op.h -- Micro operations template for comparison operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
__or_dynop void glue(glue(op_, COMP_NAME), _t0_t0)(void) |
{ |
if(COMP_CAST(t0) COMP COMP_CAST(t0)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _t0_t1)(void) |
{ |
if(COMP_CAST(t0) COMP COMP_CAST(t1)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _t0_t2)(void) |
{ |
if(COMP_CAST(t0) COMP COMP_CAST(t2)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _t1_t0)(void) |
{ |
if(COMP_CAST(t1) COMP COMP_CAST(t0)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _t1_t1)(void) |
{ |
if(COMP_CAST(t1) COMP COMP_CAST(t1)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _t1_t2)(void) |
{ |
if(COMP_CAST(t1) COMP COMP_CAST(t2)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _t2_t0)(void) |
{ |
if(COMP_CAST(t2) COMP COMP_CAST(t0)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _t2_t1)(void) |
{ |
if(COMP_CAST(t2) COMP COMP_CAST(t1)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _t2_t2)(void) |
{ |
if(COMP_CAST(t2) COMP COMP_CAST(t2)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _imm_t0)(void) |
{ |
if(COMP_CAST(t0) COMP COMP_CAST(OP_PARAM1)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _imm_t1)(void) |
{ |
if(COMP_CAST(t1) COMP COMP_CAST(OP_PARAM1)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _imm_t2)(void) |
{ |
if(COMP_CAST(t2) COMP COMP_CAST(OP_PARAM1)) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _null_t0)(void) |
{ |
if(COMP_CAST(t0) COMP 0) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _null_t1)(void) |
{ |
if(COMP_CAST(t1) COMP 0) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
|
__or_dynop void glue(glue(op_, COMP_NAME), _null_t2)(void) |
{ |
if(COMP_CAST(t2) COMP 0) |
env->sprs[SPR_SR] |= SPR_SR_F; |
else |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
FORCE_RET; |
} |
/dyn_rec_stubs.c
0,0 → 1,262
/* dyn_rec_stubs.c -- Stubs to allow the recompiler to be run standalone |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
/* Stubs to test the recompiler */ |
#include <stdio.h> |
#include <string.h> |
#include <errno.h> |
#include <byteswap.h> |
#include <stdlib.h> |
#include <inttypes.h> |
|
#include "arch.h" |
#include "immu.h" |
#include "spr_defs.h" |
#include "opcode/or32.h" |
#include "abstract.h" |
#include "execute.h" |
#include "sim-config.h" |
#include "sched.h" |
|
#include "i386_regs.h" |
#include "dyn_rec.h" |
|
#define PAGE_LEN 8192 |
|
int do_stats = 0; |
|
/* NOTE: Directly copied from execute.c */ |
uorreg_t eval_operand_val(uint32_t insn, struct insn_op_struct *opd) |
{ |
unsigned long operand = 0; |
unsigned long sbit; |
unsigned int nbits = 0; |
|
while(1) { |
operand |= ((insn >> (opd->type & OPTYPE_SHR)) & ((1 << opd->data) - 1)) << nbits; |
nbits += opd->data; |
|
if(opd->type & OPTYPE_OP) |
break; |
opd++; |
} |
|
if(opd->type & OPTYPE_SIG) { |
sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR; |
if(operand & (1 << sbit)) operand |= ~REG_C(0) << sbit; |
} |
|
return operand; |
} |
|
oraddr_t immu_translate(oraddr_t virtaddr) |
{ |
return virtaddr; |
} |
|
oraddr_t peek_into_itlb(oraddr_t virtaddr) |
{ |
return virtaddr; |
} |
|
void do_scheduler() |
{ |
return; |
} |
|
static uint32_t page[PAGE_LEN / 4]; |
|
uint32_t eval_insn(oraddr_t addr, int *brkp) |
{ |
if(addr >= PAGE_LEN) { |
fprintf(stderr, "DR is trying to access memory outside the boundries of a page %08x\n", addr); |
return 0; |
} |
|
return bswap_32(page[addr / 4]); |
} |
|
int main(int argc, char **argv) |
{ |
FILE *f; |
long len; |
int i; |
struct dyn_page *dp; |
long off = 0; |
|
if((argc < 3) || (argc > 4)) { |
fprintf(stderr, "Usage: %s <binary file to recompile> <output code file> [offset into the file]\n", |
argv[0]); |
return 1; |
} |
|
if(argc == 4) |
off = strtol(argv[3], NULL, 0); |
|
f = fopen(argv[1], "r"); |
if(!f) { |
fprintf(stderr, "Unable to open %s: %s\n", argv[1], strerror(errno)); |
return 1; |
} |
|
if(fseek(f, 0, SEEK_END)) { |
fprintf(stderr, "Uanble to seek to the end of the file %s: %s\n", argv[1], |
strerror(errno)); |
return 1; |
} |
|
len = ftell(f); |
|
if(len == -1) { |
fprintf(stderr, "Unable to determine file length: %s\n", strerror(errno)); |
return 1; |
} |
|
fseek(f, off, SEEK_SET); |
|
if((len - off) < PAGE_LEN) { |
printf("File is less than 1 page long, padding with zeros.\n"); |
fread(page, len, 1, f); |
/* Pad the page with zeros */ |
for(i = len; i < PAGE_LEN; i++) |
page[i] = 0; |
} else |
fread(page, PAGE_LEN, 1, f); |
|
fclose(f); |
|
build_automata(); |
init_dyn_recomp(); |
|
dp = new_dp(0); |
|
/* Cool, recompile the page */ |
fprintf(stderr, "Hold on a sec, I'm recompileing the given page...\n"); |
|
recompile_page(dp); |
|
fprintf(stderr, "Recompiled page length: %i\n", dp->host_len); |
fprintf(stderr, "Dumping reced page to disk...\n"); |
|
f = fopen(argv[2], "w"); |
fwrite(dp->host_page, dp->host_len, 1, f); |
fclose(f); |
|
/* |
printf("--- Recompiled or disassembly ---\n"); |
for(i = 0; i < 2048; i++) { |
extern char *disassembled; |
disassemble_insn(eval_insn(i * 4, NULL)); |
if(!eval_insn(i * 4, NULL)) continue; |
printf("%04x: %08x %s\n", i * 4, eval_insn(i * 4, NULL), disassembled); |
} |
printf("--- Recompiled or disassembly end ---\n"); |
*/ |
|
dump_xrefs(dp, stdout); |
|
destruct_automata(); |
|
return 0; |
} |
|
/* Lame linker stubs. These are only referenced in the recompiled code */ |
struct cpu_state cpu_state; |
struct runtime runtime; |
struct scheduler_struct scheduler; |
struct config config; |
int immu_ex_from_insn; |
|
/* FIXME: This needs to go */ |
oraddr_t pcprev; |
|
/* FIXME: eval_insn should become this */ |
uint32_t eval_insn_direct(oraddr_t memaddr, int* breakpoint, int through_mmu) |
{ |
return 0; |
} |
|
uint32_t eval_direct32(oraddr_t memaddr, int *breakpoint, int through_mmu, |
int through_dc) |
{ |
return 0; |
} |
|
uint32_t eval_mem32(oraddr_t addr, int *breakpoint) |
{ |
return 0; |
} |
|
uint16_t eval_mem16(oraddr_t addr, int *breakpoint) |
{ |
return 0; |
} |
|
uint8_t eval_mem8(oraddr_t addr, int *breakpoint) |
{ |
return 0; |
} |
|
void set_mem32(oraddr_t addr, uint32_t val, int *breakpoint) |
{ |
} |
|
void set_mem16(oraddr_t addr, uint16_t val, int *breakpoint) |
{ |
} |
|
void set_mem8(oraddr_t addr, uint8_t val, int *breakpoint) |
{ |
} |
|
void analysis(struct iqueue_entry *current) |
{ |
} |
|
void mtspr(uint16_t regno, const uorreg_t value) |
{ |
} |
|
unsigned long spr_read_ttcr(void) |
{ |
return 0; |
} |
|
void debug(int level, const char *format,...) |
{ |
} |
|
void simprintf(oraddr_t stackaddr, unsigned long regparam) |
{ |
} |
|
const char *except_name(oraddr_t except) |
{ |
return NULL; |
} |
|
struct dev_memarea *verify_memoryarea(oraddr_t addr) |
{ |
return NULL; |
} |
|
void sim_done (void) |
{ |
} |
/op_swhb_op.h
0,0 → 1,150
/* op_swhb_op.h -- Micro operations template for store operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
/* FIXME: Do something with breakpoint */ |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _t0_t0)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t0 + OP_PARAM1, t0, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _t0_t1)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t0 + OP_PARAM1, t1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _t0_t2)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t0 + OP_PARAM1, t2, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _t1_t1)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t1 + OP_PARAM1, t1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _t1_t0)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t1 + OP_PARAM1, t0, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _t1_t2)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t1 + OP_PARAM1, t2, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _t2_t0)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t2 + OP_PARAM1, t0, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _t2_t1)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t2 + OP_PARAM1, t1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _t2_t2)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t2 + OP_PARAM1, t2, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _imm_t0)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(OP_PARAM1, t0, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _imm_t1)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(OP_PARAM1, t1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _imm_t2)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(OP_PARAM1, t2, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _clear_t0)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t0 + OP_PARAM1, 0, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _clear_t1)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t1 + OP_PARAM1, 0, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _clear_t2)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(t2 + OP_PARAM1, 0, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, S_OP_NAME), _clear_imm)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
S_FUNC(OP_PARAM1, 0, &breakpoint); |
} |
|
/sched_i386.h
0,0 → 1,40
/* sched_i386.h -- i386 specific support routines for the scheduler |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
/* Sets the cycle counter to a specific value */ |
static inline void set_sched_cycle(int32_t job_time) |
{ |
union { |
uint64_t val64; |
union { |
uint32_t low32; |
uint32_t high32; |
} val3232; |
} time_pc; |
|
asm("movq %%mm0, %0\n" |
"\tmovl %2, %1\n" |
"\tmovq %3, %%mm0\n" |
: "=m" (time_pc.val64), |
"=m" (time_pc.val3232.low32) |
: "r" (job_time), |
"m" (time_pc.val64)); |
} |
|
/dyn32_defs.h
0,0 → 1,114
/* dyn32_defs.h -- Definitions for the complex execution model |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
struct op_queue { |
unsigned int num_ops; |
unsigned int ops_len; |
unsigned int *ops; |
unsigned int num_ops_param; |
unsigned int ops_param_len; |
unsigned int *ops_param; |
int jump_local; /* Is this instruction a page-local jump */ |
unsigned int *jump_local_loc; /* Points to the parameter that holds the location of the jump */ |
struct x_ref *xref; /* Cross-reference of the page-local jump */ |
oraddr_t insn_addr; /* Physical address of the instruction */ |
unsigned int reg_t[3]; /* Which registers are in the temporaries? */ |
struct op_queue *prev; |
struct op_queue *next; |
}; |
|
void gen_l_add PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_addc PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_and PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_bf PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_bnf PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_cmov PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_cust1 PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_cust2 PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_cust3 PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_cust4 PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_div PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_divu PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_extbs PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_extbz PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_exths PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_exthz PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_extws PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_extwz PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_ff1 PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_j PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_jal PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_jr PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_jalr PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_lbs PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_lbz PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_lhs PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_lhz PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_lws PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_lwz PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_mac PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_macrc PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_mfspr PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_movhi PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_msb PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_mtspr PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_mul PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_mulu PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_nop PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_or PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_rfe PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sb PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sh PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sw PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sfeq PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sfges PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sfgeu PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sfgts PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sfgtu PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sfles PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sfleu PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sflts PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sfltu PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sfne PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sll PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sra PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_srl PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sub PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_sys PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_trap PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_xor PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_l_invalid PARAMS((struct op_queue *, int *, orreg_t *, int)); |
|
void gen_lf_add_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_div_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_ftoi_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_itof_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_madd_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_mul_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_rem_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_sfeq_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_sfge_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_sfgt_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_sfle_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_sflt_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_sfne_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void gen_lf_sub_s PARAMS((struct op_queue *, int *, orreg_t *, int)); |
void l_none(struct op_queue *opq, int *param_t, orreg_t *param, int delay_slot); |
|
/op_arith_op.h
0,0 → 1,201
/* op_arith_op.h -- Micro operations template for arithmetic operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t0_t0)(void) |
{ |
OP_CAST(t0) = OP_CAST(t0) OP OP_CAST(t0) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t0_t1)(void) |
{ |
OP_CAST(t0) = OP_CAST(t0) OP OP_CAST(t1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t0_t2)(void) |
{ |
OP_CAST(t0) = OP_CAST(t0) OP OP_CAST(t2) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t1_t0)(void) |
{ |
OP_CAST(t0) = OP_CAST(t1) OP OP_CAST(t0) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t1_t1)(void) |
{ |
OP_CAST(t0) = OP_CAST(t1) OP OP_CAST(t1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t1_t2)(void) |
{ |
OP_CAST(t0) = OP_CAST(t1) OP OP_CAST(t2) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t2_t0)(void) |
{ |
OP_CAST(t0) = OP_CAST(t2) OP OP_CAST(t0) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t2_t1)(void) |
{ |
OP_CAST(t0) = OP_CAST(t2) OP OP_CAST(t1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t2_t2)(void) |
{ |
OP_CAST(t0) = OP_CAST(t2) OP OP_CAST(t2) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t0_t0)(void) |
{ |
OP_CAST(t1) = OP_CAST(t0) OP OP_CAST(t0) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t0_t1)(void) |
{ |
OP_CAST(t1) = OP_CAST(t0) OP OP_CAST(t1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t0_t2)(void) |
{ |
OP_CAST(t1) = OP_CAST(t0) OP OP_CAST(t2) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t1_t0)(void) |
{ |
OP_CAST(t1) = OP_CAST(t1) OP OP_CAST(t0) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t1_t1)(void) |
{ |
OP_CAST(t1) = OP_CAST(t1) OP OP_CAST(t1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t1_t2)(void) |
{ |
OP_CAST(t1) = OP_CAST(t1) OP OP_CAST(t2) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t2_t0)(void) |
{ |
OP_CAST(t1) = OP_CAST(t2) OP OP_CAST(t0) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t2_t1)(void) |
{ |
OP_CAST(t1) = OP_CAST(t2) OP OP_CAST(t1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t2_t2)(void) |
{ |
OP_CAST(t1) = OP_CAST(t2) OP OP_CAST(t2) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t2_t0_t0)(void) |
{ |
OP_CAST(t2) = OP_CAST(t0) OP OP_CAST(t0) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t2_t0_t1)(void) |
{ |
OP_CAST(t2) = OP_CAST(t0) OP OP_CAST(t1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t2_t0_t2)(void) |
{ |
OP_CAST(t2) = OP_CAST(t0) OP OP_CAST(t2) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t2_t1_t0)(void) |
{ |
OP_CAST(t2) = OP_CAST(t1) OP OP_CAST(t0) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t2_t1_t1)(void) |
{ |
OP_CAST(t2) = OP_CAST(t1) OP OP_CAST(t1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t2_t1_t2)(void) |
{ |
OP_CAST(t2) = OP_CAST(t1) OP OP_CAST(t2) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t2_t2_t0)(void) |
{ |
OP_CAST(t2) = OP_CAST(t2) OP OP_CAST(t0) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t2_t2_t1)(void) |
{ |
OP_CAST(t2) = OP_CAST(t2) OP OP_CAST(t1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t2_t2_t2)(void) |
{ |
OP_CAST(t2) = OP_CAST(t2) OP OP_CAST(t2) OP_EXTRA; |
} |
|
#ifdef OP_HAS_IMM |
__or_dynop void glue(glue(op_, OP_NAME), _imm_t0_t0)(void) |
{ |
OP_CAST(t0) = OP_CAST(t0) OP OP_CAST(OP_PARAM1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _imm_t0_t1)(void) |
{ |
OP_CAST(t0) = OP_CAST(t1) OP OP_CAST(OP_PARAM1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _imm_t0_t2)(void) |
{ |
OP_CAST(t0) = OP_CAST(t2) OP OP_CAST(OP_PARAM1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _imm_t1_t0)(void) |
{ |
OP_CAST(t1) = OP_CAST(t0) OP OP_CAST(OP_PARAM1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _imm_t1_t1)(void) |
{ |
OP_CAST(t1) = OP_CAST(t1) OP OP_CAST(OP_PARAM1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _imm_t1_t2)(void) |
{ |
OP_CAST(t1) = OP_CAST(t2) OP OP_CAST(OP_PARAM1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _imm_t2_t0)(void) |
{ |
OP_CAST(t2) = OP_CAST(t0) OP OP_CAST(OP_PARAM1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _imm_t2_t1)(void) |
{ |
OP_CAST(t2) = OP_CAST(t1) OP OP_CAST(OP_PARAM1) OP_EXTRA; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _imm_t2_t2)(void) |
{ |
OP_CAST(t2) = OP_CAST(t2) OP OP_CAST(OP_PARAM1) OP_EXTRA; |
} |
#endif /* OP_HAS_IMM */ |
/op_support.c
0,0 → 1,345
/* op_support.c -- Support routines for micro operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
#include <stdlib.h> |
|
#include "config.h" |
|
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
|
#include "port.h" |
#include "arch.h" |
#include "opcode/or32.h" |
#include "sim-config.h" |
#include "spr_defs.h" |
#include "except.h" |
#include "immu.h" |
#include "abstract.h" |
#include "execute.h" |
#include "sched.h" |
|
#include "i386_regs.h" |
|
#include "dyn_rec.h" |
#include "op_support.h" |
|
#include "rec_i386.h" |
|
/* Stuff that is really a `micro' operation but is rather big (or for some other |
* reason (like calling exit()) */ |
|
void upd_reg_from_t(oraddr_t pc) |
{ |
int reg; |
|
reg = cpu_state.curr_page->ts[(pc & (PAGE_SIZE - 1)) / 2]; |
|
if(reg & 0x1f) |
cpu_state.reg[reg & 0x1f] = cpu_state.t0; |
|
if((reg >> 5) & 0x1f) |
cpu_state.reg[(reg >> 5) & 0x1f] = cpu_state.t1; |
|
if((reg >> 10) & 0x1f) |
cpu_state.reg[(reg >> 10) & 0x1f] = cpu_state.t2; |
} |
|
void op_support_nop_exit(void) |
{ |
upd_reg_from_t(get_pc()); |
PRINTF("exit(%"PRIdREG")\n", cpu_state.reg[3]); |
fprintf(stderr, "@reset : cycles %lld, insn #%lld\n", |
runtime.sim.reset_cycles, runtime.cpu.reset_instructions); |
fprintf(stderr, "@exit : cycles %lld, insn #%lld\n", runtime.sim.cycles, |
runtime.cpu.instructions); |
fprintf(stderr, " diff : cycles %lld, insn #%lld\n", |
runtime.sim.cycles - runtime.sim.reset_cycles, |
runtime.cpu.instructions - runtime.cpu.reset_instructions); |
/* FIXME: Implement emulation of a stalled cpu |
if (config.debug.gdb_enabled) |
set_stall_state (1); |
else |
runtime.sim.cont_run = 0; |
*/ |
exit(0); |
} |
|
void op_support_nop_reset(void) |
{ |
PRINTF("****************** counters reset ******************\n"); |
PRINTF("cycles %lld, insn #%lld\n", runtime.sim.cycles, runtime.cpu.instructions); |
PRINTF("****************** counters reset ******************\n"); |
runtime.sim.reset_cycles = runtime.sim.cycles; |
runtime.cpu.reset_instructions = runtime.cpu.instructions; |
} |
|
void op_support_nop_printf(void) |
{ |
upd_reg_from_t(get_pc()); |
simprintf(cpu_state.reg[4], cpu_state.reg[3]); |
} |
|
void op_support_nop_report(void) |
{ |
upd_reg_from_t(get_pc()); |
PRINTF("report(0x%"PRIxREG");\n", cpu_state.reg[3]); |
} |
|
void op_support_nop_report_imm(int imm) |
{ |
upd_reg_from_t(get_pc()); |
PRINTF("report %i (0x%"PRIxREG");\n", imm, cpu_state.reg[3]); |
} |
|
/* Handles a jump */ |
/* addr is a VIRTUAL address */ |
/* NOTE: We can't use env since this code is compiled like the rest of the |
* simulator (most likely without -fomit-frame-pointer) and thus env will point |
* to some bogus value. */ |
void do_jump(oraddr_t addr) |
{ |
struct dyn_page *target_dp; |
struct x_ref *xref; |
oraddr_t phys_page; |
|
/* The pc is set to the location of the jump in op_set_pc_preemt(_check) and |
* then it is incermented by 4 when the scheduler is run. If a scheduled job |
* so happens to raise an exception cpu_state.delay_insn will still be set and |
* so except_handle will do its pc adjusting magic (ie. -4 from it) and every- |
* thing ends up just working right, except when a scheduled job does not |
* raise an exeception. In that case we set the pc here explicitly */ |
set_pc(addr); |
|
/* immu_translate must be called after set_pc. If it would be called before |
* it and it issued an ITLB miss then it would appear that the instruction |
* that faulted was the instruction in the delay slot which is incorrect */ |
phys_page = immu_translate(addr); |
|
/* do_jump is called from the delay slot, which is the jump instruction |
* address + 4. */ |
/* |
printf("Recompiled code jumping out to %"PRIxADDR" from %"PRIxADDR"\n", |
phys_page, cpu_state.sprs[SPR_PPC] - 4); |
*/ |
|
/* immu_translate() adds the hit delay to runtime.sim.mem_cycles but we add it |
* to the cycles when the instruction is executed so if we don't reset it now |
* it will produce wrong results */ |
runtime.sim.mem_cycles = 0; |
|
target_dp = find_dynd_page(phys_page); |
|
if(!target_dp) |
target_dp = new_dp(phys_page); |
|
/* Since writes to the 0x0-0xff range do not dirtyfy a page recompile the 0x0 |
* page if the jump is to that location */ |
if(phys_page < 0x100) |
target_dp->dirty = 1; |
|
/* Check if this location is cross-referenced */ |
if(!(xref = find_host_x_ref(target_dp->xrefs, phys_page))) { |
target_dp->dirty = 1; |
xref = add_to_xrefs(target_dp, phys_page); |
if(cpu_state.curr_page) |
add_to_held_xrefs(cpu_state.curr_page, xref); |
} else { |
/* Only increment reference count if this page didn't already */ |
if(cpu_state.curr_page && !find_held_x_ref(cpu_state.curr_page->held_xrefs, |
phys_page)) { |
xref->ref++; |
add_to_held_xrefs(cpu_state.curr_page, xref); |
} |
} |
|
if(target_dp->dirty) |
recompile_page(target_dp); |
|
cpu_state.curr_page = target_dp; |
|
/* FIXME: If the page is backed by more than one type of memory, this will |
* produce wrong results */ |
if(cpu_state.sprs[SPR_SR] & SPR_SR_IME) |
/* Add the mmu hit delay to the cycle counter */ |
upd_cycles_dec(target_dp->delayr - config.immu.hitdelay); |
else |
upd_cycles_dec(target_dp->delayr); |
|
cpu_state.ts_current = 0; |
|
/* Initially this (and do_rfe/handle_except) returned the address that we |
* should jump to and then the recompiled code performed the jump. This was |
* no problem if the jump was trully an interpage jump or if the location |
* didn't need recompileation. If the jump is page local and the page needs |
* recompileation there is a very high probability that the page will move in |
* memory and then the return address that is on the stack will point to |
* memory that has already been freed, sometimes leading to crashes */ |
/* This looks like it could really be simpler, but no it can't. The only |
* issue here is the stack: it has to be unwound. This function is called |
* from except_handle, which generally ends up quite high on the stack... */ |
or_longjmp(xref->dyn_addr); |
} |
|
/* l.rfe is a hard instruction to emulate. One could just call |
* do_jump(cpu_state.sprs[SPR_EPCR_BASE]), but then the location that we jump to |
* will get cross referenced and because the page that contains the exception |
* handlers is very rearly marked as dirty it will accumulate alot of held |
* cross references over time. */ |
void do_rfe(void) |
{ |
struct dyn_page *target_dp; |
struct x_ref *xref; |
oraddr_t phys_page; |
int already_held = 0; |
|
set_pc(cpu_state.sprs[SPR_EPCR_BASE]); |
|
phys_page = immu_translate(cpu_state.sprs[SPR_EPCR_BASE]); |
|
/* Same reason as in do_jump() */ |
runtime.sim.mem_cycles = 0; |
|
/* op_do_sched has run by the time this is run, which makes the pc point to |
* the instruction after l.rfe. */ |
printf("Returning from exception to %"PRIxADDR" from %"PRIxADDR"\n", |
phys_page, cpu_state.sprs[SPR_PPC]); |
|
target_dp = find_dynd_page(phys_page); |
|
if(!target_dp) |
target_dp = new_dp(phys_page); |
|
/* Since writes to the 0x0-0xff range do not dirtyfy a page recompile the 0x0 |
* page if the jump is to that location */ |
if(phys_page < 0x100) |
target_dp->dirty = 1; |
|
/* Check if this location is cross-referenced */ |
if(!(xref = find_host_x_ref(target_dp->xrefs, phys_page))) { |
xref = add_to_xrefs(target_dp, phys_page); |
/* Calling dirtyfy_page is real tempting but if we get to the situation were |
* the l.rfe instruction and the location to which it returns to are on the |
* same page then all the exception cross references will get removed and |
* this will result in excessive recompileations of this page */ |
target_dp->dirty = 1; |
|
/* There is alot of code (especially in linux) that do loops like this: |
* int a; |
* // Stuff such that b gets on another page than a |
* int b; |
* for(i = 0; i < (some big value); i++) { |
* a = b; |
* // Some more stuff |
* } |
* Here a DTLB miss will happen on every acess to a and b and l.rfe will |
* always return to the same locations but since the previous l.rfe to this |
* page was to a different location the page will get recompiled each time a |
* or b is acessed. This is why the last NUM_RFE_HELD returns are `cached'. |
*/ |
if(++cpu_state.rfe_held_xref_pos == NUM_RFE_HELD) |
cpu_state.rfe_held_xref_pos = 0; |
|
if(cpu_state.rfe_held_xrefs[cpu_state.rfe_held_xref_pos]) |
cpu_state.rfe_held_xrefs[cpu_state.rfe_held_xref_pos]->ref--; |
|
cpu_state.rfe_held_xrefs[cpu_state.rfe_held_xref_pos] = xref; |
} else { |
/* Make sure we increase this cross reference's reference count, since it is |
* decremented below. */ |
xref->ref++; |
already_held = 1; |
} |
|
if(target_dp->dirty) |
recompile_page(target_dp); |
|
if(already_held) |
xref->ref--; |
|
cpu_state.curr_page = target_dp; |
|
/* FIXME: If the page is backed by more than one type of memory, this will |
* produce wrong results */ |
if(cpu_state.sprs[SPR_SR] & SPR_SR_IME) |
/* Add the mmu hit delay to the cycle counter */ |
upd_cycles_dec(target_dp->delayr - config.immu.hitdelay); |
else |
upd_cycles_dec(target_dp->delayr); |
|
cpu_state.ts_current = 0; |
|
/* See the comment at the end of do_jump */ |
or_longjmp(xref->dyn_addr); |
} |
|
/* Handles an exception. */ |
void handle_except(oraddr_t except) |
{ |
struct dyn_page *target_dp; |
struct x_ref *xref; |
|
/* NOTE: It is known when this code will be run. It is therefore not |
* necessary to have to plough through cpu_state.curr_page->ts to store the |
* temporaries. On the other hand, except_handle is also called from the |
* scheduler, therefore we don't know when it is called and we can't move the |
* temporaries to their permanent storeage in the recompiled code. */ |
|
/* op_do_sched has run by the time we run this, which makes the pc point to |
* the next instruction. */ |
printf("Exception %"PRIxADDR" (%s) from %"PRIxADDR"\n", except, |
except_name(except), get_pc() - 4); |
|
set_pc(except); |
|
target_dp = find_dynd_page(except); |
|
if(!target_dp) |
target_dp = new_dp(except); |
|
/* Check if this location is cross-referenced */ |
if(!(xref = find_host_x_ref(target_dp->xrefs, except))) { |
/* See the comment in do_rfe for why dirtyfy page is not called */ |
target_dp->dirty = 1; |
xref = add_to_xrefs(target_dp, except); |
} else { |
/* If this cross reference is scheduled for removal increment its reference |
* count */ |
if(!xref->ref) |
xref->ref++; |
} |
|
if(target_dp->dirty) |
recompile_page(target_dp); |
|
cpu_state.curr_page = target_dp; |
|
/* FIXME: If the page is backed by more than one type of memory, this will |
* produce wrong results */ |
/* Address translation is disabled above (no need to add hitdelay) */ |
upd_cycles_dec(target_dp->delayr); |
|
cpu_state.ts_current = 0; |
|
/* See the comment at the end of do_jump */ |
or_longjmp(xref->dyn_addr); |
} |
|
/op_ff1_op.h
0,0 → 1,35
/* op_ff1_op.h -- Micro operations template for the ff1 instruction |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
__or_dynop void glue(glue(glue(op_ff1_, DST_T), _), SRC_T)(void) |
{ |
int i; |
|
for(i = 0; i < 32; i++, SRC_T >>= 1) { |
if(SRC_T & 1) { |
DST_T = i; |
break; |
} |
} |
|
FORCE_RET; |
} |
|
|
/op.c
0,0 → 1,1323
/* op.c -- Micro operations for the recompiler |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
#include <stdio.h> |
#include <stdint.h> |
#include <stdlib.h> |
|
#include "config.h" |
|
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
|
#include "port.h" |
#include "arch.h" |
#include "spr_defs.h" |
#include "opcode/or32.h" |
#include "sim-config.h" |
#include "except.h" |
#include "abstract.h" |
#include "execute.h" |
#include "sprs.h" |
#include "sched.h" |
|
#include "op_support.h" |
|
#include "i386_regs.h" |
|
#include "dyn_rec.h" |
|
/* This must be here since the function in op_i386.h use this variable */ |
register struct cpu_state *env asm(CPU_STATE_REG); |
|
#include "op_i386.h" |
|
/* FIXME: Move this */ |
void analysis (struct iqueue_entry *current); |
|
/* FIXME: Move this */ |
#define PAGE_LEN 8192 |
|
/* |
* WARNING: Before going of and wildly editing everything in the file remember |
* the following about its contents: |
* 1) The `functions' don't EVER return. In otherwords haveing return state- |
* ments _anywere_ in this file is likely not to work. This is because |
* dyngen just strips away the ret from the end of the function and just uses |
* the function `body'. If a ret statement is executed _anyware_ inside the |
* dynamicly generated code, then it is undefined were we shall jump to. |
* 2) Because of 1), try not to have overly complicated functions. In too |
* complicated functions, gcc may decide to generate premature `exits'. This |
* is what passing the -fno-reorder-blocks command line switch to gcc helps |
* with. This is ofcourse not desired and is rather flaky as we don't (and |
* can't) control the kind of code that gcc generates: It may work for one |
* and break for another. The less branches there are the less likely it is |
* that a premature return shall occur. |
* 3) If gcc decides that it is going to be a basterd then it will optimise a |
* very simple condition (if/switch) with a premature exit. But gcc can't |
* fuck ME over! Just stick a FORCE_RET; at the END of the offending |
* function. |
* 4) All operations must start with `op_'. dyngen ignores all other functions. |
* 5) Local variables are depriciated: They hinder performance. |
* 6) Function calls are expensive as the stack has to be shifted (twice). |
*/ |
|
/*#define __or_dynop __attribute__((noreturn))*/ |
#define __or_dynop |
|
/* Temporaries to hold the (simulated) registers in */ |
register uint32_t t0 asm(T0_REG); |
register uint32_t t1 asm(T1_REG); |
register uint32_t t2 asm(T2_REG); |
|
#define OP_PARAM1 ((uorreg_t)(&__op_param1)) |
#define OP_PARAM2 ((uorreg_t)(&__op_param2)) |
#define OP_PARAM3 ((uorreg_t)(&__op_param3)) |
|
extern uorreg_t __op_param1; |
extern uorreg_t __op_param2; |
extern uorreg_t __op_param3; |
|
#define xglue(x, y) x ## y |
#define glue(x, y) xglue(x, y) |
|
/* Helper function. Whenever we escape the recompiled code and there is a |
* potential that an exception may happen this function must be called */ |
static inline void save_t_temporary(void) |
{ |
env->t0 = t0; |
env->t1 = t1; |
env->t2 = t2; |
} |
|
/* Wrapper around do_scheduler. This is needed because op_do_sched must be as |
* small as possible. */ |
void do_sched_wrap(void) |
{ |
save_t_temporary(); |
upd_sim_cycles(); |
do_scheduler(); |
} |
|
/* Helper function. Hopefully it will get inlined */ |
__or_dynop void op_t0_imm(void) |
{ |
t0 = OP_PARAM1; |
} |
|
__or_dynop void op_t1_imm(void) |
{ |
t1 = OP_PARAM1; |
} |
|
__or_dynop void op_t2_imm(void) |
{ |
t2 = OP_PARAM1; |
} |
|
__or_dynop void op_clear_t0(void) |
{ |
t0 = 0; |
} |
|
__or_dynop void op_clear_t1(void) |
{ |
t1 = 0; |
} |
|
__or_dynop void op_clear_t2(void) |
{ |
t2 = 0; |
} |
|
__or_dynop void op_move_t0_t1(void) |
{ |
t0 = t1; |
} |
|
__or_dynop void op_move_t0_t2(void) |
{ |
t0 = t2; |
} |
|
__or_dynop void op_move_t1_t0(void) |
{ |
t1 = t0; |
} |
|
__or_dynop void op_move_t1_t2(void) |
{ |
t1 = t2; |
} |
|
__or_dynop void op_move_t2_t0(void) |
{ |
t2 = t0; |
} |
|
__or_dynop void op_move_t2_t1(void) |
{ |
t2 = t1; |
} |
|
__or_dynop void op_set_pc_delay_t0(void) |
{ |
env->pc_delay = t0; |
env->delay_insn = 1; |
} |
|
__or_dynop void op_set_pc_delay_t1(void) |
{ |
env->pc_delay = t1; |
env->delay_insn = 1; |
} |
|
__or_dynop void op_set_pc_delay_t2(void) |
{ |
env->pc_delay = t2; |
env->delay_insn = 1; |
} |
|
__or_dynop void op_set_pc_delay_imm(void) |
{ |
env->pc_delay = get_pc() + (orreg_t)OP_PARAM1; |
env->delay_insn = 1; |
} |
|
__or_dynop void op_set_pc_delay_pc(void) |
{ |
env->pc_delay = get_pc(); |
env->delay_insn = 1; |
} |
|
__or_dynop void op_clear_pc_delay(void) |
{ |
env->pc_delay = 0; |
env->delay_insn = 1; |
} |
|
__or_dynop void op_do_jump(void) |
{ |
do_jump(env->pc_delay); |
} |
|
/* Only used to handle branch instruction ie. j.bf and j.bnf */ |
__or_dynop void op_do_jump_check(void) |
{ |
if(env->delay_insn) { |
env->delay_insn = 0; |
do_jump(env->pc_delay); |
} |
} |
|
/* Only used to jump out to the next page */ |
__or_dynop void op_do_jump_pc(void) |
{ |
do_jump(get_pc()); |
} |
|
__or_dynop void op_clear_delay_insn(void) |
{ |
env->delay_insn = 0; |
} |
|
__or_dynop void op_jmp_imm(void) |
{ |
env->ts_current = 0; |
set_pc(env->pc_delay); |
OP_JUMP(OP_PARAM1); |
} |
|
__or_dynop void op_jmp_imm_check(void) |
{ |
if(env->delay_insn) { |
env->ts_current = 0; |
env->delay_insn = 0; |
set_pc(env->pc_delay); |
OP_JUMP(OP_PARAM1); |
} |
} |
|
__or_dynop void op_set_flag(void) |
{ |
env->sprs[SPR_SR] |= SPR_SR_F; |
} |
|
__or_dynop void op_clear_flag(void) |
{ |
env->sprs[SPR_SR] &= ~SPR_SR_F; |
} |
|
__or_dynop void op_check_flag(void) |
{ |
if(env->sprs[SPR_SR] & SPR_SR_F) { |
env->pc_delay = get_pc() + (orreg_t)OP_PARAM1; |
env->delay_insn = 1; |
} |
} |
|
__or_dynop void op_check_not_flag(void) |
{ |
if(!(env->sprs[SPR_SR] & SPR_SR_F)) { |
env->pc_delay = get_pc() + (orreg_t)OP_PARAM1; |
env->delay_insn = 1; |
} |
} |
|
__or_dynop void op_set_ts_current(void) |
{ |
env->ts_current = 1; |
} |
|
__or_dynop void op_set_pc_preemt(void) |
{ |
env->ts_current = 1; |
env->sprs[SPR_PPC] = get_pc(); |
set_pc(env->pc_delay); |
} |
|
__or_dynop void op_set_pc_preemt_check(void) |
{ |
if(env->delay_insn) { |
env->ts_current = 1; |
env->sprs[SPR_PPC] = get_pc(); |
set_pc(env->pc_delay); |
} |
} |
|
__or_dynop void op_nop_exit(void) |
{ |
upd_sim_cycles(); |
save_t_temporary(); |
op_support_nop_exit(); |
FORCE_RET; |
} |
|
__or_dynop void op_nop_reset(void) |
{ |
upd_sim_cycles(); |
op_support_nop_reset(); |
handle_except(EXCEPT_RESET); |
} |
|
__or_dynop void op_nop_printf(void) |
{ |
save_t_temporary(); |
upd_sim_cycles(); |
op_support_nop_printf(); |
FORCE_RET; |
} |
|
__or_dynop void op_nop_report(void) |
{ |
save_t_temporary(); |
upd_sim_cycles(); |
op_support_nop_report(); |
FORCE_RET; |
} |
|
__or_dynop void op_nop_report_imm(void) |
{ |
save_t_temporary(); |
upd_sim_cycles(); |
op_support_nop_report_imm(OP_PARAM1); |
} |
|
__or_dynop void op_check_null_except_t0_delay(void) |
{ |
if(!t0) { |
/* Do exception */ |
env->sprs[SPR_EEAR_BASE] = get_pc() - 4; |
env->delay_insn = 0; |
handle_except(EXCEPT_ILLEGAL); |
} |
} |
|
|
__or_dynop void op_check_null_except_t0(void) |
{ |
if(!t0) { |
/* Do exception */ |
env->sprs[SPR_EEAR_BASE] = get_pc(); |
handle_except(EXCEPT_ILLEGAL); |
} |
} |
|
__or_dynop void op_check_null_except_t1_delay(void) |
{ |
if(!t1) { |
/* Do exception */ |
env->sprs[SPR_EEAR_BASE] = get_pc() - 4; |
env->delay_insn = 0; |
handle_except(EXCEPT_ILLEGAL); |
} |
} |
|
|
__or_dynop void op_check_null_except_t1(void) |
{ |
if(!t1) { |
/* Do exception */ |
env->sprs[SPR_EEAR_BASE] = get_pc(); |
handle_except(EXCEPT_ILLEGAL); |
} |
} |
|
__or_dynop void op_check_null_except_t2_delay(void) |
{ |
if(!t2) { |
/* Do exception */ |
env->sprs[SPR_EEAR_BASE] = get_pc() - 4; |
env->delay_insn = 0; |
handle_except(EXCEPT_ILLEGAL); |
} |
} |
|
__or_dynop void op_check_null_except_t2(void) |
{ |
if(!t2) { |
/* Do exception */ |
env->sprs[SPR_EEAR_BASE] = get_pc(); |
handle_except(EXCEPT_ILLEGAL); |
} |
} |
|
__or_dynop void op_analysis(void) |
{ |
env->iqueue.insn_index = OP_PARAM1; |
env->iqueue.insn = OP_PARAM2; |
env->iqueue.insn_addr = get_pc(); |
upd_sim_cycles(); |
runtime.cpu.instructions++; |
analysis(&env->iqueue); |
FORCE_RET; |
} |
|
#define OP_EXTRA |
|
#define OP / |
#define OP_CAST(T) (orreg_t)T |
#define OP_NAME div |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#define OP / |
#define OP_CAST(T) T |
#define OP_NAME divu |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#define OP * |
#define OP_CAST(T) T |
#define OP_NAME mulu |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#define OP - |
#define OP_CAST(T) (orreg_t)T |
#define OP_NAME sub |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#undef OP_EXTRA |
|
#define OP_HAS_IMM |
|
#define OP_EXTRA + ((env->sprs[SPR_SR] & SPR_SR_CY) >> 10) |
#define OP + |
#define OP_CAST(T) (orreg_t)T |
#define OP_NAME addc |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#undef OP_EXTRA |
#define OP_EXTRA |
|
#define OP + |
#define OP_CAST(T) (orreg_t)T |
#define OP_NAME add |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#define OP & |
#define OP_CAST(T) T |
#define OP_NAME and |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#define OP * |
#define OP_CAST(T) (orreg_t)T |
#define OP_NAME mul |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#define OP | |
#define OP_CAST(T) T |
#define OP_NAME or |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#define OP << |
#define OP_CAST(T) T |
#define OP_NAME sll |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#define OP >> |
#define OP_CAST(T) (orreg_t)T |
#define OP_NAME sra |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#define OP >> |
#define OP_CAST(T) T |
#define OP_NAME srl |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#define OP ^ |
#define OP_CAST(T) T |
#define OP_NAME xor |
#include "op_arith_op.h" |
#undef OP_NAME |
#undef OP_CAST |
#undef OP |
|
#undef OP_EXTRA |
#undef OP_HAS_IMM |
|
#define EXT_NAME extbs |
#define EXT_TYPE int8_t |
#define EXT_CAST (orreg_t) |
#include "op_extend_op.h" |
#undef EXT_CAST |
#undef EXT_TYPE |
#undef EXT_NAME |
|
#define EXT_NAME extbz |
#define EXT_TYPE uint8_t |
#define EXT_CAST (uorreg_t) |
#include "op_extend_op.h" |
#undef EXT_CAST |
#undef EXT_TYPE |
#undef EXT_NAME |
|
#define EXT_NAME exths |
#define EXT_TYPE int16_t |
#define EXT_CAST (orreg_t) |
#include "op_extend_op.h" |
#undef EXT_CAST |
#undef EXT_TYPE |
#undef EXT_NAME |
|
#define EXT_NAME exthz |
#define EXT_TYPE uint16_t |
#define EXT_CAST (uorreg_t) |
#include "op_extend_op.h" |
#undef EXT_CAST |
#undef EXT_TYPE |
#undef EXT_NAME |
|
#define COMP == |
#define COMP_NAME sfeq |
#define COMP_CAST(t) t |
#include "op_comp_op.h" |
#undef COMP_CAST |
#undef COMP_NAME |
#undef COMP |
|
#define COMP != |
#define COMP_NAME sfne |
#define COMP_CAST(t) t |
#include "op_comp_op.h" |
#undef COMP_CAST |
#undef COMP_NAME |
#undef COMP |
|
#define COMP > |
#define COMP_NAME sfgtu |
#define COMP_CAST(t) t |
#include "op_comp_op.h" |
#undef COMP_CAST |
#undef COMP_NAME |
#undef COMP |
|
#define COMP >= |
#define COMP_NAME sfgeu |
#define COMP_CAST(t) t |
#include "op_comp_op.h" |
#undef COMP_CAST |
#undef COMP_NAME |
#undef COMP |
|
#define COMP < |
#define COMP_NAME sfltu |
#define COMP_CAST(t) t |
#include "op_comp_op.h" |
#undef COMP_CAST |
#undef COMP_NAME |
#undef COMP |
|
#define COMP <= |
#define COMP_NAME sfleu |
#define COMP_CAST(t) t |
#include "op_comp_op.h" |
#undef COMP_CAST |
#undef COMP_NAME |
#undef COMP |
|
#define COMP > |
#define COMP_NAME sfgts |
#define COMP_CAST(t) (orreg_t)t |
#include "op_comp_op.h" |
#undef COMP_CAST |
#undef COMP_NAME |
#undef COMP |
|
#define COMP >= |
#define COMP_NAME sfges |
#define COMP_CAST(t) (orreg_t)t |
#include "op_comp_op.h" |
#undef COMP_CAST |
#undef COMP_NAME |
#undef COMP |
|
#define COMP < |
#define COMP_NAME sflts |
#define COMP_CAST(t) (orreg_t)t |
#include "op_comp_op.h" |
#undef COMP_CAST |
#undef COMP_NAME |
#undef COMP |
|
#define COMP <= |
#define COMP_NAME sfles |
#define COMP_CAST(t) (orreg_t)t |
#include "op_comp_op.h" |
#undef COMP_CAST |
#undef COMP_NAME |
#undef COMP |
|
#define REG 1 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 2 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 3 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 4 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 5 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 6 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 7 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 8 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 9 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 10 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 11 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 12 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 13 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 14 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 15 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 16 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 17 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 18 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 19 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 20 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 21 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 22 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 23 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 24 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 25 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 26 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 27 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 28 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 29 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 30 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define REG 31 |
#include "op_t_reg_mov_op.h" |
#undef REG |
|
#define DST_T t0 |
#define SRC_T t0 |
#include "op_ff1_op.h" |
#undef SRC_T |
|
#define SRC_T t1 |
#include "op_ff1_op.h" |
#undef SRC_T |
|
#define SRC_T t2 |
#include "op_ff1_op.h" |
#undef SRC_T |
#undef DST_T |
|
#define DST_T t1 |
#define SRC_T t0 |
#include "op_ff1_op.h" |
#undef SRC_T |
|
#define SRC_T t1 |
#include "op_ff1_op.h" |
#undef SRC_T |
|
#define SRC_T t2 |
#include "op_ff1_op.h" |
#undef SRC_T |
#undef DST_T |
|
#define DST_T t2 |
#define SRC_T t0 |
#include "op_ff1_op.h" |
#undef SRC_T |
|
#define SRC_T t1 |
#include "op_ff1_op.h" |
#undef SRC_T |
|
#define SRC_T t2 |
#include "op_ff1_op.h" |
#undef SRC_T |
#undef DST_T |
|
#define SPR_T_NAME SPR_T |
#define GPR_T_NAME GPR_T |
|
#define SPR_T t0 |
#define GPR_T t0 |
#include "op_mftspr_op.h" |
#undef GPR_T |
|
#define GPR_T t1 |
#include "op_mftspr_op.h" |
#undef GPR_T |
|
#define GPR_T t2 |
#include "op_mftspr_op.h" |
#undef GPR_T |
#undef SPR_T |
|
#define SPR_T t1 |
#define GPR_T t0 |
#include "op_mftspr_op.h" |
#undef GPR_T |
|
#define GPR_T t1 |
#include "op_mftspr_op.h" |
#undef GPR_T |
|
#define GPR_T t2 |
#include "op_mftspr_op.h" |
#undef GPR_T |
#undef SPR_T |
|
#define SPR_T t2 |
#define GPR_T t0 |
#include "op_mftspr_op.h" |
#undef GPR_T |
|
#define GPR_T t1 |
#include "op_mftspr_op.h" |
#undef GPR_T |
|
#define GPR_T t2 |
#include "op_mftspr_op.h" |
#undef GPR_T |
#undef SPR_T |
|
#undef GPR_T_NAME |
#undef SPR_T_NAME |
|
#define SPR_T_NAME imm |
#define GPR_T_NAME GPR_T |
|
#define SPR_T 0 |
|
#define GPR_T t0 |
#include "op_mftspr_op.h" |
#undef GPR_T |
|
#define GPR_T t1 |
#include "op_mftspr_op.h" |
#undef GPR_T |
|
#define GPR_T t2 |
#include "op_mftspr_op.h" |
#undef GPR_T |
#undef SPR_T |
|
#undef SPR_T_NAME |
#undef GPR_T_NAME |
|
#define ONLY_MTSPR |
#define SPR_T_NAME SPR_T |
#define GPR_T_NAME clear |
|
#define GPR_T 0 |
|
#define SPR_T t0 |
#include "op_mftspr_op.h" |
#undef SPR_T |
|
#define SPR_T t1 |
#include "op_mftspr_op.h" |
#undef SPR_T |
|
#define SPR_T t2 |
#include "op_mftspr_op.h" |
#undef SPR_T |
|
#undef GPR_T |
|
#undef SPR_T_NAME |
#undef GPR_T_NAME |
|
#define SPR_T_NAME imm |
#define GPR_T_NAME clear |
#define GPR_T 0 |
#define SPR_T 0 |
#include "op_mftspr_op.h" |
#undef SPR_T |
#undef GPR_T |
#undef GPR_T_NAME |
#undef SPR_T_NAME |
|
#undef ONLY_MTSPR |
|
#define OP += |
#define OP_NAME mac |
#include "op_mac_op.h" |
#undef OP_NAME |
#undef OP |
|
#define OP -= |
#define OP_NAME msb |
#include "op_mac_op.h" |
#undef OP_NAME |
#undef OP |
|
#define LS_OP_NAME lbz |
#define LS_OP_CAST |
#define LS_OP_FUNC eval_mem8 |
#include "op_lwhb_op.h" |
#undef LS_OP_FUNC |
#undef LS_OP_CAST |
#undef LS_OP_NAME |
|
#define LS_OP_NAME lbs |
#define LS_OP_CAST (int8_t) |
#define LS_OP_FUNC eval_mem8 |
#include "op_lwhb_op.h" |
#undef LS_OP_FUNC |
#undef LS_OP_CAST |
#undef LS_OP_NAME |
|
#define LS_OP_NAME lhz |
#define LS_OP_CAST |
#define LS_OP_FUNC eval_mem16 |
#include "op_lwhb_op.h" |
#undef LS_OP_FUNC |
#undef LS_OP_CAST |
#undef LS_OP_NAME |
|
#define LS_OP_NAME lhs |
#define LS_OP_CAST (int16_t) |
#define LS_OP_FUNC eval_mem16 |
#include "op_lwhb_op.h" |
#undef LS_OP_FUNC |
#undef LS_OP_CAST |
#undef LS_OP_NAME |
|
#define LS_OP_NAME lwz |
#define LS_OP_CAST |
#define LS_OP_FUNC eval_mem32 |
#include "op_lwhb_op.h" |
#undef LS_OP_FUNC |
#undef LS_OP_CAST |
#undef LS_OP_NAME |
|
#define LS_OP_NAME lws |
#define LS_OP_CAST (int32_t) |
#define LS_OP_FUNC eval_mem32 |
#include "op_lwhb_op.h" |
#undef LS_OP_FUNC |
#undef LS_OP_CAST |
#undef LS_OP_NAME |
|
#define S_OP_NAME sb |
#define S_FUNC set_mem8 |
#include "op_swhb_op.h" |
#undef S_FUNC |
#undef S_OP_NAME |
|
#define S_OP_NAME sh |
#define S_FUNC set_mem16 |
#include "op_swhb_op.h" |
#undef S_FUNC |
#undef S_OP_NAME |
|
#define S_OP_NAME sw |
#define S_FUNC set_mem32 |
#include "op_swhb_op.h" |
#undef S_FUNC |
#undef S_OP_NAME |
|
__or_dynop void op_join_mem_cycles(void) |
{ |
join_mem_cycles(); |
} |
|
__or_dynop void op_store_link_addr_gpr(void) |
{ |
env->reg[LINK_REGNO] = get_pc() + 8; |
} |
|
__or_dynop void op_set_rfe_pc(void) |
{ |
set_pc(env->sprs[SPR_EPCR_BASE] - 4); |
} |
|
__or_dynop void op_prep_rfe(void) |
{ |
env->sprs[SPR_SR] = env->sprs[SPR_ESR_BASE] | SPR_SR_FO; |
env->sprs[SPR_PPC] = get_pc(); |
} |
|
__or_dynop void op_rfe(void) |
{ |
do_rfe(); |
FORCE_RET; |
} |
|
static inline void prep_except(oraddr_t epcr_base) |
{ |
env->sprs[SPR_EPCR_BASE] = epcr_base; |
|
env->sprs[SPR_ESR_BASE] = env->sprs[SPR_SR]; |
|
/* Address translation is always disabled when starting exception. */ |
env->sprs[SPR_SR] &= ~SPR_SR_DME; |
env->sprs[SPR_SR] &= ~SPR_SR_IME; |
|
env->sprs[SPR_SR] &= ~SPR_SR_OVE; /* Disable overflow flag exception. */ |
|
env->sprs[SPR_SR] |= SPR_SR_SM; /* SUPV mode */ |
env->sprs[SPR_SR] &= ~(SPR_SR_IEE | SPR_SR_TEE); /* Disable interrupts. */ |
} |
|
__or_dynop void op_set_except_pc(void) |
{ |
set_pc(OP_PARAM1); |
} |
|
/* Before the code in op_{sys,trap}{,_delay} gets run, the scheduler runs. |
* Therefore the pc will point to the instruction after the l.sys or l.trap |
* instruction */ |
__or_dynop void op_prep_sys_delay(void) |
{ |
env->delay_insn = 0; |
prep_except(get_pc() - 4); |
} |
|
__or_dynop void op_prep_sys(void) |
{ |
prep_except(get_pc() + 4); |
} |
|
__or_dynop void op_prep_trap_delay(void) |
{ |
env->delay_insn = 0; |
prep_except(get_pc() - 4); |
} |
|
__or_dynop void op_prep_trap(void) |
{ |
prep_except(get_pc()); |
} |
|
__or_dynop void op_do_except(void) |
{ |
handle_except(OP_PARAM1); |
} |
|
/* FIXME: This `instruction' should be split up like the l.trap and l.sys |
* instructions are done */ |
__or_dynop void op_illegal_delay(void) |
{ |
env->delay_insn = 0; |
env->sprs[SPR_EEAR_BASE] = get_pc() - 4; |
handle_except(EXCEPT_ILLEGAL); |
} |
|
__or_dynop void op_illegal(void) |
{ |
env->sprs[SPR_EEAR_BASE] = get_pc(); |
handle_except(EXCEPT_ILLEGAL); |
} |
|
__or_dynop void op_do_sched(void) |
{ |
handle_sched(); |
} |
|
__or_dynop void op_macc(void) |
{ |
env->sprs[SPR_MACLO] = 0; |
env->sprs[SPR_MACHI] = 0; |
} |
|
__or_dynop void op_store_insn_ea(void) |
{ |
env->insn_ea = OP_PARAM1; |
} |
|
__or_dynop void op_calc_insn_ea_t0(void) |
{ |
env->insn_ea = t0 + OP_PARAM1; |
} |
|
__or_dynop void op_calc_insn_ea_t1(void) |
{ |
env->insn_ea = t1 + OP_PARAM1; |
} |
|
__or_dynop void op_calc_insn_ea_t2(void) |
{ |
env->insn_ea = t2 + OP_PARAM1; |
} |
|
__or_dynop void op_macrc_t0(void) |
{ |
/* FIXME: How is this supposed to work? The architechture manual says that |
* the low 32-bits shall be saved into rD. I have just copied this code from |
* insnset.c to make testbench/mul pass */ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
t0 = (orreg_t)(temp >> 28); |
env->sprs[SPR_MACLO] = 0; |
env->sprs[SPR_MACHI] = 0; |
} |
|
__or_dynop void op_macrc_t1(void) |
{ |
/* FIXME: How is this supposed to work? The architechture manual says that |
* the low 32-bits shall be saved into rD. I have just copied this code from |
* insnset.c to make testbench/mul pass */ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
t1 = (orreg_t)(temp >> 28); |
|
env->sprs[SPR_MACLO] = 0; |
env->sprs[SPR_MACHI] = 0; |
} |
|
__or_dynop void op_macrc_t2(void) |
{ |
/* FIXME: How is this supposed to work? The architechture manual says that |
* the low 32-bits shall be saved into rD. I have just copied this code from |
* insnset.c to make testbench/mul pass */ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
t2 = (orreg_t)(temp >> 28); |
|
env->sprs[SPR_MACLO] = 0; |
env->sprs[SPR_MACHI] = 0; |
} |
|
__or_dynop void op_mac_imm_t0(void) |
{ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
temp += (int64_t)t0 * (int64_t)OP_PARAM1; |
|
env->sprs[SPR_MACLO] = temp & 0xffffffff; |
env->sprs[SPR_MACHI] = temp >> 32; |
} |
|
__or_dynop void op_mac_imm_t1(void) |
{ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
temp += (int64_t)t1 * (int64_t)OP_PARAM1; |
|
env->sprs[SPR_MACLO] = temp & 0xffffffff; |
env->sprs[SPR_MACHI] = temp >> 32; |
} |
|
__or_dynop void op_mac_imm_t2(void) |
{ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
temp += (int64_t)t2 * (int64_t)OP_PARAM1; |
|
env->sprs[SPR_MACLO] = temp & 0xffffffff; |
env->sprs[SPR_MACHI] = temp >> 32; |
} |
|
__or_dynop void op_cmov_t0_t0_t1(void) |
{ |
t0 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t1; |
} |
|
__or_dynop void op_cmov_t0_t0_t2(void) |
{ |
t0 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t2; |
} |
|
__or_dynop void op_cmov_t0_t1_t0(void) |
{ |
t0 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t0; |
} |
|
__or_dynop void op_cmov_t0_t1_t2(void) |
{ |
t0 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t2; |
FORCE_RET; |
} |
|
__or_dynop void op_cmov_t0_t2_t0(void) |
{ |
t0 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t0; |
} |
|
__or_dynop void op_cmov_t0_t2_t1(void) |
{ |
t0 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t1; |
FORCE_RET; |
} |
|
__or_dynop void op_cmov_t1_t0_t1(void) |
{ |
t1 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t1; |
} |
|
__or_dynop void op_cmov_t1_t0_t2(void) |
{ |
t1 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t2; |
FORCE_RET; |
} |
|
__or_dynop void op_cmov_t1_t1_t0(void) |
{ |
t1 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t0; |
} |
|
__or_dynop void op_cmov_t1_t1_t2(void) |
{ |
t1 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t2; |
} |
|
__or_dynop void op_cmov_t1_t2_t0(void) |
{ |
t1 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t0; |
FORCE_RET; |
} |
|
__or_dynop void op_cmov_t1_t2_t1(void) |
{ |
t1 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t1; |
} |
|
__or_dynop void op_cmov_t2_t0_t1(void) |
{ |
t2 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t1; |
FORCE_RET; |
} |
|
__or_dynop void op_cmov_t2_t0_t2(void) |
{ |
t2 = env->sprs[SPR_SR] & SPR_SR_F ? t0 : t2; |
} |
|
__or_dynop void op_cmov_t2_t1_t0(void) |
{ |
t2 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t0; |
FORCE_RET; |
} |
|
__or_dynop void op_cmov_t2_t1_t2(void) |
{ |
t2 = env->sprs[SPR_SR] & SPR_SR_F ? t1 : t2; |
} |
|
__or_dynop void op_cmov_t2_t2_t0(void) |
{ |
t2 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t0; |
} |
|
__or_dynop void op_cmov_t2_t2_t1(void) |
{ |
t2 = env->sprs[SPR_SR] & SPR_SR_F ? t2 : t1; |
} |
|
__or_dynop void op_neg_t0_t0(void) |
{ |
t0 = -t0; |
} |
|
__or_dynop void op_neg_t0_t1(void) |
{ |
t0 = -t1; |
} |
|
__or_dynop void op_neg_t0_t2(void) |
{ |
t0 = -t2; |
} |
|
__or_dynop void op_neg_t1_t0(void) |
{ |
t1 = -t0; |
} |
|
__or_dynop void op_neg_t1_t1(void) |
{ |
t1 = -t1; |
} |
|
__or_dynop void op_neg_t1_t2(void) |
{ |
t1 = -t2; |
} |
|
__or_dynop void op_neg_t2_t0(void) |
{ |
t2 = -t0; |
} |
|
__or_dynop void op_neg_t2_t1(void) |
{ |
t2 = -t1; |
} |
|
__or_dynop void op_neg_t2_t2(void) |
{ |
t2 = -t2; |
} |
|
/op_support.h
0,0 → 1,29
/* op_support.h -- Definitions of support routines for operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
void op_support_nop_exit(void); |
void op_support_nop_reset(void); |
void op_support_nop_printf(void); |
void op_support_nop_report(void); |
void op_support_nop_report_imm(int imm); |
void do_jump(oraddr_t addr); |
void do_rfe(void); |
void handle_except(oraddr_t except); |
|
void upd_reg_from_t(oraddr_t pc); |
/dyn_rec.c
0,0 → 1,3166
/* dyn_rec.c -- Dynamic recompiler implementation for or32 |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <sys/mman.h> |
#include <signal.h> |
#include <errno.h> |
#include <execinfo.h> |
|
#include "config.h" |
|
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
|
#include "port.h" |
#include "arch.h" |
#include "immu.h" |
#include "abstract.h" |
#include "opcode/or32.h" |
#include "spr_defs.h" |
#include "execute.h" |
#include "except.h" |
#include "spr_defs.h" |
#include "sim-config.h" |
#include "sched.h" |
|
#include "rec_i386.h" |
#include "i386_regs.h" |
|
#include "dyn_rec.h" |
#include "gen_ops.h" |
|
#include "op_support.h" |
|
/* NOTE: All openrisc (or) addresses in this file are *PHYSICAL* addresses */ |
|
/* FIXME: Optimise sorted list adding */ |
|
/* FIXME: remove this and use config.immu.pagesize */ |
#define PAGE_LEN 8192 |
|
typedef void (*generic_gen_op)(struct op_queue *opq, int end); |
typedef void (*imm_gen_op)(struct op_queue *opq, int end, uorreg_t imm); |
|
void gen_l_invalid(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot); |
|
static const generic_gen_op gen_op_move_gpr_t[NUM_T_REGS][32] = { |
{ NULL, |
gen_op_move_gpr1_t0, |
gen_op_move_gpr2_t0, |
gen_op_move_gpr3_t0, |
gen_op_move_gpr4_t0, |
gen_op_move_gpr5_t0, |
gen_op_move_gpr6_t0, |
gen_op_move_gpr7_t0, |
gen_op_move_gpr8_t0, |
gen_op_move_gpr9_t0, |
gen_op_move_gpr10_t0, |
gen_op_move_gpr11_t0, |
gen_op_move_gpr12_t0, |
gen_op_move_gpr13_t0, |
gen_op_move_gpr14_t0, |
gen_op_move_gpr15_t0, |
gen_op_move_gpr16_t0, |
gen_op_move_gpr17_t0, |
gen_op_move_gpr18_t0, |
gen_op_move_gpr19_t0, |
gen_op_move_gpr20_t0, |
gen_op_move_gpr21_t0, |
gen_op_move_gpr22_t0, |
gen_op_move_gpr23_t0, |
gen_op_move_gpr24_t0, |
gen_op_move_gpr25_t0, |
gen_op_move_gpr26_t0, |
gen_op_move_gpr27_t0, |
gen_op_move_gpr28_t0, |
gen_op_move_gpr29_t0, |
gen_op_move_gpr30_t0, |
gen_op_move_gpr31_t0 }, |
{ NULL, |
gen_op_move_gpr1_t1, |
gen_op_move_gpr2_t1, |
gen_op_move_gpr3_t1, |
gen_op_move_gpr4_t1, |
gen_op_move_gpr5_t1, |
gen_op_move_gpr6_t1, |
gen_op_move_gpr7_t1, |
gen_op_move_gpr8_t1, |
gen_op_move_gpr9_t1, |
gen_op_move_gpr10_t1, |
gen_op_move_gpr11_t1, |
gen_op_move_gpr12_t1, |
gen_op_move_gpr13_t1, |
gen_op_move_gpr14_t1, |
gen_op_move_gpr15_t1, |
gen_op_move_gpr16_t1, |
gen_op_move_gpr17_t1, |
gen_op_move_gpr18_t1, |
gen_op_move_gpr19_t1, |
gen_op_move_gpr20_t1, |
gen_op_move_gpr21_t1, |
gen_op_move_gpr22_t1, |
gen_op_move_gpr23_t1, |
gen_op_move_gpr24_t1, |
gen_op_move_gpr25_t1, |
gen_op_move_gpr26_t1, |
gen_op_move_gpr27_t1, |
gen_op_move_gpr28_t1, |
gen_op_move_gpr29_t1, |
gen_op_move_gpr30_t1, |
gen_op_move_gpr31_t1 }, |
{ NULL, |
gen_op_move_gpr1_t2, |
gen_op_move_gpr2_t2, |
gen_op_move_gpr3_t2, |
gen_op_move_gpr4_t2, |
gen_op_move_gpr5_t2, |
gen_op_move_gpr6_t2, |
gen_op_move_gpr7_t2, |
gen_op_move_gpr8_t2, |
gen_op_move_gpr9_t2, |
gen_op_move_gpr10_t2, |
gen_op_move_gpr11_t2, |
gen_op_move_gpr12_t2, |
gen_op_move_gpr13_t2, |
gen_op_move_gpr14_t2, |
gen_op_move_gpr15_t2, |
gen_op_move_gpr16_t2, |
gen_op_move_gpr17_t2, |
gen_op_move_gpr18_t2, |
gen_op_move_gpr19_t2, |
gen_op_move_gpr20_t2, |
gen_op_move_gpr21_t2, |
gen_op_move_gpr22_t2, |
gen_op_move_gpr23_t2, |
gen_op_move_gpr24_t2, |
gen_op_move_gpr25_t2, |
gen_op_move_gpr26_t2, |
gen_op_move_gpr27_t2, |
gen_op_move_gpr28_t2, |
gen_op_move_gpr29_t2, |
gen_op_move_gpr30_t2, |
gen_op_move_gpr31_t2 } }; |
|
static const generic_gen_op gen_op_move_t_gpr[NUM_T_REGS][32] = { |
{ NULL, |
gen_op_move_t0_gpr1, |
gen_op_move_t0_gpr2, |
gen_op_move_t0_gpr3, |
gen_op_move_t0_gpr4, |
gen_op_move_t0_gpr5, |
gen_op_move_t0_gpr6, |
gen_op_move_t0_gpr7, |
gen_op_move_t0_gpr8, |
gen_op_move_t0_gpr9, |
gen_op_move_t0_gpr10, |
gen_op_move_t0_gpr11, |
gen_op_move_t0_gpr12, |
gen_op_move_t0_gpr13, |
gen_op_move_t0_gpr14, |
gen_op_move_t0_gpr15, |
gen_op_move_t0_gpr16, |
gen_op_move_t0_gpr17, |
gen_op_move_t0_gpr18, |
gen_op_move_t0_gpr19, |
gen_op_move_t0_gpr20, |
gen_op_move_t0_gpr21, |
gen_op_move_t0_gpr22, |
gen_op_move_t0_gpr23, |
gen_op_move_t0_gpr24, |
gen_op_move_t0_gpr25, |
gen_op_move_t0_gpr26, |
gen_op_move_t0_gpr27, |
gen_op_move_t0_gpr28, |
gen_op_move_t0_gpr29, |
gen_op_move_t0_gpr30, |
gen_op_move_t0_gpr31 }, |
{ NULL, |
gen_op_move_t1_gpr1, |
gen_op_move_t1_gpr2, |
gen_op_move_t1_gpr3, |
gen_op_move_t1_gpr4, |
gen_op_move_t1_gpr5, |
gen_op_move_t1_gpr6, |
gen_op_move_t1_gpr7, |
gen_op_move_t1_gpr8, |
gen_op_move_t1_gpr9, |
gen_op_move_t1_gpr10, |
gen_op_move_t1_gpr11, |
gen_op_move_t1_gpr12, |
gen_op_move_t1_gpr13, |
gen_op_move_t1_gpr14, |
gen_op_move_t1_gpr15, |
gen_op_move_t1_gpr16, |
gen_op_move_t1_gpr17, |
gen_op_move_t1_gpr18, |
gen_op_move_t1_gpr19, |
gen_op_move_t1_gpr20, |
gen_op_move_t1_gpr21, |
gen_op_move_t1_gpr22, |
gen_op_move_t1_gpr23, |
gen_op_move_t1_gpr24, |
gen_op_move_t1_gpr25, |
gen_op_move_t1_gpr26, |
gen_op_move_t1_gpr27, |
gen_op_move_t1_gpr28, |
gen_op_move_t1_gpr29, |
gen_op_move_t1_gpr30, |
gen_op_move_t1_gpr31 }, |
{ NULL, |
gen_op_move_t2_gpr1, |
gen_op_move_t2_gpr2, |
gen_op_move_t2_gpr3, |
gen_op_move_t2_gpr4, |
gen_op_move_t2_gpr5, |
gen_op_move_t2_gpr6, |
gen_op_move_t2_gpr7, |
gen_op_move_t2_gpr8, |
gen_op_move_t2_gpr9, |
gen_op_move_t2_gpr10, |
gen_op_move_t2_gpr11, |
gen_op_move_t2_gpr12, |
gen_op_move_t2_gpr13, |
gen_op_move_t2_gpr14, |
gen_op_move_t2_gpr15, |
gen_op_move_t2_gpr16, |
gen_op_move_t2_gpr17, |
gen_op_move_t2_gpr18, |
gen_op_move_t2_gpr19, |
gen_op_move_t2_gpr20, |
gen_op_move_t2_gpr21, |
gen_op_move_t2_gpr22, |
gen_op_move_t2_gpr23, |
gen_op_move_t2_gpr24, |
gen_op_move_t2_gpr25, |
gen_op_move_t2_gpr26, |
gen_op_move_t2_gpr27, |
gen_op_move_t2_gpr28, |
gen_op_move_t2_gpr29, |
gen_op_move_t2_gpr30, |
gen_op_move_t2_gpr31 } }; |
|
static const imm_gen_op calc_insn_ea_table[NUM_T_REGS] = |
{ gen_op_calc_insn_ea_t0, gen_op_calc_insn_ea_t1, gen_op_calc_insn_ea_t2 }; |
|
/* Linker stubs. This will allow the linker to link in op.o. The relocations |
* that the linker does for these will be irrelevent anyway, since we patch the |
* relocations during recompilation. */ |
uorreg_t __op_param1; |
uorreg_t __op_param2; |
uorreg_t __op_param3; |
|
/* The number of bytes that a dynamicly recompiled page should be enlarged by */ |
#define RECED_PAGE_ENLARGE_BY 51200 |
|
/* The number of entries that the micro operations array in op_queue should be |
* enlarged by */ |
#define OPS_ENLARGE_BY 5 |
|
#define T_NONE (-1) |
|
void *rec_stack_base; |
|
/* FIXME: Put this into some header */ |
extern int do_stats; |
|
static int sigsegv_state = 0; |
static void *sigsegv_addr = NULL; |
|
void dyn_ret_stack_prot(void); |
void dump_held_xrefs(struct dyn_page *dp, FILE *f); |
|
void dyn_sigsegv_debug(int u, siginfo_t *siginf, void *dat) |
{ |
struct dyn_page *dp; |
FILE *f; |
char filen[18]; /* 18 == strlen("or_page.%08x") + 1 */ |
void *stack; |
int i, j; |
void *trace[10]; |
int num_trace; |
char **trace_names; |
|
if(!sigsegv_state) { |
sigsegv_addr = siginf->si_addr; |
} else { |
printf("Nested SIGSEGV occured, dumping next chuck of info\n"); |
sigsegv_state++; |
} |
|
/* First dump all the data that does not need dereferenceing to get */ |
switch(sigsegv_state) { |
case 0: |
fflush(stdout); |
printf("Segmentation fault at %p (or address: 0x%"PRIxADDR")\n\n", |
sigsegv_addr, get_pc()); |
sigsegv_state++; |
case 1: |
/* Run through the recompiled pages, dumping them to disk as we go */ |
for(dp = cpu_state.dyn_pages; dp; dp = dp->next) { |
printf("Dumping%s page 0x%"PRIxADDR" recompiled to %p (len: %u) to disk\n", |
dp->dirty ? " dirty" : "", dp->or_page, dp->host_page, |
dp->host_len); |
fflush(stdout); |
|
sprintf(filen, "or_page.%"PRIxADDR, dp->or_page); |
if(!(f = fopen(filen, "w"))) { |
fprintf(stderr, "Unable to open %s to dump the recompiled page to: %s\n", |
filen, strerror(errno)); |
continue; |
} |
if(fwrite(dp->host_page, dp->host_len, 1, f) < 1) |
fprintf(stderr, "Unable to write recompiled data to file: %s\n", |
strerror(errno)); |
|
fclose(f); |
} |
sigsegv_state++; |
case 2: |
/* Dump the x-refs to disk */ |
for(dp = cpu_state.dyn_pages; dp; dp = dp->next) { |
printf("Dumping cross references of 0x%"PRIxADDR" to disk\n", dp->or_page); |
|
sprintf(filen, "or_xref.%"PRIxADDR, dp->or_page); |
if(!(f = fopen(filen, "w"))) { |
fprintf(stderr, "Unable to open %s to dump cross references to: %s\n", |
filen, strerror(errno)); |
continue; |
} |
|
fprintf(f, "Cross references in the page:\n"); |
dump_xrefs(dp, f); |
|
fprintf(f, "\nCross references held by this page:\n"); |
dump_held_xrefs(dp, f); |
|
fclose(f); |
} |
sigsegv_state++; |
case 3: |
/* Dump the contents of the stack */ |
printf("Stack dump: "); |
fflush(stdout); |
|
num_trace = backtrace(trace, 10); |
|
trace_names = backtrace_symbols(trace, num_trace); |
|
stack = get_sp(); |
printf("(of stack at %p, base: %p)\n", stack, rec_stack_base); |
fflush(stdout); |
for(i = 0; stack < rec_stack_base; i++, stack += 4) { |
printf(" <%i> 0x%08x", i, *(uint32_t *)stack); |
/* Try to find a symbolic name with this entry */ |
for(j = 0; j < num_trace; j++) { |
if(trace[j] == *(void **)stack) |
printf(" <%s>", trace_names[j]); |
} |
printf("\n"); |
fflush(stdout); |
} |
sigsegv_state++; |
case 4: |
sim_done(); |
} |
} |
|
void dump_xrefs(struct dyn_page *dp, FILE *f) |
{ |
struct x_ref *xref; |
|
fprintf(f, "--- Cross reference dump for %"PRIxADDR" at %p ---\n", |
dp->or_page, dp->host_page); |
for(xref = dp->xrefs; xref; xref = xref->next) { |
fprintf(f, "x-refed or location: 0x%"PRIxADDR", host-location: %p, ref: %i\n", |
xref->or_addr, xref->dyn_addr, xref->ref); |
} |
fprintf(f, "--- Cross reference dump end ---\n"); |
} |
|
void dump_held_xrefs(struct dyn_page *dp, FILE *f) |
{ |
struct x_ref **xrefs; |
|
fprintf(f, "--- Held cross reference dump for %"PRIxADDR" at %p ---\n", |
dp->or_page, dp->host_page); |
for(xrefs = dp->held_xrefs; *xrefs; xrefs++) |
fprintf(f, "Holds an x-ref to 0x%"PRIxADDR", host-location: %p, ref: %i\n", |
(*xrefs)->or_addr, (*xrefs)->dyn_addr, (*xrefs)->ref); |
fprintf(f, "--- Held cross reference dump end ---\n"); |
} |
|
static void add_to_dp(struct dyn_page *new) |
{ |
struct dyn_page *cur; |
struct dyn_page *prev; |
|
/* Find the location to insert the address */ |
for(cur = cpu_state.dyn_pages, prev = NULL; cur; prev = cur, cur = cur->next) { |
if(cur->or_page > new->or_page) |
break; |
} |
|
if(prev) |
prev->next = new; |
else |
cpu_state.dyn_pages = new; |
new->next = cur; |
} |
|
struct dyn_page *new_dp(oraddr_t page) |
{ |
struct dyn_page *dp = malloc(sizeof(struct dyn_page)); |
dp->or_page = ADDR_PAGE(page); |
|
/* Allocate xref terminator */ |
dp->xrefs = NULL; |
|
dp->held_xrefs = malloc(sizeof(struct x_ref *)); |
dp->held_xrefs[0] = NULL; |
|
dp->host_len = 0; |
dp->host_page = NULL; |
dp->dirty = 1; |
|
add_to_dp(dp); |
return dp; |
} |
|
struct dyn_page *find_dynd_page(oraddr_t addr) |
{ |
struct dyn_page *cur = cpu_state.dyn_pages; |
|
addr &= ~(ADDR_C(PAGE_LEN) - 1); |
while(cur) { |
if(cur->or_page == addr) |
return cur; |
if(cur->or_page > addr) |
return NULL; /* The dyn_page linked list is ordered */ |
cur = cur->next; |
} |
return NULL; |
} |
|
/* Finds the dynamicly recompiled location of the given or address */ |
struct x_ref *find_host_x_ref(struct x_ref *x_refs, oraddr_t addr) |
{ |
/* FIXME: Optimise this by knowing that the x_refs array is orderd */ |
while(x_refs && (x_refs->or_addr != addr)) x_refs = x_refs->next; |
|
return x_refs; |
} |
|
static void remove_xref(struct dyn_page *dp, struct x_ref *xref) |
{ |
struct x_ref *prev_xref; |
|
if(dp->xrefs == xref) { |
dp->xrefs = xref->next; |
free(xref); |
return; |
} |
|
prev_xref = dp->xrefs; |
while(prev_xref->next != xref) |
prev_xref = prev_xref->next; |
|
prev_xref->next = xref->next; |
free(xref); |
} |
|
struct x_ref *find_held_x_ref(struct x_ref **held_xrefs, oraddr_t or_addr) |
{ |
/* FIXME: Order this list in add_to_held_xrefs below and optimise this */ |
while(*held_xrefs && ((*held_xrefs)->or_addr != or_addr)) held_xrefs++; |
return *held_xrefs; |
} |
|
void add_to_held_xrefs(struct dyn_page *dp, struct x_ref *xref) |
{ |
unsigned int i; |
|
for(i = 0; dp->held_xrefs[i]; i++); |
|
dp->held_xrefs = realloc(dp->held_xrefs, sizeof(struct x_ref *) * (i + 2)); |
dp->held_xrefs[i] = xref; |
dp->held_xrefs[++i] = NULL; |
} |
|
/* This is called whenever the immu is either enabled/disabled or reconfigured |
* while enabled. This checks if an itlb miss would occour and updates the immu |
* hit delay counter */ |
void recheck_immu(int got_en_dis) |
{ |
oraddr_t addr = get_pc(); |
extern int immu_ex_from_insn; |
|
if(cpu_state.delay_insn) { |
/* If an instruction pagefault or ITLB would occur, it must appear to have |
* come from the jumped-to address */ |
if(ADDR_PAGE(addr) == ADDR_PAGE(cpu_state.pc_delay)) { |
immu_ex_from_insn = 1; |
immu_translate(addr + 4); |
immu_ex_from_insn = 0; |
runtime.sim.mem_cycles = 0; |
} |
return; |
} |
|
if(ADDR_PAGE(addr) == ADDR_PAGE(addr + 4)) { |
/* If the next instruction is on another page then the immu will be checked |
* when the jump to the next page happens */ |
immu_ex_from_insn = 1; |
immu_translate(addr + 4); |
immu_ex_from_insn = 0; |
/* If we had am immu hit then runtime.sim.mem_cycles will hold the value |
* config.immu.hitdelay, but this value is added to the cycle when the next |
* instruction is run */ |
runtime.sim.mem_cycles = 0; |
} |
/* Only update the cycle decrementer if the mmu got enabled or disabled */ |
if(got_en_dis == IMMU_GOT_ENABLED) |
/* Add the mmu hit delay to the cycle counter */ |
upd_cycles_dec(cpu_state.curr_page->delayr - config.immu.hitdelay); |
else if(got_en_dis == IMMU_GOT_DISABLED) { |
upd_cycles_dec(cpu_state.curr_page->delayr); |
/* Since we updated the cycle decrementer above the immu hit delay will not |
* be added to the cycle counter for this instruction. Compensate for this |
* by adding it now */ |
/* FIXME: This is not correct here. In the complex execution model the hit |
* delay is added to runtime.sim.mem_cycles which is only joined with the |
* cycle counter after analysis() and before the scheduler would run. |
* Therefore the scheduler will still be correct but analysis() will produce |
* wrong results just for this one instruction. */ |
add_to_cycles(config.immu.hitdelay); |
} |
} |
|
/* Runs the scheduler. Called from except_handler (and dirtyfy_page below) */ |
void run_sched_out_of_line(int add_normal) |
{ |
int brk; |
oraddr_t pc = get_pc(); |
|
if(!cpu_state.ts_current) |
upd_reg_from_t(pc); |
|
if(add_normal && do_stats) { |
cpu_state.iqueue.insn_addr = pc; |
cpu_state.iqueue.insn = eval_insn_direct(pc, &brk, 1); |
cpu_state.iqueue.insn_index = insn_decode(cpu_state.iqueue.insn); |
analysis(&cpu_state.iqueue); |
} |
|
/* Run the scheduler */ |
if(add_normal) |
sched_add_cycles(); |
|
op_join_mem_cycles(); |
upd_sim_cycles(); |
if(scheduler.job_queue->time <= 0) |
do_scheduler(); |
} |
|
/* Signals a page as dirty */ |
void dirtyfy_page(struct dyn_page *dp) |
{ |
struct x_ref **held_xrefs; |
struct x_ref *xref; |
oraddr_t check; |
|
printf("Dirtyfying page 0x%"PRIxADDR"\n", dp->or_page); |
|
/* decrease the reference counts of the xrefs that we hold */ |
for(held_xrefs = dp->held_xrefs; *held_xrefs; held_xrefs++) |
(*held_xrefs)->ref--; |
dp->held_xrefs = realloc(dp->held_xrefs, sizeof(struct x_ref *)); |
dp->held_xrefs[0] = NULL; |
|
dp->dirty = 1; |
|
/* If the execution is currently in the page that was touched then recompile |
* it now and jump back to the point of execution */ |
check = cpu_state.delay_insn ? cpu_state.pc_delay : get_pc() + 4; |
if(ADDR_PAGE(check) == dp->or_page) { |
run_sched_out_of_line(1); |
if(!(xref = find_host_x_ref(dp->xrefs, check))) { |
xref = add_to_xrefs(dp, check); |
add_to_held_xrefs(dp, xref); |
} else { |
if(!find_held_x_ref(dp->held_xrefs, check)) { |
add_to_held_xrefs(dp, xref); |
xref->ref++; |
} |
} |
recompile_page(dp); |
|
cpu_state.delay_insn = 0; |
|
/* Jump out to the next instruction */ |
or_longjmp(xref->dyn_addr); |
} |
} |
|
static void ship_gprs_out_t(struct op_queue *opq, int end, unsigned int *reg_t) |
{ |
int i; |
|
for(i = 0; i < NUM_T_REGS; i++) { |
if(reg_t[i] < 32) |
gen_op_move_gpr_t[i][reg_t[i]](opq, end); |
} |
} |
|
static int find_unused_t(unsigned int *pres_t, unsigned int *reg_t) |
{ |
int empty = -1; /* Invalid */ |
int i; |
|
/* Try to find a temporary that does not contain a register and is not |
* needed to be preserved */ |
for(i = 0; i < NUM_T_REGS; i++) { |
if(!pres_t[i]) { |
empty = i; |
if(reg_t[i] > 31) |
return i; |
} |
} |
return empty; |
} |
|
/* Checks if there is enough space in dp->host_page, if not grow it */ |
void *enough_host_page(struct dyn_page *dp, void *cur, unsigned int *len, |
unsigned int amount) |
{ |
unsigned int used = cur - dp->host_page; |
|
/* The array is long enough */ |
if((used + amount) <= *len) |
return cur; |
|
/* Reallocate */ |
*len += RECED_PAGE_ENLARGE_BY; |
|
if(!(dp->host_page = realloc(dp->host_page, *len))) { |
fprintf(stderr, "OOM\n"); |
exit(1); |
} |
|
return dp->host_page + used; |
} |
|
/* Adds an operation to the opq */ |
void add_to_opq(struct op_queue *opq, int end, int op) |
{ |
if(opq->num_ops == opq->ops_len) { |
opq->ops_len += OPS_ENLARGE_BY; |
if(!(opq->ops = realloc(opq->ops, opq->ops_len * sizeof(int)))) { |
fprintf(stderr, "OOM\n"); |
exit(1); |
} |
} |
|
if(end) |
opq->ops[opq->num_ops] = op; |
else { |
/* Shift everything over by one */ |
memmove(opq->ops + 1, opq->ops, opq->num_ops* sizeof(int)); |
opq->ops[0] = op; |
} |
|
opq->num_ops++; |
} |
|
/* Adds a parameter to the opq */ |
void add_to_op_params(struct op_queue *opq, int end, unsigned long param) |
{ |
if(opq->num_ops_param == opq->ops_param_len) { |
opq->ops_param_len += OPS_ENLARGE_BY * sizeof(int); |
if(!(opq->ops_param = realloc(opq->ops_param, opq->ops_param_len))) { |
fprintf(stderr, "OOM\n"); |
exit(1); |
} |
} |
|
if(end) |
opq->ops_param[opq->num_ops_param] = param; |
else { |
/* Shift everything over by one */ |
memmove(opq->ops_param + 1, opq->ops_param, opq->num_ops_param); |
opq->ops_param[0] = param; |
} |
|
opq->num_ops_param++; |
} |
|
/* Function to guard against rogue ret instructions in the operations */ |
void dyn_ret_stack_prot(void) |
{ |
fprintf(stderr, "An operation (I have no clue which) has a ret statement in it\n"); |
fprintf(stderr, "Good luck debugging it!\n"); |
|
exit(1); |
} |
|
/* Jumps out to some Openrisc address */ |
void jump_dyn_code(oraddr_t addr) |
{ |
set_pc(addr); |
do_jump(addr); |
} |
|
/* Initialises the recompiler */ |
void init_dyn_recomp(void) |
{ |
struct sigaction sigact; |
struct op_queue *opq; |
struct x_ref *xref; |
unsigned int i; |
|
cpu_state.opqs = NULL; |
|
/* Allocate the operation queue list (+1 for the page chaining) */ |
for(i = 0; i < (PAGE_LEN / 4) + 1; i++) { |
if(!(opq = malloc(sizeof(struct op_queue)))) { |
fprintf(stderr, "OOM\n"); |
exit(1); |
} |
|
/* initialise some fields */ |
opq->ops_len = 0; |
opq->ops = NULL; |
opq->ops_param_len = 0; |
opq->ops_param = NULL; |
|
if(cpu_state.opqs) |
cpu_state.opqs->prev = opq; |
|
opq->next = cpu_state.opqs; |
cpu_state.opqs = opq; |
} |
|
opq->prev = NULL; |
|
/* Allocate the x-ref structures that will be used for the infinite loop |
* instruction (l.j 0). Allocate a whole page's worth just to make sure that |
* we will have enough */ |
for(i = 0; i < (PAGE_LEN / 4); i++) { |
if(!(xref = malloc(sizeof(struct x_ref)))) { |
fprintf(stderr, "Out-of-memory while allocateing x-ref structures\n"); |
exit(1); |
} |
xref->next = cpu_state.inf_xrefs; |
cpu_state.inf_xrefs = xref; |
} |
|
/* Just some value that we'll use as the base for our stack */ |
rec_stack_base = get_sp(); |
|
cpu_state.curr_page = NULL; |
cpu_state.dyn_pages = NULL; |
|
/* Register our segmentation fault handler */ |
sigact.sa_sigaction = dyn_sigsegv_debug; |
memset(&sigact.sa_mask, 0, sizeof(sigact.sa_mask)); |
sigact.sa_flags = SA_SIGINFO | SA_NOMASK; |
if(sigaction(SIGSEGV, &sigact, NULL)) |
printf("WARN: Unable to install SIGSEGV handler! Don't expect to be able to debug the recompiler.\n"); |
|
/* Allocate memory for the rfe corss reference cache */ |
if(!(cpu_state.rfe_held_xrefs = malloc(sizeof(struct xref *) * NUM_RFE_HELD))) { |
printf("OOM\n"); |
exit(1); |
} |
cpu_state.rfe_held_xref_pos = 0; |
memset(cpu_state.rfe_held_xrefs, 0, sizeof(struct xref *) * NUM_RFE_HELD); |
|
init_dyn_rec(); |
|
/* FIXME: Find a better place for this */ |
{ /* Needed by execution */ |
extern int do_stats; |
do_stats = config.cpu.dependstats || config.cpu.superscalar || config.cpu.dependstats |
|| config.sim.history || config.sim.exe_log; |
} |
|
printf("Recompile engine up and running\n"); |
} |
|
/* rec_page is a physical address */ |
void recompile_page(struct dyn_page *dyn) |
{ |
unsigned int j, k; |
unsigned int reg_t[NUM_T_REGS]; |
unsigned int pres_t[NUM_T_REGS]; /* Which temporary to preserve */ |
unsigned int insn_index; |
int delay_insn = 0; /* Is the next instruction to be decoded in a delay slot*/ |
enum insn_type delay_insn_type = 0; |
uint32_t insn; |
int param_t[3]; /* Which temporary the parameters reside in */ |
int param_r[3]; /* is parameter a register */ |
orreg_t param[3]; |
int param_num; |
struct op_queue *opq = NULL; |
oraddr_t rec_addr = dyn->or_page; |
oraddr_t rec_page = dyn->or_page; |
struct x_ref *xref; |
int breakp; |
struct dyn_page *prev_dp; |
|
struct insn_op_struct *opd; |
|
/* The start of the next page */ |
rec_page += PAGE_LEN; |
|
printf("Recompileing page %"PRIxADDR"\n", rec_addr); |
fflush(stdout); |
|
/* Mark all temporaries as not containing a register */ |
for(j = 0; j < NUM_T_REGS; j++) |
reg_t[j] = 32; /* Out-of-range registers */ |
|
dyn->delayr = -verify_memoryarea(rec_addr)->delayr; |
|
dyn->carrys_delay_slot = 0; |
|
/* Check if the previous page carries a delay slot over to this page */ |
if((prev_dp = find_dynd_page(rec_addr - PAGE_LEN))) |
delay_insn = prev_dp->carrys_delay_slot; |
|
for(opq = cpu_state.opqs; rec_addr < rec_page; rec_addr += 4, opq = opq->next) { |
opq->num_ops = 0; |
opq->num_ops_param = 0; |
opq->jump_local = 0; |
|
opq->insn_addr = rec_addr; |
|
breakp = 0; |
insn = eval_insn(rec_addr, &breakp); |
|
/* FIXME: If a breakpoint is set at this location, insert exception code */ |
if(breakp) { |
fprintf(stderr, "FIXME: Insert breakpoint code\n"); |
} |
|
insn_index = insn_decode(insn); |
|
/* FIXME: Optimise this by knowing that dyn->x_refs is ordered (ie. Don't |
* call find_host_x_ref) */ |
/* Check if this location is cross referenced */ |
if((xref = find_host_x_ref(dyn->xrefs, rec_addr))) { |
/* If the x-refs reference count reached zero remove it */ |
if(xref->ref) { |
/* If the current address is cross-referenced, the temporaries shall be |
* in an undefined state, so we must assume that no registers reside in |
* them */ |
/* Ship out the current set of registers from the temporaries */ |
if(opq->prev) { |
ship_gprs_out_t(opq->prev, 1, reg_t); |
} |
for(j = 0; j < NUM_T_REGS; j++) |
reg_t[j] = 32; |
} else { |
/* Remove x-ref */ |
remove_xref(dyn, xref); |
} |
} |
|
memcpy(opq->reg_t, reg_t, sizeof(reg_t)); |
|
/* Check if we have an illegal instruction */ |
if(insn_index == -1) { |
gen_l_invalid(opq, param_t, param, delay_insn); |
if(delay_insn) { |
/* There is no need to do any jump handleing stuff as the instruction |
* will generate an exception */ |
if(opq->prev->jump_local == 2) { |
opq->prev->xref->next = cpu_state.inf_xrefs; |
cpu_state.inf_xrefs = opq->prev->xref; |
} |
opq->prev->jump_local = 0; |
delay_insn = 0; |
} |
continue; |
} |
|
/* figure out instruction operands */ |
for(j = 0; j < NUM_T_REGS; j++) |
pres_t[j] = 0; |
|
param_t[0] = T_NONE; |
param_t[1] = T_NONE; |
param_t[2] = T_NONE; |
param_r[0] = 0; |
param_r[1] = 0; |
param_r[2] = 0; |
param_num = 0; |
|
opd = op_start[insn_index]; |
while(1) { |
param[param_num] = eval_operand_val(insn, opd); |
|
if(opd->type & OPTYPE_REG) { |
/* check which temporary the register is in, if any */ |
for(j = 0; j < NUM_T_REGS; j++) { |
if(reg_t[j] == param[param_num]) { |
param_t[param_num] = j; |
pres_t[j] = 1; |
} |
} |
} |
|
param_num++; |
while(!(opd->type & OPTYPE_OP)) opd++; |
if(opd->type & OPTYPE_LAST) |
break; |
opd++; |
} |
|
opd = op_start[insn_index]; |
|
/* Before an exception takes place, all registers must be stored. */ |
if((or32_opcodes[insn_index].func_unit == it_exception)) { |
if(opq->prev) { |
ship_gprs_out_t(opq->prev, 1, reg_t); |
for(j = 0; j < NUM_T_REGS; j++) { |
opq->prev->reg_t[j] = 32; |
reg_t[j] = 32; |
} |
} |
} |
|
for(j = 0; j < param_num; j++, opd++) { |
while(!(opd->type & OPTYPE_OP)) opd++; |
if(!(opd->type & OPTYPE_REG)) |
continue; |
|
/* Never, ever, move r0 into a temporary */ |
if(!param[j]) |
continue; |
|
/* Check if this register has been moved into a temporary in a previous |
* operand */ |
for(k = 0; k < NUM_T_REGS; k++) { |
if(reg_t[k] == param[j]) { |
/* Yes, this register is already in a temporary */ |
pres_t[k] = 1; |
reg_t[k] = param[j]; |
param_t[j] = k; |
break; |
} |
} |
if(k != NUM_T_REGS) |
continue; |
|
if((param_t[j] != T_NONE)) |
continue; |
|
/* Search for an unused temporary */ |
k = find_unused_t(pres_t, reg_t); |
if(reg_t[k] < 32) { |
gen_op_move_gpr_t[k][reg_t[k]](opq->prev, 1); |
opq->reg_t[k] = 32; |
} |
pres_t[k] = 1; |
reg_t[k] = param[j]; |
param_t[j] = k; |
/* FIXME: Only generate code to move the register into a temporary if it |
* is used as a source operand */ |
gen_op_move_t_gpr[k][reg_t[k]](opq, 1); |
} |
|
/* FIXME: Do this in a more elegent way */ |
if(!strncmp(or32_opcodes[insn_index].name, "l.jal", 5)) { |
/* In the case of a l.jal instruction, make sure that LINK_REGNO is not in |
* a temporary. The problem is that the l.jal(r) instruction stores the |
* `return address' in LINK_REGNO. The temporaries are shiped out only |
* after the delay slot instruction has executed and so it overwrittes the |
* `return address'. */ |
for(k = 0; k < NUM_T_REGS; k++) { |
if(reg_t[k] == LINK_REGNO) { |
gen_op_move_gpr_t[k][LINK_REGNO](opq, 1); |
reg_t[k] = 32; |
opq->reg_t[k] = 32; |
break; |
} |
} |
} |
|
/* Store the state of the temporaries into dyn->ts */ |
dyn->ts[(rec_addr & (PAGE_LEN - 1)) / 2] = 0; |
if(reg_t[0] < 32) |
dyn->ts[(rec_addr & (PAGE_LEN - 1)) / 2] = reg_t[0]; |
if(reg_t[1] < 32) |
dyn->ts[(rec_addr & (PAGE_LEN - 1)) / 2] |= reg_t[1] << 5; |
if(reg_t[2] < 32) |
dyn->ts[(rec_addr & (PAGE_LEN - 1)) / 2] |= reg_t[2] << 10; |
|
/* To get the execution log correct for instructions like l.lwz r4,0(r4) the |
* effective address needs to be calculated before the instruction is |
* simulated */ |
if(do_stats) { |
/* Find any disposition in the instruction */ |
opd = op_start[insn_index]; |
for(j = 0; j < param_num; j++, opd++) { |
while(!(opd->type & OPTYPE_OP)) opd++; |
if(!(opd->type & OPTYPE_DIS)) |
continue; |
|
if(!param[j + 1]) |
gen_op_store_insn_ea(opq, 1, param[j]); |
else |
calc_insn_ea_table[param_t[j + 1]](opq, 1, param[j]); |
} |
} |
|
or32_opcodes[insn_index].exec(opq, param_t, param, delay_insn); |
|
/* If any sort of analysis is done, store all temporaries and run |
* analysis() */ |
if(do_stats) { |
ship_gprs_out_t(opq, 1, reg_t); |
for(j = 0; j < NUM_T_REGS; j++) |
reg_t[j] = 32; |
|
gen_op_analysis(opq, 1, insn_index, insn); |
} |
|
/* The call to join_mem_cycles() could be put into the individual operations |
* that emulate the load/store instructions, but then it would be added to |
* the cycle counter before analysis() is called, which not how the complex |
* execution modell does it. */ |
if((or32_opcodes[insn_index].func_unit == it_load) || |
(or32_opcodes[insn_index].func_unit == it_store)) |
gen_op_join_mem_cycles(opq, 1); |
|
/* If a delay sloted instruction is in the delay slot, avoid doing a jump on |
* the first delay sloted instruction. The problem with not doing the above |
* is that the 0x00000000 instruction is a jump instruction, which is used |
* for padding, and if there ends up being a jump instruction directly after |
* some padding and the code jumps to this location (as with the mmu test) |
* the jump instruction will set cpu_state.pc_delay but code will get |
* generated after the jump instruction and before the delay slot |
* instruciton to check cpu_state.pc_delay and jump out if it is set and so |
* we end up jumping out to the padding instruction. With some thought, the |
* 0x00000000 opcode could really have been encoded to some arithmetic |
* operation that would end up nop-ing (or better yet, to the l.nop 0 |
* instruction itself) */ |
/* If we came up to a page local jump and because it is the delay slot of |
* another delay sloted instruction the case below is skipped and |
* opq->prev->jump_local will remain set to 1, fix this by reseting it now*/ |
if(delay_insn && ((or32_opcodes[insn_index].func_unit == it_jump) || |
(or32_opcodes[insn_index].func_unit == it_branch))) { |
/* We don't generate code to do the relocation so there will be none. |
* Avoid haveing a reference to it */ |
/* Also remove the cross reference to it */ |
if(opq->prev) { |
if(opq->prev->jump_local == 2) { |
opq->prev->xref->next = cpu_state.inf_xrefs; |
cpu_state.inf_xrefs = opq->prev->xref; |
} |
opq->prev->jump_local = 0; |
} |
delay_insn = 0; |
} |
|
/* In the case of an instruction in the delay slot the pc must be updated |
* before op_do_sched runs because if it so happens to generate an exception |
* it will think that we are still executeing the delay slot instruction |
* which infact we have just executed and then SPR_EPCR_BASE will end up |
* pointing to the delay slot instruction, which is wrong. If the delay |
* slot instruction is an exception instruction (l.trap/l.sys) the exception |
* must appear to have been generated in the delay slot */ |
if(delay_insn && (or32_opcodes[insn_index].func_unit != it_exception)) { |
if(xref || (delay_insn_type == it_branch)) |
gen_op_set_pc_preemt_check(opq, 1); |
else /* delay_insn_tyte == it_jump */ |
gen_op_set_pc_preemt(opq, 1); |
/* Move temporaries to their permanent storage */ |
ship_gprs_out_t(opq, 1, reg_t); |
} |
|
/* Same reason as for the above case */ |
if(or32_opcodes[insn_index].func_unit == it_exception) { |
/* FIXME: Do the instruction switch below in a more elegent way */ |
if(!strcmp(or32_opcodes[insn_index].name, "l.rfe")) { |
gen_op_set_rfe_pc(opq, 1); |
} else if(!strcmp(or32_opcodes[insn_index].name, "l.sys")) { |
gen_op_set_except_pc(opq, 1, EXCEPT_SYSCALL - 4); |
} else { /* or32_opcodes[insn_index].name == "l.trap" */ |
gen_op_set_except_pc(opq, 1, EXCEPT_TRAP - 4); |
} |
gen_op_set_ts_current(opq, 1); |
} |
|
gen_op_do_sched(opq, 1); |
|
/* If this is an exception instruction then we still need to perform the |
* exception */ |
if(or32_opcodes[insn_index].func_unit == it_exception) { |
/* FIXME: Do the instruction switch below in a more elegent way */ |
if(!strcmp(or32_opcodes[insn_index].name, "l.rfe")) { |
gen_op_rfe(opq, 1); |
} else if(!strcmp(or32_opcodes[insn_index].name, "l.sys")) { |
gen_op_do_except(opq, 1, EXCEPT_SYSCALL); |
} else { /* or32_opcodes[insn_index].name == "l.trap" */ |
gen_op_do_except(opq, 1, EXCEPT_TRAP); |
} |
} |
|
/* FIXME: If the delay slot is cross referenced after we have stuck the jump |
* instruction in the operations queue we will genererate temporary-> |
* register code after the jump, which will be unreachable. This is no |
* problem as all temporaries are stored in anticipation for a jump. */ |
/* FIXME: If the delay slot is cross referenced we should generate the |
* conditional jump code as we do below. This will not happen if the delay |
* slot is cross referenced after we generate the operations for the jump */ |
/* FIXME: If the instruction in the delay slot is an exception instruction |
* the code that we generate below will be unreachable since the exception |
* instruction jumps to the exection vector */ |
/* Generate code to jump out to the proper location */ |
if(delay_insn) { |
for(j = 0; j < NUM_T_REGS; j++) |
reg_t[j] = 32; |
|
if(xref || (delay_insn_type == it_branch)) { |
/* If the delay-slot instruction is cross referenced, then we have to |
* check env->delay_insn */ |
if(opq->prev && opq->prev->jump_local) { |
gen_op_jmp_imm_check(opq, 1, 0); |
opq->prev->jump_local_loc = &opq->ops_param[opq->num_ops_param - 1]; |
} else { |
gen_op_do_jump_check(opq, 1); |
} |
} else if(delay_insn_type == it_jump) { |
gen_op_clear_delay_insn(opq, 1); |
if(opq->prev && opq->prev->jump_local) { |
/* The 0 will get patched when the page-local jumps get patched */ |
gen_op_jmp_imm(opq, 1, 0); |
/* FIXME: opq->ops_param is realloced with realloc and so we risk a |
* reallocation in which the location ends up moveing in memory */ |
opq->prev->jump_local_loc = &opq->ops_param[opq->num_ops_param - 1]; |
} else { |
gen_op_do_jump(opq, 1); |
} |
} |
delay_insn = 0; |
} |
|
/* Set flag for next instruction to be in a delay slot */ |
if((or32_opcodes[insn_index].func_unit == it_jump) || |
(or32_opcodes[insn_index].func_unit == it_branch)) { |
delay_insn = 1; |
delay_insn_type = or32_opcodes[insn_index].func_unit; |
} |
} |
|
if(delay_insn) { |
dyn->carrys_delay_slot = 1; |
/* Quick hack to avoid dereferencing an uninitialised pointer below with |
* *opq->jump_local_loc */ |
if(opq->prev->jump_local == 2) { |
/* FIXME: In this case the delay slot instruction won't get executed */ |
opq->prev->xref->next = cpu_state.inf_xrefs; |
cpu_state.inf_xrefs = opq->prev->xref; |
} |
opq->prev->jump_local = 0; |
} |
|
dyn->dirty = 0; |
|
/* Ship temporaries out to the corrisponding registers */ |
ship_gprs_out_t(opq->prev, 1, reg_t); |
|
opq->num_ops = 0; |
opq->num_ops_param = 0; |
opq->jump_local = 0; |
|
/* Insert code to jump to the next page */ |
gen_op_set_ts_current(opq, 1); |
gen_op_do_jump_pc(opq, 1); |
|
/* Generate the code */ |
gen_code(cpu_state.opqs, dyn); |
|
/* Patch the x-ref table */ |
for(xref = dyn->xrefs; xref; xref = xref->next) |
xref->dyn_addr = dyn->host_page + (unsigned int)xref->dyn_addr; |
|
/* Search for page-local jumps */ |
for(opq = cpu_state.opqs; opq; opq = opq->next) { |
if(opq->jump_local) { |
if(opq->jump_local == 2) |
/* This cross reference was not patched above so patch it now */ |
opq->xref->dyn_addr = dyn->host_page + (unsigned int)opq->xref->dyn_addr; |
|
*opq->jump_local_loc = (unsigned int)opq->xref->dyn_addr; |
if(opq->jump_local == 2) { |
/* Return the xref to the pool of infinite loop cross references */ |
opq->xref->next = cpu_state.inf_xrefs; |
cpu_state.inf_xrefs = opq->xref; |
} |
} |
} |
|
/* Patch the relocations */ |
patch_relocs(cpu_state.opqs, dyn->host_page); |
|
/* FIXME: Fix the issue below in a more elegent way */ |
/* Since eval_insn is called to get the instruction, runtime.sim.mem_cycles is |
* updated but the recompiler expectes it to start a 0, so reset it */ |
runtime.sim.mem_cycles = 0; |
|
#if 0 |
This is very usefull during debuging |
/* Count the number of infinite loop cross references (to make sure that we |
* returned them all) */ |
for(j = 0, xref = cpu_state.inf_xrefs; xref; xref = xref->next) { |
printf("Cross reference to %"PRIxADDR" is here\n", xref->or_addr); |
j++; |
} |
|
if(j != (PAGE_LEN / 4)) { |
fprintf(stderr, "Infinite loop cross references are leaked!\n"); |
fprintf(stderr, "Number in free list now: %i, meant to be: %i\n", j, PAGE_LEN / 4); |
exit(1); |
} |
#endif |
|
} |
|
struct x_ref *add_to_xrefs(struct dyn_page *dp, oraddr_t addr) |
{ |
struct x_ref *new; |
struct x_ref *cur; |
struct x_ref *prev; |
|
new = malloc(sizeof(struct x_ref)); |
|
new->ref = 1; |
new->or_addr = addr; |
|
/* Find the location to insert the address */ |
for(cur = dp->xrefs, prev = NULL; cur; prev = cur, cur = cur->next) { |
if(cur->or_addr > addr) |
break; |
} |
|
if(prev) |
prev->next = new; |
else |
dp->xrefs = new; |
new->next = cur; |
|
return new; |
} |
|
/* Returns non-zero if the jump is into this page, 0 otherwise */ |
static int find_jump_loc(oraddr_t j_ea, struct op_queue *opq) |
{ |
struct dyn_page *dp; |
int i; |
struct x_ref *xref = NULL; |
int *ops; |
|
/* Mark the jump as non page local if the delay slot instruction is on the |
* next page to the jump instruction. This should not be needed */ |
if((ADDR_PAGE(j_ea) != ADDR_PAGE(opq->insn_addr)) || |
(ADDR_PAGE(opq->insn_addr) != ADDR_PAGE(opq->insn_addr + 4))) |
/* We can't do anything as the j_ea (as passed to find_jump_loc) is a |
* VIRTUAL offset and the next physical page may not be the next VIRTUAL |
* page */ |
return 0; |
|
/* The jump is into the page currently undergoing dynamic recompilation */ |
|
/* FIXME: It would be great if we didn't have to do this (find_dynd...) (it is |
* already passed to recompile_page) */ |
dp = find_dynd_page(j_ea); |
|
/* Check if we have already x-refed this location */ |
if((xref = find_host_x_ref(dp->xrefs, j_ea))) { |
/* If we have already x-refed this location, don't x-ref it again */ |
if(!find_held_x_ref(dp->held_xrefs, j_ea)) { |
xref->ref++; |
add_to_held_xrefs(dp, xref); |
} |
} else { |
/* Stick this address into the page's x-ref table */ |
xref = add_to_xrefs(dp, j_ea); |
add_to_held_xrefs(dp, xref); |
} |
|
opq->xref = xref; |
|
/* If we haven't got to the location of the jump, everything is ok */ |
if(j_ea > opq->insn_addr) |
return 1; |
|
/* Insert temporary -> register code before the jump ea and register -> |
* temporary at the x-ref address */ |
while(opq->insn_addr > j_ea) opq = opq->prev; |
if(!opq->prev) |
/* We're at the begining of a page, no need to do anything */ |
return 1; |
|
/* Found location, insert code */ |
ship_gprs_out_t(opq->prev, 1, opq->reg_t); |
|
for(i = 0; i < NUM_T_REGS; i++) { |
if(opq->reg_t[i] < 32) { |
gen_op_move_t_gpr[i][opq->reg_t[i]](opq, 0); |
opq->reg_t[i] = 32; |
} |
} |
|
/* In the event of a page local jump that jumps backwards (l.j -4) the cross |
* reference to the target may not have existed when the jump-ed to adress was |
* recompiled and if the jump-ed to address is in the delay slot of another |
* jump instruction an op_jmp_imm_check operation must be generated and not an |
* op_jmp_imm operation */ |
for(ops = opq->ops, i = 0; i < opq->num_ops; i++, ops++) { |
if(*ops == op_jmp_imm_indx) |
*ops = op_jmp_imm_check_indx; |
else if(*ops == op_set_pc_preemt_indx) |
*ops = op_set_pc_preemt_check_indx; |
} |
|
return 1; |
} |
|
/*------------------------------[ Operation generation for an instruction ]---*/ |
/* FIXME: Flag setting is not done in any instruction */ |
/* FIXME: Since r0 is not moved into a temporary, check all arguments below! */ |
|
static const generic_gen_op clear_t[NUM_T_REGS] = |
{ gen_op_clear_t0, gen_op_clear_t1, gen_op_clear_t2 }; |
|
static const generic_gen_op move_t_t[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { NULL, gen_op_move_t0_t1, gen_op_move_t0_t2 }, |
/* param0 -> t1 */ { gen_op_move_t1_t0, NULL, gen_op_move_t1_t2 }, |
/* param0 -> t2 */ { gen_op_move_t2_t0, gen_op_move_t2_t1, NULL } }; |
|
static const imm_gen_op mov_t_imm[NUM_T_REGS] = |
{ gen_op_t0_imm, gen_op_t1_imm, gen_op_t2_imm }; |
|
static const imm_gen_op l_add_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_add_imm_t0_t0, gen_op_add_imm_t0_t1, gen_op_add_imm_t0_t2 }, |
/* param0 -> t1 */ { gen_op_add_imm_t1_t0, gen_op_add_imm_t1_t1, gen_op_add_imm_t1_t2 }, |
/* param0 -> t2 */ { gen_op_add_imm_t2_t0, gen_op_add_imm_t2_t1, gen_op_add_imm_t2_t2 } }; |
|
static const generic_gen_op l_add_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_add_t0_t0_t0, gen_op_add_t0_t0_t1, gen_op_add_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_add_t0_t1_t0, gen_op_add_t0_t1_t1, gen_op_add_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_add_t0_t2_t0, gen_op_add_t0_t2_t1, gen_op_add_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_add_t1_t0_t0, gen_op_add_t1_t0_t1, gen_op_add_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_add_t1_t1_t0, gen_op_add_t1_t1_t1, gen_op_add_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_add_t1_t2_t0, gen_op_add_t1_t2_t1, gen_op_add_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_add_t2_t0_t0, gen_op_add_t2_t0_t1, gen_op_add_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_add_t2_t1_t0, gen_op_add_t2_t1_t1, gen_op_add_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_add_t2_t2_t0, gen_op_add_t2_t2_t1, gen_op_add_t2_t2_t2 } } }; |
|
void gen_l_add(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
/* Screw this, the operation shall do nothing */ |
return; |
|
if(!param[1] && !param[2]) { |
/* Just clear param_t[0] */ |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(!param[2]) { |
if(param[0] != param[1]) |
/* This just moves a register */ |
move_t_t[param_t[0]][param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
/* Check if we are moveing an immediate */ |
if(param_t[2] == T_NONE) { |
/* Yep, an immediate */ |
mov_t_imm[param_t[0]](opq, 1, param[2]); |
return; |
} |
/* Just another move */ |
if(param[0] != param[2]) |
move_t_t[param_t[0]][param_t[2]](opq, 1); |
return; |
} |
|
/* Ok, This _IS_ an add... */ |
if(param_t[2] == T_NONE) |
/* immediate */ |
l_add_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); |
else |
l_add_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
static const generic_gen_op l_addc_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_addc_t0_t0_t0, gen_op_addc_t0_t0_t1, gen_op_addc_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_addc_t0_t1_t0, gen_op_addc_t0_t1_t1, gen_op_addc_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_addc_t0_t2_t0, gen_op_addc_t0_t2_t1, gen_op_addc_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_addc_t1_t0_t0, gen_op_addc_t1_t0_t1, gen_op_addc_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_addc_t1_t1_t0, gen_op_addc_t1_t1_t1, gen_op_addc_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_addc_t1_t2_t0, gen_op_addc_t1_t2_t1, gen_op_addc_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_addc_t2_t0_t0, gen_op_addc_t2_t0_t1, gen_op_addc_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_addc_t2_t1_t0, gen_op_addc_t2_t1_t1, gen_op_addc_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_addc_t2_t2_t0, gen_op_addc_t2_t2_t1, gen_op_addc_t2_t2_t2 } } }; |
|
void gen_l_addc(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
/* Screw this, the operation shall do nothing */ |
return; |
|
/* FIXME: More optimisations !! (...and immediate...) */ |
l_addc_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
static const imm_gen_op l_and_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_and_imm_t0_t0, gen_op_and_imm_t0_t1, gen_op_and_imm_t0_t2 }, |
/* param0 -> t1 */ { gen_op_and_imm_t1_t0, gen_op_and_imm_t1_t1, gen_op_and_imm_t1_t2 }, |
/* param0 -> t2 */ { gen_op_and_imm_t2_t0, gen_op_and_imm_t2_t1, gen_op_and_imm_t2_t2 } }; |
|
static const generic_gen_op l_and_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { NULL, gen_op_and_t0_t0_t1, gen_op_and_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_and_t0_t1_t0, gen_op_and_t0_t1_t1, gen_op_and_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_and_t0_t2_t0, gen_op_and_t0_t2_t1, gen_op_and_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_and_t1_t0_t0, gen_op_and_t1_t0_t1, gen_op_and_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_and_t1_t1_t0, NULL, gen_op_and_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_and_t1_t2_t0, gen_op_and_t1_t2_t1, gen_op_and_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_and_t2_t0_t0, gen_op_and_t2_t0_t1, gen_op_and_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_and_t2_t1_t0, gen_op_and_t2_t1_t1, gen_op_and_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_and_t2_t2_t0, gen_op_and_t2_t2_t1, NULL } } }; |
|
void gen_l_and(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
/* Screw this, the operation shall do nothing */ |
return; |
|
if(!param[1] || !param[2]) { |
/* Just clear param_t[0] */ |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if((param[0] == param[1] == param[2]) && (param_t[2] != T_NONE)) |
return; |
|
if(param_t[2] == T_NONE) |
l_and_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); |
else |
l_and_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
void gen_l_bf(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
opq->jump_local = find_jump_loc(opq->insn_addr + (orreg_t)(param[0] << 2), opq); |
gen_op_check_flag(opq, 1, param[0] << 2); |
} |
|
void gen_l_bnf(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
opq->jump_local = find_jump_loc(opq->insn_addr + (orreg_t)(param[0] << 2), opq); |
gen_op_check_not_flag(opq, 1, param[0] << 2); |
} |
|
static const generic_gen_op l_cmov_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { NULL, gen_op_cmov_t0_t0_t1, gen_op_cmov_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_cmov_t0_t1_t0, NULL, gen_op_cmov_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_cmov_t0_t2_t0, gen_op_cmov_t0_t2_t1, NULL } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { NULL, gen_op_cmov_t1_t0_t1, gen_op_cmov_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_cmov_t1_t1_t0, NULL, gen_op_cmov_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_cmov_t1_t2_t0, gen_op_cmov_t1_t2_t1, NULL } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { NULL, gen_op_cmov_t2_t0_t1, gen_op_cmov_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_cmov_t2_t1_t0, NULL, gen_op_cmov_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_cmov_t2_t2_t0, gen_op_cmov_t2_t2_t1, NULL } } }; |
|
/* FIXME: Check if either opperand 1 or 2 is r0 */ |
void gen_l_cmov(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1] && !param[2]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(param[1] == param[2]) { |
move_t_t[param_t[0]][param_t[1]](opq, 1); |
return; |
} |
|
if((param[1] == param[2]) && (param[0] == param[1])) |
return; |
|
l_cmov_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
void gen_l_cust1(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
} |
|
void gen_l_cust2(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
} |
|
void gen_l_cust3(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
} |
|
void gen_l_cust4(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
} |
|
void gen_l_cust5(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
} |
|
void gen_l_cust6(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
} |
|
void gen_l_cust7(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
} |
|
void gen_l_cust8(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
} |
|
/* FIXME: All registers need to be stored before the div instructions as they |
* have the potenticial to cause an exception */ |
|
static const generic_gen_op check_null_excpt[NUM_T_REGS] = |
{ gen_op_check_null_except_t0, gen_op_check_null_except_t1, gen_op_check_null_except_t2 }; |
|
static const generic_gen_op check_null_excpt_delay[NUM_T_REGS] = { |
gen_op_check_null_except_t0_delay, |
gen_op_check_null_except_t1_delay, |
gen_op_check_null_except_t2_delay }; |
|
static const generic_gen_op l_div_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_div_t0_t0_t0, gen_op_div_t0_t0_t1, gen_op_div_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_div_t0_t1_t0, gen_op_div_t0_t1_t1, gen_op_div_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_div_t0_t2_t0, gen_op_div_t0_t2_t1, gen_op_div_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_div_t1_t0_t0, gen_op_div_t1_t0_t1, gen_op_div_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_div_t1_t1_t0, gen_op_div_t1_t1_t1, gen_op_div_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_div_t1_t2_t0, gen_op_div_t1_t2_t1, gen_op_div_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_div_t2_t0_t0, gen_op_div_t2_t0_t1, gen_op_div_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_div_t2_t1_t0, gen_op_div_t2_t1_t1, gen_op_div_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_div_t2_t2_t0, gen_op_div_t2_t2_t1, gen_op_div_t2_t2_t2 } } }; |
|
void gen_l_div(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
/* Cross reference this location, since an ILLEGAL exception may happen */ |
find_jump_loc(opq->insn_addr, opq); |
if(!param[2]) { |
/* There is no option. This _will_ cause an illeagal exception */ |
if(!delay_slot) |
gen_op_illegal(opq, 1); |
else |
gen_op_illegal(opq, 1); |
return; |
} |
|
if(!delay_slot) |
check_null_excpt[param_t[2]](opq, 1); |
else |
check_null_excpt_delay[param_t[2]](opq, 1); |
|
if(!param[0]) |
return; |
|
if(!param[1]) { |
/* Clear param_t[0] */ |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
l_div_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
static const generic_gen_op l_divu_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_divu_t0_t0_t0, gen_op_divu_t0_t0_t1, gen_op_divu_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_divu_t0_t1_t0, gen_op_divu_t0_t1_t1, gen_op_divu_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_divu_t0_t2_t0, gen_op_divu_t0_t2_t1, gen_op_divu_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_divu_t1_t0_t0, gen_op_divu_t1_t0_t1, gen_op_divu_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_divu_t1_t1_t0, gen_op_divu_t1_t1_t1, gen_op_divu_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_divu_t1_t2_t0, gen_op_divu_t1_t2_t1, gen_op_divu_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_divu_t2_t0_t0, gen_op_divu_t2_t0_t1, gen_op_divu_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_divu_t2_t1_t0, gen_op_divu_t2_t1_t1, gen_op_divu_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_divu_t2_t2_t0, gen_op_divu_t2_t2_t1, gen_op_divu_t2_t2_t2 } } }; |
|
void gen_l_divu(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
/* Cross reference this location, since an ILLEGAL exception may happen */ |
find_jump_loc(opq->insn_addr, opq); |
if(!param[2]) { |
/* There is no option. This _will_ cause an illeagal exception */ |
if(!delay_slot) |
gen_op_illegal(opq, 1); |
else |
gen_op_illegal(opq, 1); |
return; |
} |
|
if(!delay_slot) |
check_null_excpt[param_t[2]](opq, 1); |
else |
check_null_excpt_delay[param_t[2]](opq, 1); |
|
if(!param[0]) |
return; |
|
if(!param[1]) { |
/* Clear param_t[0] */ |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
l_divu_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
static const generic_gen_op l_extbs_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_extbs_t0_t0, gen_op_extbs_t0_t1, gen_op_extbs_t0_t2 }, |
/* param0 -> t1 */ { gen_op_extbs_t1_t0, gen_op_extbs_t1_t1, gen_op_extbs_t1_t2 }, |
/* param0 -> t2 */ { gen_op_extbs_t2_t0, gen_op_extbs_t2_t1, gen_op_extbs_t2_t2 } }; |
|
void gen_l_extbs(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
l_extbs_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const generic_gen_op l_extbz_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_extbz_t0_t0, gen_op_extbz_t0_t1, gen_op_extbz_t0_t2 }, |
/* param0 -> t1 */ { gen_op_extbz_t1_t0, gen_op_extbz_t1_t1, gen_op_extbz_t1_t2 }, |
/* param0 -> t2 */ { gen_op_extbz_t2_t0, gen_op_extbz_t2_t1, gen_op_extbz_t2_t2 } }; |
|
void gen_l_extbz(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
l_extbz_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const generic_gen_op l_exths_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_exths_t0_t0, gen_op_exths_t0_t1, gen_op_exths_t0_t2 }, |
/* param0 -> t1 */ { gen_op_exths_t1_t0, gen_op_exths_t1_t1, gen_op_exths_t1_t2 }, |
/* param0 -> t2 */ { gen_op_exths_t2_t0, gen_op_exths_t2_t1, gen_op_exths_t2_t2 } }; |
|
void gen_l_exths(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
l_exths_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const generic_gen_op l_exthz_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_exthz_t0_t0, gen_op_exthz_t0_t1, gen_op_exthz_t0_t2 }, |
/* param0 -> t1 */ { gen_op_exthz_t1_t0, gen_op_exthz_t1_t1, gen_op_exthz_t1_t2 }, |
/* param0 -> t2 */ { gen_op_exthz_t2_t0, gen_op_exthz_t2_t1, gen_op_exthz_t2_t2 } }; |
|
void gen_l_exthz(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
l_exthz_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
void gen_l_extws(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(param[0] == param[1]) |
return; |
|
/* In the 32-bit architechture this instruction reduces to a move */ |
move_t_t[param_t[0]][param_t[1]](opq, 1); |
} |
|
void gen_l_extwz(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(param[0] == param[1]) |
return; |
|
/* In the 32-bit architechture this instruction reduces to a move */ |
move_t_t[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const generic_gen_op l_ff1_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_ff1_t0_t0, gen_op_ff1_t0_t1, gen_op_ff1_t0_t2 }, |
/* param0 -> t1 */ { gen_op_ff1_t1_t0, gen_op_ff1_t1_t1, gen_op_ff1_t1_t2 }, |
/* param0 -> t2 */ { gen_op_ff1_t2_t0, gen_op_ff1_t2_t1, gen_op_ff1_t2_t2 } }; |
|
void gen_l_ff1(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
l_ff1_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
void gen_l_j(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_op_set_pc_delay_imm(opq, 1, param[0] << 2); |
|
/* Don't allocate a seporate x-ref structure for the infinite loop instruction |
* (l.j 0) */ |
if(!param[0]) { |
opq->jump_local = 2; |
opq->xref = cpu_state.inf_xrefs; |
opq->xref->or_addr = opq->insn_addr; |
cpu_state.inf_xrefs = opq->xref->next; |
return; |
} |
|
opq->jump_local = find_jump_loc(opq->insn_addr + (orreg_t)(param[0] << 2), opq); |
} |
|
void gen_l_jal(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
/* It is highly likely that the location that was jumped to will `return'. |
* Therefore, insert a cross reference at that address */ |
find_jump_loc(opq->insn_addr + 8, opq); |
|
gen_l_j(opq, param_t, param, delay_slot); |
|
/* Store the return address */ |
gen_op_store_link_addr_gpr(opq, 1); |
} |
|
static const generic_gen_op set_pc_delay_t[NUM_T_REGS] = |
{ gen_op_set_pc_delay_t0, gen_op_set_pc_delay_t1, gen_op_set_pc_delay_t2 }; |
|
void gen_l_jr(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
/* Treat all jumps as non page-local */ |
opq->jump_local = 0; |
|
if(!param[0]) { |
gen_op_clear_pc_delay(opq, 1); |
return; |
} |
|
set_pc_delay_t[param_t[0]](opq, 1); |
} |
|
void gen_l_jalr(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
/* It is highly likely that the location that was jumped to will `return'. |
* Therefore, insert a cross reference at that address */ |
find_jump_loc(opq->insn_addr + 8, opq); |
|
gen_l_jr(opq, param_t, param, delay_slot); |
|
/* Store the return address */ |
gen_op_store_link_addr_gpr(opq, 1); |
} |
|
/* FIXME: Optimise all load instruction when the disposition == 0 */ |
|
static const imm_gen_op l_lbs_imm_t_table[NUM_T_REGS] = |
{ gen_op_lbs_imm_t0, gen_op_lbs_imm_t1, gen_op_lbs_imm_t2 }; |
|
static const imm_gen_op l_lbs_t_table[3][3] = { |
/* param0 -> t0 */ { gen_op_lbs_t0_t0, gen_op_lbs_t0_t1, gen_op_lbs_t0_t2 }, |
/* param0 -> t1 */ { gen_op_lbs_t1_t0, gen_op_lbs_t1_t1, gen_op_lbs_t1_t2 }, |
/* param0 -> t2 */ { gen_op_lbs_t2_t0, gen_op_lbs_t2_t1, gen_op_lbs_t2_t2 } }; |
|
void gen_l_lbs(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) { |
/* FIXME: This will work, but the statistics need to be updated... */ |
return; |
} |
|
if(!param[2]) { |
/* Load the data from the immediate */ |
l_lbs_imm_t_table[param_t[0]](opq, 1, param[1]); |
return; |
} |
|
l_lbs_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); |
} |
|
static const imm_gen_op l_lbz_imm_t_table[NUM_T_REGS] = |
{ gen_op_lbz_imm_t0, gen_op_lbz_imm_t1, gen_op_lbz_imm_t2 }; |
|
static const imm_gen_op l_lbz_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_lbz_t0_t0, gen_op_lbz_t0_t1, gen_op_lbz_t0_t2 }, |
/* param0 -> t1 */ { gen_op_lbz_t1_t0, gen_op_lbz_t1_t1, gen_op_lbz_t1_t2 }, |
/* param0 -> t2 */ { gen_op_lbz_t2_t0, gen_op_lbz_t2_t1, gen_op_lbz_t2_t2 } }; |
|
void gen_l_lbz(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) { |
/* FIXME: This will work, but the statistics need to be updated... */ |
return; |
} |
|
if(!param[2]) { |
/* Load the data from the immediate */ |
l_lbz_imm_t_table[param_t[0]](opq, 1, param[1]); |
return; |
} |
|
l_lbz_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); |
} |
|
static const imm_gen_op l_lhs_imm_t_table[NUM_T_REGS] = |
{ gen_op_lhs_imm_t0, gen_op_lhs_imm_t1, gen_op_lhs_imm_t2 }; |
|
static const imm_gen_op l_lhs_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_lhs_t0_t0, gen_op_lhs_t0_t1, gen_op_lhs_t0_t2 }, |
/* param0 -> t1 */ { gen_op_lhs_t1_t0, gen_op_lhs_t1_t1, gen_op_lhs_t1_t2 }, |
/* param0 -> t2 */ { gen_op_lhs_t2_t0, gen_op_lhs_t2_t1, gen_op_lhs_t2_t2 } }; |
|
void gen_l_lhs(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) { |
/* FIXME: This will work, but the statistics need to be updated... */ |
return; |
} |
|
if(!param[2]) { |
/* Load the data from the immediate */ |
l_lhs_imm_t_table[param_t[0]](opq, 1, param[1]); |
return; |
} |
|
l_lhs_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); |
} |
|
static const imm_gen_op l_lhz_imm_t_table[NUM_T_REGS] = |
{ gen_op_lhz_imm_t0, gen_op_lhz_imm_t1, gen_op_lhz_imm_t2 }; |
|
static const imm_gen_op l_lhz_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_lhz_t0_t0, gen_op_lhz_t0_t1, gen_op_lhz_t0_t2 }, |
/* param0 -> t1 */ { gen_op_lhz_t1_t0, gen_op_lhz_t1_t1, gen_op_lhz_t1_t2 }, |
/* param0 -> t2 */ { gen_op_lhz_t2_t0, gen_op_lhz_t2_t1, gen_op_lhz_t2_t2 } }; |
|
void gen_l_lhz(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) { |
/* FIXME: This will work, but the statistics need to be updated... */ |
return; |
} |
|
if(!param[2]) { |
/* Load the data from the immediate */ |
l_lhz_imm_t_table[param_t[0]](opq, 1, param[1]); |
return; |
} |
|
l_lhz_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); |
} |
|
static const imm_gen_op l_lws_imm_t_table[NUM_T_REGS] = |
{ gen_op_lws_imm_t0, gen_op_lws_imm_t1, gen_op_lws_imm_t2 }; |
|
static const imm_gen_op l_lws_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_lws_t0_t0, gen_op_lws_t0_t1, gen_op_lws_t0_t2 }, |
/* param0 -> t1 */ { gen_op_lws_t1_t0, gen_op_lws_t1_t1, gen_op_lws_t1_t2 }, |
/* param0 -> t2 */ { gen_op_lws_t2_t0, gen_op_lws_t2_t1, gen_op_lws_t2_t2 } }; |
|
void gen_l_lws(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) { |
/* FIXME: This will work, but the statistics need to be updated... */ |
return; |
} |
|
if(!param[2]) { |
/* Load the data from the immediate */ |
l_lws_imm_t_table[param_t[0]](opq, 1, param[1]); |
return; |
} |
|
l_lws_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); |
} |
|
static const imm_gen_op l_lwz_imm_t_table[NUM_T_REGS] = |
{ gen_op_lwz_imm_t0, gen_op_lwz_imm_t1, gen_op_lwz_imm_t2 }; |
|
static const imm_gen_op l_lwz_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_lwz_t0_t0, gen_op_lwz_t0_t1, gen_op_lwz_t0_t2 }, |
/* param0 -> t1 */ { gen_op_lwz_t1_t0, gen_op_lwz_t1_t1, gen_op_lwz_t1_t2 }, |
/* param0 -> t2 */ { gen_op_lwz_t2_t0, gen_op_lwz_t2_t1, gen_op_lwz_t2_t2 } }; |
|
void gen_l_lwz(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) { |
/* FIXME: This will work, but the statistics need to be updated... */ |
return; |
} |
|
if(!param[2]) { |
/* Load the data from the immediate */ |
l_lwz_imm_t_table[param_t[0]](opq, 1, param[1]); |
return; |
} |
|
l_lwz_t_table[param_t[0]][param_t[2]](opq, 1, param[1]); |
} |
|
static const imm_gen_op l_mac_imm_t_table[NUM_T_REGS] = |
{ gen_op_mac_imm_t0, gen_op_mac_imm_t1, gen_op_mac_imm_t2 }; |
|
static const generic_gen_op l_mac_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_mac_t0_t0, gen_op_mac_t0_t1, gen_op_mac_t0_t2 }, |
/* param0 -> t1 */ { gen_op_mac_t0_t1, gen_op_mac_t1_t1, gen_op_mac_t1_t2 }, |
/* param0 -> t2 */ { gen_op_mac_t0_t2, gen_op_mac_t1_t2, gen_op_mac_t2_t2 } }; |
|
void gen_l_mac(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] || !param[1]) |
return; |
|
if(param_t[1] == T_NONE) |
l_mac_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_mac_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const generic_gen_op l_macrc_t_table[NUM_T_REGS] = |
{ gen_op_macrc_t0, gen_op_macrc_t1, gen_op_macrc_t2 }; |
|
void gen_l_macrc(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) { |
gen_op_macc(opq, 1); |
return; |
} |
|
l_macrc_t_table[param_t[0]](opq, 1); |
} |
|
static const imm_gen_op l_mfspr_imm_t_table[NUM_T_REGS] = |
{ gen_op_mfspr_t0_imm, gen_op_mfspr_t1_imm, gen_op_mfspr_t2_imm }; |
|
static const imm_gen_op l_mfspr_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_mfspr_t0_t0, gen_op_mfspr_t0_t1, gen_op_mfspr_t0_t2 }, |
/* param0 -> t1 */ { gen_op_mfspr_t1_t0, gen_op_mfspr_t1_t1, gen_op_mfspr_t1_t2 }, |
/* param0 -> t2 */ { gen_op_mfspr_t2_t0, gen_op_mfspr_t2_t1, gen_op_mfspr_t2_t2 } }; |
|
void gen_l_mfspr(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
l_mfspr_imm_t_table[param_t[0]](opq, 1, param[2]); |
return; |
} |
|
l_mfspr_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); |
} |
|
void gen_l_movhi(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
mov_t_imm[param_t[0]](opq, 1, param[1] << 16); |
} |
|
static const generic_gen_op l_msb_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_msb_t0_t0, gen_op_msb_t0_t1, gen_op_msb_t0_t2 }, |
/* param0 -> t1 */ { gen_op_msb_t0_t1, gen_op_msb_t1_t1, gen_op_msb_t1_t2 }, |
/* param0 -> t2 */ { gen_op_msb_t0_t2, gen_op_msb_t1_t2, gen_op_msb_t2_t2 } }; |
|
void gen_l_msb(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] || !param[1]) |
return; |
|
l_msb_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const imm_gen_op l_mtspr_clear_t_table[NUM_T_REGS] = |
{ gen_op_mtspr_t0_clear, gen_op_mtspr_t1_clear, gen_op_mtspr_t2_clear }; |
|
static const imm_gen_op l_mtspr_imm_t_table[NUM_T_REGS] = |
{ gen_op_mtspr_imm_t0, gen_op_mtspr_imm_t1, gen_op_mtspr_imm_t2 }; |
|
static const imm_gen_op l_mtspr_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_mtspr_t0_t0, gen_op_mtspr_t0_t1, gen_op_mtspr_t0_t2 }, |
/* param0 -> t1 */ { gen_op_mtspr_t1_t0, gen_op_mtspr_t1_t1, gen_op_mtspr_t1_t2 }, |
/* param0 -> t2 */ { gen_op_mtspr_t2_t0, gen_op_mtspr_t2_t1, gen_op_mtspr_t2_t2 } }; |
|
void gen_l_mtspr(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) { |
if(!param[1]) { |
/* Clear the immediate SPR */ |
gen_op_mtspr_imm_clear(opq, 1, param[2]); |
return; |
} |
l_mtspr_imm_t_table[param_t[1]](opq, 1, param[2]); |
return; |
} |
|
if(!param[1]) { |
l_mtspr_clear_t_table[param_t[0]](opq, 1, param[2]); |
return; |
} |
|
l_mtspr_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); |
} |
|
static const imm_gen_op l_mul_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_mul_imm_t0_t0, gen_op_mul_imm_t0_t1, gen_op_mul_imm_t0_t2 }, |
/* param0 -> t1 */ { gen_op_mul_imm_t1_t0, gen_op_mul_imm_t1_t1, gen_op_mul_imm_t1_t2 }, |
/* param0 -> t2 */ { gen_op_mul_imm_t2_t0, gen_op_mul_imm_t2_t1, gen_op_mul_imm_t2_t2 } }; |
|
static const generic_gen_op l_mul_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_mul_t0_t0_t0, gen_op_mul_t0_t0_t1, gen_op_mul_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_mul_t0_t1_t0, gen_op_mul_t0_t1_t1, gen_op_mul_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_mul_t0_t2_t0, gen_op_mul_t0_t2_t1, gen_op_mul_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_mul_t1_t0_t0, gen_op_mul_t1_t0_t1, gen_op_mul_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_mul_t1_t1_t0, gen_op_mul_t1_t1_t1, gen_op_mul_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_mul_t1_t2_t0, gen_op_mul_t1_t2_t1, gen_op_mul_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_mul_t2_t0_t0, gen_op_mul_t2_t0_t1, gen_op_mul_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_mul_t2_t1_t0, gen_op_mul_t2_t1_t1, gen_op_mul_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_mul_t2_t2_t0, gen_op_mul_t2_t2_t1, gen_op_mul_t2_t2_t2 } } }; |
|
void gen_l_mul(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1] || !param[2]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(param_t[2] == T_NONE) |
l_mul_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); |
else |
l_mul_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
static const generic_gen_op l_mulu_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_mulu_t0_t0_t0, gen_op_mulu_t0_t0_t1, gen_op_mulu_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_mulu_t0_t1_t0, gen_op_mulu_t0_t1_t1, gen_op_mulu_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_mulu_t0_t2_t0, gen_op_mulu_t0_t2_t1, gen_op_mulu_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_mulu_t1_t0_t0, gen_op_mulu_t1_t0_t1, gen_op_mulu_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_mulu_t1_t1_t0, gen_op_mulu_t1_t1_t1, gen_op_mulu_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_mulu_t1_t2_t0, gen_op_mulu_t1_t2_t1, gen_op_mulu_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_mulu_t2_t0_t0, gen_op_mulu_t2_t0_t1, gen_op_mulu_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_mulu_t2_t1_t0, gen_op_mulu_t2_t1_t1, gen_op_mulu_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_mulu_t2_t2_t0, gen_op_mulu_t2_t2_t1, gen_op_mulu_t2_t2_t2 } } }; |
|
void gen_l_mulu(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1] || !param[2]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
l_mulu_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
void gen_l_nop(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
/* Do parameter switch now */ |
switch (param[0]) { |
case NOP_NOP: |
break; |
case NOP_EXIT: |
gen_op_nop_exit(opq, 1); |
break; |
case NOP_CNT_RESET: |
/* FIXME: Since op_nop_reset calls handle_except, this instruction wont show |
* up in the execution log, nor will the scheduler run */ |
gen_op_nop_reset(opq, 1); |
break; |
case NOP_PRINTF: |
gen_op_nop_printf(opq, 1); |
break; |
case NOP_REPORT: |
gen_op_nop_report(opq, 1); |
break; |
default: |
if((param[0] >= NOP_REPORT_FIRST) && (param[0] <= NOP_REPORT_LAST)) |
gen_op_nop_report_imm(opq, 1, param[0] - NOP_REPORT_FIRST); |
break; |
} |
} |
|
static const imm_gen_op l_or_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_or_imm_t0_t0, gen_op_or_imm_t0_t1, gen_op_or_imm_t0_t2 }, |
/* param0 -> t1 */ { gen_op_or_imm_t1_t0, gen_op_or_imm_t1_t1, gen_op_or_imm_t1_t2 }, |
/* param0 -> t2 */ { gen_op_or_imm_t2_t0, gen_op_or_imm_t2_t1, gen_op_or_imm_t2_t2 } }; |
|
static const generic_gen_op l_or_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { NULL, gen_op_or_t0_t0_t1, gen_op_or_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_or_t0_t1_t0, gen_op_or_t0_t1_t1, gen_op_or_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_or_t0_t2_t0, gen_op_or_t0_t2_t1, gen_op_or_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_or_t1_t0_t0, gen_op_or_t1_t0_t1, gen_op_or_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_or_t1_t1_t0, NULL, gen_op_or_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_or_t1_t2_t0, gen_op_or_t1_t2_t1, gen_op_or_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_or_t2_t0_t0, gen_op_or_t2_t0_t1, gen_op_or_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_or_t2_t1_t0, gen_op_or_t2_t1_t1, gen_op_or_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_or_t2_t2_t0, gen_op_or_t2_t2_t1, NULL } } }; |
|
void gen_l_or(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if((param[0] == param[1] == param[2]) && (param_t[2] != T_NONE)) |
return; |
|
if(!param[1] && !param[2]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(!param[2]) { |
if((param_t[2] == T_NONE) && (param[0] == param[1])) |
return; |
move_t_t[param_t[0]][param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
/* Check if we are moveing an immediate */ |
if(param_t[2] == T_NONE) { |
/* Yep, an immediate */ |
mov_t_imm[param_t[0]](opq, 1, param[2]); |
return; |
} |
/* Just another move */ |
move_t_t[param_t[0]][param_t[2]](opq, 1); |
return; |
} |
|
if(param_t[2] == T_NONE) |
l_or_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); |
else |
l_or_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
void gen_l_rfe(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_op_prep_rfe(opq, 1); |
} |
|
/* FIXME: All store instructions should be optimised when the disposition = 0 */ |
|
static const imm_gen_op l_sb_clear_table[NUM_T_REGS] = |
{ gen_op_sb_clear_t0, gen_op_sb_clear_t1, gen_op_sb_clear_t2 }; |
|
static const imm_gen_op l_sb_imm_t_table[NUM_T_REGS] = |
{ gen_op_sb_imm_t0, gen_op_sb_imm_t1, gen_op_sb_imm_t2 }; |
|
static const imm_gen_op l_sb_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sb_t0_t0, gen_op_sb_t0_t1, gen_op_sb_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sb_t1_t0, gen_op_sb_t1_t1, gen_op_sb_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sb_t2_t0, gen_op_sb_t2_t1, gen_op_sb_t2_t2 } }; |
|
void gen_l_sb(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[2]) { |
if(!param[1]) { |
gen_op_sb_clear_imm(opq, 1, param[0]); |
return; |
} |
l_sb_clear_table[param_t[1]](opq, 1, param[0]); |
return; |
} |
|
if(!param[1]) { |
/* Store the data to the immediate */ |
l_sb_imm_t_table[param_t[2]](opq, 1, param[0]); |
return; |
} |
|
l_sb_t_table[param_t[1]][param_t[2]](opq, 1, param[0]); |
} |
|
static const imm_gen_op l_sh_clear_table[NUM_T_REGS] = |
{ gen_op_sh_clear_t0, gen_op_sh_clear_t1, gen_op_sh_clear_t2 }; |
|
static const imm_gen_op l_sh_imm_t_table[NUM_T_REGS] = |
{ gen_op_sh_imm_t0, gen_op_sh_imm_t1, gen_op_sh_imm_t2 }; |
|
static const imm_gen_op l_sh_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sh_t0_t0, gen_op_sh_t0_t1, gen_op_sh_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sh_t1_t0, gen_op_sh_t1_t1, gen_op_sh_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sh_t2_t0, gen_op_sh_t2_t1, gen_op_sh_t2_t2 } }; |
|
void gen_l_sh(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[2]) { |
if(!param[1]) { |
gen_op_sh_clear_imm(opq, 1, param[0]); |
return; |
} |
l_sh_clear_table[param_t[1]](opq, 1, param[0]); |
return; |
} |
|
if(!param[1]) { |
/* Store the data to the immediate */ |
l_sh_imm_t_table[param_t[2]](opq, 1, param[0]); |
return; |
} |
|
l_sh_t_table[param_t[1]][param_t[2]](opq, 1, param[0]); |
} |
|
static const imm_gen_op l_sw_clear_table[NUM_T_REGS] = |
{ gen_op_sw_clear_t0, gen_op_sw_clear_t1, gen_op_sw_clear_t2 }; |
|
static const imm_gen_op l_sw_imm_t_table[NUM_T_REGS] = |
{ gen_op_sw_imm_t0, gen_op_sw_imm_t1, gen_op_sw_imm_t2 }; |
|
static const imm_gen_op l_sw_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sw_t0_t0, gen_op_sw_t0_t1, gen_op_sw_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sw_t1_t0, gen_op_sw_t1_t1, gen_op_sw_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sw_t2_t0, gen_op_sw_t2_t1, gen_op_sw_t2_t2 } }; |
|
void gen_l_sw(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[2]) { |
if(!param[1]) { |
gen_op_sw_clear_imm(opq, 1, param[0]); |
return; |
} |
l_sw_clear_table[param_t[1]](opq, 1, param[0]); |
return; |
} |
|
if(!param[1]) { |
/* Store the data to the immediate */ |
l_sw_imm_t_table[param_t[2]](opq, 1, param[0]); |
return; |
} |
|
l_sw_t_table[param_t[1]][param_t[2]](opq, 1, param[0]); |
} |
|
static const generic_gen_op l_sfeq_null_t_table[NUM_T_REGS] = |
{ gen_op_sfeq_null_t0, gen_op_sfeq_null_t1, gen_op_sfeq_null_t2 }; |
|
static const imm_gen_op l_sfeq_imm_t_table[NUM_T_REGS] = |
{ gen_op_sfeq_imm_t0, gen_op_sfeq_imm_t1, gen_op_sfeq_imm_t2 }; |
|
static const generic_gen_op l_sfeq_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sfeq_t0_t0, gen_op_sfeq_t0_t1, gen_op_sfeq_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sfeq_t1_t0, gen_op_sfeq_t1_t1, gen_op_sfeq_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sfeq_t2_t0, gen_op_sfeq_t2_t1, gen_op_sfeq_t2_t2 } }; |
|
void gen_l_sfeq(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] && !param[1]) { |
gen_op_set_flag(opq, 1); |
return; |
} |
|
if(!param[0]) { |
if(param_t[1] == T_NONE) { |
if(!param[1]) |
gen_op_set_flag(opq, 1); |
else |
gen_op_clear_flag(opq, 1); |
} else |
l_sfeq_null_t_table[param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
l_sfeq_null_t_table[param_t[0]](opq, 1); |
return; |
} |
|
if(param_t[1] == T_NONE) |
l_sfeq_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_sfeq_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const generic_gen_op l_sfges_null_t_table[NUM_T_REGS] = |
{ gen_op_sfges_null_t0, gen_op_sfges_null_t1, gen_op_sfges_null_t2 }; |
|
static const generic_gen_op l_sfles_null_t_table[NUM_T_REGS] = |
{ gen_op_sfles_null_t0, gen_op_sfles_null_t1, gen_op_sfles_null_t2 }; |
|
static const imm_gen_op l_sfges_imm_t_table[NUM_T_REGS] = |
{ gen_op_sfges_imm_t0, gen_op_sfges_imm_t1, gen_op_sfges_imm_t2 }; |
|
static const generic_gen_op l_sfges_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sfges_t0_t0, gen_op_sfges_t0_t1, gen_op_sfges_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sfges_t1_t0, gen_op_sfges_t1_t1, gen_op_sfges_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sfges_t2_t0, gen_op_sfges_t2_t1, gen_op_sfges_t2_t2 } }; |
|
void gen_l_sfges(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] && !param[1]) { |
gen_op_set_flag(opq, 1); |
return; |
} |
|
if(!param[0]) { |
/* sfles IS correct */ |
if(param_t[1] == T_NONE) { |
if(0 >= (orreg_t)param[1]) |
gen_op_set_flag(opq, 1); |
else |
gen_op_clear_flag(opq, 1); |
} else |
l_sfles_null_t_table[param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
l_sfges_null_t_table[param_t[0]](opq, 1); |
return; |
} |
|
if(param_t[1] == T_NONE) |
l_sfges_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_sfges_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const generic_gen_op l_sfgeu_null_t_table[NUM_T_REGS] = |
{ gen_op_sfgeu_null_t0, gen_op_sfgeu_null_t1, gen_op_sfgeu_null_t2 }; |
|
static const generic_gen_op l_sfleu_null_t_table[NUM_T_REGS] = |
{ gen_op_sfleu_null_t0, gen_op_sfleu_null_t1, gen_op_sfleu_null_t2 }; |
|
static const imm_gen_op l_sfgeu_imm_t_table[NUM_T_REGS] = |
{ gen_op_sfgeu_imm_t0, gen_op_sfgeu_imm_t1, gen_op_sfgeu_imm_t2 }; |
|
static const generic_gen_op l_sfgeu_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sfgeu_t0_t0, gen_op_sfgeu_t0_t1, gen_op_sfgeu_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sfgeu_t1_t0, gen_op_sfgeu_t1_t1, gen_op_sfgeu_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sfgeu_t2_t0, gen_op_sfgeu_t2_t1, gen_op_sfgeu_t2_t2 } }; |
|
void gen_l_sfgeu(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] && !param[1]) { |
gen_op_set_flag(opq, 1); |
return; |
} |
|
if(!param[0]) { |
/* sfleu IS correct */ |
if(param_t[1] == T_NONE) { |
if(0 >= param[1]) |
gen_op_set_flag(opq, 1); |
else |
gen_op_clear_flag(opq, 1); |
} else |
l_sfleu_null_t_table[param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
l_sfgeu_null_t_table[param_t[0]](opq, 1); |
return; |
} |
if(param_t[1] == T_NONE) |
l_sfgeu_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_sfgeu_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const generic_gen_op l_sfgts_null_t_table[NUM_T_REGS] = |
{ gen_op_sfgts_null_t0, gen_op_sfgts_null_t1, gen_op_sfgts_null_t2 }; |
|
static const generic_gen_op l_sflts_null_t_table[NUM_T_REGS] = |
{ gen_op_sflts_null_t0, gen_op_sflts_null_t1, gen_op_sflts_null_t2 }; |
|
static const imm_gen_op l_sfgts_imm_t_table[NUM_T_REGS] = |
{ gen_op_sfgts_imm_t0, gen_op_sfgts_imm_t1, gen_op_sfgts_imm_t2 }; |
|
static const generic_gen_op l_sfgts_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sfgts_t0_t0, gen_op_sfgts_t0_t1, gen_op_sfgts_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sfgts_t1_t0, gen_op_sfgts_t1_t1, gen_op_sfgts_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sfgts_t2_t0, gen_op_sfgts_t2_t1, gen_op_sfgts_t2_t2 } }; |
|
void gen_l_sfgts(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] && !param[1]) { |
gen_op_clear_flag(opq, 1); |
return; |
} |
|
if(!param[0]) { |
/* sflts IS correct */ |
if(param_t[1] == T_NONE) { |
if(0 > (orreg_t)param[1]) |
gen_op_set_flag(opq, 1); |
else |
gen_op_clear_flag(opq, 1); |
} else |
l_sflts_null_t_table[param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
l_sfgts_null_t_table[param_t[0]](opq, 1); |
return; |
} |
|
if(param_t[1] == T_NONE) |
l_sfgts_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_sfgts_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const generic_gen_op l_sfgtu_null_t_table[NUM_T_REGS] = |
{ gen_op_sfgtu_null_t0, gen_op_sfgtu_null_t1, gen_op_sfgtu_null_t2 }; |
|
static const generic_gen_op l_sfltu_null_t_table[NUM_T_REGS] = |
{ gen_op_sfltu_null_t0, gen_op_sfltu_null_t1, gen_op_sfltu_null_t2 }; |
|
static const imm_gen_op l_sfgtu_imm_t_table[NUM_T_REGS] = |
{ gen_op_sfgtu_imm_t0, gen_op_sfgtu_imm_t1, gen_op_sfgtu_imm_t2 }; |
|
static const generic_gen_op l_sfgtu_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sfgtu_t0_t0, gen_op_sfgtu_t0_t1, gen_op_sfgtu_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sfgtu_t1_t0, gen_op_sfgtu_t1_t1, gen_op_sfgtu_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sfgtu_t2_t0, gen_op_sfgtu_t2_t1, gen_op_sfgtu_t2_t2 } }; |
|
void gen_l_sfgtu(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] && !param[1]) { |
gen_op_clear_flag(opq, 1); |
return; |
} |
|
if(!param[0]) { |
/* sfltu IS correct */ |
if(param_t[1] == T_NONE) { |
if(0 > param[1]) |
gen_op_set_flag(opq, 1); |
else |
gen_op_clear_flag(opq, 1); |
} else |
l_sfltu_null_t_table[param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
l_sfgtu_null_t_table[param_t[0]](opq, 1); |
return; |
} |
|
if(param_t[1] == T_NONE) |
l_sfgtu_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_sfgtu_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const imm_gen_op l_sfles_imm_t_table[NUM_T_REGS] = |
{ gen_op_sfles_imm_t0, gen_op_sfles_imm_t1, gen_op_sfles_imm_t2 }; |
|
static const generic_gen_op l_sfles_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sfles_t0_t0, gen_op_sfles_t0_t1, gen_op_sfles_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sfles_t1_t0, gen_op_sfles_t1_t1, gen_op_sfles_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sfles_t2_t0, gen_op_sfles_t2_t1, gen_op_sfles_t2_t2 } }; |
|
void gen_l_sfles(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] && !param[1]) { |
gen_op_set_flag(opq, 1); |
return; |
} |
|
if(!param[0]) { |
/* sfges IS correct */ |
if(param_t[1] == T_NONE) { |
if(0 <= (orreg_t)param[1]) |
gen_op_set_flag(opq, 1); |
else |
gen_op_clear_flag(opq, 1); |
} else |
l_sfges_null_t_table[param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
l_sfles_null_t_table[param_t[0]](opq, 1); |
return; |
} |
|
if(param_t[1] == T_NONE) |
l_sfles_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_sfles_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const imm_gen_op l_sfleu_imm_t_table[NUM_T_REGS] = |
{ gen_op_sfleu_imm_t0, gen_op_sfleu_imm_t1, gen_op_sfleu_imm_t2 }; |
|
static const generic_gen_op l_sfleu_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sfleu_t0_t0, gen_op_sfleu_t0_t1, gen_op_sfleu_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sfleu_t1_t0, gen_op_sfleu_t1_t1, gen_op_sfleu_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sfleu_t2_t0, gen_op_sfleu_t2_t1, gen_op_sfleu_t2_t2 } }; |
|
void gen_l_sfleu(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] && !param[1]) { |
gen_op_set_flag(opq, 1); |
return; |
} |
|
if(!param[0]) { |
/* sfleu IS correct */ |
if(param_t[1] == T_NONE) { |
if(0 <= param[1]) |
gen_op_set_flag(opq, 1); |
else |
gen_op_clear_flag(opq, 1); |
} else |
l_sfgeu_null_t_table[param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
l_sfleu_null_t_table[param_t[0]](opq, 1); |
return; |
} |
|
if(param_t[1] == T_NONE) |
l_sfleu_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_sfleu_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const imm_gen_op l_sflts_imm_t_table[NUM_T_REGS] = |
{ gen_op_sflts_imm_t0, gen_op_sflts_imm_t1, gen_op_sflts_imm_t2 }; |
|
static const generic_gen_op l_sflts_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sflts_t0_t0, gen_op_sflts_t0_t1, gen_op_sflts_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sflts_t1_t0, gen_op_sflts_t1_t1, gen_op_sflts_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sflts_t2_t0, gen_op_sflts_t2_t1, gen_op_sflts_t2_t2 } }; |
|
void gen_l_sflts(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] && !param[1]) { |
gen_op_clear_flag(opq, 1); |
return; |
} |
|
if(!param[0]) { |
/* sfgts IS correct */ |
if(param_t[1] == T_NONE) { |
if(0 < (orreg_t)param[1]) |
gen_op_set_flag(opq, 1); |
else |
gen_op_clear_flag(opq, 1); |
} else |
l_sfgts_null_t_table[param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
l_sflts_null_t_table[param_t[0]](opq, 1); |
return; |
} |
|
if(param_t[1] == T_NONE) |
l_sflts_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_sflts_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const imm_gen_op l_sfltu_imm_t_table[NUM_T_REGS] = |
{ gen_op_sfltu_imm_t0, gen_op_sfltu_imm_t1, gen_op_sfltu_imm_t2 }; |
|
static const generic_gen_op l_sfltu_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sfltu_t0_t0, gen_op_sfltu_t0_t1, gen_op_sfltu_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sfltu_t1_t0, gen_op_sfltu_t1_t1, gen_op_sfltu_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sfltu_t2_t0, gen_op_sfltu_t2_t1, gen_op_sfltu_t2_t2 } }; |
|
void gen_l_sfltu(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] && !param[1]) { |
gen_op_clear_flag(opq, 1); |
return; |
} |
|
if(!param[0]) { |
/* sfgtu IS correct */ |
if(param_t[1] == T_NONE) { |
if(0 < param[1]) |
gen_op_set_flag(opq, 1); |
else |
gen_op_clear_flag(opq, 1); |
} else |
l_sfgtu_null_t_table[param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
l_sfltu_null_t_table[param_t[0]](opq, 1); |
return; |
} |
|
if(param_t[1] == T_NONE) |
l_sfltu_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_sfltu_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const generic_gen_op l_sfne_null_t_table[NUM_T_REGS] = |
{ gen_op_sfne_null_t0, gen_op_sfne_null_t1, gen_op_sfne_null_t2 }; |
|
static const imm_gen_op l_sfne_imm_t_table[NUM_T_REGS] = |
{ gen_op_sfne_imm_t0, gen_op_sfne_imm_t1, gen_op_sfne_imm_t2 }; |
|
static const generic_gen_op l_sfne_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sfne_t0_t0, gen_op_sfne_t0_t1, gen_op_sfne_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sfne_t1_t0, gen_op_sfne_t1_t1, gen_op_sfne_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sfne_t2_t0, gen_op_sfne_t2_t1, gen_op_sfne_t2_t2 } }; |
|
void gen_l_sfne(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0] && !param[1]) { |
gen_op_set_flag(opq, 1); |
return; |
} |
|
if(!param[0]) { |
if(param_t[1] == T_NONE) |
if(param[1]) |
gen_op_set_flag(opq, 1); |
else |
gen_op_clear_flag(opq, 1); |
else |
l_sfne_null_t_table[param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
l_sfne_null_t_table[param_t[0]](opq, 1); |
return; |
} |
|
if(param_t[1] == T_NONE) |
l_sfne_imm_t_table[param_t[0]](opq, 1, param[1]); |
else |
l_sfne_t_table[param_t[0]][param_t[1]](opq, 1); |
} |
|
static const imm_gen_op l_sll_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sll_imm_t0_t0, gen_op_sll_imm_t0_t1, gen_op_sll_imm_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sll_imm_t1_t0, gen_op_sll_imm_t1_t1, gen_op_sll_imm_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sll_imm_t2_t0, gen_op_sll_imm_t2_t1, gen_op_sll_imm_t2_t2 } }; |
|
static const generic_gen_op l_sll_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_sll_t0_t0_t0, gen_op_sll_t0_t0_t1, gen_op_sll_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_sll_t0_t1_t0, gen_op_sll_t0_t1_t1, gen_op_sll_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_sll_t0_t2_t0, gen_op_sll_t0_t2_t1, gen_op_sll_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_sll_t1_t0_t0, gen_op_sll_t1_t0_t1, gen_op_sll_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_sll_t1_t1_t0, gen_op_sll_t1_t1_t1, gen_op_sll_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_sll_t1_t2_t0, gen_op_sll_t1_t2_t1, gen_op_sll_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_sll_t2_t0_t0, gen_op_sll_t2_t0_t1, gen_op_sll_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_sll_t2_t1_t0, gen_op_sll_t2_t1_t1, gen_op_sll_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_sll_t2_t2_t0, gen_op_sll_t2_t2_t1, gen_op_sll_t2_t2_t2 } } }; |
|
void gen_l_sll(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(!param[2]) { |
move_t_t[param_t[0]][param_t[1]](opq, 1); |
return; |
} |
|
if(param_t[2] == T_NONE) |
l_sll_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); |
else |
l_sll_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
static const imm_gen_op l_sra_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_sra_imm_t0_t0, gen_op_sra_imm_t0_t1, gen_op_sra_imm_t0_t2 }, |
/* param0 -> t1 */ { gen_op_sra_imm_t1_t0, gen_op_sra_imm_t1_t1, gen_op_sra_imm_t1_t2 }, |
/* param0 -> t2 */ { gen_op_sra_imm_t2_t0, gen_op_sra_imm_t2_t1, gen_op_sra_imm_t2_t2 } }; |
|
static const generic_gen_op l_sra_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_sra_t0_t0_t0, gen_op_sra_t0_t0_t1, gen_op_sra_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_sra_t0_t1_t0, gen_op_sra_t0_t1_t1, gen_op_sra_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_sra_t0_t2_t0, gen_op_sra_t0_t2_t1, gen_op_sra_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_sra_t1_t0_t0, gen_op_sra_t1_t0_t1, gen_op_sra_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_sra_t1_t1_t0, gen_op_sra_t1_t1_t1, gen_op_sra_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_sra_t1_t2_t0, gen_op_sra_t1_t2_t1, gen_op_sra_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_sra_t2_t0_t0, gen_op_sra_t2_t0_t1, gen_op_sra_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_sra_t2_t1_t0, gen_op_sra_t2_t1_t1, gen_op_sra_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_sra_t2_t2_t0, gen_op_sra_t2_t2_t1, gen_op_sra_t2_t2_t2 } } }; |
|
void gen_l_sra(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(!param[2]) { |
move_t_t[param_t[0]][param_t[1]](opq, 1); |
return; |
} |
|
if(param_t[2] == T_NONE) |
l_sra_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); |
else |
l_sra_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
static const imm_gen_op l_srl_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_srl_imm_t0_t0, gen_op_srl_imm_t0_t1, gen_op_srl_imm_t0_t2 }, |
/* param0 -> t1 */ { gen_op_srl_imm_t1_t0, gen_op_srl_imm_t1_t1, gen_op_srl_imm_t1_t2 }, |
/* param0 -> t2 */ { gen_op_srl_imm_t2_t0, gen_op_srl_imm_t2_t1, gen_op_srl_imm_t2_t2 } }; |
|
static const generic_gen_op l_srl_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_srl_t0_t0_t0, gen_op_srl_t0_t0_t1, gen_op_srl_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_srl_t0_t1_t0, gen_op_srl_t0_t1_t1, gen_op_srl_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_srl_t0_t2_t0, gen_op_srl_t0_t2_t1, gen_op_srl_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_srl_t1_t0_t0, gen_op_srl_t1_t0_t1, gen_op_srl_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_srl_t1_t1_t0, gen_op_srl_t1_t1_t1, gen_op_srl_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_srl_t1_t2_t0, gen_op_srl_t1_t2_t1, gen_op_srl_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_srl_t2_t0_t0, gen_op_srl_t2_t0_t1, gen_op_srl_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_srl_t2_t1_t0, gen_op_srl_t2_t1_t1, gen_op_srl_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_srl_t2_t2_t0, gen_op_srl_t2_t2_t1, gen_op_srl_t2_t2_t2 } } }; |
|
void gen_l_srl(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if(!param[1]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(!param[2]) { |
move_t_t[param_t[0]][param_t[1]](opq, 1); |
return; |
} |
|
if(param_t[2] == T_NONE) |
l_srl_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); |
else |
l_srl_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
static const generic_gen_op l_neg_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_neg_t0_t0, gen_op_neg_t0_t1, gen_op_neg_t0_t2 }, |
/* param0 -> t1 */ { gen_op_neg_t1_t0, gen_op_neg_t1_t1, gen_op_neg_t1_t2 }, |
/* param0 -> t2 */ { gen_op_neg_t2_t0, gen_op_neg_t2_t1, gen_op_neg_t2_t2 } }; |
|
static const generic_gen_op l_sub_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_sub_t0_t0_t0, gen_op_sub_t0_t0_t1, gen_op_sub_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_sub_t0_t1_t0, gen_op_sub_t0_t1_t1, gen_op_sub_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_sub_t0_t2_t0, gen_op_sub_t0_t2_t1, gen_op_sub_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_sub_t1_t0_t0, gen_op_sub_t1_t0_t1, gen_op_sub_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_sub_t1_t1_t0, gen_op_sub_t1_t1_t1, gen_op_sub_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_sub_t1_t2_t0, gen_op_sub_t1_t2_t1, gen_op_sub_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_sub_t2_t0_t0, gen_op_sub_t2_t0_t1, gen_op_sub_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_sub_t2_t1_t0, gen_op_sub_t2_t1_t1, gen_op_sub_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_sub_t2_t2_t0, gen_op_sub_t2_t2_t1, gen_op_sub_t2_t2_t2 } } }; |
|
void gen_l_sub(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if((param_t[2] != T_NONE) && (param[1] == param[2])) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(!param[1] && !param[2]) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
if(param_t[2] == T_NONE) |
mov_t_imm[param_t[0]](opq, 1, -param[2]); |
else |
l_neg_t_table[param_t[0]][param_t[2]](opq, 1); |
return; |
} |
|
if(!param[2]) { |
move_t_t[param_t[0]][param_t[1]](opq, 1); |
return; |
} |
|
l_sub_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
/* FIXME: This will not work if the l.sys is in a delay slot */ |
void gen_l_sys(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
/* Since we *know* that we *will* jump to the next instruction, insert an xref |
* there */ |
find_jump_loc(opq->insn_addr + 4, opq); |
|
if(!delay_slot) |
gen_op_prep_sys(opq, 1); |
else |
gen_op_prep_sys_delay(opq, 1); |
} |
|
/* FIXME: This will not work if the l.trap is in a delay slot */ |
void gen_l_trap(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
/* Since we *know* that we *will* jump to the next instruction, insert an xref |
* there */ |
find_jump_loc(opq->insn_addr + 4, opq); |
|
if(!delay_slot) |
gen_op_prep_trap(opq, 1); |
else |
gen_op_prep_trap_delay(opq, 1); |
} |
|
static const imm_gen_op l_xor_imm_t_table[NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { gen_op_xor_imm_t0_t0, gen_op_xor_imm_t0_t1, gen_op_xor_imm_t0_t2 }, |
/* param0 -> t1 */ { gen_op_xor_imm_t1_t0, gen_op_xor_imm_t1_t1, gen_op_xor_imm_t1_t2 }, |
/* param0 -> t2 */ { gen_op_xor_imm_t2_t0, gen_op_xor_imm_t2_t1, gen_op_xor_imm_t2_t2 } }; |
|
static const generic_gen_op l_xor_t_table[NUM_T_REGS][NUM_T_REGS][NUM_T_REGS] = { |
/* param0 -> t0 */ { |
/* param0 -> t0, param1 -> t0 */ { gen_op_xor_t0_t0_t0, gen_op_xor_t0_t0_t1, gen_op_xor_t0_t0_t2 }, |
/* param0 -> t0, param1 -> t1 */ { gen_op_xor_t0_t1_t0, gen_op_xor_t0_t1_t1, gen_op_xor_t0_t1_t2 }, |
/* param0 -> t0, param1 -> t2 */ { gen_op_xor_t0_t2_t0, gen_op_xor_t0_t2_t1, gen_op_xor_t0_t2_t2 } }, |
/* param0 -> t1 */ { |
/* param0 -> t1, param1 -> t0 */ { gen_op_xor_t1_t0_t0, gen_op_xor_t1_t0_t1, gen_op_xor_t1_t0_t2 }, |
/* param0 -> t1, param1 -> t1 */ { gen_op_xor_t1_t1_t0, gen_op_xor_t1_t1_t1, gen_op_xor_t1_t1_t2 }, |
/* param0 -> t1, param1 -> t2 */ { gen_op_xor_t1_t2_t0, gen_op_xor_t1_t2_t1, gen_op_xor_t1_t2_t2 } }, |
/* param0 -> t2 */ { |
/* param0 -> t2, param1 -> t0 */ { gen_op_xor_t2_t0_t0, gen_op_xor_t2_t0_t1, gen_op_xor_t2_t0_t2 }, |
/* param0 -> t2, param1 -> t1 */ { gen_op_xor_t2_t1_t0, gen_op_xor_t2_t1_t1, gen_op_xor_t2_t1_t2 }, |
/* param0 -> t2, param1 -> t2 */ { gen_op_xor_t2_t2_t0, gen_op_xor_t2_t2_t1, gen_op_xor_t2_t2_t2 } } }; |
|
void gen_l_xor(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
if(!param[0]) |
return; |
|
if((param_t[2] != T_NONE) && (param[1] == param[2])) { |
clear_t[param_t[0]](opq, 1); |
return; |
} |
|
if(!param[2]) { |
if((param_t[2] == T_NONE) && (param[0] == param[1])) |
return; |
move_t_t[param_t[0]][param_t[1]](opq, 1); |
return; |
} |
|
if(!param[1]) { |
if(param_t[2] == T_NONE) { |
mov_t_imm[param_t[0]](opq, 1, param[2]); |
return; |
} |
move_t_t[param_t[0]][param_t[2]](opq, 1); |
return; |
} |
|
if(param_t[2] == T_NONE) |
l_xor_imm_t_table[param_t[0]][param_t[1]](opq, 1, param[2]); |
else |
l_xor_t_table[param_t[0]][param_t[1]][param_t[2]](opq, 1); |
} |
|
void gen_l_invalid(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
/* The program running on openrisc may decide to patch this location, so |
* just cross reference this location just-in-case */ |
find_jump_loc(opq->insn_addr, opq); |
if(!delay_slot) |
gen_op_illegal(opq, 1); |
else |
gen_op_illegal_delay(opq, 1); |
} |
|
/*----------------------------------[ Floating point instructions (stubs) ]---*/ |
void gen_lf_add_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_div_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_ftoi_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_itof_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_madd_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_mul_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_rem_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_sfeq_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_sfge_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_sfgt_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_sfle_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_sflt_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_sfne_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
void gen_lf_sub_s(struct op_queue *opq, int param_t[3], orreg_t param[3], |
int delay_slot) |
{ |
gen_l_invalid(opq, param_t, param, delay_slot); |
} |
|
/or32.c
0,0 → 1,1310
/* Table of opcodes for the OpenRISC 1000 ISA. |
Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc. |
Contributed by Damjan Lampret (lampret@opencores.org). |
|
This file is part of gen_or1k_isa, or1ksim, GDB and GAS. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
|
/* |
* $Log: not supported by cvs2svn $ |
* Revision 1.43 2005/03/31 16:01:59 nogj |
* Reclasify l.trap and l.sys to be an exception instruction |
* |
* Revision 1.42 2005/03/16 12:25:56 nogj |
* Fix the parameters to the l.ff1/l.maci instructions |
* |
* Revision 1.41 2005/02/09 17:41:03 nogj |
* Mark a simulated cpu address as such, by introducing the new oraddr_t type |
* |
* Revision 1.40 2005/01/27 14:14:13 nogj |
* Remove the global op structure |
* |
* Revision 1.39 2005/01/27 13:35:40 nogj |
* * Fix generate.c to produce a execgen.c with less warnings. |
* * Fix the --enable-simple configure option. |
* |
* Revision 1.38 2005/01/27 13:15:50 nogj |
* Mark wich operand is the destination operand in the architechture definition |
* |
* Revision 1.37 2005/01/11 15:41:58 andreje |
* l.ff1 instruction added |
* |
* Revision 1.36 2004/07/22 20:17:23 phoenix |
* removed includes |
* |
* Revision 1.35 2004/07/19 23:07:37 phoenix |
* Gyorgy Jeney: extensive cleanup |
* |
* Revision 1.34 2004/06/27 22:56:48 lampret |
* Updated instruction set descriptions. Changed FP instructions encoding. |
* |
* Revision 1.33 2004/05/09 19:52:31 lampret |
* Changed desciption of the l.cust5 insns |
* |
* Revision 1.31 2003/07/01 19:34:49 csanchez |
* Added support for l.addc instruction. |
* |
* Revision 1.30 2003/01/28 03:49:24 lampret |
* Added cvs log keywords |
* |
*/ |
|
#include <string.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <ctype.h> |
|
|
#ifdef HAVE_CONFIG_H |
# include "config.h" |
#endif |
#ifdef HAS_EXECUTION |
# ifdef HAVE_INTTYPES_H |
# include <inttypes.h> /* ...but to get arch.h we need uint{8,16,32}_t... */ |
# endif |
# include "port.h" |
# include "arch.h" /* ...but to get abstract.h, we need oraddr_t... */ |
# include "abstract.h" /* To get struct iqueue_entry... */ |
#endif |
#include "opcode/or32.h" |
|
/* **INDENT-OFF** */ |
|
/* We treat all letters the same in encode/decode routines so |
we need to assign some characteristics to them like signess etc.*/ |
CONST struct or32_letter or32_letters[] = |
{ |
{ 'A', NUM_UNSIGNED }, |
{ 'B', NUM_UNSIGNED }, |
{ 'D', NUM_UNSIGNED }, |
{ 'I', NUM_SIGNED }, |
{ 'K', NUM_UNSIGNED }, |
{ 'L', NUM_UNSIGNED }, |
{ 'N', NUM_SIGNED }, |
{ '0', NUM_UNSIGNED }, |
{ '\0', 0 } /* dummy entry */ |
}; |
|
/* Opcode encoding: |
machine[31:30]: first two bits of opcode |
00 - neither of source operands is GPR |
01 - second source operand is GPR (rB) |
10 - first source operand is GPR (rA) |
11 - both source operands are GPRs (rA and rB) |
machine[29:26]: next four bits of opcode |
machine[25:00]: instruction operands (specific to individual instruction) |
|
Recommendation: irrelevant instruction bits should be set with a value of |
bits in same positions of instruction preceding current instruction in the |
code (when assembling). |
*/ |
|
#ifdef HAS_EXECUTION |
# if SIMPLE_EXECUTION |
# define EFN &l_none |
# define EF(func) &(func) |
# define EFI &l_invalid |
# elif COMPLEX_EXECUTION |
# define EFN "l_none" |
# define EFI "l_invalid" |
# ifdef __GNUC__ |
# define EF(func) #func |
# else |
# define EF(func) "func" |
# endif |
# else /* DYNAMIC_EXECUTION */ |
# define EFN &l_none |
# define EF(func) &(gen_ ##func) |
# define EFI &gen_l_invalid |
# endif |
#else /* HAS_EXECUTION */ |
# define EFN &l_none |
# define EF(func) EFN |
# define EFI EFN |
#endif /* HAS_EXECUTION */ |
|
CONST struct or32_opcode or32_opcodes[] = |
{ |
|
{ "l.j", "N", "00 0x0 NNNNN NNNNN NNNN NNNN NNNN NNNN", |
EF(l_j), OR32_IF_DELAY, it_jump }, |
{ "l.jal", "N", "00 0x1 NNNNN NNNNN NNNN NNNN NNNN NNNN", |
EF(l_jal), OR32_IF_DELAY, it_jump }, |
{ "l.bnf", "N", "00 0x3 NNNNN NNNNN NNNN NNNN NNNN NNNN", |
EF(l_bnf), OR32_IF_DELAY | OR32_R_FLAG, it_branch }, |
{ "l.bf", "N", "00 0x4 NNNNN NNNNN NNNN NNNN NNNN NNNN", |
EF(l_bf), OR32_IF_DELAY | OR32_R_FLAG, it_branch }, |
{ "l.nop", "K", "00 0x5 01--- ----- KKKK KKKK KKKK KKKK", |
EF(l_nop), 0, it_nop }, |
{ "l.movhi", "rD,K", "00 0x6 DDDDD ----0 KKKK KKKK KKKK KKKK", |
EF(l_movhi), 0, it_movimm }, |
{ "l.macrc", "rD", "00 0x6 DDDDD ----1 0000 0000 0000 0000", |
EF(l_macrc), 0, it_mac }, |
{ "l.sys", "K", "00 0x8 00000 00000 KKKK KKKK KKKK KKKK", |
EF(l_sys), 0, it_exception }, |
{ "l.trap", "K", "00 0x8 01000 00000 KKKK KKKK KKKK KKKK", |
EF(l_trap), 0, it_exception }, |
{ "l.msync", "", "00 0x8 10000 00000 0000 0000 0000 0000", EFN, |
0, it_unknown }, |
{ "l.psync", "", "00 0x8 10100 00000 0000 0000 0000 0000", EFN, |
0, it_unknown }, |
{ "l.csync", "", "00 0x8 11000 00000 0000 0000 0000 0000", EFN, |
0, it_unknown }, |
{ "l.rfe", "", "00 0x9 ----- ----- ---- ---- ---- ----", |
EF(l_rfe), OR32_IF_DELAY, it_exception }, |
{ "lv.all_eq.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x0", EFI, 0, |
it_unknown }, |
{ "lv.all_eq.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x1", EFI, 0, |
it_unknown }, |
{ "lv.all_ge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x2", EFI, 0, |
it_unknown }, |
{ "lv.all_ge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x3", EFI, 0, |
it_unknown }, |
{ "lv.all_gt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x4", EFI, 0, |
it_unknown }, |
{ "lv.all_gt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x5", EFI, 0, |
it_unknown }, |
{ "lv.all_le.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x6", EFI, 0, |
it_unknown }, |
{ "lv.all_le.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x7", EFI, 0, |
it_unknown }, |
{ "lv.all_lt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x8", EFI, 0, |
it_unknown }, |
{ "lv.all_lt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0x9", EFI, 0, |
it_unknown }, |
{ "lv.all_ne.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0xA", EFI, 0, |
it_unknown }, |
{ "lv.all_ne.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x1 0xB", EFI, 0, |
it_unknown }, |
{ "lv.any_eq.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x0", EFI, 0, |
it_unknown }, |
{ "lv.any_eq.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x1", EFI, 0, |
it_unknown }, |
{ "lv.any_ge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x2", EFI, 0, |
it_unknown }, |
{ "lv.any_ge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x3", EFI, 0, |
it_unknown }, |
{ "lv.any_gt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x4", EFI, 0, |
it_unknown }, |
{ "lv.any_gt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x5", EFI, 0, |
it_unknown }, |
{ "lv.any_le.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x6", EFI, 0, |
it_unknown }, |
{ "lv.any_le.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x7", EFI, 0, |
it_unknown }, |
{ "lv.any_lt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x8", EFI, 0, |
it_unknown }, |
{ "lv.any_lt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0x9", EFI, 0, |
it_unknown }, |
{ "lv.any_ne.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0xA", EFI, 0, |
it_unknown }, |
{ "lv.any_ne.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x2 0xB", EFI, 0, |
it_unknown }, |
{ "lv.add.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x0", EFI, 0, |
it_unknown }, |
{ "lv.add.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x1", EFI, 0, |
it_unknown }, |
{ "lv.adds.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x2", EFI, 0, |
it_unknown }, |
{ "lv.adds.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x3", EFI, 0, |
it_unknown }, |
{ "lv.addu.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x4", EFI, 0, |
it_unknown }, |
{ "lv.addu.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x5", EFI, 0, |
it_unknown }, |
{ "lv.addus.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x6", EFI, 0, |
it_unknown }, |
{ "lv.addus.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x7", EFI, 0, |
it_unknown }, |
{ "lv.and", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x8", EFI, 0, |
it_unknown }, |
{ "lv.avg.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0x9", EFI, 0, |
it_unknown }, |
{ "lv.avg.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x3 0xA", EFI, 0, |
it_unknown }, |
{ "lv.cmp_eq.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x0", EFI, 0, |
it_unknown }, |
{ "lv.cmp_eq.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x1", EFI, 0, |
it_unknown }, |
{ "lv.cmp_ge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x2", EFI, 0, |
it_unknown }, |
{ "lv.cmp_ge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x3", EFI, 0, |
it_unknown }, |
{ "lv.cmp_gt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x4", EFI, 0, |
it_unknown }, |
{ "lv.cmp_gt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x5", EFI, 0, |
it_unknown }, |
{ "lv.cmp_le.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x6", EFI, 0, |
it_unknown }, |
{ "lv.cmp_le.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x7", EFI, 0, |
it_unknown }, |
{ "lv.cmp_lt.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x8", EFI, 0, |
it_unknown }, |
{ "lv.cmp_lt.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0x9", EFI, 0, |
it_unknown }, |
{ "lv.cmp_ne.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0xA", EFI, 0, |
it_unknown }, |
{ "lv.cmp_ne.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x4 0xB", EFI, 0, |
it_unknown }, |
{ "lv.madds.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x4", EFI, 0, |
it_unknown }, |
{ "lv.max.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x5", EFI, 0, |
it_unknown }, |
{ "lv.max.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x6", EFI, 0, |
it_unknown }, |
{ "lv.merge.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x7", EFI, 0, |
it_unknown }, |
{ "lv.merge.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x8", EFI, 0, |
it_unknown }, |
{ "lv.min.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0x9", EFI, 0, |
it_unknown }, |
{ "lv.min.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xA", EFI, 0, |
it_unknown }, |
{ "lv.msubs.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xB", EFI, 0, |
it_unknown }, |
{ "lv.muls.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xC", EFI, 0, |
it_unknown }, |
{ "lv.nand", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xD", EFI, 0, |
it_unknown }, |
{ "lv.nor", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xE", EFI, 0, |
it_unknown }, |
{ "lv.or", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x5 0xF", EFI, 0, |
it_unknown }, |
{ "lv.pack.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x0", EFI, 0, |
it_unknown }, |
{ "lv.pack.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x1", EFI, 0, |
it_unknown }, |
{ "lv.packs.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x2", EFI, 0, |
it_unknown }, |
{ "lv.packs.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x3", EFI, 0, |
it_unknown }, |
{ "lv.packus.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x4", EFI, 0, |
it_unknown }, |
{ "lv.packus.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x5", EFI, 0, |
it_unknown }, |
{ "lv.perm.n", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x6", EFI, 0, |
it_unknown }, |
{ "lv.rl.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x7", EFI, 0, |
it_unknown }, |
{ "lv.rl.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x8", EFI, 0, |
it_unknown }, |
{ "lv.sll.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0x9", EFI, 0, |
it_unknown }, |
{ "lv.sll.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xA", EFI, 0, |
it_unknown }, |
{ "lv.sll", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xB", EFI, 0, |
it_unknown }, |
{ "lv.srl.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xC", EFI, 0, |
it_unknown }, |
{ "lv.srl.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xD", EFI, 0, |
it_unknown }, |
{ "lv.sra.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xE", EFI, 0, |
it_unknown }, |
{ "lv.sra.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x6 0xF", EFI, 0, |
it_unknown }, |
{ "lv.srl", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x0", EFI, 0, |
it_unknown }, |
{ "lv.sub.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x1", EFI, 0, |
it_unknown }, |
{ "lv.sub.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x2", EFI, 0, |
it_unknown }, |
{ "lv.subs.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x3", EFI, 0, |
it_unknown }, |
{ "lv.subs.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x4", EFI, 0, |
it_unknown }, |
{ "lv.subu.b", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x5", EFI, 0, |
it_unknown }, |
{ "lv.subu.h", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x6", EFI, 0, |
it_unknown }, |
{ "lv.subus.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x7", EFI, 0, |
it_unknown }, |
{ "lv.subus.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x8", EFI, 0, |
it_unknown }, |
{ "lv.unpack.b","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0x9", EFI, 0, |
it_unknown }, |
{ "lv.unpack.h","rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0xA", EFI, 0, |
it_unknown }, |
{ "lv.xor", "rD,rA,rB", "00 0xA DDDDD AAAAA BBBB B--- 0x7 0xB", EFI, 0, |
it_unknown }, |
{ "lv.cust1", "", "00 0xA ----- ----- ---- ---- 0xC ----", EFI, 0, |
it_unknown }, |
{ "lv.cust2", "", "00 0xA ----- ----- ---- ---- 0xD ----", EFI, 0, |
it_unknown }, |
{ "lv.cust3", "", "00 0xA ----- ----- ---- ---- 0xE ----", EFI, 0, |
it_unknown }, |
{ "lv.cust4", "", "00 0xA ----- ----- ---- ---- 0xF ----", EFI, 0, |
it_unknown }, |
|
{ "l.jr", "rB", "01 0x1 ----- ----- BBBB B--- ---- ----", |
EF(l_jr), OR32_IF_DELAY, it_jump }, |
{ "l.jalr", "rB", "01 0x2 ----- ----- BBBB B--- ---- ----", |
EF(l_jalr), OR32_IF_DELAY, it_jump }, |
{ "l.maci", "rA,I", "01 0x3 IIIII ----- AAAA AIII IIII IIII", |
EF(l_mac), 0, it_mac }, |
{ "l.cust1", "", "01 0xC ----- ----- ---- ---- ---- ----", |
EF(l_cust1), 0, it_unknown }, |
{ "l.cust2", "", "01 0xD ----- ----- ---- ---- ---- ----", |
EF(l_cust2), 0, it_unknown }, |
{ "l.cust3", "", "01 0xE ----- ----- ---- ---- ---- ----", |
EF(l_cust3), 0, it_unknown }, |
{ "l.cust4", "", "01 0xF ----- ----- ---- ---- ---- ----", |
EF(l_cust4), 0, it_unknown }, |
|
{ "l.ld", "rD,I(rA)", "10 0x0 DDDDD AAAAA IIII IIII IIII IIII", EFI, |
0, it_load }, |
{ "l.lwz", "rD,I(rA)", "10 0x1 DDDDD AAAAA IIII IIII IIII IIII", |
EF(l_lwz), 0, it_load }, |
{ "l.lws", "rD,I(rA)", "10 0x2 DDDDD AAAAA IIII IIII IIII IIII", EFI, |
0, it_load }, |
{ "l.lbz", "rD,I(rA)", "10 0x3 DDDDD AAAAA IIII IIII IIII IIII", |
EF(l_lbz), 0, it_load }, |
{ "l.lbs", "rD,I(rA)", "10 0x4 DDDDD AAAAA IIII IIII IIII IIII", |
EF(l_lbs), 0, it_load }, |
{ "l.lhz", "rD,I(rA)", "10 0x5 DDDDD AAAAA IIII IIII IIII IIII", |
EF(l_lhz), 0, it_load }, |
{ "l.lhs", "rD,I(rA)", "10 0x6 DDDDD AAAAA IIII IIII IIII IIII", |
EF(l_lhs), 0, it_load }, |
|
{ "l.addi", "rD,rA,I", "10 0x7 DDDDD AAAAA IIII IIII IIII IIII", |
EF(l_add), OR32_W_FLAG, it_arith }, |
{ "l.addic", "rD,rA,I", "10 0x8 DDDDD AAAAA IIII IIII IIII IIII", EFI, |
0, it_arith }, |
{ "l.andi", "rD,rA,K", "10 0x9 DDDDD AAAAA KKKK KKKK KKKK KKKK", |
EF(l_and), OR32_W_FLAG, it_arith }, |
{ "l.ori", "rD,rA,K", "10 0xA DDDDD AAAAA KKKK KKKK KKKK KKKK", |
EF(l_or), 0, it_arith }, |
{ "l.xori", "rD,rA,I", "10 0xB DDDDD AAAAA IIII IIII IIII IIII", |
EF(l_xor), 0, it_arith }, |
{ "l.muli", "rD,rA,I", "10 0xC DDDDD AAAAA IIII IIII IIII IIII", |
EF(l_mul), 0, it_arith }, |
{ "l.mfspr", "rD,rA,K", "10 0xD DDDDD AAAAA KKKK KKKK KKKK KKKK", |
EF(l_mfspr), 0, it_move }, |
{ "l.slli", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 00LL LLLL", |
EF(l_sll), 0, it_shift }, |
{ "l.srli", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 01LL LLLL", |
EF(l_srl), 0, it_shift }, |
{ "l.srai", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 10LL LLLL", |
EF(l_sra), 0, it_shift }, |
{ "l.rori", "rD,rA,L", "10 0xE DDDDD AAAAA ---- ---- 11LL LLLL", EFI, |
0, it_shift }, |
|
{ "l.sfeqi", "rA,I", "10 0xF 00000 AAAAA IIII IIII IIII IIII", |
EF(l_sfeq), OR32_W_FLAG, it_compare }, |
{ "l.sfnei", "rA,I", "10 0xF 00001 AAAAA IIII IIII IIII IIII", |
EF(l_sfne), OR32_W_FLAG, it_compare }, |
{ "l.sfgtui", "rA,I", "10 0xF 00010 AAAAA IIII IIII IIII IIII", |
EF(l_sfgtu), OR32_W_FLAG, it_compare }, |
{ "l.sfgeui", "rA,I", "10 0xF 00011 AAAAA IIII IIII IIII IIII", |
EF(l_sfgeu), OR32_W_FLAG, it_compare }, |
{ "l.sfltui", "rA,I", "10 0xF 00100 AAAAA IIII IIII IIII IIII", |
EF(l_sfltu), OR32_W_FLAG, it_compare }, |
{ "l.sfleui", "rA,I", "10 0xF 00101 AAAAA IIII IIII IIII IIII", |
EF(l_sfleu), OR32_W_FLAG, it_compare }, |
{ "l.sfgtsi", "rA,I", "10 0xF 01010 AAAAA IIII IIII IIII IIII", |
EF(l_sfgts), OR32_W_FLAG, it_compare }, |
{ "l.sfgesi", "rA,I", "10 0xF 01011 AAAAA IIII IIII IIII IIII", |
EF(l_sfges), OR32_W_FLAG, it_compare }, |
{ "l.sfltsi", "rA,I", "10 0xF 01100 AAAAA IIII IIII IIII IIII", |
EF(l_sflts), OR32_W_FLAG, it_compare }, |
{ "l.sflesi", "rA,I", "10 0xF 01101 AAAAA IIII IIII IIII IIII", |
EF(l_sfles), OR32_W_FLAG, it_compare }, |
|
{ "l.mtspr", "rA,rB,K", "11 0x0 KKKKK AAAAA BBBB BKKK KKKK KKKK", |
EF(l_mtspr), 0, it_move }, |
{ "l.mac", "rA,rB", "11 0x1 ----- AAAAA BBBB B--- ---- 0x1", |
EF(l_mac), 0, it_mac }, |
{ "l.msb", "rA,rB", "11 0x1 ----- AAAAA BBBB B--- ---- 0x2", |
EF(l_msb), 0, it_mac }, |
|
{ "lf.add.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x0", |
EF(lf_add_s), 0, it_float }, |
{ "lf.sub.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x1", |
EF(lf_sub_s), 0, it_float }, |
{ "lf.mul.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x2", |
EF(lf_mul_s), 0, it_float }, |
{ "lf.div.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x3", |
EF(lf_div_s), 0, it_float }, |
{ "lf.itof.s", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x0 0x4", |
EF(lf_itof_s), 0, it_float }, |
{ "lf.ftoi.s", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x0 0x5", |
EF(lf_ftoi_s), 0, it_float }, |
{ "lf.rem.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x6", |
EF(lf_rem_s), 0, it_float }, |
{ "lf.madd.s", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x0 0x7", |
EF(lf_madd_s), 0, it_float }, |
{ "lf.sfeq.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0x8", |
EF(lf_sfeq_s), 0, it_float }, |
{ "lf.sfne.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0x9", |
EF(lf_sfne_s), 0, it_float }, |
{ "lf.sfgt.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xA", |
EF(lf_sfgt_s), 0, it_float }, |
{ "lf.sfge.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xB", |
EF(lf_sfge_s), 0, it_float }, |
{ "lf.sflt.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xC", |
EF(lf_sflt_s), 0, it_float }, |
{ "lf.sfle.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x0 0xD", |
EF(lf_sfle_s), 0, it_float }, |
{ "lf.cust1.s", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0xD ----", EFI, |
0, it_float }, |
|
{ "lf.add.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x0", EFI, 0, |
it_float }, |
{ "lf.sub.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x1", EFI, 0, |
it_float }, |
{ "lf.mul.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x2", EFI, 0, |
it_float }, |
{ "lf.div.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x3", EFI, 0, |
it_float }, |
{ "lf.itof.d", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x1 0x4", EFI, 0, |
it_float }, |
{ "lf.ftoi.d", "rD,rA", "11 0x2 DDDDD AAAAA 0000 0--- 0x1 0x5", EFI, 0, |
it_float }, |
{ "lf.rem.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x6", EFI, 0, |
it_float }, |
{ "lf.madd.d", "rD,rA,rB", "11 0x2 DDDDD AAAAA BBBB B--- 0x1 0x7", EFI, 0, |
it_float }, |
{ "lf.sfeq.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0x8", EFI, 0, |
it_float }, |
{ "lf.sfne.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0x9", EFI, 0, |
it_float }, |
{ "lf.sfgt.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xA", EFI, 0, |
it_float }, |
{ "lf.sfge.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xB", EFI, 0, |
it_float }, |
{ "lf.sflt.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xC", EFI, 0, |
it_float }, |
{ "lf.sfle.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0x1 0xD", EFI, 0, |
it_float }, |
{ "lf.cust1.d", "rA,rB", "11 0x2 ----- AAAAA BBBB B--- 0xE ----", EFI, 0, |
it_float }, |
|
{ "l.sd", "I(rD),rB", "11 0x4 IIIII DDDDD BBBB BIII IIII IIII", EFI, |
0, it_store }, |
{ "l.sw", "I(rD),rB", "11 0x5 IIIII DDDDD BBBB BIII IIII IIII", |
EF(l_sw), 0, it_store }, |
{ "l.sb", "I(rD),rB", "11 0x6 IIIII DDDDD BBBB BIII IIII IIII", |
EF(l_sb), 0, it_store }, |
{ "l.sh", "I(rD),rB", "11 0x7 IIIII DDDDD BBBB BIII IIII IIII", |
EF(l_sh), 0, it_store }, |
|
{ "l.add", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x0", |
EF(l_add), OR32_W_FLAG, it_arith }, |
{ "l.addc", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x1", |
EF(l_addc), OR32_W_FLAG, it_arith }, |
{ "l.sub", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x2", |
EF(l_sub), 0, it_arith }, |
{ "l.and", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x3", |
EF(l_and), OR32_W_FLAG, it_arith }, |
{ "l.or", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x4", |
EF(l_or), 0, it_arith }, |
{ "l.xor", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0x5", |
EF(l_xor), 0, it_arith }, |
{ "l.mul", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0x6", |
EF(l_mul), 0, it_arith }, |
|
{ "l.sll", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 00-- 0x8", |
EF(l_sll), 0, it_shift }, |
{ "l.srl", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 01-- 0x8", |
EF(l_srl), 0, it_shift }, |
{ "l.sra", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 10-- 0x8", |
EF(l_sra), 0, it_shift }, |
{ "l.ror", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 11-- 0x8", EFI, |
0, it_shift }, |
{ "l.div", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0x9", |
EF(l_div), 0, it_arith }, |
{ "l.divu", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0xA", |
EF(l_divu), 0, it_arith }, |
{ "l.mulu", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-11 ---- 0xB", EFI, |
0, it_arith }, |
{ "l.extbs", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 01-- 0xC", |
EF(l_extbs), 0, it_move }, |
{ "l.exths", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 00-- 0xC", |
EF(l_exths), 0, it_move }, |
{ "l.extws", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 00-- 0xD", |
EF(l_extws), 0, it_move }, |
{ "l.extbz", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 11-- 0xC", |
EF(l_extbz), 0, it_move }, |
{ "l.exthz", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 10-- 0xC", |
EF(l_exthz), 0, it_move }, |
{ "l.extwz", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 01-- 0xD", |
EF(l_extwz), 0, it_move }, |
{ "l.cmov", "rD,rA,rB", "11 0x8 DDDDD AAAAA BBBB B-00 ---- 0xE", |
EF(l_cmov), OR32_R_FLAG, it_move }, |
{ "l.ff1", "rD,rA", "11 0x8 DDDDD AAAAA ---- --00 ---- 0xF", EFI, 0, |
it_arith }, |
|
{ "l.sfeq", "rA,rB", "11 0x9 00000 AAAAA BBBB B--- ---- ----", |
EF(l_sfeq), OR32_W_FLAG, it_compare }, |
{ "l.sfne", "rA,rB", "11 0x9 00001 AAAAA BBBB B--- ---- ----", |
EF(l_sfne), OR32_W_FLAG, it_compare }, |
{ "l.sfgtu", "rA,rB", "11 0x9 00010 AAAAA BBBB B--- ---- ----", |
EF(l_sfgtu), OR32_W_FLAG, it_compare }, |
{ "l.sfgeu", "rA,rB", "11 0x9 00011 AAAAA BBBB B--- ---- ----", |
EF(l_sfgeu), OR32_W_FLAG, it_compare }, |
{ "l.sfltu", "rA,rB", "11 0x9 00100 AAAAA BBBB B--- ---- ----", |
EF(l_sfltu), OR32_W_FLAG, it_compare }, |
{ "l.sfleu", "rA,rB", "11 0x9 00101 AAAAA BBBB B--- ---- ----", |
EF(l_sfleu), OR32_W_FLAG, it_compare }, |
{ "l.sfgts", "rA,rB", "11 0x9 01010 AAAAA BBBB B--- ---- ----", |
EF(l_sfgts), OR32_W_FLAG, it_compare }, |
{ "l.sfges", "rA,rB", "11 0x9 01011 AAAAA BBBB B--- ---- ----", |
EF(l_sfges), OR32_W_FLAG, it_compare }, |
{ "l.sflts", "rA,rB", "11 0x9 01100 AAAAA BBBB B--- ---- ----", |
EF(l_sflts), OR32_W_FLAG, it_compare }, |
{ "l.sfles", "rA,rB", "11 0x9 01101 AAAAA BBBB B--- ---- ----", |
EF(l_sfles), OR32_W_FLAG, it_compare }, |
|
{ "l.cust5", "rD,rA,rB,L,K", "11 0xC DDDDD AAAAA BBBB BLLL LLLK KKKK", EFI, |
0, it_unknown }, |
{ "l.cust6", "", "11 0xD ----- ----- ---- ---- ---- ----", EFI, |
0, it_unknown }, |
{ "l.cust7", "", "11 0xE ----- ----- ---- ---- ---- ----", EFI, |
0, it_unknown }, |
{ "l.cust8", "", "11 0xF ----- ----- ---- ---- ---- ----", EFI, |
0, it_unknown }, |
|
/* This section should not be defined in or1ksim, since it contains duplicates, |
which would cause machine builder to complain. */ |
#ifdef HAS_CUST |
{ "l.cust5_1", "rD", "11 0xC DDDDD ----- ---- ---- ---- ----", EFI, |
0, it_unknown }, |
{ "l.cust5_2", "rD,rA" , "11 0xC DDDDD AAAAA ---- ---- ---- ----", EFI, |
0, it_unknown }, |
{ "l.cust5_3", "rD,rA,rB", "11 0xC DDDDD AAAAA BBBB B--- ---- ----", EFI, |
0, it_unknown }, |
|
{ "l.cust6_1", "rD", "11 0xD DDDDD ----- ---- ---- ---- ----", EFI, |
0, it_unknown }, |
{ "l.cust6_2", "rD,rA" , "11 0xD DDDDD AAAAA ---- ---- ---- ----", EFI, |
0, it_unknown }, |
{ "l.cust6_3", "rD,rA,rB", "11 0xD DDDDD AAAAA BBBB B--- ---- ----", EFI, |
0, it_unknown }, |
|
{ "l.cust7_1", "rD", "11 0xE DDDDD ----- ---- ---- ---- ----", EFI, |
0, it_unknown }, |
{ "l.cust7_2", "rD,rA" , "11 0xE DDDDD AAAAA ---- ---- ---- ----", EFI, |
0, it_unknown }, |
{ "l.cust7_3", "rD,rA,rB", "11 0xE DDDDD AAAAA BBBB B--- ---- ----", EFI, |
0, it_unknown }, |
|
{ "l.cust8_1", "rD", "11 0xF DDDDD ----- ---- ---- ---- ----", EFI, |
0, it_unknown }, |
{ "l.cust8_2", "rD,rA" , "11 0xF DDDDD AAAAA ---- ---- ---- ----", EFI, |
0, it_unknown }, |
{ "l.cust8_3", "rD,rA,rB", "11 0xF DDDDD AAAAA BBBB B--- ---- ----", EFI, |
0, it_unknown }, |
#endif |
|
{ "", "", "", EFI, 0, 0 } /* Dummy entry, not included in num_opcodes. This |
* lets code examine entry i+1 without checking |
* if we've run off the end of the table. */ |
}; |
|
#undef EFI |
#undef EFN |
#undef EF |
|
/* **INDENT-ON** */ |
|
/* Define dummy, if debug is not defined. */ |
#ifndef HAS_DEBUG |
#define debug(l, fmt...) ; |
#endif |
|
CONST int num_opcodes = ((sizeof(or32_opcodes)) / (sizeof(struct or32_opcode))) - 1; |
|
/* Calculates instruction length in bytes. Always 4 for OR32. */ |
int |
insn_len(int insn_index) |
{ |
insn_index = 0; /* Just to get rid that warning. */ |
return 4; |
} |
|
/* Is individual insn's operand signed or unsigned? */ |
int |
letter_signed(char l) |
{ |
CONST struct or32_letter *pletter; |
|
for(pletter = or32_letters; pletter->letter != '\0'; pletter++) |
if (pletter->letter == l) |
return pletter->sign; |
|
printf("letter_signed(%c): Unknown letter.\n", l); |
return 0; |
} |
|
/* Simple cache for letter ranges */ |
static int range_cache[256] = {0}; |
|
/* Number of letters in the individual lettered operand. */ |
int |
letter_range(char l) |
{ |
CONST struct or32_opcode *pinsn; |
char *enc; |
int range = 0; |
|
/* Is value cached? */ |
if ((range = range_cache[(unsigned char)l])) return range; |
|
for(pinsn = or32_opcodes; strlen(pinsn->name); pinsn++) |
{ |
if (strchr(pinsn->encoding,l)) |
{ |
for (enc = pinsn->encoding; *enc != '\0'; enc++) |
if ((*enc == '0') && (*(enc+1) == 'x')) |
enc += 2; |
else if (*enc == l) |
range++; |
return range_cache[(unsigned char)l] = range; |
} |
} |
|
printf("\nABORT: letter_range(%c): Never used letter.\n", l); |
exit(1); |
} |
|
/* MM: Returns index of given instruction name. */ |
int |
insn_index (char *insn) |
{ |
int i, found = -1; |
for (i = 0; i < num_opcodes; i++) |
if (!strcmp (or32_opcodes[i].name, insn)) |
{ |
found = i; |
break; |
} |
return found; |
} |
|
/* Returns name of the specified instruction index */ |
CONST char * |
insn_name(int index) |
{ |
if (index >= 0 && index < num_opcodes) |
return or32_opcodes[index].name; |
else |
return "???"; |
} |
|
#if defined(HAS_EXECUTION) && SIMPLE_EXECUTION |
void |
l_none(struct iqueue_entry *current) |
{ |
} |
#elif defined(HAS_EXECUTION) && DYNAMIC_EXECUTION |
void |
l_none(struct op_queue *opq, int *param_t, orreg_t *param, int delay_slot) |
{ |
} |
#else |
void |
l_none() |
{ |
} |
#endif |
|
/*** Finite automata for instruction decoding building code ***/ |
|
/* Find symbols in encoding. */ |
unsigned long |
insn_extract(param_ch, enc_initial) |
char param_ch; |
char *enc_initial; |
{ |
char *enc; |
unsigned long ret = 0; |
unsigned opc_pos = 32; |
for (enc = enc_initial; *enc != '\0'; ) |
if ((*enc == '0') && (*(enc+1) == 'x')) |
{ |
unsigned long tmp = strtol(enc+2, NULL, 16); |
opc_pos -= 4; |
if (param_ch == '0' || param_ch == '1') |
{ |
if (param_ch == '0') |
tmp = 15 - tmp; |
ret |= tmp << opc_pos; |
} |
enc += 3; |
} |
else |
{ |
if (*enc == '0' || *enc == '1' || *enc == '-' || isalpha(*enc) ) |
{ |
opc_pos--; |
if (param_ch == *enc) |
ret |= 1 << opc_pos; |
} |
enc++; |
} |
return ret; |
} |
|
#define MAX_AUTOMATA_SIZE (1200) |
#define MAX_OP_TABLE_SIZE (1200) |
#define MAX_LEN (8) |
|
#ifndef MIN |
# define MIN(x,y) ((x) < (y) ? (x) : (y)) |
#endif |
|
unsigned long *automata; |
int nuncovered; |
int curpass = 0; |
|
/* MM: Struct that holds runtime build information about instructions. */ |
struct temp_insn_struct *ti; |
|
struct insn_op_struct *op_data, **op_start; |
|
/* Recursive utility function used to find best match and to build automata. */ |
|
static unsigned long * |
cover_insn (unsigned long *cur, int pass, unsigned int mask) |
{ |
int best_first = 0, best_len = 0, i, last_match = -1, ninstr = 0; |
unsigned long cur_mask = mask; |
unsigned long *next; |
|
for (i = 0; i < num_opcodes; i++) |
if (ti[i].in_pass == pass) |
{ |
cur_mask &= ti[i].insn_mask; |
ninstr++; |
last_match = i; |
} |
|
debug(8, "%08X %08X\n", mask, cur_mask); |
if (ninstr == 0) |
return 0; |
if (ninstr == 1) |
{ |
/* Leaf holds instruction index. */ |
debug(8, "%i>I%i %s\n", cur - automata, last_match, or32_opcodes[last_match].name); |
*cur = LEAF_FLAG | last_match; |
cur++; |
nuncovered--; |
} else { |
/* Find longest match. */ |
for (i = 0; i < 32; i++) |
{ |
int len; |
for (len = best_len + 1; len < MIN(MAX_LEN, 33 - i); len++) |
{ |
unsigned long m = (1UL << ((unsigned long)len)) - 1; |
debug(9, " (%i(%08X & %08X>>%i = %08X, %08X)",len,m, cur_mask, i, (cur_mask >> (unsigned)i), (cur_mask >> (unsigned)i) & m); |
if ((m & (cur_mask >> (unsigned)i)) == m) |
{ |
best_len = len; |
best_first = i; |
debug(9, "!"); |
} |
else |
break; |
} |
} |
debug(9, "\n"); |
if (!best_len) |
{ |
fprintf (stderr, "%i instructions match mask 0x%08X:\n", ninstr, mask); |
for (i = 0; i < num_opcodes; i++) |
if (ti[i].in_pass == pass) |
fprintf (stderr, "%s ", or32_opcodes[i].name); |
|
fprintf (stderr, "\n"); |
exit (1); |
} |
debug(8, "%i> #### %i << %i (%i) ####\n", cur - automata, best_len, best_first, ninstr); |
*cur = best_first; |
cur++; |
*cur = (1 << best_len) - 1; |
cur++; |
next = cur; |
/* Allocate space for pointers. */ |
cur += 1 << best_len; |
cur_mask = (1 << (unsigned long)best_len) - 1; |
|
for (i = 0; i < (1 << (unsigned long)best_len); i++) |
{ |
int j; |
unsigned long *c; |
curpass++; |
for (j = 0; j < num_opcodes; j++) |
if (ti[j].in_pass == pass |
&& ((ti[j].insn >> best_first) & cur_mask) == (unsigned long) i |
&& ((ti[j].insn_mask >> best_first) & cur_mask) == cur_mask) |
ti[j].in_pass = curpass; |
|
debug(9, "%08X %08X %i\n", mask, cur_mask, best_first); |
c = cover_insn (cur, curpass, mask & (~(cur_mask << best_first))); |
if (c) |
{ |
debug(8, "%i> #%X -> %u\n", next - automata, i, cur - automata); |
*next = cur - automata; |
cur = c; |
} |
else |
{ |
debug(8, "%i> N/A\n", next - automata); |
*next = 0; |
} |
next++; |
} |
} |
return cur; |
} |
|
/* Returns number of nonzero bits. */ |
static int |
num_ones (unsigned long value) |
{ |
int c = 0; |
while (value) |
{ |
if (value & 1) |
c++; |
value >>= 1; |
} |
return c; |
} |
|
/* Utility function, which converts parameters from or32_opcode format to more binary form. |
Parameters are stored in ti struct. */ |
|
static struct insn_op_struct * |
parse_params (CONST struct or32_opcode *opcode, struct insn_op_struct *cur) |
{ |
char *args = opcode->args; |
int i, type; |
int num_cur_op = 0;; |
|
i = 0; |
type = 0; |
/* In case we don't have any parameters, we add dummy read from r0. */ |
if (!(*args)) { |
cur->type = OPTYPE_REG | OPTYPE_OP | OPTYPE_LAST; |
cur->data = 0; |
debug(9, "#%08X %08X\n", cur->type, cur->data); |
cur++; |
return cur; |
} |
|
while (*args != '\0') |
{ |
if (*args == 'r') |
{ |
args++; |
type |= OPTYPE_REG; |
if(args[1] == 'D') |
type |= OPTYPE_DST; |
} |
else if (isalpha (*args)) |
{ |
unsigned long arg; |
arg = insn_extract(*args, opcode->encoding); |
debug(9, "%s : %08X ------\n", opcode->name, arg); |
if (letter_signed (*args)) |
{ |
type |= OPTYPE_SIG; |
type |= ((num_ones (arg) - 1) << OPTYPE_SBIT_SHR) & OPTYPE_SBIT; |
} |
|
num_cur_op = 0; |
/* Split argument to sequences of consecutive ones. */ |
while (arg) |
{ |
int shr = 0; |
unsigned long tmp = arg, mask = 0; |
while ((tmp & 1) == 0) |
{ |
shr++; |
tmp >>= 1; |
} |
while (tmp & 1) |
{ |
mask++; |
tmp >>= 1; |
} |
cur->type = type | shr; |
cur->data = mask; |
arg &= ~(((1 << mask) - 1) << shr); |
debug(6, "|%08X %08X\n", cur->type, cur->data); |
cur++; |
num_cur_op++; |
} |
args++; |
} |
else if (*args == '(') |
{ |
/* Next param is displacement. Later we will treat them as one operand. */ |
/* Set the OPTYPE_DIS flag on all insn_op_structs that belong to this |
* operand */ |
while(num_cur_op > 0) { |
cur[-num_cur_op].type |= type | OPTYPE_DIS; |
num_cur_op--; |
} |
cur[-1].type |= OPTYPE_OP; |
debug(9, ">%08X %08X\n", cur->type, cur->data); |
type = 0; |
i++; |
args++; |
} |
else if (*args == OPERAND_DELIM) |
{ |
cur--; |
cur->type = type | cur->type | OPTYPE_OP; |
debug(9, ">%08X %08X\n", cur->type, cur->data); |
cur++; |
type = 0; |
i++; |
args++; |
} |
else if (*args == '0') |
{ |
cur->type = type; |
cur->data = 0; |
debug(9, ">%08X %08X\n", cur->type, cur->data); |
cur++; |
type = 0; |
i++; |
args++; |
} |
else if (*args == ')') |
args++; |
else |
{ |
fprintf (stderr, "%s : parse error in args.\n", opcode->name); |
exit (1); |
} |
} |
cur--; |
cur->type = type | cur->type | OPTYPE_OP | OPTYPE_LAST; |
debug(9, "#%08X %08X\n", cur->type, cur->data); |
cur++; |
return cur; |
} |
|
/* Constructs new automata based on or32_opcodes array. */ |
|
void |
build_automata() |
{ |
int i; |
unsigned long *end; |
struct insn_op_struct *cur; |
|
automata = (unsigned long *) malloc (MAX_AUTOMATA_SIZE * sizeof (unsigned long)); |
ti = (struct temp_insn_struct *) malloc (sizeof (struct temp_insn_struct) * num_opcodes); |
|
nuncovered = num_opcodes; |
|
#ifdef HAS_EXECUTION |
printf("Building automata... "); |
#endif |
|
/* Build temporary information about instructions. */ |
for (i = 0; i < num_opcodes; i++) |
{ |
unsigned long ones, zeros; |
char *encoding = or32_opcodes[i].encoding; |
ones = insn_extract('1', encoding); |
zeros = insn_extract('0', encoding); |
ti[i].insn_mask = ones | zeros; |
ti[i].insn = ones; |
ti[i].in_pass = curpass = 0; |
/*debug(9, "%s: %s %08X %08X\n", or32_opcodes[i].name, |
or32_opcodes[i].encoding, ti[i].insn_mask, ti[i].insn);*/ |
} |
|
/* Until all are covered search for best criteria to separate them. */ |
end = cover_insn (automata, curpass, 0xFFFFFFFF); |
if (end - automata > MAX_AUTOMATA_SIZE) |
{ |
fprintf (stderr, "Automata too large. Increase MAX_AUTOMATA_SIZE."); |
exit (1); |
} |
#ifdef HAS_EXECUTION |
printf("done, num uncovered: %i/%i.\n", nuncovered, num_opcodes); |
#endif |
|
#ifdef HAS_EXECUTION |
printf("Parsing operands data... "); |
#endif |
op_data = (struct insn_op_struct *) malloc (MAX_OP_TABLE_SIZE * sizeof (struct insn_op_struct)); |
op_start = (struct insn_op_struct **) malloc (num_opcodes * sizeof (struct insn_op_struct *)); |
cur = op_data; |
for (i = 0; i < num_opcodes; i++) |
{ |
op_start[i] = cur; |
cur = parse_params (&or32_opcodes[i], cur); |
if (cur - op_data > MAX_OP_TABLE_SIZE) |
{ |
fprintf (stderr, "Operands table too small, increase MAX_OP_TABLE_SIZE.\n"); |
exit (1); |
} |
} |
#ifdef HAS_EXECUTION |
printf("done.\n"); |
#endif |
} |
|
void destruct_automata () |
{ |
free (ti); |
free (automata); |
free (op_data); |
free (op_start); |
} |
|
/* Decodes instruction and returns instruction index. */ |
int insn_decode (unsigned int insn) |
{ |
unsigned long *a = automata; |
int i; |
while (!(*a & LEAF_FLAG)) |
{ |
unsigned int first = *a; |
//debug(9, "%i ", a - automata); |
a++; |
i = (insn >> first) & *a; |
a++; |
if (!*(a + i)) |
{ /* Invalid instruction found? */ |
//debug(9, "XXX\n", i); |
return -1; |
} |
a = automata + *(a + i); |
} |
i = *a & ~LEAF_FLAG; |
//debug(9, "%i\n", i); |
/* Final check - do we have direct match? |
(based on or32_opcodes this should be the only possibility, |
but in case of invalid/missing instruction we must perform a check) */ |
if ((ti[i].insn_mask & insn) == ti[i].insn) |
return i; |
else |
return -1; |
} |
|
static char disassembled_str[50]; |
char *disassembled = &disassembled_str[0]; |
|
/* Automagically does zero- or sign- extension and also finds correct |
sign bit position if sign extension is correct extension. Which extension |
is proper is figured out from letter description. */ |
|
unsigned long |
extend_imm(unsigned long imm, char l) |
{ |
unsigned long mask; |
int letter_bits; |
|
/* First truncate all bits above valid range for this letter |
in case it is zero extend. */ |
letter_bits = letter_range(l); |
mask = (1 << letter_bits) - 1; |
imm &= mask; |
|
/* Do sign extend if this is the right one. */ |
if (letter_signed(l) && (imm >> (letter_bits - 1))) |
imm |= (~mask); |
|
return imm; |
} |
|
unsigned long |
or32_extract(param_ch, enc_initial, insn) |
char param_ch; |
char *enc_initial; |
unsigned long insn; |
{ |
char *enc; |
unsigned long ret = 0; |
int opc_pos = 0; |
int param_pos = 0; |
|
for (enc = enc_initial; *enc != '\0'; enc++) |
if (*enc == param_ch) |
{ |
if (enc - 2 >= enc_initial && (*(enc - 2) == '0') && (*(enc - 1) == 'x')) |
continue; |
else |
param_pos++; |
} |
|
#if DEBUG |
printf("or32_extract: %x ", param_pos); |
#endif |
opc_pos = 32; |
for (enc = enc_initial; *enc != '\0'; ) |
if ((*enc == '0') && (*(enc+1) == 'x')) |
{ |
opc_pos -= 4; |
if ((param_ch == '0') || (param_ch == '1')) |
{ |
unsigned long tmp = strtol(enc, NULL, 16); |
#if DEBUG |
printf(" enc=%s, tmp=%x ", enc, tmp); |
#endif |
if (param_ch == '0') |
tmp = 15 - tmp; |
ret |= tmp << opc_pos; |
} |
enc += 3; |
} |
else if ((*enc == '0') || (*enc == '1')) |
{ |
opc_pos--; |
if (param_ch == *enc) |
ret |= 1 << opc_pos; |
enc++; |
} |
else if (*enc == param_ch) |
{ |
opc_pos--; |
param_pos--; |
#if DEBUG |
printf("\n ret=%x opc_pos=%x, param_pos=%x\n", ret, opc_pos, param_pos); |
#endif |
if (islower(param_ch)) |
ret -= ((insn >> opc_pos) & 0x1) << param_pos; |
else |
ret += ((insn >> opc_pos) & 0x1) << param_pos; |
enc++; |
} |
else if (isalpha(*enc)) |
{ |
opc_pos--; |
enc++; |
} |
else if (*enc == '-') |
{ |
opc_pos--; |
enc++; |
} |
else |
enc++; |
|
#if DEBUG |
printf ("ret=%x\n", ret); |
#endif |
return ret; |
} |
|
/* Print register. Used only by print_insn. */ |
|
static char * |
or32_print_register (dest, param_ch, encoding, insn) |
char *dest; |
char param_ch; |
char *encoding; |
unsigned long insn; |
{ |
int regnum = or32_extract(param_ch, encoding, insn); |
|
sprintf (dest, "r%d", regnum); |
while (*dest) dest++; |
return dest; |
} |
|
/* Print immediate. Used only by print_insn. */ |
|
static char * |
or32_print_immediate (dest, param_ch, encoding, insn) |
char *dest; |
char param_ch; |
char *encoding; |
unsigned long insn; |
{ |
int imm = or32_extract (param_ch, encoding, insn); |
|
imm = extend_imm(imm, param_ch); |
|
if (letter_signed(param_ch)) |
{ |
if (imm < 0) |
sprintf (dest, "%d", imm); |
else |
sprintf (dest, "0x%x", imm); |
} |
else |
sprintf (dest, "%#x", imm); |
while (*dest) dest++; |
return dest; |
} |
|
/* Disassemble one instruction from insn to disassemble. |
Return the size of the instruction. */ |
|
int |
disassemble_insn (insn) |
unsigned long insn; |
{ |
return disassemble_index (insn, insn_decode (insn)); |
} |
|
/* Disassemble one instruction from insn index. |
Return the size of the instruction. */ |
|
int |
disassemble_index (insn, index) |
unsigned long insn; |
int index; |
{ |
char *dest = disassembled; |
if (index >= 0) |
{ |
struct or32_opcode const *opcode = &or32_opcodes[index]; |
char *s; |
|
strcpy (dest, opcode->name); |
while (*dest) dest++; |
*dest++ = ' '; |
*dest = 0; |
|
for (s = opcode->args; *s != '\0'; ++s) |
{ |
switch (*s) |
{ |
case '\0': |
return insn_len (insn); |
|
case 'r': |
dest = or32_print_register(dest, *++s, opcode->encoding, insn); |
break; |
|
default: |
if (strchr (opcode->encoding, *s)) |
dest = or32_print_immediate (dest, *s, opcode->encoding, insn); |
else { |
*dest++ = *s; |
*dest = 0; |
} |
} |
} |
} |
else |
{ |
/* This used to be %8x for binutils. */ |
sprintf(dest, ".word 0x%08lx", insn); |
while (*dest) dest++; |
} |
return insn_len (insn); |
} |
/dyn_rec.h
0,0 → 1,68
/* dyn_rec.h -- Recompiler specific definitions |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
#ifndef DYN_REC_H |
#define DYN_REC_H |
|
struct x_ref { |
void *dyn_addr; /* Recompiled address */ |
oraddr_t or_addr; /* The or address of the x-ref (physical) */ |
unsigned int ref; /* How many times the x-ref is referenced */ |
struct x_ref *next; |
}; |
|
/* Each dynamically recompiled page has one of these */ |
struct dyn_page { |
oraddr_t or_page; |
void *host_page; |
unsigned int host_len; |
int carrys_delay_slot; /* Is the delay-slot of the last insn on the next page?*/ |
int dirty; /* Is recompiled page invalid? */ |
struct x_ref *xrefs; /* what's referenced in this page */ |
struct x_ref **held_xrefs; /* The xrefs that this page holds */ |
int delayr; /* delayr of memory backing this page */ |
uint16_t ts[4096]; /* What registers the temporaries back */ |
struct dyn_page *next; |
}; |
|
struct dyn_page *find_dynd_page(oraddr_t addr); |
struct x_ref *find_host_x_ref(struct x_ref *x_refs, oraddr_t addr); |
struct x_ref *add_to_xrefs(struct dyn_page *dp, oraddr_t addr); |
void recompile_page(struct dyn_page *dyn); |
struct dyn_page *new_dp(oraddr_t page); |
void add_to_held_xrefs(struct dyn_page *dp, struct x_ref *xref); |
void add_to_opq(struct op_queue *opq, int end, int op); |
void add_to_op_params(struct op_queue *opq, int end, unsigned long param); |
void *enough_host_page(struct dyn_page *dp, void *cur, unsigned int *len, |
unsigned int amount); |
void dirtyfy_page(struct dyn_page *dp); |
struct x_ref *find_held_x_ref(struct x_ref **held_xrefs, oraddr_t or_addr); |
void init_dyn_recomp(void); |
void jump_dyn_code(oraddr_t addr); |
void dump_xrefs(struct dyn_page *dp, FILE *f); |
void run_sched_out_of_line(int add_normal); |
void recheck_immu(int got_en_dis); |
|
#define IMMU_GOT_ENABLED 1 |
#define IMMU_GOT_DISABLED 2 |
|
#define NUM_RFE_HELD 100 |
|
#endif |
/op_extend_op.h
0,0 → 1,83
/* op_extend_op.h -- Micro operations template for sign extention operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
void glue(glue(op_, EXT_NAME), _t0_t0)(void) |
{ |
register EXT_TYPE x; |
x = t0; |
t0 = EXT_CAST x; |
} |
|
void glue(glue(op_, EXT_NAME), _t0_t1)(void) |
{ |
register EXT_TYPE x; |
x = t1; |
t0 = EXT_CAST x; |
} |
|
void glue(glue(op_, EXT_NAME), _t0_t2)(void) |
{ |
register EXT_TYPE x; |
x = t2; |
t0 = EXT_CAST x; |
} |
|
void glue(glue(op_, EXT_NAME), _t1_t0)(void) |
{ |
register EXT_TYPE x; |
x = t0; |
t1 = EXT_CAST x; |
} |
|
void glue(glue(op_, EXT_NAME), _t1_t1)(void) |
{ |
register EXT_TYPE x; |
x = t1; |
t1 = EXT_CAST x; |
} |
|
void glue(glue(op_, EXT_NAME), _t1_t2)(void) |
{ |
register EXT_TYPE x; |
x = t2; |
t1 = EXT_CAST x; |
} |
|
void glue(glue(op_, EXT_NAME), _t2_t0)(void) |
{ |
register EXT_TYPE x; |
x = t0; |
t2 = EXT_CAST x; |
} |
|
void glue(glue(op_, EXT_NAME), _t2_t1)(void) |
{ |
register EXT_TYPE x; |
x = t1; |
t2 = EXT_CAST x; |
} |
|
void glue(glue(op_, EXT_NAME), _t2_t2)(void) |
{ |
register EXT_TYPE x; |
x = t2; |
t2 = EXT_CAST x; |
} |
|
/dyngen_i386.c
0,0 → 1,74
/* dyngen_i386.c -- i386 parts of dyngen |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
#include <stdio.h> |
#include <stdint.h> |
#include <stdlib.h> |
|
#include <elf.h> |
|
#include "dyngen.h" |
|
#define RET_OPCODE 0xc3 |
|
unsigned int i386_get_real_func_len(void *f_start, unsigned int f_len, char *name) |
{ |
if(((uint8_t *)f_start)[f_len - 1] != RET_OPCODE) { |
fprintf(stderr, "`%s' does not have a ret at the end!\n", name); |
exit(1); |
} |
|
return f_len - 1; |
} |
|
void i386_gen_reloc(FILE *f, struct reloc *reloc, unsigned int param) |
{ |
switch(reloc->type) { |
case R_386_32: |
fprintf(f, " *(uint32_t *)(host_page + %d) = *(ops_param + %u) + %d;\n", |
reloc->func_offset, param - 1, reloc->addend); |
break; |
default: |
fprintf(stderr, "Unknown i386 relocation: %i\n", reloc->type); |
} |
} |
|
void i386_gen_func_reloc(FILE *f, struct reloc *reloc) |
{ |
switch(reloc->type) { |
case R_386_32: |
/* This relocation is absolute. There is nothing to relocate (The linker |
* handles this fine). */ |
break; |
case R_386_PC32: |
fprintf(f, " *(uint32_t *)(host_page + %d) = (uint32_t)((%s + %d) - (unsigned int)(host_page + %d));\n", |
reloc->func_offset, reloc->name, reloc->addend, reloc->func_offset); |
break; |
default: |
fprintf(stderr, "Unknown i386 relocation: %i (symbol: %s)\n", reloc->type, |
reloc->name); |
} |
} |
|
const struct archf archfs = { |
i386_get_real_func_len, |
i386_gen_reloc, |
i386_gen_func_reloc |
}; |
/op_mac_op.h
0,0 → 1,80
/* op_mac_op.h -- Micro operations template for mac operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t0)(void) |
{ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
temp OP (int64_t)t0 * (int64_t)t0; |
|
env->sprs[SPR_MACLO] = temp & 0xffffffff; |
env->sprs[SPR_MACHI] = temp >> 32; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t1)(void) |
{ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
temp OP (int64_t)t0 * (int64_t)t1; |
|
env->sprs[SPR_MACLO] = temp & 0xffffffff; |
env->sprs[SPR_MACHI] = temp >> 32; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t0_t2)(void) |
{ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
temp OP (int64_t)t0 * (int64_t)t2; |
|
env->sprs[SPR_MACLO] = temp & 0xffffffff; |
env->sprs[SPR_MACHI] = temp >> 32; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t1)(void) |
{ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
temp OP (int64_t)t1 * (int64_t)t1; |
|
env->sprs[SPR_MACLO] = temp & 0xffffffff; |
env->sprs[SPR_MACHI] = temp >> 32; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t1_t2)(void) |
{ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
temp OP (int64_t)t1 * (int64_t)t2; |
|
env->sprs[SPR_MACLO] = temp & 0xffffffff; |
env->sprs[SPR_MACHI] = temp >> 32; |
} |
|
__or_dynop void glue(glue(op_, OP_NAME), _t2_t2)(void) |
{ |
int64_t temp = env->sprs[SPR_MACLO] | ((int64_t)env->sprs[SPR_MACHI] << 32); |
|
temp OP (int64_t)t2 * (int64_t)t2; |
|
env->sprs[SPR_MACLO] = temp & 0xffffffff; |
env->sprs[SPR_MACHI] = temp >> 32; |
} |
|
/execute.c
0,0 → 1,816
/* execute.c -- OR1K architecture dependent simulation |
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
/* Most of the OR1K simulation is done in here. |
|
When SIMPLE_EXECUTION is defined below a file insnset.c is included! |
*/ |
|
#include <stdlib.h> |
#include <stdio.h> |
#include <string.h> |
#include <ctype.h> |
|
#include "config.h" |
|
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
|
#include "port.h" |
#include "arch.h" |
#include "branch_predict.h" |
#include "abstract.h" |
#include "labels.h" |
#include "parse.h" |
#include "except.h" |
#include "sim-config.h" |
#include "debug_unit.h" |
#include "opcode/or32.h" |
#include "spr_defs.h" |
#include "execute.h" |
#include "sprs.h" |
#include "immu.h" |
#include "dmmu.h" |
#include "debug.h" |
#include "stats.h" |
|
/* Current cpu state */ |
struct cpu_state cpu_state; |
|
/* Benchmark multi issue execution */ |
int multissue[20]; |
int issued_per_cycle = 4; |
|
/* Previous program counter */ |
oraddr_t pcprev = 0; |
|
/* Temporary program counter */ |
oraddr_t pcnext; |
|
/* CCR */ |
int flag; |
|
/* Store buffer analysis - stores are accumulated and commited when IO is idle */ |
static int sbuf_head = 0, sbuf_tail = 0, sbuf_count = 0; |
static int sbuf_buf[MAX_SBUF_LEN] = {0}; |
static int sbuf_prev_cycles = 0; |
|
/* Num cycles waiting for stores to complete */ |
int sbuf_wait_cyc = 0; |
|
/* Number of total store cycles */ |
int sbuf_total_cyc = 0; |
|
/* Whether we are doing statistical analysis */ |
int do_stats = 0; |
|
/* Local data needed for execution. */ |
static int next_delay_insn; |
static int breakpoint; |
|
|
/* History of execution */ |
struct hist_exec *hist_exec_tail = NULL; |
|
/* Implementation specific. |
Get an actual value of a specific register. */ |
|
uorreg_t evalsim_reg(unsigned int regno) |
{ |
if (regno < MAX_GPRS) { |
return cpu_state.reg[regno]; |
} else { |
PRINTF("\nABORT: read out of registers\n"); |
runtime.sim.cont_run = 0; |
return 0; |
} |
} |
|
/* Implementation specific. |
Set a specific register with value. */ |
|
void setsim_reg(unsigned int regno, uorreg_t value) |
{ |
if (regno == 0) /* gpr0 is always zero */ |
value = 0; |
|
if (regno < MAX_GPRS) { |
cpu_state.reg[regno] = value; |
} else { |
PRINTF("\nABORT: write out of registers\n"); |
runtime.sim.cont_run = 0; |
} |
} |
|
/* Implementation specific. |
Set a specific register with value. */ |
|
inline static void set_reg(int regno, uorreg_t value) |
{ |
#if 0 |
if (strcmp(regstr, FRAME_REG) == 0) { |
PRINTF("FP (%s) modified by insn at %x. ", FRAME_REG, cpu_state.pc); |
PRINTF("Old:%.8lx New:%.8lx\n", eval_reg(regno), value); |
} |
|
if (strcmp(regstr, STACK_REG) == 0) { |
PRINTF("SP (%s) modified by insn at %x. ", STACK_REG, cpu_state.pc); |
PRINTF("Old:%.8lx New:%.8lx\n", eval_reg(regno), value); |
} |
#endif |
|
if (regno < MAX_GPRS) { |
cpu_state.reg[regno] = value; |
#if RAW_RANGE_STATS |
raw_stats.reg[regno] = runtime.sim.cycles; |
#endif /* RAW_RANGE */ |
} else { |
PRINTF("\nABORT: write out of registers\n"); |
runtime.sim.cont_run = 0; |
} |
} |
|
/* Implementation specific. |
Evaluates source operand opd. */ |
|
#if !(DYNAMIC_EXECUTION) |
static |
#endif |
uorreg_t eval_operand_val(uint32_t insn, struct insn_op_struct *opd) |
{ |
unsigned long operand = 0; |
unsigned long sbit; |
unsigned int nbits = 0; |
|
while(1) { |
operand |= ((insn >> (opd->type & OPTYPE_SHR)) & ((1 << opd->data) - 1)) << nbits; |
nbits += opd->data; |
|
if(opd->type & OPTYPE_OP) |
break; |
opd++; |
} |
|
if(opd->type & OPTYPE_SIG) { |
sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR; |
if(operand & (1 << sbit)) operand |= ~REG_C(0) << sbit; |
} |
|
return operand; |
} |
|
/* Does source operand depend on computation of dstoperand? Return |
non-zero if yes. |
|
Cycle t Cycle t+1 |
dst: irrelevant src: immediate always 0 |
dst: reg1 direct src: reg2 direct 0 if reg1 != reg2 |
dst: reg1 disp src: reg2 direct always 0 |
dst: reg1 direct src: reg2 disp 0 if reg1 != reg2 |
dst: reg1 disp src: reg2 disp always 1 (store must |
finish before load) |
dst: flag src: flag always 1 |
*/ |
|
static int check_depend(prev, next) |
struct iqueue_entry *prev; |
struct iqueue_entry *next; |
{ |
/* Find destination type. */ |
unsigned long type = 0; |
int prev_dis, next_dis; |
orreg_t prev_reg_val = 0; |
struct insn_op_struct *opd; |
|
if (or32_opcodes[prev->insn_index].flags & OR32_W_FLAG |
&& or32_opcodes[next->insn_index].flags & OR32_R_FLAG) |
return 1; |
|
opd = op_start[prev->insn_index]; |
prev_dis = 0; |
|
while (1) { |
if (opd->type & OPTYPE_DIS) |
prev_dis = 1; |
|
if (opd->type & OPTYPE_DST) { |
type = opd->type; |
if (prev_dis) |
type |= OPTYPE_DIS; |
/* Destination is always a register */ |
prev_reg_val = eval_operand_val (prev->insn, opd); |
break; |
} |
if (opd->type & OPTYPE_LAST) |
return 0; /* Doesn't have a destination operand */ |
if (opd->type & OPTYPE_OP) |
prev_dis = 0; |
opd++; |
} |
|
/* We search all source operands - if we find confict => return 1 */ |
opd = op_start[next->insn_index]; |
next_dis = 0; |
|
while (1) { |
if (opd->type & OPTYPE_DIS) |
next_dis = 1; |
/* This instruction sequence also depends on order of execution: |
* l.lw r1, k(r1) |
* l.sw k(r1), r4 |
* Here r1 is a destination in l.sw */ |
/* FIXME: This situation is not handeld here when r1 == r2: |
* l.sw k(r1), r4 |
* l.lw r3, k(r2) |
*/ |
if (!(opd->type & OPTYPE_DST) || (next_dis && (opd->type & OPTYPE_DST))) { |
if (opd->type & OPTYPE_REG) |
if (eval_operand_val (next->insn, opd) == prev_reg_val) |
return 1; |
} |
if (opd->type & OPTYPE_LAST) |
break; |
opd++; |
} |
|
return 0; |
} |
|
/* Sets a new SPR_SR_OV value, based on next register value */ |
|
#if SET_OV_FLAG |
#define set_ov_flag(value) if((value) & 0x80000000) setsprbits (SPR_SR, SPR_SR_OV, 1); else setsprbits (SPR_SR, SPR_SR_OV, 0) |
#else |
#define set_ov_flag(value) |
#endif |
|
/* Modified by CZ 26/05/01 for new mode execution */ |
/* Fetch returns nonzero if instruction should NOT be executed. */ |
static inline int fetch() |
{ |
static int break_just_hit = 0; |
|
if (CHECK_BREAKPOINTS) { |
/* MM: Check for breakpoint. This has to be done in fetch cycle, |
because of peripheria. |
MM1709: if we cannot access the memory entry, we could not set the |
breakpoint earlier, so just check the breakpoint list. */ |
if (has_breakpoint (peek_into_itlb (cpu_state.pc)) && !break_just_hit) { |
break_just_hit = 1; |
return 1; /* Breakpoint set. */ |
} |
break_just_hit = 0; |
} |
|
breakpoint = 0; |
/* Fetch instruction. */ |
if (!except_pending) |
runtime.cpu.instructions++; |
cpu_state.iqueue.insn_addr = cpu_state.pc; |
cpu_state.iqueue.insn = eval_insn (cpu_state.pc, &breakpoint); |
|
/* update_pc will be called after execution */ |
|
return 0; |
} |
|
/* This code actually updates the PC value. */ |
static inline void update_pc () |
{ |
cpu_state.delay_insn = next_delay_insn; |
pcprev = cpu_state.pc; /* Store value for later */ |
cpu_state.pc = pcnext; |
pcnext = cpu_state.delay_insn ? cpu_state.pc_delay : pcnext + 4; |
} |
|
#if SIMPLE_EXECUTION |
static inline |
#endif |
void analysis (struct iqueue_entry *current) |
{ |
if (config.cpu.dependstats) { |
/* Dynamic, dependency stats. */ |
adddstats(cpu_state.icomplet.insn_index, current->insn_index, 1, |
check_depend(&cpu_state.icomplet, current)); |
|
/* Dynamic, functional units stats. */ |
addfstats(or32_opcodes[cpu_state.icomplet.insn_index].func_unit, |
or32_opcodes[current->insn_index].func_unit, 1, |
check_depend(&cpu_state.icomplet, current)); |
|
/* Dynamic, single stats. */ |
addsstats(current->insn_index, 1); |
} |
|
if (config.cpu.superscalar) { |
if ((or32_opcodes[current->insn_index].func_unit == it_branch) || |
(or32_opcodes[current->insn_index].func_unit == it_jump)) |
runtime.sim.storecycles += 0; |
|
if (or32_opcodes[current->insn_index].func_unit == it_store) |
runtime.sim.storecycles += 1; |
|
if (or32_opcodes[current->insn_index].func_unit == it_load) |
runtime.sim.loadcycles += 1; |
#if 0 |
if ((cpu_state.icomplet.func_unit == it_load) && |
check_depend(&cpu_state.icomplet, current)) |
runtime.sim.loadcycles++; |
#endif |
|
/* Pseudo multiple issue benchmark */ |
if ((multissue[or32_opcodes[current->insn_index].func_unit] < 1) || |
(check_depend(&cpu_state.icomplet, current)) || (issued_per_cycle < 1)) { |
int i; |
for (i = 0; i < 20; i++) |
multissue[i] = 2; |
issued_per_cycle = 2; |
runtime.cpu.supercycles++; |
if (check_depend(&cpu_state.icomplet, current)) |
runtime.cpu.hazardwait++; |
multissue[it_unknown] = 2; |
multissue[it_shift] = 2; |
multissue[it_compare] = 1; |
multissue[it_branch] = 1; |
multissue[it_jump] = 1; |
multissue[it_extend] = 2; |
multissue[it_nop] = 2; |
multissue[it_move] = 2; |
multissue[it_movimm] = 2; |
multissue[it_arith] = 2; |
multissue[it_store] = 2; |
multissue[it_load] = 2; |
} |
multissue[or32_opcodes[current->insn_index].func_unit]--; |
issued_per_cycle--; |
} |
|
if (config.cpu.dependstats) |
/* Instruction waits in completition buffer until retired. */ |
memcpy (&cpu_state.icomplet, current, sizeof (struct iqueue_entry)); |
|
if (config.sim.history) { |
/* History of execution */ |
hist_exec_tail = hist_exec_tail->next; |
hist_exec_tail->addr = cpu_state.icomplet.insn_addr; |
} |
|
if (config.sim.exe_log) dump_exe_log(); |
} |
|
/* Store buffer analysis - stores are accumulated and commited when IO is idle */ |
static inline void sbuf_store (int cyc) { |
int delta = runtime.sim.cycles - sbuf_prev_cycles; |
sbuf_total_cyc += cyc; |
sbuf_prev_cycles = runtime.sim.cycles; |
|
//PRINTF (">STORE %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]); |
//PRINTF ("|%i,%i\n", sbuf_total_cyc, sbuf_wait_cyc); |
/* Take stores from buffer, that occured meanwhile */ |
while (sbuf_count && delta >= sbuf_buf[sbuf_tail]) { |
delta -= sbuf_buf[sbuf_tail]; |
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN; |
sbuf_count--; |
} |
if (sbuf_count) |
sbuf_buf[sbuf_tail] -= delta; |
|
/* Store buffer is full, take one out */ |
if (sbuf_count >= config.cpu.sbuf_len) { |
sbuf_wait_cyc += sbuf_buf[sbuf_tail]; |
runtime.sim.mem_cycles += sbuf_buf[sbuf_tail]; |
sbuf_prev_cycles += sbuf_buf[sbuf_tail]; |
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN; |
sbuf_count--; |
} |
/* Put newest store in the buffer */ |
sbuf_buf[sbuf_head] = cyc; |
sbuf_head = (sbuf_head + 1) % MAX_SBUF_LEN; |
sbuf_count++; |
//PRINTF ("|STORE %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]); |
} |
|
/* Store buffer analysis - previous stores should commit, before any load */ |
static inline void sbuf_load () { |
int delta = runtime.sim.cycles - sbuf_prev_cycles; |
sbuf_prev_cycles = runtime.sim.cycles; |
|
//PRINTF (">LOAD %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]); |
//PRINTF ("|%i,%i\n", sbuf_total_cyc, sbuf_wait_cyc); |
/* Take stores from buffer, that occured meanwhile */ |
while (sbuf_count && delta >= sbuf_buf[sbuf_tail]) { |
delta -= sbuf_buf[sbuf_tail]; |
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN; |
sbuf_count--; |
} |
if (sbuf_count) |
sbuf_buf[sbuf_tail] -= delta; |
|
/* Wait for all stores to complete */ |
while (sbuf_count > 0) { |
sbuf_wait_cyc += sbuf_buf[sbuf_tail]; |
runtime.sim.mem_cycles += sbuf_buf[sbuf_tail]; |
sbuf_prev_cycles += sbuf_buf[sbuf_tail]; |
sbuf_tail = (sbuf_tail + 1) % MAX_SBUF_LEN; |
sbuf_count--; |
} |
//PRINTF ("|LOAD %i,%i,%i,%i,%i\n", delta, sbuf_count, sbuf_tail, sbuf_head, sbuf_buf[sbuf_tail], sbuf_buf[sbuf_head]); |
} |
|
/* Outputs dissasembled instruction */ |
void dump_exe_log () |
{ |
oraddr_t insn_addr = cpu_state.iqueue.insn_addr; |
unsigned int i, j; |
uorreg_t operand; |
|
if (insn_addr == 0xffffffff) return; |
if ((config.sim.exe_log_start <= runtime.cpu.instructions) && |
((config.sim.exe_log_end <= 0) || |
(runtime.cpu.instructions <= config.sim.exe_log_end))) { |
if (config.sim.exe_log_marker && |
!(runtime.cpu.instructions % config.sim.exe_log_marker)) { |
fprintf (runtime.sim.fexe_log, "--------------------- %8lli instruction ---------------------\n", runtime.cpu.instructions); |
} |
switch (config.sim.exe_log_type) { |
case EXE_LOG_HARDWARE: |
fprintf (runtime.sim.fexe_log, "\nEXECUTED(%11llu): %"PRIxADDR": ", |
runtime.cpu.instructions, insn_addr); |
fprintf (runtime.sim.fexe_log, "%.2x%.2x", evalsim_mem8_void(insn_addr), |
evalsim_mem8_void(insn_addr + 1)); |
fprintf (runtime.sim.fexe_log, "%.2x%.2x", |
evalsim_mem8_void(insn_addr + 2), |
evalsim_mem8_void(insn_addr + 3)); |
for(i = 0; i < MAX_GPRS; i++) { |
if (i % 4 == 0) |
fprintf(runtime.sim.fexe_log, "\n"); |
fprintf (runtime.sim.fexe_log, "GPR%2u: %"PRIxREG" ", i, |
cpu_state.reg[i]); |
} |
fprintf (runtime.sim.fexe_log, "\n"); |
fprintf (runtime.sim.fexe_log, "SR : %.8lx ", mfspr(SPR_SR)); |
fprintf (runtime.sim.fexe_log, "EPCR0: %.8lx ", mfspr(SPR_EPCR_BASE)); |
fprintf (runtime.sim.fexe_log, "EEAR0: %.8lx ", mfspr(SPR_EEAR_BASE)); |
fprintf (runtime.sim.fexe_log, "ESR0 : %.8lx\n", mfspr(SPR_ESR_BASE)); |
break; |
case EXE_LOG_SIMPLE: |
case EXE_LOG_SOFTWARE: |
{ |
extern char *disassembled; |
disassemble_index (cpu_state.iqueue.insn, cpu_state.iqueue.insn_index); |
{ |
struct label_entry *entry; |
entry = get_label(insn_addr); |
if (entry) |
fprintf (runtime.sim.fexe_log, "%s:\n", entry->name); |
} |
|
if (config.sim.exe_log_type == EXE_LOG_SOFTWARE) { |
struct insn_op_struct *opd = op_start[cpu_state.iqueue.insn_index]; |
|
j = 0; |
while (1) { |
operand = eval_operand_val (cpu_state.iqueue.insn, opd); |
while (!(opd->type & OPTYPE_OP)) |
opd++; |
if (opd->type & OPTYPE_DIS) { |
fprintf (runtime.sim.fexe_log, "EA =%"PRIxADDR" PA =%"PRIxADDR" ", |
cpu_state.insn_ea, peek_into_dtlb(cpu_state.insn_ea,0,0)); |
opd++; /* Skip of register operand */ |
j++; |
} else if ((opd->type & OPTYPE_REG) && operand) { |
fprintf (runtime.sim.fexe_log, "r%-2i=%"PRIxREG" ", |
(int)operand, evalsim_reg (operand)); |
} else |
fprintf (runtime.sim.fexe_log, " "); |
j++; |
if(opd->type & OPTYPE_LAST) |
break; |
opd++; |
} |
if(or32_opcodes[cpu_state.iqueue.insn_index].flags & OR32_R_FLAG) { |
fprintf (runtime.sim.fexe_log, "SR =%08x", |
cpu_state.sprs[SPR_SR]); |
j++; |
} |
while(j < 3) { |
fprintf (runtime.sim.fexe_log, " "); |
j++; |
} |
} |
fprintf (runtime.sim.fexe_log, "%"PRIxADDR" ", insn_addr); |
fprintf (runtime.sim.fexe_log, "%s\n", disassembled); |
} |
} |
} |
} |
|
/* Dump registers - 'r' or 't' command */ |
void dumpreg() |
{ |
int i; |
oraddr_t physical_pc; |
|
if ((physical_pc = peek_into_itlb(cpu_state.iqueue.insn_addr))) { |
/* |
* PRINTF("\t\t\tEA: %08x <--> PA: %08x\n", cpu_state.iqueue.insn_addr, physical_pc); |
*/ |
dumpmemory(physical_pc, physical_pc + 4, 1, 0); |
} |
else { |
PRINTF("INTERNAL SIMULATOR ERROR:\n"); |
PRINTF("no translation for currently executed instruction\n"); |
} |
|
// generate_time_pretty (temp, runtime.sim.cycles * config.sim.clkcycle_ps); |
PRINTF(" (executed) [cycle %lld, #%lld]\n", runtime.sim.cycles, |
runtime.cpu.instructions); |
if (config.cpu.superscalar) |
PRINTF ("Superscalar CYCLES: %u", runtime.cpu.supercycles); |
if (config.cpu.hazards) |
PRINTF (" HAZARDWAIT: %u\n", runtime.cpu.hazardwait); |
else |
if (config.cpu.superscalar) |
PRINTF ("\n"); |
|
if ((physical_pc = peek_into_itlb(cpu_state.pc))) { |
/* |
* PRINTF("\t\t\tEA: %08x <--> PA: %08x\n", cpu_state.pc, physical_pc); |
*/ |
dumpmemory(physical_pc, physical_pc + 4, 1, 0); |
} |
else |
PRINTF("%"PRIxADDR": : xxxxxxxx ITLB miss follows", cpu_state.pc); |
|
PRINTF(" (next insn) %s", (cpu_state.delay_insn?"(delay insn)":"")); |
for(i = 0; i < MAX_GPRS; i++) { |
if (i % 4 == 0) |
PRINTF("\n"); |
PRINTF("GPR%.2u: %"PRIxREG" ", i, evalsim_reg(i)); |
} |
PRINTF("flag: %u\n", flag); |
} |
|
/* Generated/built in decoding/executing function */ |
static inline void decode_execute (struct iqueue_entry *current); |
|
/* Wrapper around real decode_execute function -- some statistics here only */ |
static inline void decode_execute_wrapper (struct iqueue_entry *current) |
{ |
breakpoint = 0; |
|
#ifndef HAS_EXECUTION |
#error HAS_EXECUTION has to be defined in order to execute programs. |
#endif |
|
/* FIXME: Most of this file is not needed with DYNAMIC_EXECUTION */ |
#if !(DYNAMIC_EXECUTION) |
decode_execute (current); |
#endif |
|
#if SET_OV_FLAG |
/* Check for range exception */ |
if (testsprbits (SPR_SR, SPR_SR_OVE) && testsprbits (SPR_SR, SPR_SR_OV)) |
except_handle (EXCEPT_RANGE, mfspr(SPR_EEAR_BASE)); |
#endif |
|
if(breakpoint) |
except_handle(EXCEPT_TRAP, mfspr(SPR_EEAR_BASE)); |
} |
|
/* Reset the CPU */ |
void cpu_reset() |
{ |
int i; |
struct hist_exec *hist_exec_head = NULL; |
struct hist_exec *hist_exec_new; |
|
runtime.sim.cycles = 0; |
runtime.sim.loadcycles = 0; |
runtime.sim.storecycles = 0; |
runtime.cpu.instructions = 0; |
runtime.cpu.supercycles = 0; |
runtime.cpu.hazardwait = 0; |
for (i = 0; i < MAX_GPRS; i++) |
set_reg (i, 0); |
memset(&cpu_state.iqueue, 0, sizeof(cpu_state.iqueue)); |
memset(&cpu_state.icomplet, 0, sizeof(cpu_state.icomplet)); |
|
sbuf_head = 0; |
sbuf_tail = 0; |
sbuf_count = 0; |
sbuf_prev_cycles = 0; |
|
/* Initialise execution history circular buffer */ |
for (i = 0; i < HISTEXEC_LEN; i++) { |
hist_exec_new = malloc(sizeof(struct hist_exec)); |
if(!hist_exec_new) { |
fprintf(stderr, "Out-of-memory\n"); |
exit(1); |
} |
if(!hist_exec_head) |
hist_exec_head = hist_exec_new; |
else |
hist_exec_tail->next = hist_exec_new; |
|
hist_exec_new->prev = hist_exec_tail; |
hist_exec_tail = hist_exec_new; |
} |
/* Make hist_exec_tail->next point to hist_exec_head */ |
hist_exec_tail->next = hist_exec_head; |
hist_exec_head->prev = hist_exec_tail; |
|
/* Cpu configuration */ |
cpu_state.sprs[SPR_UPR] = config.cpu.upr; |
setsprbits(SPR_VR, SPR_VR_VER, config.cpu.ver); |
setsprbits(SPR_VR, SPR_VR_REV, config.cpu.rev); |
cpu_state.sprs[SPR_SR] = config.cpu.sr; |
|
pcnext = 0x0; /* MM1409: All programs should start at reset vector entry! */ |
if (config.sim.verbose) PRINTF ("Starting at 0x%"PRIxADDR"\n", pcnext); |
cpu_state.pc = pcnext; |
pcnext += 4; |
debug(1, "reset ...\n"); |
|
#if DYNAMIC_EXECUTION |
cpu_state.ts_current = 1; |
#endif |
|
/* MM1409: All programs should set their stack pointer! */ |
except_handle(EXCEPT_RESET, 0); |
update_pc(); |
except_pending = 0; |
} |
|
/* Simulates one CPU clock cycle */ |
inline int cpu_clock () |
{ |
except_pending = 0; |
next_delay_insn = 0; |
if(fetch()) { |
PRINTF ("Breakpoint hit.\n"); |
runtime.sim.cont_run = 0; /* memory breakpoint encountered */ |
return 1; |
} |
|
if(except_pending) { |
update_pc(); |
except_pending = 0; |
return 0; |
} |
|
if(breakpoint) { |
except_handle(EXCEPT_TRAP, mfspr(SPR_EEAR_BASE)); |
update_pc(); |
except_pending = 0; |
return 0; |
} |
|
decode_execute_wrapper (&cpu_state.iqueue); |
update_pc(); |
return 0; |
} |
|
/* If decoding cannot be found, call this function */ |
#if SIMPLE_EXECUTION |
void l_invalid (struct iqueue_entry *current) { |
#else |
void l_invalid () { |
#endif |
except_handle(EXCEPT_ILLEGAL, cpu_state.iqueue.insn_addr); |
} |
|
#if COMPLEX_EXECUTION |
|
/* Include decode_execute function */ |
#include "execgen.c" |
|
#elif SIMPLE_EXECUTION |
|
|
#define INSTRUCTION(name) void name (struct iqueue_entry *current) |
|
/* Implementation specific. |
Get an actual value of a specific register. */ |
|
static uorreg_t eval_reg(unsigned int regno) |
{ |
if (regno < MAX_GPRS) { |
#if RAW_RANGE_STATS |
int delta = (runtime.sim.cycles - raw_stats.reg[regno]); |
if ((unsigned long)delta < (unsigned long)MAX_RAW_RANGE) |
raw_stats.range[delta]++; |
#endif /* RAW_RANGE */ |
return cpu_state.reg[regno]; |
} else { |
PRINTF("\nABORT: read out of registers\n"); |
runtime.sim.cont_run = 0; |
return 0; |
} |
} |
|
/* Implementation specific. |
Evaluates source operand op_no. */ |
|
static uorreg_t eval_operand (int op_no, unsigned long insn_index, uint32_t insn) |
{ |
struct insn_op_struct *opd = op_start[insn_index]; |
uorreg_t ret; |
|
while (op_no) { |
if(opd->type & OPTYPE_LAST) { |
fprintf (stderr, "Instruction requested more operands than it has\n"); |
exit (1); |
} |
if((opd->type & OPTYPE_OP) && !(opd->type & OPTYPE_DIS)) |
op_no--; |
opd++; |
} |
|
if (opd->type & OPTYPE_DIS) { |
ret = eval_operand_val (insn, opd); |
while (!(opd->type & OPTYPE_OP)) |
opd++; |
opd++; |
ret += eval_reg (eval_operand_val (insn, opd)); |
cpu_state.insn_ea = ret; |
return ret; |
} |
if (opd->type & OPTYPE_REG) |
return eval_reg (eval_operand_val (insn, opd)); |
|
return eval_operand_val (insn, opd); |
} |
|
/* Implementation specific. |
Set destination operand (reister direct) with value. */ |
|
inline static void set_operand(int op_no, orreg_t value, |
unsigned long insn_index, uint32_t insn) |
{ |
struct insn_op_struct *opd = op_start[insn_index]; |
|
while (op_no) { |
if(opd->type & OPTYPE_LAST) { |
fprintf (stderr, "Instruction requested more operands than it has\n"); |
exit (1); |
} |
if((opd->type & OPTYPE_OP) && !(opd->type & OPTYPE_DIS)) |
op_no--; |
opd++; |
} |
|
if (!(opd->type & OPTYPE_REG)) { |
fprintf (stderr, "Trying to set a non-register operand\n"); |
exit (1); |
} |
set_reg (eval_operand_val (insn, opd), value); |
} |
|
/* Simple and rather slow decoding function based on built automata. */ |
static inline void decode_execute (struct iqueue_entry *current) |
{ |
int insn_index; |
|
current->insn_index = insn_index = insn_decode(current->insn); |
|
if (insn_index < 0) |
l_invalid(current); |
else { |
or32_opcodes[insn_index].exec(current); |
} |
|
if (do_stats) analysis(&cpu_state.iqueue); |
} |
|
#define SET_PARAM0(val) set_operand(0, val, current->insn_index, current->insn) |
|
#define PARAM0 eval_operand(0, current->insn_index, current->insn) |
#define PARAM1 eval_operand(1, current->insn_index, current->insn) |
#define PARAM2 eval_operand(2, current->insn_index, current->insn) |
|
#include "insnset.c" |
|
#elif defined(DYNAMIC_EXECUTION) |
|
#else |
# error "One of SIMPLE_EXECUTION/COMPLEX_EXECUTION must be defined" |
#endif |
/common_i386.h
0,0 → 1,63
/* common_i386.h -- Assembler routines used in rec_i386.h and op_i386.h |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
/* This is needed because we can't move an mmx register to a general purpose |
* register. */ |
static union { |
struct { |
uint32_t low32; |
uint32_t high32; |
} val3232; |
uint64_t val64; |
} useless_x86; |
|
/* Sets the PC with a specified value */ |
static inline void set_pc(oraddr_t pc) |
{ |
/* I could just use pc as a memory argument, but if I do that then gcc may put |
* the value of pc onto the stack, in which case gcc would also shift the |
* stack twice, which would result in two add 4, %esp instructions and a |
* mov %eax, *%esp, which would not only be slow but it would take up more |
* space. */ |
asm("movq %%mm0, %0\n" |
"\tmovl %2, %1\n" |
"\tmovq %3, %%mm0" |
: "=m" (useless_x86.val64), |
"=m" (useless_x86.val3232.high32) |
: "r" (pc), |
"m" (useless_x86.val64)); |
} |
|
/* Returns the current value of the pc */ |
static inline oraddr_t get_pc(void) |
{ |
asm("movq %%mm0, %0" : "=m" (useless_x86.val64)); |
return useless_x86.val3232.high32; |
} |
|
/* Updates the runtime.sim.cycles counter */ |
static inline void upd_sim_cycles(void) |
{ |
asm volatile ("movq %%mm0, %0\n" : "=m" (useless_x86.val64)); |
runtime.sim.cycles += scheduler.job_queue->time - useless_x86.val3232.low32; |
scheduler.job_queue->time = useless_x86.val3232.low32; |
cpu_state.pc = useless_x86.val3232.high32; |
} |
|
/dyngen_elf.c
0,0 → 1,359
/* dyngen_elf.c -- Elf parser for dyngen |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <stdint.h> |
#include <assert.h> |
|
#include <elf.h> |
|
#include "dyngen.h" |
|
struct elf_obj { |
Elf32_Ehdr e_hdr; |
Elf32_Shdr *e_shdrs; |
void **e_sections; |
Elf32_Sym *e_syms; /* The symbol table in the elf file */ |
unsigned int e_sym_num; /* The number of symbols */ |
unsigned int e_sym_str_tab; /* The string-table associated with symbols */ |
Elf32_Rel *e_rels; |
unsigned int e_rel_num; /* The number of relocations (in e_rel) */ |
unsigned int e_rel_sym; |
unsigned int e_rel_sec; /* The section to modify */ |
Elf32_Rela *e_relas; |
unsigned int e_rela_num; /* The number of relocations (in e_rela) */ |
unsigned int e_rela_sym; |
unsigned int e_rela_sec; /* The section to modify */ |
}; |
|
void *elf_open_obj(const char *file) |
{ |
struct elf_obj *obj; |
FILE *f; |
int i; |
|
if(!(obj = malloc(sizeof(struct elf_obj)))) { |
fprintf(stderr, "OOM\n"); |
return NULL; |
} |
|
if(!(f = fopen(file, "r"))) { |
free(obj); |
return NULL; |
} |
|
fread(&obj->e_hdr, sizeof(Elf32_Ehdr), 1, f); |
|
/* Do some sanity checks */ |
if((obj->e_hdr.e_ident[EI_MAG0] != ELFMAG0) || |
(obj->e_hdr.e_ident[EI_MAG1] != ELFMAG1) || |
(obj->e_hdr.e_ident[EI_MAG2] != ELFMAG2) || |
(obj->e_hdr.e_ident[EI_MAG3] != ELFMAG3)) { |
fprintf(stderr, "%s is not an elf file!\n", file); |
goto error_load; |
} |
|
if(obj->e_hdr.e_ident[EI_CLASS] == ELFCLASSNONE) { |
fprintf(stderr, "Invalid class in ELF header\n"); |
goto error_load; |
} |
|
if(obj->e_hdr.e_ident[EI_DATA] == ELFDATANONE) { |
fprintf(stderr, "Invalid data format in ELF header\n"); |
goto error_load; |
} |
|
/* FIXME: Swap data as necessary */ |
|
if((obj->e_hdr.e_ident[EI_VERSION] != 1) || |
(obj->e_hdr.e_version != 1)) { |
fprintf(stderr, "Unexpected elf version found: %i (%i)\n", |
obj->e_hdr.e_ident[EI_VERSION], obj->e_hdr.e_version); |
goto error_load; |
} |
|
if(obj->e_hdr.e_type != ET_REL) { |
fprintf(stderr, "Appears that we did not receive a object file\n"); |
goto error_load; |
} |
|
if(obj->e_hdr.e_phoff) { |
fprintf(stderr, "What am I supposed to do with a program header??\n"); |
goto error_load; |
} |
|
if(obj->e_hdr.e_ehsize != sizeof(Elf32_Ehdr)) { |
fprintf(stderr, "Unknown size of elf header\n"); |
goto error_load; |
} |
|
if(!obj->e_hdr.e_shoff || !obj->e_hdr.e_shnum) { |
fprintf(stderr, "The elf file contains no sections!\n"); |
goto error_load; |
} |
|
if(obj->e_hdr.e_shentsize != sizeof(Elf32_Shdr)) { |
fprintf(stderr, "Unknown section header size %i\n", obj->e_hdr.e_shentsize); |
goto error_load; |
} |
|
/* Load the section headers */ |
if(!(obj->e_shdrs = malloc(obj->e_hdr.e_shentsize * obj->e_hdr.e_shnum))){ |
fprintf(stderr, "OOM\n"); |
goto error_load; |
} |
|
fseek(f, obj->e_hdr.e_shoff, SEEK_SET); |
fread(obj->e_shdrs, obj->e_hdr.e_shentsize, obj->e_hdr.e_shnum, f); |
|
/* FIXME: swap data */ |
|
/* Load the sections */ |
if(!(obj->e_sections = calloc(obj->e_hdr.e_shnum, sizeof(void *)))) { |
fprintf(stderr, "OOM\n"); |
free(obj->e_shdrs); |
goto error_load; |
} |
|
for(i = 0; i < obj->e_hdr.e_shnum; i++) { |
if(obj->e_shdrs[i].sh_type == SHT_NOBITS) |
continue; |
if(!(obj->e_sections[i] = malloc(obj->e_shdrs[i].sh_size))) { |
fprintf(stderr, "OOM\n"); |
goto post_sec_error_load; |
} |
fseek(f, obj->e_shdrs[i].sh_offset, SEEK_SET); |
fread(obj->e_sections[i], obj->e_shdrs[i].sh_size, 1, f); |
} |
|
obj->e_rels = NULL; |
obj->e_syms = NULL; |
obj->e_relas = NULL; |
|
/* Find the symbol table and relocation table(s) */ |
for(i = 0; i < obj->e_hdr.e_shnum; i++) { |
switch(obj->e_shdrs[i].sh_type) { |
case SHT_SYMTAB: |
if(obj->e_syms) { |
fprintf(stderr, "ELF file has more than one symbol table\n"); |
goto post_sec_error_load; |
} |
if(obj->e_shdrs[i].sh_entsize != sizeof(Elf32_Sym)) { |
fprintf(stderr, "ELF symbol table entry size is unknown\n"); |
goto post_sec_error_load; |
} |
if((obj->e_shdrs[i].sh_size % obj->e_shdrs[i].sh_entsize)) { |
fprintf(stderr, "Symbol table's length is not a multiple of sizeof(Elf32_Sym\n"); |
goto post_sec_error_load; |
} |
obj->e_syms = obj->e_sections[i]; |
obj->e_sym_num = obj->e_shdrs[i].sh_size / obj->e_shdrs[i].sh_entsize; |
obj->e_sym_str_tab = obj->e_shdrs[i].sh_link; |
break; |
case SHT_REL: |
if(obj->e_rels) { |
fprintf(stderr, "ELF file has more than one relocation table\n"); |
goto post_sec_error_load; |
} |
if(obj->e_shdrs[i].sh_entsize != sizeof(Elf32_Rel)) { |
fprintf(stderr, "ELF relocation table entry size is unknown\n"); |
goto post_sec_error_load; |
} |
if((obj->e_shdrs[i].sh_size % obj->e_shdrs[i].sh_entsize)) { |
fprintf(stderr, "Relocation table's length is not a multiple of sizeof(Elf32_Rel\n"); |
goto post_sec_error_load; |
} |
obj->e_rels = obj->e_sections[i]; |
obj->e_rel_sec = obj->e_shdrs[i].sh_info; |
obj->e_rel_sym = obj->e_shdrs[i].sh_link; |
obj->e_rel_num = obj->e_shdrs[i].sh_size / obj->e_shdrs[i].sh_entsize; |
break; |
case SHT_RELA: |
if(obj->e_relas) { |
fprintf(stderr, "ELF file has more than one a-relocation table\n"); |
goto post_sec_error_load; |
} |
if(obj->e_shdrs[i].sh_entsize != sizeof(Elf32_Rela)) { |
fprintf(stderr, "ELF a-relocation table entry size is unknown\n"); |
goto post_sec_error_load; |
} |
if((obj->e_shdrs[i].sh_size % obj->e_shdrs[i].sh_entsize)) { |
fprintf(stderr, "Relocation table's length is not a multiple of sizeof(Elf32_Rela)\n"); |
goto post_sec_error_load; |
} |
obj->e_relas = obj->e_sections[i]; |
obj->e_rela_sec = obj->e_shdrs[i].sh_info; |
obj->e_rela_sym = obj->e_shdrs[i].sh_link; |
obj->e_rela_num = obj->e_shdrs[i].sh_size / obj->e_shdrs[i].sh_entsize; |
break; |
} |
} |
|
fclose(f); |
return obj; |
|
post_sec_error_load: |
for(i = 0; i < obj->e_hdr.e_shnum; i++) { |
if(obj->e_sections[i]) |
free(obj->e_sections[i]); |
} |
free(obj->e_sections); |
free(obj->e_shdrs); |
error_load: |
free(obj); |
fclose(f); |
return NULL; |
} |
|
void elf_close_obj(void *e_obj) |
{ |
struct elf_obj *obj = e_obj; |
int i; |
|
for(i = 0; i < obj->e_hdr.e_shnum; i++) { |
if(obj->e_sections[i]) |
free(obj->e_sections[i]); |
} |
free(obj->e_sections); |
free(obj->e_shdrs); |
free(obj); |
} |
|
static Elf32_Sym *elf_find_func(struct elf_obj *obj, unsigned int func) |
{ |
int i, j; |
Elf32_Sym *cur; |
|
for(i = 0, j = 0, cur = obj->e_syms; i < obj->e_sym_num; i++, cur++) { |
if(ELF32_ST_BIND(cur->st_info) != STB_GLOBAL) |
continue; |
if(ELF32_ST_TYPE(cur->st_info) != STT_FUNC) |
continue; |
if(j == func) |
return cur; |
j++; |
} |
return NULL; |
} |
|
char *elf_get_func_name(void *e_obj, unsigned int func) |
{ |
struct elf_obj *obj = e_obj; |
Elf32_Sym *func_sym = elf_find_func(obj, func); |
|
if(func_sym) |
return obj->e_sections[obj->e_sym_str_tab] + func_sym->st_name; |
|
return NULL; |
} |
|
unsigned int elf_get_func_len(void *e_obj, unsigned int func) |
{ |
struct elf_obj *obj = e_obj; |
Elf32_Sym *func_sym = elf_find_func(obj, func); |
|
if(func_sym) |
return func_sym->st_size; |
return 0; |
} |
|
void *elf_get_func_start(void *e_obj, unsigned int func) |
{ |
struct elf_obj *obj = e_obj; |
Elf32_Sym *func_sym = elf_find_func(obj, func); |
|
if(!func_sym) |
return NULL; |
|
if(func_sym->st_shndx == SHN_COMMON) { |
fprintf(stderr, "Don't know how to handle SHN_COMMON section header\n"); |
return NULL; |
} |
|
return obj->e_sections[func_sym->st_shndx] + func_sym->st_value; |
} |
|
static char *elf_get_sym_name(struct elf_obj *obj, unsigned int sym) |
{ |
char *name; |
|
name = obj->e_sections[obj->e_sym_str_tab]; |
name += obj->e_syms[sym].st_name; |
|
return name; |
} |
|
int elf_get_func_reloc(void *e_obj, unsigned int func, unsigned int relocn, |
struct reloc *reloc) |
{ |
struct elf_obj *obj = e_obj; |
Elf32_Sym *func_sym = elf_find_func(obj, func); |
Elf32_Rel *cur; |
Elf32_Rela *cura; |
int i, j; |
|
/* |
if(obj->e_rel_sec != func_sym->st_shndx) { |
fprintf(stderr, "Don't know what to do: Function does not have a relocation table\n"); |
return 0; |
} |
*/ |
|
for(i = 0, j = 0, cur = obj->e_rels; i < obj->e_rel_num; i++, cur++) { |
if((cur->r_offset - func_sym->st_value) > func_sym->st_size) |
continue; |
if(relocn == j) { |
reloc->name = elf_get_sym_name(obj, ELF32_R_SYM(cur->r_info)); |
reloc->func_offset = cur->r_offset - func_sym->st_value; |
reloc->type = ELF32_R_TYPE(cur->r_info); |
/* FIXME: Byte-swap */ |
reloc->addend = *(uint32_t *)(obj->e_sections[obj->e_rel_sec] + cur->r_offset); |
return 1; |
} |
j++; |
} |
|
if(!obj->e_relas) |
return 0; |
|
for(i = 0, cura = obj->e_relas; i < obj->e_rela_num; i++, cura++) { |
if((cura->r_offset - func_sym->st_value) > func_sym->st_size) |
continue; |
if(relocn == j) { |
reloc->name = elf_get_sym_name(obj, ELF32_R_SYM(cur->r_info)); |
reloc->func_offset = cura->r_offset - func_sym->st_value; |
reloc->type = ELF32_R_TYPE(cur->r_info); |
reloc->addend = cura->r_addend; |
return 1; |
} |
j++; |
} |
|
return 0; |
} |
|
const struct bff bffs = { |
elf_open_obj, |
elf_close_obj, |
elf_get_func_name, |
elf_get_func_start, |
elf_get_func_len, |
elf_get_func_reloc }; |
/op_mftspr_op.h
0,0 → 1,43
/* op_mftspr_op.h -- Micro operations template for the m{f,t}spr operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
#ifndef ONLY_MTSPR |
__or_dynop void glue(glue(glue(op_mfspr_, GPR_T_NAME), _), SPR_T_NAME)(void) |
{ |
/* FIXME: NPC/PPC Handling is br0ke */ |
if(env->sprs[SPR_SR] & SPR_SR_SM) { |
upd_sim_cycles(); |
GPR_T = mfspr(SPR_T + OP_PARAM1); |
} |
} |
#endif |
|
__or_dynop void glue(glue(glue(op_mtspr_, SPR_T_NAME), _), GPR_T_NAME)(void) |
{ |
/* FIXME: NPC handling DOES NOT WORK like this */ |
if(env->sprs[SPR_SR] & SPR_SR_SM) { |
upd_sim_cycles(); |
/* Yes, an l.mtspr instruction can cause an exception if the immu is touched |
* it might cause an ITLB miss of instruction page fault. */ |
save_t_temporary(); |
mtspr(SPR_T + OP_PARAM1, GPR_T); |
} |
} |
|
/i386_regs.h
0,0 → 1,26
/* i386_regs.h -- Register definitions for i386 |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
#define CPU_STATE_REG "ebp" |
#define T0_REG "ebx" |
#define T1_REG "esi" |
#define T2_REG "edi" |
|
#define NUM_T_REGS 3 |
/op_t_reg_mov_op.h
0,0 → 1,49
/* op_t_reg_mov_op.h -- Micro operations template for reg->temporary operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
__or_dynop void glue(op_move_t0_gpr, REG)(void) |
{ |
t0 = env->reg[REG]; |
} |
|
__or_dynop void glue(op_move_t1_gpr, REG)(void) |
{ |
t1 = env->reg[REG]; |
} |
|
__or_dynop void glue(op_move_t2_gpr, REG)(void) |
{ |
t2 = env->reg[REG]; |
} |
|
__or_dynop void glue(glue(op_move_gpr, REG), _t0)(void) |
{ |
env->reg[REG] = t0; |
} |
|
__or_dynop void glue(glue(op_move_gpr, REG), _t1)(void) |
{ |
env->reg[REG] = t1; |
} |
|
__or_dynop void glue(glue(op_move_gpr, REG), _t2)(void) |
{ |
env->reg[REG] = t2; |
} |
/dyngen.c
0,0 → 1,291
/* dyngen.c -- Generates micro operation generating functions |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
#include <stdio.h> |
#include <string.h> |
#include <stdlib.h> |
|
#include "dyngen.h" |
|
#define OP_FUNC_PREFIX "op_" |
#define OP_FUNC_PARAM_PREFIX "__op_param" |
/* Have to add to to make sure that the param[] is 0 */ |
#define MAX_PARAMS (3 + 1) |
|
static const char *c_file_head = |
"#include \"config.h\"\n" |
"\n" |
"#include <inttypes.h>\n" |
"\n" |
"#include \"arch.h\"\n" |
"#include \"opcode/or32.h\"\n" |
"#include \"spr_defs.h\"\n" |
"#include \"i386_regs.h\"\n" |
"#include \"abstract.h\"\n" |
"\n" |
"#include \"dyn_rec.h\"\n" |
"#include \"%s\"\n" |
"\n"; |
|
static const char *gen_code_proto = |
"void gen_code(struct op_queue *opq, struct dyn_page *dp);\n" |
"void patch_relocs(struct op_queue *opq, void *host_page);\n" |
"\n"; |
|
static const char *c_sw_file_head = |
"#include <stdlib.h>\n" |
"#include <string.h>\n" |
"\n" |
"#include \"config.h\"\n" |
"\n" |
"#include <inttypes.h>\n" |
"\n" |
"#include \"arch.h\"\n" |
"#include \"opcode/or32.h\"\n" |
"#include \"spr_defs.h\"\n" |
"#include \"i386_regs.h\"\n" |
"#include \"abstract.h\"\n" |
"#include \"dyn_rec.h\"\n" |
"#include \"%s\"\n" |
"\n" |
"void gen_code(struct op_queue *opq, struct dyn_page *dp)\n" |
"{\n" |
" unsigned int *ops, i;\n" |
" unsigned int host_len = dp->host_len;\n" |
" void *host_cur = dp->host_page;\n" |
" oraddr_t pc = dp->or_page;\n" |
" struct x_ref *next_x_ref = dp->xrefs;\n" |
"\n" |
" while(opq) {\n" |
" /* For now, only store offsets in the x-ref table */\n" |
" if(next_x_ref && (next_x_ref->or_addr == pc)) {\n" |
" next_x_ref->dyn_addr = (void *)(host_cur - dp->host_page);\n" |
" next_x_ref = next_x_ref->next;\n" |
" }\n" |
"\n" |
" /* Patch the dyn_addr of the xrefs for infinite loops */\n" |
" if(opq->jump_local == 2)\n" |
" opq->xref->dyn_addr = (void *)(host_cur - dp->host_page);\n" |
"\n" |
" for(i = 0, ops = opq->ops; i < opq->num_ops; i++, ops++) {\n" |
" switch(*ops) {\n"; |
|
static const char *c_sw_file_tail = |
" }\n" |
" }\n" |
" opq = opq->next;\n" |
" pc += 4;\n" |
" }\n" |
"\n" |
" dp->host_len = host_cur - dp->host_page;\n" |
" dp->host_page = realloc(dp->host_page, dp->host_len);\n" |
"}\n"; |
|
static const char *c_rel_file_head = |
"#include <stdio.h> /* To get printf... */\n" |
"#include <stdlib.h>\n" |
"\n" |
"#include \"config.h\"\n" |
"\n" |
"#include <inttypes.h>\n" |
"\n" |
"#include \"arch.h\"\n" |
"#include \"spr_defs.h\"\n" |
"#include \"i386_regs.h\"\n" |
"#include \"opcode/or32.h\"\n" |
"#include \"abstract.h\"\n" |
"#include \"tick.h\"\n" |
"#include \"execute.h\"\n" |
"#include \"sprs.h\"\n" |
"#include \"dyn_rec.h\"\n" |
"#include \"op_support.h\"\n" |
"#include \"%s\"\n" |
"\n" |
"void do_scheduler(void); /* FIXME: Remove */\n" |
"void analysis(struct iqueue_entry *current); /* FIXME: Remove */\n" |
"void do_sched_wrap(void); /* FIXME: Remove */\n" |
"void simprintf(oraddr_t stackaddr, unsigned long regparam); /* FIXME: Remove */\n" |
"\n" |
"void patch_relocs(struct op_queue *opq, void *host_page)\n" |
"{\n" |
" unsigned int *ops, *ops_param, i;\n" |
"\n" |
" while(opq) {\n" |
" for(i = 0, ops = opq->ops, ops_param = opq->ops_param; i < opq->num_ops; i++, ops++) {\n" |
" switch(*ops) {\n"; |
|
static const char *c_rel_file_tail = |
" }\n" |
" }\n" |
" opq = opq->next;\n" |
" }\n" |
"}\n"; |
|
static void gen_func_proto(FILE *f, const char *name, int *params) |
{ |
int i; |
|
fprintf(f, "void gen_%s(struct op_queue *opq, int end", name); |
for(i = 0; (i < MAX_PARAMS) && params[i]; i++) { |
fprintf(f, ", uorreg_t param%i", i + 1); |
} |
fprintf(f, ")"); |
} |
|
int main(int argc, char **argv) |
{ |
void *obj; |
int i, j; |
unsigned int len; |
char *name; |
int params[MAX_PARAMS]; |
struct reloc reloc; |
|
FILE *c_file; |
FILE *h_file; |
FILE *c_sw_file; |
FILE *c_rel_file; |
|
if(argc != 6) { |
fprintf(stderr, "Usage: %s <object file> <c file> <c file with gen_code()> <c file with patch_reloc()> <h file>\n", argv[0]); |
return 1; |
} |
|
obj = bffs.open_obj(argv[1]); |
if(!obj) { |
fprintf(stderr, "Unable to open object file %s\n", argv[1]); |
return 1; |
} |
|
if(!(c_file = fopen(argv[2], "w"))) { |
fprintf(stderr, "Unable to open %s for writting\n", argv[2]); |
bffs.close_obj(obj); |
return 1; |
} |
|
if(!(c_sw_file = fopen(argv[3], "w"))) { |
fprintf(stderr, "Unable to open %s for writting\n", argv[2]); |
fclose(c_file); |
bffs.close_obj(obj); |
} |
|
if(!(c_rel_file = fopen(argv[4], "w"))) { |
fprintf(stderr, "Unable to open %s for writting\n", argv[3]); |
fclose(c_file); |
fclose(c_sw_file); |
bffs.close_obj(obj); |
return 1; |
} |
|
if(!(h_file = fopen(argv[5], "w"))) { |
fprintf(stderr, "Unable to open %s for writting\n", argv[3]); |
fclose(c_file); |
fclose(c_sw_file); |
fclose(c_rel_file); |
bffs.close_obj(obj); |
return 1; |
} |
|
fprintf(c_file, c_file_head, argv[5]); |
fprintf(c_sw_file, c_sw_file_head, argv[5]); |
fprintf(c_rel_file, c_rel_file_head, argv[5]); |
fprintf(h_file, "%s", gen_code_proto); |
|
/* Itterate through the functions in the object file */ |
for(i = 0; (name = bffs.get_func_name(obj, i)); i++) { |
if(strncmp(name, OP_FUNC_PREFIX, strlen(OP_FUNC_PREFIX))) |
continue; |
|
/* Find all the relocations associated with this function */ |
memset(params, 0, sizeof(params)); |
for(j = 0; bffs.get_func_reloc(obj, i, j, &reloc); j++) { |
//fprintf(stderr, "%s %i %i\n", reloc.name, reloc.func_offset, reloc.addend); |
if(strncmp(reloc.name, OP_FUNC_PARAM_PREFIX, strlen(OP_FUNC_PARAM_PREFIX))) { |
continue; |
} |
params[atoi(reloc.name + strlen(OP_FUNC_PARAM_PREFIX)) - 1] = 1; |
} |
|
len = archfs.get_real_func_len(bffs.get_func_start(obj, i), |
bffs.get_func_len(obj, i), name); |
|
gen_func_proto(h_file, name, params); |
fprintf(h_file, ";\n"); |
|
if(len) { |
/* Prototype the operation */ |
fprintf(h_file, "void %s(void);\n", name); |
fprintf(h_file, "#define %s_indx %i\n", name, i); |
} |
|
gen_func_proto(c_file, name, params); |
fprintf(c_file, "\n{\n"); |
if(len) { |
fprintf(c_file, " add_to_opq(opq, end, %s_indx);\n", name); |
|
for(j = 0; params[j]; j++) |
fprintf(c_file, " add_to_op_params(opq, end, param%i);\n", j + 1); |
} |
fprintf(c_file, "}\n\n"); |
|
if(!len) { |
/* If the operation is of length 0, then just ignore it */ |
fprintf(stderr, "WARNING: Useless operation (size == 0): %s\n", name); |
continue; |
} |
|
fprintf(c_sw_file, " case %s_indx:\n", name); |
fprintf(c_sw_file, " host_cur = enough_host_page(dp, host_cur, &host_len, %i);\n", len); |
fprintf(c_sw_file, " memcpy(host_cur, %s, %i);\n", name, len); |
|
fprintf(c_rel_file, " case %s_indx:\n", name); |
for(j = 0; bffs.get_func_reloc(obj, i, j, &reloc); j++) { |
/* Ignore nameless relocations, they appear to be absolute */ |
if(!*reloc.name) |
continue; |
if(strncmp(reloc.name, OP_FUNC_PARAM_PREFIX, strlen(OP_FUNC_PARAM_PREFIX))) { |
/* We have to manually do the relocations when the relocation is |
* relative to the PC as the code gets copied to a different location |
* during recompilation, where the relative addresses shall be waay out. |
*/ |
archfs.gen_func_reloc(c_rel_file, &reloc); |
} else { |
archfs.gen_reloc(c_rel_file, &reloc, |
atoi(reloc.name + strlen(OP_FUNC_PARAM_PREFIX))); |
} |
} |
|
fprintf(c_sw_file, " host_cur += %i;\n break;\n\n", len); |
fprintf(c_rel_file, " host_page += %i;\n", len); |
/* Count how many parameters where used */ |
for(j = 0; params[j]; j++); |
fprintf(c_rel_file, " ops_param += %i;\n break;\n\n", j); |
} |
|
fprintf(c_sw_file, "%s", c_sw_file_tail); |
fprintf(c_rel_file, "%s", c_rel_file_tail); |
|
fclose(h_file); |
fclose(c_file); |
fclose(c_sw_file); |
fclose(c_rel_file); |
bffs.close_obj(obj); |
return 0; |
} |
/rec_i386.h
0,0 → 1,95
/* rec_i386.h -- i386 specific parts of the recompile engine |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
#include "common_i386.h" |
|
extern void *rec_stack_base; |
|
/* Sets the stack to a specified value */ |
static inline void or_longjmp(void *loc) __attribute__((noreturn)); |
static inline void or_longjmp(void *loc) |
{ |
/* We push a trampoline address (dyn_ret_stack_prot) onto the stack to be able |
* to detect if any ret instructions found their way into an operation. */ |
asm("\tmovl %0, %%eax\n" |
"\tmovl %1, %%esp\n" |
"\tmovl $%2, %%ebp\n" |
"\tpush $dyn_ret_stack_prot\n" |
"\tpush $dyn_ret_stack_prot\n" |
"\tpush $dyn_ret_stack_prot\n" |
"\tjmp *%%eax\n" |
: |
: "m" (loc), |
"m" (rec_stack_base), |
"m" (cpu_state)); |
} |
|
|
/* Initialises the recompiler (architechture specific). */ |
static inline void init_dyn_rec(void) |
{ |
uint64_t add = UINT32_C(-1) | UINT64_C(4) << 32; |
|
/* Initialises the scheduler handling for future use. Because the x86 has a |
* very low number of registers (8), I have to use MMX registers. I could do |
* load/store combination but that takes up space and is slow. I use packed |
* doublewords to strut my stuff. The high 32-bits of the first MMX register |
* is the PC, the low 32-bits is the number of cycles that are still |
* outstanding for the next scheduled job to run. The second MMX register |
* holds the amount that needs to be added to the two values on each cycle. |
* The third MMX register only holds the value that we must use to update the |
* low 32-bits with */ |
asm volatile ("movq %0, %%mm1\n" |
: : "m" (add)); |
} |
|
/* Gets the current stack pointer */ |
static inline void *get_sp(void) |
{ |
void *stack; |
asm("movl %%esp, %0" : "=rm" (stack)); |
return stack; |
} |
|
/* Updates the number of cycles that it takes to load 1 instruction */ |
static inline void upd_cycles_dec(int32_t amount) |
{ |
useless_x86.val3232.high32 = 4; |
useless_x86.val3232.low32 = amount; |
asm volatile ("movq %0, %%mm1" : : "m" (useless_x86.val64)); |
} |
|
/* Adds the number of cycles to the next job that would be added anyway */ |
static inline void sched_add_cycles(void) |
{ |
asm("movd %%mm1, %%eax\n" |
"\tmovd %%eax, %%mm2\n" |
"paddd %%mm2, %%mm0" |
: : : "eax"); |
} |
|
/* Adds an arbitary amount to the cycle counter */ |
static inline void add_to_cycles(int32_t val) |
{ |
val = -val; |
asm("movd %0, %%mm2\n" |
"paddd %%mm2, %%mm0\n" |
: : "rm" (val)); |
} |
/Makefile.am
0,0 → 1,69
# Makefile -- Makefile for OR32 dependent simulation |
# Copyright (C) 1999 Damjan Lampret, lampret@opencores.org |
# |
# This file is part of OpenRISC 1000 Architectural Simulator. |
# |
# This program is free software; you can redistribute it and/or modify |
# it under the terms of the GNU General Public License as published by |
# the Free Software Foundation; either version 2 of the License, or |
# (at your option) any later version. |
# |
# This program is distributed in the hope that it will be useful, |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
# 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, write to the Free Software |
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
# |
|
noinst_LIBRARIES = libarch.a |
|
if DYNAMIC_EXECUTION |
|
noinst_PROGRAMS = dyngen test_dyn_rec |
test_dyn_rec_SOURCES = op.c dyn_rec.c op_support.c gen_ops.c gen_ops_gen.c gen_ops_rel.c dyn_rec_stubs.c or32.c |
|
dyngen_SOURCES = dyngen.c dyngen_i386.c dyngen_elf.c |
|
libarch_a_SOURCES = execute.c or32.c op.c dyn_rec.c op_support.c gen_ops.c gen_ops_gen.c gen_ops_rel.c |
|
dyn_rec.o: gen_ops.h |
|
OP_CFLAGS=-Wall -fomit-frame-pointer -fno-reorder-blocks -O2 |
|
op.S: op.c op_i386.h op_arith_op.h op_comp_op.h op_extend_op.h op_ff1_op.h op_mac_op.h op_mftspr_op.h op_lwhb_op.h op_swhb_op.h |
$(CC) $(INCLUDES) $(OP_CFLAGS) -o $@ -S $< |
|
gen_ops.h gen_ops.c gen_ops_gen.c gen_ops_rel.c: dyngen op.o |
|
op.o: op.c op_i386.h op_arith_op.h op_comp_op.h op_extend_op.h op_ff1_op.h op_mac_op.h op_mftspr_op.h op_lwhb_op.h op_swhb_op.h |
$(CC) $(INCLUDES) $(OP_CFLAGS) -o $@ -c $< |
|
gen_ops.h gen_ops.c gen_ops_gen.c gen_ops_rel.c: dyngen op.o |
./dyngen op.o gen_ops.c gen_ops_gen.c gen_ops_rel.c gen_ops.h |
|
else |
|
libarch_a_SOURCES = execute.c or32.c |
|
if GENERATE_NEEDED |
noinst_PROGRAMS = generate |
generate_SOURCES = or32.c generate.c |
|
BUILT_SOURCES = execgen.c |
|
execgen.c: generate $(srcdir)/insnset.c |
./generate $(srcdir)/insnset.c execgen.c |
|
else |
|
noinst_PROGRAMS = |
|
endif |
endif |
|
# If the simulator was first built without --enable-simple and then with it, |
# then also remove these two files |
CLEANFILES=execgen.c generate |
/dyngen.h
0,0 → 1,45
/* dyngen.h -- Definitions for dyngen.c |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
struct reloc { |
unsigned int func_offset; |
unsigned int addend; |
int type; |
const char *name; |
}; |
|
struct bff { |
void *(*open_obj)(const char *object); /* Open the object file */ |
void (*close_obj)(void *); |
char *(*get_func_name)(void *, unsigned int func); /* Gets the name of func */ |
void *(*get_func_start)(void *, unsigned int func); |
unsigned int (*get_func_len)(void *, unsigned int func); |
int (*get_func_reloc)(void *, unsigned int func, unsigned int relocn, struct reloc *reloc); |
}; |
|
extern const struct bff bffs; |
|
struct archf { |
unsigned int (*get_real_func_len)(void *func, unsigned int len, char *name); |
void (*gen_reloc)(FILE *f, struct reloc *reloc, unsigned int param); |
void (*gen_func_reloc)(FILE *f, struct reloc *reloc); |
}; |
|
extern const struct archf archfs; |
/op_i386.h
0,0 → 1,57
/* op_i386.h -- i386 specific support routines for micro operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
#include "common_i386.h" |
|
#define OP_JUMP(x) asm("jmp *%0" : : "rm" (x)) |
|
#define FORCE_RET asm volatile ("") |
|
/* Handles the scheduler and PC updateing. Yes, useing MMX is a requirement. It |
* just won't change. This must be as compact as possible */ |
static inline void handle_sched(void) |
{ |
asm("paddd %%mm1, %%mm0\n" |
"\tmovd %%mm0, %%eax\n" |
"\ttestl %%eax, %%eax\n" |
"\tjg .no_need_run_sched\n" |
"\tcall do_sched_wrap\n" |
"\t.no_need_run_sched:" : : ); |
} |
|
static inline int32_t do_cycles(void) |
{ |
register uint32_t cycles; |
|
asm("paddd %%mm1, %%mm0\n" |
"\tmovd %%mm0, %0\n" |
: "=r" (cycles)); |
return cycles; |
} |
|
/* Joins runtime.sim.mem_cycles with the cycle counter */ |
static inline void join_mem_cycles(void) |
{ |
runtime.sim.mem_cycles = -runtime.sim.mem_cycles; |
asm volatile ("movd %0, %%mm2\n" |
"\tpaddd %%mm2, %%mm0" |
: : "m" (runtime.sim.mem_cycles)); |
runtime.sim.mem_cycles = 0; |
} |
|
/op_lwhb_op.h
0,0 → 1,118
/* op_lwhb_op.h -- Micro operations template for load operations |
|
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
/* FIXME: Do something if a breakpoint is hit */ |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _t0_t0)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t0 = LS_OP_CAST LS_OP_FUNC(t0 + OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _t0_t1)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t0 = LS_OP_CAST LS_OP_FUNC(t1 + OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _t0_t2)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t0 = LS_OP_CAST LS_OP_FUNC(t2 + OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _t1_t0)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t1 = LS_OP_CAST LS_OP_FUNC(t0 + OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _t1_t1)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t1 = LS_OP_CAST LS_OP_FUNC(t1 + OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _t1_t2)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t1 = LS_OP_CAST LS_OP_FUNC(t2 + OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _t2_t0)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t2 = LS_OP_CAST LS_OP_FUNC(t0 + OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _t2_t1)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t2 = LS_OP_CAST LS_OP_FUNC(t1 + OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _t2_t2)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t2 = LS_OP_CAST LS_OP_FUNC(t2 + OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _imm_t0)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t0 = LS_OP_CAST LS_OP_FUNC(OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _imm_t1)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t1 = LS_OP_CAST LS_OP_FUNC(OP_PARAM1, &breakpoint); |
} |
|
__or_dynop void glue(glue(op_, LS_OP_NAME), _imm_t2)(void) |
{ |
int breakpoint; |
upd_sim_cycles(); |
save_t_temporary(); |
t2 = LS_OP_CAST LS_OP_FUNC(OP_PARAM1, &breakpoint); |
} |
|
/simpl32_defs.h
0,0 → 1,95
/* simpl32_defs.h -- Definitions for the simple execution model |
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org |
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
extern void l_invalid PARAMS((struct iqueue_entry *)); |
extern void l_sfne PARAMS((struct iqueue_entry *)); |
extern void l_bf PARAMS((struct iqueue_entry *)); |
extern void l_add PARAMS((struct iqueue_entry *)); |
extern void l_addc PARAMS((struct iqueue_entry *)); |
extern void l_sw PARAMS((struct iqueue_entry *)); |
extern void l_sb PARAMS((struct iqueue_entry *)); |
extern void l_sh PARAMS((struct iqueue_entry *)); |
extern void l_lwz PARAMS((struct iqueue_entry *)); |
extern void l_lbs PARAMS((struct iqueue_entry *)); |
extern void l_lbz PARAMS((struct iqueue_entry *)); |
extern void l_lhs PARAMS((struct iqueue_entry *)); |
extern void l_lhz PARAMS((struct iqueue_entry *)); |
extern void l_movhi PARAMS((struct iqueue_entry *)); |
extern void l_and PARAMS((struct iqueue_entry *)); |
extern void l_or PARAMS((struct iqueue_entry *)); |
extern void l_xor PARAMS((struct iqueue_entry *)); |
extern void l_sub PARAMS((struct iqueue_entry *)); |
extern void l_mul PARAMS((struct iqueue_entry *)); |
extern void l_div PARAMS((struct iqueue_entry *)); |
extern void l_divu PARAMS((struct iqueue_entry *)); |
extern void l_sll PARAMS((struct iqueue_entry *)); |
extern void l_sra PARAMS((struct iqueue_entry *)); |
extern void l_srl PARAMS((struct iqueue_entry *)); |
extern void l_j PARAMS((struct iqueue_entry *)); |
extern void l_jal PARAMS((struct iqueue_entry *)); |
extern void l_jalr PARAMS((struct iqueue_entry *)); |
extern void l_jr PARAMS((struct iqueue_entry *)); |
extern void l_rfe PARAMS((struct iqueue_entry *)); |
extern void l_nop PARAMS((struct iqueue_entry *)); |
extern void l_bnf PARAMS((struct iqueue_entry *)); |
extern void l_sfeq PARAMS((struct iqueue_entry *)); |
extern void l_sfgts PARAMS((struct iqueue_entry *)); |
extern void l_sfges PARAMS((struct iqueue_entry *)); |
extern void l_sflts PARAMS((struct iqueue_entry *)); |
extern void l_sfles PARAMS((struct iqueue_entry *)); |
extern void l_sfgtu PARAMS((struct iqueue_entry *)); |
extern void l_sfgeu PARAMS()(struct iqueue_entry *); |
extern void l_sfltu PARAMS((struct iqueue_entry *)); |
extern void l_sfleu PARAMS((struct iqueue_entry *)); |
extern void l_extbs PARAMS((struct iqueue_entry *)); |
extern void l_extbz PARAMS((struct iqueue_entry *)); |
extern void l_exths PARAMS((struct iqueue_entry *)); |
extern void l_exthz PARAMS((struct iqueue_entry *)); |
extern void l_extws PARAMS((struct iqueue_entry *)); |
extern void l_extwz PARAMS((struct iqueue_entry *)); |
extern void l_mtspr PARAMS((struct iqueue_entry *)); |
extern void l_mfspr PARAMS((struct iqueue_entry *)); |
extern void l_sys PARAMS((struct iqueue_entry *)); |
extern void l_trap PARAMS((struct iqueue_entry *)); /* CZ 21/06/01 */ |
extern void l_macrc PARAMS((struct iqueue_entry *)); |
extern void l_mac PARAMS((struct iqueue_entry *)); |
extern void l_msb PARAMS((struct iqueue_entry *)); |
extern void l_invalid PARAMS((struct iqueue_entry *)); |
extern void l_cmov PARAMS ((struct iqueue_entry *)); |
extern void l_ff1 PARAMS ((struct iqueue_entry *)); |
extern void l_cust1 PARAMS ((struct iqueue_entry *)); |
extern void l_cust2 PARAMS ((struct iqueue_entry *)); |
extern void l_cust3 PARAMS ((struct iqueue_entry *)); |
extern void l_cust4 PARAMS ((struct iqueue_entry *)); |
extern void lf_add_s PARAMS ((struct iqueue_entry *)); |
extern void lf_div_s PARAMS ((struct iqueue_entry *)); |
extern void lf_ftoi_s PARAMS ((struct iqueue_entry *)); |
extern void lf_itof_s PARAMS ((struct iqueue_entry *)); |
extern void lf_madd_s PARAMS ((struct iqueue_entry *)); |
extern void lf_mul_s PARAMS ((struct iqueue_entry *)); |
extern void lf_rem_s PARAMS ((struct iqueue_entry *)); |
extern void lf_sfeq_s PARAMS ((struct iqueue_entry *)); |
extern void lf_sfge_s PARAMS ((struct iqueue_entry *)); |
extern void lf_sfgt_s PARAMS ((struct iqueue_entry *)); |
extern void lf_sfle_s PARAMS ((struct iqueue_entry *)); |
extern void lf_sflt_s PARAMS ((struct iqueue_entry *)); |
extern void lf_sfne_s PARAMS ((struct iqueue_entry *)); |
extern void lf_sub_s PARAMS((struct iqueue_entry *)); |
extern void l_none PARAMS((struct iqueue_entry *)); |
|
/insnset.c
0,0 → 1,567
/* execute.c -- Instruction specific functions. |
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org |
2000-2002 Marko Mlinar, markom@opencores.org |
|
This file is part of OpenRISC 1000 Architectural Simulator. |
|
This program is free software; you can redistribute it and/or modify |
it under the terms of the GNU General Public License as published by |
the Free Software Foundation; either version 2 of the License, or |
(at your option) any later version. |
|
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
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, write to the Free Software |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
INSTRUCTION (l_add) { |
orreg_t temp1, temp2, temp3; |
int8_t temp4; |
|
temp2 = (orreg_t)PARAM2; |
temp3 = (orreg_t)PARAM1; |
temp1 = temp2 + temp3; |
SET_PARAM0(temp1); |
set_ov_flag (temp1); |
if (ARITH_SET_FLAG) { |
flag = temp1 == 0; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
if ((uorreg_t) temp1 < (uorreg_t) temp2) |
setsprbits(SPR_SR, SPR_SR_CY, 1); |
else |
setsprbits(SPR_SR, SPR_SR_CY, 0); |
|
temp4 = temp1; |
if (temp4 == temp1) |
or1k_mstats.byteadd++; |
} |
INSTRUCTION (l_addc) { |
orreg_t temp1, temp2, temp3; |
int8_t temp4; |
|
temp2 = (orreg_t)PARAM2; |
temp3 = (orreg_t)PARAM1; |
temp1 = temp2 + temp3 + getsprbits(SPR_SR, SPR_SR_CY); |
SET_PARAM0(temp1); |
set_ov_flag (temp1); |
if (ARITH_SET_FLAG) { |
flag = temp1 == 0; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
if ((uorreg_t) temp1 < (uorreg_t) temp2) |
setsprbits(SPR_SR, SPR_SR_CY, 1); |
else |
setsprbits(SPR_SR, SPR_SR_CY, 0); |
|
temp4 = temp1; |
if (temp4 == temp1) |
or1k_mstats.byteadd++; |
} |
INSTRUCTION (l_sw) { |
int old_cyc = 0; |
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles; |
set_mem32(PARAM0, PARAM1, &breakpoint); |
if (config.cpu.sbuf_len) { |
int t = runtime.sim.mem_cycles; |
runtime.sim.mem_cycles = old_cyc; |
sbuf_store (t - old_cyc); |
} |
} |
INSTRUCTION (l_sb) { |
int old_cyc = 0; |
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles; |
set_mem8(PARAM0, PARAM1, &breakpoint); |
if (config.cpu.sbuf_len) { |
int t = runtime.sim.mem_cycles; |
runtime.sim.mem_cycles = old_cyc; |
sbuf_store (t- old_cyc); |
} |
} |
INSTRUCTION (l_sh) { |
int old_cyc = 0; |
if (config.cpu.sbuf_len) old_cyc = runtime.sim.mem_cycles; |
set_mem16(PARAM0, PARAM1, &breakpoint); |
if (config.cpu.sbuf_len) { |
int t = runtime.sim.mem_cycles; |
runtime.sim.mem_cycles = old_cyc; |
sbuf_store (t - old_cyc); |
} |
} |
INSTRUCTION (l_lwz) { |
uint32_t val; |
if (config.cpu.sbuf_len) sbuf_load (); |
val = eval_mem32(PARAM1, &breakpoint); |
/* If eval operand produced exception don't set anything */ |
if (!except_pending) |
SET_PARAM0(val); |
} |
INSTRUCTION (l_lbs) { |
int8_t val; |
if (config.cpu.sbuf_len) sbuf_load (); |
val = eval_mem8(PARAM1, &breakpoint); |
/* If eval opreand produced exception don't set anything */ |
if (!except_pending) |
SET_PARAM0(val); |
} |
INSTRUCTION (l_lbz) { |
uint8_t val; |
if (config.cpu.sbuf_len) sbuf_load (); |
val = eval_mem8(PARAM1, &breakpoint); |
/* If eval opreand produced exception don't set anything */ |
if (!except_pending) |
SET_PARAM0(val); |
} |
INSTRUCTION (l_lhs) { |
int16_t val; |
if (config.cpu.sbuf_len) sbuf_load (); |
val = eval_mem16(PARAM1, &breakpoint); |
/* If eval opreand produced exception don't set anything */ |
if (!except_pending) |
SET_PARAM0(val); |
} |
INSTRUCTION (l_lhz) { |
uint16_t val; |
if (config.cpu.sbuf_len) sbuf_load (); |
val = eval_mem16(PARAM1, &breakpoint); |
/* If eval opreand produced exception don't set anything */ |
if (!except_pending) |
SET_PARAM0(val); |
} |
INSTRUCTION (l_movhi) { |
SET_PARAM0(PARAM1 << 16); |
} |
INSTRUCTION (l_and) { |
uorreg_t temp1; |
temp1 = PARAM1 & PARAM2; |
set_ov_flag (temp1); |
SET_PARAM0(temp1); |
if (ARITH_SET_FLAG) { |
flag = temp1 == 0; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
} |
INSTRUCTION (l_or) { |
uorreg_t temp1; |
temp1 = PARAM1 | PARAM2; |
set_ov_flag (temp1); |
SET_PARAM0(temp1); |
} |
INSTRUCTION (l_xor) { |
uorreg_t temp1; |
temp1 = PARAM1 ^ PARAM2; |
set_ov_flag (temp1); |
SET_PARAM0(temp1); |
} |
INSTRUCTION (l_sub) { |
orreg_t temp1; |
temp1 = (orreg_t)PARAM1 - (orreg_t)PARAM2; |
set_ov_flag (temp1); |
SET_PARAM0(temp1); |
} |
/*int mcount = 0;*/ |
INSTRUCTION (l_mul) { |
orreg_t temp1; |
|
temp1 = (orreg_t)PARAM1 * (orreg_t)PARAM2; |
set_ov_flag (temp1); |
SET_PARAM0(temp1); |
/*if (!(mcount++ & 1023)) { |
PRINTF ("[%i]\n",mcount); |
}*/ |
} |
INSTRUCTION (l_div) { |
orreg_t temp3, temp2, temp1; |
|
temp3 = PARAM2; |
temp2 = PARAM1; |
if (temp3) |
temp1 = temp2 / temp3; |
else { |
except_handle(EXCEPT_ILLEGAL, cpu_state.pc); |
return; |
} |
set_ov_flag (temp1); |
SET_PARAM0(temp1); |
} |
INSTRUCTION (l_divu) { |
uorreg_t temp3, temp2, temp1; |
|
temp3 = PARAM2; |
temp2 = PARAM1; |
if (temp3) |
temp1 = temp2 / temp3; |
else { |
except_handle(EXCEPT_ILLEGAL, cpu_state.pc); |
return; |
} |
set_ov_flag (temp1); |
SET_PARAM0(temp1); |
/* runtime.sim.cycles += 16; */ |
} |
INSTRUCTION (l_sll) { |
uorreg_t temp1; |
|
temp1 = PARAM1 << PARAM2; |
set_ov_flag (temp1); |
SET_PARAM0(temp1); |
/* runtime.sim.cycles += 2; */ |
} |
INSTRUCTION (l_sra) { |
orreg_t temp1; |
|
temp1 = (orreg_t)PARAM1 >> PARAM2; |
set_ov_flag (temp1); |
SET_PARAM0(temp1); |
/* runtime.sim.cycles += 2; */ |
} |
INSTRUCTION (l_srl) { |
uorreg_t temp1; |
temp1 = PARAM1 >> PARAM2; |
set_ov_flag (temp1); |
SET_PARAM0(temp1); |
/* runtime.sim.cycles += 2; */ |
} |
INSTRUCTION (l_bf) { |
if (config.bpb.enabled) { |
int fwd = (PARAM0 >= cpu_state.pc) ? 1 : 0; |
or1k_mstats.bf[flag][fwd]++; |
bpb_update(current->insn_addr, flag); |
} |
if (flag) { |
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4; |
btic_update(pcnext); |
next_delay_insn = 1; |
} else { |
btic_update(cpu_state.pc); |
} |
} |
INSTRUCTION (l_bnf) { |
if (config.bpb.enabled) { |
int fwd = (PARAM0 >= cpu_state.pc) ? 1 : 0; |
or1k_mstats.bnf[!flag][fwd]++; |
bpb_update(current->insn_addr, flag == 0); |
} |
if (flag == 0) { |
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4; |
btic_update(pcnext); |
next_delay_insn = 1; |
} else { |
btic_update(cpu_state.pc); |
} |
} |
INSTRUCTION (l_j) { |
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4; |
next_delay_insn = 1; |
} |
INSTRUCTION (l_jal) { |
cpu_state.pc_delay = cpu_state.pc + (orreg_t)PARAM0 * 4; |
|
set_reg(LINK_REGNO, cpu_state.pc + 8); |
next_delay_insn = 1; |
if (config.sim.profile) { |
struct label_entry *tmp; |
if (verify_memoryarea(cpu_state.pc_delay) && (tmp = get_label (cpu_state.pc_delay))) |
fprintf (runtime.sim.fprof, "+%08llX %"PRIxADDR" %"PRIxADDR" %s\n", |
runtime.sim.cycles, cpu_state.pc + 8, cpu_state.pc_delay, |
tmp->name); |
else |
fprintf (runtime.sim.fprof, "+%08llX %"PRIxADDR" %"PRIxADDR" @%"PRIxADDR"\n", |
runtime.sim.cycles, cpu_state.pc + 8, cpu_state.pc_delay, |
cpu_state.pc_delay); |
} |
} |
INSTRUCTION (l_jalr) { |
cpu_state.pc_delay = PARAM0; |
set_reg(LINK_REGNO, cpu_state.pc + 8); |
next_delay_insn = 1; |
} |
INSTRUCTION (l_jr) { |
cpu_state.pc_delay = PARAM0; |
next_delay_insn = 1; |
if (config.sim.profile) |
fprintf (runtime.sim.fprof, "-%08llX %"PRIxADDR"\n", runtime.sim.cycles, |
cpu_state.pc_delay); |
} |
INSTRUCTION (l_rfe) { |
pcnext = mfspr(SPR_EPCR_BASE); |
mtspr(SPR_SR, mfspr(SPR_ESR_BASE)); |
} |
INSTRUCTION (l_nop) { |
oraddr_t stackaddr; |
uint32_t k = PARAM0; |
switch (k) { |
case NOP_NOP: |
break; |
case NOP_EXIT: |
PRINTF("exit(%"PRIdREG")\n", evalsim_reg (3)); |
fprintf(stderr, "@reset : cycles %lld, insn #%lld\n", |
runtime.sim.reset_cycles, runtime.cpu.reset_instructions); |
fprintf(stderr, "@exit : cycles %lld, insn #%lld\n", runtime.sim.cycles, |
runtime.cpu.instructions); |
fprintf(stderr, " diff : cycles %lld, insn #%lld\n", |
runtime.sim.cycles - runtime.sim.reset_cycles, |
runtime.cpu.instructions - runtime.cpu.reset_instructions); |
if (config.debug.gdb_enabled) |
set_stall_state (1); |
else |
runtime.sim.cont_run = 0; |
break; |
case NOP_CNT_RESET: |
PRINTF("****************** counters reset ******************\n"); |
PRINTF("cycles %lld, insn #%lld\n", runtime.sim.cycles, runtime.cpu.instructions); |
PRINTF("****************** counters reset ******************\n"); |
runtime.sim.reset_cycles = runtime.sim.cycles; |
runtime.cpu.reset_instructions = runtime.cpu.instructions; |
break; |
case NOP_PRINTF: |
stackaddr = evalsim_reg(4); |
simprintf(stackaddr, evalsim_reg(3)); |
debug(5, "simprintf %x\n", stackaddr); |
break; |
case NOP_REPORT: |
PRINTF("report(0x%"PRIxREG");\n", evalsim_reg(3)); |
default: |
if (k >= NOP_REPORT_FIRST && k <= NOP_REPORT_LAST) |
PRINTF("report %i (0x%"PRIxREG");\n", k - NOP_REPORT_FIRST, |
evalsim_reg(3)); |
break; |
} |
} |
INSTRUCTION (l_sfeq) { |
flag = PARAM0 == PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (l_sfne) { |
flag = PARAM0 != PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (l_sfgts) { |
flag = (orreg_t)PARAM0 > (orreg_t)PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (l_sfges) { |
flag = (orreg_t)PARAM0 >= (orreg_t)PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (l_sflts) { |
flag = (orreg_t)PARAM0 < (orreg_t)PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (l_sfles) { |
flag = (orreg_t)PARAM0 <= (orreg_t)PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (l_sfgtu) { |
flag = PARAM0 > PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (l_sfgeu) { |
flag = PARAM0 >= PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (l_sfltu) { |
flag = PARAM0 < PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (l_sfleu) { |
flag = PARAM0 <= PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (l_extbs) { |
int8_t x; |
x = PARAM1; |
SET_PARAM0((orreg_t)x); |
} |
INSTRUCTION (l_extbz) { |
uint8_t x; |
x = PARAM1; |
SET_PARAM0((uorreg_t)x); |
} |
INSTRUCTION (l_exths) { |
int16_t x; |
x = PARAM1; |
SET_PARAM0((orreg_t)x); |
} |
INSTRUCTION (l_exthz) { |
uint16_t x; |
x = PARAM1; |
SET_PARAM0((uorreg_t)x); |
} |
INSTRUCTION (l_extws) { |
int32_t x; |
x = PARAM1; |
SET_PARAM0((orreg_t)x); |
} |
INSTRUCTION (l_extwz) { |
uint32_t x; |
x = PARAM1; |
SET_PARAM0((uorreg_t)x); |
} |
INSTRUCTION (l_mtspr) { |
uint16_t regno = PARAM0 + PARAM2; |
uorreg_t value = PARAM1; |
|
if (runtime.sim.fspr_log) { |
fprintf(runtime.sim.fspr_log, "Write to SPR : [%08"PRIx16"] <- [%08"PRIx32"]\n", regno, value); |
} |
|
if (mfspr(SPR_SR) & SPR_SR_SM) |
mtspr(regno, value); |
else { |
PRINTF("WARNING: trying to write SPR while SR[SUPV] is cleared.\n"); |
runtime.sim.cont_run = 0; |
} |
} |
INSTRUCTION (l_mfspr) { |
uint16_t regno = PARAM1 + PARAM2; |
uorreg_t value = mfspr(regno); |
|
if (runtime.sim.fspr_log) { |
fprintf(runtime.sim.fspr_log, "Read from SPR : [%08"PRIx16"] -> [%08"PRIx32"]\n", regno, value); |
} |
|
if (mfspr(SPR_SR) & SPR_SR_SM) |
SET_PARAM0(value); |
else { |
SET_PARAM0(0); |
PRINTF("WARNING: trying to read SPR while SR[SUPV] is cleared.\n"); |
runtime.sim.cont_run = 0; |
} |
} |
INSTRUCTION (l_sys) { |
except_handle(EXCEPT_SYSCALL, mfspr(SPR_EEAR_BASE)); |
} |
INSTRUCTION (l_trap) { |
/* TODO: some SR related code here! */ |
except_handle(EXCEPT_TRAP, mfspr(SPR_EEAR_BASE)); |
} |
INSTRUCTION (l_mac) { |
sprword lo, hi; |
LONGEST l; |
orreg_t x, y; |
|
lo = mfspr (SPR_MACLO); |
hi = mfspr (SPR_MACHI); |
x = PARAM0; |
y = PARAM1; |
PRINTF ("[%"PRIxREG",%"PRIxREG"]\t", x, y); |
l = (ULONGEST)lo | ((LONGEST)hi << 32); |
l += (LONGEST) x * (LONGEST) y; |
|
/* This implementation is very fast - it needs only one cycle for mac. */ |
lo = ((ULONGEST)l) & 0xFFFFFFFF; |
hi = ((LONGEST)l) >> 32; |
mtspr (SPR_MACLO, lo); |
mtspr (SPR_MACHI, hi); |
PRINTF ("(%08lx,%08lx)\n", hi, lo); |
} |
INSTRUCTION (l_msb) { |
sprword lo, hi; |
LONGEST l; |
orreg_t x, y; |
|
lo = mfspr (SPR_MACLO); |
hi = mfspr (SPR_MACHI); |
x = PARAM0; |
y = PARAM1; |
|
PRINTF ("[%"PRIxREG",%"PRIxREG"]\t", x, y); |
|
l = (ULONGEST)lo | ((LONGEST)hi << 32); |
l -= x * y; |
|
/* This implementation is very fast - it needs only one cycle for msb. */ |
lo = ((ULONGEST)l) & 0xFFFFFFFF; |
hi = ((LONGEST)l) >> 32; |
mtspr (SPR_MACLO, lo); |
mtspr (SPR_MACHI, hi); |
PRINTF ("(%08lx,%08lx)\n", hi, lo); |
} |
INSTRUCTION (l_macrc) { |
sprword lo, hi; |
LONGEST l; |
/* No need for synchronization here -- all MAC instructions are 1 cycle long. */ |
lo = mfspr (SPR_MACLO); |
hi = mfspr (SPR_MACHI); |
l = (ULONGEST) lo | ((LONGEST)hi << 32); |
l >>= 28; |
//PRINTF ("<%08x>\n", (unsigned long)l); |
SET_PARAM0((orreg_t)l); |
mtspr (SPR_MACLO, 0); |
mtspr (SPR_MACHI, 0); |
} |
INSTRUCTION (l_cmov) { |
SET_PARAM0(flag ? PARAM1 : PARAM2); |
} |
INSTRUCTION (l_ff1) { |
SET_PARAM0(ffs(PARAM1)); |
} |
/******* Floating point instructions *******/ |
/* Single precision */ |
INSTRUCTION (lf_add_s) { |
SET_PARAM0((float)PARAM1 + (float)PARAM2); |
} |
INSTRUCTION (lf_div_s) { |
SET_PARAM0((float)PARAM1 / (float)PARAM2); |
} |
INSTRUCTION (lf_ftoi_s) { |
// set_operand32(0, freg[get_operand(1)], &breakpoint); |
} |
INSTRUCTION (lf_itof_s) { |
// freg[get_operand(0)] = eval_operand32(1, &breakpoint); |
} |
INSTRUCTION (lf_madd_s) { |
SET_PARAM0((float)PARAM0 + (float)PARAM1 * (float)PARAM2); |
} |
INSTRUCTION (lf_mul_s) { |
SET_PARAM0((float)PARAM1 * (float)PARAM2); |
} |
INSTRUCTION (lf_rem_s) { |
float temp = (float)PARAM1 / (float)PARAM2; |
SET_PARAM0(temp - (uint32_t)temp); |
} |
INSTRUCTION (lf_sfeq_s) { |
flag = (float)PARAM0 == (float)PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (lf_sfge_s) { |
flag = (float)PARAM0 >= (float)PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (lf_sfgt_s) { |
flag = (float)PARAM0 > (float)PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (lf_sfle_s) { |
flag = (float)PARAM0 <= (float)PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (lf_sflt_s) { |
flag = (float)PARAM0 < (float)PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (lf_sfne_s) { |
flag = (float)PARAM0 != (float)PARAM1; |
setsprbits(SPR_SR, SPR_SR_F, flag); |
} |
INSTRUCTION (lf_sub_s) { |
SET_PARAM0((float)PARAM1 - (float)PARAM2); |
} |
|
/******* Custom instructions *******/ |
INSTRUCTION (l_cust1) { |
/*int destr = current->insn >> 21; |
int src1r = current->insn >> 15; |
int src2r = current->insn >> 9;*/ |
} |
INSTRUCTION (l_cust2) { |
} |
INSTRUCTION (l_cust3) { |
} |
INSTRUCTION (l_cust4) { |
} |
insnset.c
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: generate.c
===================================================================
--- generate.c (nonexistent)
+++ generate.c (revision 1765)
@@ -0,0 +1,392 @@
+/* generate.c -- generates file execgen.c from instruction set
+ Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
+ Copyright (C) 2005 György `nog' Jeney, nog@sdf.lonestar.org
+
+This file is part of OpenRISC 1000 Architectural Simulator.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+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, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include
+#include
+#include
+#include
+#include
+
+#include "config.h"
+#include "opcode/or32.h"
+
+static char *in_file;
+static char *out_file;
+
+/* Whether this instruction stores something in register */
+static int write_to_reg;
+
+static int out_lines = 0;
+
+void debug(int level, const char *format, ...)
+{
+#if DEBUG
+ char *p;
+ va_list ap;
+
+ if ((p = malloc(1000)) == NULL)
+ return;
+ va_start(ap, format);
+ (void) vsnprintf(p, 1000, format, ap);
+ va_end(ap);
+ printf("%s\n", p);
+ fflush(stdout);
+ free(p);
+#endif
+}
+
+static int shift_fprintf(int level, FILE *f, const char *fmt, ...)
+{
+ va_list ap;
+ int i;
+
+ va_start(ap, fmt);
+ for(i = 0; i < level; i++)
+ fprintf(f, " ");
+
+ i = vfprintf(f, fmt, ap);
+ va_end(ap);
+
+ out_lines++;
+ return i + (level * 2);
+}
+
+/* Generates a execute sequence for one instruction */
+int output_function (FILE *fo, const char *func_name, int level)
+{
+ FILE *fi;
+ int olevel;
+ int line_num = 0;
+
+ if ((fi = fopen (in_file, "rt")) == NULL) {
+ printf("could not open file\n");
+ return 1;
+ }
+
+ while (!feof (fi)) {
+ char line[10000], *str = line;
+ fgets (str, sizeof (line), fi);
+ line[sizeof (line) - 1] = 0;
+ line_num++;
+ if (strncmp (str, "INSTRUCTION (", 13) == 0) {
+ char *s;
+ str += 13;
+ while (isspace (*str)) str++;
+ s = str;
+ while (*s && *s != ')') s++;
+ *s = 0;
+ while (isspace(*(s - 1))) s--;
+ *s = 0;
+ if (strcmp (str, func_name) == 0) {
+ olevel = 1;
+ str += strlen (str) + 1;
+ while (isspace (*str)) str++;
+ s = str;
+ while (*s && *s != '\n' && *s != '\r') s++;
+ *s = 0;
+ while (isspace(*(s - 1))) s--;
+ *s = 0;
+ /*shift_fprintf (level, fo, "#line %i \"%s\"\n", line_num, in_file);*/
+ shift_fprintf (level, fo, "%s", str);
+ shift_fprintf (level, fo, " /* \"%s\" */\n", func_name);
+ do {
+ fgets (line, sizeof (line), fi);
+ line[sizeof(line) - 1] = 0;
+ for (str = line; *str; str++) {
+ if (*str == '{') olevel++;
+ else if (*str == '}') olevel--;
+ }
+ shift_fprintf (level, fo, "%s", line);
+ } while (olevel);
+ fclose(fi);
+ /*shift_fprintf (level, fo, "#line %i \"%s\"\n", out_lines, out_file);*/
+ return 0;
+ }
+ }
+ }
+ shift_fprintf (level, fo, "%s ();\n", func_name);
+
+ fclose(fi);
+ return 0;
+}
+
+/* Parses operands. */
+
+static int
+gen_eval_operands (FILE *fo, int insn_index, int level)
+{
+ struct insn_op_struct *opd = op_start[insn_index];
+ int i;
+ int num_ops;
+ int nbits = 0;
+ int set_param = 0;
+ int dis = 0;
+ int sbit;
+ int dis_op = -1;
+
+ write_to_reg = 0;
+
+ shift_fprintf (level, fo, "uorreg_t ");
+
+ /* Count number of operands */
+ for (i = 0, num_ops = 0;; i++) {
+ if (!(opd[i].type & OPTYPE_OP))
+ continue;
+ if (opd[i].type & OPTYPE_DIS)
+ continue;
+ if (num_ops)
+ fprintf(fo, ", ");
+ fprintf(fo, "%c", 'a' + num_ops);
+ num_ops++;
+ if (opd[i].type & OPTYPE_LAST)
+ break;
+ }
+
+ fprintf (fo, ";\n");
+
+ shift_fprintf (level, fo, "/* Number of operands: %i */\n", num_ops);
+
+ i = 0;
+ num_ops = 0;
+ do {
+/*
+ printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_LAST ? '1' : '0'); printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_OP ? '1' : '0');
+ printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_REG ? '1' : '0');
+ printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_SIG ? '1' : '0');
+ printf("opd[%i].type = %c\n", i, opd->type & OPTYPE_DIS ? '1' : '0');
+ printf("opd[%i].type = %i\n", i, opd->type & OPTYPE_SHR);
+ printf("opd[%i].type = %i\n", i, (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR);
+ printf("opd[%i].data = %i\n", i, opd->data);
+*/
+
+ if (!nbits)
+ shift_fprintf (level, fo, "%c = (insn >> %i) & 0x%x;\n", 'a' + num_ops,
+ opd->type & OPTYPE_SHR, (1 << opd->data) - 1);
+ else
+ shift_fprintf (level, fo, "%c |= ((insn >> %i) & 0x%x) << %i;\n",
+ 'a' + num_ops, opd->type & OPTYPE_SHR,
+ (1 << opd->data) - 1, nbits);
+
+ nbits += opd->data;
+
+ if ((opd->type & OPTYPE_DIS) && (opd->type & OPTYPE_OP)) {
+ sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR;
+ if (opd->type & OPTYPE_SIG)
+ shift_fprintf (level, fo, "if(%c & 0x%08x) %c |= 0x%x;\n",
+ 'a' + num_ops, 1 << sbit, 'a' + num_ops,
+ 0xffffffff << sbit);
+ opd++;
+ shift_fprintf (level, fo, "(signed)%c += (signed)cpu_state.reg[(insn >> %i) & 0x%x];\n",
+ 'a' + num_ops, opd->type & OPTYPE_SHR,
+ (1 << opd->data) - 1);
+ dis = 1;
+ dis_op = num_ops;
+ }
+
+ if (opd->type & OPTYPE_OP) {
+ sbit = (opd->type & OPTYPE_SBIT) >> OPTYPE_SBIT_SHR;
+ if (opd->type & OPTYPE_SIG)
+ shift_fprintf (level, fo, "if(%c & 0x%08x) %c |= 0x%x;\n",
+ 'a' + num_ops, 1 << sbit, 'a' + num_ops,
+ 0xffffffff << sbit);
+ if ((opd->type & OPTYPE_REG) && !dis) {
+ if(!i) {
+ shift_fprintf (level, fo, "#define SET_PARAM0(val) cpu_state.reg[a] = val\n");
+ set_param = 1;
+ }
+ shift_fprintf (level, fo, "#define PARAM%i cpu_state.reg[%c]\n", num_ops,
+ 'a' + num_ops);
+ if(opd->type & OPTYPE_DST)
+ write_to_reg = 1;
+ } else {
+ shift_fprintf (level, fo, "#define PARAM%i %c\n", num_ops,
+ 'a' + num_ops);
+ }
+ num_ops++;
+ nbits = 0;
+ dis = 0;
+ }
+
+ if ((opd->type & OPTYPE_LAST))
+ break;
+ opd++;
+ i++;
+ } while (1);
+
+ output_function (fo, or32_opcodes[insn_index].function_name, level);
+
+ if (set_param)
+ shift_fprintf (level, fo, "#undef SET_PARAM\n");
+
+ for (i = 0; i < num_ops; i++)
+ shift_fprintf (level, fo, "#undef PARAM%i\n", i);
+
+ return dis_op;
+}
+
+/* Generates decode and execute for one instruction instance */
+static int output_call (FILE *fo, int index, int level)
+{
+ int dis_op = -1;
+
+ /*printf ("%i:%s\n", index, insn_name (index));*/
+
+ shift_fprintf (level++, fo, "{\n");
+
+ if (index >= 0)
+ dis_op = gen_eval_operands (fo, index, level);
+
+ if (index < 0) output_function (fo, "l_invalid", level);
+
+ fprintf (fo, "\n");
+
+ shift_fprintf (level++, fo, "if (do_stats) {\n");
+
+ if (dis_op >= 0)
+ shift_fprintf (level, fo, "cpu_state.insn_ea = %c;\n", 'a' + dis_op);
+
+ shift_fprintf (level, fo, "current->insn_index = %i; /* \"%s\" */\n", index,
+ insn_name (index));
+
+ shift_fprintf (level, fo, "analysis(current);\n");
+ shift_fprintf (--level, fo, "}\n");
+
+ if (write_to_reg)
+ shift_fprintf (level, fo, "cpu_state.reg[0] = 0; /* Repair in case we changed it */\n");
+ shift_fprintf (--level, fo, "}\n");
+ return 0;
+}
+
+/* Generates .c file header */
+static int generate_header (FILE *fo)
+{
+ fprintf (fo, "/* This file was automatically generated by generate (see cpu/or32/generate.c) */\n\n");
+ fprintf (fo, "static inline void decode_execute (struct iqueue_entry *current)\n{\n");
+ fprintf (fo, " uint32_t insn = current->insn;\n");
+ out_lines = 5;
+ return 0;
+}
+
+/* Generates .c file footer */
+static int generate_footer (FILE *fo)
+{
+ fprintf (fo, "}\n");
+ return 0;
+}
+
+/* Decodes all instructions and generates code for that. This function
+ is similar to insn_decode, except it decodes all instructions. */
+static int generate_body (FILE *fo, unsigned long *a, unsigned long cur_mask, int level)
+{
+ unsigned long shift = *a;
+ unsigned long mask;
+ int i;
+ int prev_inv = 0;
+
+ if (!(*a & LEAF_FLAG)) {
+ shift = *a++;
+ mask = *a++;
+ shift_fprintf (level, fo, "switch((insn >> %i) & 0x%x) {\n", shift,
+ mask);
+ for (i = 0; i <= mask; i++, a++) {
+ if (!*a) {
+ shift_fprintf (level, fo, "case 0x%x:\n", i);
+ prev_inv = 1;
+ } else {
+ if(prev_inv) {
+ shift_fprintf (++level, fo, "/* Invalid instruction(s) */\n");
+ shift_fprintf (level--, fo, "break;\n");
+ }
+ shift_fprintf (level, fo, "case 0x%x:\n", i);
+ generate_body (fo, automata + *a, cur_mask | (mask << shift), ++level);
+ shift_fprintf (level--, fo, "break;\n");
+ prev_inv = 0;
+ }
+ }
+ if (prev_inv) {
+ shift_fprintf (++level, fo, "/* Invalid instruction(s) */\n");
+ shift_fprintf (level--, fo, "break;\n");
+ }
+ shift_fprintf (level, fo, "}\n");
+ } else {
+ i = *a & ~LEAF_FLAG;
+
+ /* Final check - do we have direct match?
+ (based on or32_opcodes this should be the only possibility,
+ but in case of invalid/missing instruction we must perform a check) */
+
+ if (ti[i].insn_mask != cur_mask) {
+ shift_fprintf (level, fo, "/* Not unique: real mask %08lx and current mask %08lx differ - do final check */\n", ti[i].insn_mask, cur_mask);
+ shift_fprintf (level++, fo, "if((insn & 0x%x) == 0x%x) {\n",
+ ti[i].insn_mask, ti[i].insn);
+ }
+ shift_fprintf (level, fo, "/* Instruction: %s */\n", or32_opcodes[i].name);
+
+ output_call (fo, i, level);
+
+ if (ti[i].insn_mask != cur_mask) {
+ shift_fprintf (--level, fo, "} else {\n");
+ shift_fprintf (++level, fo, "/* Invalid insn */\n");
+ output_call (fo, -1, level);
+ shift_fprintf (--level, fo, "}\n");
+ }
+ }
+ return 0;
+}
+
+/* Main function; it takes two parameters:
+ input_file(possibly insnset.c) output_file(possibly execgen.c)*/
+int main (int argc, char *argv[])
+{
+ FILE *fo;
+
+ if (argc != 3) {
+ fprintf (stderr, "USAGE: generate input_file(possibly insnset.c) output_file(possibly execgen.c)\n");
+ exit (-1);
+ }
+
+ in_file = argv[1];
+ out_file = argv[2];
+ if (!(fo = fopen (argv[2], "wt+"))) {
+ fprintf (stderr, "Cannot create '%s'.\n", argv[2]);
+ exit (1);
+ }
+
+ build_automata ();
+ if (generate_header (fo)) {
+ fprintf (stderr, "generate_header\n");
+ return 1;
+ }
+
+ if (generate_body (fo, automata, 0, 1)) {
+ fprintf (stderr, "generate_body\n");
+ return 1;
+ }
+
+ if (generate_footer (fo)) {
+ fprintf (stderr, "generate_footer\n");
+ return 1;
+ }
+
+ fclose (fo);
+ destruct_automata ();
+ return 0;
+}
+
generate.c
Property changes :
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: Makefile.in
===================================================================
--- Makefile.in (nonexistent)
+++ Makefile.in (revision 1765)
@@ -0,0 +1,368 @@
+# Makefile.in generated by automake 1.6.3 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile -- Makefile for OR32 dependent simulation
+# Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
+#
+# This file is part of OpenRISC 1000 Architectural Simulator.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# 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, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ../..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+
+EXEEXT = @EXEEXT@
+OBJEXT = @OBJEXT@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+AMTAR = @AMTAR@
+AR = @AR@
+ARFLAGS = @ARFLAGS@
+AWK = @AWK@
+BUILD_DIR = @BUILD_DIR@
+CC = @CC@
+CFLAGS = @CFLAGS@
+CPU_ARCH = @CPU_ARCH@
+DEPDIR = @DEPDIR@
+INCLUDES = @INCLUDES@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LOCAL_CFLAGS = @LOCAL_CFLAGS@
+LOCAL_DEFS = @LOCAL_DEFS@
+MAKE_SHELL = @MAKE_SHELL@
+PACKAGE = @PACKAGE@
+RANLIB = @RANLIB@
+STRIP = @STRIP@
+SUMVERSION = @SUMVERSION@
+TERMCAP_LIB = @TERMCAP_LIB@
+VERSION = @VERSION@
+am__include = @am__include@
+am__quote = @am__quote@
+host = @host@
+host_cpu = @host_cpu@
+host_os = @host_os@
+install_sh = @install_sh@
+
+noinst_LIBRARIES = libarch.a
+libarch_a_SOURCES = execute.c or32.c
+
+@SIMPLE_EXECUTION_TRUE@noinst_PROGRAMS =
+@SIMPLE_EXECUTION_FALSE@noinst_PROGRAMS = generate
+@SIMPLE_EXECUTION_TRUE@generate_SOURCES =
+@SIMPLE_EXECUTION_FALSE@generate_SOURCES = or32.c generate.c
+@SIMPLE_EXECUTION_FALSE@BUILT_SOURCES = execgen.c
+
+# If the simulator was first built without --enable-simple and then with it,
+# then also remove these two files
+CLEANFILES = execgen.c generate
+subdir = cpu/or32
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libarch_a_AR = $(AR) cru
+libarch_a_LIBADD =
+am_libarch_a_OBJECTS = execute.$(OBJEXT) or32.$(OBJEXT)
+libarch_a_OBJECTS = $(am_libarch_a_OBJECTS)
+@SIMPLE_EXECUTION_TRUE@noinst_PROGRAMS =
+@SIMPLE_EXECUTION_FALSE@noinst_PROGRAMS = generate$(EXEEXT)
+PROGRAMS = $(noinst_PROGRAMS)
+
+@SIMPLE_EXECUTION_TRUE@am_generate_OBJECTS =
+@SIMPLE_EXECUTION_FALSE@am_generate_OBJECTS = or32.$(OBJEXT) \
+@SIMPLE_EXECUTION_FALSE@ generate.$(OBJEXT)
+generate_OBJECTS = $(am_generate_OBJECTS)
+generate_LDADD = $(LDADD)
+generate_DEPENDENCIES =
+generate_LDFLAGS =
+
+DEFS = @DEFS@
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/execute.Po ./$(DEPDIR)/generate.Po \
+@AMDEP_TRUE@ ./$(DEPDIR)/or32.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libarch_a_SOURCES) $(generate_SOURCES)
+DIST_COMMON = Makefile.am Makefile.in
+SOURCES = $(libarch_a_SOURCES) $(generate_SOURCES)
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu cpu/or32/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libarch.a: $(libarch_a_OBJECTS) $(libarch_a_DEPENDENCIES)
+ -rm -f libarch.a
+ $(libarch_a_AR) libarch.a $(libarch_a_OBJECTS) $(libarch_a_LIBADD)
+ $(RANLIB) libarch.a
+
+clean-noinstPROGRAMS:
+ -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS)
+generate$(EXEEXT): $(generate_OBJECTS) $(generate_DEPENDENCIES)
+ @rm -f generate$(EXEEXT)
+ $(LINK) $(generate_LDFLAGS) $(generate_OBJECTS) $(generate_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/execute.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/generate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/or32.Po@am__quote@
+
+distclean-depend:
+ -rm -rf ./$(DEPDIR)
+
+.c.o:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ $(COMPILE) -c `cygpath -w $<`
+CCDEPMODE = @CCDEPMODE@
+uninstall-info-am:
+
+ETAGS = etags
+ETAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$tags$$unique" \
+ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ../..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @list='$(DISTFILES)'; for file in $$list; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES) $(PROGRAMS)
+
+installdirs:
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \
+ mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+uninstall-am: uninstall-info-am
+
+.PHONY: GTAGS all all-am check check-am clean clean-generic \
+ clean-noinstLIBRARIES clean-noinstPROGRAMS distclean \
+ distclean-compile distclean-depend distclean-generic \
+ distclean-tags distdir dvi dvi-am info info-am install \
+ install-am install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic tags uninstall \
+ uninstall-am uninstall-info-am
+
+
+@SIMPLE_EXECUTION_FALSE@execgen.c: generate $(srcdir)/insnset.c
+@SIMPLE_EXECUTION_FALSE@ ./generate $(srcdir)/insnset.c execgen.c
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
Index: .
===================================================================
--- . (nonexistent)
+++ . (revision 1765)
.
Property changes :
Added: svn:ignore
## -0,0 +1,3 ##
+Makefile
+.deps
+generate