More i8080 + NEC changes (#18)

* More i8080 changes

* Fix compilation

* More foundational i8080 work

* Switch to __builtin_parity for parity flag setting

Fix some incorrectly implemented instructions
This commit is contained in:
Cacodemon345
2022-09-10 14:50:50 +06:00
committed by GitHub
parent 176278bca0
commit fc2fac4c73
4 changed files with 173 additions and 31 deletions

View File

@@ -15,6 +15,151 @@
#include <stdint.h>
#include <stdlib.h>
#include "cpu.h"
#include <86box/timer.h>
#include <86box/i8080.h>
#include <86box/mem.h>
static int prefetching = 1, completed = 1;
static int in_rep = 0, repeating = 0, rep_c_flag = 0;
static int oldc, clear_lock = 0;
static int refresh = 0, cycdiff;
static void
clock_start(void)
{
cycdiff = cycles;
}
static void
clock_end(void)
{
int diff = cycdiff - cycles;
/* On 808x systems, clock speed is usually crystal frequency divided by an integer. */
tsc += (uint64_t)diff * ((uint64_t)xt_cpu_multi >> 32ULL); /* Shift xt_cpu_multi by 32 bits to the right and then multiply. */
if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc))
timer_process();
}
static void
wait(int c, int bus)
{
cycles -= c;
if (bus < 2) {
clock_end();
clock_start();
}
}
static uint8_t
readmemb(uint32_t a)
{
uint8_t ret;
wait(4, 1);
ret = read_mem_b(a);
return ret;
}
static uint8_t
ins_fetch(i8080* cpu)
{
uint8_t ret = readmemb(cpu->pmembase + cpu->pc);
cpu->pc++;
return ret;
}
void
transfer_from_808x(i8080* cpu)
{
cpu->hl = BX;
cpu->bc = CX;
cpu->de = DX;
cpu->a = AL;
cpu->flags = cpu_state.flags & 0xFF;
cpu->sp = BP;
cpu->pc = cpu_state.pc;
cpu->oldpc = cpu_state.oldpc;
cpu->pmembase = cs;
cpu->dmembase = ds;
}
void
transfer_to_808x(i8080* cpu)
{
BX = cpu->hl;
CX = cpu->bc;
DX = cpu->de;
AL = cpu->a;
cpu_state.flags &= 0xFF00;
cpu_state.flags |= cpu->flags & 0xFF;
BP = cpu->sp;
cpu_state.pc = cpu->pc;
}
uint8_t
getreg_i8080(i8080 *cpu, uint8_t reg)
{
uint8_t ret = 0xFF;
switch(reg)
{
case 0x0: ret = cpu->b; break;
case 0x1: ret = cpu->c; break;
case 0x2: ret = cpu->d; break;
case 0x3: ret = cpu->e; break;
case 0x4: ret = cpu->h; break;
case 0x5: ret = cpu->l; break;
case 0x6: ret = readmemb(cpu->dmembase + cpu->sp); break;
case 0x7: ret = cpu->a; break;
}
return ret;
}
void
interpret_exec8080(i8080* cpu, uint8_t opcode, uint8_t (*fetch_instruction)(i8080*))
{
switch (opcode) {
case 0x00:
{
break;
}
}
}
/* Actually implement i8080 emulation. */
void
exec8080(i8080* cpu, int cycs)
{
uint8_t temp = 0, temp2;
uint8_t old_af;
uint8_t handled = 0;
uint16_t addr, tempw;
uint16_t new_ip;
int bits;
cycles += cycs;
while (cycles > 0) {
clock_start();
if (!repeating) {
cpu->oldpc = cpu->pc;
opcode = ins_fetch(cpu);
oldc = cpu->flags & C_FLAG_I8080;
wait(1, 0);
}
completed = 1;
if (completed) {
repeating = 0;
in_rep = 0;
rep_c_flag = 0;
clock_end();
//check_interrupts();
}
}
}

View File

