diff --git a/.github/workflows/library-ci.yml b/.github/workflows/library-ci.yml
index 2c7750a..d577b2e 100644
--- a/.github/workflows/library-ci.yml
+++ b/.github/workflows/library-ci.yml
@@ -33,8 +33,7 @@ env:
Z80_WITH_EXECUTE: YES
Z80_WITH_FULL_IM0: YES
Z80_WITH_Q: YES
- Z80_WITH_RESET_SIGNAL: YES
- Z80_WITH_SPECIAL_RESET_SIGNAL: NO
+ Z80_WITH_SPECIAL_RESET: NO
Z80_WITH_UNOFFICIAL_RETI: NO
Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG: YES
@@ -79,8 +78,7 @@ jobs:
-DZ80_WITH_EXECUTE=${{env.Z80_WITH_EXECUTE}}
-DZ80_WITH_FULL_IM0=${{env.Z80_WITH_FULL_IM0}}
-DZ80_WITH_Q=${{env.Z80_WITH_Q}}
- -DZ80_WITH_RESET_SIGNAL=${{env.Z80_WITH_RESET_SIGNAL}}
- -DZ80_WITH_SPECIAL_RESET_SIGNAL=${{env.Z80_WITH_SPECIAL_RESET_SIGNAL}}
+ -DZ80_WITH_SPECIAL_RESET=${{env.Z80_WITH_SPECIAL_RESET}}
-DZ80_WITH_UNOFFICIAL_RETI=${{env.Z80_WITH_UNOFFICIAL_RETI}}
-DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=${{env.Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG}}
diff --git a/API/Z80.h b/API/Z80.h
index 5270020..1705180 100644
--- a/API/Z80.h
+++ b/API/Z80.h
@@ -147,11 +147,11 @@ typedef zusize (* Z80Reset)(void *context, zuint16 address);
typedef struct {
- /** @brief Number of clock cycles already executed. */
+ /** @brief Number of clock cycles (T-states) already executed. */
zusize cycles;
- /** @brief Maximum number of clock cycles to be executed. */
+ /** @brief Maximum number of clock cycles (T-states) to be executed. */
zusize cycle_limit;
@@ -227,14 +227,13 @@ typedef struct {
/** @brief Invoked to perform an opcode fetch that corresponds to an
* internal NOP.
*
- * This callback indicates the beginning of an internal NOP, which is
- * an opcode fetch M-cycle that is generated in two situations:
+ * This callback indicates the beginning of an opcode fetch M-cycle
+ * that is generated in the following cases:
*
* - During the HALT state, the CPU repeatedly executes an internal NOP
* that fetches the next opcode after @c halt without incrementing
* the PC register. This opcode is read again and again until an exit
* condition occurs.
- *
* - After detecting a special reset signal, the CPU completes the
* ongoing instruction and then executes an internal NOP during which
* it zeroes the PC register.
@@ -273,45 +272,50 @@ typedef struct {
Z80Read int_fetch;
- /** @brief Callback invoked to query the duration of a RESET signal.
- *
- * @attention This callback is optional and must be set to @c Z_NULL
- * when not used. */
-
- Z80Reset reset;
-
/** @brief Invoked when an ld i,a instruction is fetched.
*
- * @attention This callback is optional and must be set to @c Z_NULL
- * when not used. */
+ * This callback is invoked before the ld i,a instruction
+ * modifies the I register.
+ *
+ * This callback is optional and must be set to @c Z_NULL when not
+ * used. */
Z80Notify ld_i_a;
/** @brief Invoked when an ld r,a instruction is fetched.
*
- * @attention This callback is optional and must be set to @c Z_NULL
- * when not used. */
+ * This callback is invoked before the ld r,a instruction
+ * modifies the R register.
+ *
+ * This callback is optional and must be set to @c Z_NULL when not
+ * used. */
Z80Notify ld_r_a;
/** @brief Invoked when a @c reti instruction is fetched.
*
- * @attention This callback is optional and must be set to @c Z_NULL
- * when not used. */
+ * This callback is invoked before executing a @c reti instruction.
+ *
+ * This callback is optional and must be set to @c Z_NULL when not
+ * used. */
Z80Notify reti;
/** @brief Callback invoked when a @c retn instruction is fetched.
*
- * @attention This callback is optional and must be set to @c Z_NULL
- * when not used. */
+ * This callback is invoked before executing a @c retn instruction.
+ *
+ * This callback is optional and must be set to @c Z_NULL when not
+ * used. */
Z80Notify retn;
/** @brief Invoked when a trap is fecthed.
*
- * @attention This callback is optional and must be set to @c Z_NULL
- * when not used. */
+ * This callback is invoked before the @c retn instruction is executed.
+ *
+ * This callback is optional and must be set to @c Z_NULL when not
+ * used. */
Z80Read hook;
@@ -469,10 +473,6 @@ typedef struct {
#define Z80_MODEL_ST_CMOS \
(Z80_OPTION_LD_A_IR_BUG | Z80_OPTION_YQ)
-/** @brief @ref Z80 request flag anouncing an incoming RESET signal. */
-
-#define Z80_REQUEST_RESET 3
-
/** @brief @ref Z80 request flag that prevents the NMI signal from being
* accepted. */
@@ -483,16 +483,11 @@ typedef struct {
#define Z80_REQUEST_NMI 8
-#define Z80_REQUEST_CLEAR_PC 16
-
/** @brief @ref Z80 request flag anouncing an incoming special RESET signal. */
#define Z80_REQUEST_SPECIAL_RESET 32
#define Z80_REQUEST_INT 64
-#define Z80_REQUEST_ANY_RESET 35
-#define Z80_REQUEST_RESET 3
-#define Z80_REQUEST_INTERRUPT 5
/** @brief @ref Z80 resume code that is set when the emulator runs out of clock
* cycles during the HALT state. */
@@ -511,9 +506,6 @@ typedef struct {
#define Z80_RESUME_IM0_XY 3
-#define Z80_RESUME_SPECIAL_RESET_XY 5
-#define Z80_RESUME_SPECIAL_RESET_NOP 6
-
/** @brief Accesses the MEMPTR register of a @ref Z80 @p object. */
#define Z80_MEMPTR(object) (object).memptr.uint16_value
@@ -699,12 +691,6 @@ Z80_API void z80_power(Z80 *self, zboolean state);
Z80_API void z80_instant_reset(Z80 *self);
-/** @brief Sends a normal RESET signal to a @ref Z80 object.
- *
- * @param self Pointer to the object on which the function is called. */
-
-Z80_API void z80_reset(Z80 *self);
-
/** @brief Sends a special RESET signal to a @ref Z80 object.
*
* @sa
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5599d9f..4be7f51 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -91,12 +91,8 @@ option(${PROJECT_NAME}_WITH_Q
"Build the implementation of the Q \"register\"."
NO)
-option(${PROJECT_NAME}_WITH_RESET_SIGNAL
-"Build the implementation of the normal RESET signal."
-NO)
-
-option(${PROJECT_NAME}_WITH_SPECIAL_RESET_SIGNAL
-"Build the implementation of the special RESET signal."
+option(${PROJECT_NAME}_WITH_SPECIAL_RESET
+"Build the implementation of the special RESET."
NO)
option(${PROJECT_NAME}_WITH_UNOFFICIAL_RETI
@@ -184,12 +180,8 @@ if(${PROJECT_NAME}_WITH_Q)
target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_Q)
endif()
-if(${PROJECT_NAME}_WITH_RESET_SIGNAL)
- target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_RESET_SIGNAL)
-endif()
-
-if(${PROJECT_NAME}_WITH_SPECIAL_RESET_SIGNAL)
- target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_SPECIAL_RESET_SIGNAL)
+if(${PROJECT_NAME}_WITH_SPECIAL_RESET)
+ target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_SPECIAL_RESET)
endif()
if(${PROJECT_NAME}_WITH_UNOFFICIAL_RETI)
diff --git a/HISTORY b/HISTORY
index f5fa674..a1738c6 100644
--- a/HISTORY
+++ b/HISTORY
@@ -52,50 +52,50 @@ Changes:
source register with NOPs.
33. Reimplemented the HALT state. The emulation should now be fully accurate.
HALTskip is also supported.
-34. Added optional emulation of the normal and special RESET signals, along with
- the new `z80_reset` and `z80_special_reset` functions for emitting them. The
- old `z80_reset` function is now called `z80_instant_reset`.
-35. Added the `Z80::fetch_opcode` and `Z80::fetch` callbacks for performing
+34. Renamed the `z80_reset` function to `z80_instant_reset`.
+35. Added optional emulation of the special RESET, along with the new
+ `z80_special_reset` function.
+36. Added the `Z80::fetch_opcode` and `Z80::fetch` callbacks for performing
opcode fetch operations and memory read operations on instruction data
respectively.
-36. Added the `Z80::nop` callback for performing disregarded opcode fetch
+37. Added the `Z80::nop` callback for performing disregarded opcode fetch
operations during internal NOP M-cycles.
-37. Added emulation of the NMI acknowledge M-cycle through the new `Z80::nmia`
+38. Added emulation of the NMI acknowledge M-cycle through the new `Z80::nmia`
callback.
-38. Added emulation of the INT acknowledge M-cycle through the new `Z80::inta`
+39. Added emulation of the INT acknowledge M-cycle through the new `Z80::inta`
callback, which replaces `Z80::int_data`.
-39. Added optional full emulation of the interrupt mode 0, along with the new
+40. Added optional full emulation of the interrupt mode 0, along with the new
`Z80::int_fetch` callback for performing bus read operations on instruction
data. If not enabled at compile-time, the old simplified emulation is built,
which supports only the most typical instructions.
-40. Added four callbacks for notifying the execution of important instructions:
+41. Added four callbacks for notifying the execution of important instructions:
`Z80::ld_i_a`, `Z80::ld_r_a`, `Z80::reti` and `Z80::retn`.
-41. Added hooking functionality through the `ld h,h` instruction and the new
+42. Added hooking functionality through the `ld h,h` instruction and the new
`Z80::hook` callback.
-42. Added the `Z80::illegal` callback for delegating the emulation of illegal
+43. Added the `Z80::illegal` callback for delegating the emulation of illegal
instructions.
-43. Added accurate flag behavior in the following instructions: `ldir`, `lddr`,
+44. Added accurate flag behavior in the following instructions: `ldir`, `lddr`,
`cpir`, `cpdr`, `inir`, `indr`, `otir` and `otdr`.
-44. Added emulation of the interrupt acceptance deferral that occurs during the
+45. Added emulation of the interrupt acceptance deferral that occurs during the
`reti` and `retn` instructions.
-45. Added MEMPTR emulation. The `bit N,(hl)` instruction now produces a correct
+46. Added MEMPTR emulation. The `bit N,(hl)` instruction now produces a correct
value of F.
-46. Added optional emulation of the Q "register". If enabled at compile-time,
+47. Added optional emulation of the Q "register". If enabled at compile-time,
the `ccf` and `scf` instructions produce a correct value of F.
-47. Added emulation options that can be configured at runtime.
-48. Added emulation of the `out (c),255` instruction (Zilog Z80 CMOS).
-49. Added optional emulation of the bug affecting the `ld a,{i|r}` instructions
+48. Added emulation options that can be configured at runtime.
+49. Added emulation of the `out (c),255` instruction (Zilog Z80 CMOS).
+50. Added optional emulation of the bug affecting the `ld a,{i|r}` instructions
(Zilog Z80 NMOS). If enabled at compile-time, the P/V flag is reset when an
INT is accepted during the execution of these instructions.
-50. Removed `Z80::state`. Replaced with individual members for the registers,
+51. Removed `Z80::state`. Replaced with individual members for the registers,
the interrupt enable flip-flops and the interrupt mode.
-51. Removed the superfluous EI flag. The previous opcode is checked instead,
+52. Removed the superfluous EI flag. The previous opcode is checked instead,
which is faster and makes the `Z80` object smaller.
-52. Removed all module-related stuff.
-53. Optimizations in flag computation and condition evaluation.
-54. New source code comments and improvements to existing ones.
-55. Improved code aesthetics.
-56. Other improvements, optimizations and minor changes.
+53. Removed all module-related stuff.
+54. Optimizations in flag computation and condition evaluation.
+55. New source code comments and improvements to existing ones.
+56. Improved code aesthetics.
+57. Other improvements, optimizations and minor changes.
Z80 v0.1 (2018-11-10)
diff --git a/README b/README
index 4f5971e..4e2d692 100644
--- a/README
+++ b/README
@@ -176,12 +176,8 @@ library by predefining macros that enable optional implementations:
Build the implementation of the Q "register".
The default is `NO`.
- -DZ80_WITH_RESET_SIGNAL=(YES|NO)
- Build the implementation of the normal RESET signal.
- The default is `NO`.
-
- -DZ80_WITH_SPECIAL_RESET_SIGNAL=(YES|NO)
- Build the implementation of the special RESET signal.
+ -DZ80_WITH_SPECIAL_RESET=(YES|NO)
+ Build the implementation of the special RESET.
The default is `NO`.
-DZ80_WITH_UNOFFICIAL_RETI=(YES|NO)
@@ -201,7 +197,6 @@ library:
-DZ80_WITH_EXECUTE=YES
-DZ80_WITH_FULL_IM0=YES
-DZ80_WITH_Q=YES
- -DZ80_WITH_RESET_SIGNAL=YES
-DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=YES
Finally, once the build system is configured according to your needs, build and
@@ -282,8 +277,7 @@ source code by predefining the following macros:
#define Z80_WITH_EXECUTE
#define Z80_WITH_FULL_IM0
#define Z80_WITH_Q
- #define Z80_WITH_RESET_SIGNAL
- #define Z80_WITH_SPECIAL_RESET_SIGNAL
+ #define Z80_WITH_SPECIAL_RESET
#define Z80_WITH_UNOFFICIAL_RETI
#define Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG
@@ -312,4 +306,4 @@ with this library. If not, see .
--------------------------------------------------------------------------------
-Last update: 2022-07-03 README EOF
+Last update: 2022-07-16 README EOF
diff --git a/README.md b/README.md
index 306b83d..fe7363a 100644
--- a/README.md
+++ b/README.md
@@ -432,12 +432,8 @@ Package-specific options are prefixed with `Z80_` and can be divided into two gr
Build the implementation of the [Q "register"](https://worldofspectrum.org/forums/discussion/41704).
The default is `NO`.
-* **`-DZ80_WITH_RESET_SIGNAL=(YES|NO)`**
- Build the implementation of the normal RESET signal.
- The default is `NO`.
-
-* **`-DZ80_WITH_SPECIAL_RESET_SIGNAL=(YES|NO)`**
- Build the implementation of the [special RESET](http://www.primrosebank.net/computers/z80/z80_special_reset.htm) signal.
+* **`-DZ80_WITH_SPECIAL_RESET=(YES|NO)`**
+ Build the implementation of the [special RESET](http://www.primrosebank.net/computers/z80/z80_special_reset.htm).
The default is `NO`.
* **`-DZ80_WITH_UNOFFICIAL_RETI=(YES|NO)`**
@@ -454,7 +450,6 @@ Package maintainers should use at least the following options for the shared lib
-DZ80_WITH_EXECUTE=YES
-DZ80_WITH_FULL_IM0=YES
-DZ80_WITH_Q=YES
--DZ80_WITH_RESET_SIGNAL=YES
-DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=YES
```
@@ -539,8 +534,7 @@ There are several macros that can be used to configure the source code of the li
* **[`#define Z80_WITH_EXECUTE`](#option_z80_with_execute)**
* **[`#define Z80_WITH_FULL_IM0`](#option_z80_with_full_im0)**
* **[`#define Z80_WITH_Q`](#option_z80_with_q)**
-* **[`#define Z80_WITH_RESET_SIGNAL`](#option_z80_with_reset_signal)**
-* **[`#define Z80_WITH_SPECIAL_RESET_SIGNAL`](#option_z80_with_special_reset_signal)**
+* **[`#define Z80_WITH_SPECIAL_RESET`](#option_z80_with_special_reset)**
* **[`#define Z80_WITH_UNOFFICIAL_RETI`](#option_z80_with_unofficial_reti)**
* **[`#define Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG`](#option_z80_with_zilog_nmos_ld_a_ir_bug)**
diff --git a/documentation/APIReference.rst b/documentation/APIReference.rst
index 37e5c0e..3cf8863 100644
--- a/documentation/APIReference.rst
+++ b/documentation/APIReference.rst
@@ -116,6 +116,5 @@ Functions
.. doxygenfunction:: z80_power
.. doxygenfunction:: z80_r
.. doxygenfunction:: z80_refresh_address
-.. doxygenfunction:: z80_reset
.. doxygenfunction:: z80_run
.. doxygenfunction:: z80_special_reset
diff --git a/documentation/Installation.rst b/documentation/Installation.rst
index ac3d0f1..d0f8038 100644
--- a/documentation/Installation.rst
+++ b/documentation/Installation.rst
@@ -132,14 +132,9 @@ The second group of package-specific options configures the source code of the l
Build the implementation of the `Q "register" `_. |br| |nl|
The default is ``NO``.
-.. option:: -DZ80_WITH_RESET_SIGNAL=(YES|NO)
+.. option:: -DZ80_WITH_SPECIAL_RESET=(YES|NO)
- Build the implementation of the normal RESET signal. |br| |nl|
- The default is ``NO``.
-
-.. option:: -DZ80_WITH_SPECIAL_RESET_SIGNAL=(YES|NO)
-
- Build the implementation of the `special RESET `_ signal. |br| |nl|
+ Build the implementation of the `special RESET `_. |br| |nl|
The default is ``NO``.
.. option:: -DZ80_WITH_UNOFFICIAL_RETI=(YES|NO)
@@ -159,7 +154,6 @@ Package maintainers should use at least the following options for the shared lib
-DZ80_WITH_EXECUTE=YES
-DZ80_WITH_FULL_IM0=YES
-DZ80_WITH_Q=YES
- -DZ80_WITH_RESET_SIGNAL=YES
-DZ80_WITH_ZILOG_NMOS_LD_A_IR_BUG=YES
Finally, once the build system is configured according to your needs, build and install the package:
diff --git a/documentation/Integration.rst b/documentation/Integration.rst
index 2001728..d3fc0c8 100644
--- a/documentation/Integration.rst
+++ b/documentation/Integration.rst
@@ -72,8 +72,7 @@ The second group of package-specific options, explained in the "Installation" se
.. c:macro:: Z80_WITH_EXECUTE
.. c:macro:: Z80_WITH_FULL_IM0
.. c:macro:: Z80_WITH_Q
-.. c:macro:: Z80_WITH_RESET_SIGNAL
-.. c:macro:: Z80_WITH_SPECIAL_RESET_SIGNAL
+.. c:macro:: Z80_WITH_SPECIAL_RESET
.. c:macro:: Z80_WITH_UNOFFICIAL_RETI
.. c:macro:: Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG
diff --git a/documentation/VersionHistory.rst b/documentation/VersionHistory.rst
index 90d8081..1202679 100644
--- a/documentation/VersionHistory.rst
+++ b/documentation/VersionHistory.rst
@@ -42,29 +42,30 @@ Changes:
31. Replaced all register resolution functions with macros.
32. Replaced all ``ld {J,K|O,P}`` instructions that have the same destination and source register with NOPs.
33. Reimplemented the HALT state. The emulation should now be fully accurate. HALTskip is also supported.
-34. Added optional emulation of the normal and special RESET signals, along with the new ``z80_reset`` and ``z80_special_reset`` functions for emitting them. The old ``z80_reset`` function is now called ``z80_instant_reset``.
-35. Added the ``Z80::fetch_opcode`` and ``Z80::fetch`` callbacks for performing opcode fetch operations and memory read operations on instruction data respectively.
-36. Added the ``Z80::nop`` callback for performing disregarded opcode fetch operations during internal NOP M-cycles.
-37. Added emulation of the NMI acknowledge M-cycle through the new ``Z80::nmia`` callback.
-38. Added emulation of the INT acknowledge M-cycle through the new ``Z80::inta`` callback, which replaces ``Z80::int_data``.
-39. Added optional full emulation of the interrupt mode 0, along with the new ``Z80::int_fetch`` callback for performing bus read operations on instruction data. If not enabled at compile-time, the old simplified emulation is built, which supports only the most typical instructions.
-40. Added four callbacks for notifying the execution of important instructions: ``Z80::ld_i_a``, ``Z80::ld_r_a``, ``Z80::reti`` and ``Z80::retn``.
-41. Added hooking functionality through the ``ld h,h`` instruction and the new ``Z80::hook`` callback.
-42. Added the ``Z80::illegal`` callback for delegating the emulation of illegal instructions.
-43. Added accurate flag behavior in the following instructions: ``ldir``, ``lddr``, ``cpir``, ``cpdr``, ``inir``, ``indr``, ``otir`` and ``otdr``.
-44. Added emulation of the interrupt acceptance deferral that occurs during the ``reti`` and ``retn`` instructions.
-45. Added MEMPTR emulation. The ``bit N,(hl)`` instruction now produces a correct value of F.
-46. Added optional emulation of the Q "register". If enabled at compile-time, the ``ccf`` and ``scf`` instructions produce a correct value of F.
-47. Added emulation options that can be configured at runtime.
-48. Added emulation of the ``out (c),255`` instruction (Zilog Z80 CMOS).
-49. Added optional emulation of the bug affecting the ``ld a,{i|r}`` instructions (Zilog Z80 NMOS). If enabled at compile-time, the P/V flag is reset when an INT is accepted during the execution of these instructions.
-50. Removed ``Z80::state``. Replaced with individual members for the registers, the interrupt enable flip-flops and the interrupt mode.
-51. Removed the superfluous EI flag. The previous opcode is checked instead, which is faster and makes the ``Z80`` object smaller.
-52. Removed all module-related stuff.
-53. Optimizations in flag computation and condition evaluation.
-54. New source code comments and improvements to existing ones.
-55. Improved code aesthetics.
-56. Other improvements, optimizations and minor changes.
+34. Renamed the ``z80_reset`` function to ``z80_instant_reset``.
+35. Added optional emulation of the special RESET, along with the new ``z80_special_reset`` function.
+36. Added the ``Z80::fetch_opcode`` and ``Z80::fetch`` callbacks for performing opcode fetch operations and memory read operations on instruction data respectively.
+37. Added the ``Z80::nop`` callback for performing disregarded opcode fetch operations during internal NOP M-cycles.
+38. Added emulation of the NMI acknowledge M-cycle through the new ``Z80::nmia`` callback.
+39. Added emulation of the INT acknowledge M-cycle through the new ``Z80::inta`` callback, which replaces ``Z80::int_data``.
+40. Added optional full emulation of the interrupt mode 0, along with the new ``Z80::int_fetch`` callback for performing bus read operations on instruction data. If not enabled at compile-time, the old simplified emulation is built, which supports only the most typical instructions.
+41. Added four callbacks for notifying the execution of important instructions: ``Z80::ld_i_a``, ``Z80::ld_r_a``, ``Z80::reti`` and ``Z80::retn``.
+42. Added hooking functionality through the ``ld h,h`` instruction and the new ``Z80::hook`` callback.
+43. Added the ``Z80::illegal`` callback for delegating the emulation of illegal instructions.
+44. Added accurate flag behavior in the following instructions: ``ldir``, ``lddr``, ``cpir``, ``cpdr``, ``inir``, ``indr``, ``otir`` and ``otdr``.
+45. Added emulation of the interrupt acceptance deferral that occurs during the ``reti`` and ``retn`` instructions.
+46. Added MEMPTR emulation. The ``bit N,(hl)`` instruction now produces a correct value of F.
+47. Added optional emulation of the Q "register". If enabled at compile-time, the ``ccf`` and ``scf`` instructions produce a correct value of F.
+48. Added emulation options that can be configured at runtime.
+49. Added emulation of the ``out (c),255`` instruction (Zilog Z80 CMOS).
+50. Added optional emulation of the bug affecting the ``ld a,{i|r}`` instructions (Zilog Z80 NMOS). If enabled at compile-time, the P/V flag is reset when an INT is accepted during the execution of these instructions.
+51. Removed ``Z80::state``. Replaced with individual members for the registers, the interrupt enable flip-flops and the interrupt mode.
+52. Removed the superfluous EI flag. The previous opcode is checked instead, which is faster and makes the ``Z80`` object smaller.
+53. Removed all module-related stuff.
+54. Optimizations in flag computation and condition evaluation.
+55. New source code comments and improvements to existing ones.
+56. Improved code aesthetics.
+57. Other improvements, optimizations and minor changes.
v0.1 (2018-11-10)
=================
diff --git a/sources/Z80.c b/sources/Z80.c
index 779dc85..90b7302 100644
--- a/sources/Z80.c
+++ b/sources/Z80.c
@@ -957,7 +957,7 @@ static Z_INLINE zuint8 m(Z80 *self, zuint8 offset, zuint8 value)
#define OTXR(hl_operator, memptr_operator) \
zuint8 out = READ(HL hl_operator); \
- zuint8 nf = (out & 128) >> 6; \
+ zuint8 nf = (out >> 6) & NF; \
zuint t = (zuint)out + L; \
zuint8 hcf = (t > 255) ? HCF : 0; \
zuint8 p = (t & 7) ^ --B; \
@@ -967,9 +967,9 @@ static Z_INLINE zuint8 m(Z80 *self, zuint8 offset, zuint8 value)
INXR_OTXR(out)
-#define EXIT_HALT_STATE \
- HALT_LINE = FALSE; \
- if (self->halt != Z_NULL) self->halt(CONTEXT, FALSE)
+#define SET_HALT_LINE(state) \
+ HALT_LINE = state; \
+ if (self->halt != Z_NULL) self->halt(CONTEXT, state)
/* MARK: - Instructions: 8-Bit Load Group */
@@ -1223,7 +1223,7 @@ INSTRUCTION(neg)
/*---------------------------------------------------------------------------.
-| "ccf" and "scf" are the only instructions in which Q affects the flags. |
+| `ccf` and `scf` are the only instructions in which Q affects the flags. |
| Patrik Rak cracked the behavior of YF and XF in 2012, confirming that they |
| are taken, respectively, from bits 5 and 3 of the result of "(Q ^ F) | A" |
| [1,2]. This applies to all Zilog Z80 models, both NMOS and CMOS. In 2018, |
@@ -1277,12 +1277,12 @@ INSTRUCTION(scf)
/*-----------------------------------------------------------------------------.
-| The "halt" instruction enables the HALT state after PC is incremented during |
+| The `halt` instruction enables the HALT state after PC is incremented during |
| the opcode fetch. The CPU neither decrements nor avoids incrementing PC "so |
| that the instruction is re-executed" as Sean Young writes in section 5.4 of |
| "The Undocumented Z80 Documented". During the HALT state, the CPU repeatedly |
| executes an internal NOP operation. Each NOP consists of 1 M1 cycle of 4 |
-| T-states that fetches and disregards the next opcode after "halt" without |
+| T-states that fetches and disregards the next opcode after `halt` without |
| incrementing PC. This opcode is read again and again until an exit condition |
| occurs (i.e., INT, NMI or RESET). |
| |
@@ -1302,40 +1302,35 @@ INSTRUCTION(halt)
{
Q_0
PC++;
- if (REQUEST & Z80_REQUEST_INTERRUPT) return 4;
+ if (REQUEST) return 4;
RESUME = Z80_RESUME_HALT;
if ((self->cycles += 4) >= self->cycle_limit) return 0;
}
- HALT_LINE = TRUE;
- if (self->halt != Z_NULL) self->halt(CONTEXT, TRUE);
+ SET_HALT_LINE(TRUE);
}
if (self->nop == Z_NULL || (OPTIONS & Z80_OPTION_HALT_SKIP))
{
- if (REQUEST) RESUME = FALSE;
+ zusize nop_cycles = self->cycle_limit - self->cycles;
- else if (self->cycles < self->cycle_limit)
- {
- zusize nop_cycles = self->cycle_limit - self->cycles;
-
- nop_cycles += (4 - (nop_cycles & 3)) & 3;
- R += (zuint8)(nop_cycles >> 2);
- self->cycles += nop_cycles;
- }
+ nop_cycles += (4 - (nop_cycles & 3)) & 3;
+ R += (zuint8)(nop_cycles >> 2);
+ self->cycles += nop_cycles;
}
- else for (; self->cycles < self->cycle_limit; self->cycles += 4)
- {
+ else do {
+ R++; /* M1 */
+ (void)self->nop(CONTEXT, PC);
+ self->cycles += 4;
+
if (REQUEST)
{
RESUME = FALSE;
return 0;
}
-
- R++; /* M1 */
- (void)self->nop(CONTEXT, PC);
}
+ while (self->cycles < self->cycle_limit);
return 0;
}
@@ -1543,9 +1538,9 @@ INSTRUCTION(djnz_OFFSET) {DJNZ_JR_Z_OFFSET(--B, 13, 8); }
|+ reti/retn <--ED-->01***101 ........ 14:4433 |
| rst N 11nnn111 ........ 11:533 |
|---------------------------------------------------------------------|
-| (+) The instruction has undocumented opcodes. The mnemonic "reti" |
+| (+) The instruction has undocumented opcodes. The `reti` mnemonic |
| is used to represent the ED4Dh opcode, which is recognized by |
-| the Z80 CTC chip. All others opcodes are represented as "retn". |
+| the Z80 CTC chip. All other opcodes are represented as `retn`. |
'====================================================================*/
INSTRUCTION(call_WORD) {Q_0 MEMPTR = FETCH_16(PC + 1); PUSH(PC + 3); PC = MEMPTR; return 17;}
@@ -1646,7 +1641,7 @@ INSTRUCTION(out_vBYTE_a)
/*----------------------------------------------------------------------------.
-| The "out (c),0" instruction behaves as "out (c),255" on the Zilog Z80 CMOS. |
+| The `out (c),0` instruction behaves as `out (c),255` on the Zilog Z80 CMOS. |
| This was first discovered by Simon Cooke, who reported it on Usenet in 1996 |
| [1]. Later, in 2004, Colin Piggot rediscovered it with his SAM Coupé when |
| running a demo for SCPDU 6, coincidentally written by Simon Cooke [2]. In |
@@ -1885,7 +1880,7 @@ INSTRUCTION(xy_xy)
/*------------------------------------------------------------------.
| The CPU ignores illegal instructions with EDh prefix; in practice |
-| they are all equivalent to two "nop" instructions (8 T-states). |
+| they are all equivalent to two `nop` instructions (8 T-states). |
'==================================================================*/
INSTRUCTION(ed_illegal)
@@ -2019,21 +2014,34 @@ Z80_API void z80_power(Z80 *self, zboolean state)
}
+/*-------------------------------------------------------------------------.
+| The normal reset clears PC, I, and R [1,2,3,4,5], resets the interrupt |
+| enable flip-flops (IFF1 and IFF2) [1,2,4,5] and sets the interrupt mode |
+| 0 [1,2,5]. Once /RESET goes inactive, the CPU consumes 3 T-states before |
+| resuming normal processing operation at address 0000h [2,4,6,7]. |
+| |
+| References: |
+| 1. Zilog (2016-09). "Z80 CPU User Manual" revision 11. p. 6. |
+| 2. Flammenkamp, Achim. "Interrupt Behaviour of the Z80 CPU". |
+| * http://z80.info/interrup.htm |
+| 3. https://worldofspectrum.org/forums/discussion/34574 |
+| 4. https://baltazarstudios.com/webshare/Z80-undocumented-behavior.htm |
+| 5. Brewer, Tony (2014-12). "Z80 Special Reset". |
+| * http://primrosebank.net/computers/z80/z80_special_reset.htm |
+| 6. SGS-Thomson (1990-01). "Z80 Microprocessor Family" 1st edition. |
+| p. 40. |
+'=========================================================================*/
+
Z80_API void z80_instant_reset(Z80 *self)
{
- if (HALT_LINE) {EXIT_HALT_STATE;}
+ if (HALT_LINE) {SET_HALT_LINE(FALSE);}
+
PC = R = I = IFF1 = IFF2 = IM =
DATA[0] = HALT_LINE = RESUME = REQUEST = 0;
}
-#ifdef Z80_WITH_RESET_SIGNAL
- Z80_API void z80_reset(Z80 *self)
- {REQUEST |= Z80_REQUEST_RESET;}
-#endif
-
-
-#ifdef Z80_WITH_SPECIAL_RESET_SIGNAL
+#ifdef Z80_WITH_SPECIAL_RESET
Z80_API void z80_special_reset(Z80 *self)
{REQUEST |= Z80_REQUEST_SPECIAL_RESET;}
#endif
@@ -2092,7 +2100,7 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
| significant bit, commonly known as R7. This behavior is not emulated |
| in every increment for obvious speed reasons. Instead, a copy of R |
| is used to preserve R7, which is restored before returning from this |
- | function. The emulation of "ld {a,r|r,a}" takes this into account. |
+ | function. The emulation of `ld {a,r|r,a}` takes this into account. |
'=====================================================================*/
R7 = R;
@@ -2104,10 +2112,11 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
/*----------------------------------------------------------------.
| The CPU is halted. In order to avoid affecting the speed of the |
| main execution loop, this state is executed by a dedicated loop |
- | within the function that emulates the "halt" instruction. |
+ | within the function that emulates the `halt` instruction. |
'================================================================*/
case Z80_RESUME_HALT:
- (void)halt(self);
+ if (REQUEST) RESUME = FALSE;
+ else (void)halt(self);
break;
/*--------------------------------------------------------------------.
@@ -2133,58 +2142,12 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
RESUME = FALSE;
goto im0_begin;
# endif
-
-# ifdef Z80_WITH_SPECIAL_RESET_SIGNAL
- case Z80_RESUME_SPECIAL_RESET_XY:
- RESUME = FALSE;
- goto special_reset_execute;
-
- case Z80_RESUME_SPECIAL_RESET_NOP:
- RESUME = FALSE;
- goto special_reset_nop;
-# endif
}
while (self->cycles < cycles) /* Main execution loop. */
{
if (REQUEST)
{
- /*-------------------------------------------------------------------------.
- | Normal RESET Response | T-states: 3 |
- |--------------------------------------------------------------------------|
- | The normal RESET clears PC, I, and R [1,2,3,4,5], resets the interrupt |
- | enable flip-flops (IFF1 and IFF2) [1,2,4,5] and sets the interrupt mode |
- | 0 [1,2,5]. Once /RESET goes inactive, the CPU consumes 3 T-states before |
- | resuming normal processing operation at address 0000h [2,4,6,7]. |
- | |
- | References: |
- | 1. Zilog (2016-09). "Z80 CPU User Manual" revision 11. p. 6. |
- | 2. Flammenkamp, Achim. "Interrupt Behaviour of the Z80 CPU". |
- | * http://z80.info/interrup.htm |
- | 3. https://worldofspectrum.org/forums/discussion/34574 |
- | 4. https://baltazarstudios.com/webshare/Z80-undocumented-behavior.htm |
- | 5. Brewer, Tony (2014-12). "Z80 Special Reset". |
- | * http://primrosebank.net/computers/z80/z80_special_reset.htm |
- | 6. SGS-Thomson (1990-01). "Z80 Microprocessor Family" 1st edition. |
- | p. 40. |
- '=========================================================================*/
-# ifdef Z80_WITH_RESET_SIGNAL
- if (REQUEST & Z80_REQUEST_RESET)
- {
- if (HALT_LINE) {EXIT_HALT_STATE;}
-
- reset:
- self->cycles += (self->reset != Z_NULL)
- ? self->reset(CONTEXT, PC)
- : Z80_CYCLES_PER_RESET;
-
- PC = R = I = IFF1 = IFF2 = IM =
- DATA[0] = HALT_LINE = RESUME = 0;
- REQUEST = Z80_REQUEST_REJECT_NMI;
- continue;
- }
-# endif
-
/*-------------------------------------------------------------------------.
| NMI Acknowledge/Response | T-states: 11:533 |
|--------------------------------------------------------------------------|
@@ -2194,7 +2157,7 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
| NMI by storing PC on the stack and jumping to the ISR located at address |
| 0066h. The interrupt enable flip-flop 1 (IFF1) is reset to prevent any |
| INT from being accepted during the execution of this routine, which is |
- | usually exited by using a "reti" or "retn" instruction to restore the |
+ | usually exited by using a `reti` or `retn` instruction to restore the |
| original state of IFF1. |
| |
| Some technical documents from Zilog include an erroneous timing diagram |
@@ -2211,48 +2174,34 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
| * https://github.com/floooh/v6502r |
'=========================================================================*/
if (REQUEST & Z80_REQUEST_REJECT_NMI)
-# ifdef Z80_WITH_SPECIAL_RESET_SIGNAL
- REQUEST &= ~(zuint8)Z80_REQUEST_REJECT_NMI;
+# ifdef Z80_WITH_SPECIAL_RESET
+ REQUEST &= Z80_REQUEST_SPECIAL_RESET;
# else
REQUEST = 0;
# endif
else if (REQUEST & Z80_REQUEST_NMI)
{
+# ifdef Z80_WITH_SPECIAL_RESET
+ zuint8 special_reset = REQUEST & Z80_REQUEST_SPECIAL_RESET;
+# endif
+
IFF1 = 0;
-
- if (HALT_LINE)
- {
- HALT_LINE = FALSE;
-
- if (self->halt != Z_NULL)
- {
- self->halt(CONTEXT, FALSE);
-
-# ifdef Z80_WITH_RESET_SIGNAL
- if (REQUEST & Z80_REQUEST_RESET) goto reset;
-# endif
- }
- }
-
+ if (HALT_LINE) {SET_HALT_LINE(FALSE);}
R++; /* M1 */
if (self->nmia != Z_NULL) (void)self->nmia(CONTEXT, PC);
-# ifdef Z80_WITH_SPECIAL_RESET_SIGNAL
- PC >>= REQUEST & Z80_REQUEST_CLEAR_PC;
- REQUEST = (REQUEST & (Z80_REQUEST_ANY_RESET | Z80_REQUEST_NMI)) >> 1;
+# ifdef Z80_WITH_SPECIAL_RESET
+ PC >>= special_reset;
+ REQUEST = Z80_REQUEST_REJECT_NMI | (REQUEST & Z80_REQUEST_SPECIAL_RESET);
# else
- REQUEST =
-# ifdef Z80_WITH_RESET_SIGNAL
- (REQUEST & Z80_REQUEST_RESET) |
-# endif
- Z80_REQUEST_REJECT_NMI;
+ REQUEST = Z80_REQUEST_REJECT_NMI;
# endif
DATA[0] = 0;
Q_0
PUSH(PC);
- MEMPTR = PC = 0x66;
+ PC = MEMPTR = 0x66;
self->cycles += 11;
continue;
}
@@ -2260,21 +2209,21 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
/*-------------------------------------------------------------------------.
| INT Acknowledge/Response |
|--------------------------------------------------------------------------|
- | The maskable interrupt can be enabled and disabled by using the "ei" and |
- | "di" instructions respectively, which control the state of the interrupt |
+ | The maskable interrupt can be enabled and disabled by using the `ei` and |
+ | `di` instructions respectively, which control the state of the interrupt |
| enable flip-flops (IFF1 and IFF2). The CPU does not accept this kind of |
- | interrupt directly after an "ei" instruction, but only after the one |
- | following "ei" is executed. This is so that ISRs can return without the |
+ | interrupt directly after an `ei` instruction, but only after the one |
+ | following `ei` is executed. This is so that ISRs can return without the |
| danger of being interrupted immediately after re-enabling interrupts if |
| the /INT line is still active, which could cause a stack overflow. |
'=========================================================================*/
else if (
-# ifdef Z80_WITH_SPECIAL_RESET_SIGNAL
+# ifdef Z80_WITH_SPECIAL_RESET
(REQUEST & Z80_REQUEST_INT) &&
# endif
- /* if the previous instruction is not "ei" */
+ /* if the previous instruction is not `ei` */
DATA[0] != 0xFB &&
- /* if the previous instruction is not "reti/retn" or IFF1 has not changed */
+ /* if the previous instruction is not `reti/retn` or IFF1 has not changed */
(self->data.uint32_value & Z_UINT32_BIG_ENDIAN(Z_UINT32(0xFFC7FF00)))
!= Z_UINT32_BIG_ENDIAN(Z_UINT32(0xED450000))
)
@@ -2283,27 +2232,19 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
Z80Read hook;
IM0 im0;
# endif
+
+# ifdef Z80_WITH_SPECIAL_RESET
+ zuint8 special_reset = REQUEST & Z80_REQUEST_SPECIAL_RESET;
+# endif
+
zuint8 byte;
IFF1 = IFF2 = 0;
-
- if (HALT_LINE)
- {
- HALT_LINE = FALSE;
-
- if (self->halt != Z_NULL)
- {
- self->halt(CONTEXT, FALSE);
-
-# ifdef Z80_WITH_RESET_SIGNAL
- if (REQUEST & Z80_REQUEST_RESET) goto reset;
-# endif
- }
- }
+ if (HALT_LINE) {SET_HALT_LINE(FALSE);}
/*-----------------------------------------------------.
| Due to a bug, the Zilog Z80 NMOS resets PF if an INT |
- | is accepted during the execution of "ld a,{i|r}". |
+ | is accepted during the execution of `ld a,{i|r}`. |
'=====================================================*/
# ifdef Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG
if (
@@ -2321,22 +2262,18 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
| interrupt response data. The first and perhaps only byte of this data |
| is read from the data bus during this special M1 cycle. |
| |
- | The value FFh is assumed when the "inta" callback is not used. This |
- | is the most desirable behavior, since the "rst 38h" instruction will |
+ | The value FFh is assumed when the `inta` callback is not used. This |
+ | is the most desirable behavior, since the `rst 38h` instruction will |
| be executed if the interrupt mode is 0. |
'======================================================================*/
R++; /* M1 */
byte = (self->inta != Z_NULL) ? INTA : 0xFF;
-# ifdef Z80_WITH_SPECIAL_RESET_SIGNAL
- PC >>= REQUEST & Z80_REQUEST_CLEAR_PC;
- REQUEST = (REQUEST & Z80_REQUEST_NMI) | ((REQUEST & Z80_REQUEST_ANY_RESET) >> 1);
+# ifdef Z80_WITH_SPECIAL_RESET
+ PC >>= special_reset;
+ REQUEST &= Z80_REQUEST_NMI | Z80_REQUEST_SPECIAL_RESET;
# else
- REQUEST &=
-# ifdef Z80_WITH_RESET_SIGNAL
- Z80_REQUEST_RESET |
-# endif
- Z80_REQUEST_NMI;
+ REQUEST &= Z80_REQUEST_NMI;
# endif
switch (IM) /* Response */
@@ -2526,7 +2463,7 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
self->cycles += 2 + 17;
continue;
- /* "rst N" is assumed for other instructions */
+ /* `rst N` is assumed for other instructions */
default:
Q_0
PUSH(PC);
@@ -2537,9 +2474,9 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
# endif
/*----------------------------------------------------------.
- | Interrupt Mode 1: Execute "rst 38h" | T-states: 13:733 |
+ | Interrupt Mode 1: Execute `rst 38h` | T-states: 13:733 |
|-----------------------------------------------------------|
- | An internal "rst 38h" is executed. The interrupt response |
+ | An internal `rst 38h` is executed. The interrupt response |
| data read from the data bus is disregarded. |
'==========================================================*/
case 1:
@@ -2551,7 +2488,7 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
continue;
/*---------------------------------------------------------------------.
- | Interrupt Mode 2: Execute "call (i:BYTE)" | T-states: 19:73333 |
+ | Interrupt Mode 2: Execute `call (i:BYTE)` | T-states: 19:73333 |
|----------------------------------------------------------------------|
| An indirect call is executed. The pointer to the ISR is loaded from |
| the memory address formed by taking the I register as the most |
@@ -2593,22 +2530,34 @@ Z80_API zusize z80_run(Z80 *self, zusize cycles)
| * US Patent 4486827 |
| * https://worldofspectrum.org/forums/discussion/34574 |
'======================================================================*/
-# ifdef Z80_WITH_SPECIAL_RESET_SIGNAL
- if (REQUEST & Z80_REQUEST_CLEAR_PC)
- {
- if (self->nop != Z_NULL) (void)self->nop(CONTEXT, PC);
- PC = 0;
- }
-
+# ifdef Z80_WITH_SPECIAL_RESET
if (REQUEST & Z80_REQUEST_SPECIAL_RESET)
{
if (HALT_LINE)
{
- zuint8 opcode = DATA[0] = FETCH_OPCODE(PC);
- if (self->halt != Z_NULL) self->halt(CONTEXT, FALSE);
+ zuint8 opcode;
+
+ R++; /* M1 */
+ opcode = DATA[0] = FETCH_OPCODE(PC);
+ SET_HALT_LINE(FALSE);
PC--;
- self->cycles += instruction_table[opcode]();
+ self->cycles += instruction_table[opcode](self);
}
+
+ else {
+ if (DATA[0] == 0x76)
+ {
+ SET_HALT_LINE(TRUE);
+ SET_HALT_LINE(FALSE);
+ }
+
+ R++; /* M1 */
+ if (self->nop != Z_NULL) (void)self->nop(CONTEXT, PC);
+ DATA[0] = 0;
+ PC = 0;
+ }
+
+ continue;
}
# endif
}
diff --git a/sources/test-Z80.c b/sources/test-Z80.c
index 2743263..b7434e0 100644
--- a/sources/test-Z80.c
+++ b/sources/test-Z80.c
@@ -817,7 +817,6 @@ int main(int argc, char **argv)
cpu.nmia =
cpu.inta =
cpu.int_fetch = Z_NULL;
- cpu.reset = Z_NULL;
cpu.ld_i_a =
cpu.ld_r_a =
cpu.reti =