Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SH4 Support #25

Draft
wants to merge 3 commits into
base: tracewrap-6.2.0
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions linux-user/sh4/trace_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#include "frame_arch.h"

const uint64_t frame_arch = frame_arch_sh;
const uint64_t frame_mach = frame_mach_sh4;
2 changes: 1 addition & 1 deletion qobject/block-qdict.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ void qdict_array_split(QDict *src, QList **dst)
*dst = qlist_new();

for (i = 0; i < UINT_MAX; i++) {
QObject *subqobj;
QObject *subqobj = NULL;
bool is_subqdict;
QDict *subqdict = NULL;
char indexstr[32], prefix[32];
Expand Down
9 changes: 9 additions & 0 deletions target/sh4/helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,12 @@ DEF_HELPER_FLAGS_2(ftrc_FT, TCG_CALL_NO_WG, i32, env, f32)
DEF_HELPER_FLAGS_2(ftrc_DT, TCG_CALL_NO_WG, i32, env, f64)
DEF_HELPER_3(fipr, void, env, i32, i32)
DEF_HELPER_2(ftrv, void, env, i32)

#ifdef HAS_TRACEWRAP
DEF_HELPER_1(trace_newframe, void, i32)
DEF_HELPER_2(trace_endframe, void, env, i32)
DEF_HELPER_2(trace_load_reg, void, i32, i32)
DEF_HELPER_2(trace_store_reg, void, i32, i32)
DEF_HELPER_3(trace_load_mem, void, i32, i32, i32)
DEF_HELPER_3(trace_store_mem, void, i32, i32, i32)
#endif /* HAS_TRACEWRAP */
4 changes: 4 additions & 0 deletions target/sh4/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ sh4_ss.add(files(
'translate.c',
))

if get_option('tracewrap')
sh4_ss.add(files('trace_helper.c'))
endif

sh4_softmmu_ss = ss.source_set()
sh4_softmmu_ss.add(files('monitor.c'))

Expand Down
117 changes: 117 additions & 0 deletions target/sh4/trace_helper.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#include "tracewrap.h"
#include "cpu.h"
#include "qemu/log.h"
#include "exec/helper-proto.h"
#include "exec/memop.h"
#include "qemu/log.h"

const char *regs[] = {
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
"r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b",
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "sr",
"gbr", "ssr", "spc", "sgr", "dbr", "vbr", "mach", "macl", "pr"
};
static const int reg_max = sizeof(regs) / sizeof(regs[0]);

void HELPER(trace_newframe)(target_ulong pc)
{
qemu_trace_newframe(pc, 0);
}

void HELPER(trace_endframe)(CPUSH4State *env, target_ulong old_pc)
{
qemu_trace_endframe(env, old_pc, 32);
}

OperandInfo * load_store_reg(uint32_t reg, uint32_t val, int ls)
{
RegOperand * ro = g_new(RegOperand,1);
reg_operand__init(ro);
ro->name = g_strdup(reg < reg_max ? regs[reg] : "UNKNOWN");

OperandInfoSpecific *ois = g_new(OperandInfoSpecific,1);
operand_info_specific__init(ois);
ois->reg_operand = ro;
OperandUsage *ou = g_new(OperandUsage,1);
operand_usage__init(ou);
if (ls == 0)
{
ou->read = 1;
} else {
ou->written = 1;
}
OperandInfo *oi = g_new(OperandInfo,1);
operand_info__init(oi);
oi->bit_length = 0;
oi->operand_info_specific = ois;
oi->operand_usage = ou;
oi->value.len = 4;
oi->value.data = g_malloc(oi->value.len);
memcpy(oi->value.data, &val, 4);
return oi;
}

void HELPER(trace_load_reg)(uint32_t reg, uint32_t val)
{
qemu_log("This register (r%d) was read. Value 0x%x\n", reg, val);

//r0 always reads 0
OperandInfo *oi = load_store_reg(reg, (reg != 0) ? val : 0, 0);

qemu_trace_add_operand(oi, 0x1);
}

void HELPER(trace_store_reg)(uint32_t reg, uint32_t val)
{
qemu_log("This register (r%d) was written. Value: 0x%x\n", reg, val);

OperandInfo *oi = load_store_reg(reg, val, 1);

qemu_trace_add_operand(oi, 0x2);
}

OperandInfo *load_store_mem(uint64_t addr, int ls, const void *data, size_t data_size) {
MemOperand * mo = g_new(MemOperand, 1);
mem_operand__init(mo);

mo->address = addr;

OperandInfoSpecific *ois = g_new(OperandInfoSpecific, 1);
operand_info_specific__init(ois);
ois->mem_operand = mo;

OperandUsage *ou = g_new(OperandUsage, 1);
operand_usage__init(ou);
if (ls == 0) {
ou->read = 1;
} else {
ou->written = 1;
}
OperandInfo *oi = g_new(OperandInfo, 1);
operand_info__init(oi);
oi->bit_length = data_size * 8;
oi->operand_info_specific = ois;
oi->operand_usage = ou;
oi->value.len = data_size;
oi->value.data = g_malloc(oi->value.len);
#ifdef BSWAP_NEEDED
memcpy_rev(oi->value.data, data, data_size);
#else
memcpy(oi->value.data, data, data_size);
#endif
return oi;
}

void HELPER(trace_load_mem)(uint32_t addr, uint32_t val, uint32_t op)
{
qemu_log("LOAD at 0x%lx size: %d data: 0x%lx\n", (unsigned long) addr, memop_size(op), (unsigned long) val);
OperandInfo *oi = load_store_mem(addr, 0, &val, memop_size(op));
qemu_trace_add_operand(oi, 0x1);
}

void HELPER(trace_store_mem)(uint32_t addr, uint32_t val, uint32_t op)
{
qemu_log("STORE at 0x%lx size: %d data: 0x%lx\n", (unsigned long) addr, memop_size(op), (unsigned long) val);
OperandInfo *oi = load_store_mem(addr, 1, &val, memop_size(op));
qemu_trace_add_operand(oi, 0x2);
}
86 changes: 81 additions & 5 deletions target/sh4/translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,66 @@ void superh_cpu_dump_state(CPUState *cs, FILE *f, int flags)
}
}

