target/loongarch: Add other core instructions support

This includes:
-CACOP
-LDDIR
-LDPTE
-ERTN
-DBCL
-IDLE

Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
Signed-off-by: Song Gao <gaosong@loongson.cn>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20220606124333.2060567-29-yangxiaojuan@loongson.cn>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Xiaojuan Yang 2022-06-06 20:43:18 +08:00 committed by Richard Henderson
parent fcbbeb8ecd
commit d2cba6f7ce
7 changed files with 233 additions and 0 deletions

View file

@ -668,3 +668,96 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
raise_mmu_exception(env, address, access_type, ret);
cpu_loop_exit_restore(cs, retaddr);
}
target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
target_ulong level, uint32_t mem_idx)
{
CPUState *cs = env_cpu(env);
target_ulong badvaddr, index, phys, ret;
int shift;
uint64_t dir_base, dir_width;
bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1;
badvaddr = env->CSR_TLBRBADV;
base = base & TARGET_PHYS_MASK;
/* 0:64bit, 1:128bit, 2:192bit, 3:256bit */
shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH);
shift = (shift + 1) * 3;
if (huge) {
return base;
}
switch (level) {
case 1:
dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE);
dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH);
break;
case 2:
dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE);
dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH);
break;
case 3:
dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE);
dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH);
break;
case 4:
dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE);
dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH);
break;
default:
do_raise_exception(env, EXCCODE_INE, GETPC());
return 0;
}
index = (badvaddr >> dir_base) & ((1 << dir_width) - 1);
phys = base | index << shift;
ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
return ret;
}
void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
uint32_t mem_idx)
{
CPUState *cs = env_cpu(env);
target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv;
int shift;
bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1;
uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE);
uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH);
base = base & TARGET_PHYS_MASK;
if (huge) {
/* Huge Page. base is paddr */
tmp0 = base ^ (1 << LOONGARCH_PAGE_HUGE_SHIFT);
/* Move Global bit */
tmp0 = ((tmp0 & (1 << LOONGARCH_HGLOBAL_SHIFT)) >>
LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT |
(tmp0 & (~(1 << R_TLBENTRY_G_SHIFT)));
ps = ptbase + ptwidth - 1;
if (odd) {
tmp0 += (1 << ps);
}
} else {
/* 0:64bit, 1:128bit, 2:192bit, 3:256bit */
shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH);
shift = (shift + 1) * 3;
badv = env->CSR_TLBRBADV;
ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1);
ptindex = ptindex & ~0x1; /* clear bit 0 */
ptoffset0 = ptindex << shift;
ptoffset1 = (ptindex + 1) << shift;
phys = base | (odd ? ptoffset1 : ptoffset0);
tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
ps = ptbase;
}
if (odd) {
env->CSR_TLBRELO1 = tmp0;
} else {
env->CSR_TLBRELO0 = tmp0;
}
env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, PS, ps);
}