mirror of
https://github.com/hsoft/collapseos.git
synced 2024-11-27 12:08:07 +11:00
emul: copy libz80 directly into tree, pre-generated
libz80 doesn't move much anymore, there not much advantage to the git module indirection.
This commit is contained in:
parent
c072096909
commit
329219fa89
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
|||||||
[submodule "emul/libz80"]
|
|
||||||
path = emul/libz80
|
|
||||||
url = https://github.com/ggambetta/libz80.git
|
|
@ -1,5 +1,5 @@
|
|||||||
TARGETS = forth
|
TARGETS = forth
|
||||||
OBJS = emul.o libz80/libz80.o
|
OBJS = emul.o z80.o
|
||||||
CDIR = ../cvm
|
CDIR = ../cvm
|
||||||
STAGE = $(CDIR)/stage
|
STAGE = $(CDIR)/stage
|
||||||
BLKFS = $(CDIR)/blkfs
|
BLKFS = $(CDIR)/blkfs
|
||||||
@ -10,10 +10,6 @@ all: $(TARGETS)
|
|||||||
forth: forth.c $(OBJS) $(BLKFS)
|
forth: forth.c $(OBJS) $(BLKFS)
|
||||||
$(CC) forth.c $(OBJS) -lncurses -o $@
|
$(CC) forth.c $(OBJS) -lncurses -o $@
|
||||||
|
|
||||||
libz80/libz80.o: libz80/z80.c
|
|
||||||
$(MAKE) -C libz80/codegen opcodes
|
|
||||||
$(CC) -Wall -std=c89 -g -c -o libz80/libz80.o libz80/z80.c
|
|
||||||
|
|
||||||
emul.o: emul.c forth.bin $(BLKFS)
|
emul.o: emul.c forth.bin $(BLKFS)
|
||||||
$(CC) -DFBIN_PATH=\"`pwd`/forth.bin\" -DBLKFS_PATH=\"`pwd`/$(BLKFS)\" -c -o emul.o emul.c
|
$(CC) -DFBIN_PATH=\"`pwd`/forth.bin\" -DBLKFS_PATH=\"`pwd`/$(BLKFS)\" -c -o emul.o emul.c
|
||||||
|
|
||||||
@ -27,4 +23,4 @@ $(STAGE):
|
|||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
rm -f $(TARGETS) emul.o *.bin libz80/libz80.o
|
rm -f $(TARGETS) emul.o *.bin z80.o
|
||||||
|
@ -10,10 +10,7 @@ it's `libncurses5-dev`.
|
|||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
First, make sure that the `libz80` git submodule is checked out. If not, run
|
Run `make` and it builds the `forth` interpreter.
|
||||||
`git submodule init && git submodule update`.
|
|
||||||
|
|
||||||
After that, you can run `make` and it builds the `forth` interpreter.
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "libz80/z80.h"
|
#include "z80.h"
|
||||||
|
|
||||||
typedef byte (*IORD) ();
|
typedef byte (*IORD) ();
|
||||||
typedef void (*IOWR) (byte data);
|
typedef void (*IOWR) (byte data);
|
||||||
|
@ -1 +0,0 @@
|
|||||||
Subproject commit 55520abc1c69978aad3ff65493dbea00ff940d8b
|
|
1137
emul/opcodes_decl.h
Normal file
1137
emul/opcodes_decl.h
Normal file
File diff suppressed because it is too large
Load Diff
8804
emul/opcodes_impl.c
Normal file
8804
emul/opcodes_impl.c
Normal file
File diff suppressed because it is too large
Load Diff
1830
emul/opcodes_table.h
Normal file
1830
emul/opcodes_table.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
EXTOBJS = ../emul.o ../libz80/libz80.o
|
EXTOBJS = ../emul.o ../z80.o
|
||||||
OBJS = sio.o acia.o sdc.o classic.o
|
OBJS = sio.o acia.o sdc.o classic.o
|
||||||
TARGET = classic
|
TARGET = classic
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
EXTOBJS = ../emul.o ../libz80/libz80.o
|
EXTOBJS = ../emul.o ../z80.o
|
||||||
OBJS = sms.o vdp.o port.o pad.o kbd.o
|
OBJS = sms.o vdp.o port.o pad.o kbd.o
|
||||||
TARGET = sms
|
TARGET = sms
|
||||||
CFLAGS += `pkg-config --cflags xcb`
|
CFLAGS += `pkg-config --cflags xcb`
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
EXTOBJS = ../emul.o ../libz80/libz80.o
|
EXTOBJS = ../emul.o ../z80.o
|
||||||
OBJS = ti84.o t6a04.o kbd.o
|
OBJS = ti84.o t6a04.o kbd.o
|
||||||
TARGET = ti84
|
TARGET = ti84
|
||||||
CFLAGS += `pkg-config --cflags xcb`
|
CFLAGS += `pkg-config --cflags xcb`
|
||||||
|
885
emul/z80.c
Normal file
885
emul/z80.c
Normal file
@ -0,0 +1,885 @@
|
|||||||
|
// This unit has been copied from libz80 into Collapse OS and was slighly changed
|
||||||
|
/* =========================================================
|
||||||
|
* libz80 - Z80 emulation library
|
||||||
|
* =========================================================
|
||||||
|
*
|
||||||
|
* (C) Gabriel Gambetta (gabriel.gambetta@gmail.com) 2000 - 2012
|
||||||
|
*
|
||||||
|
* Version 2.1.0
|
||||||
|
*
|
||||||
|
* ---------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "z80.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BR (ctx->R1.br)
|
||||||
|
#define WR (ctx->R1.wr)
|
||||||
|
|
||||||
|
#define SETFLAG(F) setFlag(ctx, F)
|
||||||
|
#define RESFLAG(F) resFlag(ctx, F)
|
||||||
|
#define GETFLAG(F) getFlag(ctx, F)
|
||||||
|
|
||||||
|
#define VALFLAG(F,V) valFlag(ctx, F, V)
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------
|
||||||
|
* Flag tricks
|
||||||
|
* ---------------------------------------------------------
|
||||||
|
*
|
||||||
|
* To avoid repeating entries in the spec files, many operations that look similar are treated as special cases
|
||||||
|
* of a more general operation.
|
||||||
|
*
|
||||||
|
* For example, ADD and ADC are similar in syntax and operation - the difference is that ADC takes the carry flag
|
||||||
|
* into account.
|
||||||
|
*
|
||||||
|
* So we define a general operation doArithmetic(...) which accepts a boolean parameter specifying whether to do
|
||||||
|
* a Carry-operation or not. Then, when we parse, we can say
|
||||||
|
*
|
||||||
|
* (ADD|ADC) ....
|
||||||
|
* doArithmetic(FLAG_FOR_%1)
|
||||||
|
*
|
||||||
|
* and everything works fine.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Flags for doIncDec() */
|
||||||
|
static const int ID_INC = 0;
|
||||||
|
static const int ID_DEC = 1;
|
||||||
|
|
||||||
|
/* Flags for enable / disable interrupts */
|
||||||
|
static const int IE_DI = 0;
|
||||||
|
static const int IE_EI = 1;
|
||||||
|
|
||||||
|
/* Flags for doSetRes() */
|
||||||
|
static const int SR_RES = 0;
|
||||||
|
static const int SR_SET = 1;
|
||||||
|
|
||||||
|
/* Flags for logical / arithmetic operations */
|
||||||
|
static const int IA_L = 0;
|
||||||
|
static const int IA_A = 1;
|
||||||
|
|
||||||
|
/* Flags for doArithmetic() - F1 = withCarry, F2 = isSub */
|
||||||
|
static const int F1_ADC = 1;
|
||||||
|
static const int F1_SBC = 1;
|
||||||
|
static const int F1_ADD = 0;
|
||||||
|
static const int F1_SUB = 0;
|
||||||
|
|
||||||
|
static const int F2_ADC = 0;
|
||||||
|
static const int F2_SBC = 1;
|
||||||
|
static const int F2_ADD = 0;
|
||||||
|
static const int F2_SUB = 1;
|
||||||
|
|
||||||
|
/* Increment or decrement R, preserving bit 7 */
|
||||||
|
#define INCR (ctx->R = (ctx->R & 0x80) | ((ctx->R + 1) & 0x7f))
|
||||||
|
#define DECR (ctx->R = (ctx->R & 0x80) | ((ctx->R - 1) & 0x7f))
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------
|
||||||
|
* The opcode implementations
|
||||||
|
* ---------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "opcodes_decl.h"
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
OP_NONE,
|
||||||
|
OP_BYTE,
|
||||||
|
OP_OFFSET,
|
||||||
|
OP_WORD
|
||||||
|
} Z80OperandType;
|
||||||
|
|
||||||
|
typedef void (*Z80OpcodeFunc) (Z80Context* ctx);
|
||||||
|
|
||||||
|
struct Z80OpcodeEntry
|
||||||
|
{
|
||||||
|
Z80OpcodeFunc func;
|
||||||
|
|
||||||
|
int operand_type;
|
||||||
|
char* format;
|
||||||
|
|
||||||
|
struct Z80OpcodeTable* table;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Z80OpcodeTable
|
||||||
|
{
|
||||||
|
int opcode_offset;
|
||||||
|
struct Z80OpcodeEntry entries[256];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#include "opcodes_table.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------
|
||||||
|
* Data operations
|
||||||
|
* ---------------------------------------------------------
|
||||||
|
*/
|
||||||
|
static void write8 (Z80Context* ctx, ushort addr, byte val)
|
||||||
|
{
|
||||||
|
ctx->tstates += 3;
|
||||||
|
ctx->memWrite(ctx->memParam, addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void write16 (Z80Context* ctx, ushort addr, ushort val)
|
||||||
|
{
|
||||||
|
write8(ctx, addr, val);
|
||||||
|
write8(ctx, addr + 1, val >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static byte read8 (Z80Context* ctx, ushort addr)
|
||||||
|
{
|
||||||
|
ctx->tstates += 3;
|
||||||
|
return ctx->memRead(ctx->memParam, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ushort read16 (Z80Context* ctx, ushort addr)
|
||||||
|
{
|
||||||
|
byte lsb = read8(ctx, addr);
|
||||||
|
byte msb = read8(ctx, addr + 1);
|
||||||
|
return msb << 8 | lsb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static byte ioRead (Z80Context* ctx, ushort addr)
|
||||||
|
{
|
||||||
|
ctx->tstates += 4;
|
||||||
|
return ctx->ioRead(ctx->ioParam, addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ioWrite (Z80Context* ctx, ushort addr, byte val)
|
||||||
|
{
|
||||||
|
ctx->tstates += 4;
|
||||||
|
ctx->ioWrite(ctx->ioParam, addr, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------
|
||||||
|
* Flag operations
|
||||||
|
* ---------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Sets a flag */
|
||||||
|
static void setFlag(Z80Context* ctx, Z80Flags flag)
|
||||||
|
{
|
||||||
|
BR.F |= flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Resets a flag */
|
||||||
|
static void resFlag(Z80Context* ctx, Z80Flags flag)
|
||||||
|
{
|
||||||
|
BR.F &= ~flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Puts a value in a flag */
|
||||||
|
static void valFlag(Z80Context* ctx, Z80Flags flag, int val)
|
||||||
|
{
|
||||||
|
if (val)
|
||||||
|
SETFLAG(flag);
|
||||||
|
else
|
||||||
|
RESFLAG(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a flag */
|
||||||
|
static int getFlag(Z80Context* ctx, Z80Flags flag)
|
||||||
|
{
|
||||||
|
return (BR.F & flag) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------
|
||||||
|
* Flag adjustments
|
||||||
|
* ---------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int parityBit[256] = {
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||||
|
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1 };
|
||||||
|
|
||||||
|
|
||||||
|
static void adjustFlags (Z80Context* ctx, byte val)
|
||||||
|
{
|
||||||
|
VALFLAG(F_5, (val & F_5) != 0);
|
||||||
|
VALFLAG(F_3, (val & F_3) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void adjustFlagSZP (Z80Context* ctx, byte val)
|
||||||
|
{
|
||||||
|
VALFLAG(F_S, (val & 0x80) != 0);
|
||||||
|
VALFLAG(F_Z, (val == 0));
|
||||||
|
VALFLAG(F_PV, parityBit[val]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Adjust flags after AND, OR, XOR */
|
||||||
|
static void adjustLogicFlag (Z80Context* ctx, int flagH)
|
||||||
|
{
|
||||||
|
VALFLAG(F_S, (BR.A & 0x80) != 0);
|
||||||
|
VALFLAG(F_Z, (BR.A == 0));
|
||||||
|
VALFLAG(F_H, flagH);
|
||||||
|
VALFLAG(F_N, 0);
|
||||||
|
VALFLAG(F_C, 0);
|
||||||
|
VALFLAG(F_PV, parityBit[BR.A]);
|
||||||
|
|
||||||
|
adjustFlags(ctx, BR.A);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------
|
||||||
|
* Condition checks
|
||||||
|
* ---------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
C_,
|
||||||
|
C_Z,
|
||||||
|
C_NZ,
|
||||||
|
C_C,
|
||||||
|
C_NC,
|
||||||
|
C_M,
|
||||||
|
C_P,
|
||||||
|
C_PE,
|
||||||
|
C_PO
|
||||||
|
} Z80Condition;
|
||||||
|
|
||||||
|
static int condition(Z80Context* ctx, Z80Condition cond)
|
||||||
|
{
|
||||||
|
if (cond == C_)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (cond == C_Z)
|
||||||
|
return GETFLAG(F_Z);
|
||||||
|
|
||||||
|
if (cond == C_NZ)
|
||||||
|
return !GETFLAG(F_Z);
|
||||||
|
|
||||||
|
if (cond == C_C)
|
||||||
|
return GETFLAG(F_C);
|
||||||
|
|
||||||
|
if (cond == C_NC)
|
||||||
|
return !GETFLAG(F_C);
|
||||||
|
|
||||||
|
if (cond == C_M)
|
||||||
|
return GETFLAG(F_S);
|
||||||
|
|
||||||
|
if (cond == C_P)
|
||||||
|
return !GETFLAG(F_S);
|
||||||
|
|
||||||
|
if (cond == C_PE)
|
||||||
|
return GETFLAG(F_PV);
|
||||||
|
|
||||||
|
/* if (cond == C_PO)*/
|
||||||
|
return !GETFLAG(F_PV);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------
|
||||||
|
* Generic operations
|
||||||
|
* ---------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static int doComplement(byte v)
|
||||||
|
{
|
||||||
|
if ((v & 0x80) == 0)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
v = ~v;
|
||||||
|
v &= 0x7F;
|
||||||
|
v++;
|
||||||
|
|
||||||
|
return -v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Do an arithmetic operation (ADD, SUB, ADC, SBC y CP) */
|
||||||
|
static byte doArithmetic (Z80Context* ctx, byte value, int withCarry, int isSub)
|
||||||
|
{
|
||||||
|
ushort res; /* To detect carry */
|
||||||
|
|
||||||
|
if (isSub)
|
||||||
|
{
|
||||||
|
SETFLAG(F_N);
|
||||||
|
VALFLAG(F_H, (((BR.A & 0x0F) - (value & 0x0F)) & 0x10) != 0);
|
||||||
|
res = BR.A - value;
|
||||||
|
if (withCarry && GETFLAG(F_C))
|
||||||
|
res--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RESFLAG(F_N);
|
||||||
|
VALFLAG(F_H, (((BR.A & 0x0F) + (value & 0x0F)) & 0x10) != 0);
|
||||||
|
res = BR.A + value;
|
||||||
|
if (withCarry && GETFLAG(F_C))
|
||||||
|
res++;
|
||||||
|
}
|
||||||
|
VALFLAG(F_S, ((res & 0x80) != 0));
|
||||||
|
VALFLAG(F_C, ((res & 0x100) != 0));
|
||||||
|
VALFLAG(F_Z, ((res & 0xff) == 0));
|
||||||
|
int minuend_sign = BR.A & 0x80;
|
||||||
|
int subtrahend_sign = value & 0x80;
|
||||||
|
int result_sign = res & 0x80;
|
||||||
|
int overflow;
|
||||||
|
if(isSub)
|
||||||
|
overflow = minuend_sign != subtrahend_sign && result_sign != minuend_sign;
|
||||||
|
else
|
||||||
|
overflow = minuend_sign == subtrahend_sign && result_sign != minuend_sign;
|
||||||
|
VALFLAG(F_PV, overflow);
|
||||||
|
adjustFlags(ctx, res);
|
||||||
|
|
||||||
|
return (byte)(res & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Do a 16-bit addition, setting the appropriate flags. */
|
||||||
|
static ushort doAddWord(Z80Context* ctx, ushort a1, ushort a2, int withCarry, int isSub)
|
||||||
|
{
|
||||||
|
if(withCarry && GETFLAG(F_C))
|
||||||
|
a2++;
|
||||||
|
int sum = a1;
|
||||||
|
if(isSub)
|
||||||
|
{
|
||||||
|
sum -= a2;
|
||||||
|
VALFLAG(F_H, ((a1 & 0x0fff) - (a2 & 0x0fff)) & 0x1000);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sum += a2;
|
||||||
|
VALFLAG(F_H, ((a1 & 0x0fff) + (a2 & 0x0fff)) & 0x1000);
|
||||||
|
}
|
||||||
|
VALFLAG(F_C, sum & 0x10000);
|
||||||
|
if(withCarry || isSub)
|
||||||
|
{
|
||||||
|
int minuend_sign = a1 & 0x8000;
|
||||||
|
int subtrahend_sign = a2 & 0x8000;
|
||||||
|
int result_sign = sum & 0x8000;
|
||||||
|
int overflow;
|
||||||
|
if(isSub)
|
||||||
|
overflow = minuend_sign != subtrahend_sign && result_sign != minuend_sign;
|
||||||
|
else
|
||||||
|
overflow = minuend_sign == subtrahend_sign && result_sign != minuend_sign;
|
||||||
|
VALFLAG(F_PV, overflow);
|
||||||
|
VALFLAG(F_S, (sum & 0x8000) != 0);
|
||||||
|
VALFLAG(F_Z, (sum & 0xFFFF) == 0);
|
||||||
|
}
|
||||||
|
VALFLAG(F_N, isSub);
|
||||||
|
adjustFlags(ctx, sum >> 8);
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void doAND (Z80Context* ctx, byte value)
|
||||||
|
{
|
||||||
|
BR.A &= value;
|
||||||
|
adjustLogicFlag(ctx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void doOR (Z80Context* ctx, byte value)
|
||||||
|
{
|
||||||
|
BR.A |= value;
|
||||||
|
adjustLogicFlag(ctx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void doXOR (Z80Context* ctx, byte value)
|
||||||
|
{
|
||||||
|
BR.A ^= value;
|
||||||
|
adjustLogicFlag(ctx, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void doBIT (Z80Context* ctx, int b, byte val)
|
||||||
|
{
|
||||||
|
if (val & (1 << b))
|
||||||
|
RESFLAG(F_Z | F_PV);
|
||||||
|
else
|
||||||
|
SETFLAG(F_Z | F_PV);
|
||||||
|
|
||||||
|
SETFLAG(F_H);
|
||||||
|
RESFLAG(F_N);
|
||||||
|
|
||||||
|
RESFLAG(F_S);
|
||||||
|
if ((b == 7) && !GETFLAG(F_Z))
|
||||||
|
SETFLAG(F_S);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void doBIT_r(Z80Context* ctx, int b, byte val)
|
||||||
|
{
|
||||||
|
doBIT(ctx, b, val);
|
||||||
|
VALFLAG(F_5, val & F_5);
|
||||||
|
VALFLAG(F_3, val & F_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void doBIT_indexed(Z80Context* ctx, int b, ushort address)
|
||||||
|
{
|
||||||
|
byte val = read8(ctx, address);
|
||||||
|
doBIT(ctx, b, val);
|
||||||
|
VALFLAG(F_5, (address >> 8) & F_5);
|
||||||
|
VALFLAG(F_3, (address >> 8) & F_3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
byte doSetRes (Z80Context* ctx, int bit, int pos, byte val)
|
||||||
|
{
|
||||||
|
if (bit)
|
||||||
|
val |= (1 << pos);
|
||||||
|
else
|
||||||
|
val &= ~(1 << pos);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static byte doIncDec (Z80Context* ctx, byte val, int isDec)
|
||||||
|
{
|
||||||
|
if (isDec)
|
||||||
|
{
|
||||||
|
VALFLAG(F_PV, (val & 0x80) && !((val - 1) & 0x80));
|
||||||
|
val--;
|
||||||
|
VALFLAG(F_H, (val & 0x0F) == 0x0F);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VALFLAG(F_PV, !(val & 0x80) && ((val + 1) & 0x80));
|
||||||
|
val++;
|
||||||
|
VALFLAG(F_H, !(val & 0x0F));
|
||||||
|
}
|
||||||
|
|
||||||
|
VALFLAG(F_S, ((val & 0x80) != 0));
|
||||||
|
VALFLAG(F_Z, (val == 0));
|
||||||
|
VALFLAG(F_N, isDec);
|
||||||
|
|
||||||
|
adjustFlags(ctx, val);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static byte doRLC (Z80Context* ctx, int adjFlags, byte val)
|
||||||
|
{
|
||||||
|
VALFLAG(F_C, (val & 0x80) != 0);
|
||||||
|
val <<= 1;
|
||||||
|
val |= (byte)GETFLAG(F_C);
|
||||||
|
|
||||||
|
adjustFlags(ctx, val);
|
||||||
|
RESFLAG(F_H | F_N);
|
||||||
|
|
||||||
|
if (adjFlags)
|
||||||
|
adjustFlagSZP(ctx, val);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static byte doRL (Z80Context* ctx, int adjFlags, byte val)
|
||||||
|
{
|
||||||
|
int CY = GETFLAG(F_C);
|
||||||
|
VALFLAG(F_C, (val & 0x80) != 0);
|
||||||
|
val <<= 1;
|
||||||
|
val |= (byte)CY;
|
||||||
|
|
||||||
|
adjustFlags(ctx, val);
|
||||||
|
RESFLAG(F_H | F_N);
|
||||||
|
|
||||||
|
if (adjFlags)
|
||||||
|
adjustFlagSZP(ctx, val);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static byte doRRC (Z80Context* ctx, int adjFlags, byte val)
|
||||||
|
{
|
||||||
|
VALFLAG(F_C, (val & 0x01) != 0);
|
||||||
|
val >>= 1;
|
||||||
|
val |= ((byte)GETFLAG(F_C) << 7);
|
||||||
|
|
||||||
|
adjustFlags(ctx, val);
|
||||||
|
RESFLAG(F_H | F_N);
|
||||||
|
|
||||||
|
if (adjFlags)
|
||||||
|
adjustFlagSZP(ctx, val);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static byte doRR (Z80Context* ctx, int adjFlags, byte val)
|
||||||
|
{
|
||||||
|
int CY = GETFLAG(F_C);
|
||||||
|
VALFLAG(F_C, (val & 0x01));
|
||||||
|
val >>= 1;
|
||||||
|
val |= (CY << 7);
|
||||||
|
|
||||||
|
adjustFlags(ctx, val);
|
||||||
|
RESFLAG(F_H | F_N);
|
||||||
|
|
||||||
|
if (adjFlags)
|
||||||
|
adjustFlagSZP(ctx, val);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static byte doSL (Z80Context* ctx, byte val, int isArith)
|
||||||
|
{
|
||||||
|
VALFLAG(F_C, (val & 0x80) != 0);
|
||||||
|
val <<= 1;
|
||||||
|
|
||||||
|
if (!isArith)
|
||||||
|
val |= 1;
|
||||||
|
|
||||||
|
adjustFlags(ctx, val);
|
||||||
|
RESFLAG(F_H | F_N);
|
||||||
|
adjustFlagSZP(ctx, val);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static byte doSR (Z80Context* ctx, byte val, int isArith)
|
||||||
|
{
|
||||||
|
int b = val & 0x80;
|
||||||
|
|
||||||
|
VALFLAG(F_C, (val & 0x01) != 0);
|
||||||
|
val >>= 1;
|
||||||
|
|
||||||
|
if (isArith)
|
||||||
|
val |= b;
|
||||||
|
|
||||||
|
adjustFlags(ctx, val);
|
||||||
|
RESFLAG(F_H | F_N);
|
||||||
|
adjustFlagSZP(ctx, val);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void doPush (Z80Context* ctx, ushort val)
|
||||||
|
{
|
||||||
|
WR.SP--;
|
||||||
|
WR.SP--;
|
||||||
|
write16(ctx, WR.SP, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ushort doPop (Z80Context* ctx)
|
||||||
|
{
|
||||||
|
ushort val;
|
||||||
|
val = read16(ctx, WR.SP);
|
||||||
|
WR.SP++;
|
||||||
|
WR.SP++;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static byte doCP_HL(Z80Context * ctx)
|
||||||
|
{
|
||||||
|
byte val = read8(ctx, WR.HL);
|
||||||
|
byte result = doArithmetic(ctx, val, 0, 1);
|
||||||
|
adjustFlags(ctx, val);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* The DAA opcode
|
||||||
|
* According to the value in A and the flags set, add a value to A
|
||||||
|
* This algorithm taken from:
|
||||||
|
* http://www.worldofspectrum.org/faq/reference/z80reference.htm
|
||||||
|
* and verified against the specification in the Zilog
|
||||||
|
* Z80 Family CPU User Manual, rev. 04, Dec. 2004, pp. 166-167
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void doDAA(Z80Context * ctx) {
|
||||||
|
int correction_factor = 0x00;
|
||||||
|
int carry = 0;
|
||||||
|
if(BR.A > 0x99 || GETFLAG(F_C)) {
|
||||||
|
correction_factor |= 0x60;
|
||||||
|
carry = 1;
|
||||||
|
}
|
||||||
|
if((BR.A & 0x0f) > 9 || GETFLAG(F_H))
|
||||||
|
correction_factor |= 0x06;
|
||||||
|
int a_before = BR.A;
|
||||||
|
if(GETFLAG(F_N))
|
||||||
|
BR.A -= correction_factor;
|
||||||
|
else
|
||||||
|
BR.A += correction_factor;
|
||||||
|
VALFLAG(F_H, (a_before ^ BR.A) & 0x10);
|
||||||
|
VALFLAG(F_C, carry);
|
||||||
|
VALFLAG(F_S, (BR.A & 0x80) != 0);
|
||||||
|
VALFLAG(F_Z, (BR.A == 0));
|
||||||
|
VALFLAG(F_PV, parityBit[BR.A]);
|
||||||
|
adjustFlags(ctx, BR.A);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "opcodes_impl.c"
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------
|
||||||
|
* The top-level functions
|
||||||
|
* ---------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static void do_execute(Z80Context* ctx)
|
||||||
|
{
|
||||||
|
struct Z80OpcodeTable* current = &opcodes_main;
|
||||||
|
struct Z80OpcodeEntry* entries = current->entries;
|
||||||
|
Z80OpcodeFunc func;
|
||||||
|
|
||||||
|
byte opcode;
|
||||||
|
int offset = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (ctx->exec_int_vector)
|
||||||
|
{
|
||||||
|
opcode = ctx->int_vector;
|
||||||
|
ctx->tstates += 6;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
opcode = read8(ctx, ctx->PC + offset);
|
||||||
|
ctx->PC++;
|
||||||
|
ctx->tstates += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
INCR;
|
||||||
|
func = entries[opcode].func;
|
||||||
|
if (func != NULL)
|
||||||
|
{
|
||||||
|
ctx->PC -= offset;
|
||||||
|
func(ctx);
|
||||||
|
ctx->PC += offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (entries[opcode].table != NULL)
|
||||||
|
{
|
||||||
|
current = entries[opcode].table;
|
||||||
|
entries = current->entries;
|
||||||
|
offset = current->opcode_offset;
|
||||||
|
if (offset > 0)
|
||||||
|
DECR;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* NOP */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void unhalt(Z80Context* ctx)
|
||||||
|
{
|
||||||
|
if (ctx->halted)
|
||||||
|
{
|
||||||
|
ctx->halted = 0;
|
||||||
|
ctx->PC++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void do_nmi(Z80Context* ctx)
|
||||||
|
{
|
||||||
|
unhalt(ctx);
|
||||||
|
ctx->IFF2 = ctx->IFF1;
|
||||||
|
ctx->IFF1 = 0;
|
||||||
|
doPush(ctx, ctx->PC);
|
||||||
|
ctx->PC = 0x0066;
|
||||||
|
ctx->nmi_req = 0;
|
||||||
|
ctx->tstates += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void do_int(Z80Context* ctx)
|
||||||
|
{
|
||||||
|
unhalt(ctx);
|
||||||
|
ctx->IFF1 = 0;
|
||||||
|
ctx->IFF2 = 0;
|
||||||
|
ctx->int_req = 0;
|
||||||
|
if (ctx->IM == 0)
|
||||||
|
{
|
||||||
|
ctx->exec_int_vector = 1;
|
||||||
|
do_execute(ctx);
|
||||||
|
ctx->exec_int_vector = 0;
|
||||||
|
}
|
||||||
|
else if (ctx->IM == 1)
|
||||||
|
{
|
||||||
|
doPush(ctx, ctx->PC);
|
||||||
|
ctx->PC = 0x0038;
|
||||||
|
ctx->tstates += 7;
|
||||||
|
}
|
||||||
|
else if (ctx->IM == 2)
|
||||||
|
{
|
||||||
|
doPush(ctx, ctx->PC);
|
||||||
|
ushort vector_address = (ctx->I << 8) | ctx->int_vector;
|
||||||
|
ctx->PC = read16(ctx, vector_address);
|
||||||
|
ctx->tstates += 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Z80Execute (Z80Context* ctx)
|
||||||
|
{
|
||||||
|
if (ctx->nmi_req)
|
||||||
|
do_nmi(ctx);
|
||||||
|
else if (ctx->int_req && !ctx->defer_int && ctx->IFF1)
|
||||||
|
do_int(ctx);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctx->defer_int = 0;
|
||||||
|
do_execute(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned Z80ExecuteTStates(Z80Context* ctx, unsigned tstates)
|
||||||
|
{
|
||||||
|
ctx->tstates = 0;
|
||||||
|
while (ctx->tstates < tstates)
|
||||||
|
Z80Execute(ctx);
|
||||||
|
return ctx->tstates;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Z80Debug (Z80Context* ctx, char* dump, char* decode)
|
||||||
|
{
|
||||||
|
char tmp[20];
|
||||||
|
struct Z80OpcodeTable* current = &opcodes_main;
|
||||||
|
struct Z80OpcodeEntry* entries = current->entries;
|
||||||
|
char* fmt;
|
||||||
|
byte opcode;
|
||||||
|
ushort parm;
|
||||||
|
int offset = 0;
|
||||||
|
int PC = ctx->PC;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
if (dump)
|
||||||
|
dump[0] = 0;
|
||||||
|
|
||||||
|
if (decode)
|
||||||
|
decode[0] = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
opcode = read8(ctx, PC + offset);
|
||||||
|
size++;
|
||||||
|
|
||||||
|
PC++;
|
||||||
|
fmt = entries[opcode].format;
|
||||||
|
if (fmt != NULL)
|
||||||
|
{
|
||||||
|
PC -= offset;
|
||||||
|
parm = read16(ctx, PC);
|
||||||
|
|
||||||
|
if (entries[opcode].operand_type == OP_NONE)
|
||||||
|
size++;
|
||||||
|
else
|
||||||
|
size += 2;
|
||||||
|
if (entries[opcode].operand_type != OP_WORD)
|
||||||
|
{
|
||||||
|
parm &= 0xFF;
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decode)
|
||||||
|
sprintf(decode, fmt, parm);
|
||||||
|
|
||||||
|
PC += offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (entries[opcode].table != NULL)
|
||||||
|
{
|
||||||
|
current = entries[opcode].table;
|
||||||
|
entries = current->entries;
|
||||||
|
offset = current->opcode_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (decode != NULL)
|
||||||
|
strcpy(decode, "NOP (ignored)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(1);
|
||||||
|
|
||||||
|
if (dump)
|
||||||
|
{
|
||||||
|
for (offset = 0; offset < size; offset++)
|
||||||
|
{
|
||||||
|
sprintf(tmp, "%02X", read8(ctx, ctx->PC + offset));
|
||||||
|
strcat(dump, tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Z80RESET (Z80Context* ctx)
|
||||||
|
{
|
||||||
|
ctx->PC = 0x0000;
|
||||||
|
BR.F = 0;
|
||||||
|
ctx->IM = 0;
|
||||||
|
ctx->IFF1 = ctx->IFF2 = 0;
|
||||||
|
ctx->R = 0;
|
||||||
|
ctx->I = 0;
|
||||||
|
ctx->halted = 0;
|
||||||
|
ctx->tstates = 0;
|
||||||
|
ctx->nmi_req = 0;
|
||||||
|
ctx->int_req = 0;
|
||||||
|
ctx->defer_int = 0;
|
||||||
|
ctx->exec_int_vector = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Z80INT (Z80Context* ctx, byte value)
|
||||||
|
{
|
||||||
|
ctx->int_req = 1;
|
||||||
|
ctx->int_vector = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Z80NMI (Z80Context* ctx)
|
||||||
|
{
|
||||||
|
ctx->nmi_req = 1;
|
||||||
|
}
|
||||||
|
|
163
emul/z80.h
Normal file
163
emul/z80.h
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
// This unit has been copied from libz80 into Collapse OS and was slighly changed
|
||||||
|
/* =============================================================================
|
||||||
|
* libz80 - Z80 emulation library
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* (C) Gabriel Gambetta (gabriel.gambetta@gmail.com) 2000 - 2012
|
||||||
|
*
|
||||||
|
* Version 2.1.0
|
||||||
|
*
|
||||||
|
* -----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
typedef unsigned short ushort;
|
||||||
|
typedef unsigned char byte;
|
||||||
|
|
||||||
|
|
||||||
|
/** Function type to emulate data read. */
|
||||||
|
typedef byte (*Z80DataIn) (int param, ushort address);
|
||||||
|
|
||||||
|
|
||||||
|
/** Function type to emulate data write. */
|
||||||
|
typedef void (*Z80DataOut) (int param, ushort address, byte data);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Z80 register set.
|
||||||
|
* An union is used since we want independent access to the high and low bytes of the 16-bit registers.
|
||||||
|
*/
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
/** Word registers. */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
ushort AF, BC, DE, HL, IX, IY, SP;
|
||||||
|
} wr;
|
||||||
|
|
||||||
|
/** Byte registers. Note that SP can't be accessed partially. */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
byte F, A, C, B, E, D, L, H, IXl, IXh, IYl, IYh;
|
||||||
|
} br;
|
||||||
|
} Z80Regs;
|
||||||
|
|
||||||
|
|
||||||
|
/** The Z80 flags */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
F_C = 1, /**< Carry */
|
||||||
|
F_N = 2, /**< Sub / Add */
|
||||||
|
F_PV = 4, /**< Parity / Overflow */
|
||||||
|
F_3 = 8, /**< Reserved */
|
||||||
|
F_H = 16, /**< Half carry */
|
||||||
|
F_5 = 32, /**< Reserved */
|
||||||
|
F_Z = 64, /**< Zero */
|
||||||
|
F_S = 128 /**< Sign */
|
||||||
|
} Z80Flags;
|
||||||
|
|
||||||
|
|
||||||
|
/** A Z80 execution context. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Z80Regs R1; /**< Main register set (R) */
|
||||||
|
Z80Regs R2; /**< Alternate register set (R') */
|
||||||
|
ushort PC; /**< Program counter */
|
||||||
|
byte R; /**< Refresh */
|
||||||
|
byte I;
|
||||||
|
byte IFF1; /**< Interrupt Flipflop 1 */
|
||||||
|
byte IFF2; /**< Interrupt Flipflop 2 */
|
||||||
|
byte IM; /**< Instruction mode */
|
||||||
|
|
||||||
|
Z80DataIn memRead;
|
||||||
|
Z80DataOut memWrite;
|
||||||
|
int memParam;
|
||||||
|
|
||||||
|
Z80DataIn ioRead;
|
||||||
|
Z80DataOut ioWrite;
|
||||||
|
int ioParam;
|
||||||
|
|
||||||
|
byte halted;
|
||||||
|
unsigned tstates;
|
||||||
|
|
||||||
|
/* Below are implementation details which may change without
|
||||||
|
* warning; they should not be relied upon by any user of this
|
||||||
|
* library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* If true, an NMI has been requested. */
|
||||||
|
|
||||||
|
byte nmi_req;
|
||||||
|
|
||||||
|
/* If true, a maskable interrupt has been requested. */
|
||||||
|
|
||||||
|
byte int_req;
|
||||||
|
|
||||||
|
/* If true, defer checking maskable interrupts for one
|
||||||
|
* instruction. This is used to keep an interrupt from happening
|
||||||
|
* immediately after an IE instruction. */
|
||||||
|
|
||||||
|
byte defer_int;
|
||||||
|
|
||||||
|
/* When a maskable interrupt has been requested, the interrupt
|
||||||
|
* vector. For interrupt mode 1, it's the opcode to execute. For
|
||||||
|
* interrupt mode 2, it's the LSB of the interrupt vector address.
|
||||||
|
* Not used for interrupt mode 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
byte int_vector;
|
||||||
|
|
||||||
|
/* If true, then execute the opcode in int_vector. */
|
||||||
|
|
||||||
|
byte exec_int_vector;
|
||||||
|
|
||||||
|
} Z80Context;
|
||||||
|
|
||||||
|
|
||||||
|
/** Execute the next instruction. */
|
||||||
|
void Z80Execute (Z80Context* ctx);
|
||||||
|
|
||||||
|
/** Execute enough instructions to use at least tstates cycles.
|
||||||
|
* Returns the number of tstates actually executed. Note: Resets
|
||||||
|
* ctx->tstates.*/
|
||||||
|
unsigned Z80ExecuteTStates(Z80Context* ctx, unsigned tstates);
|
||||||
|
|
||||||
|
/** Decode the next instruction to be executed.
|
||||||
|
* dump and decode can be NULL if such information is not needed
|
||||||
|
*
|
||||||
|
* @param dump A buffer which receives the hex dump
|
||||||
|
* @param decode A buffer which receives the decoded instruction
|
||||||
|
*/
|
||||||
|
void Z80Debug (Z80Context* ctx, char* dump, char* decode);
|
||||||
|
|
||||||
|
/** Resets the processor. */
|
||||||
|
void Z80RESET (Z80Context* ctx);
|
||||||
|
|
||||||
|
/** Generates a hardware interrupt.
|
||||||
|
* Some interrupt modes read a value from the data bus; this value must be provided in this function call, even
|
||||||
|
* if the processor ignores that value in the current interrupt mode.
|
||||||
|
*
|
||||||
|
* @param value The value to read from the data bus
|
||||||
|
*/
|
||||||
|
void Z80INT (Z80Context* ctx, byte value);
|
||||||
|
|
||||||
|
|
||||||
|
/** Generates a non-maskable interrupt. */
|
||||||
|
void Z80NMI (Z80Context* ctx);
|
@ -1,7 +1,5 @@
|
|||||||
#!/bin/sh -e
|
#!/bin/sh -e
|
||||||
|
|
||||||
git submodule init
|
|
||||||
git submodule update
|
|
||||||
git clean -fxd
|
git clean -fxd
|
||||||
|
|
||||||
make -C tests
|
make -C tests
|
||||||
|
Loading…
Reference in New Issue
Block a user