Skip to content

Commit

Permalink
target-xtensa: implement ATOMCTL SR
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
jcmvbkbc authored and blueswirl committed Dec 8, 2012
1 parent 536b558 commit fcc803d
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 14 deletions.
2 changes: 2 additions & 0 deletions target-xtensa/cpu.c
Expand Up @@ -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);
Expand Down
10 changes: 10 additions & 0 deletions target-xtensa/cpu.h
Expand Up @@ -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,
Expand Down Expand Up @@ -128,6 +129,7 @@ enum {
ITLBCFG = 91,
DTLBCFG = 92,
IBREAKENABLE = 96,
ATOMCTL = 99,
IBREAKA = 128,
DBREAKA = 144,
DBREAKC = 160,
Expand Down Expand Up @@ -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,
Expand Down
56 changes: 42 additions & 14 deletions target-xtensa/helper.c
Expand Up @@ -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) {
Expand All @@ -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;
}
Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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");
}
}
}
Expand Down
1 change: 1 addition & 0 deletions target-xtensa/helper.h
Expand Up @@ -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)
Expand Down
57 changes: 57 additions & 0 deletions target-xtensa/op_helper.c
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions target-xtensa/overlay_tool.h
Expand Up @@ -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 ( \
Expand All @@ -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) | \
Expand Down
13 changes: 13 additions & 0 deletions target-xtensa/translate.c
Expand Up @@ -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",
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -2317,17 +2324,23 @@ 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);

tcg_gen_qemu_st32(tmp, addr, dc->cring);

gen_set_label(label);
tcg_temp_free(tpc);
tcg_temp_free(addr);
tcg_temp_free(tmp);
}
Expand Down

0 comments on commit fcc803d

Please sign in to comment.