Commit bb41e74b authored by Fredrik Noring's avatar Fredrik Noring Committed by Aleksandar Markovic
Browse files

target/mips: Add a placeholder for R5900 SQ, handle user mode RDHWR



Add placeholder for SQ instruction, handle RDHWR.

Reviewed-by: default avatarAleksandar Markovic <amarkovic@wavecomp.com>
Signed-off-by: default avatarFredrik Noring <noring@nocrew.org>
Signed-off-by: default avatarAleksandar Markovic <amarkovic@wavecomp.com>
parent dd581bf9
Loading
Loading
Loading
Loading
+52 −1
Original line number Diff line number Diff line
@@ -24420,6 +24420,53 @@ static void decode_opc_special3_legacy(CPUMIPSState *env, DisasContext *ctx)
    }
}
static void gen_tx79_sq(DisasContext *ctx, int base, int rt, int offset)
{
    generate_exception_end(ctx, EXCP_RI);    /* TODO: TX79_SQ */
}
/*
 * The TX79-specific instruction Store Quadword
 *
 * +--------+-------+-------+------------------------+
 * | 011111 |  base |   rt  |           offset       | SQ
 * +--------+-------+-------+------------------------+
 *      6       5       5                 16
 *
 * has the same opcode as the Read Hardware Register instruction
 *
 * +--------+-------+-------+-------+-------+--------+
 * | 011111 | 00000 |   rt  |   rd  | 00000 | 111011 | RDHWR
 * +--------+-------+-------+-------+-------+--------+
 *      6       5       5       5       5        6
 *
 * that is required, trapped and emulated by the Linux kernel. However, all
 * RDHWR encodings yield address error exceptions on the TX79 since the SQ
 * offset is odd. Therefore all valid SQ instructions can execute normally.
 * In user mode, QEMU must verify the upper and lower 11 bits to distinguish
 * between SQ and RDHWR, as the Linux kernel does.
 */
static void decode_tx79_sq(CPUMIPSState *env, DisasContext *ctx)
{
    int base = extract32(ctx->opcode, 21, 5);
    int rt = extract32(ctx->opcode, 16, 5);
    int offset = extract32(ctx->opcode, 0, 16);
#ifdef CONFIG_USER_ONLY
    uint32_t op1 = MASK_SPECIAL3(ctx->opcode);
    uint32_t op2 = extract32(ctx->opcode, 6, 5);
    if (base == 0 && op2 == 0 && op1 == OPC_RDHWR) {
        int rd = extract32(ctx->opcode, 11, 5);
        gen_rdhwr(ctx, rt, rd, 0);
        return;
    }
#endif
    gen_tx79_sq(ctx, base, rt, offset);
}
static void decode_opc_special3(CPUMIPSState *env, DisasContext *ctx)
{
    int rs, rt, rd, sa;
@@ -25720,7 +25767,11 @@ static void decode_opc(CPUMIPSState *env, DisasContext *ctx)
        decode_opc_special2_legacy(env, ctx);
        break;
    case OPC_SPECIAL3:
        if (ctx->insn_flags & INSN_R5900) {
            decode_tx79_sq(env, ctx);    /* TX79_SQ */
        } else {
            decode_opc_special3(env, ctx);
        }
        break;
    case OPC_REGIMM:
        op1 = MASK_REGIMM(ctx->opcode);