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-06-13 22:20:35 +02:00
|
|
|
static void check_param_type(ctx_t *ctx, instr_t *in, uint prm, uchar fmt)
|
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-06-13 22:20:35 +02:00
|
|
|
"FT1 or FT2 not matching %s's expected parameter types: "
|
|
|
|
"fmt=0x%x prm=0x%x", 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-06-07 22:23:38 +02:00
|
|
|
if (ctx->r[reg].flags & (RES | CTL))
|
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)
|
|
|
|
if (cr0 & UF)
|
|
|
|
_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-06-14 12:40:49 +02:00
|
|
|
p->addr = R(p->reg1) + R(p->reg2) * p->imm1
|
|
|
|
+ (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
|
|
|
char *illmsg;
|
|
|
|
|
|
|
|
instr_t *in;
|
|
|
|
|
|
|
|
acc_t p1 = { 0 };
|
|
|
|
acc_t p2 = { 0 };
|
|
|
|
|
|
|
|
bool rep = 0;
|
|
|
|
uint cond = 0;
|
|
|
|
bool lock, nomore;
|
|
|
|
|
|
|
|
ushort w1, w2;
|
|
|
|
uchar f1 = 0, f2 = 0;
|
|
|
|
|
|
|
|
ulong pc = rip;
|
2019-06-19 21:41:22 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
sym_t *sym = find_sym_by_addr(pc);
|
|
|
|
if (sym)
|
|
|
|
trace("0x%lX: %s:\n", pc, sym->name);
|
|
|
|
*/
|
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-06-17 20:59:30 +02:00
|
|
|
lock = !!(w1 & PREF_LOCK);
|
|
|
|
nomore = !!(w1 & PREF_NOMORE);
|
2019-06-07 22:23:38 +02:00
|
|
|
|
2019-06-17 20:59:30 +02:00
|
|
|
w1 &= ~(PREF_LOCK|PREF_NOMORE);
|
|
|
|
|
|
|
|
// 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-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
|
|
|
|
rep = !!(w2 & PREF_REP);
|
|
|
|
cond = (w2 & BITS_COND) >> COND_SHIFT;
|
2019-06-07 23:25:47 +02:00
|
|
|
|
2019-06-19 13:47:10 +02:00
|
|
|
// F1 and F2
|
|
|
|
f1 = (w2 >> F1_SHIFT) & Fx_MASK;
|
|
|
|
f2 = w2 & Fx_MASK;
|
|
|
|
}
|
2019-06-07 23:25:47 +02:00
|
|
|
|
2019-06-17 20:59:30 +02:00
|
|
|
//
|
|
|
|
// Deal with operand 1
|
|
|
|
//
|
|
|
|
|
|
|
|
if (in->prm1 == NOPRM)
|
|
|
|
{
|
|
|
|
if (f1 || f2)
|
2019-06-07 22:23:38 +02:00
|
|
|
{
|
2019-06-17 20:59:30 +02:00
|
|
|
illmsg = "FT1 and/or FT2 filled for 0-param INSTR";
|
|
|
|
goto ill;
|
2019-06-12 15:47:11 +02:00
|
|
|
}
|
2019-06-17 20:59:30 +02:00
|
|
|
|
|
|
|
exec_instr(ctx, in, NULL, NULL, lock, rep, cond, pc);
|
|
|
|
return;
|
2019-06-12 15:47:11 +02:00
|
|
|
}
|
|
|
|
|
2019-06-17 20:59:30 +02:00
|
|
|
check_param_type(ctx, in, in->prm1, f1);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
if (f2)
|
2019-06-12 15:47:11 +02:00
|
|
|
{
|
2019-06-17 20:59:30 +02:00
|
|
|
illmsg = "FT2 filled for 1-param INSTR";
|
|
|
|
goto ill;
|
2019-06-07 22:23:38 +02:00
|
|
|
}
|
2019-06-13 15:32:24 +02:00
|
|
|
|
2019-06-17 20:59:30 +02:00
|
|
|
exec_instr(ctx, in, &p1, NULL, lock, rep, cond, pc);
|
|
|
|
return;
|
|
|
|
}
|
2019-06-13 17:13:59 +02:00
|
|
|
|
2019-06-17 20:59:30 +02:00
|
|
|
check_param_type(ctx, in, in->prm2, f2);
|
|
|
|
extract_param(ctx, &p2, f2);
|
2019-06-13 17:13:59 +02:00
|
|
|
|
2019-06-17 20:59:30 +02:00
|
|
|
exec_instr(ctx, in, &p1, &p2, lock, rep, cond, pc);
|
|
|
|
return;
|
2019-06-13 15:32:24 +02:00
|
|
|
|
2019-06-17 20:59:30 +02:00
|
|
|
ill:
|
|
|
|
_except(ctx, E_ILL, illmsg);
|
2019-05-15 19:26:40 +02:00
|
|
|
}
|
|
|
|
|