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

@ -314,6 +314,17 @@ static void output_i_rr(DisasContext *ctx, arg_i_rr *a, const char *mnemonic)
output(ctx, mnemonic, "%d, r%d, r%d", a->imm, a->rj, a->rk);
}
static void output_cop_r_i(DisasContext *ctx, arg_cop_r_i *a,
const char *mnemonic)
{
output(ctx, mnemonic, "%d, r%d, %d", a->cop, a->rj, a->imm);
}
static void output_j_i(DisasContext *ctx, arg_j_i *a, const char *mnemonic)
{
output(ctx, mnemonic, "r%d, %d", a->rj, a->imm);
}
#define INSN(insn, type) \
static bool trans_##insn(DisasContext *ctx, arg_##type * a) \
{ \
@ -641,6 +652,12 @@ INSN(tlbfill, empty)
INSN(tlbclr, empty)
INSN(tlbflush, empty)
INSN(invtlb, i_rr)
INSN(cacop, cop_r_i)
INSN(lddir, rr_i)
INSN(ldpte, j_i)
INSN(ertn, empty)
INSN(idle, i)
INSN(dbcl, i)
#define output_fcmp(C, PREFIX, SUFFIX) \
{ \

View File

@ -121,3 +121,8 @@ DEF_HELPER_2(invtlb_all_g, void, env, i32)
DEF_HELPER_2(invtlb_all_asid, void, env, tl)
DEF_HELPER_3(invtlb_page_asid, void, env, tl, tl)
DEF_HELPER_3(invtlb_page_asid_or_g, void, env, tl, tl)
DEF_HELPER_4(lddir, tl, env, tl, tl, i32)
DEF_HELPER_4(ldpte, void, env, tl, tl, i32)
DEF_HELPER_1(ertn, void, env)
DEF_HELPER_1(idle, void, env)

View File

@ -399,3 +399,68 @@ static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
ctx->base.is_jmp = DISAS_STOP;
return true;
}
static bool trans_cacop(DisasContext *ctx, arg_cacop *a)
{
/* Treat the cacop as a nop */
if (check_plv(ctx)) {
return false;
}
return true;
}
static bool trans_ldpte(DisasContext *ctx, arg_ldpte *a)
{
TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx);
TCGv src1 = gpr_src(ctx, a->rj, EXT_NONE);
if (check_plv(ctx)) {
return false;
}
gen_helper_ldpte(cpu_env, src1, tcg_constant_tl(a->imm), mem_idx);
return true;
}
static bool trans_lddir(DisasContext *ctx, arg_lddir *a)
{
TCGv_i32 mem_idx = tcg_constant_i32(ctx->mem_idx);
TCGv src = gpr_src(ctx, a->rj, EXT_NONE);
TCGv dest = gpr_dst(ctx, a->rd, EXT_NONE);
if (check_plv(ctx)) {
return false;
}
gen_helper_lddir(dest, cpu_env, src, tcg_constant_tl(a->imm), mem_idx);
return true;
}
static bool trans_ertn(DisasContext *ctx, arg_ertn *a)
{
if (check_plv(ctx)) {
return false;
}
gen_helper_ertn(cpu_env);
ctx->base.is_jmp = DISAS_EXIT;
return true;
}
static bool trans_dbcl(DisasContext *ctx, arg_dbcl *a)
{
if (check_plv(ctx)) {
return false;
}
generate_exception(ctx, EXCCODE_DBP);
return true;
}
static bool trans_idle(DisasContext *ctx, arg_idle *a)
{
if (check_plv(ctx)) {
return false;
}
tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
gen_helper_idle(cpu_env);
ctx->base.is_jmp = DISAS_NORETURN;
return true;
}

View File

