1
0
mirror of https://gitlab.os-k.eu/os-k-team/kvisc.git synced 2023-08-25 14:05:46 +02:00
kvisc/vm/pc/exec.c

130 lines
2.9 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-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;
case CD_C: ok = flg&CF; break;
case CD_O: ok = flg&OF; break;
case CD_Z: ok = flg&ZF; break;
case CD_S: ok = flg&SF; break;
case CD_P: ok = flg&PF; break;
case CD_A: ok = !(flg&CF || flg&ZF); break;
case CD_AE: ok = !(flg&CF); break;
case CD_B: ok = flg&CF; break;
case CD_BE: ok = flg&CF || flg&ZF; break;
case CD_G: ok = !(flg&ZF) && (!(flg&SF) == !(flg&OF)); break;
case CD_GE: ok = !(flg&SF) == !(flg&OF); break;
case CD_L: ok = !(flg&SF) != !(flg&OF); break;
case CD_LE: ok = flg&ZF || (!(flg&SF) != !(flg&OF)); break;
case CD_CXZ: ok = !rcx; break;
default:
_except(ctx, E_ILL, "Invalid COND value: 0x%x", (neg?cond|(1<<4):cond));
}
return neg ? !ok : !!ok;
}
//
// Executes an instruction
//
void exec_instr(ctx_t *ctx,
instr_t *in,
acc_t *p1,
acc_t *p2,
bool lock,
bool rep,
uint cond,
ulong pc)
{
bool out;
ulong r1 = 0, r2 = 0;
2019-06-21 22:19:55 +02:00
// Instruction counter
ctx->ninstrs++;
#ifndef NDEBUG
2019-06-17 20:59:30 +02:00
dump_instr(ctx, in, p1, p2, lock, rep, cond, pc);
2019-06-21 22:19:55 +02:00
#endif
2019-06-17 20:59:30 +02:00
//
// For REPs we evaluate the condition AFTER running the instruction,
// in a do ... while(cond) fashion
//
if (!rep && !eval_cond(ctx, cond))
return;
do_rep:
out = in->func(ctx, p1, p2, &r1, &r2);
if (out)
{
if (p1->type == A_REG)
R(p1->reg) = r1;
else if (p1->type == A_IMM64)
_except(ctx, E_ACC, "Trying to output to an IMM64");
else
{
assert(ACC_IS_MEM(p1));
writemem(ctx, r1, p1->addr, p1->mlen);
}
}
if (out == 2)
{
if (p2->type == A_REG)
R(p2->reg) = r2;
else if (p2->type == A_IMM64)
_except(ctx, E_ACC, "Trying to output to an IMM64");
else
{
assert(ACC_IS_MEM(p2));
writemem(ctx, r2, p2->addr, p2->mlen);
}
}
if (rep)
{
// RCX remains untouched when condition fails
if (!eval_cond(ctx, cond))
return;
if (rcx > 0)
rcx--;
if (rcx == 0)
return;
2019-06-21 22:19:55 +02:00
ctx->ninstrs++;
#ifndef NDEBUG
2019-06-17 20:59:30 +02:00
// Show that we're REP'ing
dump_instr(ctx, in, p1, p2, lock, rep, cond, pc);
2019-06-21 22:19:55 +02:00
#endif
2019-06-17 20:59:30 +02:00
goto do_rep;
}
}