--- 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:11 18 @@ -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.15 2005/10/27 14:01:13 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,25 +70,43 @@ #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); @@ -98,7 +123,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 +142,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 +196,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 +226,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. + */ + unsigned char x = cpu->cd.arm.is_userpage[addr >> 15]; + if (!(x & (1 << ((addr >> 12) & 7)))) + 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 +258,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 +276,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 +286,7 @@ #endif #endif #endif +#endif /* Index Write-back: */ #ifdef A__P @@ -235,7 +298,7 @@ reg(ic->arg[0]) = addr + offset; #endif } -#endif /* not T-bit */ +#endif /* not STRD */ } @@ -272,7 +335,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); + if (cpu->machine->show_trace_tree) + cpu_functioncall_trace(cpu, cpu->pc); + quick_pc_to_pointers(cpu); } #else /* Store: */ @@ -369,3 +434,8 @@ ((cpu->cd.arm.cpsr & ARM_FLAG_V)?1:0) || (cpu->cd.arm.cpsr & ARM_FLAG_Z)) A__NAME_PC(cpu, ic); } #endif + + +#ifdef A__STRD +#undef A__STRD +#endif