BizHawk/waterbox/ngp/z80-fuse/z80.cpp

184 lines
4.1 KiB
C++

/* z80.c: z80 supplementary functions
Copyright (c) 1999-2003 Philip Kendall
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Author contact information:
E-mail: philip-fuse@shadowmagic.org.uk
*/
#include "z80.h"
#include "z80_macros.h"
void (*z80_writebyte)(uint16, uint8);
uint8 (*z80_readbyte)(uint16);
void (*z80_writeport)(uint16, uint8);
uint8 (*z80_readport)(uint16);
/* Whether a half carry occurred or not can be determined by looking at
the 3rd bit of the two arguments and the result; these are hashed
into this table in the form r12, where r is the 3rd bit of the
result, 1 is the 3rd bit of the 1st argument and 2 is the
third bit of the 2nd argument; the tables differ for add and subtract
operations */
const uint8 halfcarry_add_table[] =
{0, FLAG_H, FLAG_H, FLAG_H, 0, 0, 0, FLAG_H};
const uint8 halfcarry_sub_table[] =
{0, 0, FLAG_H, 0, FLAG_H, 0, FLAG_H, FLAG_H};
/* Similarly, overflow can be determined by looking at the 7th bits; again
the hash into this table is r12 */
const uint8 overflow_add_table[] = {0, 0, 0, FLAG_V, FLAG_V, 0, 0, 0};
const uint8 overflow_sub_table[] = {0, FLAG_V, 0, 0, 0, 0, FLAG_V, 0};
/* Some more tables; initialised in z80_init_tables() */
uint8 sz53_table[0x100]; /* The S, Z, 5 and 3 bits of the index */
uint8 parity_table[0x100]; /* The parity of the lookup value */
uint8 sz53p_table[0x100]; /* OR the above two tables together */
/* This is what everything acts on! */
processor z80;
uint64 z80_tstates;
uint64 last_z80_tstates;
static void z80_init_tables(void);
/* Set up the z80 emulation */
void z80_init(void)
{
z80_init_tables();
}
/* Initalise the tables used to set flags */
static void z80_init_tables(void)
{
int i, j, k;
uint8 parity;
for (i = 0; i < 0x100; i++)
{
sz53_table[i] = i & (FLAG_3 | FLAG_5 | FLAG_S);
j = i;
parity = 0;
for (k = 0; k < 8; k++)
{
parity ^= j & 1;
j >>= 1;
}
parity_table[i] = (parity ? 0 : FLAG_P);
sz53p_table[i] = sz53_table[i] | parity_table[i];
}
sz53_table[0] |= FLAG_Z;
sz53p_table[0] |= FLAG_Z;
}
/* Reset the z80 */
void z80_reset(void)
{
AF = BC = DE = HL = 0;
AF_ = BC_ = DE_ = HL_ = 0;
IX = IY = 0;
I = R = R7 = 0;
SP = PC = 0;
IFF1 = IFF2 = IM = 0;
z80.halted = 0;
z80.interrupts_enabled_at = 0;
z80_tstates = last_z80_tstates = 0;
}
/* Process a z80 maskable interrupt */
int z80_interrupt(void)
{
if (IFF1)
{
/* If interrupts have just been enabled, don't accept the interrupt now,
but check after the next instruction has been executed */
if (z80_tstates == z80.interrupts_enabled_at)
{
return 0;
}
if (z80.halted)
{
PC++;
z80.halted = 0;
}
IFF1 = IFF2 = 0;
Z80_WB_MACRO(--SP, PCH);
Z80_WB_MACRO(--SP, PCL);
R++;
switch (IM)
{
case 0:
PC = 0x0038;
z80_tstates += 7;
break;
case 1:
PC = 0x0038;
z80_tstates += 7;
break;
case 2:
{
uint16 inttemp = (0x100 * I) + 0xff;
PCL = Z80_RB_MACRO(inttemp++);
PCH = Z80_RB_MACRO(inttemp);
z80_tstates += 7;
break;
}
//default:
// ui_error( UI_ERROR_ERROR, "Unknown interrupt mode %d", IM );
// fuse_abort();
}
return 1; /* Accepted an interrupt */
}
else
{
return 0; /* Did not accept an interrupt */
}
}
/* Process a z80 non-maskable interrupt */
void z80_nmi(void)
{
if (z80.halted)
{
PC++;
z80.halted = 0;
}
IFF1 = 0;
Z80_WB_MACRO(--SP, PCH);
Z80_WB_MACRO(--SP, PCL);
/* FIXME: how is R affected? */
/* FIXME: how does contention apply here? */
z80_tstates += 11;
PC = 0x0066;
}