text: /*
   Z80 emulator code derived from Lin Ke-Fong source. Copyright says:
  
   Copyright (c) 2016, 2017 Lin Ke-Fong
  
   This code is free, do whatever you want with it.
  
   2020 adapted by Fabrizio Di Vittorio for fabgl ESP32 library
   */
  
  
  #pragma once
  
  
  #include <stdint.h>
  
  
  
  
  
  
  /* Define this macro if the host processor is big endian. */
  
  /* #define Z80_BIG_ENDIAN */
  
  /* Emulation can be speed up a little bit by emulating only the documented
   * flags.
   */
  
  /* #define Z80_DOCUMENTED_FLAGS_ONLY */
  
  /* HALT, DI, EI, RETI, and RETN instructions can be catched. When such an
   * instruction is catched, the emulator is stopped and the PC register points
   * at the opcode to be executed next. The catched instruction can be determined
   * from the Z80_STATE's status value. Keep in mind that no interrupt can be
   * accepted at the instruction right after a DI or EI on an actual processor.
   */
  
  /*
   #define Z80_CATCH_HALT
   #define Z80_CATCH_DI
   #define Z80_CATCH_EI
   #define Z80_CATCH_RETI
   #define Z80_CATCH_RETN
   */
  
  /* Undefined 0xed prefixed opcodes may be catched, otherwise they are treated
   * like NOP instructions. When one is catched, Z80_STATUS_ED_UNDEFINED is set
   * in Z80_STATE's status member and the PC register points at the 0xed prefix
   * before the undefined opcode.
   */
  
  /* #define Z80_CATCH_ED_UNDEFINED */
  
  /* The emulator cannot be stopped between prefixed opcodes. This can be a
   * problem if there is a long sequence of 0xdd and/or 0xfd prefixes. But if
   * Z80_PREFIX_FAILSAFE is defined, it will always be able to stop after at
   * least numbers_cycles are executed, in which case Z80_STATE's status is set
   * to Z80_STATUS_PREFIX. Note that if the memory where the opcodes are read,
   * has wait states (slow memory), then the additional cycles for a one byte
   * fetch (the non executed prefix) must be substracted. Even if it is safer,
   * most program won't need this feature.
   */
  
  /* #define Z80_PREFIX_FAILSAFE */
  
  /* By defining this macro, the emulator will always fetch the displacement or
   * address of a conditionnal jump or call instruction, even if the condition
   * is false and the fetch can be avoided. Define this macro if you need to
   * account for memory wait states on code read.
   */
  
  /* #define Z80_FALSE_CONDITION_FETCH */
  
  /* It may be possible to overwrite the opcode of the currently executing LDIR,
   * LDDR, INIR, or OTDR instruction. Define this macro if you need to handle
   * these pathological cases.
   */
  
  /* #define Z80_HANDLE_SELF_MODIFYING_CODE */
  
  /* For interrupt mode 2, bit 0 of the 16-bit address to the interrupt vector
   * can be masked to zero. Some documentation states that this bit is forced to
   * zero. For instance, Zilog's application note about interrupts, states that
   * "only 7 bits are required" and "the least significant bit is zero". Yet,
   * this is quite unclear, even from Zilog's manuals. So this is left as an
   * option.
   */
  
  /* #define Z80_MASK_IM2_VECTOR_ADDRESS */
  
  
  
  
  
  
  /* If Z80_STATE's status is non-zero, the emulation has been stopped for some
   * reason other than emulating the requested number of cycles.
   */
  
  enum {
  
    Z80_STATUS_HALT = 1,
    Z80_STATUS_DI,
    Z80_STATUS_EI,
    Z80_STATUS_RETI,
    Z80_STATUS_RETN,
    Z80_STATUS_ED_UNDEFINED,
    Z80_STATUS_PREFIX
  
  };
  
  
  
  /* The main registers are stored inside Z80_STATE as an union of arrays named
   * registers. They are referenced using indexes. Words are stored in the
   * endianness of the host processor. The alternate set of word registers AF',
   * BC', DE', and HL' is stored in the alternates member of Z80_STATE, as an
   * array using the same ordering.
   */
  
  #ifdef Z80_BIG_ENDIAN
  
  #       define Z80_B            0
  #       define Z80_C            1
  #       define Z80_D            2
  #       define Z80_E            3
  #       define Z80_H            4
  #       define Z80_L            5
  #       define Z80_A            6
  #       define Z80_F            7
  
  #       define Z80_IXH          8
  #       define Z80_IXL          9
  #       define Z80_IYH          10
  #       define Z80_IYL          11
  
  #else
  
  #       define Z80_B            1
  #       define Z80_C            0
  #       define Z80_D            3
  #       define Z80_E            2
  #       define Z80_H            5
  #       define Z80_L            4
  #       define Z80_A            7
  #       define Z80_F            6
  
  #       define Z80_IXH          9
  #       define Z80_IXL          8
  #       define Z80_IYH          11
  #       define Z80_IYL          10
  
  #endif
  
  #define Z80_BC                  0
  #define Z80_DE                  1
  #define Z80_HL                  2
  #define Z80_AF                  3
  
  #define Z80_IX                  4
  #define Z80_IY                  5
  #define Z80_SP                  6
  
  
  
  /* Z80's flags. */
  
  #define Z80_S_FLAG_SHIFT        7
  #define Z80_Z_FLAG_SHIFT        6
  #define Z80_Y_FLAG_SHIFT        5
  #define Z80_H_FLAG_SHIFT        4
  #define Z80_X_FLAG_SHIFT        3
  #define Z80_PV_FLAG_SHIFT       2
  #define Z80_N_FLAG_SHIFT        1
  #define Z80_C_FLAG_SHIFT        0
  
  #define Z80_S_FLAG              (1 << Z80_S_FLAG_SHIFT)
  #define Z80_Z_FLAG              (1 << Z80_Z_FLAG_SHIFT)
  #define Z80_Y_FLAG              (1 << Z80_Y_FLAG_SHIFT)
  #define Z80_H_FLAG              (1 << Z80_H_FLAG_SHIFT)
  #define Z80_X_FLAG              (1 << Z80_X_FLAG_SHIFT)
  #define Z80_PV_FLAG             (1 << Z80_PV_FLAG_SHIFT)
  #define Z80_N_FLAG              (1 << Z80_N_FLAG_SHIFT)
  #define Z80_C_FLAG              (1 << Z80_C_FLAG_SHIFT)
  
  #define Z80_P_FLAG_SHIFT        Z80_PV_FLAG_SHIFT
  #define Z80_V_FLAG_SHIFT        Z80_PV_FLAG_SHIFT
  #define Z80_P_FLAG              Z80_PV_FLAG
  #define Z80_V_FLAG              Z80_PV_FLAG
  
  
  
  /* Z80's three interrupt modes. */
  
  enum {
    Z80_INTERRUPT_MODE_0,
    Z80_INTERRUPT_MODE_1,
    Z80_INTERRUPT_MODE_2
  };
  
  
  
  struct Z80_STATE {
    int               status;
  
    union {
      unsigned char   byte[14];
      unsigned short  word[7];
    } registers;
  
    unsigned short    alternates[4];
  
    int               i, r, pc, iff1, iff2, im;
  
    /* Register decoding tables. */
  
    void              * register_table[16];
    void              * dd_register_table[16];
    void              * fd_register_table[16];
  };
  
  
  
  // RAM and IO interface
  
  struct Z80Interface {
    virtual uint8_t readByte(uint16_t addr) = 0;
    virtual void writeByte(uint16_t addr, uint8_t value) = 0;
    virtual uint16_t readWord(uint16_t addr) = 0;
    virtual void writeWord(uint16_t addr, uint16_t value) = 0;
    virtual uint8_t readIO(uint16_t addr) = 0;
    virtual void writeIO(uint16_t addr, uint8_t value) = 0;
  };
  
  
  
  
  class Z80 {
  
  public:
  
    Z80(Z80Interface * interface_) : interface(interface_) { reset(); }
  
    /* Initialize processor's state to power-on default. */
    void reset();
  
    /* Trigger an interrupt according to the current interrupt mode and return the
    * number of cycles elapsed to accept it. If maskable interrupts are disabled,
    * this will return zero. In interrupt mode 0, data_on_bus must be a single
    * byte opcode.
    */
    int interrupt(int data_on_bus);
  
    /* Trigger a non maskable interrupt, then return the number of cycles elapsed
     * to accept it.
     */
    int nonMaskableInterrupt();
  
    /* Execute instructions as long as the number of elapsed cycles is smaller than
     * number_cycles, and return the number of cycles emulated. The emulator can be
     * set to stop early on some conditions. The user macros also control the emulation.
     */
    int emulate(int number_cycles);
  
  
    // CPU registers access
  
    uint8_t readRegByte(int reg)                { return state.registers.byte[reg]; }
    void writeRegByte(int reg, uint8_t value)   { state.registers.byte[reg] = value; }
  
    uint16_t readRegWord(int reg)               { return state.registers.word[reg]; }
    void writeRegWord(int reg, uint16_t value)  { state.registers.word[reg] = value; }
  
    uint16_t getPC()                            { return state.pc; }
    void setPC(uint16_t value)                  { state.pc = value; }
  
  
  private:
  
    int intemulate(int opcode, int elapsed_cycles, int number_cycles);
  
    Z80_STATE      state;
    Z80Interface * interface;
  
  };
  
  
  
  
  
  
  
  
  
  
  
  
  
  