@ -49,6 +49,8 @@
&rr_csr rd rj csr
&empty
&i_rr imm rj rk
&cop_r_i cop rj imm
&j_i rj imm
#
# Formats
@ -60,6 +62,7 @@
@r_i20 .... ... imm:s20 rd:5 &r_i
@rr_ui5 .... ........ ..... imm:5 rj:5 rd:5 &rr_i
@rr_ui6 .... ........ .... imm:6 rj:5 rd:5 &rr_i
@rr_ui8 .. ........ .... imm:8 rj:5 rd:5 &rr_i
@rr_i12 .... ...... imm:s12 rj:5 rd:5 &rr_i
@rr_ui12 .... ...... imm:12 rj:5 rd:5 &rr_i
@rr_i14s2 .... .... .............. rj:5 rd:5 &rr_i imm=%i14s2
@ -93,6 +96,8 @@
@rr_csr .... .... csr:14 rj:5 rd:5 &rr_csr
@empty .... ........ ..... ..... ..... ..... &empty
@i_rr ...... ...... ..... rk:5 rj:5 imm:5 &i_rr
@cop_r_i .... ...... imm:s12 rj:5 cop:5 &cop_r_i
@j_i .... ........ .. imm:8 rj:5 ..... &j_i
#
# Fixed point arithmetic operation instruction
@ -470,3 +475,9 @@ tlbfill 0000 01100100 10000 01101 00000 00000 @empty
tlbclr 0000 01100100 10000 01000 00000 00000 @empty
tlbflush 0000 01100100 10000 01001 00000 00000 @empty
invtlb 0000 01100100 10011 ..... ..... ..... @i_rr
cacop 0000 011000 ............ ..... ..... @cop_r_i
lddir 0000 01100100 00 ........ ..... ..... @rr_ui8
ldpte 0000 01100100 01 ........ ..... 00000 @j_i
ertn 0000 01100100 10000 01110 00000 00000 @empty
idle 0000 01100100 10001 ............... @i15
dbcl 0000 00000010 10101 ............... @i15

View File

@ -16,6 +16,11 @@
#define TARGET_PHYS_MASK MAKE_64BIT_MASK(0, TARGET_PHYS_ADDR_SPACE_BITS)
#define TARGET_VIRT_MASK MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS)
/* Global bit used for lddir/ldpte */
#define LOONGARCH_PAGE_HUGE_SHIFT 6
/* Global bit for huge page */
#define LOONGARCH_HGLOBAL_SHIFT 12
void loongarch_translate_init(void);
void loongarch_cpu_dump_state(CPUState *cpu, FILE *f, int flags);

View File

@ -6,6 +6,7 @@
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "cpu.h"
#include "qemu/host-utils.h"
@ -15,6 +16,7 @@
#include "internals.h"
#include "qemu/crc32c.h"
#include <zlib.h>
#include "cpu-csr.h"
/* Exceptions helpers */
void helper_raise_exception(CPULoongArchState *env, uint32_t exception)
@ -81,3 +83,38 @@ target_ulong helper_cpucfg(CPULoongArchState *env, target_ulong rj)
{
return rj > 21 ? 0 : env->cpucfg[rj];
}
void helper_ertn(CPULoongArchState *env)
{
uint64_t csr_pplv, csr_pie;
if (FIELD_EX64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR)) {
csr_pplv = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PPLV);
csr_pie = FIELD_EX64(env->CSR_TLBRPRMD, CSR_TLBRPRMD, PIE);
env->CSR_TLBRERA = FIELD_DP64(env->CSR_TLBRERA, CSR_TLBRERA, ISTLBR, 0);
env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, DA, 0);
env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PG, 1);
env->pc = env->CSR_TLBRERA;
qemu_log_mask(CPU_LOG_INT, "%s: TLBRERA " TARGET_FMT_lx "\n",
__func__, env->CSR_TLBRERA);
} else {
csr_pplv = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PPLV);
csr_pie = FIELD_EX64(env->CSR_PRMD, CSR_PRMD, PIE);
env->pc = env->CSR_ERA;
qemu_log_mask(CPU_LOG_INT, "%s: ERA " TARGET_FMT_lx "\n",
__func__, env->CSR_ERA);
}
env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, PLV, csr_pplv);
env->CSR_CRMD = FIELD_DP64(env->CSR_CRMD, CSR_CRMD, IE, csr_pie);
env->lladdr = 1;
}
void helper_idle(CPULoongArchState *env)
{
CPUState *cs = env_cpu(env);
cs->halted = 1;
do_raise_exception(env, EXCP_HLT, 0);
}

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);
}