qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Add minimal Hexagon target - First in a series of patches -


From: Richard Henderson
Subject: Re: [PATCH] Add minimal Hexagon target - First in a series of patches - linux-user changes + linux-user/hexagon + skeleton of target/hexagon - Files in target/hexagon/imported are from another project and therefore do not conform to qemu coding standards
Date: Tue, 19 Nov 2019 20:33:59 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.9.0

On 11/19/19 12:58 AM, Taylor Simpson wrote:
> +static abi_ulong get_sigframe(struct target_sigaction *ka,
> +                              CPUHexagonState *regs, size_t framesize)
> +{
> +    abi_ulong sp = get_sp_from_cpustate(regs);
> +
> +    /* This is the X/Open sanctioned signal stack switching.  */
> +    sp = target_sigsp(sp, ka) - framesize;
> +
> +    sp &= ~7UL; /* align sp on 8-byte boundary */

QEMU_ALIGN_DOWN.

> diff --git a/linux-user/hexagon/sockbits.h b/linux-user/hexagon/sockbits.h
> new file mode 100644
> index 0000000..85bd64a
> --- /dev/null
> +++ b/linux-user/hexagon/sockbits.h
> @@ -0,0 +1,3 @@
> +/* Copyright (c) 2019 Qualcomm Innovation Center, Inc. All Rights Reserved. 
> */
> +
> +#include "../generic/sockbits.h"

All new files should have denote their license.

> +static inline const char *cpu_get_model(uint32_t eflags)
> +{
> +    /* For now, treat anything newer than v60 as a v67 */
> +    /* FIXME - Disable instructions that are newer than the specified arch */
> +    if (eflags == 0x04 ||    /* v5  */
> +        eflags == 0x05 ||    /* v55 */
> +        eflags == 0x60 ||    /* v60 */
> +        eflags == 0x61 ||    /* v61 */
> +        eflags == 0x62 ||    /* v62 */
> +        eflags == 0x65 ||    /* v65 */
> +        eflags == 0x66 ||    /* v66 */
> +        eflags == 0x67) {    /* v67 */
> +        return "v67";
> +    }
> +    printf("eflags = 0x%x\n", eflags);

Left over debug.

> diff --git a/target/hexagon/Makefile.objs b/target/hexagon/Makefile.objs
> new file mode 100644
> index 0000000..dfab6ee
> --- /dev/null
> +++ b/target/hexagon/Makefile.objs
> @@ -0,0 +1,6 @@
> +obj-y += \
> +    cpu.o \
> +    translate.o \
> +    op_helper.o
> +
> +CFLAGS += -I$(SRC_PATH)/target/hexagon/imported

Is this really better than

#include "imported/global_types.h"

etc?

> +++ b/target/hexagon/cpu-param.h
> @@ -0,0 +1,11 @@
> +/* Copyright (c) 2019 Qualcomm Innovation Center, Inc. All Rights Reserved. 
> */
> +
> +
> +#ifndef HEXAGON_CPU_PARAM_H
> +#define HEXAGON_CPU_PARAM_H
> +
> +# define TARGET_PHYS_ADDR_SPACE_BITS 36

Watch your spacing.

Does this really compile without TARGET_VIRT_ADDR_SPACE_BITS?

It's used in linux-user/main.c, but I suppose in a way that
the preprocessor interprets it as 0.

> +const char * const hexagon_prednames[] = {
> +  "p0 ", "p1 ", "p2 ", "p3 "
> +};

Inter-string spacing probably belongs to the format not the name.

> +static inline target_ulong hack_stack_ptrs(CPUHexagonState *env,
> +                                           target_ulong addr)
> +{
> +    target_ulong stack_start = env->stack_start;
> +    target_ulong stack_size = 0x10000;
> +    target_ulong stack_adjust = env->stack_adjust;
> +
> +    if (stack_start + 0x1000 >= addr && addr >= (stack_start - stack_size)) {
> +        return addr - stack_adjust;
> +    }
> +    return addr;
> +}

An explanation would be welcome here.

> +static void hexagon_dump(CPUHexagonState *env, FILE *f)
> +{
> +    static target_ulong last_pc;
> +    int i;
> +
> +    /*
> +     * When comparing with LLDB, it doesn't step through single-cycle
> +     * hardware loops the same way.  So, we just skip them here
> +     */
> +    if (env->gpr[HEX_REG_PC] == last_pc) {
> +        return;
> +    }

This seems mis-placed.

> +#ifdef FIXME
> +    /*
> +     * LLDB bug swaps gp and ugp
> +     * FIXME when the LLDB bug is fixed
> +     */
> +    print_reg(f, env, HEX_REG_GP);
> +    print_reg(f, env, HEX_REG_UGP);
> +#else
> +    fprintf(f, "  %s = 0x" TARGET_FMT_lx "\n",
> +        hexagon_regnames[HEX_REG_GP],
> +        hack_stack_ptrs(env, env->gpr[HEX_REG_UGP]));
> +    fprintf(f, "  %s = 0x" TARGET_FMT_lx "\n",
> +        hexagon_regnames[HEX_REG_UGP],
> +        hack_stack_ptrs(env, env->gpr[HEX_REG_GP]));
> +#endif
> +    print_reg(f, env, HEX_REG_PC);
> +#ifdef FIXME
> +    /*
> +     * Not modelled in qemu, print junk to minimize the diff's
> +     * with LLDB output
> +     */
> +    print_reg(f, env, HEX_REG_CAUSE);
> +    print_reg(f, env, HEX_REG_BADVA);
> +    print_reg(f, env, HEX_REG_CS0);
> +    print_reg(f, env, HEX_REG_CS1);
> +#else
> +    fprintf(f, "  cause = 0x000000db\n");
> +    fprintf(f, "  badva = 0x00000000\n");
> +    fprintf(f, "  cs0 = 0x00000000\n");
> +    fprintf(f, "  cs1 = 0x00000000\n");
> +#endif

Need we retain the fixme?

> +void hexagon_debug(CPUHexagonState *env)
> +{
> +    hexagon_dump(env, stdout);
> +}

Is this to be called from the debugger?  From what location did you find it
useful?  There are only certain locations in tcg that are self-consistent...

> +    DEFINE_CPU(TYPE_HEXAGON_CPU_V67,              hexagon_v67_cpu_init),

Spacing?

> +#ifndef HEXAGON_CPU_H
> +#define HEXAGON_CPU_H
> +
> +/* FIXME - Change this to a command-line option */
> +#ifdef FIXME
> +#define DEBUG_HEX
> +#endif
> +#ifdef FIXME
> +#define COUNT_HEX_HELPERS
> +#endif

Eh?

> +
> +/* Forward declaration needed by some of the header files */
> +typedef struct CPUHexagonState CPUHexagonState;
> +
> +#include <fenv.h>
> +#include "qemu/osdep.h"

osdep.h should already have been included.
Indeed, it must be first for *.c files.

Why do you need fenv.h?

> +#include "global_types.h"
> +#include "max.h"
> +#include "iss_ver_registers.h"
> +
> +#define TARGET_PAGE_BITS 16     /* 64K pages */
> +/*
> + * For experimenting with oslib (4K pages)
> + * #define TARGET_PAGE_BITS 12
> + */
> +#define TARGET_LONG_BITS 32
> +#define TARGET_VIRT_ADDR_SPACE_BITS 32

Ah, to answer my earlier question, these belong to cpu-param.h.
Drop the "experimenting" comment.

> +
> +#include <time.h>

time.h is included by osdep.h.


> +#include "qemu/compiler.h"
> +#include "qemu-common.h"
> +#include "exec/cpu-defs.h"
> +#include "regs.h"
> +
> +#define TYPE_HEXAGON_CPU "hexagon-cpu"
> +
> +#define HEXAGON_CPU_TYPE_SUFFIX "-" TYPE_HEXAGON_CPU
> +#define HEXAGON_CPU_TYPE_NAME(name) (name HEXAGON_CPU_TYPE_SUFFIX)
> +#define CPU_RESOLVING_TYPE TYPE_HEXAGON_CPU
> +
> +#define TYPE_HEXAGON_CPU_V67             HEXAGON_CPU_TYPE_NAME("v67")
> +
> +#define MMU_USER_IDX 0
> +
> +#define TRANSLATE_FAIL 1
> +#define TRANSLATE_SUCCESS 0

What's this for?  This looks like it's cribbed from riscv,
which oddly doesn't match the actual tlb_fill interface,
which uses bool true for success.

> +
> +struct MemLog {
> +    vaddr_t va;
> +    size1u_t width;
> +    size4u_t data32;
> +    size8u_t data64;
> +};

Is this part of translation?  Maybe save this til you
actually use it, and probably place in translate.h.

> +    /* For comparing with LLDB on target - see hack_stack_ptrs function */
> +    target_ulong stack_start;
> +    target_ulong stack_adjust;

Which, as you recall, doesn't actually have any commentary.

> +extern const char * const hexagon_regnames[];
> +extern const char * const hexagon_prednames[];

Do these actually need declaring here?
Let's keep them private to cpu.c otherwise.

> +#define ENV_GET_CPU(e)  CPU(hexagon_env_get_cpu(e))
> +#define ENV_OFFSET      offsetof(HexagonCPU, env)

Obsolete. Remove.

> +int hexagon_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
> +int hexagon_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);

Move these decls to e.g. internal.h?
They're not relevant to generic users of cpu.h

> +void QEMU_NORETURN do_raise_exception_err(CPUHexagonState *env,
> +                                          uint32_t exception, uintptr_t pc);

Likewise.

> +void hexagon_translate_init(void);
> +void hexagon_debug(CPUHexagonState *env);
> +void hexagon_debug_vreg(CPUHexagonState *env, int regnum);
> +void hexagon_debug_qreg(CPUHexagonState *env, int regnum);

Likewise.

> +#ifdef COUNT_HEX_HELPERS
> +extern void print_helper_counts(void);
> +#endif

Likewise.

> +static void decode_packet(CPUHexagonState *env, DisasContext *ctx)
> +{
> +    size4u_t words[4];
> +    int i;
> +    /* Brute force way to make sure current PC is set */
> +    tcg_gen_movi_tl(hex_gpr[HEX_REG_PC], ctx->base.pc_next);

What's this for?

> +
> +    for (i = 0; i < 4; i++) {
> +        words[i] = cpu_ldl_code(env, ctx->base.pc_next + i * 
> sizeof(size4u_t));
> +    }

And this?

> +    /*
> +     * Brute force just enough to get the first program to execute.
> +     */
> +    switch (words[0]) {
> +    case 0x7800c806:                                /* r6 = #64 */
> +        tcg_gen_movi_tl(hex_gpr[6], 64);
> +        ctx->base.pc_next += 4;
> +        break;
> +    case 0x7800c020:                                /* r0 = #1 */
> +        tcg_gen_movi_tl(hex_gpr[0], 1);
> +        ctx->base.pc_next += 4;
> +        break;
> +    case 0x00044002:
> +        if (words[1] == 0x7800c001) {               /* r1 = ##0x400080 */
> +            tcg_gen_movi_tl(hex_gpr[1], 0x400080);
> +            ctx->base.pc_next += 8;
> +        } else {
> +            printf("ERROR: Unknown instruction 0x%x\n", words[1]);
> +            g_assert_not_reached();
> +        }
> +        break;
> +    case 0x7800c0e2:                                /* r2 = #7 */
> +        tcg_gen_movi_tl(hex_gpr[2], 7);
> +        ctx->base.pc_next += 4;
> +        break;
> +    case 0x5400c004:                               /* trap0(#1) */
> +    {
> +        TCGv excp_trap0 = tcg_const_tl(HEX_EXCP_TRAP0);
> +        gen_helper_raise_exception(cpu_env, excp_trap0);
> +        tcg_temp_free(excp_trap0);
> +        ctx->base.pc_next += 4;
> +        break;
> +    }
> +    case 0x7800cbc6:                               /* r6 = #94 */
> +        tcg_gen_movi_tl(hex_gpr[6], 94);
> +        ctx->base.pc_next += 4;
> +        break;
> +    case 0x7800cba6:                               /* r6 = #93 */
> +        tcg_gen_movi_tl(hex_gpr[6], 93);
> +        ctx->base.pc_next += 4;
> +        break;
> +    case 0x7800c000:                               /* r0 = #0 */
> +        tcg_gen_movi_tl(hex_gpr[0], 0);
> +        ctx->base.pc_next += 4;
> +        break;
> +    default:
> +        ctx->base.is_jmp = DISAS_TOO_MANY;
> +        ctx->base.pc_next += 4;
> +    }

I'm not especially keen on this, since it will just be removed in subsequent
patches.  The initial patch must compile, but it need not do *anything*
interesting.

C.f. 61766fe9e2d3 which is the initial commit for target/hppa, wherein the
decoder is

> +static ExitStatus translate_one(DisasContext *ctx, uint32_t insn)
> +{
> +    uint32_t opc = extract32(insn, 26, 6);
> +
> +    switch (opc) {
> +    default:
> +        break;
> +    }
> +    return gen_illegal(ctx);
> +}



> +}
> +
> +static void hexagon_tr_init_disas_context(DisasContextBase *dcbase,
> +                                          CPUState *cs)
> +{
> +    DisasContext *ctx = container_of(dcbase, DisasContext, base);
> +
> +    ctx->mem_idx = ctx->base.tb->flags & TB_FLAGS_MMU_MASK;

Since you're not initializing this in cpu_get_tb_cpu_state, you might as well
just use

    ctx->mem_idx = MMU_USER_IDX;

> +static void hexagon_tr_translate_packet(DisasContextBase *dcbase, CPUState 
> *cpu)
> +{
> +    DisasContext *ctx = container_of(dcbase, DisasContext, base);
> +    CPUHexagonState *env = cpu->env_ptr;
> +
> +    decode_packet(env, ctx);
> +
> +    if (ctx->base.is_jmp == DISAS_NEXT) {
> +        target_ulong page_start;
> +
> +        page_start = ctx->base.pc_first & TARGET_PAGE_MASK;
> +        if (ctx->base.pc_next - page_start >= TARGET_PAGE_SIZE) {
> +            ctx->base.is_jmp = DISAS_TOO_MANY;
> +        }
> +
> +#ifdef DEBUG_HEX
> +        /* When debugging, force the end of the TB after each packet */
> +        if (ctx->base.pc_next - ctx->base.pc_first >= 0x04) {
> +            ctx->base.is_jmp = DISAS_TOO_MANY;
> +        }
> +#endif
> +    }

As mentioned elsewhere, this latter should be handled by -singlestep.  The
generic translator loop will have set max_insns to 1.


r~



reply via email to

[Prev in Thread] Current Thread [Next in Thread]