Special RESET WIP; Removed the normal RESET signal; Documentation/comments; Other improvements.
This commit is contained in:
6
.github/workflows/library-ci.yml
vendored
6
.github/workflows/library-ci.yml
vendored
@@ -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}}
|
||||
|
||||
|
||||
66
API/Z80.h
66
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 <tt>ld i,a</tt> 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 <tt>ld i,a</tt> 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 <tt>ld r,a</tt> 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 <tt>ld r,a</tt> 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
|
||||
|
||||
@@ -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)
|
||||
|
||||
50
HISTORY
50
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)
|
||||
|
||||
14
README
14
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
Last update: 2022-07-03 README EOF
|
||||
Last update: 2022-07-16 README EOF
|
||||
|
||||
12
README.md
12
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`.
|
||||
|
||||
* <span id="option_z80_with_reset_signal">**`-DZ80_WITH_RESET_SIGNAL=(YES|NO)`**</span>
|
||||
Build the implementation of the normal RESET signal.
|
||||
The default is `NO`.
|
||||
|
||||
* <span id="option_z80_with_special_reset_signal">**`-DZ80_WITH_SPECIAL_RESET_SIGNAL=(YES|NO)`**</span>
|
||||
Build the implementation of the [special RESET](http://www.primrosebank.net/computers/z80/z80_special_reset.htm) signal.
|
||||
* <span id="option_z80_with_special_reset">**`-DZ80_WITH_SPECIAL_RESET=(YES|NO)`**</span>
|
||||
Build the implementation of the [special RESET](http://www.primrosebank.net/computers/z80/z80_special_reset.htm).
|
||||
The default is `NO`.
|
||||
|
||||
* <span id="option_z80_with_unofficial_reti">**`-DZ80_WITH_UNOFFICIAL_RETI=(YES|NO)`**</span>
|
||||
@@ -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)**
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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" <https://worldofspectrum.org/forums/discussion/41704>`_. |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 <http://www.primrosebank.net/computers/z80/z80_special_reset.htm>`_ signal. |br| |nl|
|
||||
Build the implementation of the `special RESET <http://www.primrosebank.net/computers/z80/z80_special_reset.htm>`_. |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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
=================
|
||||
|
||||
265
sources/Z80.c
265
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
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
Reference in New Issue
Block a user