kvisc/vm/pc/decode.c

252 lines
4.5 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
//
2019-08-03 19:01:12 +02:00
static uchar fetchb(void)
2019-07-24 16:52:26 +02:00
{
2019-09-08 19:04:07 +02:00
uchar v = *(ctx->mp + R(EIP) + R(CR1) - MEMOFF);
R(EIP) += 1;
2019-07-24 16:52:26 +02:00
return v;
}
2019-08-03 19:01:12 +02:00
static ushort fetchw(void)
2019-05-16 21:42:23 +02:00
{
2019-09-08 19:04:07 +02:00
ushort v = *(ushort *)(ctx->mp + R(EIP) + R(CR1) - MEMOFF);
R(EIP) += 2;
2019-07-24 16:52:26 +02:00
return v;
}
2019-05-16 21:42:23 +02:00
2019-08-03 19:01:12 +02:00
static uint fetchd(void)
2019-07-24 16:52:26 +02:00
{
2019-09-08 19:04:07 +02:00
uint v = *(uint *)(ctx->mp + R(EIP) + R(CR1) - MEMOFF);
R(EIP) += 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-08-03 19:01:12 +02:00
static ulong fetchq(void)
2019-07-24 16:52:26 +02:00
{
2019-09-08 19:04:07 +02:00
ulong v = *(ulong *)(ctx->mp + R(EIP) + R(CR1) - MEMOFF);
R(EIP) += 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-08-03 19:01:12 +02:00
static void checkreg(uint reg)
2019-06-07 22:23:38 +02:00
{
if (reg >= NREGS)
2019-08-03 19:01:12 +02:00
_except(E_ILL, "Inexistent register: %u", reg);
2019-06-07 22:23:38 +02:00
2019-07-11 18:34:21 +02:00
if (ctx->r[reg].flags & RES)
2019-08-03 19:01:12 +02:00
_except(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-08-03 19:01:12 +02:00
_except(E_SYS, "User access to SYS REG: %u", reg);
2019-06-07 22:23:38 +02:00
}
//
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 19:01:12 +02:00
static void checklength(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 19:01:12 +02:00
_except(E_ILL, "%s: Invalid memory access length: %u",
2019-08-03 17:41:44 +02:00
in->name, len);
2019-07-24 16:52:26 +02:00
}
//
// Extracts one operand
//
2019-08-03 19:01:12 +02:00
static void extract_param(instr_t *in, acc_t *p)
2019-07-24 16:52:26 +02:00
{
// Get next operand ModRM-like byte
2019-08-03 19:01:12 +02:00
uchar fmt = fetchb();
2019-07-24 16:52:26 +02:00
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-08-03 19:01:12 +02:00
checkreg(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;
2019-08-03 19:01:12 +02:00
p->val = fetchb();
2019-07-24 16:52:26 +02:00
break;
case 2:
p->type = A_IMM16;
2019-08-03 19:01:12 +02:00
p->val = fetchw();
2019-07-24 16:52:26 +02:00
break;
case 4:
p->type = A_IMM32;
2019-08-03 19:01:12 +02:00
p->val = fetchd();
2019-07-24 16:52:26 +02:00
break;
case 8:
p->type = A_IMM64;
2019-08-03 19:01:12 +02:00
p->val = fetchq();
2019-07-24 16:52:26 +02:00
break;
default:
2019-08-03 19:01:12 +02:00
_except(E_ILL, "%s: Invalid immediate length: %hhu",
2019-08-03 17:41:44 +02:00
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 19:01:12 +02:00
checklength(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;
2019-08-03 19:01:12 +02:00
p->reg1 = fetchb();
2019-07-24 16:52:26 +02:00
p->reg2 = p->imm1 = p->imm2 = 0;
break;
case 2:
p->type = AM_RR;
2019-08-03 19:01:12 +02:00
p->reg1 = fetchb();
p->reg2 = fetchb();
2019-07-24 16:52:26 +02:00
p->imm1 = 1;
p->imm2 = 0;
break;
case 3:
p->type = AM_RRI;
2019-08-03 19:01:12 +02:00
p->reg1 = fetchb();
p->imm2 = (short)fetchw();
2019-09-08 19:04:07 +02:00
p->reg2 = EZX;
2019-07-24 16:52:26 +02:00
p->imm1 = 1;
break;
case 4:
p->type = AM_RRI;
2019-08-03 19:01:12 +02:00
p->reg1 = fetchb();
p->reg2 = fetchb();
p->imm2 = (int)fetchd();
2019-07-24 16:52:26 +02:00
p->imm1 = 1;
break;
case 5:
p->type = AM_RRII;
2019-08-03 19:01:12 +02:00
p->reg1 = fetchb();
p->reg2 = fetchb();
p->imm1 = fetchb();
p->imm2 = (short)fetchd();
2019-07-24 16:52:26 +02:00
break;
case 6:
p->type = AM_RRI;
2019-08-03 19:01:12 +02:00
p->reg1 = fetchb();
p->imm2 = fetchq();
2019-09-08 19:04:07 +02:00
p->reg2 = EZX;
2019-07-24 16:52:26 +02:00
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-08-03 19:01:12 +02:00
void decode(void)
2019-06-07 22:23:38 +02:00
{
2019-08-14 20:23:05 +02:00
ushort b;
2019-06-17 20:59:30 +02:00
instr_t *in;
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-08-08 18:39:12 +02:00
//logerr("decodin'\n");
2019-09-08 19:04:07 +02:00
ctx->cur_pc = R(EIP);
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)
2019-09-08 19:04:07 +02:00
if (R(EIP) + R(CR1) - MEMOFF >= ctx->mz - 32)
2019-08-03 19:01:12 +02:00
_except(E_ACC, "Executing out of memory");
2019-07-01 21:46:36 +02:00
2019-07-24 16:52:26 +02:00
// Instruction bytes
2019-08-14 20:23:05 +02:00
b = fetchb();
2019-06-07 22:23:38 +02:00
2019-07-24 16:52:26 +02:00
// Renge check
2019-08-14 20:23:05 +02:00
if (b >= NINSTRS)
_except(E_ILL, "No such INSTR: 0x%hhX", b);
2019-05-15 19:26:40 +02:00
2019-07-17 22:25:50 +02:00
// Find instruction
2019-08-14 20:23:05 +02:00
in = &ctx->i[b];
2019-07-04 20:33:49 +02:00
ctx->cur_in = in;
2019-06-07 22:23:38 +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-08-14 20:23:05 +02:00
exec_instr(in, NULL, NULL, NULL);
2019-06-17 20:59:30 +02:00
return;
2019-06-12 15:47:11 +02:00
}
2019-08-03 19:01:12 +02:00
extract_param(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-08-14 20:23:05 +02:00
exec_instr(in, &p1, NULL, NULL);
2019-06-17 20:59:30 +02:00
return;
}
2019-06-13 17:13:59 +02:00
2019-08-03 19:01:12 +02:00
extract_param(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-08-14 20:23:05 +02:00
exec_instr(in, &p1, &p2, NULL);
2019-07-01 21:46:36 +02:00
return;
}
2019-08-03 19:01:12 +02:00
extract_param(in, &p3);
2019-06-13 15:32:24 +02:00
2019-08-14 20:23:05 +02:00
exec_instr(in, &p1, &p2, &p3);
2019-05-15 19:26:40 +02:00
}