Upgrade to Pro — share decks privately, control downloads, hide ads and more …

続CPUとは何か / What is a CPU continued

続CPUとは何か / What is a CPU continued

Z80ハードウェアエミュレータを通して「CPUとは何か」を語るトークの資料です

PHP Conference Japan 2022
続CPUとは何か - ハードウェアエミュレータから見たCPU
https://fortee.jp/phpcon-2022/proposal/c184ec3f-27dd-4e2c-a51c-6b7608b46d2a

以下のトークの続編です
PHP Conference Japan 2019
「CPUとは何か」をPHPで考える
https://fortee.jp/phpcon-2019/speaker/proposal/view/621ab238-115c-4fdc-8d43-0e9a67e188d5

HASEGAWA Tomoki

September 24, 2022
Tweet

More Decks by HASEGAWA Tomoki

Other Decks in Technology

Transcript

  1. 長谷川智希 @tomzoh
    2022/09/24 PHP Conference Japan 2022
    続CPUとは何か
    ハードウェアエミュレータから見たCPU

    View full-size slide

  2. 2
    ௕୩઒ஐر
    ͸͕ͤΘ ͱ΋͖
    @tomzoh
    http://www.dgcircus.com
    デジタルサーカス株式会社 副団長CTO
    ॴଐ ٕज़ΧϯϑΝϨϯεओ࠻
    دߘɾஶॻ
    来たれ!PHPer!We are hiring!

    View full-size slide

  3. 2
    ௕୩઒ஐر
    ͸͕ͤΘ ͱ΋͖
    @tomzoh
    http://www.dgcircus.com
    デジタルサーカス株式会社 副団長CTO
    ॴଐ ٕज़ΧϯϑΝϨϯεओ࠻
    دߘɾஶॻ
    来たれ!PHPer!We are hiring!
    4PGUXBSF%FTJHO೥݄߸
    ʮ$16ͱ͸ԿͩΖ͏͔ʯ

    View full-size slide

  4. 3
    ௕୩઒ஐر
    ͸͕ͤΘ ͱ΋͖
    @tomzoh
    ςοΫΧϯϑΝϨϯεӡӦࢀՃ 8FCJ04ΞϓϦ։ൃ
    $16 ϨτϩήʔϜػ ిࢠ޻࡞ Ϗʔϧ
    αοΧʔ؍ઓ ϨϯλϧΧʔτϨʔε ʜ
    ϥΠϑϫʔΫ

    View full-size slide

  5. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU 4
    続CPUとは何か
    ハードウェアエミュレータから見たCPU

    View full-size slide

  6. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    前回までのあらすじ
    PHP Conference Japan 2019
    • 「CPUとは何か」をPHPで考える


    • CPUを3つの視点で見た


    • プログラム実行環境


    • エミュレート対象


    • 電気回路
    5

    View full-size slide

  7. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 1: プログラム実行環境
    6

    View full-size slide

  8. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 1: プログラム実行環境
    • 対象CPUで動くプログラムを書く
    6

    View full-size slide

  9. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 1: プログラム実行環境
    • 対象CPUで動くプログラムを書く
    • CPUをプログラム実行環境として見ると:
    6

    View full-size slide

  10. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 1: プログラム実行環境
    • 対象CPUで動くプログラムを書く
    • CPUをプログラム実行環境として見ると:
    • CPUはプログラム言語の様に見える
    6

    View full-size slide

  11. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 1: プログラム実行環境
    • 対象CPUで動くプログラムを書く
    • CPUをプログラム実行環境として見ると:
    • CPUはプログラム言語の様に見える
    • CPUの命令セットを理解し、プログラムを書く
    6

    View full-size slide

  12. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 2: エミュレート対象
    7

    View full-size slide

  13. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 2: エミュレート対象
    • 対象CPUのエミュレータを作る
    7

    View full-size slide

  14. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 2: エミュレート対象
    • 対象CPUのエミュレータを作る
    • CPUをエミュレート対象として見ると:
    7

    View full-size slide

  15. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 2: エミュレート対象
    • 対象CPUのエミュレータを作る
    • CPUをエミュレート対象として見ると:
    • 他人の書いたプログラムを受け入れる存在に見える
    7

    View full-size slide

  16. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 2: エミュレート対象
    • 対象CPUのエミュレータを作る
    • CPUをエミュレート対象として見ると:
    • 他人の書いたプログラムを受け入れる存在に見える
    • CPUエミュレータと外部との境界は曖昧
    7

    View full-size slide

  17. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 2: エミュレート対象
    • 対象CPUのエミュレータを作る
    • CPUをエミュレート対象として見ると:
    • 他人の書いたプログラムを受け入れる存在に見える
    • CPUエミュレータと外部との境界は曖昧
    • CPUエミュレータ単体でなくコンピュータのエミュレータの中の1コンポーネントとして

    実装される / グラフィックやサウンド、入出力との境界は曖昧
    7

    View full-size slide

  18. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 2: エミュレート対象
    • 対象CPUのエミュレータを作る
    • CPUをエミュレート対象として見ると:
    • 他人の書いたプログラムを受け入れる存在に見える
    • CPUエミュレータと外部との境界は曖昧
    • CPUエミュレータ単体でなくコンピュータのエミュレータの中の1コンポーネントとして

    実装される / グラフィックやサウンド、入出力との境界は曖昧
    • Hardware speci
    fi
    cation as Code
    7

    View full-size slide

  19. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 2: エミュレート対象
    • 対象CPUのエミュレータを作る
    • CPUをエミュレート対象として見ると:
    • 他人の書いたプログラムを受け入れる存在に見える
    • CPUエミュレータと外部との境界は曖昧
    • CPUエミュレータ単体でなくコンピュータのエミュレータの中の1コンポーネントとして

    実装される / グラフィックやサウンド、入出力との境界は曖昧
    • Hardware speci
    fi
    cation as Code
    • エミュレータのソースを読むとハードウェアの仕様がわかる
    7

    View full-size slide

  20. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 2: エミュレート対象
    • 対象CPUのエミュレータを作る
    • CPUをエミュレート対象として見ると:
    • 他人の書いたプログラムを受け入れる存在に見える
    • CPUエミュレータと外部との境界は曖昧
    • CPUエミュレータ単体でなくコンピュータのエミュレータの中の1コンポーネントとして

    実装される / グラフィックやサウンド、入出力との境界は曖昧
    • Hardware speci
    fi
    cation as Code
    • エミュレータのソースを読むとハードウェアの仕様がわかる
    • Undocumentedな仕様もエミュレータのソースには書いてある
    7

    View full-size slide

  21. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 3: 電気回路
    8

    View full-size slide

  22. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 3: 電気回路
    • 対象CPUを電気回路として作る
    8

    View full-size slide

  23. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 3: 電気回路
    • 対象CPUを電気回路として作る
    • CPUを電気回路として見ると:
    8

    View full-size slide

  24. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 3: 電気回路
    • 対象CPUを電気回路として作る
    • CPUを電気回路として見ると:
    • 外部から供給されるクロックによって内部状態が切り替わる状態装置に見える
    8

    View full-size slide

  25. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 3: 電気回路
    • 対象CPUを電気回路として作る
    • CPUを電気回路として見ると:
    • 外部から供給されるクロックによって内部状態が切り替わる状態装置に見える
    • クロック: 心臓の鼓動
    8

    View full-size slide

  26. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 3: 電気回路
    • 対象CPUを電気回路として作る
    • CPUを電気回路として見ると:
    • 外部から供給されるクロックによって内部状態が切り替わる状態装置に見える
    • クロック: 心臓の鼓動
    • クロック ➡ CPUの状態変化
    8

    View full-size slide

  27. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 3: 電気回路
    • 対象CPUを電気回路として作る
    • CPUを電気回路として見ると:
    • 外部から供給されるクロックによって内部状態が切り替わる状態装置に見える
    • クロック: 心臓の鼓動
    • クロック ➡ CPUの状態変化
    • PC(プログラムカウンタ)が示すメモリアドレスから命令をフェッチする(読み込む)
    8

    View full-size slide

  28. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 3: 電気回路
    • 対象CPUを電気回路として作る
    • CPUを電気回路として見ると:
    • 外部から供給されるクロックによって内部状態が切り替わる状態装置に見える
    • クロック: 心臓の鼓動
    • クロック ➡ CPUの状態変化
    • PC(プログラムカウンタ)が示すメモリアドレスから命令をフェッチする(読み込む)
    • フェッチした内容によってデータフロー・演算器のモードが決定される
    8

    View full-size slide

  29. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 3: 電気回路
    • 対象CPUを電気回路として作る
    • CPUを電気回路として見ると:
    • 外部から供給されるクロックによって内部状態が切り替わる状態装置に見える
    • クロック: 心臓の鼓動
    • クロック ➡ CPUの状態変化
    • PC(プログラムカウンタ)が示すメモリアドレスから命令をフェッチする(読み込む)
    • フェッチした内容によってデータフロー・演算器のモードが決定される
    • 演算器の出力がレジスタやメモリに格納される
    8

    View full-size slide

  30. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU 3つの視点 - 3: 電気回路
    • 対象CPUを電気回路として作る
    • CPUを電気回路として見ると:
    • 外部から供給されるクロックによって内部状態が切り替わる状態装置に見える
    • クロック: 心臓の鼓動
    • クロック ➡ CPUの状態変化
    • PC(プログラムカウンタ)が示すメモリアドレスから命令をフェッチする(読み込む)
    • フェッチした内容によってデータフロー・演算器のモードが決定される
    • 演算器の出力がレジスタやメモリに格納される
    • プログラム実行環境, エミュレータの様な1本の流れとしての実行ではなく

    複数の回路が同時に切り替わる形での実行
    8

    View full-size slide

  31. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    今回のおはなし
    PHP Conference Japan 2022
    9

    View full-size slide

  32. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    今回のおはなし
    PHP Conference Japan 2022
    9

    View full-size slide

  33. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    今回のおはなし
    PHP Conference Japan 2022
    • 4つ目の視点
    9

    View full-size slide

  34. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    今回のおはなし
    PHP Conference Japan 2022
    • 4つ目の視点
    • ハードウェアエミュレータから見たCPU
    9

    View full-size slide

  35. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    今回のおはなし
    PHP Conference Japan 2022
    • 4つ目の視点
    • ハードウェアエミュレータから見たCPU
    • コンピュータのCPUのフリをする

    ハードウェア
    9

    View full-size slide

  36. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    今回のおはなし
    PHP Conference Japan 2022
    • 4つ目の視点
    • ハードウェアエミュレータから見たCPU
    • コンピュータのCPUのフリをする

    ハードウェア
    • ハードウェアエミュレータを作るとCPU
    がどう見えるか
    9

    View full-size slide

  37. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80のハードウェアエミュレータ
    10
    今回作ったもの

    View full-size slide

  38. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Zilog Z80
    11

    View full-size slide

  39. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Zilog Z80
    • 1976年に米国ザイログ社より発表 現在も製造されている


    • PC-8801(1981-1989), X1(1982-1988), MSX(1983-1990)


    • セガ・マークIII(1985), セガ・マスターシステム(1987), メガドライブ(サブ・1988), ゲ
    ームボーイ(1989), ゲームギア(1990), ネオジオ(サブ・1991)


    • ギャラクシアン(1979), パックマン(1980), ディグダグ(1982), ゼビウス(1983),
    1942(1984), 戦場の狼(1985), 魔界村(サウンド・1985), ファイナルファイト(サウンド・
    1989), ストリートファイターII(サウンド・1991), …


    • 競合: MC6809(モトローラ), MOS 6502(モステクノロジー)
    12

    View full-size slide

  40. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU 13
    https://ja.wikipedia.org/wiki/パチンコ
    https://ja.wikipedia.org/wiki/パチスロ
    https://www.msx.org/wiki/Sony_HB-F1XDJ https://ja.wikipedia.org/wiki/PC-8800シリーズ

    View full-size slide

  41. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 シングルボードコンピュータ SBCZ80
    14

    View full-size slide

  42. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ
    15

    View full-size slide

  43. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ
    • Z80で動いているシステムからZ80を抜いて

    自作のハードウェアを挿入して動作させる
    15

    View full-size slide

  44. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ
    • Z80で動いているシステムからZ80を抜いて

    自作のハードウェアを挿入して動作させる
    15

    View full-size slide

  45. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ
    • Z80で動いているシステムからZ80を抜いて

    自作のハードウェアを挿入して動作させる
    15
    Z80を抜く

    View full-size slide

  46. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ
    • Z80で動いているシステムからZ80を抜いて

    自作のハードウェアを挿入して動作させる
    15
    Z80を抜く

    View full-size slide

  47. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ
    • Z80で動いているシステムからZ80を抜いて

    自作のハードウェアを挿入して動作させる
    15
    Z80を抜く
    自作ハードウェアを


    挿入して動作させる

    View full-size slide

  48. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80
    Z80 ハードウェアエミュレータのレイヤ構造
    16
    Z80コンピュータ (SBCZ80)
    ΞυϨεόε σʔλόε ੍ޚ৴߸
    RAM ROM SERIAL


    PORT
    CLOCK

    View full-size slide

  49. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェアエミュレータのレイヤ構造
    16
    Z80コンピュータ (SBCZ80)
    ΞυϨεόε σʔλόε ੍ޚ৴߸
    RAM ROM SERIAL


    PORT
    CLOCK

    View full-size slide

  50. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80ハードウェアエミュレータ
    Raspberry Pi GPIO
    Z80 エミュレータ
    電圧変換 / ラッチ
    Z80 ハードウェアエミュレータのレイヤ構造
    16
    Z80コンピュータ (SBCZ80)
    ΞυϨεόε σʔλόε ੍ޚ৴߸
    RAM ROM SERIAL


    PORT
    CLOCK

    View full-size slide

  51. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80ハードウェアエミュレータ
    Raspberry Pi GPIO
    Z80 エミュレータ
    電圧変換 / ラッチ
    Z80 ハードウェアエミュレータのレイヤ構造
    16
    Z80コンピュータ (SBCZ80)
    ΞυϨεόε σʔλόε ੍ޚ৴߸
    RAM ROM SERIAL


    PORT
    CLOCK
    ソフトウェアエミュレータ

    View full-size slide

  52. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80ハードウェアエミュレータ
    Raspberry Pi GPIO
    Z80 エミュレータ
    電圧変換 / ラッチ
    Z80 ハードウェアエミュレータのレイヤ構造
    16
    Z80コンピュータ (SBCZ80)
    ΞυϨεόε σʔλόε ੍ޚ৴߸
    RAM ROM SERIAL


    PORT
    CLOCK
    物理インターフェース
    ソフトウェアエミュレータ

    View full-size slide

  53. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    物理的インターフェース(I/F)
    17

    View full-size slide

  54. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80の物理I/F
    18

    View full-size slide

  55. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80の物理I/F
    • 40本のピン
    18

    View full-size slide

  56. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80の物理I/F
    • 40本のピン
    • そのうち2本は電源なので38本の信号線
    18

    View full-size slide

  57. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80の物理I/F
    • 40本のピン
    • そのうち2本は電源なので38本の信号線
    • 16本のアドレス信号線(16bit), 8本のデータ信号線(8bit)
    18

    View full-size slide

  58. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80の物理I/F
    • 40本のピン
    • そのうち2本は電源なので38本の信号線
    • 16本のアドレス信号線(16bit), 8本のデータ信号線(8bit)
    • 8本の出力信号線, 6本の入力信号線
    18

    View full-size slide

  59. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80の物理I/F
    • 40本のピン
    • そのうち2本は電源なので38本の信号線
    • 16本のアドレス信号線(16bit), 8本のデータ信号線(8bit)
    • 8本の出力信号線, 6本の入力信号線
    • 38本の信号線の0/1(電圧)をエミュレートすれば良い
    18

    View full-size slide

  60. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi の物理I/F
    19

    View full-size slide

  61. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi の物理I/F
    • Raspberry Pi は Linux が動作する ARM CPU 搭載のコンピュータ
    19

    View full-size slide

  62. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi の物理I/F
    • Raspberry Pi は Linux が動作する ARM CPU 搭載のコンピュータ
    19
    https://ja.wikipedia.org/wiki/Raspberry_Pi

    View full-size slide

  63. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi の物理I/F
    • Raspberry Pi は Linux が動作する ARM CPU 搭載のコンピュータ
    • ソフトウェアで入出力できるGPIOを28本持つ
    19
    https://ja.wikipedia.org/wiki/Raspberry_Pi

    View full-size slide

  64. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi の物理I/F
    • Raspberry Pi は Linux が動作する ARM CPU 搭載のコンピュータ
    • ソフトウェアで入出力できるGPIOを28本持つ
    19
    https://ja.wikipedia.org/wiki/Raspberry_Pi

    View full-size slide

  65. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi の物理I/F
    • Raspberry Pi は Linux が動作する ARM CPU 搭載のコンピュータ
    • ソフトウェアで入出力できるGPIOを28本持つ
    • 制御はC, Pythonがラク
    19
    https://ja.wikipedia.org/wiki/Raspberry_Pi

    View full-size slide

  66. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi の物理I/F
    • Raspberry Pi は Linux が動作する ARM CPU 搭載のコンピュータ
    • ソフトウェアで入出力できるGPIOを28本持つ
    • 制御はC, Pythonがラク
    19
    https://ja.wikipedia.org/wiki/Raspberry_Pi
    gpioWrite(0, 1);
    bool value = gpioRead(0);
    C言語

    View full-size slide

  67. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi の物理I/F
    • Raspberry Pi は Linux が動作する ARM CPU 搭載のコンピュータ
    • ソフトウェアで入出力できるGPIOを28本持つ
    • 制御はC, Pythonがラク
    • PHPでもできる (おすすめはしない)
    19
    https://ja.wikipedia.org/wiki/Raspberry_Pi
    gpioWrite(0, 1);
    bool value = gpioRead(0);
    C言語

    View full-size slide

  68. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi と Z80 コンピュータの接続
    20

    View full-size slide

  69. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi と Z80 コンピュータの接続
    • Raspberry Pi が Z80 のフリをするには工夫が必要
    20

    View full-size slide

  70. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi と Z80 コンピュータの接続
    • Raspberry Pi が Z80 のフリをするには工夫が必要
    • Raspberry Pi GPIOは3.3V, Z80は5V
    20

    View full-size slide

  71. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi と Z80 コンピュータの接続
    • Raspberry Pi が Z80 のフリをするには工夫が必要
    • Raspberry Pi GPIOは3.3V, Z80は5V
    • 電圧変換が必要
    20

    View full-size slide

  72. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi と Z80 コンピュータの接続
    • Raspberry Pi が Z80 のフリをするには工夫が必要
    • Raspberry Pi GPIOは3.3V, Z80は5V
    • 電圧変換が必要
    • Raspberry Pi はGPIOを28本持つ, Z80は信号線を38本持つ
    20

    View full-size slide

  73. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi と Z80 コンピュータの接続
    • Raspberry Pi が Z80 のフリをするには工夫が必要
    • Raspberry Pi GPIOは3.3V, Z80は5V
    • 電圧変換が必要
    • Raspberry Pi はGPIOを28本持つ, Z80は信号線を38本持つ
    • 足りない
    20

    View full-size slide

  74. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi と Z80 コンピュータの接続
    • Raspberry Pi が Z80 のフリをするには工夫が必要
    • Raspberry Pi GPIOは3.3V, Z80は5V
    • 電圧変換が必要
    • Raspberry Pi はGPIOを28本持つ, Z80は信号線を38本持つ
    • 足りない
    • 出力信号線はラッチを使って共有する
    20

    View full-size slide

  75. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Raspberry Pi と Z80 コンピュータの接続
    • Raspberry Pi が Z80 のフリをするには工夫が必要
    • Raspberry Pi GPIOは3.3V, Z80は5V
    • 電圧変換が必要
    • Raspberry Pi はGPIOを28本持つ, Z80は信号線を38本持つ
    • 足りない
    • 出力信号線はラッチを使って共有する
    • ラッチ: 入力値を保持する電気回路
    20

    View full-size slide

  76. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    GPIO不足の解消
    21
    Raspberry Pi
    8 x GPIO
    8 x GPIO
    6 x GPIO
    3 x GPIO
    3 x GPIO
    28 x GPIO 38pin IC
    16 x Address
    8 x Data
    Z80
    8 x Control
    6 x Control

    View full-size slide

  77. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    GPIO不足の解消
    21
    Raspberry Pi
    8 x GPIO
    8 x GPIO
    6 x GPIO
    3 x GPIO
    (Z80からの)


    出力
    3 x GPIO
    28 x GPIO 38pin IC
    16 x Address
    8 x Data
    Z80
    8 x Control
    6 x Control

    View full-size slide

  78. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    GPIO不足の解消
    21
    Raspberry Pi
    8 x GPIO
    8 x GPIO
    6 x GPIO
    3 x GPIO
    ラッチ1
    ラッチ2
    ラッチ3
    (Z80からの)


    出力
    3 x GPIO
    28 x GPIO 38pin IC
    16 x Address
    8 x Data
    Z80
    8 x Control
    6 x Control

    View full-size slide

  79. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    GPIO不足の解消
    21
    Raspberry Pi
    8 x GPIO
    8 x GPIO
    6 x GPIO
    3 x GPIO
    ラッチ1
    ラッチ2
    ラッチ3
    (Z80からの)


    出力
    3 x GPIO
    28 x GPIO 38pin IC
    16 x Address
    8 x Data
    Z80
    8 x Control
    6 x Control

    View full-size slide

  80. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    GPIO不足の解消
    21
    Raspberry Pi
    8 x GPIO
    8 x GPIO
    6 x GPIO
    3 x GPIO
    ラッチ1
    ラッチ2
    ラッチ3
    ラッチ


    コントロール
    (Z80からの)


    出力
    3 x GPIO
    28 x GPIO 38pin IC
    16 x Address
    8 x Data
    Z80
    8 x Control
    6 x Control

    View full-size slide

  81. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    5V 3.3V 変換
    双方向
    GPIO不足の解消
    21
    Raspberry Pi
    8 x GPIO
    8 x GPIO
    6 x GPIO
    3 x GPIO
    ラッチ1
    ラッチ2
    ラッチ3
    ラッチ


    コントロール
    (Z80からの)


    出力
    3 x GPIO
    28 x GPIO 38pin IC
    16 x Address
    8 x Data
    Z80
    8 x Control
    6 x Control

    View full-size slide

  82. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    5V 3.3V 変換
    (Z80への)


    入力
    5V 3.3V 変換
    双方向
    GPIO不足の解消
    21
    Raspberry Pi
    8 x GPIO
    8 x GPIO
    6 x GPIO
    3 x GPIO
    ラッチ1
    ラッチ2
    ラッチ3
    ラッチ


    コントロール
    (Z80からの)


    出力
    3 x GPIO
    28 x GPIO 38pin IC
    16 x Address
    8 x Data
    Z80
    8 x Control
    6 x Control

    View full-size slide

  83. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    5V 3.3V 変換
    (Z80への)


    入力
    5V 3.3V 変換
    双方向
    GPIO不足の解消
    21
    Raspberry Pi
    8 x GPIO
    8 x GPIO
    6 x GPIO
    3 x GPIO
    ラッチ1
    ラッチ2
    ラッチ3
    ラッチ


    コントロール
    (Z80からの)


    出力
    3 x GPIO ͋·Γ
    28 x GPIO 38pin IC
    16 x Address
    8 x Data
    Z80
    8 x Control
    6 x Control

    View full-size slide

  84. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアからソフトウェアへ
    22

    View full-size slide

  85. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアからソフトウェアへ
    • Raspberry Pi が(ハードウェア的に)Z80のフリをできる様になった
    22

    View full-size slide

  86. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアからソフトウェアへ
    • Raspberry Pi が(ハードウェア的に)Z80のフリをできる様になった
    • 38本の信号線をソフトウェア的にコントロールできるようになった
    22

    View full-size slide

  87. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアからソフトウェアへ
    • Raspberry Pi が(ハードウェア的に)Z80のフリをできる様になった
    • 38本の信号線をソフトウェア的にコントロールできるようになった
    • 38本の信号線を適切に制御(=Z80エミュレート)すれば良い
    22

    View full-size slide

  88. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアからソフトウェアへ
    • Raspberry Pi が(ハードウェア的に)Z80のフリをできる様になった
    • 38本の信号線をソフトウェア的にコントロールできるようになった
    • 38本の信号線を適切に制御(=Z80エミュレート)すれば良い
    • 適切とは?
    22

    View full-size slide

  89. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    信号線のエミュレート
    23

    View full-size slide

  90. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    信号線のエミュレート
    • Z80の38本の信号線の仕様はZ80のマニュアルに書いてある
    23

    View full-size slide

  91. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    信号線のエミュレート
    • Z80の38本の信号線の仕様はZ80のマニュアルに書いてある
    • ザイログ社がPDFで公開している
    23

    View full-size slide

  92. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    信号線のエミュレート
    • Z80の38本の信号線の仕様はZ80のマニュアルに書いてある
    • ザイログ社がPDFで公開している
    • さすが現役CPU
    23

    View full-size slide

  93. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    信号線のエミュレート
    • Z80の38本の信号線の仕様はZ80のマニュアルに書いてある
    • ザイログ社がPDFで公開している
    • さすが現役CPU
    • 信号線の意味、CPUの動作と信号線が変化するタイミング
    23

    View full-size slide

  94. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    信号線のエミュレート
    • Z80の38本の信号線の仕様はZ80のマニュアルに書いてある
    • ザイログ社がPDFで公開している
    • さすが現役CPU
    • 信号線の意味、CPUの動作と信号線が変化するタイミング
    • メモリから命令を読み込む
    23

    View full-size slide

  95. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    信号線のエミュレート
    • Z80の38本の信号線の仕様はZ80のマニュアルに書いてある
    • ザイログ社がPDFで公開している
    • さすが現役CPU
    • 信号線の意味、CPUの動作と信号線が変化するタイミング
    • メモリから命令を読み込む
    • メモリからデータを読み込む / 書き込む
    23

    View full-size slide

  96. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    信号線のエミュレート
    • Z80の38本の信号線の仕様はZ80のマニュアルに書いてある
    • ザイログ社がPDFで公開している
    • さすが現役CPU
    • 信号線の意味、CPUの動作と信号線が変化するタイミング
    • メモリから命令を読み込む
    • メモリからデータを読み込む / 書き込む
    • 周辺装置からデータを読み込む / データを書き込む
    23

    View full-size slide

  97. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    信号線のエミュレート
    • Z80の38本の信号線の仕様はZ80のマニュアルに書いてある
    • ザイログ社がPDFで公開している
    • さすが現役CPU
    • 信号線の意味、CPUの動作と信号線が変化するタイミング
    • メモリから命令を読み込む
    • メモリからデータを読み込む / 書き込む
    • 周辺装置からデータを読み込む / データを書き込む
    • 周辺装置から割り込みを受け付ける
    23

    View full-size slide

  98. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    例えば: メモリリード
    24

    View full-size slide

  99. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU 25

    View full-size slide

  100. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU 25
    メモリからの読み込み

    View full-size slide

  101. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU 25
    メモリからの読み込み
    1. 読み込むアドレスを出力する

    View full-size slide

  102. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU 25
    メモリからの読み込み
    1. 読み込むアドレスを出力する
    2. MREQ, RDを有効(0)にする
    ① ②

    View full-size slide

  103. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU 25
    メモリからの読み込み
    1. 読み込むアドレスを出力する
    2. MREQ, RDを有効(0)にする
    3. メモリがWAITを無効(0)に

    するまで間待つ
    ① ② ③

    View full-size slide

  104. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU 25
    メモリからの読み込み
    1. 読み込むアドレスを出力する
    2. MREQ, RDを有効(0)にする
    3. メモリがWAITを無効(0)に

    するまで間待つ
    4. データを取り込む
    ① ② ③ ④

    View full-size slide

  105. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU 25
    メモリからの読み込み
    1. 読み込むアドレスを出力する
    2. MREQ, RDを有効(0)にする
    3. メモリがWAITを無効(0)に

    するまで間待つ
    4. データを取り込む
    5. MREQ, RDを無効化(1)する
    ① ② ③ ④ ⑤

    View full-size slide

  106. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    メモリリードのエミュレート
    26

    View full-size slide

  107. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    メモリリードのエミュレート
    • 仕様書に書いてあるとおりに各信号線を上げ下げすれば良い
    26

    View full-size slide

  108. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    メモリリードのエミュレート
    • 仕様書に書いてあるとおりに各信号線を上げ下げすれば良い
    • 愚直にやるシリーズ
    26

    View full-size slide

  109. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    愚直に実装したメモリリード
    27
    uint8_t Mcycle::m2(Cpu* cpu, uint16_t addr){
    // T1
    cpu->bus->waitClockRising();
    cpu->bus->setAddress(addr);
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_LOW;
    cpu->bus->pin_o_rd = Bus::PIN_LOW;
    cpu->bus->syncControl();
    // T2
    cpu->bus->waitClockRising();
    cpu->bus->waitClockFalling();
    while (!cpu->bus->getInput(
    Bus::Z80_PIN_I_WAIT)){
    cpu->bus->waitClockFalling();
    }
    // T3
    cpu->bus->waitClockRising();
    uint8_t data = cpu->bus->getData();
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_HIGH;
    cpu->bus->pin_o_rd = Bus::PIN_HIGH;
    cpu->bus->syncControl();
    Log::mem_read(cpu, addr, data);
    return data;
    }

    View full-size slide

  110. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    愚直に実装したメモリリード
    27
    uint8_t Mcycle::m2(Cpu* cpu, uint16_t addr){
    // T1
    cpu->bus->waitClockRising();
    cpu->bus->setAddress(addr);
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_LOW;
    cpu->bus->pin_o_rd = Bus::PIN_LOW;
    cpu->bus->syncControl();
    // T2
    cpu->bus->waitClockRising();
    cpu->bus->waitClockFalling();
    while (!cpu->bus->getInput(
    Bus::Z80_PIN_I_WAIT)){
    cpu->bus->waitClockFalling();
    }
    // T3
    cpu->bus->waitClockRising();
    uint8_t data = cpu->bus->getData();
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_HIGH;
    cpu->bus->pin_o_rd = Bus::PIN_HIGH;
    cpu->bus->syncControl();
    Log::mem_read(cpu, addr, data);
    return data;
    }
    1. クロックの立ち上がり(0→1になる)を待つ

    View full-size slide

  111. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    愚直に実装したメモリリード
    27
    uint8_t Mcycle::m2(Cpu* cpu, uint16_t addr){
    // T1
    cpu->bus->waitClockRising();
    cpu->bus->setAddress(addr);
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_LOW;
    cpu->bus->pin_o_rd = Bus::PIN_LOW;
    cpu->bus->syncControl();
    // T2
    cpu->bus->waitClockRising();
    cpu->bus->waitClockFalling();
    while (!cpu->bus->getInput(
    Bus::Z80_PIN_I_WAIT)){
    cpu->bus->waitClockFalling();
    }
    // T3
    cpu->bus->waitClockRising();
    uint8_t data = cpu->bus->getData();
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_HIGH;
    cpu->bus->pin_o_rd = Bus::PIN_HIGH;
    cpu->bus->syncControl();
    Log::mem_read(cpu, addr, data);
    return data;
    }
    1. クロックの立ち上がり(0→1になる)を待つ
    2. アドレスバスに読み込むアドレスを出力する

    View full-size slide

  112. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    愚直に実装したメモリリード
    27
    uint8_t Mcycle::m2(Cpu* cpu, uint16_t addr){
    // T1
    cpu->bus->waitClockRising();
    cpu->bus->setAddress(addr);
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_LOW;
    cpu->bus->pin_o_rd = Bus::PIN_LOW;
    cpu->bus->syncControl();
    // T2
    cpu->bus->waitClockRising();
    cpu->bus->waitClockFalling();
    while (!cpu->bus->getInput(
    Bus::Z80_PIN_I_WAIT)){
    cpu->bus->waitClockFalling();
    }
    // T3
    cpu->bus->waitClockRising();
    uint8_t data = cpu->bus->getData();
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_HIGH;
    cpu->bus->pin_o_rd = Bus::PIN_HIGH;
    cpu->bus->syncControl();
    Log::mem_read(cpu, addr, data);
    return data;
    }
    1. クロックの立ち上がり(0→1になる)を待つ
    2. アドレスバスに読み込むアドレスを出力する
    3. クロックの立ち下がり(1→0になる)を待つ

    View full-size slide

  113. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    愚直に実装したメモリリード
    27
    uint8_t Mcycle::m2(Cpu* cpu, uint16_t addr){
    // T1
    cpu->bus->waitClockRising();
    cpu->bus->setAddress(addr);
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_LOW;
    cpu->bus->pin_o_rd = Bus::PIN_LOW;
    cpu->bus->syncControl();
    // T2
    cpu->bus->waitClockRising();
    cpu->bus->waitClockFalling();
    while (!cpu->bus->getInput(
    Bus::Z80_PIN_I_WAIT)){
    cpu->bus->waitClockFalling();
    }
    // T3
    cpu->bus->waitClockRising();
    uint8_t data = cpu->bus->getData();
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_HIGH;
    cpu->bus->pin_o_rd = Bus::PIN_HIGH;
    cpu->bus->syncControl();
    Log::mem_read(cpu, addr, data);
    return data;
    }
    1. クロックの立ち上がり(0→1になる)を待つ
    2. アドレスバスに読み込むアドレスを出力する
    3. クロックの立ち下がり(1→0になる)を待つ
    4. MREQ, RDを有効にする(0にする)

    View full-size slide

  114. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    愚直に実装したメモリリード
    27
    uint8_t Mcycle::m2(Cpu* cpu, uint16_t addr){
    // T1
    cpu->bus->waitClockRising();
    cpu->bus->setAddress(addr);
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_LOW;
    cpu->bus->pin_o_rd = Bus::PIN_LOW;
    cpu->bus->syncControl();
    // T2
    cpu->bus->waitClockRising();
    cpu->bus->waitClockFalling();
    while (!cpu->bus->getInput(
    Bus::Z80_PIN_I_WAIT)){
    cpu->bus->waitClockFalling();
    }
    // T3
    cpu->bus->waitClockRising();
    uint8_t data = cpu->bus->getData();
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_HIGH;
    cpu->bus->pin_o_rd = Bus::PIN_HIGH;
    cpu->bus->syncControl();
    Log::mem_read(cpu, addr, data);
    return data;
    }
    1. クロックの立ち上がり(0→1になる)を待つ
    2. アドレスバスに読み込むアドレスを出力する
    3. クロックの立ち下がり(1→0になる)を待つ
    4. MREQ, RDを有効にする(0にする)
    5. WAITが無効になる(0になる)のを待つ

    View full-size slide

  115. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    愚直に実装したメモリリード
    27
    uint8_t Mcycle::m2(Cpu* cpu, uint16_t addr){
    // T1
    cpu->bus->waitClockRising();
    cpu->bus->setAddress(addr);
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_LOW;
    cpu->bus->pin_o_rd = Bus::PIN_LOW;
    cpu->bus->syncControl();
    // T2
    cpu->bus->waitClockRising();
    cpu->bus->waitClockFalling();
    while (!cpu->bus->getInput(
    Bus::Z80_PIN_I_WAIT)){
    cpu->bus->waitClockFalling();
    }
    // T3
    cpu->bus->waitClockRising();
    uint8_t data = cpu->bus->getData();
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_HIGH;
    cpu->bus->pin_o_rd = Bus::PIN_HIGH;
    cpu->bus->syncControl();
    Log::mem_read(cpu, addr, data);
    return data;
    }
    1. クロックの立ち上がり(0→1になる)を待つ
    2. アドレスバスに読み込むアドレスを出力する
    3. クロックの立ち下がり(1→0になる)を待つ
    4. MREQ, RDを有効にする(0にする)
    5. WAITが無効になる(0になる)のを待つ
    6. データバスの信号を読み取る

    View full-size slide

  116. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    愚直に実装したメモリリード
    27
    uint8_t Mcycle::m2(Cpu* cpu, uint16_t addr){
    // T1
    cpu->bus->waitClockRising();
    cpu->bus->setAddress(addr);
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_LOW;
    cpu->bus->pin_o_rd = Bus::PIN_LOW;
    cpu->bus->syncControl();
    // T2
    cpu->bus->waitClockRising();
    cpu->bus->waitClockFalling();
    while (!cpu->bus->getInput(
    Bus::Z80_PIN_I_WAIT)){
    cpu->bus->waitClockFalling();
    }
    // T3
    cpu->bus->waitClockRising();
    uint8_t data = cpu->bus->getData();
    cpu->bus->waitClockFalling();
    cpu->bus->pin_o_mreq = Bus::PIN_HIGH;
    cpu->bus->pin_o_rd = Bus::PIN_HIGH;
    cpu->bus->syncControl();
    Log::mem_read(cpu, addr, data);
    return data;
    }
    1. クロックの立ち上がり(0→1になる)を待つ
    2. アドレスバスに読み込むアドレスを出力する
    3. クロックの立ち下がり(1→0になる)を待つ
    4. MREQ, RDを有効にする(0にする)
    5. WAITが無効になる(0になる)のを待つ
    6. データバスの信号を読み取る
    7. MREQ, RDを無効にする(1にする)

    View full-size slide

  117. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアI/F完成
    28

    View full-size slide

  118. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU機能の実装
    29

    View full-size slide

  119. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU機能の実装
    • ここからはただの(?)エミュレータの世界
    29

    View full-size slide

  120. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU機能の実装
    • ここからはただの(?)エミュレータの世界
    • ソフトウェアエミュレータではメモリを配列などで表現していた
    29

    View full-size slide

  121. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU機能の実装
    • ここからはただの(?)エミュレータの世界
    • ソフトウェアエミュレータではメモリを配列などで表現していた
    • メモリの読み書き = 配列の読み書き
    29

    View full-size slide

  122. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU機能の実装
    • ここからはただの(?)エミュレータの世界
    • ソフトウェアエミュレータではメモリを配列などで表現していた
    • メモリの読み書き = 配列の読み書き
    • Z80 ハードウェア エミュレータ ではメモリアクセスは電気的に表現されている
    29

    View full-size slide

  123. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU機能の実装
    • ここからはただの(?)エミュレータの世界
    • ソフトウェアエミュレータではメモリを配列などで表現していた
    • メモリの読み書き = 配列の読み書き
    • Z80 ハードウェア エミュレータ ではメモリアクセスは電気的に表現されている
    • メモリの読み書き = 信号線の制御
    29

    View full-size slide

  124. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU機能の実装
    • ここからはただの(?)エミュレータの世界
    • ソフトウェアエミュレータではメモリを配列などで表現していた
    • メモリの読み書き = 配列の読み書き
    • Z80 ハードウェア エミュレータ ではメモリアクセスは電気的に表現されている
    • メモリの読み書き = 信号線の制御
    • CPU機能実装のレイヤーから見るとその差は無い
    29

    View full-size slide

  125. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPU機能の実装
    • ここからはただの(?)エミュレータの世界
    • ソフトウェアエミュレータではメモリを配列などで表現していた
    • メモリの読み書き = 配列の読み書き
    • Z80 ハードウェア エミュレータ ではメモリアクセスは電気的に表現されている
    • メモリの読み書き = 信号線の制御
    • CPU機能実装のレイヤーから見るとその差は無い
    • 既存のZ80エミュレータの知見を活かせる
    29

    View full-size slide

  126. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令を実装する
    30

    View full-size slide

  127. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令を実装する
    30
    void OpCode::execute(uint8_t opCode){
    if ((opCode >> 6) == 0b01 && (opCode & 0b00111000) != 0b00110000 && (opCode & 0b00000111) != 0b00000110){
    // ld r, r'
    Log::execute(this->_cpu, opCode, "ld r, r'");
    uint8_t *reg = this->targetRegister(opCode, 3);
    uint8_t *reg_dash = this->targetRegister(opCode, 0);
    *reg = *reg_dash;
    Log::dump_registers(this->_cpu);
    return;
    }
    switch (opCode){
    case 0x00: // nop
    Log::execute(this->_cpu, opCode, "nop");
    break;
    case 0x01: // ld bc, nn
    Log::execute(this->_cpu, opCode, "ld bc, nn");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x02: { // ld (bc), a
    Log::execute(this->_cpu, opCode, "ld (bc), a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.bc(), this->_cpu->registers.a);
    break;
    }
    case 0x03: // inc bc
    Log::execute(this->_cpu, opCode, "inc bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() + 1);
    break;
    case 0x04: // inc r
    case 0x0C:
    case 0x14:
    case 0x1C:
    case 0x24:
    case 0x2C:
    case 0x3C: {
    Log::execute(this->_cpu, opCode, "inc r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByIncrement(*reg);
    (*reg)++;
    break;
    }
    case 0x05: // dec r
    case 0x0D:
    case 0x15:
    case 0x1D:
    case 0x25:
    case 0x2D:
    case 0x3D: {
    Log::execute(this->_cpu, opCode, "dec r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByDecrement(*reg);
    (*reg)--;
    break;
    }
    case 0x06: // ld r, n
    case 0x0e:
    case 0x16:
    case 0x1e:
    case 0x26:
    case 0x2e:
    case 0x3e: {
    Log::execute(this->_cpu, opCode, "ld r, n");
    uint8_t* reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    break;
    }
    case 0x07: { // rlca
    Log::execute(this->_cpu, opCode, "rlca");
    bool carry_bit = (this->_cpu->registers.a >> 7);
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_bit;
    this->_cpu->registers.FC_Carry = carry_bit;
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    break;
    }
    case 0x08: { // ex af, af'
    Log::execute(this->_cpu, opCode, "ex af, af'");
    uint16_t af = this->_cpu->registers.af();
    this->_cpu->registers.af(this->_cpu->registers_alternate.af());
    this->_cpu->registers_alternate.af(af);
    break;
    }
    case 0x09: // add hl, rr
    case 0x19:
    case 0x29:
    case 0x39: {
    Log::execute(this->_cpu, opCode, "add hl, rr");
    uint16_t value;
    switch (opCode){ // NOLINT(hicpp-multiway-paths-covered)
    case 0x09: value = this->_cpu->registers.bc(); break;
    case 0x19: value = this->_cpu->registers.de(); break;
    case 0x29: value = this->_cpu->registers.hl(); break;
    case 0x39: value = this->_cpu->special_registers.sp; break;
    }
    this->setFlagsByAdd16(this->_cpu->registers.hl(), value);
    this->_cpu->registers.hl(this->_cpu->registers.hl() + value);
    break;
    }
    case 0x0A: // ld a,(bc)
    Log::execute(this->_cpu, opCode, "ld a,(bc)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.bc());
    break;
    case 0x0B: // dec bc
    Log::execute(this->_cpu, opCode, "dec bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() - 1);
    break;
    case 0x0F: { // rrca
    Log::execute(this->_cpu, opCode, "rrca");
    bool carry_bit = ((this->_cpu->registers.a & 1) > 0);
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) + ((this->_cpu->registers.a & 1) << 7);
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FC_Carry = carry_bit;
    break;
    }
    case 0x10: { // djnz n
    Log::execute(this->_cpu, opCode, "djnz n");
    this->_cpu->registers.b--;
    if (this->_cpu->registers.b != 0){
    auto diff = (int8_t)Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    }
    case 0x11: // ld de, nn
    Log::execute(this->_cpu, opCode, "ld de, nn");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x12: // ld (de),a
    Log::execute(this->_cpu, opCode, "ld (de),a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.de(), this->_cpu->registers.a);
    break;
    case 0x13: // inc de
    Log::execute(this->_cpu, opCode, "inc de");
    this->_cpu->registers.de(this->_cpu->registers.de() + 1);
    break;
    case 0x17: { // rla
    Log::execute(this->_cpu, opCode, "rla");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a >> 7;
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_flg;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x18: { // jr n
    Log::execute(this->_cpu, opCode, "jr n");
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    break;
    }
    case 0x1A: // ld a,(de)
    Log::execute(this->_cpu, opCode, "ld a,(de)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.de());
    break;
    case 0x1B: // dec de
    Log::execute(this->_cpu, opCode, "dec de");
    this->_cpu->registers.de(this->_cpu->registers.de() - 1);
    break;
    case 0x1F: { // rra
    Log::execute(this->_cpu, opCode, "rra");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a & 1;
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) | (carry_flg << 7);
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x20: // jr nz, n
    Log::execute(this->_cpu, opCode, "jr nz, n");
    if (! this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x21: // ld hl, nn
    Log::execute(this->_cpu, opCode, "ld hl, nn");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8)
    );
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x22: { // ld (nn), hl
    Log::execute(this->_cpu, opCode, "ld (nn), hl");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.l);
    Mcycle::m3(this->_cpu, addr + 1, this->_cpu->registers.h);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x23: // inc hl
    Log::execute(this->_cpu, opCode, "inc hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() + 1);
    break;
    case 0x27: { // daa
    Log::execute(this->_cpu, opCode, "daa");
    uint8_t cr = 0;
    if ((this->_cpu->registers.a & 0x0f) > 0x09 || this->_cpu->registers.FH_HalfCarry){
    cr += 0x06;
    }
    if (this->_cpu->registers.a > 0x99 || this->_cpu->registers.FC_Carry){
    cr += 0x60;
    this->_cpu->registers.FC_Carry = true;
    }
    if (this->_cpu->registers.FN_Subtract){
    this->_cpu->registers.FH_HalfCarry =
    this->_cpu->registers.FH_HalfCarry &&
    (this->_cpu->registers.a & 0x0f) < 0x06;
    this->_cpu->registers.a -= cr;
    } else {
    this->_cpu->registers.FH_HalfCarry = (this->_cpu->registers.a & 0x0f) > 0x09;
    this->_cpu->registers.a += cr;
    }
    this->_cpu->registers.FS_Sign = this->_cpu->registers.a >> 7;
    this->_cpu->registers.FZ_Zero = this->_cpu->registers.a == 0;
    this->_cpu->registers.FPV_ParityOverflow = (OpCode::count1(this->_cpu->registers.a) % 2 == 0);
    break;
    }
    case 0x28: // jr z, n
    Log::execute(this->_cpu, opCode, "jr z, n");
    if (this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x2A: { // ld hl, (nn)
    Log::execute(this->_cpu, opCode, "ld hl, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.l = Mcycle::m2(this->_cpu, addr);
    this->_cpu->registers.h = Mcycle::m2(this->_cpu, addr + 1);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x2B: // dec hl
    Log::execute(this->_cpu, opCode, "dec hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() - 1);
    break;
    case 0x2F: // cpl
    Log::execute(this->_cpu, opCode, "cpl");
    this->_cpu->registers.a ^= 0xff;
    this->_cpu->registers.FN_Subtract = true;
    this->_cpu->registers.FH_HalfCarry = true;
    break;
    case 0x30: // jr nc, n
    Log::execute(this->_cpu, opCode, "jr nc, n");
    if (!this->_cpu->registers.FC_Carry){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x31: // ld sp, nn
    Log::execute(this->_cpu, opCode, "ld sp, nn");
    this->_cpu->special_registers.sp =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x32: { // ld (nn), a
    Log::execute(this->_cpu, opCode, "ld (nn), a");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.a);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x33: // inc sp
    Log::execute(this->_cpu, opCode, "inc sp");
    this->_cpu->special_registers.sp++;
    break;
    case 0x34: { // inc (hl)
    Log::execute(this->_cpu, opCode, "inc (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByIncrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value + 1);
    break;
    }
    case 0x35: { // dec (hl)
    Log::execute(this->_cpu, opCode, "dec (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByDecrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value - 1);
    break;
    }
    case 0x36: // ld (hl), n
    Log::execute(this->_cpu, opCode, "ld (hl), n");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    break;
    case 0x37: // scf
    Log::execute(this->_cpu, opCode, "scf");
    this->_cpu->registers.FC_Carry = true;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    case 0x38: // jr c, n
    Log::execute(this->_cpu, opCode, "jr c, n");
    if (this->_cpu->registers.FC_Carry) {
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x3A: { // ld a, (nn)
    Log::execute(this->_cpu, opCode, "ld a, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, addr);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x3B: // dec sp
    Log::execute(this->_cpu, opCode, "dec sp");
    this->_cpu->special_registers.sp--;
    break;
    case 0x3F: { // ccf
    Log::execute(this->_cpu, opCode, "ccf");
    bool saved_carry = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = !this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = saved_carry;
    break;
    }
    case 0x46: // ld r, (hl)
    case 0x4E:
    case 0x56:
    case 0x5E:
    case 0x66:
    case 0x6E: {
    Log::execute(this->_cpu, opCode, "ld r, (hl)");
    uint8_t *reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    }
    case 0x70: // ld (hl), r
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x77:
    Log::execute(this->_cpu, opCode, "ld (hl), r");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), *(this->targetRegister(opCode, 0)));
    break;
    case 0x76: // halt
    Log::execute(this->_cpu, opCode, "halt");
    this->_cpu->halt = true;
    break;
    case 0x7E: // ld a,(hl)
    Log::execute(this->_cpu, opCode, "ld a,(hl)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    case 0x80: // add a, r
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x87: {
    Log::execute(this->_cpu, opCode, "add a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a += *reg;
    break;
    }
    case 0x86: { // add a, (hl)
    Log::execute(this->_cpu, opCode, "add a, (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0x88: // adc a, r
    case 0x89:
    case 0x8A:
    case 0x8B:
    case 0x8C:
    case 0x8D:
    case 0x8F: {
    Log::execute(this->_cpu, opCode, "adc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a += *reg + carry;
    break;
    }
    case 0x8E: { // adc a, (hl)
    Log::execute(this->_cpu, opCode, "adc a, (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0x90: // sub r
    case 0x91:
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x97: {
    Log::execute(this->_cpu, opCode, "sub r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a -= *reg;
    break;
    }
    case 0x96: { // sub (hl)
    Log::execute(this->_cpu, opCode, "sub (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0x98: // sbc a, r
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9F: {
    Log::execute(this->_cpu, opCode, "sbc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a -= *reg + carry;
    break;
    }
    case 0x9E: { // sbc a,(hl)
    Log::execute(this->_cpu, opCode, "sbc a,(hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xA0: // and r
    case 0xA1:
    case 0xA2:
    case 0xA3:
    case 0xA4:
    case 0xA5:
    case 0xA7: {
    Log::execute(this->_cpu, opCode, "and r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a &= *reg;
    this->setFlagsByLogical(true);
    break;
    }
    case 0xA6: // and (hl)
    Log::execute(this->_cpu, opCode, "and (hl)");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(true);
    break;
    case 0xA8: // xor r
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAF: {
    Log::execute(this->_cpu, opCode, "xor r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a ^= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xAE: // xor (hl)
    Log::execute(this->_cpu, opCode, "xor (hl)");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB0: // or r
    case 0xB1:
    case 0xB2:
    case 0xB3:
    case 0xB4:
    case 0xB5:
    case 0xB7: {
    Log::execute(this->_cpu, opCode, "or r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a |= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xB6: // or (hl)
    Log::execute(this->_cpu, opCode, "or (hl)");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB8: // cp r
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBF:
    Log::execute(this->_cpu, opCode, "cp r");
    this->setFlagsBySubtract(this->_cpu->registers.a, *(this->targetRegister(opCode, 0)), 0);
    break;
    case 0xBE: { // cp (hl)
    Log::execute(this->_cpu, opCode, "cp (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    break;
    }
    case 0xC0: // ret nz
    Log::execute(this->_cpu, opCode, "ret nz");
    if (!this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC1: // pop bc
    Log::execute(this->_cpu, opCode, "pop bc");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xC2: // jp nz, nn
    Log::execute(this->_cpu, opCode, "jp nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC3: // jp nn
    Log::execute(this->_cpu, opCode, "jp nn");
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    break;
    case 0xC4: // call nz, nn
    Log::execute(this->_cpu, opCode, "call nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC5: // push bc
    Log::execute(this->_cpu, opCode, "push bc");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.b);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.c);
    Log::dump_registers(this->_cpu);
    break;
    case 0xC6: { // add a, n
    Log::execute(this->_cpu, opCode, "add a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0xC7: // rst n (n = 0 - 7)
    case 0xCF:
    case 0xD7:
    case 0xDF:
    case 0xE7:
    case 0xEF:
    case 0xF7:
    case 0xFF:
    Log::execute(this->_cpu, opCode, "rst n (n = 0 - 7)");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc & 0xff);
    this->_cpu->special_registers.pc = (opCode & 0b00111000);
    break;
    case 0xC8: // ret z
    Log::execute(this->_cpu, opCode, "ret z");
    if (this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC9: // ret
    Log::execute(this->_cpu, opCode, "ret");
    executeRet();
    break;
    case 0xCA: // jp z, nn
    Log::execute(this->_cpu, opCode, "jp z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCB: { // BITS
    Log::execute(this->_cpu, opCode, "BITS");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeCb(opcode);
    break;
    }
    case 0xCC: // call z, nn
    Log::execute(this->_cpu, opCode, "call z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCD: { // call nn
    Log::execute(this->_cpu, opCode, "call nn");
    this->executeCall();
    break;
    }
    case 0xCE: { // adc a, n
    Log::execute(this->_cpu, opCode, "adc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0xD0: // ret nc
    Log::execute(this->_cpu, opCode, "ret nc");
    if (!this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD1: // pop de
    Log::execute(this->_cpu, opCode, "pop de");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xD2: // jp nc, nn
    Log::execute(this->_cpu, opCode, "jp nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD3: { // out (n),a
    Log::execute(this->_cpu, opCode, "out (n),a");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc += 1;
    Mcycle::out(this->_cpu, port, this->_cpu->registers.a, this->_cpu->registers.a);
    break;
    }
    case 0xD4: // call nc, nn
    Log::execute(this->_cpu, opCode, "call nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD5: // push de
    Log::execute(this->_cpu, opCode, "push de");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.d);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.e);
    Log::dump_registers(this->_cpu);
    break;
    case 0xD6: { // sub n
    Log::execute(this->_cpu, opCode, "sub n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0xD8: // ret c
    Log::execute(this->_cpu, opCode, "ret c");
    if (this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD9: { // exx
    Log::execute(this->_cpu, opCode, "exx");
    uint16_t temp;
    temp = this->_cpu->registers.bc();
    this->_cpu->registers.bc(this->_cpu->registers_alternate.bc());
    this->_cpu->registers_alternate.bc(temp);
    temp = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers_alternate.de());
    this->_cpu->registers_alternate.de(temp);
    temp = this->_cpu->registers.hl();
    this->_cpu->registers.hl(this->_cpu->registers_alternate.hl());
    this->_cpu->registers_alternate.hl(temp);
    break;
    }
    case 0xDA: // jp c, nn
    Log::execute(this->_cpu, opCode, "jp c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDB: { // in a, (n)
    Log::execute(this->_cpu, opCode, "in a, (n)");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->registers.a = Mcycle::in(this->_cpu, port, this->_cpu->registers.a);
    break;
    }
    case 0xDC: // call c, nn
    Log::execute(this->_cpu, opCode, "call c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDD: { // IX
    Log::execute(this->_cpu, opCode, "IX");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeDd(opcode);
    break;
    }
    case 0xDE: { // sbc a, n
    Log::execute(this->_cpu, opCode, "sbc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xE0: // ret po
    Log::execute(this->_cpu, opCode, "ret po");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    executeRet();
    }
    break;
    case 0xE1: // pop hl
    Log::execute(this->_cpu, opCode, "pop hl");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8)
    );
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xE2: // jp po, nn
    Log::execute(this->_cpu, opCode, "jp po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE3: { // ex (sp), hl
    Log::execute(this->_cpu, opCode, "ex (sp), hl");
    uint16_t mem_value =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8);
    uint16_t temp_hl = this->_cpu->registers.hl();
    this->_cpu->registers.hl(mem_value);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, temp_hl & 0xff);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp + 1, temp_hl >> 8);
    break;
    }
    case 0xE4: // call po, nn
    Log::execute(this->_cpu, opCode, "call po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE5: // push hl
    Log::execute(this->_cpu, opCode, "push hl");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() & 0xff);
    Log::dump_registers(this->_cpu);
    break;
    case 0xE6: // and n
    Log::execute(this->_cpu, opCode, "and n");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(true);
    break;
    case 0xE8: // ret pe
    Log::execute(this->_cpu, opCode, "ret pe");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    executeRet();
    }
    break;
    case 0xE9: // jp (hl)
    Log::execute(this->_cpu, opCode, "jp (hl)");
    this->_cpu->special_registers.pc = this->_cpu->registers.hl();
    break;
    case 0xEA: // jp pe, nn
    Log::execute(this->_cpu, opCode, "jp pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xEB: { // ex de,hl
    Log::execute(this->_cpu, opCode, "ex de,hl");
    uint16_t de = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers.hl());
    this->_cpu->registers.hl(de);
    break;
    }
    case 0xEC: // call pe, nn
    Log::execute(this->_cpu, opCode, "call pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xED: { // EXTD
    Log::execute(this->_cpu, opCode, "EXTD");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeEd(opcode);
    break;
    }
    case 0xEE: // xor n
    Log::execute(this->_cpu, opCode, "xor n");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF0: // ret p
    Log::execute(this->_cpu, opCode, "ret p");
    if (! this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF1: // pop af
    Log::execute(this->_cpu, opCode, "pop af");
    this->_cpu->registers.f(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp));
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xF2: // jp p, nn
    Log::execute(this->_cpu, opCode, "jp p, nn");
    if (! this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF3: // di
    Log::execute(this->_cpu, opCode, "di");
    this->_cpu->waitingDI = 1;
    break;
    case 0xF4: // call p, nn
    Log::execute(this->_cpu, opCode, "call p, nn");
    if (! this->_cpu->registers.FS_Sign) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF5: // push af
    Log::execute(this->_cpu, opCode, "push af");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.a);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.f());
    Log::dump_registers(this->_cpu);
    break;
    case 0xF6: // or n
    Log::execute(this->_cpu, opCode, "or n");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF8: // ret m
    Log::execute(this->_cpu, opCode, "ret m");
    if (this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF9: // ld sp,hl
    Log::execute(this->_cpu, opCode, "ld sp,hl");
    this->_cpu->special_registers.sp = this->_cpu->registers.hl();
    break;
    case 0xFA: // jp m, nn
    Log::execute(this->_cpu, opCode, "jp m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFB: // ei
    Log::execute(this->_cpu, opCode, "ei");
    this->_cpu->waitingEI = 2;
    break;
    case 0xFC: // call m, nn
    Log::execute(this->_cpu, opCode, "call m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFD: { // IY
    Log::execute(this->_cpu, opCode, "IY");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeFd(opcode);
    break;
    }
    case 0xFE: { // cp n
    Log::execute(this->_cpu, opCode, "cp n");
    this->setFlagsBySubtract(this->_cpu->registers.a, Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc), 0);
    this->_cpu->special_registers.pc++;
    break;
    }
    default:
    char error[100];
    sprintf(error, "Invalid op code: %02x", opCode);
    Log::error(this->_cpu, error);
    throw std::runtime_error(error);
    }
    }

    View full-size slide

  128. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令を実装する
    • 左のリストはZ80の命令 0x00 〜 0xff まで
    30
    void OpCode::execute(uint8_t opCode){
    if ((opCode >> 6) == 0b01 && (opCode & 0b00111000) != 0b00110000 && (opCode & 0b00000111) != 0b00000110){
    // ld r, r'
    Log::execute(this->_cpu, opCode, "ld r, r'");
    uint8_t *reg = this->targetRegister(opCode, 3);
    uint8_t *reg_dash = this->targetRegister(opCode, 0);
    *reg = *reg_dash;
    Log::dump_registers(this->_cpu);
    return;
    }
    switch (opCode){
    case 0x00: // nop
    Log::execute(this->_cpu, opCode, "nop");
    break;
    case 0x01: // ld bc, nn
    Log::execute(this->_cpu, opCode, "ld bc, nn");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x02: { // ld (bc), a
    Log::execute(this->_cpu, opCode, "ld (bc), a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.bc(), this->_cpu->registers.a);
    break;
    }
    case 0x03: // inc bc
    Log::execute(this->_cpu, opCode, "inc bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() + 1);
    break;
    case 0x04: // inc r
    case 0x0C:
    case 0x14:
    case 0x1C:
    case 0x24:
    case 0x2C:
    case 0x3C: {
    Log::execute(this->_cpu, opCode, "inc r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByIncrement(*reg);
    (*reg)++;
    break;
    }
    case 0x05: // dec r
    case 0x0D:
    case 0x15:
    case 0x1D:
    case 0x25:
    case 0x2D:
    case 0x3D: {
    Log::execute(this->_cpu, opCode, "dec r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByDecrement(*reg);
    (*reg)--;
    break;
    }
    case 0x06: // ld r, n
    case 0x0e:
    case 0x16:
    case 0x1e:
    case 0x26:
    case 0x2e:
    case 0x3e: {
    Log::execute(this->_cpu, opCode, "ld r, n");
    uint8_t* reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    break;
    }
    case 0x07: { // rlca
    Log::execute(this->_cpu, opCode, "rlca");
    bool carry_bit = (this->_cpu->registers.a >> 7);
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_bit;
    this->_cpu->registers.FC_Carry = carry_bit;
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    break;
    }
    case 0x08: { // ex af, af'
    Log::execute(this->_cpu, opCode, "ex af, af'");
    uint16_t af = this->_cpu->registers.af();
    this->_cpu->registers.af(this->_cpu->registers_alternate.af());
    this->_cpu->registers_alternate.af(af);
    break;
    }
    case 0x09: // add hl, rr
    case 0x19:
    case 0x29:
    case 0x39: {
    Log::execute(this->_cpu, opCode, "add hl, rr");
    uint16_t value;
    switch (opCode){ // NOLINT(hicpp-multiway-paths-covered)
    case 0x09: value = this->_cpu->registers.bc(); break;
    case 0x19: value = this->_cpu->registers.de(); break;
    case 0x29: value = this->_cpu->registers.hl(); break;
    case 0x39: value = this->_cpu->special_registers.sp; break;
    }
    this->setFlagsByAdd16(this->_cpu->registers.hl(), value);
    this->_cpu->registers.hl(this->_cpu->registers.hl() + value);
    break;
    }
    case 0x0A: // ld a,(bc)
    Log::execute(this->_cpu, opCode, "ld a,(bc)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.bc());
    break;
    case 0x0B: // dec bc
    Log::execute(this->_cpu, opCode, "dec bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() - 1);
    break;
    case 0x0F: { // rrca
    Log::execute(this->_cpu, opCode, "rrca");
    bool carry_bit = ((this->_cpu->registers.a & 1) > 0);
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) + ((this->_cpu->registers.a & 1) << 7);
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FC_Carry = carry_bit;
    break;
    }
    case 0x10: { // djnz n
    Log::execute(this->_cpu, opCode, "djnz n");
    this->_cpu->registers.b--;
    if (this->_cpu->registers.b != 0){
    auto diff = (int8_t)Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    }
    case 0x11: // ld de, nn
    Log::execute(this->_cpu, opCode, "ld de, nn");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x12: // ld (de),a
    Log::execute(this->_cpu, opCode, "ld (de),a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.de(), this->_cpu->registers.a);
    break;
    case 0x13: // inc de
    Log::execute(this->_cpu, opCode, "inc de");
    this->_cpu->registers.de(this->_cpu->registers.de() + 1);
    break;
    case 0x17: { // rla
    Log::execute(this->_cpu, opCode, "rla");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a >> 7;
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_flg;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x18: { // jr n
    Log::execute(this->_cpu, opCode, "jr n");
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    break;
    }
    case 0x1A: // ld a,(de)
    Log::execute(this->_cpu, opCode, "ld a,(de)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.de());
    break;
    case 0x1B: // dec de
    Log::execute(this->_cpu, opCode, "dec de");
    this->_cpu->registers.de(this->_cpu->registers.de() - 1);
    break;
    case 0x1F: { // rra
    Log::execute(this->_cpu, opCode, "rra");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a & 1;
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) | (carry_flg << 7);
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x20: // jr nz, n
    Log::execute(this->_cpu, opCode, "jr nz, n");
    if (! this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x21: // ld hl, nn
    Log::execute(this->_cpu, opCode, "ld hl, nn");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8)
    );
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x22: { // ld (nn), hl
    Log::execute(this->_cpu, opCode, "ld (nn), hl");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.l);
    Mcycle::m3(this->_cpu, addr + 1, this->_cpu->registers.h);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x23: // inc hl
    Log::execute(this->_cpu, opCode, "inc hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() + 1);
    break;
    case 0x27: { // daa
    Log::execute(this->_cpu, opCode, "daa");
    uint8_t cr = 0;
    if ((this->_cpu->registers.a & 0x0f) > 0x09 || this->_cpu->registers.FH_HalfCarry){
    cr += 0x06;
    }
    if (this->_cpu->registers.a > 0x99 || this->_cpu->registers.FC_Carry){
    cr += 0x60;
    this->_cpu->registers.FC_Carry = true;
    }
    if (this->_cpu->registers.FN_Subtract){
    this->_cpu->registers.FH_HalfCarry =
    this->_cpu->registers.FH_HalfCarry &&
    (this->_cpu->registers.a & 0x0f) < 0x06;
    this->_cpu->registers.a -= cr;
    } else {
    this->_cpu->registers.FH_HalfCarry = (this->_cpu->registers.a & 0x0f) > 0x09;
    this->_cpu->registers.a += cr;
    }
    this->_cpu->registers.FS_Sign = this->_cpu->registers.a >> 7;
    this->_cpu->registers.FZ_Zero = this->_cpu->registers.a == 0;
    this->_cpu->registers.FPV_ParityOverflow = (OpCode::count1(this->_cpu->registers.a) % 2 == 0);
    break;
    }
    case 0x28: // jr z, n
    Log::execute(this->_cpu, opCode, "jr z, n");
    if (this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x2A: { // ld hl, (nn)
    Log::execute(this->_cpu, opCode, "ld hl, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.l = Mcycle::m2(this->_cpu, addr);
    this->_cpu->registers.h = Mcycle::m2(this->_cpu, addr + 1);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x2B: // dec hl
    Log::execute(this->_cpu, opCode, "dec hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() - 1);
    break;
    case 0x2F: // cpl
    Log::execute(this->_cpu, opCode, "cpl");
    this->_cpu->registers.a ^= 0xff;
    this->_cpu->registers.FN_Subtract = true;
    this->_cpu->registers.FH_HalfCarry = true;
    break;
    case 0x30: // jr nc, n
    Log::execute(this->_cpu, opCode, "jr nc, n");
    if (!this->_cpu->registers.FC_Carry){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x31: // ld sp, nn
    Log::execute(this->_cpu, opCode, "ld sp, nn");
    this->_cpu->special_registers.sp =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x32: { // ld (nn), a
    Log::execute(this->_cpu, opCode, "ld (nn), a");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.a);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x33: // inc sp
    Log::execute(this->_cpu, opCode, "inc sp");
    this->_cpu->special_registers.sp++;
    break;
    case 0x34: { // inc (hl)
    Log::execute(this->_cpu, opCode, "inc (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByIncrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value + 1);
    break;
    }
    case 0x35: { // dec (hl)
    Log::execute(this->_cpu, opCode, "dec (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByDecrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value - 1);
    break;
    }
    case 0x36: // ld (hl), n
    Log::execute(this->_cpu, opCode, "ld (hl), n");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    break;
    case 0x37: // scf
    Log::execute(this->_cpu, opCode, "scf");
    this->_cpu->registers.FC_Carry = true;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    case 0x38: // jr c, n
    Log::execute(this->_cpu, opCode, "jr c, n");
    if (this->_cpu->registers.FC_Carry) {
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x3A: { // ld a, (nn)
    Log::execute(this->_cpu, opCode, "ld a, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, addr);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x3B: // dec sp
    Log::execute(this->_cpu, opCode, "dec sp");
    this->_cpu->special_registers.sp--;
    break;
    case 0x3F: { // ccf
    Log::execute(this->_cpu, opCode, "ccf");
    bool saved_carry = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = !this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = saved_carry;
    break;
    }
    case 0x46: // ld r, (hl)
    case 0x4E:
    case 0x56:
    case 0x5E:
    case 0x66:
    case 0x6E: {
    Log::execute(this->_cpu, opCode, "ld r, (hl)");
    uint8_t *reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    }
    case 0x70: // ld (hl), r
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x77:
    Log::execute(this->_cpu, opCode, "ld (hl), r");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), *(this->targetRegister(opCode, 0)));
    break;
    case 0x76: // halt
    Log::execute(this->_cpu, opCode, "halt");
    this->_cpu->halt = true;
    break;
    case 0x7E: // ld a,(hl)
    Log::execute(this->_cpu, opCode, "ld a,(hl)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    case 0x80: // add a, r
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x87: {
    Log::execute(this->_cpu, opCode, "add a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a += *reg;
    break;
    }
    case 0x86: { // add a, (hl)
    Log::execute(this->_cpu, opCode, "add a, (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0x88: // adc a, r
    case 0x89:
    case 0x8A:
    case 0x8B:
    case 0x8C:
    case 0x8D:
    case 0x8F: {
    Log::execute(this->_cpu, opCode, "adc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a += *reg + carry;
    break;
    }
    case 0x8E: { // adc a, (hl)
    Log::execute(this->_cpu, opCode, "adc a, (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0x90: // sub r
    case 0x91:
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x97: {
    Log::execute(this->_cpu, opCode, "sub r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a -= *reg;
    break;
    }
    case 0x96: { // sub (hl)
    Log::execute(this->_cpu, opCode, "sub (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0x98: // sbc a, r
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9F: {
    Log::execute(this->_cpu, opCode, "sbc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a -= *reg + carry;
    break;
    }
    case 0x9E: { // sbc a,(hl)
    Log::execute(this->_cpu, opCode, "sbc a,(hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xA0: // and r
    case 0xA1:
    case 0xA2:
    case 0xA3:
    case 0xA4:
    case 0xA5:
    case 0xA7: {
    Log::execute(this->_cpu, opCode, "and r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a &= *reg;
    this->setFlagsByLogical(true);
    break;
    }
    case 0xA6: // and (hl)
    Log::execute(this->_cpu, opCode, "and (hl)");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(true);
    break;
    case 0xA8: // xor r
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAF: {
    Log::execute(this->_cpu, opCode, "xor r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a ^= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xAE: // xor (hl)
    Log::execute(this->_cpu, opCode, "xor (hl)");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB0: // or r
    case 0xB1:
    case 0xB2:
    case 0xB3:
    case 0xB4:
    case 0xB5:
    case 0xB7: {
    Log::execute(this->_cpu, opCode, "or r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a |= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xB6: // or (hl)
    Log::execute(this->_cpu, opCode, "or (hl)");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB8: // cp r
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBF:
    Log::execute(this->_cpu, opCode, "cp r");
    this->setFlagsBySubtract(this->_cpu->registers.a, *(this->targetRegister(opCode, 0)), 0);
    break;
    case 0xBE: { // cp (hl)
    Log::execute(this->_cpu, opCode, "cp (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    break;
    }
    case 0xC0: // ret nz
    Log::execute(this->_cpu, opCode, "ret nz");
    if (!this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC1: // pop bc
    Log::execute(this->_cpu, opCode, "pop bc");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xC2: // jp nz, nn
    Log::execute(this->_cpu, opCode, "jp nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC3: // jp nn
    Log::execute(this->_cpu, opCode, "jp nn");
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    break;
    case 0xC4: // call nz, nn
    Log::execute(this->_cpu, opCode, "call nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC5: // push bc
    Log::execute(this->_cpu, opCode, "push bc");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.b);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.c);
    Log::dump_registers(this->_cpu);
    break;
    case 0xC6: { // add a, n
    Log::execute(this->_cpu, opCode, "add a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0xC7: // rst n (n = 0 - 7)
    case 0xCF:
    case 0xD7:
    case 0xDF:
    case 0xE7:
    case 0xEF:
    case 0xF7:
    case 0xFF:
    Log::execute(this->_cpu, opCode, "rst n (n = 0 - 7)");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc & 0xff);
    this->_cpu->special_registers.pc = (opCode & 0b00111000);
    break;
    case 0xC8: // ret z
    Log::execute(this->_cpu, opCode, "ret z");
    if (this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC9: // ret
    Log::execute(this->_cpu, opCode, "ret");
    executeRet();
    break;
    case 0xCA: // jp z, nn
    Log::execute(this->_cpu, opCode, "jp z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCB: { // BITS
    Log::execute(this->_cpu, opCode, "BITS");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeCb(opcode);
    break;
    }
    case 0xCC: // call z, nn
    Log::execute(this->_cpu, opCode, "call z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCD: { // call nn
    Log::execute(this->_cpu, opCode, "call nn");
    this->executeCall();
    break;
    }
    case 0xCE: { // adc a, n
    Log::execute(this->_cpu, opCode, "adc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0xD0: // ret nc
    Log::execute(this->_cpu, opCode, "ret nc");
    if (!this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD1: // pop de
    Log::execute(this->_cpu, opCode, "pop de");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xD2: // jp nc, nn
    Log::execute(this->_cpu, opCode, "jp nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD3: { // out (n),a
    Log::execute(this->_cpu, opCode, "out (n),a");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc += 1;
    Mcycle::out(this->_cpu, port, this->_cpu->registers.a, this->_cpu->registers.a);
    break;
    }
    case 0xD4: // call nc, nn
    Log::execute(this->_cpu, opCode, "call nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD5: // push de
    Log::execute(this->_cpu, opCode, "push de");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.d);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.e);
    Log::dump_registers(this->_cpu);
    break;
    case 0xD6: { // sub n
    Log::execute(this->_cpu, opCode, "sub n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0xD8: // ret c
    Log::execute(this->_cpu, opCode, "ret c");
    if (this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD9: { // exx
    Log::execute(this->_cpu, opCode, "exx");
    uint16_t temp;
    temp = this->_cpu->registers.bc();
    this->_cpu->registers.bc(this->_cpu->registers_alternate.bc());
    this->_cpu->registers_alternate.bc(temp);
    temp = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers_alternate.de());
    this->_cpu->registers_alternate.de(temp);
    temp = this->_cpu->registers.hl();
    this->_cpu->registers.hl(this->_cpu->registers_alternate.hl());
    this->_cpu->registers_alternate.hl(temp);
    break;
    }
    case 0xDA: // jp c, nn
    Log::execute(this->_cpu, opCode, "jp c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDB: { // in a, (n)
    Log::execute(this->_cpu, opCode, "in a, (n)");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->registers.a = Mcycle::in(this->_cpu, port, this->_cpu->registers.a);
    break;
    }
    case 0xDC: // call c, nn
    Log::execute(this->_cpu, opCode, "call c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDD: { // IX
    Log::execute(this->_cpu, opCode, "IX");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeDd(opcode);
    break;
    }
    case 0xDE: { // sbc a, n
    Log::execute(this->_cpu, opCode, "sbc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xE0: // ret po
    Log::execute(this->_cpu, opCode, "ret po");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    executeRet();
    }
    break;
    case 0xE1: // pop hl
    Log::execute(this->_cpu, opCode, "pop hl");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8)
    );
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xE2: // jp po, nn
    Log::execute(this->_cpu, opCode, "jp po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE3: { // ex (sp), hl
    Log::execute(this->_cpu, opCode, "ex (sp), hl");
    uint16_t mem_value =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8);
    uint16_t temp_hl = this->_cpu->registers.hl();
    this->_cpu->registers.hl(mem_value);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, temp_hl & 0xff);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp + 1, temp_hl >> 8);
    break;
    }
    case 0xE4: // call po, nn
    Log::execute(this->_cpu, opCode, "call po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE5: // push hl
    Log::execute(this->_cpu, opCode, "push hl");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() & 0xff);
    Log::dump_registers(this->_cpu);
    break;
    case 0xE6: // and n
    Log::execute(this->_cpu, opCode, "and n");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(true);
    break;
    case 0xE8: // ret pe
    Log::execute(this->_cpu, opCode, "ret pe");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    executeRet();
    }
    break;
    case 0xE9: // jp (hl)
    Log::execute(this->_cpu, opCode, "jp (hl)");
    this->_cpu->special_registers.pc = this->_cpu->registers.hl();
    break;
    case 0xEA: // jp pe, nn
    Log::execute(this->_cpu, opCode, "jp pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xEB: { // ex de,hl
    Log::execute(this->_cpu, opCode, "ex de,hl");
    uint16_t de = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers.hl());
    this->_cpu->registers.hl(de);
    break;
    }
    case 0xEC: // call pe, nn
    Log::execute(this->_cpu, opCode, "call pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xED: { // EXTD
    Log::execute(this->_cpu, opCode, "EXTD");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeEd(opcode);
    break;
    }
    case 0xEE: // xor n
    Log::execute(this->_cpu, opCode, "xor n");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF0: // ret p
    Log::execute(this->_cpu, opCode, "ret p");
    if (! this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF1: // pop af
    Log::execute(this->_cpu, opCode, "pop af");
    this->_cpu->registers.f(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp));
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xF2: // jp p, nn
    Log::execute(this->_cpu, opCode, "jp p, nn");
    if (! this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF3: // di
    Log::execute(this->_cpu, opCode, "di");
    this->_cpu->waitingDI = 1;
    break;
    case 0xF4: // call p, nn
    Log::execute(this->_cpu, opCode, "call p, nn");
    if (! this->_cpu->registers.FS_Sign) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF5: // push af
    Log::execute(this->_cpu, opCode, "push af");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.a);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.f());
    Log::dump_registers(this->_cpu);
    break;
    case 0xF6: // or n
    Log::execute(this->_cpu, opCode, "or n");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF8: // ret m
    Log::execute(this->_cpu, opCode, "ret m");
    if (this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF9: // ld sp,hl
    Log::execute(this->_cpu, opCode, "ld sp,hl");
    this->_cpu->special_registers.sp = this->_cpu->registers.hl();
    break;
    case 0xFA: // jp m, nn
    Log::execute(this->_cpu, opCode, "jp m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFB: // ei
    Log::execute(this->_cpu, opCode, "ei");
    this->_cpu->waitingEI = 2;
    break;
    case 0xFC: // call m, nn
    Log::execute(this->_cpu, opCode, "call m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFD: { // IY
    Log::execute(this->_cpu, opCode, "IY");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeFd(opcode);
    break;
    }
    case 0xFE: { // cp n
    Log::execute(this->_cpu, opCode, "cp n");
    this->setFlagsBySubtract(this->_cpu->registers.a, Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc), 0);
    this->_cpu->special_registers.pc++;
    break;
    }
    default:
    char error[100];
    sprintf(error, "Invalid op code: %02x", opCode);
    Log::error(this->_cpu, error);
    throw std::runtime_error(error);
    }
    }

    View full-size slide

  129. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令を実装する
    • 左のリストはZ80の命令 0x00 〜 0xff まで
    • 256個の case 文 1,300行ぐらい
    30
    void OpCode::execute(uint8_t opCode){
    if ((opCode >> 6) == 0b01 && (opCode & 0b00111000) != 0b00110000 && (opCode & 0b00000111) != 0b00000110){
    // ld r, r'
    Log::execute(this->_cpu, opCode, "ld r, r'");
    uint8_t *reg = this->targetRegister(opCode, 3);
    uint8_t *reg_dash = this->targetRegister(opCode, 0);
    *reg = *reg_dash;
    Log::dump_registers(this->_cpu);
    return;
    }
    switch (opCode){
    case 0x00: // nop
    Log::execute(this->_cpu, opCode, "nop");
    break;
    case 0x01: // ld bc, nn
    Log::execute(this->_cpu, opCode, "ld bc, nn");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x02: { // ld (bc), a
    Log::execute(this->_cpu, opCode, "ld (bc), a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.bc(), this->_cpu->registers.a);
    break;
    }
    case 0x03: // inc bc
    Log::execute(this->_cpu, opCode, "inc bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() + 1);
    break;
    case 0x04: // inc r
    case 0x0C:
    case 0x14:
    case 0x1C:
    case 0x24:
    case 0x2C:
    case 0x3C: {
    Log::execute(this->_cpu, opCode, "inc r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByIncrement(*reg);
    (*reg)++;
    break;
    }
    case 0x05: // dec r
    case 0x0D:
    case 0x15:
    case 0x1D:
    case 0x25:
    case 0x2D:
    case 0x3D: {
    Log::execute(this->_cpu, opCode, "dec r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByDecrement(*reg);
    (*reg)--;
    break;
    }
    case 0x06: // ld r, n
    case 0x0e:
    case 0x16:
    case 0x1e:
    case 0x26:
    case 0x2e:
    case 0x3e: {
    Log::execute(this->_cpu, opCode, "ld r, n");
    uint8_t* reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    break;
    }
    case 0x07: { // rlca
    Log::execute(this->_cpu, opCode, "rlca");
    bool carry_bit = (this->_cpu->registers.a >> 7);
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_bit;
    this->_cpu->registers.FC_Carry = carry_bit;
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    break;
    }
    case 0x08: { // ex af, af'
    Log::execute(this->_cpu, opCode, "ex af, af'");
    uint16_t af = this->_cpu->registers.af();
    this->_cpu->registers.af(this->_cpu->registers_alternate.af());
    this->_cpu->registers_alternate.af(af);
    break;
    }
    case 0x09: // add hl, rr
    case 0x19:
    case 0x29:
    case 0x39: {
    Log::execute(this->_cpu, opCode, "add hl, rr");
    uint16_t value;
    switch (opCode){ // NOLINT(hicpp-multiway-paths-covered)
    case 0x09: value = this->_cpu->registers.bc(); break;
    case 0x19: value = this->_cpu->registers.de(); break;
    case 0x29: value = this->_cpu->registers.hl(); break;
    case 0x39: value = this->_cpu->special_registers.sp; break;
    }
    this->setFlagsByAdd16(this->_cpu->registers.hl(), value);
    this->_cpu->registers.hl(this->_cpu->registers.hl() + value);
    break;
    }
    case 0x0A: // ld a,(bc)
    Log::execute(this->_cpu, opCode, "ld a,(bc)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.bc());
    break;
    case 0x0B: // dec bc
    Log::execute(this->_cpu, opCode, "dec bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() - 1);
    break;
    case 0x0F: { // rrca
    Log::execute(this->_cpu, opCode, "rrca");
    bool carry_bit = ((this->_cpu->registers.a & 1) > 0);
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) + ((this->_cpu->registers.a & 1) << 7);
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FC_Carry = carry_bit;
    break;
    }
    case 0x10: { // djnz n
    Log::execute(this->_cpu, opCode, "djnz n");
    this->_cpu->registers.b--;
    if (this->_cpu->registers.b != 0){
    auto diff = (int8_t)Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    }
    case 0x11: // ld de, nn
    Log::execute(this->_cpu, opCode, "ld de, nn");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x12: // ld (de),a
    Log::execute(this->_cpu, opCode, "ld (de),a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.de(), this->_cpu->registers.a);
    break;
    case 0x13: // inc de
    Log::execute(this->_cpu, opCode, "inc de");
    this->_cpu->registers.de(this->_cpu->registers.de() + 1);
    break;
    case 0x17: { // rla
    Log::execute(this->_cpu, opCode, "rla");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a >> 7;
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_flg;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x18: { // jr n
    Log::execute(this->_cpu, opCode, "jr n");
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    break;
    }
    case 0x1A: // ld a,(de)
    Log::execute(this->_cpu, opCode, "ld a,(de)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.de());
    break;
    case 0x1B: // dec de
    Log::execute(this->_cpu, opCode, "dec de");
    this->_cpu->registers.de(this->_cpu->registers.de() - 1);
    break;
    case 0x1F: { // rra
    Log::execute(this->_cpu, opCode, "rra");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a & 1;
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) | (carry_flg << 7);
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x20: // jr nz, n
    Log::execute(this->_cpu, opCode, "jr nz, n");
    if (! this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x21: // ld hl, nn
    Log::execute(this->_cpu, opCode, "ld hl, nn");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8)
    );
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x22: { // ld (nn), hl
    Log::execute(this->_cpu, opCode, "ld (nn), hl");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.l);
    Mcycle::m3(this->_cpu, addr + 1, this->_cpu->registers.h);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x23: // inc hl
    Log::execute(this->_cpu, opCode, "inc hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() + 1);
    break;
    case 0x27: { // daa
    Log::execute(this->_cpu, opCode, "daa");
    uint8_t cr = 0;
    if ((this->_cpu->registers.a & 0x0f) > 0x09 || this->_cpu->registers.FH_HalfCarry){
    cr += 0x06;
    }
    if (this->_cpu->registers.a > 0x99 || this->_cpu->registers.FC_Carry){
    cr += 0x60;
    this->_cpu->registers.FC_Carry = true;
    }
    if (this->_cpu->registers.FN_Subtract){
    this->_cpu->registers.FH_HalfCarry =
    this->_cpu->registers.FH_HalfCarry &&
    (this->_cpu->registers.a & 0x0f) < 0x06;
    this->_cpu->registers.a -= cr;
    } else {
    this->_cpu->registers.FH_HalfCarry = (this->_cpu->registers.a & 0x0f) > 0x09;
    this->_cpu->registers.a += cr;
    }
    this->_cpu->registers.FS_Sign = this->_cpu->registers.a >> 7;
    this->_cpu->registers.FZ_Zero = this->_cpu->registers.a == 0;
    this->_cpu->registers.FPV_ParityOverflow = (OpCode::count1(this->_cpu->registers.a) % 2 == 0);
    break;
    }
    case 0x28: // jr z, n
    Log::execute(this->_cpu, opCode, "jr z, n");
    if (this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x2A: { // ld hl, (nn)
    Log::execute(this->_cpu, opCode, "ld hl, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.l = Mcycle::m2(this->_cpu, addr);
    this->_cpu->registers.h = Mcycle::m2(this->_cpu, addr + 1);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x2B: // dec hl
    Log::execute(this->_cpu, opCode, "dec hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() - 1);
    break;
    case 0x2F: // cpl
    Log::execute(this->_cpu, opCode, "cpl");
    this->_cpu->registers.a ^= 0xff;
    this->_cpu->registers.FN_Subtract = true;
    this->_cpu->registers.FH_HalfCarry = true;
    break;
    case 0x30: // jr nc, n
    Log::execute(this->_cpu, opCode, "jr nc, n");
    if (!this->_cpu->registers.FC_Carry){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x31: // ld sp, nn
    Log::execute(this->_cpu, opCode, "ld sp, nn");
    this->_cpu->special_registers.sp =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x32: { // ld (nn), a
    Log::execute(this->_cpu, opCode, "ld (nn), a");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.a);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x33: // inc sp
    Log::execute(this->_cpu, opCode, "inc sp");
    this->_cpu->special_registers.sp++;
    break;
    case 0x34: { // inc (hl)
    Log::execute(this->_cpu, opCode, "inc (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByIncrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value + 1);
    break;
    }
    case 0x35: { // dec (hl)
    Log::execute(this->_cpu, opCode, "dec (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByDecrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value - 1);
    break;
    }
    case 0x36: // ld (hl), n
    Log::execute(this->_cpu, opCode, "ld (hl), n");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    break;
    case 0x37: // scf
    Log::execute(this->_cpu, opCode, "scf");
    this->_cpu->registers.FC_Carry = true;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    case 0x38: // jr c, n
    Log::execute(this->_cpu, opCode, "jr c, n");
    if (this->_cpu->registers.FC_Carry) {
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x3A: { // ld a, (nn)
    Log::execute(this->_cpu, opCode, "ld a, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, addr);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x3B: // dec sp
    Log::execute(this->_cpu, opCode, "dec sp");
    this->_cpu->special_registers.sp--;
    break;
    case 0x3F: { // ccf
    Log::execute(this->_cpu, opCode, "ccf");
    bool saved_carry = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = !this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = saved_carry;
    break;
    }
    case 0x46: // ld r, (hl)
    case 0x4E:
    case 0x56:
    case 0x5E:
    case 0x66:
    case 0x6E: {
    Log::execute(this->_cpu, opCode, "ld r, (hl)");
    uint8_t *reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    }
    case 0x70: // ld (hl), r
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x77:
    Log::execute(this->_cpu, opCode, "ld (hl), r");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), *(this->targetRegister(opCode, 0)));
    break;
    case 0x76: // halt
    Log::execute(this->_cpu, opCode, "halt");
    this->_cpu->halt = true;
    break;
    case 0x7E: // ld a,(hl)
    Log::execute(this->_cpu, opCode, "ld a,(hl)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    case 0x80: // add a, r
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x87: {
    Log::execute(this->_cpu, opCode, "add a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a += *reg;
    break;
    }
    case 0x86: { // add a, (hl)
    Log::execute(this->_cpu, opCode, "add a, (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0x88: // adc a, r
    case 0x89:
    case 0x8A:
    case 0x8B:
    case 0x8C:
    case 0x8D:
    case 0x8F: {
    Log::execute(this->_cpu, opCode, "adc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a += *reg + carry;
    break;
    }
    case 0x8E: { // adc a, (hl)
    Log::execute(this->_cpu, opCode, "adc a, (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0x90: // sub r
    case 0x91:
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x97: {
    Log::execute(this->_cpu, opCode, "sub r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a -= *reg;
    break;
    }
    case 0x96: { // sub (hl)
    Log::execute(this->_cpu, opCode, "sub (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0x98: // sbc a, r
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9F: {
    Log::execute(this->_cpu, opCode, "sbc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a -= *reg + carry;
    break;
    }
    case 0x9E: { // sbc a,(hl)
    Log::execute(this->_cpu, opCode, "sbc a,(hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xA0: // and r
    case 0xA1:
    case 0xA2:
    case 0xA3:
    case 0xA4:
    case 0xA5:
    case 0xA7: {
    Log::execute(this->_cpu, opCode, "and r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a &= *reg;
    this->setFlagsByLogical(true);
    break;
    }
    case 0xA6: // and (hl)
    Log::execute(this->_cpu, opCode, "and (hl)");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(true);
    break;
    case 0xA8: // xor r
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAF: {
    Log::execute(this->_cpu, opCode, "xor r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a ^= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xAE: // xor (hl)
    Log::execute(this->_cpu, opCode, "xor (hl)");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB0: // or r
    case 0xB1:
    case 0xB2:
    case 0xB3:
    case 0xB4:
    case 0xB5:
    case 0xB7: {
    Log::execute(this->_cpu, opCode, "or r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a |= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xB6: // or (hl)
    Log::execute(this->_cpu, opCode, "or (hl)");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB8: // cp r
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBF:
    Log::execute(this->_cpu, opCode, "cp r");
    this->setFlagsBySubtract(this->_cpu->registers.a, *(this->targetRegister(opCode, 0)), 0);
    break;
    case 0xBE: { // cp (hl)
    Log::execute(this->_cpu, opCode, "cp (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    break;
    }
    case 0xC0: // ret nz
    Log::execute(this->_cpu, opCode, "ret nz");
    if (!this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC1: // pop bc
    Log::execute(this->_cpu, opCode, "pop bc");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xC2: // jp nz, nn
    Log::execute(this->_cpu, opCode, "jp nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC3: // jp nn
    Log::execute(this->_cpu, opCode, "jp nn");
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    break;
    case 0xC4: // call nz, nn
    Log::execute(this->_cpu, opCode, "call nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC5: // push bc
    Log::execute(this->_cpu, opCode, "push bc");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.b);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.c);
    Log::dump_registers(this->_cpu);
    break;
    case 0xC6: { // add a, n
    Log::execute(this->_cpu, opCode, "add a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0xC7: // rst n (n = 0 - 7)
    case 0xCF:
    case 0xD7:
    case 0xDF:
    case 0xE7:
    case 0xEF:
    case 0xF7:
    case 0xFF:
    Log::execute(this->_cpu, opCode, "rst n (n = 0 - 7)");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc & 0xff);
    this->_cpu->special_registers.pc = (opCode & 0b00111000);
    break;
    case 0xC8: // ret z
    Log::execute(this->_cpu, opCode, "ret z");
    if (this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC9: // ret
    Log::execute(this->_cpu, opCode, "ret");
    executeRet();
    break;
    case 0xCA: // jp z, nn
    Log::execute(this->_cpu, opCode, "jp z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCB: { // BITS
    Log::execute(this->_cpu, opCode, "BITS");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeCb(opcode);
    break;
    }
    case 0xCC: // call z, nn
    Log::execute(this->_cpu, opCode, "call z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCD: { // call nn
    Log::execute(this->_cpu, opCode, "call nn");
    this->executeCall();
    break;
    }
    case 0xCE: { // adc a, n
    Log::execute(this->_cpu, opCode, "adc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0xD0: // ret nc
    Log::execute(this->_cpu, opCode, "ret nc");
    if (!this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD1: // pop de
    Log::execute(this->_cpu, opCode, "pop de");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xD2: // jp nc, nn
    Log::execute(this->_cpu, opCode, "jp nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD3: { // out (n),a
    Log::execute(this->_cpu, opCode, "out (n),a");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc += 1;
    Mcycle::out(this->_cpu, port, this->_cpu->registers.a, this->_cpu->registers.a);
    break;
    }
    case 0xD4: // call nc, nn
    Log::execute(this->_cpu, opCode, "call nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD5: // push de
    Log::execute(this->_cpu, opCode, "push de");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.d);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.e);
    Log::dump_registers(this->_cpu);
    break;
    case 0xD6: { // sub n
    Log::execute(this->_cpu, opCode, "sub n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0xD8: // ret c
    Log::execute(this->_cpu, opCode, "ret c");
    if (this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD9: { // exx
    Log::execute(this->_cpu, opCode, "exx");
    uint16_t temp;
    temp = this->_cpu->registers.bc();
    this->_cpu->registers.bc(this->_cpu->registers_alternate.bc());
    this->_cpu->registers_alternate.bc(temp);
    temp = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers_alternate.de());
    this->_cpu->registers_alternate.de(temp);
    temp = this->_cpu->registers.hl();
    this->_cpu->registers.hl(this->_cpu->registers_alternate.hl());
    this->_cpu->registers_alternate.hl(temp);
    break;
    }
    case 0xDA: // jp c, nn
    Log::execute(this->_cpu, opCode, "jp c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDB: { // in a, (n)
    Log::execute(this->_cpu, opCode, "in a, (n)");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->registers.a = Mcycle::in(this->_cpu, port, this->_cpu->registers.a);
    break;
    }
    case 0xDC: // call c, nn
    Log::execute(this->_cpu, opCode, "call c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDD: { // IX
    Log::execute(this->_cpu, opCode, "IX");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeDd(opcode);
    break;
    }
    case 0xDE: { // sbc a, n
    Log::execute(this->_cpu, opCode, "sbc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xE0: // ret po
    Log::execute(this->_cpu, opCode, "ret po");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    executeRet();
    }
    break;
    case 0xE1: // pop hl
    Log::execute(this->_cpu, opCode, "pop hl");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8)
    );
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xE2: // jp po, nn
    Log::execute(this->_cpu, opCode, "jp po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE3: { // ex (sp), hl
    Log::execute(this->_cpu, opCode, "ex (sp), hl");
    uint16_t mem_value =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8);
    uint16_t temp_hl = this->_cpu->registers.hl();
    this->_cpu->registers.hl(mem_value);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, temp_hl & 0xff);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp + 1, temp_hl >> 8);
    break;
    }
    case 0xE4: // call po, nn
    Log::execute(this->_cpu, opCode, "call po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE5: // push hl
    Log::execute(this->_cpu, opCode, "push hl");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() & 0xff);
    Log::dump_registers(this->_cpu);
    break;
    case 0xE6: // and n
    Log::execute(this->_cpu, opCode, "and n");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(true);
    break;
    case 0xE8: // ret pe
    Log::execute(this->_cpu, opCode, "ret pe");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    executeRet();
    }
    break;
    case 0xE9: // jp (hl)
    Log::execute(this->_cpu, opCode, "jp (hl)");
    this->_cpu->special_registers.pc = this->_cpu->registers.hl();
    break;
    case 0xEA: // jp pe, nn
    Log::execute(this->_cpu, opCode, "jp pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xEB: { // ex de,hl
    Log::execute(this->_cpu, opCode, "ex de,hl");
    uint16_t de = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers.hl());
    this->_cpu->registers.hl(de);
    break;
    }
    case 0xEC: // call pe, nn
    Log::execute(this->_cpu, opCode, "call pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xED: { // EXTD
    Log::execute(this->_cpu, opCode, "EXTD");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeEd(opcode);
    break;
    }
    case 0xEE: // xor n
    Log::execute(this->_cpu, opCode, "xor n");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF0: // ret p
    Log::execute(this->_cpu, opCode, "ret p");
    if (! this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF1: // pop af
    Log::execute(this->_cpu, opCode, "pop af");
    this->_cpu->registers.f(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp));
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xF2: // jp p, nn
    Log::execute(this->_cpu, opCode, "jp p, nn");
    if (! this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF3: // di
    Log::execute(this->_cpu, opCode, "di");
    this->_cpu->waitingDI = 1;
    break;
    case 0xF4: // call p, nn
    Log::execute(this->_cpu, opCode, "call p, nn");
    if (! this->_cpu->registers.FS_Sign) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF5: // push af
    Log::execute(this->_cpu, opCode, "push af");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.a);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.f());
    Log::dump_registers(this->_cpu);
    break;
    case 0xF6: // or n
    Log::execute(this->_cpu, opCode, "or n");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF8: // ret m
    Log::execute(this->_cpu, opCode, "ret m");
    if (this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF9: // ld sp,hl
    Log::execute(this->_cpu, opCode, "ld sp,hl");
    this->_cpu->special_registers.sp = this->_cpu->registers.hl();
    break;
    case 0xFA: // jp m, nn
    Log::execute(this->_cpu, opCode, "jp m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFB: // ei
    Log::execute(this->_cpu, opCode, "ei");
    this->_cpu->waitingEI = 2;
    break;
    case 0xFC: // call m, nn
    Log::execute(this->_cpu, opCode, "call m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFD: { // IY
    Log::execute(this->_cpu, opCode, "IY");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeFd(opcode);
    break;
    }
    case 0xFE: { // cp n
    Log::execute(this->_cpu, opCode, "cp n");
    this->setFlagsBySubtract(this->_cpu->registers.a, Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc), 0);
    this->_cpu->special_registers.pc++;
    break;
    }
    default:
    char error[100];
    sprintf(error, "Invalid op code: %02x", opCode);
    Log::error(this->_cpu, error);
    throw std::runtime_error(error);
    }
    }

    View full-size slide

  130. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令を実装する
    • 左のリストはZ80の命令 0x00 〜 0xff まで
    • 256個の case 文 1,300行ぐらい
    • 実際は少し工夫してるのでもう少し少ない
    30
    void OpCode::execute(uint8_t opCode){
    if ((opCode >> 6) == 0b01 && (opCode & 0b00111000) != 0b00110000 && (opCode & 0b00000111) != 0b00000110){
    // ld r, r'
    Log::execute(this->_cpu, opCode, "ld r, r'");
    uint8_t *reg = this->targetRegister(opCode, 3);
    uint8_t *reg_dash = this->targetRegister(opCode, 0);
    *reg = *reg_dash;
    Log::dump_registers(this->_cpu);
    return;
    }
    switch (opCode){
    case 0x00: // nop
    Log::execute(this->_cpu, opCode, "nop");
    break;
    case 0x01: // ld bc, nn
    Log::execute(this->_cpu, opCode, "ld bc, nn");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x02: { // ld (bc), a
    Log::execute(this->_cpu, opCode, "ld (bc), a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.bc(), this->_cpu->registers.a);
    break;
    }
    case 0x03: // inc bc
    Log::execute(this->_cpu, opCode, "inc bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() + 1);
    break;
    case 0x04: // inc r
    case 0x0C:
    case 0x14:
    case 0x1C:
    case 0x24:
    case 0x2C:
    case 0x3C: {
    Log::execute(this->_cpu, opCode, "inc r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByIncrement(*reg);
    (*reg)++;
    break;
    }
    case 0x05: // dec r
    case 0x0D:
    case 0x15:
    case 0x1D:
    case 0x25:
    case 0x2D:
    case 0x3D: {
    Log::execute(this->_cpu, opCode, "dec r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByDecrement(*reg);
    (*reg)--;
    break;
    }
    case 0x06: // ld r, n
    case 0x0e:
    case 0x16:
    case 0x1e:
    case 0x26:
    case 0x2e:
    case 0x3e: {
    Log::execute(this->_cpu, opCode, "ld r, n");
    uint8_t* reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    break;
    }
    case 0x07: { // rlca
    Log::execute(this->_cpu, opCode, "rlca");
    bool carry_bit = (this->_cpu->registers.a >> 7);
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_bit;
    this->_cpu->registers.FC_Carry = carry_bit;
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    break;
    }
    case 0x08: { // ex af, af'
    Log::execute(this->_cpu, opCode, "ex af, af'");
    uint16_t af = this->_cpu->registers.af();
    this->_cpu->registers.af(this->_cpu->registers_alternate.af());
    this->_cpu->registers_alternate.af(af);
    break;
    }
    case 0x09: // add hl, rr
    case 0x19:
    case 0x29:
    case 0x39: {
    Log::execute(this->_cpu, opCode, "add hl, rr");
    uint16_t value;
    switch (opCode){ // NOLINT(hicpp-multiway-paths-covered)
    case 0x09: value = this->_cpu->registers.bc(); break;
    case 0x19: value = this->_cpu->registers.de(); break;
    case 0x29: value = this->_cpu->registers.hl(); break;
    case 0x39: value = this->_cpu->special_registers.sp; break;
    }
    this->setFlagsByAdd16(this->_cpu->registers.hl(), value);
    this->_cpu->registers.hl(this->_cpu->registers.hl() + value);
    break;
    }
    case 0x0A: // ld a,(bc)
    Log::execute(this->_cpu, opCode, "ld a,(bc)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.bc());
    break;
    case 0x0B: // dec bc
    Log::execute(this->_cpu, opCode, "dec bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() - 1);
    break;
    case 0x0F: { // rrca
    Log::execute(this->_cpu, opCode, "rrca");
    bool carry_bit = ((this->_cpu->registers.a & 1) > 0);
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) + ((this->_cpu->registers.a & 1) << 7);
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FC_Carry = carry_bit;
    break;
    }
    case 0x10: { // djnz n
    Log::execute(this->_cpu, opCode, "djnz n");
    this->_cpu->registers.b--;
    if (this->_cpu->registers.b != 0){
    auto diff = (int8_t)Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    }
    case 0x11: // ld de, nn
    Log::execute(this->_cpu, opCode, "ld de, nn");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x12: // ld (de),a
    Log::execute(this->_cpu, opCode, "ld (de),a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.de(), this->_cpu->registers.a);
    break;
    case 0x13: // inc de
    Log::execute(this->_cpu, opCode, "inc de");
    this->_cpu->registers.de(this->_cpu->registers.de() + 1);
    break;
    case 0x17: { // rla
    Log::execute(this->_cpu, opCode, "rla");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a >> 7;
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_flg;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x18: { // jr n
    Log::execute(this->_cpu, opCode, "jr n");
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    break;
    }
    case 0x1A: // ld a,(de)
    Log::execute(this->_cpu, opCode, "ld a,(de)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.de());
    break;
    case 0x1B: // dec de
    Log::execute(this->_cpu, opCode, "dec de");
    this->_cpu->registers.de(this->_cpu->registers.de() - 1);
    break;
    case 0x1F: { // rra
    Log::execute(this->_cpu, opCode, "rra");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a & 1;
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) | (carry_flg << 7);
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x20: // jr nz, n
    Log::execute(this->_cpu, opCode, "jr nz, n");
    if (! this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x21: // ld hl, nn
    Log::execute(this->_cpu, opCode, "ld hl, nn");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8)
    );
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x22: { // ld (nn), hl
    Log::execute(this->_cpu, opCode, "ld (nn), hl");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.l);
    Mcycle::m3(this->_cpu, addr + 1, this->_cpu->registers.h);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x23: // inc hl
    Log::execute(this->_cpu, opCode, "inc hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() + 1);
    break;
    case 0x27: { // daa
    Log::execute(this->_cpu, opCode, "daa");
    uint8_t cr = 0;
    if ((this->_cpu->registers.a & 0x0f) > 0x09 || this->_cpu->registers.FH_HalfCarry){
    cr += 0x06;
    }
    if (this->_cpu->registers.a > 0x99 || this->_cpu->registers.FC_Carry){
    cr += 0x60;
    this->_cpu->registers.FC_Carry = true;
    }
    if (this->_cpu->registers.FN_Subtract){
    this->_cpu->registers.FH_HalfCarry =
    this->_cpu->registers.FH_HalfCarry &&
    (this->_cpu->registers.a & 0x0f) < 0x06;
    this->_cpu->registers.a -= cr;
    } else {
    this->_cpu->registers.FH_HalfCarry = (this->_cpu->registers.a & 0x0f) > 0x09;
    this->_cpu->registers.a += cr;
    }
    this->_cpu->registers.FS_Sign = this->_cpu->registers.a >> 7;
    this->_cpu->registers.FZ_Zero = this->_cpu->registers.a == 0;
    this->_cpu->registers.FPV_ParityOverflow = (OpCode::count1(this->_cpu->registers.a) % 2 == 0);
    break;
    }
    case 0x28: // jr z, n
    Log::execute(this->_cpu, opCode, "jr z, n");
    if (this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x2A: { // ld hl, (nn)
    Log::execute(this->_cpu, opCode, "ld hl, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.l = Mcycle::m2(this->_cpu, addr);
    this->_cpu->registers.h = Mcycle::m2(this->_cpu, addr + 1);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x2B: // dec hl
    Log::execute(this->_cpu, opCode, "dec hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() - 1);
    break;
    case 0x2F: // cpl
    Log::execute(this->_cpu, opCode, "cpl");
    this->_cpu->registers.a ^= 0xff;
    this->_cpu->registers.FN_Subtract = true;
    this->_cpu->registers.FH_HalfCarry = true;
    break;
    case 0x30: // jr nc, n
    Log::execute(this->_cpu, opCode, "jr nc, n");
    if (!this->_cpu->registers.FC_Carry){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x31: // ld sp, nn
    Log::execute(this->_cpu, opCode, "ld sp, nn");
    this->_cpu->special_registers.sp =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x32: { // ld (nn), a
    Log::execute(this->_cpu, opCode, "ld (nn), a");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.a);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x33: // inc sp
    Log::execute(this->_cpu, opCode, "inc sp");
    this->_cpu->special_registers.sp++;
    break;
    case 0x34: { // inc (hl)
    Log::execute(this->_cpu, opCode, "inc (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByIncrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value + 1);
    break;
    }
    case 0x35: { // dec (hl)
    Log::execute(this->_cpu, opCode, "dec (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByDecrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value - 1);
    break;
    }
    case 0x36: // ld (hl), n
    Log::execute(this->_cpu, opCode, "ld (hl), n");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    break;
    case 0x37: // scf
    Log::execute(this->_cpu, opCode, "scf");
    this->_cpu->registers.FC_Carry = true;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    case 0x38: // jr c, n
    Log::execute(this->_cpu, opCode, "jr c, n");
    if (this->_cpu->registers.FC_Carry) {
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x3A: { // ld a, (nn)
    Log::execute(this->_cpu, opCode, "ld a, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, addr);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x3B: // dec sp
    Log::execute(this->_cpu, opCode, "dec sp");
    this->_cpu->special_registers.sp--;
    break;
    case 0x3F: { // ccf
    Log::execute(this->_cpu, opCode, "ccf");
    bool saved_carry = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = !this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = saved_carry;
    break;
    }
    case 0x46: // ld r, (hl)
    case 0x4E:
    case 0x56:
    case 0x5E:
    case 0x66:
    case 0x6E: {
    Log::execute(this->_cpu, opCode, "ld r, (hl)");
    uint8_t *reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    }
    case 0x70: // ld (hl), r
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x77:
    Log::execute(this->_cpu, opCode, "ld (hl), r");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), *(this->targetRegister(opCode, 0)));
    break;
    case 0x76: // halt
    Log::execute(this->_cpu, opCode, "halt");
    this->_cpu->halt = true;
    break;
    case 0x7E: // ld a,(hl)
    Log::execute(this->_cpu, opCode, "ld a,(hl)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    case 0x80: // add a, r
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x87: {
    Log::execute(this->_cpu, opCode, "add a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a += *reg;
    break;
    }
    case 0x86: { // add a, (hl)
    Log::execute(this->_cpu, opCode, "add a, (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0x88: // adc a, r
    case 0x89:
    case 0x8A:
    case 0x8B:
    case 0x8C:
    case 0x8D:
    case 0x8F: {
    Log::execute(this->_cpu, opCode, "adc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a += *reg + carry;
    break;
    }
    case 0x8E: { // adc a, (hl)
    Log::execute(this->_cpu, opCode, "adc a, (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0x90: // sub r
    case 0x91:
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x97: {
    Log::execute(this->_cpu, opCode, "sub r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a -= *reg;
    break;
    }
    case 0x96: { // sub (hl)
    Log::execute(this->_cpu, opCode, "sub (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0x98: // sbc a, r
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9F: {
    Log::execute(this->_cpu, opCode, "sbc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a -= *reg + carry;
    break;
    }
    case 0x9E: { // sbc a,(hl)
    Log::execute(this->_cpu, opCode, "sbc a,(hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xA0: // and r
    case 0xA1:
    case 0xA2:
    case 0xA3:
    case 0xA4:
    case 0xA5:
    case 0xA7: {
    Log::execute(this->_cpu, opCode, "and r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a &= *reg;
    this->setFlagsByLogical(true);
    break;
    }
    case 0xA6: // and (hl)
    Log::execute(this->_cpu, opCode, "and (hl)");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(true);
    break;
    case 0xA8: // xor r
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAF: {
    Log::execute(this->_cpu, opCode, "xor r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a ^= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xAE: // xor (hl)
    Log::execute(this->_cpu, opCode, "xor (hl)");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB0: // or r
    case 0xB1:
    case 0xB2:
    case 0xB3:
    case 0xB4:
    case 0xB5:
    case 0xB7: {
    Log::execute(this->_cpu, opCode, "or r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a |= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xB6: // or (hl)
    Log::execute(this->_cpu, opCode, "or (hl)");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB8: // cp r
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBF:
    Log::execute(this->_cpu, opCode, "cp r");
    this->setFlagsBySubtract(this->_cpu->registers.a, *(this->targetRegister(opCode, 0)), 0);
    break;
    case 0xBE: { // cp (hl)
    Log::execute(this->_cpu, opCode, "cp (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    break;
    }
    case 0xC0: // ret nz
    Log::execute(this->_cpu, opCode, "ret nz");
    if (!this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC1: // pop bc
    Log::execute(this->_cpu, opCode, "pop bc");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xC2: // jp nz, nn
    Log::execute(this->_cpu, opCode, "jp nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC3: // jp nn
    Log::execute(this->_cpu, opCode, "jp nn");
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    break;
    case 0xC4: // call nz, nn
    Log::execute(this->_cpu, opCode, "call nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC5: // push bc
    Log::execute(this->_cpu, opCode, "push bc");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.b);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.c);
    Log::dump_registers(this->_cpu);
    break;
    case 0xC6: { // add a, n
    Log::execute(this->_cpu, opCode, "add a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0xC7: // rst n (n = 0 - 7)
    case 0xCF:
    case 0xD7:
    case 0xDF:
    case 0xE7:
    case 0xEF:
    case 0xF7:
    case 0xFF:
    Log::execute(this->_cpu, opCode, "rst n (n = 0 - 7)");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc & 0xff);
    this->_cpu->special_registers.pc = (opCode & 0b00111000);
    break;
    case 0xC8: // ret z
    Log::execute(this->_cpu, opCode, "ret z");
    if (this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC9: // ret
    Log::execute(this->_cpu, opCode, "ret");
    executeRet();
    break;
    case 0xCA: // jp z, nn
    Log::execute(this->_cpu, opCode, "jp z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCB: { // BITS
    Log::execute(this->_cpu, opCode, "BITS");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeCb(opcode);
    break;
    }
    case 0xCC: // call z, nn
    Log::execute(this->_cpu, opCode, "call z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCD: { // call nn
    Log::execute(this->_cpu, opCode, "call nn");
    this->executeCall();
    break;
    }
    case 0xCE: { // adc a, n
    Log::execute(this->_cpu, opCode, "adc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0xD0: // ret nc
    Log::execute(this->_cpu, opCode, "ret nc");
    if (!this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD1: // pop de
    Log::execute(this->_cpu, opCode, "pop de");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xD2: // jp nc, nn
    Log::execute(this->_cpu, opCode, "jp nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD3: { // out (n),a
    Log::execute(this->_cpu, opCode, "out (n),a");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc += 1;
    Mcycle::out(this->_cpu, port, this->_cpu->registers.a, this->_cpu->registers.a);
    break;
    }
    case 0xD4: // call nc, nn
    Log::execute(this->_cpu, opCode, "call nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD5: // push de
    Log::execute(this->_cpu, opCode, "push de");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.d);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.e);
    Log::dump_registers(this->_cpu);
    break;
    case 0xD6: { // sub n
    Log::execute(this->_cpu, opCode, "sub n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0xD8: // ret c
    Log::execute(this->_cpu, opCode, "ret c");
    if (this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD9: { // exx
    Log::execute(this->_cpu, opCode, "exx");
    uint16_t temp;
    temp = this->_cpu->registers.bc();
    this->_cpu->registers.bc(this->_cpu->registers_alternate.bc());
    this->_cpu->registers_alternate.bc(temp);
    temp = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers_alternate.de());
    this->_cpu->registers_alternate.de(temp);
    temp = this->_cpu->registers.hl();
    this->_cpu->registers.hl(this->_cpu->registers_alternate.hl());
    this->_cpu->registers_alternate.hl(temp);
    break;
    }
    case 0xDA: // jp c, nn
    Log::execute(this->_cpu, opCode, "jp c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDB: { // in a, (n)
    Log::execute(this->_cpu, opCode, "in a, (n)");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->registers.a = Mcycle::in(this->_cpu, port, this->_cpu->registers.a);
    break;
    }
    case 0xDC: // call c, nn
    Log::execute(this->_cpu, opCode, "call c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDD: { // IX
    Log::execute(this->_cpu, opCode, "IX");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeDd(opcode);
    break;
    }
    case 0xDE: { // sbc a, n
    Log::execute(this->_cpu, opCode, "sbc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xE0: // ret po
    Log::execute(this->_cpu, opCode, "ret po");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    executeRet();
    }
    break;
    case 0xE1: // pop hl
    Log::execute(this->_cpu, opCode, "pop hl");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8)
    );
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xE2: // jp po, nn
    Log::execute(this->_cpu, opCode, "jp po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE3: { // ex (sp), hl
    Log::execute(this->_cpu, opCode, "ex (sp), hl");
    uint16_t mem_value =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8);
    uint16_t temp_hl = this->_cpu->registers.hl();
    this->_cpu->registers.hl(mem_value);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, temp_hl & 0xff);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp + 1, temp_hl >> 8);
    break;
    }
    case 0xE4: // call po, nn
    Log::execute(this->_cpu, opCode, "call po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE5: // push hl
    Log::execute(this->_cpu, opCode, "push hl");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() & 0xff);
    Log::dump_registers(this->_cpu);
    break;
    case 0xE6: // and n
    Log::execute(this->_cpu, opCode, "and n");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(true);
    break;
    case 0xE8: // ret pe
    Log::execute(this->_cpu, opCode, "ret pe");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    executeRet();
    }
    break;
    case 0xE9: // jp (hl)
    Log::execute(this->_cpu, opCode, "jp (hl)");
    this->_cpu->special_registers.pc = this->_cpu->registers.hl();
    break;
    case 0xEA: // jp pe, nn
    Log::execute(this->_cpu, opCode, "jp pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xEB: { // ex de,hl
    Log::execute(this->_cpu, opCode, "ex de,hl");
    uint16_t de = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers.hl());
    this->_cpu->registers.hl(de);
    break;
    }
    case 0xEC: // call pe, nn
    Log::execute(this->_cpu, opCode, "call pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xED: { // EXTD
    Log::execute(this->_cpu, opCode, "EXTD");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeEd(opcode);
    break;
    }
    case 0xEE: // xor n
    Log::execute(this->_cpu, opCode, "xor n");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF0: // ret p
    Log::execute(this->_cpu, opCode, "ret p");
    if (! this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF1: // pop af
    Log::execute(this->_cpu, opCode, "pop af");
    this->_cpu->registers.f(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp));
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xF2: // jp p, nn
    Log::execute(this->_cpu, opCode, "jp p, nn");
    if (! this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF3: // di
    Log::execute(this->_cpu, opCode, "di");
    this->_cpu->waitingDI = 1;
    break;
    case 0xF4: // call p, nn
    Log::execute(this->_cpu, opCode, "call p, nn");
    if (! this->_cpu->registers.FS_Sign) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF5: // push af
    Log::execute(this->_cpu, opCode, "push af");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.a);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.f());
    Log::dump_registers(this->_cpu);
    break;
    case 0xF6: // or n
    Log::execute(this->_cpu, opCode, "or n");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF8: // ret m
    Log::execute(this->_cpu, opCode, "ret m");
    if (this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF9: // ld sp,hl
    Log::execute(this->_cpu, opCode, "ld sp,hl");
    this->_cpu->special_registers.sp = this->_cpu->registers.hl();
    break;
    case 0xFA: // jp m, nn
    Log::execute(this->_cpu, opCode, "jp m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFB: // ei
    Log::execute(this->_cpu, opCode, "ei");
    this->_cpu->waitingEI = 2;
    break;
    case 0xFC: // call m, nn
    Log::execute(this->_cpu, opCode, "call m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFD: { // IY
    Log::execute(this->_cpu, opCode, "IY");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeFd(opcode);
    break;
    }
    case 0xFE: { // cp n
    Log::execute(this->_cpu, opCode, "cp n");
    this->setFlagsBySubtract(this->_cpu->registers.a, Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc), 0);
    this->_cpu->special_registers.pc++;
    break;
    }
    default:
    char error[100];
    sprintf(error, "Invalid op code: %02x", opCode);
    Log::error(this->_cpu, error);
    throw std::runtime_error(error);
    }
    }

    View full-size slide

  131. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令を実装する
    • 左のリストはZ80の命令 0x00 〜 0xff まで
    • 256個の case 文 1,300行ぐらい
    • 実際は少し工夫してるのでもう少し少ない
    • 工夫しない方が速いことも
    30
    void OpCode::execute(uint8_t opCode){
    if ((opCode >> 6) == 0b01 && (opCode & 0b00111000) != 0b00110000 && (opCode & 0b00000111) != 0b00000110){
    // ld r, r'
    Log::execute(this->_cpu, opCode, "ld r, r'");
    uint8_t *reg = this->targetRegister(opCode, 3);
    uint8_t *reg_dash = this->targetRegister(opCode, 0);
    *reg = *reg_dash;
    Log::dump_registers(this->_cpu);
    return;
    }
    switch (opCode){
    case 0x00: // nop
    Log::execute(this->_cpu, opCode, "nop");
    break;
    case 0x01: // ld bc, nn
    Log::execute(this->_cpu, opCode, "ld bc, nn");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x02: { // ld (bc), a
    Log::execute(this->_cpu, opCode, "ld (bc), a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.bc(), this->_cpu->registers.a);
    break;
    }
    case 0x03: // inc bc
    Log::execute(this->_cpu, opCode, "inc bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() + 1);
    break;
    case 0x04: // inc r
    case 0x0C:
    case 0x14:
    case 0x1C:
    case 0x24:
    case 0x2C:
    case 0x3C: {
    Log::execute(this->_cpu, opCode, "inc r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByIncrement(*reg);
    (*reg)++;
    break;
    }
    case 0x05: // dec r
    case 0x0D:
    case 0x15:
    case 0x1D:
    case 0x25:
    case 0x2D:
    case 0x3D: {
    Log::execute(this->_cpu, opCode, "dec r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByDecrement(*reg);
    (*reg)--;
    break;
    }
    case 0x06: // ld r, n
    case 0x0e:
    case 0x16:
    case 0x1e:
    case 0x26:
    case 0x2e:
    case 0x3e: {
    Log::execute(this->_cpu, opCode, "ld r, n");
    uint8_t* reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    break;
    }
    case 0x07: { // rlca
    Log::execute(this->_cpu, opCode, "rlca");
    bool carry_bit = (this->_cpu->registers.a >> 7);
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_bit;
    this->_cpu->registers.FC_Carry = carry_bit;
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    break;
    }
    case 0x08: { // ex af, af'
    Log::execute(this->_cpu, opCode, "ex af, af'");
    uint16_t af = this->_cpu->registers.af();
    this->_cpu->registers.af(this->_cpu->registers_alternate.af());
    this->_cpu->registers_alternate.af(af);
    break;
    }
    case 0x09: // add hl, rr
    case 0x19:
    case 0x29:
    case 0x39: {
    Log::execute(this->_cpu, opCode, "add hl, rr");
    uint16_t value;
    switch (opCode){ // NOLINT(hicpp-multiway-paths-covered)
    case 0x09: value = this->_cpu->registers.bc(); break;
    case 0x19: value = this->_cpu->registers.de(); break;
    case 0x29: value = this->_cpu->registers.hl(); break;
    case 0x39: value = this->_cpu->special_registers.sp; break;
    }
    this->setFlagsByAdd16(this->_cpu->registers.hl(), value);
    this->_cpu->registers.hl(this->_cpu->registers.hl() + value);
    break;
    }
    case 0x0A: // ld a,(bc)
    Log::execute(this->_cpu, opCode, "ld a,(bc)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.bc());
    break;
    case 0x0B: // dec bc
    Log::execute(this->_cpu, opCode, "dec bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() - 1);
    break;
    case 0x0F: { // rrca
    Log::execute(this->_cpu, opCode, "rrca");
    bool carry_bit = ((this->_cpu->registers.a & 1) > 0);
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) + ((this->_cpu->registers.a & 1) << 7);
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FC_Carry = carry_bit;
    break;
    }
    case 0x10: { // djnz n
    Log::execute(this->_cpu, opCode, "djnz n");
    this->_cpu->registers.b--;
    if (this->_cpu->registers.b != 0){
    auto diff = (int8_t)Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    }
    case 0x11: // ld de, nn
    Log::execute(this->_cpu, opCode, "ld de, nn");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x12: // ld (de),a
    Log::execute(this->_cpu, opCode, "ld (de),a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.de(), this->_cpu->registers.a);
    break;
    case 0x13: // inc de
    Log::execute(this->_cpu, opCode, "inc de");
    this->_cpu->registers.de(this->_cpu->registers.de() + 1);
    break;
    case 0x17: { // rla
    Log::execute(this->_cpu, opCode, "rla");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a >> 7;
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_flg;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x18: { // jr n
    Log::execute(this->_cpu, opCode, "jr n");
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    break;
    }
    case 0x1A: // ld a,(de)
    Log::execute(this->_cpu, opCode, "ld a,(de)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.de());
    break;
    case 0x1B: // dec de
    Log::execute(this->_cpu, opCode, "dec de");
    this->_cpu->registers.de(this->_cpu->registers.de() - 1);
    break;
    case 0x1F: { // rra
    Log::execute(this->_cpu, opCode, "rra");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a & 1;
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) | (carry_flg << 7);
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x20: // jr nz, n
    Log::execute(this->_cpu, opCode, "jr nz, n");
    if (! this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x21: // ld hl, nn
    Log::execute(this->_cpu, opCode, "ld hl, nn");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8)
    );
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x22: { // ld (nn), hl
    Log::execute(this->_cpu, opCode, "ld (nn), hl");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.l);
    Mcycle::m3(this->_cpu, addr + 1, this->_cpu->registers.h);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x23: // inc hl
    Log::execute(this->_cpu, opCode, "inc hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() + 1);
    break;
    case 0x27: { // daa
    Log::execute(this->_cpu, opCode, "daa");
    uint8_t cr = 0;
    if ((this->_cpu->registers.a & 0x0f) > 0x09 || this->_cpu->registers.FH_HalfCarry){
    cr += 0x06;
    }
    if (this->_cpu->registers.a > 0x99 || this->_cpu->registers.FC_Carry){
    cr += 0x60;
    this->_cpu->registers.FC_Carry = true;
    }
    if (this->_cpu->registers.FN_Subtract){
    this->_cpu->registers.FH_HalfCarry =
    this->_cpu->registers.FH_HalfCarry &&
    (this->_cpu->registers.a & 0x0f) < 0x06;
    this->_cpu->registers.a -= cr;
    } else {
    this->_cpu->registers.FH_HalfCarry = (this->_cpu->registers.a & 0x0f) > 0x09;
    this->_cpu->registers.a += cr;
    }
    this->_cpu->registers.FS_Sign = this->_cpu->registers.a >> 7;
    this->_cpu->registers.FZ_Zero = this->_cpu->registers.a == 0;
    this->_cpu->registers.FPV_ParityOverflow = (OpCode::count1(this->_cpu->registers.a) % 2 == 0);
    break;
    }
    case 0x28: // jr z, n
    Log::execute(this->_cpu, opCode, "jr z, n");
    if (this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x2A: { // ld hl, (nn)
    Log::execute(this->_cpu, opCode, "ld hl, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.l = Mcycle::m2(this->_cpu, addr);
    this->_cpu->registers.h = Mcycle::m2(this->_cpu, addr + 1);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x2B: // dec hl
    Log::execute(this->_cpu, opCode, "dec hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() - 1);
    break;
    case 0x2F: // cpl
    Log::execute(this->_cpu, opCode, "cpl");
    this->_cpu->registers.a ^= 0xff;
    this->_cpu->registers.FN_Subtract = true;
    this->_cpu->registers.FH_HalfCarry = true;
    break;
    case 0x30: // jr nc, n
    Log::execute(this->_cpu, opCode, "jr nc, n");
    if (!this->_cpu->registers.FC_Carry){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x31: // ld sp, nn
    Log::execute(this->_cpu, opCode, "ld sp, nn");
    this->_cpu->special_registers.sp =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x32: { // ld (nn), a
    Log::execute(this->_cpu, opCode, "ld (nn), a");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.a);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x33: // inc sp
    Log::execute(this->_cpu, opCode, "inc sp");
    this->_cpu->special_registers.sp++;
    break;
    case 0x34: { // inc (hl)
    Log::execute(this->_cpu, opCode, "inc (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByIncrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value + 1);
    break;
    }
    case 0x35: { // dec (hl)
    Log::execute(this->_cpu, opCode, "dec (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByDecrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value - 1);
    break;
    }
    case 0x36: // ld (hl), n
    Log::execute(this->_cpu, opCode, "ld (hl), n");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    break;
    case 0x37: // scf
    Log::execute(this->_cpu, opCode, "scf");
    this->_cpu->registers.FC_Carry = true;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    case 0x38: // jr c, n
    Log::execute(this->_cpu, opCode, "jr c, n");
    if (this->_cpu->registers.FC_Carry) {
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x3A: { // ld a, (nn)
    Log::execute(this->_cpu, opCode, "ld a, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, addr);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x3B: // dec sp
    Log::execute(this->_cpu, opCode, "dec sp");
    this->_cpu->special_registers.sp--;
    break;
    case 0x3F: { // ccf
    Log::execute(this->_cpu, opCode, "ccf");
    bool saved_carry = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = !this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = saved_carry;
    break;
    }
    case 0x46: // ld r, (hl)
    case 0x4E:
    case 0x56:
    case 0x5E:
    case 0x66:
    case 0x6E: {
    Log::execute(this->_cpu, opCode, "ld r, (hl)");
    uint8_t *reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    }
    case 0x70: // ld (hl), r
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x77:
    Log::execute(this->_cpu, opCode, "ld (hl), r");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), *(this->targetRegister(opCode, 0)));
    break;
    case 0x76: // halt
    Log::execute(this->_cpu, opCode, "halt");
    this->_cpu->halt = true;
    break;
    case 0x7E: // ld a,(hl)
    Log::execute(this->_cpu, opCode, "ld a,(hl)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    case 0x80: // add a, r
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x87: {
    Log::execute(this->_cpu, opCode, "add a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a += *reg;
    break;
    }
    case 0x86: { // add a, (hl)
    Log::execute(this->_cpu, opCode, "add a, (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0x88: // adc a, r
    case 0x89:
    case 0x8A:
    case 0x8B:
    case 0x8C:
    case 0x8D:
    case 0x8F: {
    Log::execute(this->_cpu, opCode, "adc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a += *reg + carry;
    break;
    }
    case 0x8E: { // adc a, (hl)
    Log::execute(this->_cpu, opCode, "adc a, (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0x90: // sub r
    case 0x91:
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x97: {
    Log::execute(this->_cpu, opCode, "sub r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a -= *reg;
    break;
    }
    case 0x96: { // sub (hl)
    Log::execute(this->_cpu, opCode, "sub (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0x98: // sbc a, r
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9F: {
    Log::execute(this->_cpu, opCode, "sbc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a -= *reg + carry;
    break;
    }
    case 0x9E: { // sbc a,(hl)
    Log::execute(this->_cpu, opCode, "sbc a,(hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xA0: // and r
    case 0xA1:
    case 0xA2:
    case 0xA3:
    case 0xA4:
    case 0xA5:
    case 0xA7: {
    Log::execute(this->_cpu, opCode, "and r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a &= *reg;
    this->setFlagsByLogical(true);
    break;
    }
    case 0xA6: // and (hl)
    Log::execute(this->_cpu, opCode, "and (hl)");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(true);
    break;
    case 0xA8: // xor r
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAF: {
    Log::execute(this->_cpu, opCode, "xor r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a ^= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xAE: // xor (hl)
    Log::execute(this->_cpu, opCode, "xor (hl)");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB0: // or r
    case 0xB1:
    case 0xB2:
    case 0xB3:
    case 0xB4:
    case 0xB5:
    case 0xB7: {
    Log::execute(this->_cpu, opCode, "or r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a |= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xB6: // or (hl)
    Log::execute(this->_cpu, opCode, "or (hl)");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB8: // cp r
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBF:
    Log::execute(this->_cpu, opCode, "cp r");
    this->setFlagsBySubtract(this->_cpu->registers.a, *(this->targetRegister(opCode, 0)), 0);
    break;
    case 0xBE: { // cp (hl)
    Log::execute(this->_cpu, opCode, "cp (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    break;
    }
    case 0xC0: // ret nz
    Log::execute(this->_cpu, opCode, "ret nz");
    if (!this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC1: // pop bc
    Log::execute(this->_cpu, opCode, "pop bc");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xC2: // jp nz, nn
    Log::execute(this->_cpu, opCode, "jp nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC3: // jp nn
    Log::execute(this->_cpu, opCode, "jp nn");
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    break;
    case 0xC4: // call nz, nn
    Log::execute(this->_cpu, opCode, "call nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC5: // push bc
    Log::execute(this->_cpu, opCode, "push bc");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.b);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.c);
    Log::dump_registers(this->_cpu);
    break;
    case 0xC6: { // add a, n
    Log::execute(this->_cpu, opCode, "add a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0xC7: // rst n (n = 0 - 7)
    case 0xCF:
    case 0xD7:
    case 0xDF:
    case 0xE7:
    case 0xEF:
    case 0xF7:
    case 0xFF:
    Log::execute(this->_cpu, opCode, "rst n (n = 0 - 7)");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc & 0xff);
    this->_cpu->special_registers.pc = (opCode & 0b00111000);
    break;
    case 0xC8: // ret z
    Log::execute(this->_cpu, opCode, "ret z");
    if (this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC9: // ret
    Log::execute(this->_cpu, opCode, "ret");
    executeRet();
    break;
    case 0xCA: // jp z, nn
    Log::execute(this->_cpu, opCode, "jp z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCB: { // BITS
    Log::execute(this->_cpu, opCode, "BITS");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeCb(opcode);
    break;
    }
    case 0xCC: // call z, nn
    Log::execute(this->_cpu, opCode, "call z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCD: { // call nn
    Log::execute(this->_cpu, opCode, "call nn");
    this->executeCall();
    break;
    }
    case 0xCE: { // adc a, n
    Log::execute(this->_cpu, opCode, "adc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0xD0: // ret nc
    Log::execute(this->_cpu, opCode, "ret nc");
    if (!this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD1: // pop de
    Log::execute(this->_cpu, opCode, "pop de");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xD2: // jp nc, nn
    Log::execute(this->_cpu, opCode, "jp nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD3: { // out (n),a
    Log::execute(this->_cpu, opCode, "out (n),a");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc += 1;
    Mcycle::out(this->_cpu, port, this->_cpu->registers.a, this->_cpu->registers.a);
    break;
    }
    case 0xD4: // call nc, nn
    Log::execute(this->_cpu, opCode, "call nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD5: // push de
    Log::execute(this->_cpu, opCode, "push de");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.d);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.e);
    Log::dump_registers(this->_cpu);
    break;
    case 0xD6: { // sub n
    Log::execute(this->_cpu, opCode, "sub n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0xD8: // ret c
    Log::execute(this->_cpu, opCode, "ret c");
    if (this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD9: { // exx
    Log::execute(this->_cpu, opCode, "exx");
    uint16_t temp;
    temp = this->_cpu->registers.bc();
    this->_cpu->registers.bc(this->_cpu->registers_alternate.bc());
    this->_cpu->registers_alternate.bc(temp);
    temp = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers_alternate.de());
    this->_cpu->registers_alternate.de(temp);
    temp = this->_cpu->registers.hl();
    this->_cpu->registers.hl(this->_cpu->registers_alternate.hl());
    this->_cpu->registers_alternate.hl(temp);
    break;
    }
    case 0xDA: // jp c, nn
    Log::execute(this->_cpu, opCode, "jp c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDB: { // in a, (n)
    Log::execute(this->_cpu, opCode, "in a, (n)");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->registers.a = Mcycle::in(this->_cpu, port, this->_cpu->registers.a);
    break;
    }
    case 0xDC: // call c, nn
    Log::execute(this->_cpu, opCode, "call c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDD: { // IX
    Log::execute(this->_cpu, opCode, "IX");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeDd(opcode);
    break;
    }
    case 0xDE: { // sbc a, n
    Log::execute(this->_cpu, opCode, "sbc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xE0: // ret po
    Log::execute(this->_cpu, opCode, "ret po");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    executeRet();
    }
    break;
    case 0xE1: // pop hl
    Log::execute(this->_cpu, opCode, "pop hl");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8)
    );
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xE2: // jp po, nn
    Log::execute(this->_cpu, opCode, "jp po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE3: { // ex (sp), hl
    Log::execute(this->_cpu, opCode, "ex (sp), hl");
    uint16_t mem_value =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8);
    uint16_t temp_hl = this->_cpu->registers.hl();
    this->_cpu->registers.hl(mem_value);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, temp_hl & 0xff);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp + 1, temp_hl >> 8);
    break;
    }
    case 0xE4: // call po, nn
    Log::execute(this->_cpu, opCode, "call po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE5: // push hl
    Log::execute(this->_cpu, opCode, "push hl");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() & 0xff);
    Log::dump_registers(this->_cpu);
    break;
    case 0xE6: // and n
    Log::execute(this->_cpu, opCode, "and n");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(true);
    break;
    case 0xE8: // ret pe
    Log::execute(this->_cpu, opCode, "ret pe");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    executeRet();
    }
    break;
    case 0xE9: // jp (hl)
    Log::execute(this->_cpu, opCode, "jp (hl)");
    this->_cpu->special_registers.pc = this->_cpu->registers.hl();
    break;
    case 0xEA: // jp pe, nn
    Log::execute(this->_cpu, opCode, "jp pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xEB: { // ex de,hl
    Log::execute(this->_cpu, opCode, "ex de,hl");
    uint16_t de = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers.hl());
    this->_cpu->registers.hl(de);
    break;
    }
    case 0xEC: // call pe, nn
    Log::execute(this->_cpu, opCode, "call pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xED: { // EXTD
    Log::execute(this->_cpu, opCode, "EXTD");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeEd(opcode);
    break;
    }
    case 0xEE: // xor n
    Log::execute(this->_cpu, opCode, "xor n");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF0: // ret p
    Log::execute(this->_cpu, opCode, "ret p");
    if (! this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF1: // pop af
    Log::execute(this->_cpu, opCode, "pop af");
    this->_cpu->registers.f(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp));
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xF2: // jp p, nn
    Log::execute(this->_cpu, opCode, "jp p, nn");
    if (! this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF3: // di
    Log::execute(this->_cpu, opCode, "di");
    this->_cpu->waitingDI = 1;
    break;
    case 0xF4: // call p, nn
    Log::execute(this->_cpu, opCode, "call p, nn");
    if (! this->_cpu->registers.FS_Sign) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF5: // push af
    Log::execute(this->_cpu, opCode, "push af");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.a);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.f());
    Log::dump_registers(this->_cpu);
    break;
    case 0xF6: // or n
    Log::execute(this->_cpu, opCode, "or n");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF8: // ret m
    Log::execute(this->_cpu, opCode, "ret m");
    if (this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF9: // ld sp,hl
    Log::execute(this->_cpu, opCode, "ld sp,hl");
    this->_cpu->special_registers.sp = this->_cpu->registers.hl();
    break;
    case 0xFA: // jp m, nn
    Log::execute(this->_cpu, opCode, "jp m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFB: // ei
    Log::execute(this->_cpu, opCode, "ei");
    this->_cpu->waitingEI = 2;
    break;
    case 0xFC: // call m, nn
    Log::execute(this->_cpu, opCode, "call m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFD: { // IY
    Log::execute(this->_cpu, opCode, "IY");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeFd(opcode);
    break;
    }
    case 0xFE: { // cp n
    Log::execute(this->_cpu, opCode, "cp n");
    this->setFlagsBySubtract(this->_cpu->registers.a, Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc), 0);
    this->_cpu->special_registers.pc++;
    break;
    }
    default:
    char error[100];
    sprintf(error, "Invalid op code: %02x", opCode);
    Log::error(this->_cpu, error);
    throw std::runtime_error(error);
    }
    }

    View full-size slide

  132. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令を実装する
    • 左のリストはZ80の命令 0x00 〜 0xff まで
    • 256個の case 文 1,300行ぐらい
    • 実際は少し工夫してるのでもう少し少ない
    • 工夫しない方が速いことも
    • 全命令だと3,000行弱
    30
    void OpCode::execute(uint8_t opCode){
    if ((opCode >> 6) == 0b01 && (opCode & 0b00111000) != 0b00110000 && (opCode & 0b00000111) != 0b00000110){
    // ld r, r'
    Log::execute(this->_cpu, opCode, "ld r, r'");
    uint8_t *reg = this->targetRegister(opCode, 3);
    uint8_t *reg_dash = this->targetRegister(opCode, 0);
    *reg = *reg_dash;
    Log::dump_registers(this->_cpu);
    return;
    }
    switch (opCode){
    case 0x00: // nop
    Log::execute(this->_cpu, opCode, "nop");
    break;
    case 0x01: // ld bc, nn
    Log::execute(this->_cpu, opCode, "ld bc, nn");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x02: { // ld (bc), a
    Log::execute(this->_cpu, opCode, "ld (bc), a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.bc(), this->_cpu->registers.a);
    break;
    }
    case 0x03: // inc bc
    Log::execute(this->_cpu, opCode, "inc bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() + 1);
    break;
    case 0x04: // inc r
    case 0x0C:
    case 0x14:
    case 0x1C:
    case 0x24:
    case 0x2C:
    case 0x3C: {
    Log::execute(this->_cpu, opCode, "inc r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByIncrement(*reg);
    (*reg)++;
    break;
    }
    case 0x05: // dec r
    case 0x0D:
    case 0x15:
    case 0x1D:
    case 0x25:
    case 0x2D:
    case 0x3D: {
    Log::execute(this->_cpu, opCode, "dec r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByDecrement(*reg);
    (*reg)--;
    break;
    }
    case 0x06: // ld r, n
    case 0x0e:
    case 0x16:
    case 0x1e:
    case 0x26:
    case 0x2e:
    case 0x3e: {
    Log::execute(this->_cpu, opCode, "ld r, n");
    uint8_t* reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    break;
    }
    case 0x07: { // rlca
    Log::execute(this->_cpu, opCode, "rlca");
    bool carry_bit = (this->_cpu->registers.a >> 7);
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_bit;
    this->_cpu->registers.FC_Carry = carry_bit;
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    break;
    }
    case 0x08: { // ex af, af'
    Log::execute(this->_cpu, opCode, "ex af, af'");
    uint16_t af = this->_cpu->registers.af();
    this->_cpu->registers.af(this->_cpu->registers_alternate.af());
    this->_cpu->registers_alternate.af(af);
    break;
    }
    case 0x09: // add hl, rr
    case 0x19:
    case 0x29:
    case 0x39: {
    Log::execute(this->_cpu, opCode, "add hl, rr");
    uint16_t value;
    switch (opCode){ // NOLINT(hicpp-multiway-paths-covered)
    case 0x09: value = this->_cpu->registers.bc(); break;
    case 0x19: value = this->_cpu->registers.de(); break;
    case 0x29: value = this->_cpu->registers.hl(); break;
    case 0x39: value = this->_cpu->special_registers.sp; break;
    }
    this->setFlagsByAdd16(this->_cpu->registers.hl(), value);
    this->_cpu->registers.hl(this->_cpu->registers.hl() + value);
    break;
    }
    case 0x0A: // ld a,(bc)
    Log::execute(this->_cpu, opCode, "ld a,(bc)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.bc());
    break;
    case 0x0B: // dec bc
    Log::execute(this->_cpu, opCode, "dec bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() - 1);
    break;
    case 0x0F: { // rrca
    Log::execute(this->_cpu, opCode, "rrca");
    bool carry_bit = ((this->_cpu->registers.a & 1) > 0);
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) + ((this->_cpu->registers.a & 1) << 7);
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FC_Carry = carry_bit;
    break;
    }
    case 0x10: { // djnz n
    Log::execute(this->_cpu, opCode, "djnz n");
    this->_cpu->registers.b--;
    if (this->_cpu->registers.b != 0){
    auto diff = (int8_t)Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    }
    case 0x11: // ld de, nn
    Log::execute(this->_cpu, opCode, "ld de, nn");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x12: // ld (de),a
    Log::execute(this->_cpu, opCode, "ld (de),a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.de(), this->_cpu->registers.a);
    break;
    case 0x13: // inc de
    Log::execute(this->_cpu, opCode, "inc de");
    this->_cpu->registers.de(this->_cpu->registers.de() + 1);
    break;
    case 0x17: { // rla
    Log::execute(this->_cpu, opCode, "rla");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a >> 7;
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_flg;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x18: { // jr n
    Log::execute(this->_cpu, opCode, "jr n");
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    break;
    }
    case 0x1A: // ld a,(de)
    Log::execute(this->_cpu, opCode, "ld a,(de)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.de());
    break;
    case 0x1B: // dec de
    Log::execute(this->_cpu, opCode, "dec de");
    this->_cpu->registers.de(this->_cpu->registers.de() - 1);
    break;
    case 0x1F: { // rra
    Log::execute(this->_cpu, opCode, "rra");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a & 1;
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) | (carry_flg << 7);
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x20: // jr nz, n
    Log::execute(this->_cpu, opCode, "jr nz, n");
    if (! this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x21: // ld hl, nn
    Log::execute(this->_cpu, opCode, "ld hl, nn");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8)
    );
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x22: { // ld (nn), hl
    Log::execute(this->_cpu, opCode, "ld (nn), hl");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.l);
    Mcycle::m3(this->_cpu, addr + 1, this->_cpu->registers.h);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x23: // inc hl
    Log::execute(this->_cpu, opCode, "inc hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() + 1);
    break;
    case 0x27: { // daa
    Log::execute(this->_cpu, opCode, "daa");
    uint8_t cr = 0;
    if ((this->_cpu->registers.a & 0x0f) > 0x09 || this->_cpu->registers.FH_HalfCarry){
    cr += 0x06;
    }
    if (this->_cpu->registers.a > 0x99 || this->_cpu->registers.FC_Carry){
    cr += 0x60;
    this->_cpu->registers.FC_Carry = true;
    }
    if (this->_cpu->registers.FN_Subtract){
    this->_cpu->registers.FH_HalfCarry =
    this->_cpu->registers.FH_HalfCarry &&
    (this->_cpu->registers.a & 0x0f) < 0x06;
    this->_cpu->registers.a -= cr;
    } else {
    this->_cpu->registers.FH_HalfCarry = (this->_cpu->registers.a & 0x0f) > 0x09;
    this->_cpu->registers.a += cr;
    }
    this->_cpu->registers.FS_Sign = this->_cpu->registers.a >> 7;
    this->_cpu->registers.FZ_Zero = this->_cpu->registers.a == 0;
    this->_cpu->registers.FPV_ParityOverflow = (OpCode::count1(this->_cpu->registers.a) % 2 == 0);
    break;
    }
    case 0x28: // jr z, n
    Log::execute(this->_cpu, opCode, "jr z, n");
    if (this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x2A: { // ld hl, (nn)
    Log::execute(this->_cpu, opCode, "ld hl, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.l = Mcycle::m2(this->_cpu, addr);
    this->_cpu->registers.h = Mcycle::m2(this->_cpu, addr + 1);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x2B: // dec hl
    Log::execute(this->_cpu, opCode, "dec hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() - 1);
    break;
    case 0x2F: // cpl
    Log::execute(this->_cpu, opCode, "cpl");
    this->_cpu->registers.a ^= 0xff;
    this->_cpu->registers.FN_Subtract = true;
    this->_cpu->registers.FH_HalfCarry = true;
    break;
    case 0x30: // jr nc, n
    Log::execute(this->_cpu, opCode, "jr nc, n");
    if (!this->_cpu->registers.FC_Carry){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x31: // ld sp, nn
    Log::execute(this->_cpu, opCode, "ld sp, nn");
    this->_cpu->special_registers.sp =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x32: { // ld (nn), a
    Log::execute(this->_cpu, opCode, "ld (nn), a");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.a);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x33: // inc sp
    Log::execute(this->_cpu, opCode, "inc sp");
    this->_cpu->special_registers.sp++;
    break;
    case 0x34: { // inc (hl)
    Log::execute(this->_cpu, opCode, "inc (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByIncrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value + 1);
    break;
    }
    case 0x35: { // dec (hl)
    Log::execute(this->_cpu, opCode, "dec (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByDecrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value - 1);
    break;
    }
    case 0x36: // ld (hl), n
    Log::execute(this->_cpu, opCode, "ld (hl), n");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    break;
    case 0x37: // scf
    Log::execute(this->_cpu, opCode, "scf");
    this->_cpu->registers.FC_Carry = true;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    case 0x38: // jr c, n
    Log::execute(this->_cpu, opCode, "jr c, n");
    if (this->_cpu->registers.FC_Carry) {
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x3A: { // ld a, (nn)
    Log::execute(this->_cpu, opCode, "ld a, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, addr);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x3B: // dec sp
    Log::execute(this->_cpu, opCode, "dec sp");
    this->_cpu->special_registers.sp--;
    break;
    case 0x3F: { // ccf
    Log::execute(this->_cpu, opCode, "ccf");
    bool saved_carry = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = !this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = saved_carry;
    break;
    }
    case 0x46: // ld r, (hl)
    case 0x4E:
    case 0x56:
    case 0x5E:
    case 0x66:
    case 0x6E: {
    Log::execute(this->_cpu, opCode, "ld r, (hl)");
    uint8_t *reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    }
    case 0x70: // ld (hl), r
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x77:
    Log::execute(this->_cpu, opCode, "ld (hl), r");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), *(this->targetRegister(opCode, 0)));
    break;
    case 0x76: // halt
    Log::execute(this->_cpu, opCode, "halt");
    this->_cpu->halt = true;
    break;
    case 0x7E: // ld a,(hl)
    Log::execute(this->_cpu, opCode, "ld a,(hl)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    case 0x80: // add a, r
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x87: {
    Log::execute(this->_cpu, opCode, "add a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a += *reg;
    break;
    }
    case 0x86: { // add a, (hl)
    Log::execute(this->_cpu, opCode, "add a, (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0x88: // adc a, r
    case 0x89:
    case 0x8A:
    case 0x8B:
    case 0x8C:
    case 0x8D:
    case 0x8F: {
    Log::execute(this->_cpu, opCode, "adc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a += *reg + carry;
    break;
    }
    case 0x8E: { // adc a, (hl)
    Log::execute(this->_cpu, opCode, "adc a, (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0x90: // sub r
    case 0x91:
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x97: {
    Log::execute(this->_cpu, opCode, "sub r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a -= *reg;
    break;
    }
    case 0x96: { // sub (hl)
    Log::execute(this->_cpu, opCode, "sub (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0x98: // sbc a, r
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9F: {
    Log::execute(this->_cpu, opCode, "sbc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a -= *reg + carry;
    break;
    }
    case 0x9E: { // sbc a,(hl)
    Log::execute(this->_cpu, opCode, "sbc a,(hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xA0: // and r
    case 0xA1:
    case 0xA2:
    case 0xA3:
    case 0xA4:
    case 0xA5:
    case 0xA7: {
    Log::execute(this->_cpu, opCode, "and r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a &= *reg;
    this->setFlagsByLogical(true);
    break;
    }
    case 0xA6: // and (hl)
    Log::execute(this->_cpu, opCode, "and (hl)");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(true);
    break;
    case 0xA8: // xor r
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAF: {
    Log::execute(this->_cpu, opCode, "xor r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a ^= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xAE: // xor (hl)
    Log::execute(this->_cpu, opCode, "xor (hl)");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB0: // or r
    case 0xB1:
    case 0xB2:
    case 0xB3:
    case 0xB4:
    case 0xB5:
    case 0xB7: {
    Log::execute(this->_cpu, opCode, "or r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a |= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xB6: // or (hl)
    Log::execute(this->_cpu, opCode, "or (hl)");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB8: // cp r
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBF:
    Log::execute(this->_cpu, opCode, "cp r");
    this->setFlagsBySubtract(this->_cpu->registers.a, *(this->targetRegister(opCode, 0)), 0);
    break;
    case 0xBE: { // cp (hl)
    Log::execute(this->_cpu, opCode, "cp (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    break;
    }
    case 0xC0: // ret nz
    Log::execute(this->_cpu, opCode, "ret nz");
    if (!this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC1: // pop bc
    Log::execute(this->_cpu, opCode, "pop bc");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xC2: // jp nz, nn
    Log::execute(this->_cpu, opCode, "jp nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC3: // jp nn
    Log::execute(this->_cpu, opCode, "jp nn");
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    break;
    case 0xC4: // call nz, nn
    Log::execute(this->_cpu, opCode, "call nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC5: // push bc
    Log::execute(this->_cpu, opCode, "push bc");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.b);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.c);
    Log::dump_registers(this->_cpu);
    break;
    case 0xC6: { // add a, n
    Log::execute(this->_cpu, opCode, "add a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0xC7: // rst n (n = 0 - 7)
    case 0xCF:
    case 0xD7:
    case 0xDF:
    case 0xE7:
    case 0xEF:
    case 0xF7:
    case 0xFF:
    Log::execute(this->_cpu, opCode, "rst n (n = 0 - 7)");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc & 0xff);
    this->_cpu->special_registers.pc = (opCode & 0b00111000);
    break;
    case 0xC8: // ret z
    Log::execute(this->_cpu, opCode, "ret z");
    if (this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC9: // ret
    Log::execute(this->_cpu, opCode, "ret");
    executeRet();
    break;
    case 0xCA: // jp z, nn
    Log::execute(this->_cpu, opCode, "jp z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCB: { // BITS
    Log::execute(this->_cpu, opCode, "BITS");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeCb(opcode);
    break;
    }
    case 0xCC: // call z, nn
    Log::execute(this->_cpu, opCode, "call z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCD: { // call nn
    Log::execute(this->_cpu, opCode, "call nn");
    this->executeCall();
    break;
    }
    case 0xCE: { // adc a, n
    Log::execute(this->_cpu, opCode, "adc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0xD0: // ret nc
    Log::execute(this->_cpu, opCode, "ret nc");
    if (!this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD1: // pop de
    Log::execute(this->_cpu, opCode, "pop de");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xD2: // jp nc, nn
    Log::execute(this->_cpu, opCode, "jp nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD3: { // out (n),a
    Log::execute(this->_cpu, opCode, "out (n),a");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc += 1;
    Mcycle::out(this->_cpu, port, this->_cpu->registers.a, this->_cpu->registers.a);
    break;
    }
    case 0xD4: // call nc, nn
    Log::execute(this->_cpu, opCode, "call nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD5: // push de
    Log::execute(this->_cpu, opCode, "push de");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.d);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.e);
    Log::dump_registers(this->_cpu);
    break;
    case 0xD6: { // sub n
    Log::execute(this->_cpu, opCode, "sub n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0xD8: // ret c
    Log::execute(this->_cpu, opCode, "ret c");
    if (this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD9: { // exx
    Log::execute(this->_cpu, opCode, "exx");
    uint16_t temp;
    temp = this->_cpu->registers.bc();
    this->_cpu->registers.bc(this->_cpu->registers_alternate.bc());
    this->_cpu->registers_alternate.bc(temp);
    temp = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers_alternate.de());
    this->_cpu->registers_alternate.de(temp);
    temp = this->_cpu->registers.hl();
    this->_cpu->registers.hl(this->_cpu->registers_alternate.hl());
    this->_cpu->registers_alternate.hl(temp);
    break;
    }
    case 0xDA: // jp c, nn
    Log::execute(this->_cpu, opCode, "jp c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDB: { // in a, (n)
    Log::execute(this->_cpu, opCode, "in a, (n)");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->registers.a = Mcycle::in(this->_cpu, port, this->_cpu->registers.a);
    break;
    }
    case 0xDC: // call c, nn
    Log::execute(this->_cpu, opCode, "call c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDD: { // IX
    Log::execute(this->_cpu, opCode, "IX");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeDd(opcode);
    break;
    }
    case 0xDE: { // sbc a, n
    Log::execute(this->_cpu, opCode, "sbc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xE0: // ret po
    Log::execute(this->_cpu, opCode, "ret po");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    executeRet();
    }
    break;
    case 0xE1: // pop hl
    Log::execute(this->_cpu, opCode, "pop hl");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8)
    );
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xE2: // jp po, nn
    Log::execute(this->_cpu, opCode, "jp po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE3: { // ex (sp), hl
    Log::execute(this->_cpu, opCode, "ex (sp), hl");
    uint16_t mem_value =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8);
    uint16_t temp_hl = this->_cpu->registers.hl();
    this->_cpu->registers.hl(mem_value);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, temp_hl & 0xff);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp + 1, temp_hl >> 8);
    break;
    }
    case 0xE4: // call po, nn
    Log::execute(this->_cpu, opCode, "call po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE5: // push hl
    Log::execute(this->_cpu, opCode, "push hl");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() & 0xff);
    Log::dump_registers(this->_cpu);
    break;
    case 0xE6: // and n
    Log::execute(this->_cpu, opCode, "and n");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(true);
    break;
    case 0xE8: // ret pe
    Log::execute(this->_cpu, opCode, "ret pe");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    executeRet();
    }
    break;
    case 0xE9: // jp (hl)
    Log::execute(this->_cpu, opCode, "jp (hl)");
    this->_cpu->special_registers.pc = this->_cpu->registers.hl();
    break;
    case 0xEA: // jp pe, nn
    Log::execute(this->_cpu, opCode, "jp pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xEB: { // ex de,hl
    Log::execute(this->_cpu, opCode, "ex de,hl");
    uint16_t de = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers.hl());
    this->_cpu->registers.hl(de);
    break;
    }
    case 0xEC: // call pe, nn
    Log::execute(this->_cpu, opCode, "call pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xED: { // EXTD
    Log::execute(this->_cpu, opCode, "EXTD");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeEd(opcode);
    break;
    }
    case 0xEE: // xor n
    Log::execute(this->_cpu, opCode, "xor n");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF0: // ret p
    Log::execute(this->_cpu, opCode, "ret p");
    if (! this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF1: // pop af
    Log::execute(this->_cpu, opCode, "pop af");
    this->_cpu->registers.f(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp));
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xF2: // jp p, nn
    Log::execute(this->_cpu, opCode, "jp p, nn");
    if (! this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF3: // di
    Log::execute(this->_cpu, opCode, "di");
    this->_cpu->waitingDI = 1;
    break;
    case 0xF4: // call p, nn
    Log::execute(this->_cpu, opCode, "call p, nn");
    if (! this->_cpu->registers.FS_Sign) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF5: // push af
    Log::execute(this->_cpu, opCode, "push af");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.a);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.f());
    Log::dump_registers(this->_cpu);
    break;
    case 0xF6: // or n
    Log::execute(this->_cpu, opCode, "or n");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF8: // ret m
    Log::execute(this->_cpu, opCode, "ret m");
    if (this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF9: // ld sp,hl
    Log::execute(this->_cpu, opCode, "ld sp,hl");
    this->_cpu->special_registers.sp = this->_cpu->registers.hl();
    break;
    case 0xFA: // jp m, nn
    Log::execute(this->_cpu, opCode, "jp m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFB: // ei
    Log::execute(this->_cpu, opCode, "ei");
    this->_cpu->waitingEI = 2;
    break;
    case 0xFC: // call m, nn
    Log::execute(this->_cpu, opCode, "call m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFD: { // IY
    Log::execute(this->_cpu, opCode, "IY");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeFd(opcode);
    break;
    }
    case 0xFE: { // cp n
    Log::execute(this->_cpu, opCode, "cp n");
    this->setFlagsBySubtract(this->_cpu->registers.a, Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc), 0);
    this->_cpu->special_registers.pc++;
    break;
    }
    default:
    char error[100];
    sprintf(error, "Invalid op code: %02x", opCode);
    Log::error(this->_cpu, error);
    throw std::runtime_error(error);
    }
    }

    View full-size slide

  133. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令を実装する
    • 左のリストはZ80の命令 0x00 〜 0xff まで
    • 256個の case 文 1,300行ぐらい
    • 実際は少し工夫してるのでもう少し少ない
    • 工夫しない方が速いことも
    • 全命令だと3,000行弱
    • ひたすら地道に書いた
    30
    void OpCode::execute(uint8_t opCode){
    if ((opCode >> 6) == 0b01 && (opCode & 0b00111000) != 0b00110000 && (opCode & 0b00000111) != 0b00000110){
    // ld r, r'
    Log::execute(this->_cpu, opCode, "ld r, r'");
    uint8_t *reg = this->targetRegister(opCode, 3);
    uint8_t *reg_dash = this->targetRegister(opCode, 0);
    *reg = *reg_dash;
    Log::dump_registers(this->_cpu);
    return;
    }
    switch (opCode){
    case 0x00: // nop
    Log::execute(this->_cpu, opCode, "nop");
    break;
    case 0x01: // ld bc, nn
    Log::execute(this->_cpu, opCode, "ld bc, nn");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x02: { // ld (bc), a
    Log::execute(this->_cpu, opCode, "ld (bc), a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.bc(), this->_cpu->registers.a);
    break;
    }
    case 0x03: // inc bc
    Log::execute(this->_cpu, opCode, "inc bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() + 1);
    break;
    case 0x04: // inc r
    case 0x0C:
    case 0x14:
    case 0x1C:
    case 0x24:
    case 0x2C:
    case 0x3C: {
    Log::execute(this->_cpu, opCode, "inc r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByIncrement(*reg);
    (*reg)++;
    break;
    }
    case 0x05: // dec r
    case 0x0D:
    case 0x15:
    case 0x1D:
    case 0x25:
    case 0x2D:
    case 0x3D: {
    Log::execute(this->_cpu, opCode, "dec r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByDecrement(*reg);
    (*reg)--;
    break;
    }
    case 0x06: // ld r, n
    case 0x0e:
    case 0x16:
    case 0x1e:
    case 0x26:
    case 0x2e:
    case 0x3e: {
    Log::execute(this->_cpu, opCode, "ld r, n");
    uint8_t* reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    break;
    }
    case 0x07: { // rlca
    Log::execute(this->_cpu, opCode, "rlca");
    bool carry_bit = (this->_cpu->registers.a >> 7);
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_bit;
    this->_cpu->registers.FC_Carry = carry_bit;
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    break;
    }
    case 0x08: { // ex af, af'
    Log::execute(this->_cpu, opCode, "ex af, af'");
    uint16_t af = this->_cpu->registers.af();
    this->_cpu->registers.af(this->_cpu->registers_alternate.af());
    this->_cpu->registers_alternate.af(af);
    break;
    }
    case 0x09: // add hl, rr
    case 0x19:
    case 0x29:
    case 0x39: {
    Log::execute(this->_cpu, opCode, "add hl, rr");
    uint16_t value;
    switch (opCode){ // NOLINT(hicpp-multiway-paths-covered)
    case 0x09: value = this->_cpu->registers.bc(); break;
    case 0x19: value = this->_cpu->registers.de(); break;
    case 0x29: value = this->_cpu->registers.hl(); break;
    case 0x39: value = this->_cpu->special_registers.sp; break;
    }
    this->setFlagsByAdd16(this->_cpu->registers.hl(), value);
    this->_cpu->registers.hl(this->_cpu->registers.hl() + value);
    break;
    }
    case 0x0A: // ld a,(bc)
    Log::execute(this->_cpu, opCode, "ld a,(bc)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.bc());
    break;
    case 0x0B: // dec bc
    Log::execute(this->_cpu, opCode, "dec bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() - 1);
    break;
    case 0x0F: { // rrca
    Log::execute(this->_cpu, opCode, "rrca");
    bool carry_bit = ((this->_cpu->registers.a & 1) > 0);
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) + ((this->_cpu->registers.a & 1) << 7);
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FC_Carry = carry_bit;
    break;
    }
    case 0x10: { // djnz n
    Log::execute(this->_cpu, opCode, "djnz n");
    this->_cpu->registers.b--;
    if (this->_cpu->registers.b != 0){
    auto diff = (int8_t)Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    }
    case 0x11: // ld de, nn
    Log::execute(this->_cpu, opCode, "ld de, nn");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x12: // ld (de),a
    Log::execute(this->_cpu, opCode, "ld (de),a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.de(), this->_cpu->registers.a);
    break;
    case 0x13: // inc de
    Log::execute(this->_cpu, opCode, "inc de");
    this->_cpu->registers.de(this->_cpu->registers.de() + 1);
    break;
    case 0x17: { // rla
    Log::execute(this->_cpu, opCode, "rla");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a >> 7;
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_flg;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x18: { // jr n
    Log::execute(this->_cpu, opCode, "jr n");
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    break;
    }
    case 0x1A: // ld a,(de)
    Log::execute(this->_cpu, opCode, "ld a,(de)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.de());
    break;
    case 0x1B: // dec de
    Log::execute(this->_cpu, opCode, "dec de");
    this->_cpu->registers.de(this->_cpu->registers.de() - 1);
    break;
    case 0x1F: { // rra
    Log::execute(this->_cpu, opCode, "rra");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a & 1;
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) | (carry_flg << 7);
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x20: // jr nz, n
    Log::execute(this->_cpu, opCode, "jr nz, n");
    if (! this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x21: // ld hl, nn
    Log::execute(this->_cpu, opCode, "ld hl, nn");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8)
    );
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x22: { // ld (nn), hl
    Log::execute(this->_cpu, opCode, "ld (nn), hl");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.l);
    Mcycle::m3(this->_cpu, addr + 1, this->_cpu->registers.h);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x23: // inc hl
    Log::execute(this->_cpu, opCode, "inc hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() + 1);
    break;
    case 0x27: { // daa
    Log::execute(this->_cpu, opCode, "daa");
    uint8_t cr = 0;
    if ((this->_cpu->registers.a & 0x0f) > 0x09 || this->_cpu->registers.FH_HalfCarry){
    cr += 0x06;
    }
    if (this->_cpu->registers.a > 0x99 || this->_cpu->registers.FC_Carry){
    cr += 0x60;
    this->_cpu->registers.FC_Carry = true;
    }
    if (this->_cpu->registers.FN_Subtract){
    this->_cpu->registers.FH_HalfCarry =
    this->_cpu->registers.FH_HalfCarry &&
    (this->_cpu->registers.a & 0x0f) < 0x06;
    this->_cpu->registers.a -= cr;
    } else {
    this->_cpu->registers.FH_HalfCarry = (this->_cpu->registers.a & 0x0f) > 0x09;
    this->_cpu->registers.a += cr;
    }
    this->_cpu->registers.FS_Sign = this->_cpu->registers.a >> 7;
    this->_cpu->registers.FZ_Zero = this->_cpu->registers.a == 0;
    this->_cpu->registers.FPV_ParityOverflow = (OpCode::count1(this->_cpu->registers.a) % 2 == 0);
    break;
    }
    case 0x28: // jr z, n
    Log::execute(this->_cpu, opCode, "jr z, n");
    if (this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x2A: { // ld hl, (nn)
    Log::execute(this->_cpu, opCode, "ld hl, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.l = Mcycle::m2(this->_cpu, addr);
    this->_cpu->registers.h = Mcycle::m2(this->_cpu, addr + 1);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x2B: // dec hl
    Log::execute(this->_cpu, opCode, "dec hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() - 1);
    break;
    case 0x2F: // cpl
    Log::execute(this->_cpu, opCode, "cpl");
    this->_cpu->registers.a ^= 0xff;
    this->_cpu->registers.FN_Subtract = true;
    this->_cpu->registers.FH_HalfCarry = true;
    break;
    case 0x30: // jr nc, n
    Log::execute(this->_cpu, opCode, "jr nc, n");
    if (!this->_cpu->registers.FC_Carry){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x31: // ld sp, nn
    Log::execute(this->_cpu, opCode, "ld sp, nn");
    this->_cpu->special_registers.sp =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x32: { // ld (nn), a
    Log::execute(this->_cpu, opCode, "ld (nn), a");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.a);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x33: // inc sp
    Log::execute(this->_cpu, opCode, "inc sp");
    this->_cpu->special_registers.sp++;
    break;
    case 0x34: { // inc (hl)
    Log::execute(this->_cpu, opCode, "inc (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByIncrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value + 1);
    break;
    }
    case 0x35: { // dec (hl)
    Log::execute(this->_cpu, opCode, "dec (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByDecrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value - 1);
    break;
    }
    case 0x36: // ld (hl), n
    Log::execute(this->_cpu, opCode, "ld (hl), n");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    break;
    case 0x37: // scf
    Log::execute(this->_cpu, opCode, "scf");
    this->_cpu->registers.FC_Carry = true;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    case 0x38: // jr c, n
    Log::execute(this->_cpu, opCode, "jr c, n");
    if (this->_cpu->registers.FC_Carry) {
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x3A: { // ld a, (nn)
    Log::execute(this->_cpu, opCode, "ld a, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, addr);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x3B: // dec sp
    Log::execute(this->_cpu, opCode, "dec sp");
    this->_cpu->special_registers.sp--;
    break;
    case 0x3F: { // ccf
    Log::execute(this->_cpu, opCode, "ccf");
    bool saved_carry = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = !this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = saved_carry;
    break;
    }
    case 0x46: // ld r, (hl)
    case 0x4E:
    case 0x56:
    case 0x5E:
    case 0x66:
    case 0x6E: {
    Log::execute(this->_cpu, opCode, "ld r, (hl)");
    uint8_t *reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    }
    case 0x70: // ld (hl), r
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x77:
    Log::execute(this->_cpu, opCode, "ld (hl), r");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), *(this->targetRegister(opCode, 0)));
    break;
    case 0x76: // halt
    Log::execute(this->_cpu, opCode, "halt");
    this->_cpu->halt = true;
    break;
    case 0x7E: // ld a,(hl)
    Log::execute(this->_cpu, opCode, "ld a,(hl)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    case 0x80: // add a, r
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x87: {
    Log::execute(this->_cpu, opCode, "add a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a += *reg;
    break;
    }
    case 0x86: { // add a, (hl)
    Log::execute(this->_cpu, opCode, "add a, (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0x88: // adc a, r
    case 0x89:
    case 0x8A:
    case 0x8B:
    case 0x8C:
    case 0x8D:
    case 0x8F: {
    Log::execute(this->_cpu, opCode, "adc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a += *reg + carry;
    break;
    }
    case 0x8E: { // adc a, (hl)
    Log::execute(this->_cpu, opCode, "adc a, (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0x90: // sub r
    case 0x91:
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x97: {
    Log::execute(this->_cpu, opCode, "sub r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a -= *reg;
    break;
    }
    case 0x96: { // sub (hl)
    Log::execute(this->_cpu, opCode, "sub (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0x98: // sbc a, r
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9F: {
    Log::execute(this->_cpu, opCode, "sbc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a -= *reg + carry;
    break;
    }
    case 0x9E: { // sbc a,(hl)
    Log::execute(this->_cpu, opCode, "sbc a,(hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xA0: // and r
    case 0xA1:
    case 0xA2:
    case 0xA3:
    case 0xA4:
    case 0xA5:
    case 0xA7: {
    Log::execute(this->_cpu, opCode, "and r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a &= *reg;
    this->setFlagsByLogical(true);
    break;
    }
    case 0xA6: // and (hl)
    Log::execute(this->_cpu, opCode, "and (hl)");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(true);
    break;
    case 0xA8: // xor r
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAF: {
    Log::execute(this->_cpu, opCode, "xor r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a ^= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xAE: // xor (hl)
    Log::execute(this->_cpu, opCode, "xor (hl)");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB0: // or r
    case 0xB1:
    case 0xB2:
    case 0xB3:
    case 0xB4:
    case 0xB5:
    case 0xB7: {
    Log::execute(this->_cpu, opCode, "or r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a |= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xB6: // or (hl)
    Log::execute(this->_cpu, opCode, "or (hl)");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB8: // cp r
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBF:
    Log::execute(this->_cpu, opCode, "cp r");
    this->setFlagsBySubtract(this->_cpu->registers.a, *(this->targetRegister(opCode, 0)), 0);
    break;
    case 0xBE: { // cp (hl)
    Log::execute(this->_cpu, opCode, "cp (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    break;
    }
    case 0xC0: // ret nz
    Log::execute(this->_cpu, opCode, "ret nz");
    if (!this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC1: // pop bc
    Log::execute(this->_cpu, opCode, "pop bc");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xC2: // jp nz, nn
    Log::execute(this->_cpu, opCode, "jp nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC3: // jp nn
    Log::execute(this->_cpu, opCode, "jp nn");
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    break;
    case 0xC4: // call nz, nn
    Log::execute(this->_cpu, opCode, "call nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC5: // push bc
    Log::execute(this->_cpu, opCode, "push bc");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.b);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.c);
    Log::dump_registers(this->_cpu);
    break;
    case 0xC6: { // add a, n
    Log::execute(this->_cpu, opCode, "add a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0xC7: // rst n (n = 0 - 7)
    case 0xCF:
    case 0xD7:
    case 0xDF:
    case 0xE7:
    case 0xEF:
    case 0xF7:
    case 0xFF:
    Log::execute(this->_cpu, opCode, "rst n (n = 0 - 7)");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc & 0xff);
    this->_cpu->special_registers.pc = (opCode & 0b00111000);
    break;
    case 0xC8: // ret z
    Log::execute(this->_cpu, opCode, "ret z");
    if (this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC9: // ret
    Log::execute(this->_cpu, opCode, "ret");
    executeRet();
    break;
    case 0xCA: // jp z, nn
    Log::execute(this->_cpu, opCode, "jp z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCB: { // BITS
    Log::execute(this->_cpu, opCode, "BITS");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeCb(opcode);
    break;
    }
    case 0xCC: // call z, nn
    Log::execute(this->_cpu, opCode, "call z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCD: { // call nn
    Log::execute(this->_cpu, opCode, "call nn");
    this->executeCall();
    break;
    }
    case 0xCE: { // adc a, n
    Log::execute(this->_cpu, opCode, "adc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0xD0: // ret nc
    Log::execute(this->_cpu, opCode, "ret nc");
    if (!this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD1: // pop de
    Log::execute(this->_cpu, opCode, "pop de");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xD2: // jp nc, nn
    Log::execute(this->_cpu, opCode, "jp nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD3: { // out (n),a
    Log::execute(this->_cpu, opCode, "out (n),a");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc += 1;
    Mcycle::out(this->_cpu, port, this->_cpu->registers.a, this->_cpu->registers.a);
    break;
    }
    case 0xD4: // call nc, nn
    Log::execute(this->_cpu, opCode, "call nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD5: // push de
    Log::execute(this->_cpu, opCode, "push de");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.d);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.e);
    Log::dump_registers(this->_cpu);
    break;
    case 0xD6: { // sub n
    Log::execute(this->_cpu, opCode, "sub n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0xD8: // ret c
    Log::execute(this->_cpu, opCode, "ret c");
    if (this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD9: { // exx
    Log::execute(this->_cpu, opCode, "exx");
    uint16_t temp;
    temp = this->_cpu->registers.bc();
    this->_cpu->registers.bc(this->_cpu->registers_alternate.bc());
    this->_cpu->registers_alternate.bc(temp);
    temp = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers_alternate.de());
    this->_cpu->registers_alternate.de(temp);
    temp = this->_cpu->registers.hl();
    this->_cpu->registers.hl(this->_cpu->registers_alternate.hl());
    this->_cpu->registers_alternate.hl(temp);
    break;
    }
    case 0xDA: // jp c, nn
    Log::execute(this->_cpu, opCode, "jp c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDB: { // in a, (n)
    Log::execute(this->_cpu, opCode, "in a, (n)");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->registers.a = Mcycle::in(this->_cpu, port, this->_cpu->registers.a);
    break;
    }
    case 0xDC: // call c, nn
    Log::execute(this->_cpu, opCode, "call c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDD: { // IX
    Log::execute(this->_cpu, opCode, "IX");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeDd(opcode);
    break;
    }
    case 0xDE: { // sbc a, n
    Log::execute(this->_cpu, opCode, "sbc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xE0: // ret po
    Log::execute(this->_cpu, opCode, "ret po");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    executeRet();
    }
    break;
    case 0xE1: // pop hl
    Log::execute(this->_cpu, opCode, "pop hl");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8)
    );
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xE2: // jp po, nn
    Log::execute(this->_cpu, opCode, "jp po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE3: { // ex (sp), hl
    Log::execute(this->_cpu, opCode, "ex (sp), hl");
    uint16_t mem_value =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8);
    uint16_t temp_hl = this->_cpu->registers.hl();
    this->_cpu->registers.hl(mem_value);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, temp_hl & 0xff);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp + 1, temp_hl >> 8);
    break;
    }
    case 0xE4: // call po, nn
    Log::execute(this->_cpu, opCode, "call po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE5: // push hl
    Log::execute(this->_cpu, opCode, "push hl");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() & 0xff);
    Log::dump_registers(this->_cpu);
    break;
    case 0xE6: // and n
    Log::execute(this->_cpu, opCode, "and n");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(true);
    break;
    case 0xE8: // ret pe
    Log::execute(this->_cpu, opCode, "ret pe");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    executeRet();
    }
    break;
    case 0xE9: // jp (hl)
    Log::execute(this->_cpu, opCode, "jp (hl)");
    this->_cpu->special_registers.pc = this->_cpu->registers.hl();
    break;
    case 0xEA: // jp pe, nn
    Log::execute(this->_cpu, opCode, "jp pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xEB: { // ex de,hl
    Log::execute(this->_cpu, opCode, "ex de,hl");
    uint16_t de = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers.hl());
    this->_cpu->registers.hl(de);
    break;
    }
    case 0xEC: // call pe, nn
    Log::execute(this->_cpu, opCode, "call pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xED: { // EXTD
    Log::execute(this->_cpu, opCode, "EXTD");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeEd(opcode);
    break;
    }
    case 0xEE: // xor n
    Log::execute(this->_cpu, opCode, "xor n");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF0: // ret p
    Log::execute(this->_cpu, opCode, "ret p");
    if (! this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF1: // pop af
    Log::execute(this->_cpu, opCode, "pop af");
    this->_cpu->registers.f(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp));
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xF2: // jp p, nn
    Log::execute(this->_cpu, opCode, "jp p, nn");
    if (! this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF3: // di
    Log::execute(this->_cpu, opCode, "di");
    this->_cpu->waitingDI = 1;
    break;
    case 0xF4: // call p, nn
    Log::execute(this->_cpu, opCode, "call p, nn");
    if (! this->_cpu->registers.FS_Sign) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF5: // push af
    Log::execute(this->_cpu, opCode, "push af");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.a);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.f());
    Log::dump_registers(this->_cpu);
    break;
    case 0xF6: // or n
    Log::execute(this->_cpu, opCode, "or n");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF8: // ret m
    Log::execute(this->_cpu, opCode, "ret m");
    if (this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF9: // ld sp,hl
    Log::execute(this->_cpu, opCode, "ld sp,hl");
    this->_cpu->special_registers.sp = this->_cpu->registers.hl();
    break;
    case 0xFA: // jp m, nn
    Log::execute(this->_cpu, opCode, "jp m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFB: // ei
    Log::execute(this->_cpu, opCode, "ei");
    this->_cpu->waitingEI = 2;
    break;
    case 0xFC: // call m, nn
    Log::execute(this->_cpu, opCode, "call m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFD: { // IY
    Log::execute(this->_cpu, opCode, "IY");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeFd(opcode);
    break;
    }
    case 0xFE: { // cp n
    Log::execute(this->_cpu, opCode, "cp n");
    this->setFlagsBySubtract(this->_cpu->registers.a, Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc), 0);
    this->_cpu->special_registers.pc++;
    break;
    }
    default:
    char error[100];
    sprintf(error, "Invalid op code: %02x", opCode);
    Log::error(this->_cpu, error);
    throw std::runtime_error(error);
    }
    }

    View full-size slide

  134. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令を実装する
    • 左のリストはZ80の命令 0x00 〜 0xff まで
    • 256個の case 文 1,300行ぐらい
    • 実際は少し工夫してるのでもう少し少ない
    • 工夫しない方が速いことも
    • 全命令だと3,000行弱
    • ひたすら地道に書いた
    • これからやる方はイチから書くのはお勧めしない
    30
    void OpCode::execute(uint8_t opCode){
    if ((opCode >> 6) == 0b01 && (opCode & 0b00111000) != 0b00110000 && (opCode & 0b00000111) != 0b00000110){
    // ld r, r'
    Log::execute(this->_cpu, opCode, "ld r, r'");
    uint8_t *reg = this->targetRegister(opCode, 3);
    uint8_t *reg_dash = this->targetRegister(opCode, 0);
    *reg = *reg_dash;
    Log::dump_registers(this->_cpu);
    return;
    }
    switch (opCode){
    case 0x00: // nop
    Log::execute(this->_cpu, opCode, "nop");
    break;
    case 0x01: // ld bc, nn
    Log::execute(this->_cpu, opCode, "ld bc, nn");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x02: { // ld (bc), a
    Log::execute(this->_cpu, opCode, "ld (bc), a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.bc(), this->_cpu->registers.a);
    break;
    }
    case 0x03: // inc bc
    Log::execute(this->_cpu, opCode, "inc bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() + 1);
    break;
    case 0x04: // inc r
    case 0x0C:
    case 0x14:
    case 0x1C:
    case 0x24:
    case 0x2C:
    case 0x3C: {
    Log::execute(this->_cpu, opCode, "inc r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByIncrement(*reg);
    (*reg)++;
    break;
    }
    case 0x05: // dec r
    case 0x0D:
    case 0x15:
    case 0x1D:
    case 0x25:
    case 0x2D:
    case 0x3D: {
    Log::execute(this->_cpu, opCode, "dec r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByDecrement(*reg);
    (*reg)--;
    break;
    }
    case 0x06: // ld r, n
    case 0x0e:
    case 0x16:
    case 0x1e:
    case 0x26:
    case 0x2e:
    case 0x3e: {
    Log::execute(this->_cpu, opCode, "ld r, n");
    uint8_t* reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    break;
    }
    case 0x07: { // rlca
    Log::execute(this->_cpu, opCode, "rlca");
    bool carry_bit = (this->_cpu->registers.a >> 7);
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_bit;
    this->_cpu->registers.FC_Carry = carry_bit;
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    break;
    }
    case 0x08: { // ex af, af'
    Log::execute(this->_cpu, opCode, "ex af, af'");
    uint16_t af = this->_cpu->registers.af();
    this->_cpu->registers.af(this->_cpu->registers_alternate.af());
    this->_cpu->registers_alternate.af(af);
    break;
    }
    case 0x09: // add hl, rr
    case 0x19:
    case 0x29:
    case 0x39: {
    Log::execute(this->_cpu, opCode, "add hl, rr");
    uint16_t value;
    switch (opCode){ // NOLINT(hicpp-multiway-paths-covered)
    case 0x09: value = this->_cpu->registers.bc(); break;
    case 0x19: value = this->_cpu->registers.de(); break;
    case 0x29: value = this->_cpu->registers.hl(); break;
    case 0x39: value = this->_cpu->special_registers.sp; break;
    }
    this->setFlagsByAdd16(this->_cpu->registers.hl(), value);
    this->_cpu->registers.hl(this->_cpu->registers.hl() + value);
    break;
    }
    case 0x0A: // ld a,(bc)
    Log::execute(this->_cpu, opCode, "ld a,(bc)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.bc());
    break;
    case 0x0B: // dec bc
    Log::execute(this->_cpu, opCode, "dec bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() - 1);
    break;
    case 0x0F: { // rrca
    Log::execute(this->_cpu, opCode, "rrca");
    bool carry_bit = ((this->_cpu->registers.a & 1) > 0);
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) + ((this->_cpu->registers.a & 1) << 7);
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FC_Carry = carry_bit;
    break;
    }
    case 0x10: { // djnz n
    Log::execute(this->_cpu, opCode, "djnz n");
    this->_cpu->registers.b--;
    if (this->_cpu->registers.b != 0){
    auto diff = (int8_t)Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    }
    case 0x11: // ld de, nn
    Log::execute(this->_cpu, opCode, "ld de, nn");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x12: // ld (de),a
    Log::execute(this->_cpu, opCode, "ld (de),a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.de(), this->_cpu->registers.a);
    break;
    case 0x13: // inc de
    Log::execute(this->_cpu, opCode, "inc de");
    this->_cpu->registers.de(this->_cpu->registers.de() + 1);
    break;
    case 0x17: { // rla
    Log::execute(this->_cpu, opCode, "rla");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a >> 7;
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_flg;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x18: { // jr n
    Log::execute(this->_cpu, opCode, "jr n");
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    break;
    }
    case 0x1A: // ld a,(de)
    Log::execute(this->_cpu, opCode, "ld a,(de)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.de());
    break;
    case 0x1B: // dec de
    Log::execute(this->_cpu, opCode, "dec de");
    this->_cpu->registers.de(this->_cpu->registers.de() - 1);
    break;
    case 0x1F: { // rra
    Log::execute(this->_cpu, opCode, "rra");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a & 1;
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) | (carry_flg << 7);
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x20: // jr nz, n
    Log::execute(this->_cpu, opCode, "jr nz, n");
    if (! this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x21: // ld hl, nn
    Log::execute(this->_cpu, opCode, "ld hl, nn");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8)
    );
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x22: { // ld (nn), hl
    Log::execute(this->_cpu, opCode, "ld (nn), hl");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.l);
    Mcycle::m3(this->_cpu, addr + 1, this->_cpu->registers.h);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x23: // inc hl
    Log::execute(this->_cpu, opCode, "inc hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() + 1);
    break;
    case 0x27: { // daa
    Log::execute(this->_cpu, opCode, "daa");
    uint8_t cr = 0;
    if ((this->_cpu->registers.a & 0x0f) > 0x09 || this->_cpu->registers.FH_HalfCarry){
    cr += 0x06;
    }
    if (this->_cpu->registers.a > 0x99 || this->_cpu->registers.FC_Carry){
    cr += 0x60;
    this->_cpu->registers.FC_Carry = true;
    }
    if (this->_cpu->registers.FN_Subtract){
    this->_cpu->registers.FH_HalfCarry =
    this->_cpu->registers.FH_HalfCarry &&
    (this->_cpu->registers.a & 0x0f) < 0x06;
    this->_cpu->registers.a -= cr;
    } else {
    this->_cpu->registers.FH_HalfCarry = (this->_cpu->registers.a & 0x0f) > 0x09;
    this->_cpu->registers.a += cr;
    }
    this->_cpu->registers.FS_Sign = this->_cpu->registers.a >> 7;
    this->_cpu->registers.FZ_Zero = this->_cpu->registers.a == 0;
    this->_cpu->registers.FPV_ParityOverflow = (OpCode::count1(this->_cpu->registers.a) % 2 == 0);
    break;
    }
    case 0x28: // jr z, n
    Log::execute(this->_cpu, opCode, "jr z, n");
    if (this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x2A: { // ld hl, (nn)
    Log::execute(this->_cpu, opCode, "ld hl, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.l = Mcycle::m2(this->_cpu, addr);
    this->_cpu->registers.h = Mcycle::m2(this->_cpu, addr + 1);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x2B: // dec hl
    Log::execute(this->_cpu, opCode, "dec hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() - 1);
    break;
    case 0x2F: // cpl
    Log::execute(this->_cpu, opCode, "cpl");
    this->_cpu->registers.a ^= 0xff;
    this->_cpu->registers.FN_Subtract = true;
    this->_cpu->registers.FH_HalfCarry = true;
    break;
    case 0x30: // jr nc, n
    Log::execute(this->_cpu, opCode, "jr nc, n");
    if (!this->_cpu->registers.FC_Carry){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x31: // ld sp, nn
    Log::execute(this->_cpu, opCode, "ld sp, nn");
    this->_cpu->special_registers.sp =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x32: { // ld (nn), a
    Log::execute(this->_cpu, opCode, "ld (nn), a");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.a);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x33: // inc sp
    Log::execute(this->_cpu, opCode, "inc sp");
    this->_cpu->special_registers.sp++;
    break;
    case 0x34: { // inc (hl)
    Log::execute(this->_cpu, opCode, "inc (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByIncrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value + 1);
    break;
    }
    case 0x35: { // dec (hl)
    Log::execute(this->_cpu, opCode, "dec (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByDecrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value - 1);
    break;
    }
    case 0x36: // ld (hl), n
    Log::execute(this->_cpu, opCode, "ld (hl), n");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    break;
    case 0x37: // scf
    Log::execute(this->_cpu, opCode, "scf");
    this->_cpu->registers.FC_Carry = true;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    case 0x38: // jr c, n
    Log::execute(this->_cpu, opCode, "jr c, n");
    if (this->_cpu->registers.FC_Carry) {
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x3A: { // ld a, (nn)
    Log::execute(this->_cpu, opCode, "ld a, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, addr);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x3B: // dec sp
    Log::execute(this->_cpu, opCode, "dec sp");
    this->_cpu->special_registers.sp--;
    break;
    case 0x3F: { // ccf
    Log::execute(this->_cpu, opCode, "ccf");
    bool saved_carry = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = !this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = saved_carry;
    break;
    }
    case 0x46: // ld r, (hl)
    case 0x4E:
    case 0x56:
    case 0x5E:
    case 0x66:
    case 0x6E: {
    Log::execute(this->_cpu, opCode, "ld r, (hl)");
    uint8_t *reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    }
    case 0x70: // ld (hl), r
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x77:
    Log::execute(this->_cpu, opCode, "ld (hl), r");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), *(this->targetRegister(opCode, 0)));
    break;
    case 0x76: // halt
    Log::execute(this->_cpu, opCode, "halt");
    this->_cpu->halt = true;
    break;
    case 0x7E: // ld a,(hl)
    Log::execute(this->_cpu, opCode, "ld a,(hl)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    case 0x80: // add a, r
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x87: {
    Log::execute(this->_cpu, opCode, "add a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a += *reg;
    break;
    }
    case 0x86: { // add a, (hl)
    Log::execute(this->_cpu, opCode, "add a, (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0x88: // adc a, r
    case 0x89:
    case 0x8A:
    case 0x8B:
    case 0x8C:
    case 0x8D:
    case 0x8F: {
    Log::execute(this->_cpu, opCode, "adc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a += *reg + carry;
    break;
    }
    case 0x8E: { // adc a, (hl)
    Log::execute(this->_cpu, opCode, "adc a, (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0x90: // sub r
    case 0x91:
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x97: {
    Log::execute(this->_cpu, opCode, "sub r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a -= *reg;
    break;
    }
    case 0x96: { // sub (hl)
    Log::execute(this->_cpu, opCode, "sub (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0x98: // sbc a, r
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9F: {
    Log::execute(this->_cpu, opCode, "sbc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a -= *reg + carry;
    break;
    }
    case 0x9E: { // sbc a,(hl)
    Log::execute(this->_cpu, opCode, "sbc a,(hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xA0: // and r
    case 0xA1:
    case 0xA2:
    case 0xA3:
    case 0xA4:
    case 0xA5:
    case 0xA7: {
    Log::execute(this->_cpu, opCode, "and r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a &= *reg;
    this->setFlagsByLogical(true);
    break;
    }
    case 0xA6: // and (hl)
    Log::execute(this->_cpu, opCode, "and (hl)");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(true);
    break;
    case 0xA8: // xor r
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAF: {
    Log::execute(this->_cpu, opCode, "xor r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a ^= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xAE: // xor (hl)
    Log::execute(this->_cpu, opCode, "xor (hl)");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB0: // or r
    case 0xB1:
    case 0xB2:
    case 0xB3:
    case 0xB4:
    case 0xB5:
    case 0xB7: {
    Log::execute(this->_cpu, opCode, "or r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a |= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xB6: // or (hl)
    Log::execute(this->_cpu, opCode, "or (hl)");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB8: // cp r
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBF:
    Log::execute(this->_cpu, opCode, "cp r");
    this->setFlagsBySubtract(this->_cpu->registers.a, *(this->targetRegister(opCode, 0)), 0);
    break;
    case 0xBE: { // cp (hl)
    Log::execute(this->_cpu, opCode, "cp (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    break;
    }
    case 0xC0: // ret nz
    Log::execute(this->_cpu, opCode, "ret nz");
    if (!this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC1: // pop bc
    Log::execute(this->_cpu, opCode, "pop bc");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xC2: // jp nz, nn
    Log::execute(this->_cpu, opCode, "jp nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC3: // jp nn
    Log::execute(this->_cpu, opCode, "jp nn");
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    break;
    case 0xC4: // call nz, nn
    Log::execute(this->_cpu, opCode, "call nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC5: // push bc
    Log::execute(this->_cpu, opCode, "push bc");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.b);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.c);
    Log::dump_registers(this->_cpu);
    break;
    case 0xC6: { // add a, n
    Log::execute(this->_cpu, opCode, "add a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0xC7: // rst n (n = 0 - 7)
    case 0xCF:
    case 0xD7:
    case 0xDF:
    case 0xE7:
    case 0xEF:
    case 0xF7:
    case 0xFF:
    Log::execute(this->_cpu, opCode, "rst n (n = 0 - 7)");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc & 0xff);
    this->_cpu->special_registers.pc = (opCode & 0b00111000);
    break;
    case 0xC8: // ret z
    Log::execute(this->_cpu, opCode, "ret z");
    if (this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC9: // ret
    Log::execute(this->_cpu, opCode, "ret");
    executeRet();
    break;
    case 0xCA: // jp z, nn
    Log::execute(this->_cpu, opCode, "jp z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCB: { // BITS
    Log::execute(this->_cpu, opCode, "BITS");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeCb(opcode);
    break;
    }
    case 0xCC: // call z, nn
    Log::execute(this->_cpu, opCode, "call z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCD: { // call nn
    Log::execute(this->_cpu, opCode, "call nn");
    this->executeCall();
    break;
    }
    case 0xCE: { // adc a, n
    Log::execute(this->_cpu, opCode, "adc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0xD0: // ret nc
    Log::execute(this->_cpu, opCode, "ret nc");
    if (!this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD1: // pop de
    Log::execute(this->_cpu, opCode, "pop de");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xD2: // jp nc, nn
    Log::execute(this->_cpu, opCode, "jp nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD3: { // out (n),a
    Log::execute(this->_cpu, opCode, "out (n),a");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc += 1;
    Mcycle::out(this->_cpu, port, this->_cpu->registers.a, this->_cpu->registers.a);
    break;
    }
    case 0xD4: // call nc, nn
    Log::execute(this->_cpu, opCode, "call nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD5: // push de
    Log::execute(this->_cpu, opCode, "push de");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.d);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.e);
    Log::dump_registers(this->_cpu);
    break;
    case 0xD6: { // sub n
    Log::execute(this->_cpu, opCode, "sub n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0xD8: // ret c
    Log::execute(this->_cpu, opCode, "ret c");
    if (this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD9: { // exx
    Log::execute(this->_cpu, opCode, "exx");
    uint16_t temp;
    temp = this->_cpu->registers.bc();
    this->_cpu->registers.bc(this->_cpu->registers_alternate.bc());
    this->_cpu->registers_alternate.bc(temp);
    temp = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers_alternate.de());
    this->_cpu->registers_alternate.de(temp);
    temp = this->_cpu->registers.hl();
    this->_cpu->registers.hl(this->_cpu->registers_alternate.hl());
    this->_cpu->registers_alternate.hl(temp);
    break;
    }
    case 0xDA: // jp c, nn
    Log::execute(this->_cpu, opCode, "jp c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDB: { // in a, (n)
    Log::execute(this->_cpu, opCode, "in a, (n)");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->registers.a = Mcycle::in(this->_cpu, port, this->_cpu->registers.a);
    break;
    }
    case 0xDC: // call c, nn
    Log::execute(this->_cpu, opCode, "call c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDD: { // IX
    Log::execute(this->_cpu, opCode, "IX");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeDd(opcode);
    break;
    }
    case 0xDE: { // sbc a, n
    Log::execute(this->_cpu, opCode, "sbc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xE0: // ret po
    Log::execute(this->_cpu, opCode, "ret po");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    executeRet();
    }
    break;
    case 0xE1: // pop hl
    Log::execute(this->_cpu, opCode, "pop hl");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8)
    );
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xE2: // jp po, nn
    Log::execute(this->_cpu, opCode, "jp po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE3: { // ex (sp), hl
    Log::execute(this->_cpu, opCode, "ex (sp), hl");
    uint16_t mem_value =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8);
    uint16_t temp_hl = this->_cpu->registers.hl();
    this->_cpu->registers.hl(mem_value);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, temp_hl & 0xff);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp + 1, temp_hl >> 8);
    break;
    }
    case 0xE4: // call po, nn
    Log::execute(this->_cpu, opCode, "call po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE5: // push hl
    Log::execute(this->_cpu, opCode, "push hl");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() & 0xff);
    Log::dump_registers(this->_cpu);
    break;
    case 0xE6: // and n
    Log::execute(this->_cpu, opCode, "and n");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(true);
    break;
    case 0xE8: // ret pe
    Log::execute(this->_cpu, opCode, "ret pe");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    executeRet();
    }
    break;
    case 0xE9: // jp (hl)
    Log::execute(this->_cpu, opCode, "jp (hl)");
    this->_cpu->special_registers.pc = this->_cpu->registers.hl();
    break;
    case 0xEA: // jp pe, nn
    Log::execute(this->_cpu, opCode, "jp pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xEB: { // ex de,hl
    Log::execute(this->_cpu, opCode, "ex de,hl");
    uint16_t de = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers.hl());
    this->_cpu->registers.hl(de);
    break;
    }
    case 0xEC: // call pe, nn
    Log::execute(this->_cpu, opCode, "call pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xED: { // EXTD
    Log::execute(this->_cpu, opCode, "EXTD");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeEd(opcode);
    break;
    }
    case 0xEE: // xor n
    Log::execute(this->_cpu, opCode, "xor n");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF0: // ret p
    Log::execute(this->_cpu, opCode, "ret p");
    if (! this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF1: // pop af
    Log::execute(this->_cpu, opCode, "pop af");
    this->_cpu->registers.f(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp));
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xF2: // jp p, nn
    Log::execute(this->_cpu, opCode, "jp p, nn");
    if (! this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF3: // di
    Log::execute(this->_cpu, opCode, "di");
    this->_cpu->waitingDI = 1;
    break;
    case 0xF4: // call p, nn
    Log::execute(this->_cpu, opCode, "call p, nn");
    if (! this->_cpu->registers.FS_Sign) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF5: // push af
    Log::execute(this->_cpu, opCode, "push af");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.a);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.f());
    Log::dump_registers(this->_cpu);
    break;
    case 0xF6: // or n
    Log::execute(this->_cpu, opCode, "or n");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF8: // ret m
    Log::execute(this->_cpu, opCode, "ret m");
    if (this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF9: // ld sp,hl
    Log::execute(this->_cpu, opCode, "ld sp,hl");
    this->_cpu->special_registers.sp = this->_cpu->registers.hl();
    break;
    case 0xFA: // jp m, nn
    Log::execute(this->_cpu, opCode, "jp m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFB: // ei
    Log::execute(this->_cpu, opCode, "ei");
    this->_cpu->waitingEI = 2;
    break;
    case 0xFC: // call m, nn
    Log::execute(this->_cpu, opCode, "call m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFD: { // IY
    Log::execute(this->_cpu, opCode, "IY");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeFd(opcode);
    break;
    }
    case 0xFE: { // cp n
    Log::execute(this->_cpu, opCode, "cp n");
    this->setFlagsBySubtract(this->_cpu->registers.a, Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc), 0);
    this->_cpu->special_registers.pc++;
    break;
    }
    default:
    char error[100];
    sprintf(error, "Invalid op code: %02x", opCode);
    Log::error(this->_cpu, error);
    throw std::runtime_error(error);
    }
    }

    View full-size slide

  135. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令を実装する
    • 左のリストはZ80の命令 0x00 〜 0xff まで
    • 256個の case 文 1,300行ぐらい
    • 実際は少し工夫してるのでもう少し少ない
    • 工夫しない方が速いことも
    • 全命令だと3,000行弱
    • ひたすら地道に書いた
    • これからやる方はイチから書くのはお勧めしない
    • ツライだけで(30個ぐらい以降は)あまり楽しくない
    30
    void OpCode::execute(uint8_t opCode){
    if ((opCode >> 6) == 0b01 && (opCode & 0b00111000) != 0b00110000 && (opCode & 0b00000111) != 0b00000110){
    // ld r, r'
    Log::execute(this->_cpu, opCode, "ld r, r'");
    uint8_t *reg = this->targetRegister(opCode, 3);
    uint8_t *reg_dash = this->targetRegister(opCode, 0);
    *reg = *reg_dash;
    Log::dump_registers(this->_cpu);
    return;
    }
    switch (opCode){
    case 0x00: // nop
    Log::execute(this->_cpu, opCode, "nop");
    break;
    case 0x01: // ld bc, nn
    Log::execute(this->_cpu, opCode, "ld bc, nn");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x02: { // ld (bc), a
    Log::execute(this->_cpu, opCode, "ld (bc), a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.bc(), this->_cpu->registers.a);
    break;
    }
    case 0x03: // inc bc
    Log::execute(this->_cpu, opCode, "inc bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() + 1);
    break;
    case 0x04: // inc r
    case 0x0C:
    case 0x14:
    case 0x1C:
    case 0x24:
    case 0x2C:
    case 0x3C: {
    Log::execute(this->_cpu, opCode, "inc r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByIncrement(*reg);
    (*reg)++;
    break;
    }
    case 0x05: // dec r
    case 0x0D:
    case 0x15:
    case 0x1D:
    case 0x25:
    case 0x2D:
    case 0x3D: {
    Log::execute(this->_cpu, opCode, "dec r");
    uint8_t *reg = this->targetRegister(opCode, 3);
    this->setFlagsByDecrement(*reg);
    (*reg)--;
    break;
    }
    case 0x06: // ld r, n
    case 0x0e:
    case 0x16:
    case 0x1e:
    case 0x26:
    case 0x2e:
    case 0x3e: {
    Log::execute(this->_cpu, opCode, "ld r, n");
    uint8_t* reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    break;
    }
    case 0x07: { // rlca
    Log::execute(this->_cpu, opCode, "rlca");
    bool carry_bit = (this->_cpu->registers.a >> 7);
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_bit;
    this->_cpu->registers.FC_Carry = carry_bit;
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    break;
    }
    case 0x08: { // ex af, af'
    Log::execute(this->_cpu, opCode, "ex af, af'");
    uint16_t af = this->_cpu->registers.af();
    this->_cpu->registers.af(this->_cpu->registers_alternate.af());
    this->_cpu->registers_alternate.af(af);
    break;
    }
    case 0x09: // add hl, rr
    case 0x19:
    case 0x29:
    case 0x39: {
    Log::execute(this->_cpu, opCode, "add hl, rr");
    uint16_t value;
    switch (opCode){ // NOLINT(hicpp-multiway-paths-covered)
    case 0x09: value = this->_cpu->registers.bc(); break;
    case 0x19: value = this->_cpu->registers.de(); break;
    case 0x29: value = this->_cpu->registers.hl(); break;
    case 0x39: value = this->_cpu->special_registers.sp; break;
    }
    this->setFlagsByAdd16(this->_cpu->registers.hl(), value);
    this->_cpu->registers.hl(this->_cpu->registers.hl() + value);
    break;
    }
    case 0x0A: // ld a,(bc)
    Log::execute(this->_cpu, opCode, "ld a,(bc)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.bc());
    break;
    case 0x0B: // dec bc
    Log::execute(this->_cpu, opCode, "dec bc");
    this->_cpu->registers.bc(this->_cpu->registers.bc() - 1);
    break;
    case 0x0F: { // rrca
    Log::execute(this->_cpu, opCode, "rrca");
    bool carry_bit = ((this->_cpu->registers.a & 1) > 0);
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) + ((this->_cpu->registers.a & 1) << 7);
    this->_cpu->registers.FH_HalfCarry = false;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FC_Carry = carry_bit;
    break;
    }
    case 0x10: { // djnz n
    Log::execute(this->_cpu, opCode, "djnz n");
    this->_cpu->registers.b--;
    if (this->_cpu->registers.b != 0){
    auto diff = (int8_t)Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    }
    case 0x11: // ld de, nn
    Log::execute(this->_cpu, opCode, "ld de, nn");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x12: // ld (de),a
    Log::execute(this->_cpu, opCode, "ld (de),a");
    Mcycle::m3(this->_cpu, this->_cpu->registers.de(), this->_cpu->registers.a);
    break;
    case 0x13: // inc de
    Log::execute(this->_cpu, opCode, "inc de");
    this->_cpu->registers.de(this->_cpu->registers.de() + 1);
    break;
    case 0x17: { // rla
    Log::execute(this->_cpu, opCode, "rla");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a >> 7;
    this->_cpu->registers.a = (this->_cpu->registers.a << 1) | carry_flg;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x18: { // jr n
    Log::execute(this->_cpu, opCode, "jr n");
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    break;
    }
    case 0x1A: // ld a,(de)
    Log::execute(this->_cpu, opCode, "ld a,(de)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.de());
    break;
    case 0x1B: // dec de
    Log::execute(this->_cpu, opCode, "dec de");
    this->_cpu->registers.de(this->_cpu->registers.de() - 1);
    break;
    case 0x1F: { // rra
    Log::execute(this->_cpu, opCode, "rra");
    bool carry_flg = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = this->_cpu->registers.a & 1;
    this->_cpu->registers.a = (this->_cpu->registers.a >> 1) | (carry_flg << 7);
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    }
    case 0x20: // jr nz, n
    Log::execute(this->_cpu, opCode, "jr nz, n");
    if (! this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x21: // ld hl, nn
    Log::execute(this->_cpu, opCode, "ld hl, nn");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8)
    );
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x22: { // ld (nn), hl
    Log::execute(this->_cpu, opCode, "ld (nn), hl");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.l);
    Mcycle::m3(this->_cpu, addr + 1, this->_cpu->registers.h);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x23: // inc hl
    Log::execute(this->_cpu, opCode, "inc hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() + 1);
    break;
    case 0x27: { // daa
    Log::execute(this->_cpu, opCode, "daa");
    uint8_t cr = 0;
    if ((this->_cpu->registers.a & 0x0f) > 0x09 || this->_cpu->registers.FH_HalfCarry){
    cr += 0x06;
    }
    if (this->_cpu->registers.a > 0x99 || this->_cpu->registers.FC_Carry){
    cr += 0x60;
    this->_cpu->registers.FC_Carry = true;
    }
    if (this->_cpu->registers.FN_Subtract){
    this->_cpu->registers.FH_HalfCarry =
    this->_cpu->registers.FH_HalfCarry &&
    (this->_cpu->registers.a & 0x0f) < 0x06;
    this->_cpu->registers.a -= cr;
    } else {
    this->_cpu->registers.FH_HalfCarry = (this->_cpu->registers.a & 0x0f) > 0x09;
    this->_cpu->registers.a += cr;
    }
    this->_cpu->registers.FS_Sign = this->_cpu->registers.a >> 7;
    this->_cpu->registers.FZ_Zero = this->_cpu->registers.a == 0;
    this->_cpu->registers.FPV_ParityOverflow = (OpCode::count1(this->_cpu->registers.a) % 2 == 0);
    break;
    }
    case 0x28: // jr z, n
    Log::execute(this->_cpu, opCode, "jr z, n");
    if (this->_cpu->registers.FZ_Zero){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x2A: { // ld hl, (nn)
    Log::execute(this->_cpu, opCode, "ld hl, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.l = Mcycle::m2(this->_cpu, addr);
    this->_cpu->registers.h = Mcycle::m2(this->_cpu, addr + 1);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x2B: // dec hl
    Log::execute(this->_cpu, opCode, "dec hl");
    this->_cpu->registers.hl(this->_cpu->registers.hl() - 1);
    break;
    case 0x2F: // cpl
    Log::execute(this->_cpu, opCode, "cpl");
    this->_cpu->registers.a ^= 0xff;
    this->_cpu->registers.FN_Subtract = true;
    this->_cpu->registers.FH_HalfCarry = true;
    break;
    case 0x30: // jr nc, n
    Log::execute(this->_cpu, opCode, "jr nc, n");
    if (!this->_cpu->registers.FC_Carry){
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x31: // ld sp, nn
    Log::execute(this->_cpu, opCode, "ld sp, nn");
    this->_cpu->special_registers.sp =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    break;
    case 0x32: { // ld (nn), a
    Log::execute(this->_cpu, opCode, "ld (nn), a");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    Mcycle::m3(this->_cpu, addr, this->_cpu->registers.a);
    this->_cpu->special_registers.pc += 2;
    break;
    }
    case 0x33: // inc sp
    Log::execute(this->_cpu, opCode, "inc sp");
    this->_cpu->special_registers.sp++;
    break;
    case 0x34: { // inc (hl)
    Log::execute(this->_cpu, opCode, "inc (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByIncrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value + 1);
    break;
    }
    case 0x35: { // dec (hl)
    Log::execute(this->_cpu, opCode, "dec (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByDecrement(value);
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), value - 1);
    break;
    }
    case 0x36: // ld (hl), n
    Log::execute(this->_cpu, opCode, "ld (hl), n");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    break;
    case 0x37: // scf
    Log::execute(this->_cpu, opCode, "scf");
    this->_cpu->registers.FC_Carry = true;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = false;
    break;
    case 0x38: // jr c, n
    Log::execute(this->_cpu, opCode, "jr c, n");
    if (this->_cpu->registers.FC_Carry) {
    auto diff = (int8_t)(Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc));
    this->_cpu->special_registers.pc++;
    this->_cpu->special_registers.pc += diff;
    } else {
    this->_cpu->special_registers.pc++;
    }
    break;
    case 0x3A: { // ld a, (nn)
    Log::execute(this->_cpu, opCode, "ld a, (nn)");
    uint16_t addr =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    this->_cpu->special_registers.pc += 2;
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, addr);
    Log::dump_registers(this->_cpu);
    break;
    }
    case 0x3B: // dec sp
    Log::execute(this->_cpu, opCode, "dec sp");
    this->_cpu->special_registers.sp--;
    break;
    case 0x3F: { // ccf
    Log::execute(this->_cpu, opCode, "ccf");
    bool saved_carry = this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FC_Carry = !this->_cpu->registers.FC_Carry;
    this->_cpu->registers.FN_Subtract = false;
    this->_cpu->registers.FH_HalfCarry = saved_carry;
    break;
    }
    case 0x46: // ld r, (hl)
    case 0x4E:
    case 0x56:
    case 0x5E:
    case 0x66:
    case 0x6E: {
    Log::execute(this->_cpu, opCode, "ld r, (hl)");
    uint8_t *reg = this->targetRegister(opCode, 3);
    *reg = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    }
    case 0x70: // ld (hl), r
    case 0x71:
    case 0x72:
    case 0x73:
    case 0x74:
    case 0x75:
    case 0x77:
    Log::execute(this->_cpu, opCode, "ld (hl), r");
    Mcycle::m3(this->_cpu, this->_cpu->registers.hl(), *(this->targetRegister(opCode, 0)));
    break;
    case 0x76: // halt
    Log::execute(this->_cpu, opCode, "halt");
    this->_cpu->halt = true;
    break;
    case 0x7E: // ld a,(hl)
    Log::execute(this->_cpu, opCode, "ld a,(hl)");
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    break;
    case 0x80: // add a, r
    case 0x81:
    case 0x82:
    case 0x83:
    case 0x84:
    case 0x85:
    case 0x87: {
    Log::execute(this->_cpu, opCode, "add a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a += *reg;
    break;
    }
    case 0x86: { // add a, (hl)
    Log::execute(this->_cpu, opCode, "add a, (hl)");
    uint16_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0x88: // adc a, r
    case 0x89:
    case 0x8A:
    case 0x8B:
    case 0x8C:
    case 0x8D:
    case 0x8F: {
    Log::execute(this->_cpu, opCode, "adc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a += *reg + carry;
    break;
    }
    case 0x8E: { // adc a, (hl)
    Log::execute(this->_cpu, opCode, "adc a, (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0x90: // sub r
    case 0x91:
    case 0x92:
    case 0x93:
    case 0x94:
    case 0x95:
    case 0x97: {
    Log::execute(this->_cpu, opCode, "sub r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, 0);
    this->_cpu->registers.a -= *reg;
    break;
    }
    case 0x96: { // sub (hl)
    Log::execute(this->_cpu, opCode, "sub (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0x98: // sbc a, r
    case 0x99:
    case 0x9A:
    case 0x9B:
    case 0x9C:
    case 0x9D:
    case 0x9F: {
    Log::execute(this->_cpu, opCode, "sbc a, r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, *reg, carry);
    this->_cpu->registers.a -= *reg + carry;
    break;
    }
    case 0x9E: { // sbc a,(hl)
    Log::execute(this->_cpu, opCode, "sbc a,(hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xA0: // and r
    case 0xA1:
    case 0xA2:
    case 0xA3:
    case 0xA4:
    case 0xA5:
    case 0xA7: {
    Log::execute(this->_cpu, opCode, "and r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a &= *reg;
    this->setFlagsByLogical(true);
    break;
    }
    case 0xA6: // and (hl)
    Log::execute(this->_cpu, opCode, "and (hl)");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(true);
    break;
    case 0xA8: // xor r
    case 0xA9:
    case 0xAA:
    case 0xAB:
    case 0xAC:
    case 0xAD:
    case 0xAF: {
    Log::execute(this->_cpu, opCode, "xor r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a ^= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xAE: // xor (hl)
    Log::execute(this->_cpu, opCode, "xor (hl)");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB0: // or r
    case 0xB1:
    case 0xB2:
    case 0xB3:
    case 0xB4:
    case 0xB5:
    case 0xB7: {
    Log::execute(this->_cpu, opCode, "or r");
    uint8_t* reg = this->targetRegister(opCode, 0);
    this->_cpu->registers.a |= *reg;
    this->setFlagsByLogical(false);
    break;
    }
    case 0xB6: // or (hl)
    Log::execute(this->_cpu, opCode, "or (hl)");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsByLogical(false);
    break;
    case 0xB8: // cp r
    case 0xB9:
    case 0xBA:
    case 0xBB:
    case 0xBC:
    case 0xBD:
    case 0xBF:
    Log::execute(this->_cpu, opCode, "cp r");
    this->setFlagsBySubtract(this->_cpu->registers.a, *(this->targetRegister(opCode, 0)), 0);
    break;
    case 0xBE: { // cp (hl)
    Log::execute(this->_cpu, opCode, "cp (hl)");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->registers.hl());
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    break;
    }
    case 0xC0: // ret nz
    Log::execute(this->_cpu, opCode, "ret nz");
    if (!this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC1: // pop bc
    Log::execute(this->_cpu, opCode, "pop bc");
    this->_cpu->registers.c = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.b = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xC2: // jp nz, nn
    Log::execute(this->_cpu, opCode, "jp nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC3: // jp nn
    Log::execute(this->_cpu, opCode, "jp nn");
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    break;
    case 0xC4: // call nz, nn
    Log::execute(this->_cpu, opCode, "call nz, nn");
    if (!this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xC5: // push bc
    Log::execute(this->_cpu, opCode, "push bc");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.b);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.c);
    Log::dump_registers(this->_cpu);
    break;
    case 0xC6: { // add a, n
    Log::execute(this->_cpu, opCode, "add a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByAddition(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a += value;
    break;
    }
    case 0xC7: // rst n (n = 0 - 7)
    case 0xCF:
    case 0xD7:
    case 0xDF:
    case 0xE7:
    case 0xEF:
    case 0xF7:
    case 0xFF:
    Log::execute(this->_cpu, opCode, "rst n (n = 0 - 7)");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->special_registers.pc & 0xff);
    this->_cpu->special_registers.pc = (opCode & 0b00111000);
    break;
    case 0xC8: // ret z
    Log::execute(this->_cpu, opCode, "ret z");
    if (this->_cpu->registers.FZ_Zero) {
    executeRet();
    }
    break;
    case 0xC9: // ret
    Log::execute(this->_cpu, opCode, "ret");
    executeRet();
    break;
    case 0xCA: // jp z, nn
    Log::execute(this->_cpu, opCode, "jp z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCB: { // BITS
    Log::execute(this->_cpu, opCode, "BITS");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeCb(opcode);
    break;
    }
    case 0xCC: // call z, nn
    Log::execute(this->_cpu, opCode, "call z, nn");
    if (this->_cpu->registers.FZ_Zero) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xCD: { // call nn
    Log::execute(this->_cpu, opCode, "call nn");
    this->executeCall();
    break;
    }
    case 0xCE: { // adc a, n
    Log::execute(this->_cpu, opCode, "adc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsByAddition(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a += value + carry;
    break;
    }
    case 0xD0: // ret nc
    Log::execute(this->_cpu, opCode, "ret nc");
    if (!this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD1: // pop de
    Log::execute(this->_cpu, opCode, "pop de");
    this->_cpu->registers.e = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp);
    this->_cpu->registers.d = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xD2: // jp nc, nn
    Log::execute(this->_cpu, opCode, "jp nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD3: { // out (n),a
    Log::execute(this->_cpu, opCode, "out (n),a");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc += 1;
    Mcycle::out(this->_cpu, port, this->_cpu->registers.a, this->_cpu->registers.a);
    break;
    }
    case 0xD4: // call nc, nn
    Log::execute(this->_cpu, opCode, "call nc, nn");
    if (!this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xD5: // push de
    Log::execute(this->_cpu, opCode, "push de");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.d);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.e);
    Log::dump_registers(this->_cpu);
    break;
    case 0xD6: { // sub n
    Log::execute(this->_cpu, opCode, "sub n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsBySubtract(this->_cpu->registers.a, value, 0);
    this->_cpu->registers.a -= value;
    break;
    }
    case 0xD8: // ret c
    Log::execute(this->_cpu, opCode, "ret c");
    if (this->_cpu->registers.FC_Carry) {
    executeRet();
    }
    break;
    case 0xD9: { // exx
    Log::execute(this->_cpu, opCode, "exx");
    uint16_t temp;
    temp = this->_cpu->registers.bc();
    this->_cpu->registers.bc(this->_cpu->registers_alternate.bc());
    this->_cpu->registers_alternate.bc(temp);
    temp = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers_alternate.de());
    this->_cpu->registers_alternate.de(temp);
    temp = this->_cpu->registers.hl();
    this->_cpu->registers.hl(this->_cpu->registers_alternate.hl());
    this->_cpu->registers_alternate.hl(temp);
    break;
    }
    case 0xDA: // jp c, nn
    Log::execute(this->_cpu, opCode, "jp c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDB: { // in a, (n)
    Log::execute(this->_cpu, opCode, "in a, (n)");
    uint8_t port = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->_cpu->registers.a = Mcycle::in(this->_cpu, port, this->_cpu->registers.a);
    break;
    }
    case 0xDC: // call c, nn
    Log::execute(this->_cpu, opCode, "call c, nn");
    if (this->_cpu->registers.FC_Carry) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xDD: { // IX
    Log::execute(this->_cpu, opCode, "IX");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeDd(opcode);
    break;
    }
    case 0xDE: { // sbc a, n
    Log::execute(this->_cpu, opCode, "sbc a, n");
    uint8_t value = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    uint8_t carry = this->_cpu->registers.carry_by_val();
    this->setFlagsBySubtract(this->_cpu->registers.a, value, carry);
    this->_cpu->registers.a -= value + carry;
    break;
    }
    case 0xE0: // ret po
    Log::execute(this->_cpu, opCode, "ret po");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    executeRet();
    }
    break;
    case 0xE1: // pop hl
    Log::execute(this->_cpu, opCode, "pop hl");
    this->_cpu->registers.hl(
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8)
    );
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xE2: // jp po, nn
    Log::execute(this->_cpu, opCode, "jp po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE3: { // ex (sp), hl
    Log::execute(this->_cpu, opCode, "ex (sp), hl");
    uint16_t mem_value =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1) << 8);
    uint16_t temp_hl = this->_cpu->registers.hl();
    this->_cpu->registers.hl(mem_value);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, temp_hl & 0xff);
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp + 1, temp_hl >> 8);
    break;
    }
    case 0xE4: // call po, nn
    Log::execute(this->_cpu, opCode, "call po, nn");
    if (! this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xE5: // push hl
    Log::execute(this->_cpu, opCode, "push hl");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() >> 8);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.hl() & 0xff);
    Log::dump_registers(this->_cpu);
    break;
    case 0xE6: // and n
    Log::execute(this->_cpu, opCode, "and n");
    this->_cpu->registers.a &= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(true);
    break;
    case 0xE8: // ret pe
    Log::execute(this->_cpu, opCode, "ret pe");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    executeRet();
    }
    break;
    case 0xE9: // jp (hl)
    Log::execute(this->_cpu, opCode, "jp (hl)");
    this->_cpu->special_registers.pc = this->_cpu->registers.hl();
    break;
    case 0xEA: // jp pe, nn
    Log::execute(this->_cpu, opCode, "jp pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xEB: { // ex de,hl
    Log::execute(this->_cpu, opCode, "ex de,hl");
    uint16_t de = this->_cpu->registers.de();
    this->_cpu->registers.de(this->_cpu->registers.hl());
    this->_cpu->registers.hl(de);
    break;
    }
    case 0xEC: // call pe, nn
    Log::execute(this->_cpu, opCode, "call pe, nn");
    if (this->_cpu->registers.FPV_ParityOverflow) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xED: { // EXTD
    Log::execute(this->_cpu, opCode, "EXTD");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeEd(opcode);
    break;
    }
    case 0xEE: // xor n
    Log::execute(this->_cpu, opCode, "xor n");
    this->_cpu->registers.a ^= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF0: // ret p
    Log::execute(this->_cpu, opCode, "ret p");
    if (! this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF1: // pop af
    Log::execute(this->_cpu, opCode, "pop af");
    this->_cpu->registers.f(Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp));
    this->_cpu->registers.a = Mcycle::m2(this->_cpu, this->_cpu->special_registers.sp + 1);
    this->_cpu->special_registers.sp += 2;
    Log::dump_registers(this->_cpu);
    break;
    case 0xF2: // jp p, nn
    Log::execute(this->_cpu, opCode, "jp p, nn");
    if (! this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF3: // di
    Log::execute(this->_cpu, opCode, "di");
    this->_cpu->waitingDI = 1;
    break;
    case 0xF4: // call p, nn
    Log::execute(this->_cpu, opCode, "call p, nn");
    if (! this->_cpu->registers.FS_Sign) {
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xF5: // push af
    Log::execute(this->_cpu, opCode, "push af");
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.a);
    this->_cpu->special_registers.sp--;
    Mcycle::m3(this->_cpu, this->_cpu->special_registers.sp, this->_cpu->registers.f());
    Log::dump_registers(this->_cpu);
    break;
    case 0xF6: // or n
    Log::execute(this->_cpu, opCode, "or n");
    this->_cpu->registers.a |= Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    this->setFlagsByLogical(false);
    break;
    case 0xF8: // ret m
    Log::execute(this->_cpu, opCode, "ret m");
    if (this->_cpu->registers.FS_Sign){
    executeRet();
    }
    break;
    case 0xF9: // ld sp,hl
    Log::execute(this->_cpu, opCode, "ld sp,hl");
    this->_cpu->special_registers.sp = this->_cpu->registers.hl();
    break;
    case 0xFA: // jp m, nn
    Log::execute(this->_cpu, opCode, "jp m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->_cpu->special_registers.pc =
    Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc) +
    (Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc + 1) << 8);
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFB: // ei
    Log::execute(this->_cpu, opCode, "ei");
    this->_cpu->waitingEI = 2;
    break;
    case 0xFC: // call m, nn
    Log::execute(this->_cpu, opCode, "call m, nn");
    if (this->_cpu->registers.FS_Sign){
    this->executeCall();
    } else {
    this->_cpu->special_registers.pc += 2;
    }
    break;
    case 0xFD: { // IY
    Log::execute(this->_cpu, opCode, "IY");
    uint8_t opcode = Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc);
    this->_cpu->special_registers.pc++;
    executeFd(opcode);
    break;
    }
    case 0xFE: { // cp n
    Log::execute(this->_cpu, opCode, "cp n");
    this->setFlagsBySubtract(this->_cpu->registers.a, Mcycle::m2(this->_cpu, this->_cpu->special_registers.pc), 0);
    this->_cpu->special_registers.pc++;
    break;
    }
    default:
    char error[100];
    sprintf(error, "Invalid op code: %02x", opCode);
    Log::error(this->_cpu, error);
    throw std::runtime_error(error);
    }
    }

    View full-size slide