MZ2000 persona, Z80 April 2026, bug fixes and z80 timing fixes
This commit is contained in:
91
projects/Z80/API/Z80.h
vendored
91
projects/Z80/API/Z80.h
vendored
@@ -4,7 +4,7 @@
|
||||
____ \/__/ /\_\ __ \\ \/\ \ ________________________________________________
|
||||
| /\_____\\_____\\_____\ |
|
||||
| Zilog \/_____//_____//_____/ CPU Emulator |
|
||||
| Copyright (C) 1999-2024 Manuel Sainz de Baranda y Goñi. |
|
||||
| Copyright (C) 1999-2026 Manuel Sainz de Baranda y Goñi. |
|
||||
| |
|
||||
| This emulator is free software: you can redistribute it and/or modify it |
|
||||
| under the terms of the GNU Lesser General Public License as published by |
|
||||
@@ -30,13 +30,13 @@
|
||||
* of the Zilog Z80 that emulates all that is known to date about this CPU,
|
||||
* including the undocumented behaviors, MEMPTR, Q and the special RESET.
|
||||
*
|
||||
* @version 0.2
|
||||
* @date 2024
|
||||
* @version 0.2-pre-2025-07-02
|
||||
* @date 2025-07-02
|
||||
* @author Manuel Sainz de Baranda y Goñi */
|
||||
|
||||
#ifdef Z80_DEPENDENCIES_HEADER
|
||||
#ifdef Z80_EXTERNAL_HEADER
|
||||
# define Z80_H
|
||||
# include Z80_DEPENDENCIES_HEADER
|
||||
# include Z80_EXTERNAL_HEADER
|
||||
# undef Z80_H
|
||||
#else
|
||||
# include <Z/macros/language.h>
|
||||
@@ -88,11 +88,27 @@
|
||||
|
||||
#define Z80_MINIMUM_CYCLES_PER_STEP 4
|
||||
|
||||
/** @brief Opcode of the @c halt instruction in the Z80 ISA. */
|
||||
|
||||
#define Z80_HALT 0x76
|
||||
|
||||
/** @brief Opcode interpreted as a trap by the Z80 library. It corresponds to
|
||||
* the <tt>ld h,h</tt> instruction in the Z80 ISA. */
|
||||
|
||||
#define Z80_HOOK 0x64
|
||||
|
||||
/** @brief Opcode of the <tt>jp WORD</tt> instruction in the Z80 ISA. */
|
||||
|
||||
#define Z80_JP_WORD 0xC3
|
||||
|
||||
/** @brief Opcode of the @c nop instruction in the Z80 ISA. */
|
||||
|
||||
#define Z80_NOP 0x00
|
||||
|
||||
/** @brief Opcode of the @c ret instruction in the Z80 ISA. */
|
||||
|
||||
#define Z80_RET 0xC9
|
||||
|
||||
#define Z80_SF 128 /**< @brief Bitmask of the Z80 S flag. */
|
||||
#define Z80_ZF 64 /**< @brief Bitmask of the Z80 Z flag. */
|
||||
#define Z80_YF 32 /**< @brief Bitmask of the Z80 Y flag. */
|
||||
@@ -160,10 +176,10 @@ typedef zuint8 (* Z80Illegal)(Z80 *cpu, zuint8 opcode);
|
||||
* in use. */
|
||||
|
||||
struct Z80 {
|
||||
|
||||
/** @brief Number of clock cycles already executed. */
|
||||
|
||||
zusize cycles;
|
||||
# if !defined(__DOXYGEN__) && defined(Z80_WITH_VOLATILE_CYCLES)
|
||||
volatile
|
||||
# endif
|
||||
zusize cycles; /**< @brief Number of clock cycles already executed. */
|
||||
|
||||
/** @brief Maximum number of clock cycles to be executed. */
|
||||
|
||||
@@ -405,12 +421,12 @@ struct Z80 {
|
||||
|
||||
ZInt16 memptr; /**< @brief Register MEMPTR, also known as WZ. */
|
||||
ZInt16 af; /**< @brief Register pair AF (accumulator and flags). */
|
||||
ZInt16 bc; /**< @brief Register pair BC. */
|
||||
ZInt16 de; /**< @brief Register pair DE. */
|
||||
ZInt16 hl; /**< @brief Register pair HL. */
|
||||
ZInt16 af_; /**< @brief Register pair AF'. */
|
||||
ZInt16 bc; /**< @brief Register pair BC. */
|
||||
ZInt16 bc_; /**< @brief Register pair BC'. */
|
||||
ZInt16 de; /**< @brief Register pair DE. */
|
||||
ZInt16 de_; /**< @brief Register pair DE'. */
|
||||
ZInt16 hl; /**< @brief Register pair HL. */
|
||||
ZInt16 hl_; /**< @brief Register pair HL'. */
|
||||
zuint8 r; /**< @brief Register R (memory refresh). */
|
||||
zuint8 i; /**< @brief Register I (interrupt vector base). */
|
||||
@@ -447,7 +463,7 @@ struct Z80 {
|
||||
|
||||
zuint8 iff1; /**< @brief Interrupt enable flip-flop #1 (IFF1). */
|
||||
zuint8 iff2; /**< @brief Interrupt enable flip-flop #2 (IFF2). */
|
||||
zuint8 q; /**< @brief Pseudo-register Q. */
|
||||
zuint8 q; /**< @brief Q factor. */
|
||||
|
||||
/** @brief Emulation options.
|
||||
*
|
||||
@@ -471,6 +487,33 @@ struct Z80 {
|
||||
* <tt>@ref Z80::halt</tt>, not after. */
|
||||
|
||||
zuint8 halt_line;
|
||||
|
||||
# ifdef Z80_WITH_RESET_SIGNAL
|
||||
/** @brief Pointer to a memory-mapped register containing a reset signal.
|
||||
*
|
||||
* If not @c Z_NULL, the emulator reads this register at every
|
||||
* instruction boundary inside @ref z80_run and tests it against
|
||||
* @ref reset_signal_mask. A non-zero result causes the emulation
|
||||
* loop to exit immediately, before the next instruction fetch.
|
||||
* This allows an external hardware reset line to halt the CPU at
|
||||
* the same point a real Z80 would: at the end of the current
|
||||
* instruction.
|
||||
*
|
||||
* Typical usage: point this to a PIO IRQ flag register or a GPIO
|
||||
* input register, with the mask selecting the relevant bit.
|
||||
*
|
||||
* Setting this to @c Z_NULL disables the check (default). */
|
||||
|
||||
zuint32 volatile const *reset_signal;
|
||||
|
||||
/** @brief Bitmask applied to @ref reset_signal.
|
||||
*
|
||||
* The emulator tests <tt>*reset_signal & reset_signal_mask</tt>
|
||||
* at each instruction boundary. A non-zero result indicates that
|
||||
* a reset is active. */
|
||||
|
||||
zuint32 reset_signal_mask;
|
||||
# endif
|
||||
};
|
||||
|
||||
/** @brief <tt>@ref Z80::options</tt> bitmask that enables emulation of the
|
||||
@@ -775,7 +818,7 @@ Z_EXTERN_C_BEGIN
|
||||
* @c Z_TRUE = power on;
|
||||
* @c Z_FALSE = power off. */
|
||||
|
||||
Z80_API void z80_power(Z80 *self, zboolean state);
|
||||
Z80_API void z80_power(Z80 *self, zbool state);
|
||||
|
||||
/** @brief Performs an instantaneous normal RESET on a <tt>@ref Z80</tt>.
|
||||
*
|
||||
@@ -800,7 +843,7 @@ Z80_API void z80_special_reset(Z80 *self);
|
||||
* @c Z_TRUE = set line low;
|
||||
* @c Z_FALSE = set line high. */
|
||||
|
||||
Z80_API void z80_int(Z80 *self, zboolean state);
|
||||
Z80_API void z80_int(Z80 *self, zbool state);
|
||||
|
||||
/** @brief Triggers the NMI line of a <tt>@ref Z80</tt>.
|
||||
*
|
||||
@@ -809,7 +852,8 @@ Z80_API void z80_int(Z80 *self, zboolean state);
|
||||
Z80_API void z80_nmi(Z80 *self);
|
||||
|
||||
/** @brief Runs a <tt>@ref Z80</tt> for a given number of clock @p cycles,
|
||||
* executing only instructions without responding to signals.
|
||||
* executing only instructions without responding to interrupts requests or
|
||||
* special RESET signals.
|
||||
*
|
||||
* @param self Pointer to the object on which the function is called.
|
||||
* @param cycles Number of clock cycles to be emulated.
|
||||
@@ -831,7 +875,7 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles);
|
||||
*
|
||||
* This function should only be used inside callback functions. It zeroes
|
||||
* <tt>@ref Z80::cycle_limit</tt>, thus breaking the emulation loop after the
|
||||
* ongoing emulation step has finished executing.
|
||||
* completion of the ongoing emulation step.
|
||||
*
|
||||
* @param self Pointer to the object on which the function is called. */
|
||||
|
||||
@@ -899,6 +943,19 @@ static inline zuint8 z80_out_cycle(Z80 const *self)
|
||||
}
|
||||
|
||||
|
||||
/** @brief Sends a WAIT signal to a <tt>@ref Z80</tt>.
|
||||
*
|
||||
* This function should only be used inside callback functions. It adds the
|
||||
* given number of clock @p cycles to <tt>@ref Z80::cycles</tt>, thus
|
||||
* lengthening the ongoing emulation step.
|
||||
*
|
||||
* @param self Pointer to the object on which the function is called.
|
||||
* @param cycles Duration of the WAIT signal, in clock cycles. */
|
||||
|
||||
static inline void z80_wait(Z80 *self, zusize cycles)
|
||||
{self->cycles += cycles;}
|
||||
|
||||
|
||||
Z_EXTERN_C_END
|
||||
|
||||
#endif /* Z80_H */
|
||||
|
||||
Reference in New Issue
Block a user