kvisc/vm/pc/exec.c

114 lines
3.0 KiB
C
Raw Normal View History

2019-06-17 20:59:30 +02:00
// The OS/K Team licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#include <pc/arch.h>
2019-07-17 22:25:50 +02:00
#define rfx R(RFX)
2019-06-21 22:19:55 +02:00
bool eval_cond(ctx_t *ctx, uint cond)
2019-06-17 20:59:30 +02:00
{
bool neg = cond & (1 << 4);
bool ok;
cond &= ~(1 << 4);
switch (cond)
{
case CD_NONE: ok = 1; break;
2019-07-11 18:34:21 +02:00
case CD_C: ok = rfx&CF; break;
case CD_O: ok = rfx&OF; break;
case CD_Z: ok = rfx&ZF; break;
case CD_S: ok = rfx&SF; break;
case CD_P: ok = rfx&PF; break;
2019-06-17 20:59:30 +02:00
2019-07-22 14:41:50 +02:00
case CD_BE: ok = rfx&CF || rfx&ZF; break;
2019-07-11 18:34:21 +02:00
case CD_L: ok = !(rfx&SF) != !(rfx&OF); break;
case CD_LE: ok = rfx&ZF || (!(rfx&SF) != !(rfx&OF)); break;
2019-06-17 20:59:30 +02:00
2019-07-22 14:41:50 +02:00
case CD_AXZ: ok = !R(RAX); break;
case CD_BXZ: ok = !R(RBX); break;
2019-07-11 18:34:21 +02:00
case CD_CXZ: ok = !R(RCX); break;
2019-07-22 14:41:50 +02:00
case CD_DXZ: ok = !R(RDX); break;
2019-06-17 20:59:30 +02:00
default:
_except(ctx, E_ILL, "Invalid COND value: 0x%x", (neg?cond|(1<<4):cond));
}
return neg ? !ok : !!ok;
}
2019-07-17 22:25:50 +02:00
#define OUTPUT(p, r) { \
if (p->type == A_REG) \
R(p->reg) = r; \
else if (p1->type == A_IMM64) \
_except(ctx, E_ACC, "Trying to output to an IMM64"); \
else { \
assert(ACC_IS_MEM(p)); \
writemem(ctx, r, p->addr, p->mlen); \
} }
2019-06-17 20:59:30 +02:00
//
// Executes an instruction
//
void exec_instr(ctx_t *ctx,
instr_t *in,
acc_t *p1,
acc_t *p2,
2019-07-01 21:46:36 +02:00
acc_t *p3,
2019-06-17 20:59:30 +02:00
bool lock,
2019-07-02 20:13:05 +02:00
bool rep)
2019-06-17 20:59:30 +02:00
{
2019-07-09 21:02:26 +02:00
uint out;
2019-07-01 21:46:36 +02:00
ulong r1 = 0, r2 = 0, r3 = 0;
2019-06-17 20:59:30 +02:00
2019-06-23 21:12:25 +02:00
// Global instruction counter
2019-07-24 16:52:26 +02:00
ctx->ninstrs++;
2019-06-21 22:19:55 +02:00
2019-06-17 20:59:30 +02:00
//
// For REPs we evaluate the condition AFTER running the instruction,
// in a do ... while(cond) fashion
//
2019-07-02 20:13:05 +02:00
if (ctx->cond && in->func != i_b) // 'B' instruction is special
if (!rep && !eval_cond(ctx, ctx->cond))
return;
2019-06-28 19:18:53 +02:00
2019-07-04 20:33:49 +02:00
if (ctx->dumpsw)
dump_instr(ctx, in, p1, p2, p3, lock, rep);
2019-06-17 20:59:30 +02:00
do_rep:
2019-07-01 21:46:36 +02:00
out = in->func(ctx, p1, p2, p3, &r1, &r2, &r3);
2019-06-17 20:59:30 +02:00
2019-07-09 21:02:26 +02:00
if (out)
2019-07-01 21:46:36 +02:00
{
2019-07-09 21:02:26 +02:00
OUTPUT(p1, r1);
if (out >= 2) OUTPUT(p2, r2);
if (out >= 3) OUTPUT(p3, r3);
2019-07-17 22:25:50 +02:00
R(RZX) = 0;
2019-07-01 21:46:36 +02:00
}
2019-06-17 20:59:30 +02:00
if (rep)
{
// RCX remains untouched when condition fails
2019-07-02 20:13:05 +02:00
if (!eval_cond(ctx, ctx->cond))
2019-06-17 20:59:30 +02:00
return;
2019-07-11 18:34:21 +02:00
if (R(RCX) > 0)
R(RCX)--;
2019-06-17 20:59:30 +02:00
2019-07-11 18:34:21 +02:00
if (R(RCX) == 0)
2019-06-17 20:59:30 +02:00
return;
2019-07-08 17:46:10 +02:00
// Should we really count REP's in instruction count?
2019-07-24 16:52:26 +02:00
ctx->ninstrs++;
2019-07-04 20:33:49 +02:00
#if 0
2019-06-17 20:59:30 +02:00
// Show that we're REP'ing
2019-07-04 20:33:49 +02:00
if (ctx->dumpsw)
dump_instr(ctx, in, p1, p2, p3, lock, rep);
2019-06-21 22:19:55 +02:00
#endif
2019-06-17 20:59:30 +02:00
goto do_rep;
}
}