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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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


    • CPUを3つの視点で見た


    • プログラム実行環境


    • エミュレート対象


    • 電気回路
    5

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

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

    View Slide

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

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

    View Slide

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

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

    View Slide

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

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    ハードウェア
    9

    View Slide

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

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

    View Slide

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

    View Slide

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

    View 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 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 Slide

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

    View Slide

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

    View Slide

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

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

    View Slide

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

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

    View Slide

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

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

    View Slide

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

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

    View Slide

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

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


    挿入して動作させる

    View Slide

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


    PORT
    CLOCK

    View Slide

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


    PORT
    CLOCK

    View Slide

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


    PORT
    CLOCK

    View Slide

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


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

    View Slide

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


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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 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 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 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 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    するまで間待つ
    ① ② ③

    View Slide

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

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

    View Slide

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

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 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 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 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 Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View 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 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 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 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 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 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 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 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 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 Slide

  136. 長谷川智希 @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 Slide

  137. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPUエミュレートのメインループ
    31

    View Slide

  138. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CPUエミュレートのメインループ
    31
    void Cpu::instructionCycle(){
    while(true){
    if (!this->bus->getInput(Bus::Z80_PIN_I_RESET)){
    this->reset();
    }
    Mcycle::m1t1(this);
    Mcycle::m1t2(this);
    Mcycle::m1t3(this);
    Mcycle::m1t4(this);
    this->opCode.execute(this->executing);
    this->interrupt();
    }
    }

    View Slide

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

    View Slide

  140. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実装の検証
    • よし!ひととおりできたぞ!動かしてみよう!
    32

    View Slide

  141. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実装の検証
    • よし!ひととおりできたぞ!動かしてみよう!
    • で動く訳がない
    32

    View Slide

  142. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実装の検証
    • よし!ひととおりできたぞ!動かしてみよう!
    • で動く訳がない
    • デバッグ
    32

    View Slide

  143. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実装の検証
    • よし!ひととおりできたぞ!動かしてみよう!
    • で動く訳がない
    • デバッグ
    • たいへんつらい
    32

    View Slide

  144. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実装の検証
    • よし!ひととおりできたぞ!動かしてみよう!
    • で動く訳がない
    • デバッグ
    • たいへんつらい
    • 「すべてのZ80対象プログラムが動く」のがゴール
    32

    View Slide

  145. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実装の検証
    • よし!ひととおりできたぞ!動かしてみよう!
    • で動く訳がない
    • デバッグ
    • たいへんつらい
    • 「すべてのZ80対象プログラムが動く」のがゴール
    • 既存のプログラムを動かして「なんかおかしい」からのデバッグ
    32

    View Slide

  146. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実装の検証
    • よし!ひととおりできたぞ!動かしてみよう!
    • で動く訳がない
    • デバッグ
    • たいへんつらい
    • 「すべてのZ80対象プログラムが動く」のがゴール
    • 既存のプログラムを動かして「なんかおかしい」からのデバッグ
    • 非現実的
    32

    View Slide

  147. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    33

    View Slide

  148. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    • Z80の動作をテストするためのプログラムが存在する
    33

    View Slide

  149. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    • Z80の動作をテストするためのプログラムが存在する
    • prelim: zexallを動作させるための命令のテスト
    33

    View Slide

  150. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    • Z80の動作をテストするためのプログラムが存在する
    • prelim: zexallを動作させるための命令のテスト
    • zexall: 全命令のテスト
    33

    View Slide

  151. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    • Z80の動作をテストするためのプログラムが存在する
    • prelim: zexallを動作させるための命令のテスト
    • zexall: 全命令のテスト
    • Z80バイナリで配布されている
    33

    View Slide

  152. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    • Z80の動作をテストするためのプログラムが存在する
    • prelim: zexallを動作させるための命令のテスト
    • zexall: 全命令のテスト
    • Z80バイナリで配布されている
    • メモリの読み書きメソッドでテストプログラムを返す様にして実行
    33

    View Slide

  153. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    • Z80の動作をテストするためのプログラムが存在する
    • prelim: zexallを動作させるための命令のテスト
    • zexall: 全命令のテスト
    • Z80バイナリで配布されている
    • メモリの読み書きメソッドでテストプログラムを返す様にして実行
    • zexallはCP/M(太古のOS)用の文字出力API(BDOSコール)を使っている
    33

    View Slide

  154. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    • Z80の動作をテストするためのプログラムが存在する
    • prelim: zexallを動作させるための命令のテスト
    • zexall: 全命令のテスト
    • Z80バイナリで配布されている
    • メモリの読み書きメソッドでテストプログラムを返す様にして実行
    • zexallはCP/M(太古のOS)用の文字出力API(BDOSコール)を使っている
    • それほど複雑なAPIでないのでエミュレータを書いた
    33

    View Slide

  155. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    • Z80の動作をテストするためのプログラムが存在する
    • prelim: zexallを動作させるための命令のテスト
    • zexall: 全命令のテスト
    • Z80バイナリで配布されている
    • メモリの読み書きメソッドでテストプログラムを返す様にして実行
    • zexallはCP/M(太古のOS)用の文字出力API(BDOSコール)を使っている
    • それほど複雑なAPIでないのでエミュレータを書いた
    • バイナリのままでも実行できるけどソースからアセンブルできる様にした方が効率的
    33

    View Slide

  156. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    • Z80の動作をテストするためのプログラムが存在する
    • prelim: zexallを動作させるための命令のテスト
    • zexall: 全命令のテスト
    • Z80バイナリで配布されている
    • メモリの読み書きメソッドでテストプログラムを返す様にして実行
    • zexallはCP/M(太古のOS)用の文字出力API(BDOSコール)を使っている
    • それほど複雑なAPIでないのでエミュレータを書いた
    • バイナリのままでも実行できるけどソースからアセンブルできる様にした方が効率的
    • zexallはめちゃくちゃ時間がかかるので途中から実行したい
    33

    View Slide

  157. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラム
    • Z80の動作をテストするためのプログラムが存在する
    • prelim: zexallを動作させるための命令のテスト
    • zexall: 全命令のテスト
    • Z80バイナリで配布されている
    • メモリの読み書きメソッドでテストプログラムを返す様にして実行
    • zexallはCP/M(太古のOS)用の文字出力API(BDOSコール)を使っている
    • それほど複雑なAPIでないのでエミュレータを書いた
    • バイナリのままでも実行できるけどソースからアセンブルできる様にした方が効率的
    • zexallはめちゃくちゃ時間がかかるので途中から実行したい
    • 命令群まとめてのテストをバラして実行したい
    33

    View Slide

  158. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    全命令の検証が済んだぞ!


    完成だ!
    34

    View Slide

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

    View Slide

  160. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラムのカバー範囲
    36

    View Slide

  161. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラムのカバー範囲
    • prelim, zexall は命令しかカバーしない
    36

    View Slide

  162. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラムのカバー範囲
    • prelim, zexall は命令しかカバーしない
    • メモリアクセスはこの範囲でカバーされる
    36

    View Slide

  163. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラムのカバー範囲
    • prelim, zexall は命令しかカバーしない
    • メモリアクセスはこの範囲でカバーされる
    • リセット, I/O, 割り込みなどはカバーされない
    36

    View Slide

  164. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラムのカバー範囲
    • prelim, zexall は命令しかカバーしない
    • メモリアクセスはこの範囲でカバーされる
    • リセット, I/O, 割り込みなどはカバーされない
    • 実アプリケーションを動かしてテストするしかない
    36

    View Slide

  165. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラムのカバー範囲
    • prelim, zexall は命令しかカバーしない
    • メモリアクセスはこの範囲でカバーされる
    • リセット, I/O, 割り込みなどはカバーされない
    • 実アプリケーションを動かしてテストするしかない
    • 良い方法知っている方教えてください!
    36

    View Slide

  166. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    テストプログラムのカバー範囲
    • prelim, zexall は命令しかカバーしない
    • メモリアクセスはこの範囲でカバーされる
    • リセット, I/O, 割り込みなどはカバーされない
    • 実アプリケーションを動かしてテストするしかない
    • 良い方法知っている方教えてください!
    • 実アプリケーションを動かしてみる
    36

    View Slide

  167. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション1
    37

    View Slide

  168. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション1: NOPコンピュータ
    38

    View Slide

  169. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション1: NOPコンピュータ
    • Z80は0x00がNOP(No OPeration)
    命令
    38

    View Slide

  170. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション1: NOPコンピュータ
    • Z80は0x00がNOP(No OPeration)
    命令
    • データバスをすべて0に固定した簡易コンピュータ
    38

    View Slide

  171. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション1: NOPコンピュータ
    • Z80は0x00がNOP(No OPeration)
    命令
    • データバスをすべて0に固定した簡易コンピュータ
    • アドレスバスに何を出しても0x00が読み込める
    38

    View Slide

  172. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション1: NOPコンピュータ
    • Z80は0x00がNOP(No OPeration)
    命令
    • データバスをすべて0に固定した簡易コンピュータ
    • アドレスバスに何を出しても0x00が読み込める
    • NOPを実行し(=何もしないで)次のアドレスを読み込む、を繰り返すコンピュータ
    38

    View Slide

  173. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション1: NOPコンピュータ
    • Z80は0x00がNOP(No OPeration)
    命令
    • データバスをすべて0に固定した簡易コンピュータ
    • アドレスバスに何を出しても0x00が読み込める
    • NOPを実行し(=何もしないで)次のアドレスを読み込む、を繰り返すコンピュータ
    • ここまで実装できていればふつうに動く
    38

    View Slide

  174. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    NOPコンピュータ
    39

    View Slide

  175. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    NOPコンピュータ
    39

    View Slide

  176. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    NOPコンピュータ
    39
    CLK

    View Slide

  177. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    NOPコンピュータ
    39
    アドレスバス
    CLK

    View Slide

  178. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    NOPコンピュータ
    39
    アドレスバス
    RD & WR
    CLK

    View Slide

  179. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    これを Z80 ハードウェア エミュレータ で…
    40

    View Slide

  180. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ 動作の様子
    41

    View Slide

  181. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ 動作の様子
    41

    View Slide

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

    View Slide

  183. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    完璧!
    42
    (に見える)

    View Slide

  184. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション2
    43

    View Slide

  185. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション2: SBCZ80
    44

    View Slide

  186. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション2: SBCZ80
    • Z80のシングルボードコンピュータ
    44

    View Slide

  187. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション2: SBCZ80
    • Z80のシングルボードコンピュータ
    • RAM, ROMを搭載して

    シリアルポート経由でBASICが動く
    44

    View Slide

  188. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション2: SBCZ80
    • Z80のシングルボードコンピュータ
    • RAM, ROMを搭載して

    シリアルポート経由でBASICが動く
    • Z80の機能をフル活用している
    44

    View Slide

  189. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション2: SBCZ80
    • Z80のシングルボードコンピュータ
    • RAM, ROMを搭載して

    シリアルポート経由でBASICが動く
    • Z80の機能をフル活用している
    • DRAM, I/O, 割り込み, …
    44

    View Slide

  190. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    実アプリケーション2: SBCZ80
    • Z80のシングルボードコンピュータ
    • RAM, ROMを搭載して

    シリアルポート経由でBASICが動く
    • Z80の機能をフル活用している
    • DRAM, I/O, 割り込み, …
    • これが動けば

    「Z80 ハードウェア エミュレータ」

    を名乗ってもよかろう
    44

    View Slide

  191. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    これを動かすのだけど…
    45

    View Slide

  192. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    まあもちろん…
    46

    View Slide

  193. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    一発で動く訳がない
    47

    View Slide

  194. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    一発で動く訳がない
    • zexallでカバーされていないI/Oと割り込みにきっちりバグがあった
    47

    View Slide

  195. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    一発で動く訳がない
    • zexallでカバーされていないI/Oと割り込みにきっちりバグがあった
    • 回路にも問題があった
    47

    View Slide

  196. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    一発で動く訳がない
    • zexallでカバーされていないI/Oと割り込みにきっちりバグがあった
    • 回路にも問題があった
    • 絶望的に遅い
    47

    View Slide

  197. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    一発で動く訳がない
    • zexallでカバーされていないI/Oと割り込みにきっちりバグがあった
    • 回路にも問題があった
    • 絶望的に遅い
    • GPIOエクステンダをやめてラッチを使う様にした

    (ここまでの解説はすべてラッチ版)
    47

    View Slide

  198. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    一発で動く訳がない
    • zexallでカバーされていないI/Oと割り込みにきっちりバグがあった
    • 回路にも問題があった
    • 絶望的に遅い
    • GPIOエクステンダをやめてラッチを使う様にした

    (ここまでの解説はすべてラッチ版)
    • たまにメモリ読み込みが化ける
    47

    View Slide

  199. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    一発で動く訳がない
    • zexallでカバーされていないI/Oと割り込みにきっちりバグがあった
    • 回路にも問題があった
    • 絶望的に遅い
    • GPIOエクステンダをやめてラッチを使う様にした

    (ここまでの解説はすべてラッチ版)
    • たまにメモリ読み込みが化ける
    • 信号の衝突 ➡ データバスのバスバッファの方向切替前にHi-Zを経由する
    47

    View Slide

  200. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    一発で動く訳がない
    • zexallでカバーされていないI/Oと割り込みにきっちりバグがあった
    • 回路にも問題があった
    • 絶望的に遅い
    • GPIOエクステンダをやめてラッチを使う様にした

    (ここまでの解説はすべてラッチ版)
    • たまにメモリ読み込みが化ける
    • 信号の衝突 ➡ データバスのバスバッファの方向切替前にHi-Zを経由する
    • なんとなく動く様になった
    47

    View Slide

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

    View Slide

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

    View Slide

  203. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い
    • なんとなく動くが遅い
    49

    View Slide

  204. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い
    • なんとなく動くが遅い
    • Raspberry Pi 4 Model B って 1.8GHzとかっすよ…?
    49

    View Slide

  205. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い
    • なんとなく動くが遅い
    • Raspberry Pi 4 Model B って 1.8GHzとかっすよ…?
    • 2.5MHzのエミュレーションすらできないとは…720倍速いのに…
    49

    View Slide

  206. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い
    • なんとなく動くが遅い
    • Raspberry Pi 4 Model B って 1.8GHzとかっすよ…?
    • 2.5MHzのエミュレーションすらできないとは…720倍速いのに…
    • 遅い理由が2つ
    49

    View Slide

  207. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由1
    C++力が赤児
    50

    View Slide

  208. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由1
    C++力が赤児
    • zexallを動かしていても既存の実装に比べてめっちゃ遅い
    50

    View Slide

  209. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由1
    C++力が赤児
    • zexallを動かしていても既存の実装に比べてめっちゃ遅い
    • レジスタをクラス化してるのがダメ?
    50

    View Slide

  210. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由1
    C++力が赤児
    • zexallを動かしていても既存の実装に比べてめっちゃ遅い
    • レジスタをクラス化してるのがダメ?
    • C++でなくCで書いた方が良いのか…?
    50

    View Slide

  211. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由1
    C++力が赤児
    • zexallを動かしていても既存の実装に比べてめっちゃ遅い
    • レジスタをクラス化してるのがダメ?
    • C++でなくCで書いた方が良いのか…?
    • 既存の実装ぐらいまで高速化を…
    50

    View Slide

  212. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    51

    View Slide

  213. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • Z80のサイクル
    51

    View Slide

  214. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • Z80のサイクル
    • 2.5MHzだと1クロックは 250 ns
    51

    View Slide

  215. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • Z80のサイクル
    • 2.5MHzだと1クロックは 250 ns
    • M1サイクル(命令読み込み)は4クロックなので 1us (マイクロ秒)
    51

    View Slide

  216. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • Z80のサイクル
    • 2.5MHzだと1クロックは 250 ns
    • M1サイクル(命令読み込み)は4クロックなので 1us (マイクロ秒)
    • Raspberry Pi 4 Model B のGPIO操作
    51

    View Slide

  217. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • Z80のサイクル
    • 2.5MHzだと1クロックは 250 ns
    • M1サイクル(命令読み込み)は4クロックなので 1us (マイクロ秒)
    • Raspberry Pi 4 Model B のGPIO操作
    • 1ビット出力の gpioWrite(gpio, value) は平均 118ns かかる
    51

    View Slide

  218. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • Z80のサイクル
    • 2.5MHzだと1クロックは 250 ns
    • M1サイクル(命令読み込み)は4クロックなので 1us (マイクロ秒)
    • Raspberry Pi 4 Model B のGPIO操作
    • 1ビット出力の gpioWrite(gpio, value) は平均 118ns かかる
    • 32ビット同時出力の gpioWrite_Bits_0_31_Set(data) は平均 76ns かかる
    51

    View Slide

  219. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • M1サイクル(の2クロック目まで)


    • CLK(クロック)の立ち上がりを待つ


    • M1を有効化


    • CLKの立ち下がりを待つ


    • 16ビットのアドレスを出力


    • MREQ, RDを有効化


    • M1を有効化


    • クロックの立ち上がりを待つ


    • クロックの立ち下がりを待つ


    • WAITが無効になるのを待つ


    • クロックの立ち上がりを待つ


    • 8ビットのデータを入力


    • MREQ, RDを無効化
    52

    View Slide

  220. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • M1サイクル(の2クロック目まで)


    • CLK(クロック)の立ち上がりを待つ


    • M1を有効化


    • CLKの立ち下がりを待つ


    • 16ビットのアドレスを出力


    • MREQ, RDを有効化


    • M1を有効化


    • クロックの立ち上がりを待つ


    • クロックの立ち下がりを待つ


    • WAITが無効になるのを待つ


    • クロックの立ち上がりを待つ


    • 8ビットのデータを入力


    • MREQ, RDを無効化
    52
    • 愚直にやると2クロック目までで988nsかかる

    View Slide

  221. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • M1サイクル(の2クロック目まで)


    • CLK(クロック)の立ち上がりを待つ


    • M1を有効化


    • CLKの立ち下がりを待つ


    • 16ビットのアドレスを出力


    • MREQ, RDを有効化


    • M1を有効化


    • クロックの立ち上がりを待つ


    • クロックの立ち下がりを待つ


    • WAITが無効になるのを待つ


    • クロックの立ち上がりを待つ


    • 8ビットのデータを入力


    • MREQ, RDを無効化
    52
    • 愚直にやると2クロック目までで988nsかかる
    • クロック的には500nsで終了が必要

    View Slide

  222. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • M1サイクル(の2クロック目まで)


    • CLK(クロック)の立ち上がりを待つ


    • M1を有効化


    • CLKの立ち下がりを待つ


    • 16ビットのアドレスを出力


    • MREQ, RDを有効化


    • M1を有効化


    • クロックの立ち上がりを待つ


    • クロックの立ち下がりを待つ


    • WAITが無効になるのを待つ


    • クロックの立ち上がりを待つ


    • 8ビットのデータを入力


    • MREQ, RDを無効化
    52
    • 愚直にやると2クロック目までで988nsかかる
    • クロック的には500nsで終了が必要
    • 対策

    View Slide

  223. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • M1サイクル(の2クロック目まで)


    • CLK(クロック)の立ち上がりを待つ


    • M1を有効化


    • CLKの立ち下がりを待つ


    • 16ビットのアドレスを出力


    • MREQ, RDを有効化


    • M1を有効化


    • クロックの立ち上がりを待つ


    • クロックの立ち下がりを待つ


    • WAITが無効になるのを待つ


    • クロックの立ち上がりを待つ


    • 8ビットのデータを入力


    • MREQ, RDを無効化
    52
    • 愚直にやると2クロック目までで988nsかかる
    • クロック的には500nsで終了が必要
    • 対策
    • 近い処理はまとめる

    View Slide

  224. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • M1サイクル(の2クロック目まで)


    • CLK(クロック)の立ち上がりを待つ


    • M1を有効化


    • CLKの立ち下がりを待つ


    • 16ビットのアドレスを出力


    • MREQ, RDを有効化


    • M1を有効化


    • クロックの立ち上がりを待つ


    • クロックの立ち下がりを待つ


    • WAITが無効になるのを待つ


    • クロックの立ち上がりを待つ


    • 8ビットのデータを入力


    • MREQ, RDを無効化
    52
    • 愚直にやると2クロック目までで988nsかかる
    • クロック的には500nsで終了が必要
    • 対策
    • 近い処理はまとめる
    • M1, RD, MREQ有効化はまとめて同じタイミングで出力する

    View Slide

  225. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • M1サイクル(の2クロック目まで)


    • CLK(クロック)の立ち上がりを待つ


    • M1を有効化


    • CLKの立ち下がりを待つ


    • 16ビットのアドレスを出力


    • MREQ, RDを有効化


    • M1を有効化


    • クロックの立ち上がりを待つ


    • クロックの立ち下がりを待つ


    • WAITが無効になるのを待つ


    • クロックの立ち上がりを待つ


    • 8ビットのデータを入力


    • MREQ, RDを無効化
    52
    • 愚直にやると2クロック目までで988nsかかる
    • クロック的には500nsで終了が必要
    • 対策
    • 近い処理はまとめる
    • M1, RD, MREQ有効化はまとめて同じタイミングで出力する
    • クロックを見ない

    View Slide

  226. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • M1サイクル(の2クロック目まで)


    • CLK(クロック)の立ち上がりを待つ


    • M1を有効化


    • CLKの立ち下がりを待つ


    • 16ビットのアドレスを出力


    • MREQ, RDを有効化


    • M1を有効化


    • クロックの立ち上がりを待つ


    • クロックの立ち下がりを待つ


    • WAITが無効になるのを待つ


    • クロックの立ち上がりを待つ


    • 8ビットのデータを入力


    • MREQ, RDを無効化
    52
    • 愚直にやると2クロック目までで988nsかかる
    • クロック的には500nsで終了が必要
    • 対策
    • 近い処理はまとめる
    • M1, RD, MREQ有効化はまとめて同じタイミングで出力する
    • クロックを見ない
    • メモリや外部デバイスはCPUが「もういいよ」を表現するまで

    データを提示し続ける

    View Slide

  227. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    遅い理由2
    GPIOの制御に時間がかかる
    • M1サイクル(の2クロック目まで)


    • CLK(クロック)の立ち上がりを待つ


    • M1を有効化


    • CLKの立ち下がりを待つ


    • 16ビットのアドレスを出力


    • MREQ, RDを有効化


    • M1を有効化


    • クロックの立ち上がりを待つ


    • クロックの立ち下がりを待つ


    • WAITが無効になるのを待つ


    • クロックの立ち上がりを待つ


    • 8ビットのデータを入力


    • MREQ, RDを無効化
    52
    • 愚直にやると2クロック目までで988nsかかる
    • クロック的には500nsで終了が必要
    • 対策
    • 近い処理はまとめる
    • M1, RD, MREQ有効化はまとめて同じタイミングで出力する
    • クロックを見ない
    • メモリや外部デバイスはCPUが「もういいよ」を表現するまで

    データを提示し続ける
    • 他のシステムでも通用するかはわからない

    View Slide

  228. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    そしてBASICがそれなりに動く様に…
    53

    View Slide

  229. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ 動作の様子
    54
    シリアルコンソールで


    SBCZ80に接続しています

    View Slide

  230. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ 動作の様子
    54
    シリアルコンソールで


    SBCZ80に接続しています

    View Slide

  231. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    やったぜ 🎉
    55

    View Slide

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

    View Slide

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

    View Slide

  234. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ の構成
    • ハードウェアI/Fエミュレータ + ソフトウェアCPUエミュレータ
    57

    View Slide

  235. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ の構成
    • ハードウェアI/Fエミュレータ + ソフトウェアCPUエミュレータ
    • ハードウェアI/Fエミュレータ部分はCPUの物理I/Fのソフトウェア実装
    57

    View Slide

  236. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ の構成
    • ハードウェアI/Fエミュレータ + ソフトウェアCPUエミュレータ
    • ハードウェアI/Fエミュレータ部分はCPUの物理I/Fのソフトウェア実装
    • 電気信号のプロトコル(API)のエミュレート
    57

    View Slide

  237. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ の構成
    • ハードウェアI/Fエミュレータ + ソフトウェアCPUエミュレータ
    • ハードウェアI/Fエミュレータ部分はCPUの物理I/Fのソフトウェア実装
    • 電気信号のプロトコル(API)のエミュレート
    • Z80マニュアルに書いてあるとおりに信号線を上げ下げする
    57

    View Slide

  238. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ の構成
    • ハードウェアI/Fエミュレータ + ソフトウェアCPUエミュレータ
    • ハードウェアI/Fエミュレータ部分はCPUの物理I/Fのソフトウェア実装
    • 電気信号のプロトコル(API)のエミュレート
    • Z80マニュアルに書いてあるとおりに信号線を上げ下げする
    • 参考: 「PHPから見たハードウェア制御」 (PHP Conference Japan 2021)
    57

    View Slide

  239. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ の構成
    • ハードウェアI/Fエミュレータ + ソフトウェアCPUエミュレータ
    • ハードウェアI/Fエミュレータ部分はCPUの物理I/Fのソフトウェア実装
    • 電気信号のプロトコル(API)のエミュレート
    • Z80マニュアルに書いてあるとおりに信号線を上げ下げする
    • 参考: 「PHPから見たハードウェア制御」 (PHP Conference Japan 2021)
    • CPUエミュレータ部分はCPU機能のソフトウェア実装
    57

    View Slide

  240. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 ハードウェア エミュレータ の構成
    • ハードウェアI/Fエミュレータ + ソフトウェアCPUエミュレータ
    • ハードウェアI/Fエミュレータ部分はCPUの物理I/Fのソフトウェア実装
    • 電気信号のプロトコル(API)のエミュレート
    • Z80マニュアルに書いてあるとおりに信号線を上げ下げする
    • 参考: 「PHPから見たハードウェア制御」 (PHP Conference Japan 2021)
    • CPUエミュレータ部分はCPU機能のソフトウェア実装
    • 「エミュレート対象としてのCPU」と同じ
    57

    View Slide

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

    View Slide

  242. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアエミュレータから見たCPU
    • 対象CPUを搭載したコンピュータ用に書かれたプログラムを

    すべて動作させる必要がある電気回路 + ソフトウェア
    58

    View Slide

  243. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアエミュレータから見たCPU
    • 対象CPUを搭載したコンピュータ用に書かれたプログラムを

    すべて動作させる必要がある電気回路 + ソフトウェア
    • 命令実行部分は完全なエミュレートが要求される
    58

    View Slide

  244. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアエミュレータから見たCPU
    • 対象CPUを搭載したコンピュータ用に書かれたプログラムを

    すべて動作させる必要がある電気回路 + ソフトウェア
    • 命令実行部分は完全なエミュレートが要求される
    • ハードウェアI/F部分は周辺デバイスが割と忖度してくれる
    58

    View Slide

  245. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアエミュレータから見たCPU
    • 対象CPUを搭載したコンピュータ用に書かれたプログラムを

    すべて動作させる必要がある電気回路 + ソフトウェア
    • 命令実行部分は完全なエミュレートが要求される
    • ハードウェアI/F部分は周辺デバイスが割と忖度してくれる
    • 「我・CPU」みたいな態度でちょっと適当にやっても大丈夫(かも)
    58

    View Slide

  246. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ハードウェアエミュレータから見たCPU
    • 対象CPUを搭載したコンピュータ用に書かれたプログラムを

    すべて動作させる必要がある電気回路 + ソフトウェア
    • 命令実行部分は完全なエミュレートが要求される
    • ハードウェアI/F部分は周辺デバイスが割と忖度してくれる
    • 「我・CPU」みたいな態度でちょっと適当にやっても大丈夫(かも)
    • バスマスタ的な機能が付いたCPUだとそうはいかない
    58

    View Slide

  247. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    59

    View Slide

  248. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • 遅い → 高速化
    59

    View Slide

  249. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • 遅い → 高速化
    • C++プログラムとしての最適化
    59

    View Slide

  250. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • 遅い → 高速化
    • C++プログラムとしての最適化
    • Raspberry Pi のベアメタルモード
    59

    View Slide

  251. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • 遅い → 高速化
    • C++プログラムとしての最適化
    • Raspberry Pi のベアメタルモード
    • I/O or/and 割り込みを取りこぼす問題の修正
    59

    View Slide

  252. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • 遅い → 高速化
    • C++プログラムとしての最適化
    • Raspberry Pi のベアメタルモード
    • I/O or/and 割り込みを取りこぼす問題の修正
    • キー入力を取りこぼしている
    59

    View Slide

  253. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • 遅い → 高速化
    • C++プログラムとしての最適化
    • Raspberry Pi のベアメタルモード
    • I/O or/and 割り込みを取りこぼす問題の修正
    • キー入力を取りこぼしている
    • 割り込みルーチンがおかしいのかも
    59

    View Slide

  254. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    60

    View Slide

  255. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • パソコンでの動作
    60

    View Slide

  256. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • パソコンでの動作
    • HB-F1XDJ(MSX2+パソコン)に刺して動かしたい
    60

    View Slide

  257. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • パソコンでの動作
    • HB-F1XDJ(MSX2+パソコン)に刺して動かしたい
    • CPUアクセラレータとしての効果
    60

    View Slide

  258. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • パソコンでの動作
    • HB-F1XDJ(MSX2+パソコン)に刺して動かしたい
    • CPUアクセラレータとしての効果
    • Raspberry Piのメモリをメインメモリに見せかけてさらなる高速化
    60

    View Slide

  259. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • パソコンでの動作
    • HB-F1XDJ(MSX2+パソコン)に刺して動かしたい
    • CPUアクセラレータとしての効果
    • Raspberry Piのメモリをメインメモリに見せかけてさらなる高速化
    • I/Oを乗っ取ってRaspberry Pi上のFDDイメージにアクセス
    60

    View Slide

  260. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • パソコンでの動作
    • HB-F1XDJ(MSX2+パソコン)に刺して動かしたい
    • CPUアクセラレータとしての効果
    • Raspberry Piのメモリをメインメモリに見せかけてさらなる高速化
    • I/Oを乗っ取ってRaspberry Pi上のFDDイメージにアクセス
    • 小型化
    60

    View Slide

  261. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • パソコンでの動作
    • HB-F1XDJ(MSX2+パソコン)に刺して動かしたい
    • CPUアクセラレータとしての効果
    • Raspberry Piのメモリをメインメモリに見せかけてさらなる高速化
    • I/Oを乗っ取ってRaspberry Pi上のFDDイメージにアクセス
    • 小型化
    • Raspberry Pi + フラットケーブル + CPUぐらいのサイズの基板 ぐらいにしてみたい
    60

    View Slide

  262. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Future works
    今後の展開
    • パソコンでの動作
    • HB-F1XDJ(MSX2+パソコン)に刺して動かしたい
    • CPUアクセラレータとしての効果
    • Raspberry Piのメモリをメインメモリに見せかけてさらなる高速化
    • I/Oを乗っ取ってRaspberry Pi上のFDDイメージにアクセス
    • 小型化
    • Raspberry Pi + フラットケーブル + CPUぐらいのサイズの基板 ぐらいにしてみたい
    • もうちょっといろいろやってみようと思います
    60

    View Slide

  263. 61
    ௕୩઒ஐر
    ͸͕ͤΘ ͱ΋͖
    @tomzoh
    続CPUとは何か
    ϋʔυ΢ΣΞΤϛϡϨʔλ͔Βݟͨ$16
    tomzoh先生の次回作にご期待ください
    俺たちの戦いはまだ始まったばかりだ!

    View Slide

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

    https://github.com/hasegawa-tomoki/z80-hardware-emulator


    prelim, zexall

    https://github.com/superzazu/z80


    prelim, zexall アセンブル & 配列形式への変換

    https://github.com/hasegawa-tomoki/z80-hardware-emulator-test


    8ビット CPU Z80LED点滅

    http://www.yamamo10.jp/yamamoto/comp/Z80/FlashingLEDs/index.php


    SBCZ80技術資料

    http://www.amy.hi-ho.ne.jp/officetetsu/storage/sbcz80_techdata.pdf
    62

    View Slide

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

    View Slide

  266. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    CLion
    JetBrainsのC/C++用IDE
    • 機能が PhpStorm と同じで快適


    • Raspberry Pi に ssh 接続して

    ctrl + r で実行・デバッグ


    • 気の利くWarningで

    へたれC++プログラマに最高
    64

    View Slide

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

    View Slide

  268. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムの実行とは…?
    66

    View Slide

  269. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムを「実行する」とは?
    67

    View Slide

  270. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムを「実行する」とは?
    php hoge.php
    67

    View Slide

  271. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムを「実行する」とは?
    php hoge.php
    php という名前のプログラムが①実行され

    php は hoge.php を読み込んで②実行する
    67

    View Slide

  272. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムを「実行する」とは?
    php hoge.php
    php という名前のプログラムが①実行され

    php は hoge.php を読み込んで②実行する
    67
    ①実行 CPUがマシン語のプログラムを実行する

    View Slide

  273. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムを「実行する」とは?
    php hoge.php
    php という名前のプログラムが①実行され

    php は hoge.php を読み込んで②実行する
    67
    ①実行 CPUがマシン語のプログラムを実行する
    ②実行 phpがPHP言語のプログラムを実行する

    View Slide

  274. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムを「実行する」とは?
    php hoge.php
    php という名前のプログラムが①実行され

    php は hoge.php を読み込んで②実行する
    67
    ①実行 CPUがマシン語のプログラムを実行する
    ②実行 phpがPHP言語のプログラムを実行する
    ①実行 と ②実行 は何が違う?

    View Slide

  275. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ①実行 CPUがマシン語のプログラムを実行する
    68

    View Slide

  276. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    69

    View Slide

  277. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    • CPUはマシン語を実行する機械 (machine)
    69

    View Slide

  278. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    • CPUはマシン語を実行する機械 (machine)
    • マシン語 = 構文解析なしに単体で実行可能な命令
    69

    View Slide

  279. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    • CPUはマシン語を実行する機械 (machine)
    • マシン語 = 構文解析なしに単体で実行可能な命令
    • シンプルな単一機能の命令
    69

    View Slide

  280. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    • CPUはマシン語を実行する機械 (machine)
    • マシン語 = 構文解析なしに単体で実行可能な命令
    • シンプルな単一機能の命令
    • CPUは内部にレジスタを持つ
    69

    View Slide

  281. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    • CPUはマシン語を実行する機械 (machine)
    • マシン語 = 構文解析なしに単体で実行可能な命令
    • シンプルな単一機能の命令
    • CPUは内部にレジスタを持つ
    • 決まった名前を持ち、決まったサイズの超高速なメモリ
    69

    View Slide

  282. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    • CPUはマシン語を実行する機械 (machine)
    • マシン語 = 構文解析なしに単体で実行可能な命令
    • シンプルな単一機能の命令
    • CPUは内部にレジスタを持つ
    • 決まった名前を持ち、決まったサイズの超高速なメモリ
    • 一般プログラミング言語で言うところの変数
    69

    View Slide

  283. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    • CPUはマシン語を実行する機械 (machine)
    • マシン語 = 構文解析なしに単体で実行可能な命令
    • シンプルな単一機能の命令
    • CPUは内部にレジスタを持つ
    • 決まった名前を持ち、決まったサイズの超高速なメモリ
    • 一般プログラミング言語で言うところの変数
    • 汎用レジスタ, 特定用途レジスタ (PC: プログラムカウンタ, SP: スタックポインタ)
    69

    View Slide

  284. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    • CPUはマシン語を実行する機械 (machine)
    • マシン語 = 構文解析なしに単体で実行可能な命令
    • シンプルな単一機能の命令
    • CPUは内部にレジスタを持つ
    • 決まった名前を持ち、決まったサイズの超高速なメモリ
    • 一般プログラミング言語で言うところの変数
    • 汎用レジスタ, 特定用途レジスタ (PC: プログラムカウンタ, SP: スタックポインタ)
    • PC: CPUが実行中のメモリアドレスを指す
    69

    View Slide

  285. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    • CPUはマシン語を実行する機械 (machine)
    • マシン語 = 構文解析なしに単体で実行可能な命令
    • シンプルな単一機能の命令
    • CPUは内部にレジスタを持つ
    • 決まった名前を持ち、決まったサイズの超高速なメモリ
    • 一般プログラミング言語で言うところの変数
    • 汎用レジスタ, 特定用途レジスタ (PC: プログラムカウンタ, SP: スタックポインタ)
    • PC: CPUが実行中のメモリアドレスを指す
    • 「命令を実行してPCレジスタの値を+1」を繰り返すのがCPU
    69

    View Slide

  286. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    マシン語の実行
    • CPUはマシン語を実行する機械 (machine)
    • マシン語 = 構文解析なしに単体で実行可能な命令
    • シンプルな単一機能の命令
    • CPUは内部にレジスタを持つ
    • 決まった名前を持ち、決まったサイズの超高速なメモリ
    • 一般プログラミング言語で言うところの変数
    • 汎用レジスタ, 特定用途レジスタ (PC: プログラムカウンタ, SP: スタックポインタ)
    • PC: CPUが実行中のメモリアドレスを指す
    • 「命令を実行してPCレジスタの値を+1」を繰り返すのがCPU
    • マルチスレッドCPUはPCレジスタを2つ持っている
    69

    View Slide

  287. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムカウンタ(PC)とマシン語の実行
    70

    View Slide

  288. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムカウンタ(PC)とマシン語の実行
    70
    78 D8 A9 10 8D 00 20 A2 FF 9A AD 02 20 10 FB AD


    02 20 10 FB A0 FE A2 05 BD D7 07 C9 0A B0 0C CA


    10 F6 AD FF 07 C9 A5 D0 02 A0 D6 20 CC 90 8D 11


    40 8D 70 07 A9 A5 8D FF 07 8D A7 07 A9 0F 8D 15
    $8000


    $8010


    $8020


    $8030
    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F

    View Slide

  289. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムカウンタ(PC)とマシン語の実行
    70
    78 D8 A9 10 8D 00 20 A2 FF 9A AD 02 20 10 FB AD


    02 20 10 FB A0 FE A2 05 BD D7 07 C9 0A B0 0C CA


    10 F6 AD FF 07 C9 A5 D0 02 A0 D6 20 CC 90 8D 11


    40 8D 70 07 A9 A5 8D FF 07 8D A7 07 A9 0F 8D 15
    $8000


    $8010


    $8020


    $8030
    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F $78


    $D8


    $A9 $10


    $8D $00 $20


    $A2 $ff


    $9A
    SEI


    CLD


    LDA #imm


    STA abs


    LDX #imm


    TXS
    $8000


    $8001


    $8002


    $8004


    $8007


    $8009

    View Slide

  290. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムカウンタ(PC)とマシン語の実行
    70
    78 D8 A9 10 8D 00 20 A2 FF 9A AD 02 20 10 FB AD


    02 20 10 FB A0 FE A2 05 BD D7 07 C9 0A B0 0C CA


    10 F6 AD FF 07 C9 A5 D0 02 A0 D6 20 CC 90 8D 11


    40 8D 70 07 A9 A5 8D FF 07 8D A7 07 A9 0F 8D 15
    $8000


    $8010


    $8020


    $8030
    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F $78


    $D8


    $A9 $10


    $8D $00 $20


    $A2 $ff


    $9A
    SEI


    CLD


    LDA #imm


    STA abs


    LDX #imm


    TXS
    $8000


    $8001


    $8002


    $8004


    $8007


    $8009
    PC

    View Slide

  291. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムカウンタ(PC)とマシン語の実行
    70
    78 D8 A9 10 8D 00 20 A2 FF 9A AD 02 20 10 FB AD


    02 20 10 FB A0 FE A2 05 BD D7 07 C9 0A B0 0C CA


    10 F6 AD FF 07 C9 A5 D0 02 A0 D6 20 CC 90 8D 11


    40 8D 70 07 A9 A5 8D FF 07 8D A7 07 A9 0F 8D 15
    $8000


    $8010


    $8020


    $8030
    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F $78


    $D8


    $A9 $10


    $8D $00 $20


    $A2 $ff


    $9A
    SEI


    CLD


    LDA #imm


    STA abs


    LDX #imm


    TXS
    $8000


    $8001


    $8002


    $8004


    $8007


    $8009
    PC

    View Slide

  292. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムカウンタ(PC)とマシン語の実行
    70
    78 D8 A9 10 8D 00 20 A2 FF 9A AD 02 20 10 FB AD


    02 20 10 FB A0 FE A2 05 BD D7 07 C9 0A B0 0C CA


    10 F6 AD FF 07 C9 A5 D0 02 A0 D6 20 CC 90 8D 11


    40 8D 70 07 A9 A5 8D FF 07 8D A7 07 A9 0F 8D 15
    $8000


    $8010


    $8020


    $8030
    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F $78


    $D8


    $A9 $10


    $8D $00 $20


    $A2 $ff


    $9A
    SEI


    CLD


    LDA #imm


    STA abs


    LDX #imm


    TXS
    $8000


    $8001


    $8002


    $8004


    $8007


    $8009
    PC

    View Slide

  293. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    プログラムカウンタ(PC)とマシン語の実行
    70
    78 D8 A9 10 8D 00 20 A2 FF 9A AD 02 20 10 FB AD


    02 20 10 FB A0 FE A2 05 BD D7 07 C9 0A B0 0C CA


    10 F6 AD FF 07 C9 A5 D0 02 A0 D6 20 CC 90 8D 11


    40 8D 70 07 A9 A5 8D FF 07 8D A7 07 A9 0F 8D 15
    $8000


    $8010


    $8020


    $8030
    00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F $78


    $D8


    $A9 $10


    $8D $00 $20


    $A2 $ff


    $9A
    SEI


    CLD


    LDA #imm


    STA abs


    LDX #imm


    TXS
    $8000


    $8001


    $8002


    $8004


    $8007


    $8009
    PC

    View Slide

  294. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    ②実行 phpがPHP言語のプログラムを実行する
    71

    View Slide

  295. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    PHPプログラムの実行
    72

    View Slide

  296. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    PHPプログラムの実行
    • php hoge.php
    72

    View Slide

  297. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    PHPプログラムの実行
    • php hoge.php
    • phpコマンドはマシン語のプログラム
    72

    View Slide

  298. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    PHPプログラムの実行
    • php hoge.php
    • phpコマンドはマシン語のプログラム
    • 「PHPの変数をメモリ上に確保する」「PHPの関数コールを実行する」…が記述されてい

    72

    View Slide

  299. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    PHPプログラムの実行
    • php hoge.php
    • phpコマンドはマシン語のプログラム
    • 「PHPの変数をメモリ上に確保する」「PHPの関数コールを実行する」…が記述されてい

    • hoge.phpをテキストファイルとして読み込んで構文解析し、実行しやすい形でメモリに
    展開して、順番に書かれた処理を実行していく
    72

    View Slide

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

    PHPはコンパイルするんだろ?
    73

    View Slide

  301. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    コンパイル
    74

    View Slide

  302. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    コンパイル
    74
    javac hoge.java


    gcc hoge.c

    View Slide

  303. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    コンパイル
    74
    Javaのソースコード ➡ Javaバイトコード
    javac hoge.java


    gcc hoge.c

    View Slide

  304. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    コンパイル
    74
    Javaのソースコード ➡ Javaバイトコード
    C言語のソースコード ➡ マシン語
    javac hoge.java


    gcc hoge.c

    View Slide

  305. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    コンパイル
    74
    Javaのソースコード ➡ Javaバイトコード
    C言語のソースコード ➡ マシン語
    どちらもコンパイル
    javac hoge.java


    gcc hoge.c

    View Slide

  306. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    コンパイル
    74
    Javaのソースコード ➡ Javaバイトコード
    C言語のソースコード ➡ マシン語
    どちらもコンパイル
    違いは成果物がCPUでそのまま実行できるか否か
    javac hoge.java


    gcc hoge.c

    View Slide

  307. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    コンパイル
    74
    Javaのソースコード ➡ Javaバイトコード
    C言語のソースコード ➡ マシン語
    どちらもコンパイル
    違いは成果物がCPUでそのまま実行できるか否か
    javac hoge.java


    gcc hoge.c
    PHPもコンパイルという言葉を使う

    View Slide

  308. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    コンパイル
    74
    Javaのソースコード ➡ Javaバイトコード
    C言語のソースコード ➡ マシン語
    どちらもコンパイル
    違いは成果物がCPUでそのまま実行できるか否か
    javac hoge.java


    gcc hoge.c
    PHPもコンパイルという言葉を使う
    ➡ PHPのソースコードをPHP Opcodeにコンパイルする

    (CPUでそのまま実行できない = PHPが実行する)

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  313. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    アドレスバスとデータバス
    • アドレスバス
    78

    View Slide

  314. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    アドレスバスとデータバス
    • アドレスバス
    • メモリなどのアドレスを指定する信号線の総称
    78

    View Slide

  315. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    アドレスバスとデータバス
    • アドレスバス
    • メモリなどのアドレスを指定する信号線の総称
    • Z80は16本の信号線を持つ = アドレスバス 16bit
    78

    View Slide

  316. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    アドレスバスとデータバス
    • アドレスバス
    • メモリなどのアドレスを指定する信号線の総称
    • Z80は16本の信号線を持つ = アドレスバス 16bit
    • アドレスとして 0x0000(0) 〜 0xffff(65,535) まで表現できる
    78

    View Slide

  317. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    アドレスバスとデータバス
    • アドレスバス
    • メモリなどのアドレスを指定する信号線の総称
    • Z80は16本の信号線を持つ = アドレスバス 16bit
    • アドレスとして 0x0000(0) 〜 0xffff(65,535) まで表現できる
    • 0x = 16進数 ($も16進数)
    78

    View Slide

  318. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    アドレスバスとデータバス
    • アドレスバス
    • メモリなどのアドレスを指定する信号線の総称
    • Z80は16本の信号線を持つ = アドレスバス 16bit
    • アドレスとして 0x0000(0) 〜 0xffff(65,535) まで表現できる
    • 0x = 16進数 ($も16進数)
    • データバス
    78

    View Slide

  319. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    アドレスバスとデータバス
    • アドレスバス
    • メモリなどのアドレスを指定する信号線の総称
    • Z80は16本の信号線を持つ = アドレスバス 16bit
    • アドレスとして 0x0000(0) 〜 0xffff(65,535) まで表現できる
    • 0x = 16進数 ($も16進数)
    • データバス
    • データの入出力に使う信号線の総称
    78

    View Slide

  320. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    アドレスバスとデータバス
    • アドレスバス
    • メモリなどのアドレスを指定する信号線の総称
    • Z80は16本の信号線を持つ = アドレスバス 16bit
    • アドレスとして 0x0000(0) 〜 0xffff(65,535) まで表現できる
    • 0x = 16進数 ($も16進数)
    • データバス
    • データの入出力に使う信号線の総称
    • Z80は8本の信号線を持つ = データバス 8bit
    78

    View Slide

  321. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    アドレスバスとデータバス
    • アドレスバス
    • メモリなどのアドレスを指定する信号線の総称
    • Z80は16本の信号線を持つ = アドレスバス 16bit
    • アドレスとして 0x0000(0) 〜 0xffff(65,535) まで表現できる
    • 0x = 16進数 ($も16進数)
    • データバス
    • データの入出力に使う信号線の総称
    • Z80は8本の信号線を持つ = データバス 8bit
    • 1回に1byteのデータを入出力できる
    78

    View Slide

  322. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    アドレスバスとデータバス
    • アドレスバス
    • メモリなどのアドレスを指定する信号線の総称
    • Z80は16本の信号線を持つ = アドレスバス 16bit
    • アドレスとして 0x0000(0) 〜 0xffff(65,535) まで表現できる
    • 0x = 16進数 ($も16進数)
    • データバス
    • データの入出力に使う信号線の総称
    • Z80は8本の信号線を持つ = データバス 8bit
    • 1回に1byteのデータを入出力できる
    • Z80は65,536bytes = 64KBのメモリ空間にアクセスできる
    78

    View Slide

  323. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80 CPU命令の実装
    79

    View Slide

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

    View Slide

  325. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    メモリからレジスタへのロード
    81

    View Slide

  326. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    メモリからレジスタへのロード
    • メモリからデータを読み込んでレジスタに格納する
    81

    View Slide

  327. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    メモリからレジスタへのロード
    • メモリからデータを読み込んでレジスタに格納する
    • Z80は8ビットレジスタ A, B, C, D, E, H, L を持っている
    81

    View Slide

  328. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    メモリからレジスタへのロード
    • メモリからデータを読み込んでレジスタに格納する
    • Z80は8ビットレジスタ A, B, C, D, E, H, L を持っている
    • レジスタはCPUの内部なのでソフトウェアとして好きに実装すれば良い
    81

    View Slide

  329. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    メモリからレジスタへのロード
    • メモリからデータを読み込んでレジスタに格納する
    • Z80は8ビットレジスタ A, B, C, D, E, H, L を持っている
    • レジスタはCPUの内部なのでソフトウェアとして好きに実装すれば良い
    • Z80 ハードウェア エミュレータ では

    Cpuクラスが Registersクラスのインスタンスを保持している
    81

    View Slide

  330. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    メモリからレジスタへのロード
    • メモリからデータを読み込んでレジスタに格納する
    • Z80は8ビットレジスタ A, B, C, D, E, H, L を持っている
    • レジスタはCPUの内部なのでソフトウェアとして好きに実装すれば良い
    • Z80 ハードウェア エミュレータ では

    Cpuクラスが Registersクラスのインスタンスを保持している
    • this->_cpu->registers.a = 0xff
    81

    View Slide

  331. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    0x3A: LD A, (nn)
    nnで指定されたアドレスからデータを読み込んでAレジスタに格納する
    82

    View Slide

  332. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    case 0x3A: {
    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);
    break;
    }
    0x3A: LD A, (nn)
    nnで指定されたアドレスからデータを読み込んでAレジスタに格納する
    82

    View Slide

  333. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    case 0x3A: {
    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);
    break;
    }
    0x3A: LD A, (nn)
    nnで指定されたアドレスからデータを読み込んでAレジスタに格納する
    82
    LD A,(0x8000): 3A 00 80 xx

    View Slide

  334. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    case 0x3A: {
    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);
    break;
    }
    0x3A: LD A, (nn)
    nnで指定されたアドレスからデータを読み込んでAレジスタに格納する
    82
    LD A,(0x8000): 3A 00 80 xx
    PC

    View Slide

  335. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    case 0x3A: {
    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);
    break;
    }
    0x3A: LD A, (nn)
    nnで指定されたアドレスからデータを読み込んでAレジスタに格納する
    82
    LD A,(0x8000): 3A 00 80 xx
    PC

    View Slide

  336. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    83

    View Slide

  337. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    • メモリとレジスタの間のロード
    83

    View Slide

  338. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    • メモリとレジスタの間のロード
    • メモリとレジスタの間の演算
    83

    View Slide

  339. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    • メモリとレジスタの間のロード
    • メモリとレジスタの間の演算
    • 加算, 減算, シフト, 比較, ビット操作, 論理演算 …
    83

    View Slide

  340. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    • メモリとレジスタの間のロード
    • メモリとレジスタの間の演算
    • 加算, 減算, シフト, 比較, ビット操作, 論理演算 …
    • ジャンプ, コール
    83

    View Slide

  341. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    • メモリとレジスタの間のロード
    • メモリとレジスタの間の演算
    • 加算, 減算, シフト, 比較, ビット操作, 論理演算 …
    • ジャンプ, コール
    • ジャンプはPCレジスタに値を入れるだけ
    83

    View Slide

  342. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    • メモリとレジスタの間のロード
    • メモリとレジスタの間の演算
    • 加算, 減算, シフト, 比較, ビット操作, 論理演算 …
    • ジャンプ, コール
    • ジャンプはPCレジスタに値を入れるだけ
    • 次の命令はPCレジスタが指すアドレスから読み込まれる
    83

    View Slide

  343. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    • メモリとレジスタの間のロード
    • メモリとレジスタの間の演算
    • 加算, 減算, シフト, 比較, ビット操作, 論理演算 …
    • ジャンプ, コール
    • ジャンプはPCレジスタに値を入れるだけ
    • 次の命令はPCレジスタが指すアドレスから読み込まれる
    • コールの場合、スタックに次のアドレスを入れてからジャンプする
    83

    View Slide

  344. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    • メモリとレジスタの間のロード
    • メモリとレジスタの間の演算
    • 加算, 減算, シフト, 比較, ビット操作, 論理演算 …
    • ジャンプ, コール
    • ジャンプはPCレジスタに値を入れるだけ
    • 次の命令はPCレジスタが指すアドレスから読み込まれる
    • コールの場合、スタックに次のアドレスを入れてからジャンプする
    • リターン命令を実行するとスタックからアドレスを取り出してジャンプする = 元の場所に戻る
    83

    View Slide

  345. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    • メモリとレジスタの間のロード
    • メモリとレジスタの間の演算
    • 加算, 減算, シフト, 比較, ビット操作, 論理演算 …
    • ジャンプ, コール
    • ジャンプはPCレジスタに値を入れるだけ
    • 次の命令はPCレジスタが指すアドレスから読み込まれる
    • コールの場合、スタックに次のアドレスを入れてからジャンプする
    • リターン命令を実行するとスタックからアドレスを取り出してジャンプする = 元の場所に戻る
    • 特殊命令
    83

    View Slide

  346. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    命令のタイプ
    Z80の持つ命令はいくつかのタイプに分類できる
    • メモリとレジスタの間のロード
    • メモリとレジスタの間の演算
    • 加算, 減算, シフト, 比較, ビット操作, 論理演算 …
    • ジャンプ, コール
    • ジャンプはPCレジスタに値を入れるだけ
    • 次の命令はPCレジスタが指すアドレスから読み込まれる
    • コールの場合、スタックに次のアドレスを入れてからジャンプする
    • リターン命令を実行するとスタックからアドレスを取り出してジャンプする = 元の場所に戻る
    • 特殊命令
    • スタック操作, ブロック転送, I/O, …
    83

    View Slide

  347. 長谷川智希 @tomzoh
    続CPUとは何か - ハードウェアエミュレータから見たCPU
    Z80のM1サイクル
    84

    View Slide

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

    View Slide

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

    View Slide