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:
145
src/cpu/8080.c
145
src/cpu/8080.c
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
@@ -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);
|
||||
|
@@ -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)
|
||||
|
Reference in New Issue
Block a user