184 lines
4.1 KiB
C++
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;
|
|
}
|