mirror of
https://gitlab.os-k.eu/os-k-team/kvisc.git
synced 2023-08-25 14:05:46 +02:00
252 lines
4.5 KiB
C
252 lines
4.5 KiB
C
// 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>
|
|
|
|
//
|
|
// Read the "DECD" file before reading this code
|
|
//
|
|
|
|
//
|
|
// Instruction fetch
|
|
//
|
|
|
|
static uchar fetchb(void)
|
|
{
|
|
uchar v = *(ctx->mp + R(RIP) + R(CR1) - MEMOFF);
|
|
R(RIP) += 1;
|
|
|
|
return v;
|
|
}
|
|
|
|
static ushort fetchw(void)
|
|
{
|
|
ushort v = *(ushort *)(ctx->mp + R(RIP) + R(CR1) - MEMOFF);
|
|
R(RIP) += 2;
|
|
|
|
return v;
|
|
}
|
|
|
|
static uint fetchd(void)
|
|
{
|
|
uint v = *(uint *)(ctx->mp + R(RIP) + R(CR1) - MEMOFF);
|
|
R(RIP) += 4;
|
|
|
|
return v;
|
|
}
|
|
|
|
static ulong fetchq(void)
|
|
{
|
|
ulong v = *(ulong *)(ctx->mp + R(RIP) + R(CR1) - MEMOFF);
|
|
R(RIP) += 8;
|
|
|
|
return v;
|
|
}
|
|
|
|
//
|
|
// Verify that access to a certain register is legal
|
|
//
|
|
static void checkreg(uint reg)
|
|
{
|
|
if (reg >= NREGS)
|
|
_except(E_ILL, "Inexistent register: %u", reg);
|
|
|
|
if (ctx->r[reg].flags & RES)
|
|
_except(E_ACC, "Reserved REG: %u", reg);
|
|
|
|
if (ctx->r[reg].flags & SYS)
|
|
if (R(CR0) & UF)
|
|
_except(E_SYS, "User access to SYS REG: %u", reg);
|
|
}
|
|
|
|
//
|
|
// Verify that given access length is that of a byte/word/dword/qword
|
|
//
|
|
static void checklength(instr_t *in, uint len)
|
|
{
|
|
static const int lentab[9] = { 0, 1, 1, 0, 1, 0, 0, 0, 1 };
|
|
|
|
if (len > 8 || lentab[len] == 0)
|
|
_except(E_ILL, "%s: Invalid memory access length: %u",
|
|
in->name, len);
|
|
}
|
|
|
|
//
|
|
// Extracts one operand
|
|
//
|
|
static void extract_param(instr_t *in, acc_t *p)
|
|
{
|
|
// Get next operand ModRM-like byte
|
|
uchar fmt = fetchb();
|
|
|
|
uchar hi = (fmt & 0b11100000) >> 5;
|
|
uchar lo = fmt & 0b00011111;
|
|
|
|
//
|
|
// Registers
|
|
//
|
|
if (hi == 0)
|
|
{
|
|
p->reg = lo;
|
|
p->type = A_REG;
|
|
checkreg(p->reg);
|
|
|
|
p->val = R(p->reg);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Immediates
|
|
//
|
|
if (hi == 7)
|
|
{
|
|
switch (lo)
|
|
{
|
|
case 1:
|
|
p->type = A_IMM8;
|
|
p->val = fetchb();
|
|
break;
|
|
|
|
case 2:
|
|
p->type = A_IMM16;
|
|
p->val = fetchw();
|
|
break;
|
|
|
|
case 4:
|
|
p->type = A_IMM32;
|
|
p->val = fetchd();
|
|
break;
|
|
|
|
case 8:
|
|
p->type = A_IMM64;
|
|
p->val = fetchq();
|
|
break;
|
|
|
|
default:
|
|
_except(E_ILL, "%s: Invalid immediate length: %hhu",
|
|
in->name, lo);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Memory operands
|
|
//
|
|
|
|
checklength(in, lo);
|
|
p->mlen = lo;
|
|
|
|
switch (hi)
|
|
{
|
|
case 1:
|
|
p->type = AM_RR;
|
|
p->reg1 = fetchb();
|
|
p->reg2 = p->imm1 = p->imm2 = 0;
|
|
break;
|
|
|
|
case 2:
|
|
p->type = AM_RR;
|
|
p->reg1 = fetchb();
|
|
p->reg2 = fetchb();
|
|
p->imm1 = 1;
|
|
p->imm2 = 0;
|
|
break;
|
|
|
|
case 3:
|
|
p->type = AM_RRI;
|
|
p->reg1 = fetchb();
|
|
p->imm2 = (short)fetchw();
|
|
p->reg2 = RZX;
|
|
p->imm1 = 1;
|
|
break;
|
|
|
|
case 4:
|
|
p->type = AM_RRI;
|
|
p->reg1 = fetchb();
|
|
p->reg2 = fetchb();
|
|
p->imm2 = (int)fetchd();
|
|
p->imm1 = 1;
|
|
break;
|
|
|
|
case 5:
|
|
p->type = AM_RRII;
|
|
p->reg1 = fetchb();
|
|
p->reg2 = fetchb();
|
|
p->imm1 = fetchb();
|
|
p->imm2 = (short)fetchd();
|
|
break;
|
|
|
|
case 6:
|
|
p->type = AM_RRI;
|
|
p->reg1 = fetchb();
|
|
p->imm2 = fetchq();
|
|
p->reg2 = RZX;
|
|
p->imm1 = 1;
|
|
break;
|
|
}
|
|
|
|
p->addr = R(p->reg1) + R(p->reg2) * (long)p->imm1 + p->imm2;
|
|
}
|
|
|
|
//
|
|
// Instruction fetch & decode
|
|
//
|
|
void decode(void)
|
|
{
|
|
ushort b;
|
|
instr_t *in;
|
|
acc_t p1 = { 0 }, p2 = { 0 }, p3 = { 0 };
|
|
|
|
//logerr("decodin'\n");
|
|
|
|
ctx->cur_pc = R(RIP);
|
|
|
|
// Address range check
|
|
// (assumes max. instruction length is 32 bytes)
|
|
if (R(RIP) + R(CR1) - MEMOFF >= ctx->mz - 32)
|
|
_except(E_ACC, "Executing out of memory");
|
|
|
|
// Instruction bytes
|
|
b = fetchb();
|
|
|
|
// Renge check
|
|
if (b >= NINSTRS)
|
|
_except(E_ILL, "No such INSTR: 0x%hhX", b);
|
|
|
|
// Find instruction
|
|
in = &ctx->i[b];
|
|
ctx->cur_in = in;
|
|
|
|
// Operand 1?
|
|
if (in->nprms == 0)
|
|
{
|
|
exec_instr(in, NULL, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
extract_param(in, &p1);
|
|
|
|
// Operand 2?
|
|
if (in->nprms == 1)
|
|
{
|
|
exec_instr(in, &p1, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
extract_param(in, &p2);
|
|
|
|
// Operand 1?
|
|
if (in->nprms == 2)
|
|
{
|
|
exec_instr(in, &p1, &p2, NULL);
|
|
return;
|
|
}
|
|
|
|
extract_param(in, &p3);
|
|
|
|
exec_instr(in, &p1, &p2, &p3);
|
|
}
|
|
|