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/op_helper.c | |
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/op_helper.c')
-rw-r--r-- | target-xtensa/op_helper.c | 57 |
1 files changed, 57 insertions, 0 deletions
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; |