--- trunk/src/cpus/cpu_arm_instr_loadstore.c 2007/10/08 16:19:01 16 +++ trunk/src/cpus/cpu_arm_instr_loadstore.c 2007/10/08 16:19:37 22 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Anders Gavare. All rights reserved. + * Copyright (C) 2005-2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_arm_instr_loadstore.c,v 1.9 2005/10/09 21:32:07 debug Exp $ + * $Id: cpu_arm_instr_loadstore.c,v 1.20 2006/02/16 19:49:04 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,14 @@ */ +#if defined(A__SIGNED) && !defined(A__H) && !defined(A__L) +#define A__LDRD +#endif +#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,19 +73,34 @@ #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 + +#if defined(A__STRD) || defined(A__LDRD) + 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 - @@ -88,10 +113,9 @@ 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 @@ -99,47 +123,68 @@ #endif ; -#ifdef A__L + +#if defined(A__L) || defined(A__LDRD) /* 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; } -#ifdef A__B +#if defined(A__B) && !defined(A__LDRD) reg(ic->arg[2]) = #ifdef A__SIGNED (int32_t)(int8_t) #endif data[0]; #else -#ifdef A__H +#if defined(A__H) && !defined(A__LDRD) reg(ic->arg[2]) = #ifdef A__SIGNED (int32_t)(int16_t) #endif (data[0] + (data[1] << 8)); #else +#ifndef A__LDRD +#ifdef HOST_LITTLE_ENDIAN + /* Nothing. */ +#else reg(ic->arg[2]) = data[0] + (data[1] << 8) + (data[2] << 16) + (data[3] << 24); #endif +#else + reg(ic->arg[2]) = data[0] + (data[1] << 8) + + (data[2] << 16) + (data[3] << 24); + reg(((uint32_t *)ic->arg[2]) + 1) = data[4] + (data[5] << 8) + + (data[6] << 16) + (data[7] << 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; @@ -161,8 +206,8 @@ */ 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. */ +#if defined(A__LDRD) || defined(A__STRD) + /* Chicken out, let's do this unoptimized for now: */ A__NAME__general(cpu, ic); #else #ifdef A__REG @@ -191,8 +236,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 @@ -209,12 +268,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]); @@ -223,6 +286,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; @@ -230,6 +296,7 @@ #endif #endif #endif +#endif /* Index Write-back: */ #ifdef A__P @@ -241,7 +308,7 @@ reg(ic->arg[0]) = addr + offset; #endif } -#endif /* not T-bit */ +#endif /* not STRD */ } @@ -270,7 +337,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; @@ -278,7 +345,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: */ @@ -286,7 +355,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; @@ -298,80 +367,90 @@ #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__LDRD +#undef A__LDRD +#endif + +#ifdef A__STRD +#undef A__STRD +#endif +