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/decode.c

272 lines
5.6 KiB
C
Raw Normal View History

2019-05-15 20:06:45 +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.
2019-05-15 19:26:40 +02:00
2019-06-05 12:53:09 +02:00
#include <pc/arch.h>
2019-05-15 19:26:40 +02:00
2019-06-07 22:23:38 +02:00
//
2019-06-17 20:59:30 +02:00
// Read the "DECD" file before reading this code
2019-06-07 22:23:38 +02:00
//
2019-05-16 21:42:23 +02:00
2019-07-02 20:13:05 +02:00
static void check_param_type(ctx_t *ctx, instr_t *in,
uint prm, uchar fmt, int which)
2019-05-16 21:42:23 +02:00
{
2019-06-07 22:23:38 +02:00
bool ok;
2019-05-16 21:42:23 +02:00
2019-06-07 22:23:38 +02:00
if (prm == P_REG)
ok = (fmt == A_REG);
2019-05-30 12:44:56 +02:00
2019-06-07 22:23:38 +02:00
else if (prm == P_IMM)
ok = (fmt == A_IMM64);
2019-05-30 12:44:56 +02:00
2019-06-07 23:25:47 +02:00
else /* if (prm == P_MEM) */
2019-06-07 22:23:38 +02:00
ok = ACC_FMT_IS_MEM(fmt);
2019-05-16 21:42:23 +02:00
2019-06-07 22:23:38 +02:00
if (!ok)
_except(ctx, E_ILL,
2019-07-01 21:46:36 +02:00
"FT%d not matching %s's expected parameter types: "
"fmt=0x%x prm=0x%x", which, in->full, fmt, prm);
2019-05-16 21:42:23 +02:00
}
2019-06-07 22:23:38 +02:00
//
// Verify that access to a certain register is legal
//
static void checkreg(ctx_t *ctx, uint reg, bool inv_is_ok)
{
if (reg >= NREGS)
_except(ctx, E_ILL, "Inexistent register: %u", reg);
if (reg == INV)
{
if (!inv_is_ok)
_except(ctx, E_ILL, "INV dereference");
else
return;
2019-05-15 19:26:40 +02:00
}
2019-07-11 18:34:21 +02:00
if (ctx->r[reg].flags & RES)
2019-06-12 15:30:35 +02:00
//_except(ctx, E_ACC, "Reserved REG: %u", reg);
2019-06-07 22:23:38 +02:00
if (ctx->r[reg].flags & SYS)
2019-07-11 18:34:21 +02:00
if (R(CR0) & UF)
2019-06-07 22:23:38 +02:00
_except(ctx, E_SYS, "User access to SYS REG: %u", reg);
}
//
// Extract operand according to fmt
//
void extract_param(ctx_t *ctx, acc_t *p, uchar fmt)
{
2019-06-12 15:30:35 +02:00
uint mlen, mfmt;
2019-06-07 22:23:38 +02:00
ushort temp;
p->type = fmt;
2019-05-30 12:44:56 +02:00
2019-06-07 22:23:38 +02:00
if (fmt == A_REG)
{
p->reg = ctx->get(ctx);
checkreg(ctx, p->reg, 0);
p->val = R(p->reg);
2019-06-12 15:30:35 +02:00
return;
2019-05-15 19:26:40 +02:00
}
2019-05-30 12:44:56 +02:00
2019-06-07 22:23:38 +02:00
else if (fmt == A_IMM64)
{
p->val = ctx->get(ctx);
p->val |= (ulong)ctx->get(ctx) << 16;
p->val |= (ulong)ctx->get(ctx) << 32;
p->val |= (ulong)ctx->get(ctx) << 48;
2019-06-12 15:30:35 +02:00
return;
2019-05-15 19:26:40 +02:00
}
2019-05-30 12:44:56 +02:00
2019-06-07 22:23:38 +02:00
assert(ACC_FMT_IS_MEM(fmt));
//
// Handle a memory access
//
mlen = fmt & AM_MLEN_MASK;
mfmt = fmt & AM_MFMT_MASK;
p->mlen = (mlen == AM_8ACC ? 1
: (mlen == AM_16ACC ? 2
: (mlen == AM_32ACC ? 4
: (mlen == AM_64ACC ? 8 : 0))));
if (p->mlen == 0)
_except(ctx, E_ILL, "Invalid MLEN for access: %x", fmt);
switch (mfmt)
{
case AM_IMM64:
p->addr = ctx->get(ctx);
p->addr |= (ulong)ctx->get(ctx) << 16;
p->addr |= (ulong)ctx->get(ctx) << 32;
p->addr |= (ulong)ctx->get(ctx) << 48;
break;
case AM_RR:
case AM_RRI:
case AM_RRII:
temp = ctx->get(ctx);
2019-06-12 15:30:35 +02:00
p->reg1 = temp >> 8;
p->reg2 = temp & 0xFF;
checkreg(ctx, p->reg1, 1);
checkreg(ctx, p->reg2, 1);
2019-06-07 22:23:38 +02:00
2019-06-12 15:30:35 +02:00
if (mfmt == AM_RRI)
{
p->imm1 = 1;
p->imm2 = ctx->get(ctx);
}
2019-06-07 22:23:38 +02:00
2019-06-12 15:30:35 +02:00
else if (mfmt == AM_RRII)
2019-06-07 22:23:38 +02:00
{
2019-06-12 15:30:35 +02:00
p->imm1 = ctx->get(ctx);
p->imm2 = ctx->get(ctx);
2019-06-07 22:23:38 +02:00
}
2019-06-12 15:30:35 +02:00
else
2019-06-07 22:23:38 +02:00
{
2019-06-12 15:30:35 +02:00
p->imm1 = 1;
p->imm2 = 0;
2019-06-07 22:23:38 +02:00
}
2019-05-15 19:26:40 +02:00
2019-07-02 20:57:40 +02:00
p->addr = R(p->reg1) + R(p->reg2)
* (long)(short)p->imm1
2019-06-14 12:40:49 +02:00
+ (long)(short)p->imm2;
2019-06-07 22:23:38 +02:00
break;
default:
_except(ctx, E_ILL, "Invalid MFMT for access: %x", fmt);
}
}
2019-05-30 12:44:56 +02:00
2019-06-17 20:59:30 +02:00
void decode(ctx_t *ctx)
2019-06-07 22:23:38 +02:00
{
2019-06-17 20:59:30 +02:00
instr_t *in;
acc_t p1 = { 0 };
acc_t p2 = { 0 };
2019-07-01 21:46:36 +02:00
acc_t p3 = { 0 };
2019-06-17 20:59:30 +02:00
bool rep = 0;
bool lock, nomore;
ushort w1, w2;
2019-07-01 21:46:36 +02:00
uchar f1 = 0, f2 = 0, f3 = 0;
2019-06-17 20:59:30 +02:00
2019-07-11 18:34:21 +02:00
rpc = R(RIP);
2019-06-19 21:41:22 +02:00
2019-06-17 20:59:30 +02:00
//
// Process the first word of the instruction
//
w1 = ctx->get(ctx);
2019-06-07 22:23:38 +02:00
2019-06-17 20:59:30 +02:00
// Extract first word flags
2019-06-07 22:23:38 +02:00
2019-07-01 21:46:36 +02:00
lock = !!(w1 & SUFF_LOCK);
nomore = !!(w1 & SUFF_NOMORE);
if (w1 & SUFF_COND)
2019-07-02 20:13:05 +02:00
ctx->cond = ctx->get(ctx);
else
ctx->cond = 0;
2019-06-07 22:23:38 +02:00
2019-07-01 21:46:36 +02:00
w1 &= ~(SUFF_LOCK|SUFF_NOMORE|SUFF_COND);
2019-06-17 20:59:30 +02:00
// Find instruction
if (w1 >= NINSTRS)
{
2019-06-19 13:47:10 +02:00
_except(ctx, E_ILL, "No such INSTR: 0x%hX", w1);
2019-05-15 19:26:40 +02:00
}
2019-06-17 20:59:30 +02:00
in = &ctx->i[w1];
2019-07-04 20:33:49 +02:00
ctx->cur_in = in;
2019-06-07 22:23:38 +02:00
2019-06-19 13:47:10 +02:00
if (!nomore)
{
//
// Process second word
//
2019-06-13 15:32:24 +02:00
2019-06-19 13:47:10 +02:00
w2 = ctx->get(ctx);
2019-06-07 22:23:38 +02:00
2019-06-19 13:47:10 +02:00
// REP and COND
2019-07-01 21:46:36 +02:00
rep = !!(w2 & SUFF_REP);
2019-06-07 23:25:47 +02:00
2019-07-01 21:46:36 +02:00
// Fn
f3 = (w2 >> F3_SHIFT) & Fx_MASK;
f2 = (w2 >> F2_SHIFT) & Fx_MASK;
f1 = w2 & Fx_MASK;
2019-06-19 13:47:10 +02:00
}
2019-06-07 23:25:47 +02:00
2019-06-17 20:59:30 +02:00
//
// Deal with operand 1
//
if (in->prm1 == NOPRM)
{
2019-07-01 21:46:36 +02:00
if (f1 || f2 || f3)
2019-06-07 22:23:38 +02:00
{
2019-07-01 21:46:36 +02:00
_except(ctx, E_ILL,
"FTn (%u,%u,%u) filled for 0-param INSTR '%s'",
f1, f2, f3, in->full);
2019-06-12 15:47:11 +02:00
}
2019-06-17 20:59:30 +02:00
2019-07-02 20:13:05 +02:00
exec_instr(ctx, in, NULL, NULL, NULL, lock, rep);
2019-06-17 20:59:30 +02:00
return;
2019-06-12 15:47:11 +02:00
}
2019-07-01 21:46:36 +02:00
check_param_type(ctx, in, in->prm1, f1, 1);
2019-06-17 20:59:30 +02:00
extract_param(ctx, &p1, f1);
//
// Deal with operand 2
//
2019-06-12 15:47:11 +02:00
2019-06-17 20:59:30 +02:00
if (in->prm2 == NOPRM)
{
2019-07-01 21:46:36 +02:00
if (f2 || f3)
2019-06-12 15:47:11 +02:00
{
2019-07-01 21:46:36 +02:00
_except(ctx, E_ILL,
"FT3/FT2 (%u,%u,%u) filled for 1-param INSTR '%s'",
f1, f2, f3, in->full);
2019-06-07 22:23:38 +02:00
}
2019-06-13 15:32:24 +02:00
2019-07-02 20:13:05 +02:00
exec_instr(ctx, in, &p1, NULL, NULL, lock, rep);
2019-06-17 20:59:30 +02:00
return;
}
2019-06-13 17:13:59 +02:00
2019-07-01 21:46:36 +02:00
check_param_type(ctx, in, in->prm2, f2, 2);
2019-06-17 20:59:30 +02:00
extract_param(ctx, &p2, f2);
2019-06-13 17:13:59 +02:00
2019-07-01 21:46:36 +02:00
//
// Deal with operand 3
//
if (in->prm3 == NOPRM)
{
if (f3)
{
_except(ctx, E_ILL,
"FT3 (%u,%u,%u) filled for 2-param INSTR '%s'",
f1, f2, f3, in->full);
}
2019-07-02 20:13:05 +02:00
exec_instr(ctx, in, &p1, &p2, NULL, lock, rep);
2019-07-01 21:46:36 +02:00
return;
}
check_param_type(ctx, in, in->prm3, f3, 3);
extract_param(ctx, &p3, f3);
2019-06-13 15:32:24 +02:00
2019-07-02 20:13:05 +02:00
exec_instr(ctx, in, &p1, &p2, &p3, lock, rep);
2019-05-15 19:26:40 +02:00
}