target/hppa: Implement IDTLBT, IITLBT

Rename the existing insert tlb helpers to emphasize that they
are for pa1.1 cpus.  Implement a combined i/d tlb for pa2.0.
Still missing is the new 'P' tlb bit.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2023-10-12 17:55:12 -07:00
parent 25460fc5a7
commit 8577f35479
4 changed files with 100 additions and 13 deletions

View File

@ -94,8 +94,10 @@ DEF_HELPER_FLAGS_2(write_interval_timer, TCG_CALL_NO_RWG, void, env, tr)
DEF_HELPER_FLAGS_2(write_eirr, TCG_CALL_NO_RWG, void, env, tr)
DEF_HELPER_FLAGS_2(write_eiem, TCG_CALL_NO_RWG, void, env, tr)
DEF_HELPER_FLAGS_2(swap_system_mask, TCG_CALL_NO_RWG, tr, env, tr)
DEF_HELPER_FLAGS_3(itlba, TCG_CALL_NO_RWG, void, env, tl, tr)
DEF_HELPER_FLAGS_3(itlbp, TCG_CALL_NO_RWG, void, env, tl, tr)
DEF_HELPER_FLAGS_3(itlba_pa11, TCG_CALL_NO_RWG, void, env, tl, tr)
DEF_HELPER_FLAGS_3(itlbp_pa11, TCG_CALL_NO_RWG, void, env, tl, tr)
DEF_HELPER_FLAGS_3(idtlbt_pa20, TCG_CALL_NO_RWG, void, env, tr, tr)
DEF_HELPER_FLAGS_3(iitlbt_pa20, TCG_CALL_NO_RWG, void, env, tr, tr)
DEF_HELPER_FLAGS_2(ptlb, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_1(ptlbe, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_2(lpa, TCG_CALL_NO_WG, tr, env, tl)

View File

@ -145,6 +145,7 @@ nop_addrx 000001 ..... ..... -- 01001110 . 00000 @addrx # pdc
probe 000001 b:5 ri:5 sp:2 imm:1 100011 write:1 0 t:5
# pa1.x tlb insert instructions
ixtlbx 000001 b:5 r:5 sp:2 0100000 addr:1 0 00000 data=1
ixtlbx 000001 b:5 r:5 ... 000000 addr:1 0 00000 \
sp=%assemble_sr3x data=0
@ -152,6 +153,9 @@ ixtlbx 000001 b:5 r:5 ... 000000 addr:1 0 00000 \
# pcxl and pcxl2 Fast TLB Insert instructions
ixtlbxf 000001 00000 r:5 00 0 data:1 01000 addr:1 0 00000
# pa2.0 tlb insert idtlbt and iitlbt instructions
ixtlbt 000001 r2:5 r1:5 000 data:1 100000 0 00000 # idtlbt
pxtlbx 000001 b:5 x:5 sp:2 0100100 local:1 m:1 ----- data=1
pxtlbx 000001 b:5 x:5 ... 000100 local:1 m:1 ----- \
sp=%assemble_sr3x data=0

View File

@ -344,7 +344,7 @@ bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
}
/* Insert (Insn/Data) TLB Address. Note this is PA 1.1 only. */
void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
void HELPER(itlba_pa11)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
{
HPPATLBEntry *ent;
@ -365,7 +365,8 @@ void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
trace_hppa_tlb_itlba(env, ent, ent->itree.start, ent->itree.last, ent->pa);
}
static void set_access_bits(CPUHPPAState *env, HPPATLBEntry *ent, target_ureg reg)
static void set_access_bits_pa11(CPUHPPAState *env, HPPATLBEntry *ent,
target_ureg reg)
{
ent->access_id = extract32(reg, 1, 18);
ent->u = extract32(reg, 19, 1);
@ -383,20 +384,70 @@ static void set_access_bits(CPUHPPAState *env, HPPATLBEntry *ent, target_ureg re
}
/* Insert (Insn/Data) TLB Protection. Note this is PA 1.1 only. */
void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
void HELPER(itlbp_pa11)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
{
HPPATLBEntry *ent = env->tlb_partial;
if (ent) {
env->tlb_partial = NULL;
if (ent->itree.start <= addr && addr <= ent->itree.last) {
set_access_bits(env, ent, reg);
set_access_bits_pa11(env, ent, reg);
return;
}
}
qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n");
}
static void itlbt_pa20(CPUHPPAState *env, target_ureg r1,
target_ureg r2, vaddr va_b)
{
HPPATLBEntry *ent;
vaddr va_e;
uint64_t va_size;
int mask_shift;
mask_shift = 2 * (r1 & 0xf);
va_size = TARGET_PAGE_SIZE << mask_shift;
va_b &= -va_size;
va_e = va_b + va_size - 1;
hppa_flush_tlb_range(env, va_b, va_e);
ent = hppa_alloc_tlb_ent(env);
ent->itree.start = va_b;
ent->itree.last = va_e;
ent->pa = (r1 << 7) & (TARGET_PAGE_MASK << mask_shift);
ent->t = extract64(r2, 61, 1);
ent->d = extract64(r2, 60, 1);
ent->b = extract64(r2, 59, 1);
ent->ar_type = extract64(r2, 56, 3);
ent->ar_pl1 = extract64(r2, 54, 2);
ent->ar_pl2 = extract64(r2, 52, 2);
ent->u = extract64(r2, 51, 1);
/* o = bit 50 */
/* p = bit 49 */
ent->access_id = extract64(r2, 1, 31);
ent->entry_valid = 1;
interval_tree_insert(&ent->itree, &env->tlb_root);
trace_hppa_tlb_itlba(env, ent, ent->itree.start, ent->itree.last, ent->pa);
trace_hppa_tlb_itlbp(env, ent, ent->access_id, ent->u,
ent->ar_pl2, ent->ar_pl1, ent->ar_type,
ent->b, ent->d, ent->t);
}
void HELPER(idtlbt_pa20)(CPUHPPAState *env, target_ureg r1, target_ureg r2)
{
vaddr va_b = deposit64(env->cr[CR_IOR], 32, 32, env->cr[CR_ISR]);
itlbt_pa20(env, r1, r2, va_b);
}
void HELPER(iitlbt_pa20)(CPUHPPAState *env, target_ureg r1, target_ureg r2)
{
vaddr va_b = deposit64(env->cr[CR_IIAOQ], 32, 32, env->cr[CR_IIASQ]);
itlbt_pa20(env, r1, r2, va_b);
}
/* Purge (Insn/Data) TLB. This is explicitly page-based, and is
synchronous across all processors. */
static void ptlb_work(CPUState *cpu, run_on_cpu_data data)
@ -563,7 +614,7 @@ void HELPER(diag_btlb)(CPUHPPAState *env)
btlb->itree.start = virt_page << TARGET_PAGE_BITS;
btlb->itree.last = btlb->itree.start + len * TARGET_PAGE_SIZE - 1;
btlb->pa = phys_page << TARGET_PAGE_BITS;
set_access_bits(env, btlb, env->gr[20]);
set_access_bits_pa11(env, btlb, env->gr[20]);
btlb->t = 0;
btlb->d = 1;
} else {

View File

@ -2514,6 +2514,9 @@ static bool trans_probe(DisasContext *ctx, arg_probe *a)
static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
{
if (ctx->is_pa20) {
return false;
}
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
#ifndef CONFIG_USER_ONLY
TCGv_tl addr;
@ -2524,9 +2527,9 @@ static bool trans_ixtlbx(DisasContext *ctx, arg_ixtlbx *a)
form_gva(ctx, &addr, &ofs, a->b, 0, 0, 0, a->sp, 0, false);
reg = load_gpr(ctx, a->r);
if (a->addr) {
gen_helper_itlba(tcg_env, addr, reg);
gen_helper_itlba_pa11(tcg_env, addr, reg);
} else {
gen_helper_itlbp(tcg_env, addr, reg);
gen_helper_itlbp_pa11(tcg_env, addr, reg);
}
/* Exit TB for TLB change if mmu is enabled. */
@ -2572,6 +2575,9 @@ static bool trans_pxtlbx(DisasContext *ctx, arg_pxtlbx *a)
*/
static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
{
if (ctx->is_pa20) {
return false;
}
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
#ifndef CONFIG_USER_ONLY
TCGv_tl addr, atl, stl;
@ -2583,8 +2589,6 @@ static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
* FIXME:
* if (not (pcxl or pcxl2))
* return gen_illegal(ctx);
*
* Note for future: these are 32-bit systems; no hppa64.
*/
atl = tcg_temp_new_tl();
@ -2602,9 +2606,9 @@ static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
reg = load_gpr(ctx, a->r);
if (a->addr) {
gen_helper_itlba(tcg_env, addr, reg);
gen_helper_itlba_pa11(tcg_env, addr, reg);
} else {
gen_helper_itlbp(tcg_env, addr, reg);
gen_helper_itlbp_pa11(tcg_env, addr, reg);
}
/* Exit TB for TLB change if mmu is enabled. */
@ -2615,6 +2619,32 @@ static bool trans_ixtlbxf(DisasContext *ctx, arg_ixtlbxf *a)
#endif
}
static bool trans_ixtlbt(DisasContext *ctx, arg_ixtlbt *a)
{
if (!ctx->is_pa20) {
return false;
}
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);
#ifndef CONFIG_USER_ONLY
nullify_over(ctx);
{
TCGv_i64 src1 = load_gpr(ctx, a->r1);
TCGv_i64 src2 = load_gpr(ctx, a->r2);
if (a->data) {
gen_helper_idtlbt_pa20(tcg_env, src1, src2);
} else {
gen_helper_iitlbt_pa20(tcg_env, src1, src2);
}
}
/* Exit TB for TLB change if mmu is enabled. */
if (ctx->tb_flags & PSW_C) {
ctx->base.is_jmp = DISAS_IAQ_N_STALE;
}
return nullify_end(ctx);
#endif
}
static bool trans_lpa(DisasContext *ctx, arg_ldst *a)
{
CHECK_MOST_PRIVILEGED(EXCP_PRIV_OPR);