wip! implement BAL, PUSH, POP(RET)

This commit is contained in:
fridtjof 2025-08-13 01:40:34 +02:00
parent 7b0d3b1a53
commit 3382fc1700
2 changed files with 124 additions and 0 deletions

View file

@ -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 ###

View file

@ -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) {