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

265 lines
5.0 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-24 16:52:26 +02:00
//
// Instruction fetch
//
static uchar fetchb(ctx_t *ctx)
{
uchar v = *(ctx->mp + R(RIP) + R(CR1) - MEMOFF);
R(RIP) += 1;
return v;
}
static ushort fetchw(ctx_t *ctx)
2019-05-16 21:42:23 +02:00
{
2019-07-24 16:52:26 +02:00
ushort v = *(ushort *)(ctx->mp + R(RIP) + R(CR1) - MEMOFF);
R(RIP) += 2;
return v;
}
2019-05-16 21:42:23 +02:00
2019-07-24 16:52:26 +02:00
static uint fetchd(ctx_t *ctx)
{
uint v = *(uint *)(ctx->mp + R(RIP) + R(CR1) - MEMOFF);
R(RIP) += 4;
2019-05-30 12:44:56 +02:00
2019-07-24 16:52:26 +02:00
return v;
}
2019-05-30 12:44:56 +02:00
2019-07-24 16:52:26 +02:00
static ulong fetchq(ctx_t *ctx)
{
ulong v = *(ulong *)(ctx->mp + R(RIP) + R(CR1) - MEMOFF);
R(RIP) += 8;
2019-05-16 21:42:23 +02:00
2019-07-24 16:52:26 +02:00
return v;
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
//
2019-07-17 22:25:50 +02:00
static void checkreg(ctx_t *ctx, uint reg)
2019-06-07 22:23:38 +02:00
{
if (reg >= NREGS)
_except(ctx, E_ILL, "Inexistent register: %u", reg);
2019-07-11 18:34:21 +02:00
if (ctx->r[reg].flags & RES)
2019-07-17 22:25:50 +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);
}
//
2019-07-24 16:52:26 +02:00
// Verify that given access length is that of a byte/word/dword/qword
2019-06-07 22:23:38 +02:00
//
2019-08-03 17:41:44 +02:00
static void checklength(ctx_t *ctx, instr_t *in, uint len)
2019-06-07 22:23:38 +02:00
{
2019-07-24 16:52:26 +02:00
static const int lentab[9] = { 0, 1, 1, 0, 1, 0, 0, 0, 1 };
2019-06-07 22:23:38 +02:00
2019-07-24 16:52:26 +02:00
if (len > 8 || lentab[len] == 0)
2019-08-03 17:41:44 +02:00
_except(ctx, E_ILL, "%s: Invalid memory access length: %u",
in->name, len);
2019-07-24 16:52:26 +02:00
}
//
// Extracts one operand
//
2019-08-03 17:41:44 +02:00
static void extract_param(ctx_t *ctx, instr_t *in, acc_t *p)
2019-07-24 16:52:26 +02:00
{
// Get next operand ModRM-like byte
uchar fmt = fetchb(ctx);
2019-08-03 17:41:44 +02:00
uchar hi = (fmt & 0b11100000) >> 5;
uchar lo = fmt & 0b00011111;
2019-05-30 12:44:56 +02:00
2019-07-24 16:52:26 +02:00
//
// Registers
//
if (hi == 0)
2019-06-07 22:23:38 +02:00
{
2019-07-24 16:52:26 +02:00
p->reg = lo;
p->type = A_REG;
2019-07-17 22:25:50 +02:00
checkreg(ctx, p->reg);
2019-06-07 22:23:38 +02:00
p->val = R(p->reg);
2019-07-24 16:52:26 +02:00
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-07-24 16:52:26 +02:00
//
// Immediates
//
if (hi == 7)
2019-06-07 22:23:38 +02:00
{
2019-07-24 16:52:26 +02:00
switch (lo)
{
case 1:
p->type = A_IMM8;
p->val = fetchb(ctx);
break;
case 2:
p->type = A_IMM16;
p->val = fetchw(ctx);
break;
case 4:
p->type = A_IMM32;
p->val = fetchd(ctx);
break;
case 8:
p->type = A_IMM64;
p->val = fetchq(ctx);
break;
default:
2019-08-03 17:41:44 +02:00
_except(ctx, E_ILL, "%s: Invalid immediate length: %hhu",
in->name, lo);
2019-07-24 16:52:26 +02:00
}
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-07-24 16:52:26 +02:00
//
// Memory operands
//
2019-06-07 22:23:38 +02:00
2019-08-03 17:41:44 +02:00
checklength(ctx, in, lo);
2019-07-24 16:52:26 +02:00
p->mlen = lo;
2019-06-07 22:23:38 +02:00
2019-07-24 16:52:26 +02:00
switch (hi)
2019-06-07 22:23:38 +02:00
{
2019-07-24 16:52:26 +02:00
case 1:
p->type = AM_RR;
p->reg1 = fetchb(ctx);
p->reg2 = p->imm1 = p->imm2 = 0;
break;
case 2:
p->type = AM_RR;
p->reg1 = fetchb(ctx);
p->reg2 = fetchb(ctx);
p->imm1 = 1;
p->imm2 = 0;
break;
case 3:
p->type = AM_RRI;
p->reg1 = fetchb(ctx);
p->reg2 = fetchb(ctx);
p->imm2 = (short)fetchw(ctx);
p->imm1 = 1;
break;
case 4:
p->type = AM_RRI;
p->reg1 = fetchb(ctx);
p->reg2 = fetchb(ctx);
p->imm2 = (int)fetchd(ctx);
p->imm1 = 1;
break;
case 5:
p->type = AM_RRII;
p->reg1 = fetchb(ctx);
p->reg2 = fetchb(ctx);
p->imm1 = fetchb(ctx);
2019-07-24 17:42:42 +02:00
p->imm2 = (short)fetchd(ctx);
2019-07-24 16:52:26 +02:00
break;
case 6:
p->type = AM_RRI;
p->reg1 = fetchb(ctx);
p->imm2 = fetchq(ctx);
p->reg2 = RZX;
p->imm1 = 1;
break;
2019-06-07 22:23:38 +02:00
}
2019-07-24 16:52:26 +02:00
p->addr = R(p->reg1) + R(p->reg2) * (long)p->imm1 + p->imm2;
2019-06-07 22:23:38 +02:00
}
2019-05-30 12:44:56 +02:00
2019-07-24 16:52:26 +02:00
//
// Instruction fetch & decode
//
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;
2019-07-24 16:52:26 +02:00
ushort b1, b2, rep = 0, lock;
2019-07-17 22:25:50 +02:00
acc_t p1 = { 0 }, p2 = { 0 }, p3 = { 0 };
2019-06-17 20:59:30 +02:00
2019-07-24 16:52:26 +02:00
ctx->cur_pc = R(RIP);
2019-06-19 21:41:22 +02:00
2019-07-24 16:52:26 +02:00
// Address range check
// (assumes max. instruction length is 32 bytes)
if (R(RIP) + R(CR1) - MEMOFF >= ctx->mz - 32)
_except(ctx, E_ACC, "Executing out of memory");
2019-07-01 21:46:36 +02:00
2019-07-24 16:52:26 +02:00
// Instruction bytes
b1 = fetchb(ctx);
2019-08-03 18:20:36 +02:00
// Suffixes?
if (b1 & (1 << 7))
{
b1 &= ~(1 << 7);
b2 = fetchb(ctx);
}
else
b2 = 0;
2019-06-07 22:23:38 +02:00
2019-07-24 16:52:26 +02:00
// Renge check
if (b1 >= NINSTRS)
_except(ctx, E_ILL, "No such INSTR: 0x%hhX", b1);
2019-05-15 19:26:40 +02:00
2019-07-17 22:25:50 +02:00
// Find instruction
2019-07-24 16:52:26 +02:00
in = &ctx->i[b1];
2019-07-04 20:33:49 +02:00
ctx->cur_in = in;
2019-06-07 22:23:38 +02:00
2019-07-24 16:52:26 +02:00
// Get flags/etc
rep = !!(b2 & SUFF_REP);
lock = !!(b2 & SUFF_LOCK);
ctx->cond = b2 & SUFF_COND;
2019-06-07 23:25:47 +02:00
2019-07-17 22:25:50 +02:00
// Operand 1?
2019-08-03 17:41:44 +02:00
if (in->nprms == 0)
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-08-03 17:41:44 +02:00
extract_param(ctx, in, &p1);
2019-06-17 20:59:30 +02:00
2019-07-17 22:25:50 +02:00
// Operand 2?
2019-08-03 17:41:44 +02:00
if (in->nprms == 1)
2019-06-17 20:59:30 +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-08-03 17:41:44 +02:00
extract_param(ctx, in, &p2);
2019-06-13 17:13:59 +02:00
2019-07-17 22:25:50 +02:00
// Operand 1?
2019-08-03 17:41:44 +02:00
if (in->nprms == 2)
2019-07-01 21:46:36 +02:00
{
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;
}
2019-08-03 17:41:44 +02:00
extract_param(ctx, in, &p3);
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
}