--- trunk/src/cpus/cpu_arm_instr_loadstore.c 2007/10/08 16:18:51 14 +++ trunk/src/cpus/cpu_arm_instr_loadstore.c 2007/10/08 16:19:23 20 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_arm_instr_loadstore.c,v 1.8 2005/10/05 21:17:32 debug Exp $ + * $Id: cpu_arm_instr_loadstore.c,v 1.19 2005/11/19 18:53:07 debug Exp $ * * * TODO: Many things... @@ -35,6 +35,8 @@ * o) Alignment checks! * * o) Native load/store if the endianness is the same as the host's + * (only implemented for little endian, so far, and it assumes that + * alignment is correct!) * * o) "Base Updated Abort Model", which updates the base register * even if the memory access failed. @@ -51,6 +53,11 @@ */ +#if defined(A__SIGNED) && defined(A__H) && !defined(A__L) +#define A__STRD +#endif + + /* * General load/store, by using memory_rw(). If at all possible, memory_rw() * then inserts the page into the translation array, so that the fast @@ -63,32 +70,49 @@ #else const int memory_rw_flags = CACHE_DATA; #endif + +#ifdef A__REG + uint32_t (*reg_func)(struct cpu *, struct arm_instr_call *) + = (void *)(size_t)ic->arg[1]; +#endif + +#ifdef A__STRD + unsigned char data[8]; + const int datalen = 8; +#else #ifdef A__B unsigned char data[1]; + const int datalen = 1; #else #ifdef A__H unsigned char data[2]; + const int datalen = 2; +#else + const int datalen = 4; +#ifdef HOST_LITTLE_ENDIAN + unsigned char *data = (unsigned char *) ic->arg[2]; #else unsigned char data[4]; #endif #endif +#endif +#endif + uint32_t addr, low_pc, offset = #ifndef A__U - #endif #ifdef A__REG - R(cpu, ic, ic->arg[1], 0) + reg_func(cpu, ic); #else - ic->arg[1] + ic->arg[1]; #endif - ; low_pc = ((size_t)ic - (size_t)cpu->cd.arm. cur_ic_page) / sizeof(struct arm_instr_call); - cpu->cd.arm.r[ARM_PC] &= ~((ARM_IC_ENTRIES_PER_PAGE-1) + cpu->pc &= ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); - cpu->cd.arm.r[ARM_PC] += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); - cpu->pc = cpu->cd.arm.r[ARM_PC]; + cpu->pc += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); addr = reg(ic->arg[0]) #ifdef A__P @@ -98,7 +122,7 @@ #ifdef A__L /* Load: */ - if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), + if (!cpu->memory_rw(cpu, cpu->mem, addr, data, datalen, MEM_READ, memory_rw_flags)) { /* load failed, an exception was generated */ return; @@ -117,26 +141,39 @@ #endif (data[0] + (data[1] << 8)); #else +#ifdef HOST_LITTLE_ENDIAN + /* Nothing. */ +#else reg(ic->arg[2]) = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); #endif #endif +#endif #else /* Store: */ -#ifdef A__B - data[0] = reg(ic->arg[2]); +#if !defined(A__B) && !defined(A__H) && defined(HOST_LITTLE_ENDIAN) +#ifdef A__STRD + *(uint32_t *)data = reg(ic->arg[2]); + *(uint32_t *)(data + 4) = reg(ic->arg[2] + 4); +#endif #else -#ifdef A__H data[0] = reg(ic->arg[2]); +#ifndef A__B data[1] = reg(ic->arg[2]) >> 8; -#else - data[0] = reg(ic->arg[2]); +#if !defined(A__H) || defined(A__STRD) data[1] = reg(ic->arg[2]) >> 8; data[2] = reg(ic->arg[2]) >> 16; data[3] = reg(ic->arg[2]) >> 24; +#ifdef A__STRD + data[4] = reg(ic->arg[2] + 4); + data[5] = reg(ic->arg[2] + 4) >> 8; + data[6] = reg(ic->arg[2] + 4) >> 16; + data[7] = reg(ic->arg[2] + 4) >> 24; +#endif +#endif #endif #endif - if (!cpu->memory_rw(cpu, cpu->mem, addr, data, sizeof(data), + if (!cpu->memory_rw(cpu, cpu->mem, addr, data, datalen, MEM_WRITE, memory_rw_flags)) { /* store failed, an exception was generated */ return; @@ -158,20 +195,23 @@ */ void A__NAME(struct cpu *cpu, struct arm_instr_call *ic) { -#if !defined(A__P) && defined(A__W) - /* T-bit: userland access. Use the general routine for that. */ +#ifdef A__STRD + /* Chicken out, let's do this unoptimized for now: */ A__NAME__general(cpu, ic); #else +#ifdef A__REG + uint32_t (*reg_func)(struct cpu *, struct arm_instr_call *) + = (void *)(size_t)ic->arg[1]; +#endif uint32_t offset = #ifndef A__U - #endif #ifdef A__REG - R(cpu, ic, ic->arg[1], 0) + reg_func(cpu, ic); #else - ic->arg[1] + ic->arg[1]; #endif - ; uint32_t addr = reg(ic->arg[0]) #ifdef A__P + offset @@ -185,8 +225,22 @@ #endif [addr >> 12]; + +#if !defined(A__P) && defined(A__W) + /* + * T-bit: userland access: check the corresponding bit in the + * is_userpage array. If it is set, then we're ok. Otherwise: use the + * generic function. + */ + uint32_t x = cpu->cd.arm.is_userpage[addr >> 17]; + if (!(x & (1 << ((addr >> 12) & 31)))) + A__NAME__general(cpu, ic); + else +#endif + + if (page == NULL) { - A__NAME__general(cpu, ic); + A__NAME__general(cpu, ic); } else { #ifdef A__L #ifdef A__B @@ -203,12 +257,16 @@ #endif (page[addr & 0xfff] + (page[(addr & 0xfff) + 1] << 8)); #else +#ifdef HOST_LITTLE_ENDIAN + reg(ic->arg[2]) = *(uint32_t *)(page + (addr & 0xffc)); +#else reg(ic->arg[2]) = page[addr & 0xfff] + (page[(addr & 0xfff) + 1] << 8) + (page[(addr & 0xfff) + 2] << 16) + (page[(addr & 0xfff) + 3] << 24); #endif #endif +#endif #else #ifdef A__B page[addr & 0xfff] = reg(ic->arg[2]); @@ -217,6 +275,9 @@ page[addr & 0xfff] = reg(ic->arg[2]); page[(addr & 0xfff)+1] = reg(ic->arg[2]) >> 8; #else +#ifdef HOST_LITTLE_ENDIAN + *(uint32_t *)(page + (addr & 0xffc)) = reg(ic->arg[2]); +#else page[addr & 0xfff] = reg(ic->arg[2]); page[(addr & 0xfff)+1] = reg(ic->arg[2]) >> 8; page[(addr & 0xfff)+2] = reg(ic->arg[2]) >> 16; @@ -224,6 +285,7 @@ #endif #endif #endif +#endif /* Index Write-back: */ #ifdef A__P @@ -235,7 +297,7 @@ reg(ic->arg[0]) = addr + offset; #endif } -#endif /* not T-bit */ +#endif /* not STRD */ } @@ -264,7 +326,7 @@ uint32_t low_pc, tmp; low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); - tmp = cpu->cd.arm.r[ARM_PC] & ~((ARM_IC_ENTRIES_PER_PAGE-1) << + tmp = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); tmp += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); cpu->cd.arm.tmp_pc = tmp + 8; @@ -272,7 +334,9 @@ A__NAME(cpu, ic); if (ic->arg[2] == (size_t)(&cpu->cd.arm.r[ARM_PC])) { cpu->pc = cpu->cd.arm.r[ARM_PC]; - arm_pc_to_pointers(cpu); + quick_pc_to_pointers(cpu); + if (cpu->machine->show_trace_tree) + cpu_functioncall_trace(cpu, cpu->pc); } #else /* Store: */ @@ -280,7 +344,7 @@ /* Calculate tmp from this instruction's PC + 12 */ low_pc = ((size_t)ic - (size_t) cpu->cd.arm.cur_ic_page) / sizeof(struct arm_instr_call); - tmp = cpu->cd.arm.r[ARM_PC] & ~((ARM_IC_ENTRIES_PER_PAGE-1) << + tmp = cpu->pc & ~((ARM_IC_ENTRIES_PER_PAGE-1) << ARM_INSTR_ALIGNMENT_SHIFT); tmp += (low_pc << ARM_INSTR_ALIGNMENT_SHIFT); cpu->cd.arm.tmp_pc = tmp + 12; @@ -292,80 +356,85 @@ #ifndef A__NOCONDITIONS /* Load/stores with all registers except the PC register: */ void A__NAME__eq(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_Z) A__NAME(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_Z) A__NAME(cpu, ic); } void A__NAME__ne(struct cpu *cpu, struct arm_instr_call *ic) -{ if (!(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME(cpu, ic); } +{ if (!(cpu->cd.arm.flags & ARM_F_Z)) A__NAME(cpu, ic); } void A__NAME__cs(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_C) A__NAME(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_C) A__NAME(cpu, ic); } void A__NAME__cc(struct cpu *cpu, struct arm_instr_call *ic) -{ if (!(cpu->cd.arm.cpsr & ARM_FLAG_C)) A__NAME(cpu, ic); } +{ if (!(cpu->cd.arm.flags & ARM_F_C)) A__NAME(cpu, ic); } void A__NAME__mi(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_N) A__NAME(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_N) A__NAME(cpu, ic); } void A__NAME__pl(struct cpu *cpu, struct arm_instr_call *ic) -{ if (!(cpu->cd.arm.cpsr & ARM_FLAG_N)) A__NAME(cpu, ic); } +{ if (!(cpu->cd.arm.flags & ARM_F_N)) A__NAME(cpu, ic); } void A__NAME__vs(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_V) A__NAME(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_V) A__NAME(cpu, ic); } void A__NAME__vc(struct cpu *cpu, struct arm_instr_call *ic) -{ if (!(cpu->cd.arm.cpsr & ARM_FLAG_V)) A__NAME(cpu, ic); } +{ if (!(cpu->cd.arm.flags & ARM_F_V)) A__NAME(cpu, ic); } void A__NAME__hi(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_C && -!(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_C && +!(cpu->cd.arm.flags & ARM_F_Z)) A__NAME(cpu, ic); } void A__NAME__ls(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_Z || -!(cpu->cd.arm.cpsr & ARM_FLAG_C)) A__NAME(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_Z || +!(cpu->cd.arm.flags & ARM_F_C)) A__NAME(cpu, ic); } void A__NAME__ge(struct cpu *cpu, struct arm_instr_call *ic) -{ if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) == -((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) A__NAME(cpu, ic); } +{ if (((cpu->cd.arm.flags & ARM_F_N)?1:0) == +((cpu->cd.arm.flags & ARM_F_V)?1:0)) A__NAME(cpu, ic); } void A__NAME__lt(struct cpu *cpu, struct arm_instr_call *ic) -{ if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) != -((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) A__NAME(cpu, ic); } +{ if (((cpu->cd.arm.flags & ARM_F_N)?1:0) != +((cpu->cd.arm.flags & ARM_F_V)?1:0)) A__NAME(cpu, ic); } void A__NAME__gt(struct cpu *cpu, struct arm_instr_call *ic) -{ if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) == -((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) && -!(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME(cpu, ic); } +{ if (((cpu->cd.arm.flags & ARM_F_N)?1:0) == +((cpu->cd.arm.flags & ARM_F_V)?1:0) && +!(cpu->cd.arm.flags & ARM_F_Z)) A__NAME(cpu, ic); } void A__NAME__le(struct cpu *cpu, struct arm_instr_call *ic) -{ if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) != -((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) || -(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME(cpu, ic); } +{ if (((cpu->cd.arm.flags & ARM_F_N)?1:0) != +((cpu->cd.arm.flags & ARM_F_V)?1:0) || +(cpu->cd.arm.flags & ARM_F_Z)) A__NAME(cpu, ic); } /* Load/stores with the PC register: */ void A__NAME_PC__eq(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_Z) A__NAME_PC(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_Z) A__NAME_PC(cpu, ic); } void A__NAME_PC__ne(struct cpu *cpu, struct arm_instr_call *ic) -{ if (!(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME_PC(cpu, ic); } +{ if (!(cpu->cd.arm.flags & ARM_F_Z)) A__NAME_PC(cpu, ic); } void A__NAME_PC__cs(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_C) A__NAME_PC(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_C) A__NAME_PC(cpu, ic); } void A__NAME_PC__cc(struct cpu *cpu, struct arm_instr_call *ic) -{ if (!(cpu->cd.arm.cpsr & ARM_FLAG_C)) A__NAME_PC(cpu, ic); } +{ if (!(cpu->cd.arm.flags & ARM_F_C)) A__NAME_PC(cpu, ic); } void A__NAME_PC__mi(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_N) A__NAME_PC(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_N) A__NAME_PC(cpu, ic); } void A__NAME_PC__pl(struct cpu *cpu, struct arm_instr_call *ic) -{ if (!(cpu->cd.arm.cpsr & ARM_FLAG_N)) A__NAME_PC(cpu, ic); } +{ if (!(cpu->cd.arm.flags & ARM_F_N)) A__NAME_PC(cpu, ic); } void A__NAME_PC__vs(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_V) A__NAME_PC(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_V) A__NAME_PC(cpu, ic); } void A__NAME_PC__vc(struct cpu *cpu, struct arm_instr_call *ic) -{ if (!(cpu->cd.arm.cpsr & ARM_FLAG_V)) A__NAME_PC(cpu, ic); } +{ if (!(cpu->cd.arm.flags & ARM_F_V)) A__NAME_PC(cpu, ic); } void A__NAME_PC__hi(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_C && -!(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME_PC(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_C && +!(cpu->cd.arm.flags & ARM_F_Z)) A__NAME_PC(cpu, ic); } void A__NAME_PC__ls(struct cpu *cpu, struct arm_instr_call *ic) -{ if (cpu->cd.arm.cpsr & ARM_FLAG_Z || -!(cpu->cd.arm.cpsr & ARM_FLAG_C)) A__NAME_PC(cpu, ic); } +{ if (cpu->cd.arm.flags & ARM_F_Z || +!(cpu->cd.arm.flags & ARM_F_C)) A__NAME_PC(cpu, ic); } void A__NAME_PC__ge(struct cpu *cpu, struct arm_instr_call *ic) -{ if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) == -((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) A__NAME_PC(cpu, ic); } +{ if (((cpu->cd.arm.flags & ARM_F_N)?1:0) == +((cpu->cd.arm.flags & ARM_F_V)?1:0)) A__NAME_PC(cpu, ic); } void A__NAME_PC__lt(struct cpu *cpu, struct arm_instr_call *ic) -{ if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) != -((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0)) A__NAME_PC(cpu, ic); } +{ if (((cpu->cd.arm.flags & ARM_F_N)?1:0) != +((cpu->cd.arm.flags & ARM_F_V)?1:0)) A__NAME_PC(cpu, ic); } void A__NAME_PC__gt(struct cpu *cpu, struct arm_instr_call *ic) -{ if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) == -((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) && -!(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME_PC(cpu, ic); } +{ if (((cpu->cd.arm.flags & ARM_F_N)?1:0) == +((cpu->cd.arm.flags & ARM_F_V)?1:0) && +!(cpu->cd.arm.flags & ARM_F_Z)) A__NAME_PC(cpu, ic); } void A__NAME_PC__le(struct cpu *cpu, struct arm_instr_call *ic) -{ if (((cpu->cd.arm.cpsr & ARM_FLAG_N)?1:0) != -((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) || -(cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME_PC(cpu, ic); } +{ if (((cpu->cd.arm.flags & ARM_F_N)?1:0) != +((cpu->cd.arm.flags & ARM_F_V)?1:0) || +(cpu->cd.arm.flags & ARM_F_Z)) A__NAME_PC(cpu, ic); } +#endif + + +#ifdef A__STRD +#undef A__STRD #endif