mirror of
https://gitlab.os-k.eu/os-k-team/kvisc.git
synced 2023-08-25 14:05:46 +02:00
new decoding
This commit is contained in:
parent
1a12699fb6
commit
0a9d1bdc93
@ -10,15 +10,15 @@ dv_src = $(shell ls dv/*.c)
|
||||
in_src = $(shell ls in/*.c)
|
||||
pc_src = $(shell ls pc/*.c)
|
||||
|
||||
obj = pc/disd.o
|
||||
obj += $(patsubst %.c,%.o,$(dv_src))
|
||||
#obj = pc/disd.o
|
||||
obj = $(patsubst %.c,%.o,$(dv_src))
|
||||
obj += $(patsubst %.c,%.o,$(in_src))
|
||||
obj += $(patsubst %.c,%.o,$(pc_src))
|
||||
|
||||
FLAGS=-O2 -g -Wall -fno-builtin-log -I.
|
||||
|
||||
pc/disd.o: in/i_arch.h */*.h pc/decd.c
|
||||
@cc $(FLAGS) -D_NEED_DISASM -c pc/decd.c -o $@
|
||||
#pc/disd.o: in/i_arch.h */*.h pc/decd.c
|
||||
# @cc $(FLAGS) -D_NEED_DISASM -c pc/decd.c -o $@
|
||||
|
||||
%.o: %.c in/i_arch.h */*.h $(src)
|
||||
@cc $(FLAGS) -c $< -o $@
|
||||
|
@ -46,7 +46,7 @@ IMPL_START_2(devctl)
|
||||
dev_t *dev = devctl_common(ctx, v1, v2);
|
||||
|
||||
if (dev == NULL)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
switch (v2) {
|
||||
case 0:
|
||||
@ -90,7 +90,7 @@ IMPL_START_2(iocall)
|
||||
dev_t *dev = devctl_common(ctx, v1, v2);
|
||||
|
||||
if (dev == NULL)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
if (v2 >= DEVSLOTS)
|
||||
rax = -6;
|
||||
|
@ -31,38 +31,7 @@ def getflag(s):
|
||||
|
||||
return "__FLAG_ERROR__"
|
||||
|
||||
def doprnt(i, p1, p2, cond):
|
||||
doprnt_2(i, p1, p2)
|
||||
|
||||
if cond:
|
||||
doprnt_2(i + '$cxz', p1, p2)
|
||||
doprnt_2(i + '$cxnz', p1, p2)
|
||||
|
||||
doprnt_2(i + '$c', p1, p2)
|
||||
doprnt_2(i + '$o', p1, p2)
|
||||
doprnt_2(i + '$z', p1, p2)
|
||||
doprnt_2(i + '$s', p1, p2)
|
||||
doprnt_2(i + '$p', p1, p2)
|
||||
doprnt_2(i + '$e', p1, p2)
|
||||
doprnt_2(i + '$eq', p1, p2)
|
||||
|
||||
doprnt_2(i + '$a', p1, p2)
|
||||
doprnt_2(i + '$ae', p1, p2)
|
||||
doprnt_2(i + '$b', p1, p2)
|
||||
doprnt_2(i + '$be', p1, p2)
|
||||
doprnt_2(i + '$l', p1, p2)
|
||||
doprnt_2(i + '$le', p1, p2)
|
||||
doprnt_2(i + '$g', p1, p2)
|
||||
doprnt_2(i + '$ge', p1, p2)
|
||||
|
||||
doprnt_2(i + '$nc', p1, p2)
|
||||
doprnt_2(i + '$no', p1, p2)
|
||||
doprnt_2(i + '$nz', p1, p2)
|
||||
doprnt_2(i + '$ns', p1, p2)
|
||||
doprnt_2(i + '$np', p1, p2)
|
||||
doprnt_2(i + '$ne', p1, p2)
|
||||
|
||||
def doprnt_2(i, p1, p2):
|
||||
def doprnt(i, p1, p2):
|
||||
for c1 in p1:
|
||||
for c2 in p2:
|
||||
fp.write("{} {} {}".format(i, c1, c2).strip())
|
||||
@ -83,17 +52,16 @@ for _, line in enumerate(fi):
|
||||
if tok[0][0] == '!':
|
||||
assert(len(tok[0]) > 1)
|
||||
tok[0] = tok[0][1:]
|
||||
cond = True
|
||||
|
||||
i = tok[0].strip()
|
||||
|
||||
if len(tok) == 1:
|
||||
doprnt(i, ' ', ' ', cond)
|
||||
doprnt(i, ' ', ' ')
|
||||
continue
|
||||
|
||||
if len(tok) == 2:
|
||||
p = tok[1].strip()
|
||||
doprnt(i, p, ' ', cond)
|
||||
doprnt(i, p, ' ')
|
||||
continue
|
||||
|
||||
assert(len(tok) == 3)
|
||||
@ -101,7 +69,7 @@ for _, line in enumerate(fi):
|
||||
p1 = tok[1].strip()
|
||||
p2 = tok[2].strip()
|
||||
|
||||
doprnt(i, p1, p2, cond)
|
||||
doprnt(i, p1, p2)
|
||||
|
||||
fp.seek(0)
|
||||
|
||||
@ -135,7 +103,7 @@ for _, line in enumerate(fp):
|
||||
.format(tok[0], name, p1, p2, tok[0]))
|
||||
hd.write("#else\n")
|
||||
hd.write("#define I_{} {}\n".format(name.upper(), count))
|
||||
hd.write("extern void i_{}(ctx_t *, acc_t *, acc_t *);\n"
|
||||
hd.write("extern bool i_{}(ctx_t *, acc_t *, acc_t *, ulong *);\n"
|
||||
.format(tok[0]))
|
||||
hd.write("#endif\n\n")
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// The OS/K Team licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
/*
|
||||
#define _IMPL_IF_COND(name, suf, cond) \
|
||||
IMPL_START_0(name##$##suf) \
|
||||
{ \
|
||||
@ -44,4 +45,6 @@ IMPL_END \
|
||||
\
|
||||
_IMPL_IF_COND(name, g, !(flg&ZF) && (!!(flg&SF) == !!(flg&OF))); \
|
||||
_IMPL_IF_COND(name, ge, !!(flg&SF) == !!(flg&OF)); \
|
||||
*/
|
||||
|
||||
#define IMPL_COND(name)
|
||||
|
@ -7,62 +7,38 @@
|
||||
#include <in/flags.h>
|
||||
#include <in/arch_i.h>
|
||||
|
||||
#define DECV(p, v) \
|
||||
ulong v = (p->type == A_REG ? R(p->val) : p->val); \
|
||||
if (p->mem) { \
|
||||
v = readmem(ctx, v + p->off + R(p->offreg), p1->mlen); \
|
||||
}
|
||||
|
||||
#define IMPL_START_0(name) \
|
||||
void i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2) \
|
||||
bool i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2, ulong *ret) \
|
||||
{
|
||||
|
||||
#define IMPL_START_1(name) \
|
||||
void i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2) \
|
||||
bool i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2, ulong *ret) \
|
||||
{ \
|
||||
DECV(p1, v1);
|
||||
ulong v1 = p1->val;
|
||||
|
||||
#define IMPL_START_2(name) \
|
||||
void i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2) \
|
||||
bool i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2, ulong *ret) \
|
||||
{ \
|
||||
DECV(p1, v1); \
|
||||
DECV(p2, v2);
|
||||
|
||||
#define IMPL_START_3(name) \
|
||||
void i_##name(ctx_t *ctx, acc_t *p1, acc_t *p2) \
|
||||
{ \
|
||||
DECV(p2, v2);
|
||||
ulong v1 = p1->val; \
|
||||
ulong v2 = p2->val;
|
||||
|
||||
#define IMPL_OUT_ZSF \
|
||||
SET_ZSF(v1); \
|
||||
IMPL_OUT
|
||||
|
||||
#define IMPL_OUT \
|
||||
assert(p1->type == A_REG || p1->mem); \
|
||||
if (p1->mem) { \
|
||||
ulong addr = p1->type == A_REG ? R(p1->val) : p1->val; \
|
||||
writemem(ctx, v1, addr + p1->off + R(p1->offreg), p1->mlen); \
|
||||
} \
|
||||
else R(p1->val) = v1; \
|
||||
*ret = v1; \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
// XXX
|
||||
#define IMPL_OUT_2 \
|
||||
assert(p1->type == A_REG || p1->mem); \
|
||||
if (p1->mem) { \
|
||||
ulong addr = p1->type == A_REG ? R(p1->val) : p1->val; \
|
||||
writemem(ctx, v1, addr + p1->off + R(p1->offreg), p1->mlen); \
|
||||
} \
|
||||
else R(p1->val) = v1; \
|
||||
\
|
||||
assert(p2->type == A_REG || p2->mem); \
|
||||
if (p2->mem) { \
|
||||
ulong addr = p2->type == A_REG ? R(p2->val) : p2->val; \
|
||||
writemem(ctx, v2, addr + p2->off + R(p2->offreg), p2->mlen); \
|
||||
} \
|
||||
else R(p2->val) = v2; \
|
||||
*ret = v1; \
|
||||
return 1; \
|
||||
}
|
||||
|
||||
#define IMPL_END \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -68,13 +68,7 @@ IMPL_OUT_2;
|
||||
|
||||
IMPL_START_1(lea)
|
||||
{
|
||||
ulong v2 = (p2->type == A_REG ? R(p2->val) : p2->val);
|
||||
|
||||
if (p2->mem) {
|
||||
v2 += p2->off + R(p2->offreg);
|
||||
}
|
||||
|
||||
v1 = v2;
|
||||
v1 = p2->addr;
|
||||
}
|
||||
IMPL_OUT;
|
||||
|
||||
|
52
vm/pc/DECD
Normal file
52
vm/pc/DECD
Normal file
@ -0,0 +1,52 @@
|
||||
# The OS/K Team licenses this file to you under the MIT license.
|
||||
# See the LICENSE file in the project root for more information.
|
||||
|
||||
Instruction encoding:
|
||||
|
||||
15 0 15 0
|
||||
xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx
|
||||
││└────────────┘ │└───┘└───┘└───┘
|
||||
││ INSTR. │ CND FT1 FT2
|
||||
││ │
|
||||
LM R
|
||||
|
||||
M No more words
|
||||
L LOCK prefix
|
||||
R REP prefix
|
||||
D Destination register
|
||||
|
||||
Values for COND:
|
||||
00000 (none)
|
||||
00001 .C
|
||||
00010 .O
|
||||
00011 .Z .E
|
||||
00100 .S
|
||||
00101 .P
|
||||
00110 .A
|
||||
00111 .AE
|
||||
01000 .B
|
||||
01001 .BE
|
||||
01010 .G
|
||||
01011 .GE
|
||||
01100 .L
|
||||
01101 .LE
|
||||
01110 .CXZ
|
||||
01111 (reserved)
|
||||
Highest (6th) bit of COND indicates negation
|
||||
|
||||
Fx values:
|
||||
0000 (none)
|
||||
0001 reg
|
||||
0010 imm64
|
||||
|
||||
xxx00 [imm64]
|
||||
xxx01 [reg+reg]
|
||||
xxx10 [reg+reg+imm16] code(reg)|code(reg) imm16
|
||||
xxx11 [reg+reg*imm16+imm16] code(reg)|code(reg) imm16 imm16
|
||||
|
||||
Where xxx is:
|
||||
001 8-bit access
|
||||
010 16-bit access
|
||||
011 32-bit access
|
||||
100 64-bit access
|
||||
|
66
vm/pc/arch.h
66
vm/pc/arch.h
@ -35,67 +35,6 @@ typedef struct dev_t dev_t;
|
||||
void log(const char *, ...);
|
||||
void vlog(const char *, va_list);
|
||||
|
||||
// A_REG is implicit
|
||||
// A_MEM denotes a memory access
|
||||
// A_OFF is A_MEM but a 16-bit offset is expected immediatly next
|
||||
enum
|
||||
{
|
||||
A_REG = 0,
|
||||
|
||||
A_MEM8 = 0x7001,
|
||||
A_MEM16 = 0x7002,
|
||||
A_MEM32 = 0x7004,
|
||||
A_MEM64 = 0x7008,
|
||||
|
||||
A_OFF8 = 0x7701,
|
||||
A_OFF16 = 0x7702,
|
||||
A_OFF32 = 0x7704,
|
||||
A_OFF64 = 0x7708,
|
||||
|
||||
A_IMM16 = 0x7772,
|
||||
A_IMM32 = 0x7774,
|
||||
A_IMM64 = 0x7778
|
||||
};
|
||||
|
||||
#define A_IS_MEM(x) ((x) >= A_MEM8 && (x) <= A_MEM64)
|
||||
#define A_IS_OFF(x) ((x) >= A_OFF8 && (x) <= A_OFF64)
|
||||
#define A_IS_IMM(x) ((x) >= A_IMM16)
|
||||
|
||||
#define A_IS_8(x) ((x) & 0xF == 1)
|
||||
#define A_IS_16(x) ((x) & 0xF == 2)
|
||||
#define A_IS_32(x) ((x) & 0xF == 3)
|
||||
#define A_IS_64(x) ((x) & 0xF == 4)
|
||||
|
||||
struct acc_t
|
||||
{
|
||||
bool mem;
|
||||
uint mlen;
|
||||
short off;
|
||||
uint offreg;
|
||||
|
||||
uint type;
|
||||
uint ilen;
|
||||
ulong val;
|
||||
};
|
||||
|
||||
enum { NOPREF, PREF_REP=0x8000, PREF_LOCK, NPREFS };
|
||||
|
||||
#define ISPREF(x) ((x) & 0x8000 && (x)<NPREFS)
|
||||
#define ISINSTR(x) ((x) < NINSTRS)
|
||||
|
||||
enum { NOPRM, P_REG, P_IMM, P_MEM=4 };
|
||||
|
||||
struct instr_t
|
||||
{
|
||||
char *name;
|
||||
char *full;
|
||||
|
||||
uint prm1;
|
||||
uint prm2;
|
||||
|
||||
void (*func)(ctx_t *, acc_t *, acc_t *);
|
||||
};
|
||||
|
||||
struct ctx_t
|
||||
{
|
||||
reg_t *r;
|
||||
@ -142,11 +81,9 @@ enum
|
||||
void dumpregs(ctx_t *);
|
||||
void dumpinstr(ctx_t *, ulong, uint, ushort, acc_t *, acc_t *);
|
||||
void dumpmem(ctx_t *, ulong, ulong);
|
||||
void dumpfwstack(ctx_t *);
|
||||
|
||||
void _except(ctx_t *, int, char *, ...);
|
||||
void _except(ctx_t *, int, char *, ...) __attribute__((__noreturn__));
|
||||
|
||||
void disasm(ctx_t *ctx);
|
||||
void decode(ctx_t *ctx);
|
||||
|
||||
#define MEMOFF (1 * 1024 * 1024)
|
||||
@ -171,6 +108,7 @@ void writemem64(ctx_t *, ulong val, ulong addr);
|
||||
void writemem(ctx_t *, ulong val, ulong addr, uint len);
|
||||
|
||||
#include <pc/regs.h>
|
||||
#include <pc/decd.h>
|
||||
#include <in/arch_i.h>
|
||||
|
||||
extern reg_t arch_r[NREGS];
|
||||
|
501
vm/pc/decd.c
501
vm/pc/decd.c
@ -3,149 +3,392 @@
|
||||
|
||||
#include <pc/arch.h>
|
||||
|
||||
#ifdef _NEED_DISASM
|
||||
#define _except __except
|
||||
//
|
||||
// Imperatively read the "DECD" file before reading this code
|
||||
//
|
||||
|
||||
static inline void _except(ctx_t *ctx, int x, char *fmt, ...)
|
||||
static void check_param_type(ctx_t *ctx, uint prm, uchar fmt)
|
||||
{
|
||||
va_list ap;
|
||||
bool ok;
|
||||
|
||||
log("Disassembly error: ");
|
||||
if (prm == P_REG)
|
||||
ok = (fmt == A_REG);
|
||||
|
||||
va_start(ap, fmt);
|
||||
vlog(fmt, ap);
|
||||
va_end(ap);
|
||||
else if (prm == P_IMM)
|
||||
ok = (fmt == A_IMM64);
|
||||
|
||||
else /* if (prm == P_MEM */
|
||||
ok = ACC_FMT_IS_MEM(fmt);
|
||||
|
||||
if (!ok)
|
||||
_except(ctx, E_ILL,
|
||||
"FT1 or FT2 not matching INSTR's expected parameter types");
|
||||
}
|
||||
|
||||
void decode(ctx_t *ctx)
|
||||
{
|
||||
char *illmsg;
|
||||
|
||||
instr_t *in;
|
||||
|
||||
acc_t p1 = { 0 };
|
||||
acc_t p2 = { 0 };
|
||||
|
||||
bool rep = 0, cond = 0;
|
||||
bool lock, nomore;
|
||||
|
||||
ushort w1, w2;
|
||||
uchar f1 = 0, f2 = 0;
|
||||
|
||||
ulong pc = rip;
|
||||
|
||||
//
|
||||
// Process the first word of the instruction
|
||||
//
|
||||
|
||||
w1 = ctx->get(ctx);
|
||||
|
||||
// Extract first word flags
|
||||
|
||||
lock = !!(w1 & PREF_LOCK);
|
||||
nomore = !!(w1 & PREF_NOMORE);
|
||||
|
||||
w1 &= ~(PREF_LOCK|PREF_NOMORE);
|
||||
|
||||
// Find instruction
|
||||
|
||||
if (w1 >= NINSTRS)
|
||||
{
|
||||
illmsg = "No such INSTR";
|
||||
goto ill;
|
||||
}
|
||||
|
||||
in = &ctx->i[w1];
|
||||
|
||||
if (!nomore)
|
||||
goto skip_w2;
|
||||
|
||||
//
|
||||
// Process second word
|
||||
//
|
||||
|
||||
w2 = ctx->get(ctx);
|
||||
|
||||
// REP and COND
|
||||
rep = w2 & PREF_REP;
|
||||
cond = (w2 & BITS_COND) >> COND_SHIFT;
|
||||
|
||||
// F1 and F2
|
||||
f1 = (w2 >> F1_SHIFT) & Fx_MASK;
|
||||
f2 = w2 & Fx_MASK;
|
||||
|
||||
skip_w2:
|
||||
|
||||
//
|
||||
// Deal with operand 1
|
||||
//
|
||||
|
||||
if (in->prm1 == NOPRM)
|
||||
{
|
||||
if (f1 || f2)
|
||||
{
|
||||
illmsg = "FT1 and/or FT2 filled for 0-param INSTR";
|
||||
goto ill;
|
||||
}
|
||||
|
||||
exec_instr(ctx, in, NULL, NULL, lock, rep, cond, pc);
|
||||
return;
|
||||
}
|
||||
|
||||
check_param_type(ctx, in->prm1, f1);
|
||||
extract_param(ctx, &p1, f1);
|
||||
|
||||
//
|
||||
// Deal with operand 2
|
||||
//
|
||||
|
||||
if (in->prm2 == NOPRM)
|
||||
{
|
||||
if (f2)
|
||||
{
|
||||
illmsg = "FT2 filled for 1-param INSTR";
|
||||
goto ill;
|
||||
}
|
||||
|
||||
exec_instr(ctx, in, &p1, NULL, lock, rep, cond, pc);
|
||||
return;
|
||||
}
|
||||
|
||||
check_param_type(ctx, in->prm2, f2);
|
||||
extract_param(ctx, &p2, f2);
|
||||
|
||||
exec_instr(ctx, in, &p1, &p2, lock, rep, cond, pc);
|
||||
return;
|
||||
|
||||
ill:
|
||||
_except(ctx, E_ILL, illmsg);
|
||||
}
|
||||
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (ctx->r[reg].flags & (RES | CTL))
|
||||
_except(ctx, E_ACC, "Reserved REG: %u", reg);
|
||||
|
||||
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)
|
||||
{
|
||||
uint mlen, mfmt, reg1, reg2, imm1 = 0, imm2 = 0;
|
||||
ushort temp;
|
||||
|
||||
p->type = fmt;
|
||||
|
||||
if (fmt == A_REG)
|
||||
{
|
||||
p->reg = ctx->get(ctx);
|
||||
checkreg(ctx, p->reg, 0);
|
||||
|
||||
p->val = R(p->reg);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
reg1 = temp >> 8;
|
||||
reg2 = temp & 0xFF;
|
||||
|
||||
checkreg(ctx, reg1, 0);
|
||||
checkreg(ctx, reg2, 1);
|
||||
|
||||
if (fmt == AM_RRI)
|
||||
{
|
||||
imm1 = 1;
|
||||
imm2 = ctx->get(ctx);
|
||||
}
|
||||
|
||||
else if (fmt == AM_RRII)
|
||||
{
|
||||
imm1 = ctx->get(ctx);
|
||||
imm2 = ctx->get(ctx);
|
||||
}
|
||||
|
||||
p->addr = R(reg1) + R(reg2) * imm1 + imm2;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
_except(ctx, E_ILL, "Invalid MFMT for access: %x", fmt);
|
||||
}
|
||||
|
||||
p->val = readmem(ctx, p->addr, p->mlen);
|
||||
}
|
||||
|
||||
static bool eval_cond(ctx_t *ctx, uint cond)
|
||||
{
|
||||
bool neg = cond & (1 << 5);
|
||||
bool ok;
|
||||
|
||||
cond &= ~(1 << 5);
|
||||
|
||||
switch (cond)
|
||||
{
|
||||
case CD_C: ok = flg&CF; break;
|
||||
case CD_O: ok = flg&OF; break;
|
||||
case CD_Z: ok = flg&ZF; break;
|
||||
case CD_S: ok = flg&SF; break;
|
||||
case CD_P: ok = flg&PF; break;
|
||||
|
||||
case CD_A: ok = !(flg&CF || flg&ZF); break;
|
||||
case CD_AE: ok = !(flg&CF); break;
|
||||
|
||||
case CD_B: ok = flg&CF; break;
|
||||
case CD_BE: ok = flg&CF || flg&ZF; break;
|
||||
|
||||
case CD_G: ok = !(flg&ZF) && (!(flg&SF) == !(flg&OF)); break;
|
||||
case CD_GE: ok = !(flg&SF) == !(flg&OF); break;
|
||||
|
||||
case CD_L: ok = !(flg&SF) != !(flg&OF); break;
|
||||
case CD_LE: ok = flg&ZF || (!(flg&SF) != !(flg&OF)); break;
|
||||
|
||||
case CD_CXZ: ok = !rcx; break;
|
||||
|
||||
default:
|
||||
_except(ctx, E_ILL, "Invalid COND value: %x", cond);
|
||||
}
|
||||
|
||||
return neg ? !ok : !!ok;
|
||||
}
|
||||
|
||||
char *cond_suffixes[] =
|
||||
{
|
||||
"",
|
||||
".c"
|
||||
};
|
||||
|
||||
static void dump_acc(ctx_t *ctx, acc_t *p)
|
||||
{
|
||||
uint mfmt;
|
||||
|
||||
if (p->type == A_REG)
|
||||
log("%s", ctx->r[p->reg].name);
|
||||
|
||||
else if (p->type == A_IMM64)
|
||||
log("imm64:0x%016lX", p->val);
|
||||
|
||||
else
|
||||
{
|
||||
log("%c[", getmempref(p->mlen));
|
||||
|
||||
mfmt = p->type & AM_MFMT_MASK;
|
||||
|
||||
if (mfmt == AM_IMM64)
|
||||
log("imm64:");
|
||||
|
||||
else if (mfmt == AM_RR)
|
||||
log("rr:");
|
||||
|
||||
else if (mfmt == AM_RRI)
|
||||
log("rri:");
|
||||
|
||||
else if (mfmt == AM_RRII)
|
||||
log("rrii:");
|
||||
|
||||
log("0x%016lX]", p->addr);
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_instr(
|
||||
ctx_t *ctx, instr_t *in,
|
||||
acc_t *p1, acc_t *p2,
|
||||
bool lock, bool rep,
|
||||
uint cond, ulong pc)
|
||||
{
|
||||
log("0x%016lX: ", pc);
|
||||
|
||||
if (lock)
|
||||
log("lock ");
|
||||
|
||||
if (rep)
|
||||
log("rep ");
|
||||
|
||||
if (cond)
|
||||
log("cond%u ", cond);
|
||||
|
||||
log("%s ", in->full);
|
||||
|
||||
if (p1) {
|
||||
dump_acc(ctx, p1);
|
||||
|
||||
if (p2) {
|
||||
log(", ");
|
||||
dump_acc(ctx, p2);
|
||||
}
|
||||
}
|
||||
|
||||
log("\n");
|
||||
|
||||
if (ctx->disf)
|
||||
fclose(ctx->disf);
|
||||
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void scan_param(ctx_t *ctx, acc_t *p)
|
||||
//
|
||||
// Executes an instruction
|
||||
//
|
||||
void exec_instr(
|
||||
ctx_t *ctx, instr_t *in,
|
||||
acc_t *p1, acc_t *p2,
|
||||
bool lock, bool rep,
|
||||
uint cond, ulong pc)
|
||||
{
|
||||
ushort c;
|
||||
reg_t *r;
|
||||
|
||||
c = ctx->get(ctx);
|
||||
|
||||
if (A_IS_MEM(c)) {
|
||||
p->mem = 1;
|
||||
p->off = 0;
|
||||
p->mlen = c & 0xF;
|
||||
c = ctx->get(ctx);
|
||||
}
|
||||
|
||||
else if (A_IS_OFF(c)) {
|
||||
p->mem = 1;
|
||||
p->mlen = c & 0xF;
|
||||
p->off = (short)ctx->get(ctx);
|
||||
|
||||
p->offreg = ctx->get(ctx);
|
||||
|
||||
if (p->offreg > NREGS) {
|
||||
_except(ctx, E_ILL, "Inexistent REG (offreg)");
|
||||
}
|
||||
|
||||
if (p->offreg != INV) {
|
||||
r = &ctx->r[p->offreg];
|
||||
|
||||
if (r->flags & (RES | CTL)) {
|
||||
_except(ctx, E_ACC, "Reserved REG (offreg): %s", r->name);
|
||||
}
|
||||
}
|
||||
|
||||
c = ctx->get(ctx);
|
||||
}
|
||||
|
||||
if (c >= A_IMM16) {
|
||||
// Check for double access code
|
||||
if (p->type != A_REG)
|
||||
_except(ctx, E_ILL, "Bad access code");
|
||||
|
||||
p->type = c;
|
||||
c = ctx->get(ctx);
|
||||
}
|
||||
|
||||
p->val = c;
|
||||
|
||||
if (p->type == A_IMM32) {
|
||||
p->ilen = 4;
|
||||
p->val = p->val | ((ulong)ctx->get(ctx) << 16);
|
||||
}
|
||||
|
||||
else if (p->type == A_IMM64) {
|
||||
p->ilen = 8;
|
||||
p->val = p->val | ((ulong)ctx->get(ctx) << 16);
|
||||
p->val = p->val | ((ulong)ctx->get(ctx) << 32);
|
||||
p->val = p->val | ((ulong)ctx->get(ctx) << 48);
|
||||
}
|
||||
|
||||
else if (p->type == A_REG) {
|
||||
if (p->val > NREGS) {
|
||||
_except(ctx, E_ILL, "Inexistent REG");
|
||||
}
|
||||
|
||||
r = &ctx->r[p->val];
|
||||
|
||||
if (r->flags & (RES | CTL)) {
|
||||
_except(ctx, E_ACC, "Reserved REG: %s", r->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _NEED_DISASM
|
||||
void decode(ctx_t *ctx)
|
||||
#else
|
||||
void disasm(ctx_t *ctx)
|
||||
#endif
|
||||
{
|
||||
instr_t *i;
|
||||
acc_t p1 = { 0 }, p2 = { 0 };
|
||||
|
||||
uint rep = 0;
|
||||
ulong orig_rip = rip;
|
||||
ushort c = ctx->get(ctx);
|
||||
|
||||
if (ISPREF(c)) {
|
||||
if (c == PREF_REP) {
|
||||
rep = 1;
|
||||
c = ctx->get(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
else if (!ISINSTR(c)) {
|
||||
_except(ctx, E_ILL, "Bad opcode: 0x%04hX", c);
|
||||
}
|
||||
|
||||
i = &ctx->i[c];
|
||||
|
||||
// Scan for parameters
|
||||
if (i->prm1 != NOPRM) {
|
||||
scan_param(ctx, &p1);
|
||||
if (i->prm2 != NOPRM) {
|
||||
scan_param(ctx, &p2);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _NEED_DISASM
|
||||
dumpinstr(ctx, orig_rip, rep, c, &p1, &p2);
|
||||
#else
|
||||
bool out = 0;
|
||||
ulong ret = 0;
|
||||
|
||||
// Debugging
|
||||
dump_instr(ctx, in, p1, p2, lock, rep, cond, pc);
|
||||
|
||||
if (rep && !cond)
|
||||
cond = CD_CXZ;
|
||||
|
||||
do_rep:
|
||||
dumpinstr(ctx, orig_rip, rep, c, &p1, &p2);
|
||||
i->func(ctx, &p1, &p2);
|
||||
|
||||
if (!eval_cond(ctx, cond))
|
||||
return;
|
||||
|
||||
out = in->func(ctx, p1, p2, &ret);
|
||||
|
||||
if (out)
|
||||
{
|
||||
if (p1->type == A_REG)
|
||||
R(p1->reg) = ret;
|
||||
|
||||
else if (p1->type == A_IMM64)
|
||||
_except(ctx, E_ACC, "Trying to output on an IMM64");
|
||||
|
||||
else
|
||||
{
|
||||
assert(ACC_IS_MEM(p1));
|
||||
writemem(ctx, ret, p1->addr, p1->mlen);
|
||||
}
|
||||
}
|
||||
|
||||
if (rep)
|
||||
{
|
||||
if (cond == CD_CXZ)
|
||||
rcx--;
|
||||
|
||||
if (rep && rcx > 0) {
|
||||
rcx--;
|
||||
goto do_rep;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
116
vm/pc/decd.h
Normal file
116
vm/pc/decd.h
Normal file
@ -0,0 +1,116 @@
|
||||
// The OS/K Team licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
enum
|
||||
{
|
||||
CD_NONE,
|
||||
|
||||
CD_C, CD_O, CD_Z, CD_S, CD_P,
|
||||
CD_A, CD_AE, CD_B, CD_BE,
|
||||
CD_G, CD_GE, CD_L, CD_LE,
|
||||
CD_CXZ, COND_RES,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PREF_LOCK = (1 << 15),
|
||||
PREF_NOMORE = (1 << 14),
|
||||
|
||||
PREF_REP = (1 << 15),
|
||||
|
||||
BITS_COND = (1 << 14) | (1 << 13) | (1 << 12)
|
||||
| (1 << 11) | (1 << 10),
|
||||
|
||||
COND_SHIFT = 8,
|
||||
|
||||
Fx_MASK = 0x1F,
|
||||
F1_SHIFT = 5,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
A_NONE = 0b00000,
|
||||
A_REG = 0b00001,
|
||||
A_IMM64 = 0b00010,
|
||||
|
||||
AM_START = 0b00100,
|
||||
|
||||
AM_IMM64 = 0b00,
|
||||
AM_RR = 0b01,
|
||||
AM_RRI = 0b10,
|
||||
AM_RRII = 0b11,
|
||||
|
||||
AM_8ACC = 0b00100,
|
||||
AM_16ACC = 0b01000,
|
||||
AM_32ACC = 0b01100,
|
||||
AM_64ACC = 0b10000,
|
||||
|
||||
AM_MLEN_MASK = 0b11100,
|
||||
AM_MFMT_MASK = 0b00011,
|
||||
};
|
||||
|
||||
#define ACC_FMT_IS_MEM(x) ((x) >= AM_START && (x) <= (AM_64ACC|AM_RRII))
|
||||
|
||||
#define ACC_IS_MEM(x) (ACC_FMT_IS_MEM((x)->type))
|
||||
|
||||
struct acc_t
|
||||
{
|
||||
uint type;
|
||||
ulong val;
|
||||
|
||||
// A_REG
|
||||
ulong reg;
|
||||
|
||||
// AM_...
|
||||
ulong addr;
|
||||
uint mlen;
|
||||
|
||||
};
|
||||
|
||||
enum { NOPRM, P_REG, P_IMM, P_MEM=4 };
|
||||
|
||||
struct instr_t
|
||||
{
|
||||
char *name;
|
||||
char *full;
|
||||
|
||||
uint prm1;
|
||||
uint prm2;
|
||||
|
||||
bool (*func)(ctx_t *, acc_t *, acc_t *, ulong *);
|
||||
};
|
||||
|
||||
void exec_instr(ctx_t *ctx,
|
||||
instr_t *in,
|
||||
acc_t *p1,
|
||||
acc_t *p2,
|
||||
bool lock,
|
||||
bool rep,
|
||||
uint cond,
|
||||
ulong pc);
|
||||
|
||||
void extract_param(ctx_t *ctx,
|
||||
acc_t *p,
|
||||
uchar fmt);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
85
vm/pc/dump.c
85
vm/pc/dump.c
@ -1,85 +0,0 @@
|
||||
// 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>
|
||||
|
||||
void dumpmem(ctx_t *ctx, ulong start, ulong size)
|
||||
{
|
||||
uint i;
|
||||
for (i = 0; i < size/sizeof(ushort); i++) {
|
||||
if (i % 4 == 0) {
|
||||
if (i > 0) {
|
||||
if (i % 8 == 0) log("\n");
|
||||
else log(" ");
|
||||
}
|
||||
|
||||
log("[0x%08lX]=0x", start + i * 2);
|
||||
}
|
||||
|
||||
log("%04hX", ctx->mp[addr2real(start) + i]);
|
||||
|
||||
}
|
||||
log("\n");
|
||||
}
|
||||
|
||||
void dumpfwstack(ctx_t *ctx)
|
||||
{
|
||||
//log("\nFirmware stack:\n");
|
||||
//dumpmem(ctx, FWSTACK - 128, 128 + 64);
|
||||
}
|
||||
|
||||
void d_log(ctx_t *ctx, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
if (ctx->disf) {
|
||||
vfprintf(ctx->disf, fmt, ap);
|
||||
fflush(ctx->disf);
|
||||
}
|
||||
else
|
||||
vlog(fmt, ap);
|
||||
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void dumpinstr(ctx_t *ctx, ulong _rip, uint rep,
|
||||
ushort c, acc_t *p1, acc_t *p2)
|
||||
{
|
||||
acc_t *p = 0;
|
||||
instr_t *i = &ctx->i[c];
|
||||
|
||||
d_log(ctx, "0x%08lX: %s%s", _rip,
|
||||
(rep ? "rep " : ""),
|
||||
i->name);
|
||||
|
||||
if (i->prm1 != NOPRM)
|
||||
p = p1;
|
||||
lp:
|
||||
if (p != 0) {
|
||||
if (p->mem) d_log(ctx, " %c[", getmempref(p->mlen));
|
||||
else d_log(ctx, " ");
|
||||
|
||||
if (p->type == A_REG)
|
||||
d_log(ctx, "%s", ctx->r[p->val].name);
|
||||
else
|
||||
d_log(ctx, "%c0x%lX", getmempref(p->ilen), p->val);
|
||||
|
||||
if (p->mem) {
|
||||
if (p->offreg)
|
||||
d_log(ctx, "+%s", ctx->r[p->offreg].name);
|
||||
if (p->off)
|
||||
d_log(ctx, "+%hd", p->off);
|
||||
d_log(ctx, "]");
|
||||
}
|
||||
|
||||
if (p == p1 && i->prm2 != NOPRM) {
|
||||
p = p2;
|
||||
d_log(ctx, ",");
|
||||
goto lp;
|
||||
}
|
||||
}
|
||||
|
||||
d_log(ctx, "\n");
|
||||
}
|
@ -28,8 +28,6 @@ void _except(ctx_t *ctx, int code, char *fmt, ...)
|
||||
dumpregs(ctx);
|
||||
log("\n");
|
||||
|
||||
dumpfwstack(ctx);
|
||||
|
||||
if (ctx->mp)
|
||||
free(ctx->mp);
|
||||
|
||||
|
62
vm/pc/main.c
62
vm/pc/main.c
@ -112,63 +112,37 @@ int main(int argc, char **argv)
|
||||
|
||||
fwsize = fread(fwprog, 1, FWPROGSIZE, fwfile);
|
||||
|
||||
//log("Loaded %lu bytes
|
||||
|
||||
if (fwsize < 2) {
|
||||
log("Program file too small or empty\n");
|
||||
exit(-3);
|
||||
}
|
||||
|
||||
if (!(argc > 2 && !strcmp(argv[2], "-d"))) {
|
||||
main_ctx.mp = malloc(MEMSIZE + 16);
|
||||
main_ctx.mz = MEMSIZE;
|
||||
main_ctx.mp = malloc(MEMSIZE + 16);
|
||||
main_ctx.mz = MEMSIZE;
|
||||
|
||||
main_ctx.get = bget;
|
||||
main_ctx.disf = NULL;
|
||||
main_ctx.get = bget;
|
||||
main_ctx.disf = NULL;
|
||||
|
||||
main_ctx.r[RIP].val = MEMOFF;
|
||||
main_ctx.r[RIP].val = MEMOFF;
|
||||
|
||||
if (main_ctx.mp == 0) {
|
||||
log("Couldn't allocate RAM\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
memcpy(&main_ctx.mp[addr2real(main_ctx.r[RIP].val)], fwprog, fwsize);
|
||||
|
||||
main_ctx.dh = 0;
|
||||
if (devinitall(&main_ctx) < 0) {
|
||||
log("Couldn't initialize devices\n");
|
||||
exit(-10);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
decode(&main_ctx);
|
||||
|
||||
if (main_ctx.step)
|
||||
getchar();
|
||||
}
|
||||
if (main_ctx.mp == 0) {
|
||||
log("Couldn't allocate RAM\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Disassembly
|
||||
else {
|
||||
main_ctx.disf = fopen("fwprog.dis", "w");
|
||||
memcpy(&main_ctx.mp[addr2real(main_ctx.r[RIP].val)], fwprog, fwsize);
|
||||
|
||||
if (main_ctx.disf == NULL) {
|
||||
log("Couldn't open fwprog.dis\n");
|
||||
exit(-2);
|
||||
}
|
||||
|
||||
main_ctx.mp = NULL;
|
||||
main_ctx.mz = 0;
|
||||
|
||||
main_ctx.get = dget;
|
||||
|
||||
while (1) {
|
||||
disasm(&main_ctx);
|
||||
}
|
||||
main_ctx.dh = 0;
|
||||
if (devinitall(&main_ctx) < 0) {
|
||||
log("Couldn't initialize devices\n");
|
||||
exit(-10);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
decode(&main_ctx);
|
||||
|
||||
return 0;
|
||||
if (main_ctx.step)
|
||||
getchar();
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user