--- trunk/src/cpus/cpu_sparc_instr.c 2007/10/08 16:19:56 24 +++ trunk/src/cpus/cpu_sparc_instr.c 2007/10/08 16:20:26 28 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_sparc_instr.c,v 1.18 2006/05/17 20:27:31 debug Exp $ + * $Id: cpu_sparc_instr.c,v 1.21 2006/07/02 11:01:19 debug Exp $ * * SPARC instructions. * @@ -37,6 +37,18 @@ /* + * invalid: For catching bugs. + */ +X(invalid) +{ + fatal("FATAL ERROR: An internal error occured in the SPARC" + " dyntrans code. Please contact the author with detailed" + " repro steps on how to trigger this bug.\n"); + exit(1); +} + + +/* * nop: Do nothing. */ X(nop) @@ -327,6 +339,52 @@ /* + * Save: + * + * arg[0] = ptr to rs1 + * arg[1] = ptr to rs2 or an immediate value (int32_t) + * arg[2] = ptr to rd (_after_ the register window change) + */ +X(save_v9_imm) +{ + MODE_uint_t rs = reg(ic->arg[0]) + (int32_t)ic->arg[1]; + int cwp = cpu->cd.sparc.cwp; + + if (cpu->cd.sparc.cansave == 0) { + fatal("save_v9_imm: spill trap. TODO\n"); + exit(1); + } + + if (cpu->cd.sparc.cleanwin - cpu->cd.sparc.canrestore == 0) { + fatal("save_v9_imm: clean_window trap. TODO\n"); + exit(1); + } + + /* Save away old in registers: */ + memcpy(&cpu->cd.sparc.r_inout[cwp][0], &cpu->cd.sparc.r[SPARC_REG_I0], + sizeof(cpu->cd.sparc.r[SPARC_REG_I0]) * N_SPARC_INOUT_REG); + + /* Save away old local registers: */ + memcpy(&cpu->cd.sparc.r_local[cwp][0], &cpu->cd.sparc.r[SPARC_REG_L0], + sizeof(cpu->cd.sparc.r[SPARC_REG_L0]) * N_SPARC_INOUT_REG); + + cwp = cpu->cd.sparc.cwp = (cwp + 1) % cpu->cd.sparc.cpu_type.nwindows; + cpu->cd.sparc.cansave --; + cpu->cd.sparc.canrestore ++; /* TODO: modulo here too? */ + + /* The out registers become the new in registers: */ + memcpy(&cpu->cd.sparc.r[SPARC_REG_I0], &cpu->cd.sparc.r[SPARC_REG_O0], + sizeof(cpu->cd.sparc.r[SPARC_REG_O0]) * N_SPARC_INOUT_REG); + + /* Read new local registers: */ + memcpy(&cpu->cd.sparc.r[SPARC_REG_L0], &cpu->cd.sparc.r_local[cwp][0], + sizeof(cpu->cd.sparc.r[SPARC_REG_L0]) * N_SPARC_INOUT_REG); + + reg(ic->arg[2]) = rs; +} + + +/* * Subtract with ccr update: * * arg[0] = ptr to rs1 @@ -383,6 +441,9 @@ } +#include "tmp_sparc_loadstore.c" + + /* * rd: Read special register: * @@ -483,12 +544,12 @@ X(to_be_translated) { MODE_uint_t addr; - int low_pc; - int in_crosspage_delayslot = 0; + int low_pc, in_crosspage_delayslot = 0; uint32_t iword; unsigned char *page; unsigned char ib[4]; int main_opcode, op2, rd, rs1, rs2, btype, asi, cc, p, use_imm, x64 = 0; + int store, signedness, size; int32_t tmpi32, siconst; /* void (*samepage_function)(struct cpu *, struct sparc_instr_call *);*/ @@ -621,6 +682,7 @@ case 37:/* sll */ case 38:/* srl */ case 39:/* sra */ + case 60:/* save */ ic->arg[0] = (size_t)&cpu->cd.sparc.r[rs1]; ic->f = NULL; if (use_imm) { @@ -659,6 +721,12 @@ ic->arg[1] &= 31; } break; + case 60:switch (cpu->cd.sparc.cpu_type.v) { + case 9: ic->f = instr(save_v9_imm); + break; + default:fatal("only for v9 so far\n"); + goto bad; + } } } else { ic->arg[1] = (size_t)&cpu->cd.sparc.r[rs2]; @@ -696,12 +764,14 @@ } ic->arg[2] = (size_t)&cpu->cd.sparc.r[rd]; if (rd == SPARC_ZEROREG) { - /* Opcodes which update the ccr should use - the scratch register instead of being - turned into a nop, when the zero register - is used as the destination: */ + /* + * Some opcodes should write to the scratch + * register instead of becoming NOPs, when + * rd is the zero register. + */ switch (op2) { case 20:/* subcc */ + case 60:/* save */ ic->arg[2] = (size_t) &cpu->cd.sparc.scratch; break; @@ -813,8 +883,62 @@ } break; - default:fatal("TODO: unimplemented main opcode %i\n", main_opcode); - goto bad; + case 3: switch (op2) { + + case 0:/* lduw */ + case 1:/* ldub */ + case 2:/* lduh */ + case 4:/* st(w) */ + case 5:/* stb */ + case 6:/* sth */ + case 8:/* ldsw */ + case 9:/* ldsb */ + case 10:/* ldsh */ + case 11:/* ldx */ + case 14:/* stx */ + store = 1; signedness = 0; size = 3; + switch (op2) { + case 0: /* lduw */ store=0; size=2; break; + case 1: /* ldub */ store=0; size=0; break; + case 2: /* lduh */ store=0; size=1; break; + case 4: /* st */ size = 2; break; + case 5: /* stb */ size = 0; break; + case 6: /* sth */ size = 1; break; + case 8: /* ldsw */ store=0; size=2; signedness=1; + break; + case 9: /* ldsb */ store=0; size=0; signedness=1; + break; + case 10: /* ldsh */ store=0; size=1; signedness=1; + break; + case 11: /* ldx */ store=0; break; + case 14: /* stx */ break; + } + ic->f = +#ifdef MODE32 + sparc32_loadstore +#else + sparc_loadstore +#endif + [ use_imm*16 + store*8 + size*2 + signedness ]; + + ic->arg[0] = (size_t)&cpu->cd.sparc.r[rd]; + ic->arg[1] = (size_t)&cpu->cd.sparc.r[rs1]; + if (use_imm) + ic->arg[2] = siconst; + else + ic->arg[2] = (size_t)&cpu->cd.sparc.r[rs2]; + + if (!store && rd == SPARC_ZEROREG) + ic->arg[0] = (size_t)&cpu->cd.sparc.scratch; + + break; + + default:fatal("TODO: unimplemented op2=%i for main " + "opcode %i\n", op2, main_opcode); + goto bad; + } + break; + }