MZ2000 persona, Z80 April 2026, bug fixes and z80 timing fixes

This commit is contained in:
Philip Smart
2026-05-13 20:55:04 +01:00
parent 516426a8c7
commit 5bbb3bcf5f
257 changed files with 13634 additions and 4193 deletions

View File

@@ -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 */