#ifdef HAS_TRACEWRAP
static void gen_trace_load_reg(uint32_t reg, TCGv var)
{
TCGv_i32 t = tcg_const_i32(reg);
gen_helper_trace_load_reg(t, var);
tcg_temp_free_i32(t);
}

static void gen_trace_store_reg(uint32_t reg, TCGv var)
{
TCGv_i32 t = tcg_const_i32(reg);
gen_helper_trace_store_reg(t, var);
tcg_temp_free_i32(t);
}

static inline void gen_trace_newframe(uint32_t pc)
{
TCGv_i32 tmp0 = tcg_temp_new_i32();
tcg_gen_movi_i32(tmp0, pc);
gen_helper_trace_newframe(tmp0);
tcg_temp_free_i32(tmp0);
}

static inline void gen_trace_endframe(uint32_t pc)
{
TCGv_i32 tmp0 = tcg_temp_new_i32();
tcg_gen_movi_i32(tmp0, pc);
gen_helper_trace_endframe(cpu_env, tmp0);
tcg_temp_free_i32(tmp0);
}
#endif /* HAS_TRACEWRAP */

static inline void log_load_gpr(uint32_t rx, TCGv var) {
#ifdef HAS_TRACEWRAP
gen_trace_load_reg(rx, var);
#endif
}

static inline void log_store_gpr(uint32_t rx, TCGv var) {
#ifdef HAS_TRACEWRAP
gen_trace_store_reg(rx, var);
#endif
}

static inline void log_load_mem(TCGv addr, TCGv val, MemOp op) {
#ifdef HAS_TRACEWRAP
TCGv_i32 o = tcg_const_i32(op);
gen_helper_trace_load_mem(addr, val, o);
tcg_temp_free_i32(o);
#endif
}

static inline void log_store_mem(TCGv addr, TCGv val, MemOp op) {
#ifdef HAS_TRACEWRAP
TCGv_i32 o = tcg_const_i32(op);
gen_helper_trace_store_mem(addr, val, o);
tcg_temp_free_i32(o);
#endif
}

static void gen_read_sr(TCGv dst)
{
TCGv t0 = tcg_temp_new();
Expand Down Expand Up @@ -238,6 +298,9 @@ static void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
tcg_gen_goto_tb(n);
tcg_gen_movi_i32(cpu_pc, dest);
tcg_gen_exit_tb(ctx->base.tb, n);
#ifdef HAS_TRACEWRAP
gen_trace_endframe(dest);
#endif
} else {
tcg_gen_movi_i32(cpu_pc, dest);
if (use_exit_tb(ctx)) {
Expand Down Expand Up @@ -529,8 +592,9 @@ static void _decode_opc(DisasContext * ctx)
return;
case 0xd000: /* mov.l @(disp,PC),Rn */
{
TCGv addr = tcg_const_i32((ctx->base.pc_next + 4 + B7_0 * 4) & ~3);
tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL);
TCGv addr = tcg_const_i32((ctx->base.pc_next + 4 + B7_0 * 4) & ~3);
tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL);
log_load_mem(addr, REG(B11_8), MO_TESL);
tcg_temp_free(addr);
}
return;
Expand All @@ -552,7 +616,7 @@ static void _decode_opc(DisasContext * ctx)

switch (ctx->opcode & 0xf00f) {
case 0x6003: /* mov Rm,Rn */
tcg_gen_mov_i32(REG(B11_8), REG(B7_4));
tcg_gen_mov_i32(REG(B11_8), REG(B7_4));
return;
case 0x2000: /* mov.b Rm,@Rn */
tcg_gen_qemu_st_i32(REG(B7_4), REG(B11_8), ctx->memidx, MO_UB);
Expand Down Expand Up @@ -659,8 +723,8 @@ static void _decode_opc(DisasContext * ctx)
{
TCGv addr = tcg_temp_new();
tcg_gen_add_i32(addr, REG(B7_4), REG(0));
tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL);
tcg_temp_free(addr);
tcg_gen_qemu_ld_i32(REG(B11_8), addr, ctx->memidx, MO_TESL);
tcg_temp_free(addr);
}
return;
case 0x6008: /* swap.b Rm,Rn */
Expand Down Expand Up @@ -2303,9 +2367,18 @@ static void sh4_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
}
#endif

#ifdef HAS_TRACEWRAP
gen_trace_newframe(ctx->base.pc_next);
#endif

ctx->opcode = translator_lduw(env, &ctx->base, ctx->base.pc_next);
decode_opc(ctx);
ctx->base.pc_next += 2;

#ifdef HAS_TRACEWRAP
gen_trace_endframe(ctx->base.pc_next);
#endif

}

static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
Expand All @@ -2326,6 +2399,9 @@ static void sh4_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
case DISAS_TOO_MANY:
gen_save_cpu_state(ctx, false);
gen_goto_tb(ctx, 0, ctx->base.pc_next);
#ifdef HAS_TRACEWRAP
gen_trace_endframe(ctx->base.pc_next);
#endif
break;
case DISAS_NORETURN:
break;
Expand Down