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>
This commit is contained in:
parent
536b558f58
commit
fcc803d119
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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) | \
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user