Skip to content

Commit

Permalink
Updated instructionset to 8086+
Browse files Browse the repository at this point in the history
  • Loading branch information
andreas-jonsson committed Aug 28, 2024
1 parent 46bae39 commit 3fcce82
Show file tree
Hide file tree
Showing 9 changed files with 423 additions and 283 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
[![Chat](https://img.shields.io/matrix/virtualxt:matrix.org)](https://matrix.to/#/#virtualxt:matrix.org)
[![Support](https://github.com/BoostIO/issuehunt-materials/raw/master/v1/issuehunt-shield-v1.svg)](https://issuehunt.io/r/andreas-jonsson/virtualxt)

VirtualXT is a PC/XT (8088) emulator that runs on modern hardware and operating systems.
VirtualXT is a Turbo PC/XT emulator that runs on modern hardware and operating systems.
It is designed to be simple and lightweight yet still capable enough to run a large
library of old application and games.

Browser version is avalible [here](https://realmode.games).

## Features

* Intel 8088 processor
* Intel 8088 (80186) processor
* Hardware CPU validator
* CGA or VGA compatible graphics
* GLaBIOS or Turbo XT BIOS 3.1 with extensions
Expand Down
10 changes: 6 additions & 4 deletions lib/vxt/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ static void do_exec(CONSTSP(cpu) p) {
if (inst->modregrm)
read_modregrm(p);
inst->func(p, inst);

p->cycles += inst->cycles;
p->cycles += p->ea_cycles;

Expand All @@ -145,14 +145,16 @@ int cpu_step(CONSTSP(cpu) p) {

const CONSTSP(instruction) inst = &opcode_table[p->opcode];
VALIDATOR_END(p, inst->name, p->opcode, inst->modregrm, p->cycles, &p->regs);

p->invalid = inst->arch != ARCH_8086;

ENSURE(p->cycles > 0);
return p->cycles;
}

void cpu_reset_cycle_count(CONSTSP(cpu) p) {
p->cycles = 0;
p->int28 = false;
p->int28 = false;
p->invalid = false;
}

void cpu_reset(CONSTSP(cpu) p) {
Expand All @@ -162,7 +164,7 @@ void cpu_reset(CONSTSP(cpu) p) {
p->regs.flags = 0xF002;
p->regs.cs = 0xFFFF;
p->regs.debug = false;

p->inst_queue_count = 0;
cpu_reset_cycle_count(p);
}
Expand Down
2 changes: 1 addition & 1 deletion lib/vxt/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ struct address_mode {

struct cpu {
struct vxt_registers regs;
bool trap, halt, int28;
bool trap, halt, int28, invalid;
int cycles, ea_cycles;
vxt_word inst_start;

Expand Down
20 changes: 18 additions & 2 deletions lib/vxt/exec.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,28 @@
#define MOD_TARGET_MEM(mode) ((mode).mod < 3)
#define ADD_CYCLE_MOD_MEM(p, n) { if (MOD_TARGET_MEM((p->mode))) (p)->cycles += (n); }

enum architecture {
ARCH_INVALID,
ARCH_FPU,
ARCH_8086,
ARCH_80186,
ARCH_80286,
ARCH_80386
};

struct instruction {
vxt_byte opcode;
const char *name;
bool modregrm;
int cycles;
enum architecture arch;
void (*func)(CONSTSP(cpu), INST());
};

static vxt_dword sign_extend32(vxt_word v) {
return (v & 0x8000) ? ((vxt_dword)v) | 0xFFFF0000 : (vxt_dword)v;
}

static vxt_word sign_extend16(vxt_byte v) {
return (v & 0x80) ? ((vxt_word)v) | 0xFF00 : (vxt_word)v;
}
Expand Down Expand Up @@ -378,7 +392,7 @@ static vxt_byte read_modregrm(CONSTSP(cpu) p) {
.rm = modregrm & 7,
.disp = 0
};

switch(mode.mod) {
case 0:
if (mode.rm == 6)
Expand Down Expand Up @@ -413,7 +427,7 @@ static void call_int(CONSTSP(cpu) p, int n) {
p->inst_queue_dirty = true;

if (n == 0x28)
p->int28 = true;
p->int28 = true;
}

static void divZero(CONSTSP(cpu) p) {
Expand All @@ -426,6 +440,8 @@ static bool valid_repeat(vxt_byte opcode) {
return true;
if ((opcode >= 0xAA) && (opcode <= 0xAF))
return true;
if ((opcode >= 0x6C) && (opcode <= 0x6F)) // Only valid for 186+
return true;
return false;
}

Expand Down
122 changes: 121 additions & 1 deletion lib/vxt/exec.inl
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,90 @@ static void dec_reg(CONSTSP(cpu) p, INST(inst)) {
SET_FLAG(p->regs.flags, VXT_CARRY, c);
}

static void pusha_60(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
vxt_word sp = p->regs.sp;
push(p, p->regs.ax);
push(p, p->regs.cx);
push(p, p->regs.dx);
push(p, p->regs.bx);
push(p, sp);
push(p, p->regs.bp);
push(p, p->regs.si);
push(p, p->regs.di);
}

static void popa_61(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
p->regs.di = pop(p);
p->regs.si = pop(p);
p->regs.bp = pop(p);
pop(p);
p->regs.bx = pop(p);
p->regs.dx = pop(p);
p->regs.cx = pop(p);
p->regs.ax = pop(p);
}

static void bound_62(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
vxt_dword idx = sign_extend32(reg_read16(&p->regs, p->mode.reg));
vxt_word offset = get_ea_offset(p);

if ((idx < sign_extend32(cpu_segment_read_word(p, p->seg, offset))) || (idx > sign_extend32(cpu_segment_read_word(p, p->seg, offset + 2)))) {
p->regs.ip = p->inst_start;
call_int(p, 5);
}
}

static void push_68(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
push(p, read_opcode16(p));
}

static void imul_69_6B(CONSTSP(cpu) p, INST(inst)) {
vxt_int32 a = sign_extend32(rm_read16(p));
vxt_int32 b = (inst->opcode == 69) ? sign_extend32(sign_extend16(read_opcode8(p))) : sign_extend32(read_opcode16(p));

vxt_int32 res = a * b;
vxt_word res16 = (vxt_word)(res & 0xFFFF);

flag_szp16(&p->regs, res16);
SET_FLAG_IF(p->regs.flags, VXT_CARRY|VXT_OVERFLOW, res != ((vxt_int16)res));
rm_write16(p, res16);
}

static void push_6A(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
push(p, (vxt_word)read_opcode8(p));
}

static void insb_6C(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
cpu_write_byte(p, VXT_POINTER(p->regs.ds, p->regs.si), system_in(p->s, p->regs.dx));
update_di_si(p, 1);
}

static void insw_6D(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
cpu_segment_write_word(p, p->regs.ds, p->regs.si, WORD(system_in(p->s, p->regs.dx + 1), system_in(p->s, p->regs.dx)));
update_di_si(p, 2);
}

static void outsb_6E(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
system_out(p->s, p->regs.dx, cpu_read_byte(p, VXT_POINTER(p->regs.ds, p->regs.si)));
update_di_si(p, 1);
}

static void outsw_6F(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
vxt_word data = cpu_segment_read_word(p, p->regs.ds, p->regs.si);
system_out(p->s, p->regs.dx, (vxt_byte)(data & 0xFF));
system_out(p->s, p->regs.dx + 1, (vxt_byte)(data >> 8));
update_di_si(p, 2);
}

#define JUMP(name, cond) \
static void jump_ ##name (CONSTSP(cpu) p, INST(inst)) { \
UNUSED(inst); \
Expand Down Expand Up @@ -649,6 +733,16 @@ static void mov_reg16(CONSTSP(cpu) p, INST(inst)) {
reg_write16(&p->regs, inst->opcode - 0xB8, read_opcode16(p));
}

static void shl_C0(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
rm_write8(p, bitshift_8(p, rm_read8(p), read_opcode8(p)));
}

static void shl_C1(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
rm_write16(p, bitshift_16(p, rm_read16(p), (vxt_byte)read_opcode16(p)));
}

static void ret_C2(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
vxt_word ip = pop(p);
Expand Down Expand Up @@ -687,6 +781,32 @@ static void mov_C7(CONSTSP(cpu) p, INST(inst)) {
ADD_CYCLE_MOD_MEM(p, 10);
}

static void enter_C8(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
vxt_word size = read_opcode16(p);
vxt_byte level = read_opcode8(p);

push(p, p->regs.bp);
vxt_word sp = p->regs.sp;

if (level) {
for (vxt_byte i = 0; i < level; i++) {
p->regs.bp -= 2;
push(p, p->regs.bp);
}
push(p, p->regs.sp);
}

p->regs.bp = sp;
p->regs.sp -= size;
}

static void leave_C9(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
p->regs.sp = p->regs.bp;
p->regs.bp = pop(p);
}

static void retf_CA(CONSTSP(cpu) p, INST(inst)) {
UNUSED(inst);
vxt_word sp = read_opcode16(p);
Expand Down Expand Up @@ -718,7 +838,7 @@ static void int_CE(CONSTSP(cpu) p, INST(inst)) {
if (p->regs.flags & VXT_OVERFLOW) {
p->cycles += 69;
call_int(p, 4);
}
}
}

static void iret_CF(CONSTSP(cpu) p, INST(inst)) {
Expand Down
2 changes: 1 addition & 1 deletion lib/vxt/include/vxt/vxt.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ struct vxt_registers {

struct vxt_step {
int cycles;
bool halted, int28;
bool halted, int28, invalid;
vxt_error err;
};

Expand Down
Loading

0 comments on commit 3fcce82

Please sign in to comment.