diff options
author | Max Filippov <jcmvbkbc@gmail.com> | 2012-12-05 07:15:20 +0400 |
---|---|---|
committer | Blue Swirl <blauwirbel@gmail.com> | 2012-12-08 18:48:26 +0000 |
commit | fcc803d119a4c01a9b0ee5bda35fda1eeabffa33 (patch) | |
tree | bbd6697bd198b45b2322e5b43d3ab5159e093d98 /target-xtensa | |
parent | 536b558f5896ebbd635b57fa393e82faaa32ad52 (diff) |
target-xtensa: implement ATOMCTL SR
ATOMCTL SR controls s32c1i opcode behavior depending on targeted memory
type. See ISA, 4.3.12.4 for details.
Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Diffstat (limited to 'target-xtensa')
-rw-r--r-- | target-xtensa/cpu.c | 2 | ||||
-rw-r--r-- | target-xtensa/cpu.h | 10 | ||||
-rw-r--r-- | target-xtensa/helper.c | 56 | ||||
-rw-r--r-- | target-xtensa/helper.h | 1 | ||||
-rw-r--r-- | target-xtensa/op_helper.c | 57 | ||||
-rw-r--r-- | target-xtensa/overlay_tool.h | 6 | ||||
-rw-r--r-- | target-xtensa/translate.c | 13 |
7 files changed, 131 insertions, 14 deletions
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c index 9d01983d44..c6aa45ee6f 100644 --- a/target-xtensa/cpu.c +++ b/target-xtensa/cpu.c @@ -48,6 +48,8 @@ static void xtensa_cpu_reset(CPUState *s) XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; env->sregs[VECBASE] = env->config->vecbase; env->sregs[IBREAKENABLE] = 0; + env->sregs[ATOMCTL] = xtensa_option_enabled(env->config, + XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15; env->pending_irq_level = 0; reset_mmu(env); diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h index 74e98883bf..d240ab70d9 100644 --- a/target-xtensa/cpu.h +++ b/target-xtensa/cpu.h @@ -65,6 +65,7 @@ enum { XTENSA_OPTION_FP_COPROCESSOR, XTENSA_OPTION_MP_SYNCHRO, XTENSA_OPTION_CONDITIONAL_STORE, + XTENSA_OPTION_ATOMCTL, /* Interrupts and exceptions */ XTENSA_OPTION_EXCEPTION, @@ -128,6 +129,7 @@ enum { ITLBCFG = 91, DTLBCFG = 92, IBREAKENABLE = 96, + ATOMCTL = 99, IBREAKA = 128, DBREAKA = 144, DBREAKC = 160, @@ -193,6 +195,14 @@ enum { #define REGION_PAGE_MASK 0xe0000000 +#define PAGE_CACHE_MASK 0x700 +#define PAGE_CACHE_SHIFT 8 +#define PAGE_CACHE_INVALID 0x000 +#define PAGE_CACHE_BYPASS 0x100 +#define PAGE_CACHE_WT 0x200 +#define PAGE_CACHE_WB 0x400 +#define PAGE_CACHE_ISOLATE 0x600 + enum { /* Static vectors */ EXC_RESET, diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c index d94bae210d..ecd0182281 100644 --- a/target-xtensa/helper.c +++ b/target-xtensa/helper.c @@ -390,6 +390,7 @@ int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb, static unsigned mmu_attr_to_access(uint32_t attr) { unsigned access = 0; + if (attr < 12) { access |= PAGE_READ; if (attr & 0x1) { @@ -398,8 +399,22 @@ static unsigned mmu_attr_to_access(uint32_t attr) if (attr & 0x2) { access |= PAGE_WRITE; } + + switch (attr & 0xc) { + case 0: + access |= PAGE_CACHE_BYPASS; + break; + + case 4: + access |= PAGE_CACHE_WB; + break; + + case 8: + access |= PAGE_CACHE_WT; + break; + } } else if (attr == 13) { - access |= PAGE_READ | PAGE_WRITE; + access |= PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE; } return access; } @@ -410,14 +425,17 @@ static unsigned mmu_attr_to_access(uint32_t attr) */ static unsigned region_attr_to_access(uint32_t attr) { - unsigned access = 0; - if ((attr < 6 && attr != 3) || attr == 14) { - access |= PAGE_READ | PAGE_WRITE; - } - if (attr > 0 && attr < 6) { - access |= PAGE_EXEC; - } - return access; + static const unsigned access[16] = { + [0] = PAGE_READ | PAGE_WRITE | PAGE_CACHE_WT, + [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT, + [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS, + [3] = PAGE_EXEC | PAGE_CACHE_WB, + [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, + [5] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, + [14] = PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE, + }; + + return access[attr & 0xf]; } static bool is_access_granted(unsigned access, int is_write) @@ -566,7 +584,7 @@ int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, } else { *paddr = vaddr; *page_size = TARGET_PAGE_SIZE; - *access = PAGE_READ | PAGE_WRITE | PAGE_EXEC; + *access = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS; return 0; } } @@ -599,24 +617,34 @@ static void dump_tlb(FILE *f, fprintf_function cpu_fprintf, xtensa_tlb_get_entry(env, dtlb, wi, ei); if (entry->asid) { + static const char * const cache_text[8] = { + [PAGE_CACHE_BYPASS >> PAGE_CACHE_SHIFT] = "Bypass", + [PAGE_CACHE_WT >> PAGE_CACHE_SHIFT] = "WT", + [PAGE_CACHE_WB >> PAGE_CACHE_SHIFT] = "WB", + [PAGE_CACHE_ISOLATE >> PAGE_CACHE_SHIFT] = "Isolate", + }; unsigned access = attr_to_access(entry->attr); + unsigned cache_idx = (access & PAGE_CACHE_MASK) >> + PAGE_CACHE_SHIFT; if (print_header) { print_header = false; cpu_fprintf(f, "Way %u (%d %s)\n", wi, sz, sz_text); cpu_fprintf(f, - "\tVaddr Paddr ASID Attr RWX\n" - "\t---------- ---------- ---- ---- ---\n"); + "\tVaddr Paddr ASID Attr RWX Cache\n" + "\t---------- ---------- ---- ---- --- -------\n"); } cpu_fprintf(f, - "\t0x%08x 0x%08x 0x%02x 0x%02x %c%c%c\n", + "\t0x%08x 0x%08x 0x%02x 0x%02x %c%c%c %-7s\n", entry->vaddr, entry->paddr, entry->asid, entry->attr, (access & PAGE_READ) ? 'R' : '-', (access & PAGE_WRITE) ? 'W' : '-', - (access & PAGE_EXEC) ? 'X' : '-'); + (access & PAGE_EXEC) ? 'X' : '-', + cache_text[cache_idx] ? cache_text[cache_idx] : + "Invalid"); } } } diff --git a/target-xtensa/helper.h b/target-xtensa/helper.h index 1163c09836..5b4cd2700f 100644 --- a/target-xtensa/helper.h +++ b/target-xtensa/helper.h @@ -23,6 +23,7 @@ DEF_HELPER_3(waiti, void, env, i32, i32) DEF_HELPER_3(timer_irq, void, env, i32, i32) DEF_HELPER_2(advance_ccount, void, env, i32) DEF_HELPER_1(check_interrupts, void, env) +DEF_HELPER_3(check_atomctl, void, env, i32, i32) DEF_HELPER_2(wsr_rasid, void, env, i32) DEF_HELPER_FLAGS_3(rtlb0, TCG_CALL_NO_RWG_SE, i32, env, i32, i32) diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c index ae0c09977b..0e0f21d1a2 100644 --- a/target-xtensa/op_helper.c +++ b/target-xtensa/op_helper.c @@ -415,6 +415,63 @@ void HELPER(check_interrupts)(CPUXtensaState *env) check_interrupts(env); } +/*! + * Check vaddr accessibility/cache attributes and raise an exception if + * specified by the ATOMCTL SR. + * + * Note: local memory exclusion is not implemented + */ +void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr) +{ + uint32_t paddr, page_size, access; + uint32_t atomctl = env->sregs[ATOMCTL]; + int rc = xtensa_get_physical_addr(env, true, vaddr, 1, + xtensa_get_cring(env), &paddr, &page_size, &access); + + /* + * s32c1i never causes LOAD_PROHIBITED_CAUSE exceptions, + * see opcode description in the ISA + */ + if (rc == 0 && + (access & (PAGE_READ | PAGE_WRITE)) != (PAGE_READ | PAGE_WRITE)) { + rc = STORE_PROHIBITED_CAUSE; + } + + if (rc) { + HELPER(exception_cause_vaddr)(env, pc, rc, vaddr); + } + + /* + * When data cache is not configured use ATOMCTL bypass field. + * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL) + * under the Conditional Store Option. + */ + if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { + access = PAGE_CACHE_BYPASS; + } + + switch (access & PAGE_CACHE_MASK) { + case PAGE_CACHE_WB: + atomctl >>= 2; + case PAGE_CACHE_WT: + atomctl >>= 2; + case PAGE_CACHE_BYPASS: + if ((atomctl & 0x3) == 0) { + HELPER(exception_cause_vaddr)(env, pc, + LOAD_STORE_ERROR_CAUSE, vaddr); + } + break; + + case PAGE_CACHE_ISOLATE: + HELPER(exception_cause_vaddr)(env, pc, + LOAD_STORE_ERROR_CAUSE, vaddr); + break; + + default: + break; + } +} + void HELPER(wsr_rasid)(CPUXtensaState *env, uint32_t v) { v = (v & 0xffffff00) | 0x1; diff --git a/target-xtensa/overlay_tool.h b/target-xtensa/overlay_tool.h index e39505316b..50bf5735e9 100644 --- a/target-xtensa/overlay_tool.h +++ b/target-xtensa/overlay_tool.h @@ -42,6 +42,10 @@ #define XCHAL_VECBASE_RESET_VADDR 0 #endif +#ifndef XCHAL_HW_MIN_VERSION +#define XCHAL_HW_MIN_VERSION 0 +#endif + #define XCHAL_OPTION(xchal, qemu) ((xchal) ? XTENSA_OPTION_BIT(qemu) : 0) #define XTENSA_OPTIONS ( \ @@ -62,6 +66,8 @@ XCHAL_OPTION(XCHAL_HAVE_FP, XTENSA_OPTION_FP_COPROCESSOR) | \ XCHAL_OPTION(XCHAL_HAVE_RELEASE_SYNC, XTENSA_OPTION_MP_SYNCHRO) | \ XCHAL_OPTION(XCHAL_HAVE_S32C1I, XTENSA_OPTION_CONDITIONAL_STORE) | \ + XCHAL_OPTION(XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION >= 230000, \ + XTENSA_OPTION_ATOMCTL) | \ /* Interrupts and exceptions */ \ XCHAL_OPTION(XCHAL_HAVE_EXCEPTIONS, XTENSA_OPTION_EXCEPTION) | \ XCHAL_OPTION(XCHAL_HAVE_VECBASE, XTENSA_OPTION_RELOCATABLE_VECTOR) | \ diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c index 828b9cabb5..dc08de51ba 100644 --- a/target-xtensa/translate.c +++ b/target-xtensa/translate.c @@ -99,6 +99,7 @@ static const char * const sregnames[256] = { [ITLBCFG] = "ITLBCFG", [DTLBCFG] = "DTLBCFG", [IBREAKENABLE] = "IBREAKENABLE", + [ATOMCTL] = "ATOMCTL", [IBREAKA] = "IBREAKA0", [IBREAKA + 1] = "IBREAKA1", [DBREAKA] = "DBREAKA0", @@ -556,6 +557,11 @@ static void gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) gen_jumpi_check_loop_end(dc, 0); } +static void gen_wsr_atomctl(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ + tcg_gen_andi_i32(cpu_SR[sr], v, 0x3f); +} + static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) { unsigned id = sr - IBREAKA; @@ -693,6 +699,7 @@ static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) [ITLBCFG] = gen_wsr_tlbcfg, [DTLBCFG] = gen_wsr_tlbcfg, [IBREAKENABLE] = gen_wsr_ibreakenable, + [ATOMCTL] = gen_wsr_atomctl, [IBREAKA] = gen_wsr_ibreaka, [IBREAKA + 1] = gen_wsr_ibreaka, [DBREAKA] = gen_wsr_dbreaka, @@ -2317,10 +2324,15 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) int label = gen_new_label(); TCGv_i32 tmp = tcg_temp_local_new_i32(); TCGv_i32 addr = tcg_temp_local_new_i32(); + TCGv_i32 tpc; tcg_gen_mov_i32(tmp, cpu_R[RRI8_T]); tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); gen_load_store_alignment(dc, 2, addr, true); + + gen_advance_ccount(dc); + tpc = tcg_const_i32(dc->pc); + gen_helper_check_atomctl(cpu_env, tpc, addr); tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring); tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[RRI8_T], cpu_SR[SCOMPARE1], label); @@ -2328,6 +2340,7 @@ static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) tcg_gen_qemu_st32(tmp, addr, dc->cring); gen_set_label(label); + tcg_temp_free(tpc); tcg_temp_free(addr); tcg_temp_free(tmp); } |