@@ -608,6 +608,7 @@ reset_808x(int hard)
load_cs(0xFFFF);
cpu_state.pc = 0;
cpu_state.flags |= 0x8000;
rammask = 0xfffff;
prefetching = 1;
@@ -971,7 +972,7 @@ interrupt(uint16_t addr)
pfq_clear();
ovr_seg = NULL;
access(39, 16);
tempf = cpu_state.flags & 0x0fd7;
tempf = cpu_state.flags & (is_nec && cpu_state.inside_emulation_mode ? 0x8fd7 : 0x0fd7);
push(&tempf);
cpu_state.flags &= ~(I_FLAG | T_FLAG);
access(40, 16);
@@ -984,6 +985,11 @@ interrupt(uint16_t addr)
push(&old_ip);
}
void
interrupt_808x(uint16_t addr)
{
interrupt(addr);
}
static void
custom_nmi(void)
@@ -1315,25 +1321,7 @@ set_sf(int bits)
static void
set_pf(void)
{
static uint8_t table[0x100] = {
4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4,
0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
0, 4, 4, 0, 4, 0, 0, 4, 4, 0, 0, 4, 0, 4, 4, 0,
4, 0, 0, 4, 0, 4, 4, 0, 0, 4, 4, 0, 4, 0, 0, 4};
cpu_state.flags = (cpu_state.flags & ~4) | table[cpu_data & 0xff];
cpu_state.flags = (cpu_state.flags & ~4) | (!__builtin_parity(cpu_data & 0xFF) << 2);
}
@@ -2450,7 +2438,7 @@ execx86(int cycs)
}
case 0x78: /*JS*/
case 0x69: /*JNS alias*/
if (is186) { /* IMUL reg16,reg16/mem16,imm16 */
if (is186 && opcode == 0x69) { /* IMUL reg16,reg16/mem16,imm16 */
uint16_t immediate = 0;
bits = 16;
do_mod_rm();
@@ -2466,17 +2454,13 @@ execx86(int cycs)
break;
case 0x6A: /*JP alias*/
if (is186) { /* PUSH imm8 */
uint8_t bytetopush = pfq_fetchb();
{
SP -= 1;
cpu_state.eaaddr = (SP & 0xffff);
writememb(ss, cpu_state.eaaddr, bytetopush);
}
uint16_t wordtopush = sign_extend(pfq_fetchb());
push(&wordtopush);
break;
}
case 0x7A: /*JP*/
case 0x6B: /*JNP alias*/
if (is186) { /* IMUL reg16,reg16/mem16,imm8 */
if (is186 && opcode == 0x6B) { /* IMUL reg16,reg16/mem16,imm8 */
uint16_t immediate = 0;
bits = 16;
do_mod_rm();
@@ -2687,7 +2671,7 @@ execx86(int cycs)
break;
case 0x9C: /*PUSHF*/
access(33, 16);
tempw = (cpu_state.flags & 0x0fd7) | 0xf000;
tempw = cpu_state.flags & (is_nec && cpu_state.inside_emulation_mode ? 0x8fd7 : 0x0fd7);
push(&tempw);
break;
case 0x9D: /*POPF*/
@@ -2931,7 +2915,7 @@ execx86(int cycs)
access(62, 8);
set_ip(new_ip);
access(45, 8);
cpu_state.flags = pop() | 2;
cpu_state.flags = pop() | 2 | (!is_nec ? 0 : (!cpu_state.inside_emulation_mode ? 0x8000 : 0));
wait(5, 0);
noint = 1;
nmi_enable = 1;

View File

@@ -188,6 +188,7 @@ typedef struct {
#define D_FLAG 0x0400
#define V_FLAG 0x0800
#define NT_FLAG 0x4000
#define MD_FLAG 0x8000
#define RF_FLAG 0x0001 /* in EFLAGS */
#define VM_FLAG 0x0002 /* in EFLAGS */
@@ -399,6 +400,8 @@ typedef struct {
uint16_t flags, eflags;
uint32_t _smbase;
uint8_t inside_emulation_mode;
} cpu_state_t;
@@ -743,6 +746,7 @@ extern void (*cpu_exec)(int cycs);
extern uint8_t do_translate, do_translate2;
extern void reset_808x(int hard);
extern void interrupt_808x(uint16_t addr);
extern void cpu_register_fast_off_handler(void *timer);
extern void cpu_fast_off_advance(void);

View File

@@ -37,4 +37,13 @@ typedef struct i8080
struct { uint8_t h, l; };
};
uint16_t pc, sp;
uint16_t oldpc, ei;
uint32_t pmembase, dmembase; /* Base from where i8080 starts. */
uint8_t emulated; /* 0 = not emulated, use separate registers, 1 = emulated, use x86 registers. */
} i8080;
#define C_FLAG_I8080 (1 << 0)
#define P_FLAG_I8080 (1 << 2)
#define AC_FLAG_I8080 (1 << 4)
#define Z_FLAG_I8080 (1 << 6)
#define S_FLAG_I8080 (1 << 7)