URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [tags/] [nog_patch_65/] [or1ksim/] [cpu/] [or32/] [dyn_rec.c] - Rev 1452
Go to most recent revision | Compare with Previous | Blame | View Log
/* dyn_rec.c -- Dynamic recompiler implementation for or32 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 <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); }
Go to most recent revision | Compare with Previous | Blame | View Log