diff --git a/meson.build b/meson.build index d9293294d8..e645b16e2e 100644 --- a/meson.build +++ b/meson.build @@ -755,6 +755,7 @@ warn_flags = [ '-Wno-string-plus-int', '-Wno-tautological-type-limit-compare', '-Wno-typedef-redefinition', + '-Wno-unused-function', ] if host_os != 'darwin' diff --git a/target/cr16c/cpu.c b/target/cr16c/cpu.c index 4e2f1d681f..fee48363b1 100644 --- a/target/cr16c/cpu.c +++ b/target/cr16c/cpu.c @@ -14,6 +14,7 @@ static void cr16c_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) { info->mach = bfd_arch_cr16c; info->endian = BFD_ENDIAN_LITTLE; + info->print_insn = cr16c_print_insn; } static void cr16c_cpu_realizefn(DeviceState *dev, Error **errp) diff --git a/target/cr16c/disas.c b/target/cr16c/disas.c new file mode 100644 index 0000000000..129e6deb5b --- /dev/null +++ b/target/cr16c/disas.c @@ -0,0 +1,148 @@ +/* + * CR16C disassembler, adapted from the AVR one + * + * Copyright (c) 2025 fridtjof + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" + +// TODO +typedef struct { + disassemble_info *info; + uint16_t next_word; + bool next_word_used; +} DisasContext; + +static uint64_t decode_load_bytes(DisasContext *ctx, uint64_t insn, int i, int n) { + for(; i < n; i+=2) { + insn |= (uint64_t)translator_lduw(ctx->env, &ctx->base, ctx->base.pc_next) << (48 - i * 8); + ctx->base.pc_next += 2; + } + if (i == n) + return insn; + else { + gen_helper_raise_illegal_instruction(tcg_env); + return 0; + } +} + + +static int16_t u4_load_s16(DisasContext *ctx, int val) { + if (val == 0x9) { + return -1; + } + else if (val == 0xB) { + int16_t val_ld = cpu_ldsw_le_data(ctx->env, ctx->base.pc_next); + ctx->base.pc_next += 2; + return val_ld; + } + return val; +} + +static uint16_t load_u16(DisasContext *ctx) { + ctx->next_word_used = 1; + uint16_t imm = cpu_lduw_code(ctx->env, ctx->base.pc_next); + ctx->base.pc_next += 2; + return imm; +} + +static uint8_t get_disp4(DisasContext *ctx, uint8_t disp) { + return disp << 1; +} + +static int32_t disp8_get_dest(DisasContext* ctx, int32_t disp) { + int32_t dest = ctx->base.pc_next - 2; + if (disp == 0xFFFFFF80) { + dest += cpu_ldsw_le_data(ctx->env, ctx->base.pc_next); + ctx->base.pc_next += 2; + } + else { + dest += disp << 1; + } + return dest; +}; + +static uint32_t reloc_abs20(DisasContext *ctx, uint32_t addr) { + if (addr > 0xEFFFF) { + addr |= 0xF00000; + } + return addr; +} + +/* Include the auto-generated decoder. */ +static bool decode_insn(DisasContext *ctx, uint16_t insn); +#include "decode-insn.c.inc" + +#define output(mnemonic, format, ...) \ +(pctx->info->fprintf_func(pctx->info->stream, "%-9s " format, \ +mnemonic, ##__VA_ARGS__)) + +int cr16c_print_insn(bfd_vma addr, disassemble_info *info) +{ + DisasContext ctx = { info }; + DisasContext *pctx = &ctx; + bfd_byte buffer[4]; + uint16_t insn; + int status; + + status = info->read_memory_func(addr, buffer, 2, info); + if (status != 0) { + info->memory_error_func(status, addr, info); + return -1; + } + insn = bfd_getl16(buffer); + (void)insn; + + status = info->read_memory_func(addr + 2, buffer + 2, 2, info); + if (status == 0) { + ctx.next_word = bfd_getl16(buffer + 2); + } + + //if (!decode_insn(&ctx, insn)) { + output(".db", "0x%02x, 0x%02x", buffer[0], buffer[1]); + //} + + if (!ctx.next_word_used) { + return 2; + } else if (status == 0) { + return 4; + } + info->memory_error_func(status, addr + 2, info); + return -1; +} + +#define INSN(opcode, format, ...) \ +static bool trans_##opcode(DisasContext *pctx, arg_##opcode * a) \ +{ \ +output(#opcode, format, ##__VA_ARGS__); \ +return true; \ +} + +#define INSN_MNEMONIC(opcode, mnemonic, format, ...) \ +static bool trans_##opcode(DisasContext *pctx, arg_##opcode * a) \ +{ \ +output(mnemonic, format, ##__VA_ARGS__); \ +return true; \ +} + +static const char width[] = { + 'x', 'B', 'W', 'x', 'D' +}; + +INSN(MOV_imm, "%c, 0x%x, r%d", width[a->width], a->imm, a->rd) +INSN(MOV_reg, "%c r%d, r%d", width[a->width], a->rs, a->rd) +INSN(MOVD_reg, "r%d, r%d", a->rs, a->rd) diff --git a/target/cr16c/meson.build b/target/cr16c/meson.build index 88ce674ed5..f5a4a5d2e6 100644 --- a/target/cr16c/meson.build +++ b/target/cr16c/meson.build @@ -8,6 +8,7 @@ cr16c_ss.add(files( 'cpu.c', 'helper.c', 'translate.c', + 'disas.c', )) cr16c_system_ss = ss.source_set() diff --git a/target/cr16c/translate.c b/target/cr16c/translate.c index 0ccd8588b3..d065c46aad 100644 --- a/target/cr16c/translate.c +++ b/target/cr16c/translate.c @@ -1465,6 +1465,13 @@ static bool trans_STOR_rrp(DisasContext *ctx, arg_STOR_rrp *a) { return true; } +// TODO this should already be in reloc_abs20. see how to replace this in the decoder +static int abs20_remap(int addr) { + if (addr > 0xEFFFF) + return addr | 0xF00000; + return addr; +} + static bool trans_STOR_abs(DisasContext *ctx, arg_STOR_abs *a) { int32_t addr = a->addr; @@ -1473,7 +1480,7 @@ static bool trans_STOR_abs(DisasContext *ctx, arg_STOR_abs *a) { // See Table 5-7, footnote f, which applies for abs20 if (a->remap) { - addr = addr > 0xEFFFF ? addr | 0xF00000 : addr; + addr = abs20_remap(addr); } gen_combine_rp(a->rs, a->width); @@ -1498,7 +1505,7 @@ static bool trans_STOR_abs_imm(DisasContext *ctx, arg_STOR_abs_imm *a) { // third [imm -> dest] format of the instruction. // See Table 5-4, footnote e, which applies for abs20 if (a->remap) { - addr = addr > 0xEFFFF ? addr | 0xF00000 : addr; + addr = abs20_remap(addr); } tcg_gen_qemu_st_i32(tcg_constant_i32(a->imm), tcg_constant_i32(addr), 0, unsigned_op_by_width[a->width]);