From 3382fc1700aa6014ff338cc332cfcf26e04059ea Mon Sep 17 00:00:00 2001 From: fridtjof Date: Wed, 13 Aug 2025 01:40:34 +0200 Subject: [PATCH] wip! implement BAL, PUSH, POP(RET) --- target/cr16c/insn.decode | 15 ++++++ target/cr16c/translate.c | 109 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/target/cr16c/insn.decode b/target/cr16c/insn.decode index 590ba1ba3c..e77c56e9e2 100644 --- a/target/cr16c/insn.decode +++ b/target/cr16c/insn.decode @@ -257,6 +257,21 @@ JCOND 0000 1010 cond:4 ra:4 EXCP 0000 0000 1100 id:4 +&bal dest + +@bal .... .... dest:23 . &bal +#@bal_3a .... .... .... .... .... p1_1916:4 p2:4 p1_2320:4 p1_1501:15 . + +BAL_ra 1100 0000 .... .... .... .... .... ...- @bal # fmt 5 +#BAL_rp 0000 0000 1000 0000 0010 .... .... .... .... .... .... .... @bal_3a # fmt 3a + +&pop rt ra count dest +@pop .... ... rt:1 ra:1 count:3 dest:4 &pop +&push ra count src +@push .... .... ra:1 count:3 src:4 &push + +pop 0000 001. .... .... @pop # fmt 14, includes popret via rt bit +push 0000 0001 .... .... @push # fmt 14 ### Load and Store ### diff --git a/target/cr16c/translate.c b/target/cr16c/translate.c index 691c0a73e0..a4cb0a4bfe 100644 --- a/target/cr16c/translate.c +++ b/target/cr16c/translate.c @@ -6,6 +6,7 @@ #include "exec/translator.h" #include "accel/tcg/cpu-ldst.h" #include "qemu/typedefs.h" +#include "qemu/qemu-print.h" #include "tcg/tcg-cond.h" #include "tcg/tcg-op-common.h" #include "tcg/tcg-op.h" @@ -37,6 +38,27 @@ enum { CR16C_COND_UC, }; +/* Representation of register pair encoding */ +enum { + CR16C_RP_R1R0, + CR16C_RP_R2R1, + CR16C_RP_R3R2, + CR16C_RP_R4R3, + CR16C_RP_R5R4, + CR16C_RP_R6R5, + CR16C_RP_R7R6, + CR16C_RP_R8R7, + CR16C_RP_R9R8, + CR16C_RP_R10R9, + CR16C_RP_R11R10, + CR16C_RP_R12LR11, + // TODO these are ~funky, depend on CFG.SR and PSR.U + /*CR16C_RP_R12, + CR16C_RP_R13, + CR16C_RP_RA, + CR16C_RP_SP,*/ +}; + typedef struct DisasContext { DisasContextBase base; CPUCR16CState* env; @@ -1460,6 +1482,93 @@ static bool trans_STORM(DisasContext *ctx, arg_STORM *a) { return true; } +static bool trans_BAL_ra(DisasContext *ctx, arg_BAL_ra *a) { +#define BAL_LEN 4 + // TODO BAL_rp would be 3 words/6 bytes (fmt 3a) + vaddr pc_this = ctx->base.pc_next - BAL_LEN; + vaddr dest_offset = a->dest*2; + qemu_printf("!!!bal %04lx dest=%d\n", pc_this, a->dest); + + // 1) store next PC in ra TODO BAL_rp can choose where + tcg_gen_movi_i32(r[CR16C_REGNO_RA], ctx->base.pc_next); + + // 2) sign extend from 23 -> "25" bits + int32_t dest_sextend = sextract32(dest_offset, 0, 23); + + qemu_printf("=> 0x%lx\n", pc_this + dest_sextend); + ctx->base.is_jmp = DISAS_NORETURN; + gen_goto(&ctx->base, pc_this + dest_sextend, 0); + + // TODO IAD trap + // TODO CFG.SR handling + return true; +} + +static bool trans_pop(DisasContext *ctx, arg_pop *a) { + // count is 3 bits, so its range is 0-7 + // however, it encodes counts 1-8 + int32_t count = a->count + 1; + // todo if cfg.sr = 1 + if (true) { + if (count + a->dest > 15) { // TODO verify against ISA table + // invalid + return false; + } + } else { + // TODO cfg.sr = 0 + } + for (int i = 0; i < count; ++i) { + // pop regular registers + // TODO register pair popping??? + tcg_gen_qemu_ld_tl(r[a->dest + i], r[CR16C_REGNO_SP], 0, MO_UW); + tcg_gen_addi_tl(r[CR16C_REGNO_SP], r[CR16C_REGNO_SP], 2); + } + // TODO memory spaces(???) + // pop RA if requested + if (a->ra) { + tcg_gen_qemu_ld_tl(r[CR16C_REGNO_RA], r[CR16C_REGNO_SP], 0, MO_32); + tcg_gen_addi_tl(r[CR16C_REGNO_SP], r[CR16C_REGNO_SP], 4); + } + + if (a->rt) { + // basically, JUMP RA + ctx->base.is_jmp = DISAS_NORETURN; + + tcg_gen_goto_tb(0); + tcg_gen_mov_i32(pc, r[CR16C_REGNO_RA]); + tcg_gen_exit_tb(ctx->base.tb, 0); + } + return true; +} + +static bool trans_push(DisasContext *ctx, arg_push *a) { + int32_t count = a->count + 1; + + // we need to push the registers in reverse order so that they are in the correct places for POP, e.g.: + // SP = 0x100A + // # popret $3, R1, RA + // 0x1000 R1 + // 0x1002 R2 + // 0x1004 R3 + // 0x1006 RA # 4 bytes!! + // 0x100A xxxxx + + // TODO memory spaces + // push RA + if (a->ra) { + tcg_gen_subi_tl(r[CR16C_REGNO_SP], r[CR16C_REGNO_SP], 4); + tcg_gen_qemu_st_tl(r[CR16C_REGNO_RA], r[CR16C_REGNO_SP], 0, MO_32); + } + + // push regular registers + for (int i = count - 1; i >= 0; --i) { + // TODO register pairs + tcg_gen_subi_tl(r[CR16C_REGNO_SP], r[CR16C_REGNO_SP], 2); + tcg_gen_qemu_st_tl(r[a->src + i], r[CR16C_REGNO_SP], 0, MO_16); + } + + return true; +} /* Some instructions aren't implemented yet, eg. because of some binutils that make them hard to verify and we'll fix first */ static bool trans_UNIMPLEMENTED(DisasContext *ctx, arg_UNIMPLEMENTED *a) {