URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 1691 to Rev 1692
- ↔ Reverse comparison
Rev 1691 → Rev 1692
/trunk/or1ksim/cpu/or32/op_support.c
42,8 → 42,6
#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()) */ |
|
99,68 → 97,8
* to some bogus value. */ |
void do_jump(oraddr_t addr) |
{ |
struct dyn_page *target_dp; |
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 */ |
cpu_state.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 = cpu_state.dyn_pages[phys_page >> config.immu.pagesize_log2]; |
|
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; |
|
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 */ |
cpu_state.cycles_dec = target_dp->delayr - config.immu.hitdelay; |
else |
cpu_state.cycles_dec = target_dp->delayr; |
|
/* Initially this 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... */ |
enter_dyn_code(phys_page, target_dp); |
longjmp(cpu_state.excpt_loc, 0); |
} |
|
/* Wrapper around analysis() that contains all the recompiler specific stuff */ |
/trunk/or1ksim/cpu/or32/op.c
134,6 → 134,8
void enter_dyn_code(oraddr_t addr, struct dyn_page *dp) |
{ |
uint16_t reg = 0; |
uint32_t t0_reg = t0, t1_reg = t1, t2_reg = t2; |
struct cpu_state *cpu_reg = env; |
|
addr &= config.immu.pagesize - 1; |
addr >>= 2; |
153,10 → 155,15
if(addr) |
t2 = cpu_state.reg[(reg >> 10) & 0x1f]; |
|
or_longjmp(dp->locs[addr]); |
env = &cpu_state; |
|
((gen_code_ent *)dp->locs)[addr](); |
t0 = t0_reg; |
t1 = t1_reg; |
t2 = t2_reg; |
env = (struct cpu_state *)cpu_reg; |
} |
|
|
__or_dynop void op_set_pc_pc_delay(void) |
{ |
env->sprs[SPR_PPC] = env->pc; |
185,12 → 192,13
|
__or_dynop void op_do_jump(void) |
{ |
do_jump(env->pc); |
RET_FROM_DYN_CODE; |
} |
|
__or_dynop void op_do_jump_delay(void) |
{ |
do_jump(env->pc_delay); |
env->pc = env->pc_delay; |
RET_FROM_DYN_CODE; |
} |
|
__or_dynop void op_clear_delay_insn(void) |
276,7 → 284,8
__or_dynop void op_nop_reset(void) |
{ |
op_support_nop_reset(); |
do_jump(EXCEPT_RESET); |
env->pc = EXCEPT_RESET; |
RET_FROM_DYN_CODE; |
} |
|
__or_dynop void op_nop_printf(void) |
940,13 → 949,15
{ |
env->delay_insn = 0; |
env->sprs[SPR_EEAR_BASE] = env->pc - 4; |
do_jump(EXCEPT_ILLEGAL - 4); |
env->pc = EXCEPT_ILLEGAL - 4; |
RET_FROM_DYN_CODE; |
} |
|
__or_dynop void op_illegal(void) |
{ |
env->sprs[SPR_EEAR_BASE] = env->pc; |
do_jump(EXCEPT_ILLEGAL); |
env->pc = EXCEPT_ILLEGAL; |
RET_FROM_DYN_CODE; |
} |
|
__or_dynop void op_do_sched(void) |
/trunk/or1ksim/cpu/or32/dyn_rec.c
43,7 → 43,6
#include "sim-config.h" |
#include "sched.h" |
|
#include "rec_i386.h" |
#include "i386_regs.h" |
|
#include "def_op_t.h" |
84,8 → 83,6
|
#define T_NONE (-1) |
|
void *rec_stack_base; |
|
/* Temporary is used as a source operand */ |
#define TFLAG_SRC 1 |
/* Temporary is used as a destination operand */ |
110,11 → 107,7
struct dyn_page *dp; |
FILE *f; |
char filen[18]; /* 18 == strlen("or_page.%08x") + 1 */ |
void *stack; |
int i, j; |
void *trace[11]; |
int num_trace; |
char **trace_names; |
int i; |
struct sigcontext *sigc = dat; |
|
if(!sigsegv_state) { |
156,32 → 149,6
} |
sigsegv_state++; |
case 2: |
/* Dump the contents of the stack */ |
fprintf(stderr, "Stack dump: "); |
fflush(stderr); |
|
num_trace = backtrace(trace, 10); |
|
trace[num_trace++] = (void *)sigc->eip; |
trace_names = backtrace_symbols(trace, num_trace); |
|
stack = get_sp(); |
fprintf(stderr, "(of stack at %p, base: %p)\n", stack, rec_stack_base); |
fflush(stderr); |
for(i = 0; stack < rec_stack_base; i++, stack += 4) { |
fprintf(stderr, " <%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) |
fprintf(stderr, " <%s>", trace_names[j]); |
} |
fprintf(stderr, "\n"); |
fflush(stderr); |
} |
fprintf(stderr, "Fault at: 0x%08lx <%s>\n", sigc->eip, |
trace_names[num_trace - 1]); |
sigsegv_state++; |
case 3: |
sim_done(); |
} |
} |
207,6 → 174,53
return dp; |
} |
|
void dyn_main(void) |
{ |
struct dyn_page *target_dp; |
oraddr_t phys_page; |
|
setjmp(cpu_state.excpt_loc); |
for(;;) { |
phys_page = immu_translate(cpu_state.pc); |
|
/* |
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 = cpu_state.dyn_pages[phys_page >> config.immu.pagesize_log2]; |
|
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; |
|
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 */ |
cpu_state.cycles_dec = target_dp->delayr; |
if(cpu_state.sprs[SPR_SR] & SPR_SR_IME) |
/* Add the mmu hit delay to the cycle counter */ |
cpu_state.cycles_dec -= config.immu.hitdelay; |
|
/* FIXME: ebp, ebx, esi and edi are expected to be preserved across function |
* calls but the recompiled code trashes them... */ |
enter_dyn_code(phys_page, target_dp); |
} |
} |
|
static void immu_retranslate(void *dat) |
{ |
int got_en_dis = (int)dat; |
439,22 → 453,6
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) |
{ |
cpu_state.pc = addr; |
do_jump(addr); |
} |
|
/* Initialises the recompiler */ |
void init_dyn_recomp(void) |
{ |
487,9 → 485,6
|
opq->prev = NULL; |
|
/* Just some value that we'll use as the base for our stack */ |
rec_stack_base = get_sp(); |
|
cpu_state.curr_page = NULL; |
if(!(cpu_state.dyn_pages = malloc(sizeof(void *) * (2 << (32 - |
config.immu.pagesize_log2))))) { |
/trunk/or1ksim/cpu/or32/dyn_rec.h
21,6 → 21,8
#ifndef DYN_REC_H |
#define DYN_REC_H |
|
typedef void (*gen_code_ent)(void); |
|
/* Each dynamically recompiled page has one of these */ |
struct dyn_page { |
oraddr_t or_page; |
42,11 → 44,11
void *enough_host_page(struct dyn_page *dp, void *cur, unsigned int *len, |
unsigned int amount); |
void init_dyn_recomp(void); |
void jump_dyn_code(oraddr_t addr); |
void run_sched_out_of_line(void); |
void recheck_immu(int got_en_dis); |
void enter_dyn_code(oraddr_t addr, struct dyn_page *dp); |
void dyn_checkwrite(oraddr_t addr); |
void dyn_main(void); |
|
extern void *rec_stack_base; |
|
/trunk/or1ksim/cpu/or32/execute.c
659,9 → 659,12
pcnext += 4; |
|
/* MM1409: All programs should set their stack pointer! */ |
#if !(DYNAMIC_EXECUTION) |
except_handle(EXCEPT_RESET, 0); |
update_pc(); |
#endif |
except_pending = 0; |
cpu_state.pc = EXCEPT_RESET; |
} |
|
/* Simulates one CPU clock cycle */ |
/trunk/or1ksim/cpu/or32/op_i386.h
21,26 → 21,10
|
#define FORCE_RET asm volatile ("") |
|
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)); |
} |
|
/* Does a function call (with no arguments) makeing sure that gcc doesn't peddle |
* the stack. (FIXME: Is this safe??) */ |
#define SPEEDY_CALL(func) asm("call "#func"\n") |
|
/* Return out of the recompiled code */ |
#define RET_FROM_DYN_CODE asm volatile ("ret") |
|
/trunk/or1ksim/cpu/common/execute.h
18,6 → 18,7
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
#if DYNAMIC_EXECUTION |
#include "setjmp.h" |
#include "dyn_rec.h" |
#endif |
|
49,6 → 50,9
struct iqueue_entry icomplet; |
|
#if DYNAMIC_EXECUTION |
/* longjmp() to this location in case of an exception */ |
jmp_buf excpt_loc; |
|
/* Current page in execution */ |
struct dyn_page *curr_page; |
|
/trunk/or1ksim/cpu/or1k/except.c
41,7 → 41,6
|
#if DYNAMIC_EXECUTION |
#include "sched.h" |
#include "rec_i386.h" |
#include "op_support.h" |
#endif |
|
179,7 → 178,6
cpu_state.delay_insn = 0; |
|
#if DYNAMIC_EXECUTION |
cpu_state.pc = except_vector; |
jump_dyn_code(except_vector); |
do_jump(except_vector); |
#endif |
} |
/trunk/or1ksim/toplevel.c
342,7 → 342,11
|
sim_init (); |
|
#if DYNAMIC_EXECUTION |
dyn_main(); |
#else |
exec_main(); |
#endif |
|
sim_done(); |
} |