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. 2 ௕୩઒ஐر ͸͕ͤΘ ͱ΋͖ @tomzoh http://www.dgcircus.com デジタルサーカス株式会社 副団長CTO ॴଐ ٕज़ΧϯϑΝϨϯεओ࠻

    دߘɾஶॻ 来たれ!PHPer!We are hiring! 4PGUXBSF%FTJHO೥݄߸ ʮ$16ͱ͸ԿͩΖ͏͔ʯ
  2. 3 ௕୩઒ஐر ͸͕ͤΘ ͱ΋͖ @tomzoh ςοΫΧϯϑΝϨϯεӡӦࢀՃ 8FCJ04ΞϓϦ։ൃ  $16 ϨτϩήʔϜػ

    ిࢠ޻࡞ Ϗʔϧ  αοΧʔ؍ઓ ϨϯλϧΧʔτϨʔε ʜ ϥΠϑϫʔΫ
  3. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 前回までのあらすじ PHP Conference Japan 2019

    • 「CPUとは何か」をPHPで考える • CPUを3つの視点で見た • プログラム実行環境 • エミュレート対象 • 電気回路 5
  4. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU CPU 3つの視点 - 1: プログラム実行環境

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

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

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

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

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

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

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

    • 対象CPUのエミュレータを作る • CPUをエミュレート対象として見ると: • 他人の書いたプログラムを受け入れる存在に見える • CPUエミュレータと外部との境界は曖昧 • CPUエミュレータ単体でなくコンピュータのエミュレータの中の1コンポーネントとして 
 実装される / グラフィックやサウンド、入出力との境界は曖昧 • Hardware speci fi cation as Code 7
  12. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU CPU 3つの視点 - 2: エミュレート対象

    • 対象CPUのエミュレータを作る • CPUをエミュレート対象として見ると: • 他人の書いたプログラムを受け入れる存在に見える • CPUエミュレータと外部との境界は曖昧 • CPUエミュレータ単体でなくコンピュータのエミュレータの中の1コンポーネントとして 
 実装される / グラフィックやサウンド、入出力との境界は曖昧 • Hardware speci fi cation as Code • エミュレータのソースを読むとハードウェアの仕様がわかる 7
  13. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU CPU 3つの視点 - 2: エミュレート対象

    • 対象CPUのエミュレータを作る • CPUをエミュレート対象として見ると: • 他人の書いたプログラムを受け入れる存在に見える • CPUエミュレータと外部との境界は曖昧 • CPUエミュレータ単体でなくコンピュータのエミュレータの中の1コンポーネントとして 
 実装される / グラフィックやサウンド、入出力との境界は曖昧 • Hardware speci fi cation as Code • エミュレータのソースを読むとハードウェアの仕様がわかる • Undocumentedな仕様もエミュレータのソースには書いてある 7
  14. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU CPU 3つの視点 - 3: 電気回路

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

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

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

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

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

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

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

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

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

    • 4つ目の視点 • ハードウェアエミュレータから見たCPU • コンピュータのCPUのフリをする 
 ハードウェア • ハードウェアエミュレータを作るとCPU がどう見えるか 9
  24. 長谷川智希 @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
  25. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Z80 ハードウェア エミュレータ • Z80で動いているシステムからZ80を抜いて

    
 自作のハードウェアを挿入して動作させる 15 Z80を抜く 自作ハードウェアを 挿入して動作させる
  26. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Z80ハードウェアエミュレータ Raspberry Pi GPIO Z80

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

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

    エミュレータ 電圧変換 / ラッチ Z80 ハードウェアエミュレータのレイヤ構造 16 Z80コンピュータ (SBCZ80) ΞυϨεόε σʔλόε ੍ޚ৴߸ RAM ROM SERIAL PORT CLOCK 物理インターフェース ソフトウェアエミュレータ
  29. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Z80の物理I/F • 40本のピン • そのうち2本は電源なので38本の信号線

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

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

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

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

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

    Pi は Linux が動作する ARM CPU 搭載のコンピュータ • ソフトウェアで入出力できるGPIOを28本持つ • 制御はC, Pythonがラク 19 https://ja.wikipedia.org/wiki/Raspberry_Pi
  35. 長谷川智希 @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言語
  36. 長谷川智希 @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言語
  37. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Raspberry Pi と Z80 コンピュータの接続

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

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

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

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

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

    • Raspberry Pi が Z80 のフリをするには工夫が必要 • Raspberry Pi GPIOは3.3V, Z80は5V • 電圧変換が必要 • Raspberry Pi はGPIOを28本持つ, Z80は信号線を38本持つ • 足りない • 出力信号線はラッチを使って共有する • ラッチ: 入力値を保持する電気回路 20
  43. 長谷川智希 @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
  44. 長谷川智希 @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
  45. 長谷川智希 @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
  46. 長谷川智希 @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
  47. 長谷川智希 @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
  48. 長谷川智希 @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
  49. 長谷川智希 @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
  50. 長谷川智希 @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
  51. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU ハードウェアからソフトウェアへ • Raspberry Pi が(ハードウェア的に)Z80のフリをできる様になった

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

    • 38本の信号線をソフトウェア的にコントロールできるようになった • 38本の信号線を適切に制御(=Z80エミュレート)すれば良い • 適切とは? 22
  53. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 信号線のエミュレート • Z80の38本の信号線の仕様はZ80のマニュアルに書いてある • ザイログ社がPDFで公開している

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

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

    • さすが現役CPU • 信号線の意味、CPUの動作と信号線が変化するタイミング • メモリから命令を読み込む • メモリからデータを読み込む / 書き込む • 周辺装置からデータを読み込む / データを書き込む • 周辺装置から割り込みを受け付ける 23
  56. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 25 メモリからの読み込み 1. 読み込むアドレスを出力する 2.

    MREQ, RDを有効(0)にする 3. メモリがWAITを無効(0)に 
 するまで間待つ 4. データを取り込む ① ② ③ ④
  57. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 25 メモリからの読み込み 1. 読み込むアドレスを出力する 2.

    MREQ, RDを有効(0)にする 3. メモリがWAITを無効(0)に 
 するまで間待つ 4. データを取り込む 5. MREQ, RDを無効化(1)する ① ② ③ ④ ⑤
  58. 長谷川智希 @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; }
  59. 長谷川智希 @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になる)を待つ
  60. 長谷川智希 @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. アドレスバスに読み込むアドレスを出力する
  61. 長谷川智希 @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になる)を待つ
  62. 長谷川智希 @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にする)
  63. 長谷川智希 @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になる)のを待つ
  64. 長谷川智希 @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. データバスの信号を読み取る
  65. 長谷川智希 @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にする)
  66. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU CPU機能の実装 • ここからはただの(?)エミュレータの世界 • ソフトウェアエミュレータではメモリを配列などで表現していた

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

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

    • メモリの読み書き = 配列の読み書き • Z80 ハードウェア エミュレータ ではメモリアクセスは電気的に表現されている • メモリの読み書き = 信号線の制御 • CPU機能実装のレイヤーから見るとその差は無い • 既存のZ80エミュレータの知見を活かせる 29
  69. 長谷川智希 @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); } }
  70. 長谷川智希 @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); } }
  71. 長谷川智希 @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); } }
  72. 長谷川智希 @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); } }
  73. 長谷川智希 @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); } }
  74. 長谷川智希 @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); } }
  75. 長谷川智希 @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); } }
  76. 長谷川智希 @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); } }
  77. 長谷川智希 @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); } }
  78. 長谷川智希 @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); } }
  79. 長谷川智希 @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(); } }
  80. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 実装の検証 • よし!ひととおりできたぞ!動かしてみよう! • で動く訳がない

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

    • デバッグ • たいへんつらい • 「すべてのZ80対象プログラムが動く」のがゴール • 既存のプログラムを動かして「なんかおかしい」からのデバッグ • 非現実的 32
  82. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU テストプログラム • Z80の動作をテストするためのプログラムが存在する • prelim:

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

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

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

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

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

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

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

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

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

    • メモリアクセスはこの範囲でカバーされる • リセット, I/O, 割り込みなどはカバーされない • 実アプリケーションを動かしてテストするしかない • 良い方法知っている方教えてください! • 実アプリケーションを動かしてみる 36
  92. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 実アプリケーション1: NOPコンピュータ • Z80は0x00がNOP(No OPeration)

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

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

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

    RAM, ROMを搭載して 
 シリアルポート経由でBASICが動く • Z80の機能をフル活用している • DRAM, I/O, 割り込み, … 44
  96. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 実アプリケーション2: SBCZ80 • Z80のシングルボードコンピュータ •

    RAM, ROMを搭載して 
 シリアルポート経由でBASICが動く • Z80の機能をフル活用している • DRAM, I/O, 割り込み, … • これが動けば 
 「Z80 ハードウェア エミュレータ」 
 を名乗ってもよかろう 44
  97. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 一発で動く訳がない • zexallでカバーされていないI/Oと割り込みにきっちりバグがあった • 回路にも問題があった

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

    • 絶望的に遅い • GPIOエクステンダをやめてラッチを使う様にした 
 (ここまでの解説はすべてラッチ版) • たまにメモリ読み込みが化ける • 信号の衝突 ➡ データバスのバスバッファの方向切替前にHi-Zを経由する 47
  99. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 一発で動く訳がない • zexallでカバーされていないI/Oと割り込みにきっちりバグがあった • 回路にも問題があった

    • 絶望的に遅い • GPIOエクステンダをやめてラッチを使う様にした 
 (ここまでの解説はすべてラッチ版) • たまにメモリ読み込みが化ける • 信号の衝突 ➡ データバスのバスバッファの方向切替前にHi-Zを経由する • なんとなく動く様になった 47
  100. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 遅い • なんとなく動くが遅い • Raspberry

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

    Pi 4 Model B って 1.8GHzとかっすよ…? • 2.5MHzのエミュレーションすらできないとは…720倍速いのに… • 遅い理由が2つ 49
  102. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 遅い理由1 C++力が赤児 • zexallを動かしていても既存の実装に比べてめっちゃ遅い •

    レジスタをクラス化してるのがダメ? • C++でなくCで書いた方が良いのか…? • 既存の実装ぐらいまで高速化を… 50
  103. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 遅い理由2 GPIOの制御に時間がかかる • Z80のサイクル •

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

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

    CLK(クロック)の立ち上がりを待つ • M1を有効化 • CLKの立ち下がりを待つ • 16ビットのアドレスを出力 • MREQ, RDを有効化 • M1を有効化 • クロックの立ち上がりを待つ • クロックの立ち下がりを待つ • WAITが無効になるのを待つ • クロックの立ち上がりを待つ • 8ビットのデータを入力 • MREQ, RDを無効化 52
  108. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 遅い理由2 GPIOの制御に時間がかかる • M1サイクル(の2クロック目まで) •

    CLK(クロック)の立ち上がりを待つ • M1を有効化 • CLKの立ち下がりを待つ • 16ビットのアドレスを出力 • MREQ, RDを有効化 • M1を有効化 • クロックの立ち上がりを待つ • クロックの立ち下がりを待つ • WAITが無効になるのを待つ • クロックの立ち上がりを待つ • 8ビットのデータを入力 • MREQ, RDを無効化 52 • 愚直にやると2クロック目までで988nsかかる
  109. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 遅い理由2 GPIOの制御に時間がかかる • M1サイクル(の2クロック目まで) •

    CLK(クロック)の立ち上がりを待つ • M1を有効化 • CLKの立ち下がりを待つ • 16ビットのアドレスを出力 • MREQ, RDを有効化 • M1を有効化 • クロックの立ち上がりを待つ • クロックの立ち下がりを待つ • WAITが無効になるのを待つ • クロックの立ち上がりを待つ • 8ビットのデータを入力 • MREQ, RDを無効化 52 • 愚直にやると2クロック目までで988nsかかる • クロック的には500nsで終了が必要
  110. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 遅い理由2 GPIOの制御に時間がかかる • M1サイクル(の2クロック目まで) •

    CLK(クロック)の立ち上がりを待つ • M1を有効化 • CLKの立ち下がりを待つ • 16ビットのアドレスを出力 • MREQ, RDを有効化 • M1を有効化 • クロックの立ち上がりを待つ • クロックの立ち下がりを待つ • WAITが無効になるのを待つ • クロックの立ち上がりを待つ • 8ビットのデータを入力 • MREQ, RDを無効化 52 • 愚直にやると2クロック目までで988nsかかる • クロック的には500nsで終了が必要 • 対策
  111. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 遅い理由2 GPIOの制御に時間がかかる • M1サイクル(の2クロック目まで) •

    CLK(クロック)の立ち上がりを待つ • M1を有効化 • CLKの立ち下がりを待つ • 16ビットのアドレスを出力 • MREQ, RDを有効化 • M1を有効化 • クロックの立ち上がりを待つ • クロックの立ち下がりを待つ • WAITが無効になるのを待つ • クロックの立ち上がりを待つ • 8ビットのデータを入力 • MREQ, RDを無効化 52 • 愚直にやると2クロック目までで988nsかかる • クロック的には500nsで終了が必要 • 対策 • 近い処理はまとめる
  112. 長谷川智希 @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有効化はまとめて同じタイミングで出力する
  113. 長谷川智希 @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有効化はまとめて同じタイミングで出力する • クロックを見ない
  114. 長谷川智希 @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が「もういいよ」を表現するまで 
 データを提示し続ける
  115. 長谷川智希 @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が「もういいよ」を表現するまで 
 データを提示し続ける • 他のシステムでも通用するかはわからない
  116. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Z80 ハードウェア エミュレータ の構成 •

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

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

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

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

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

    ハードウェアI/Fエミュレータ + ソフトウェアCPUエミュレータ • ハードウェアI/Fエミュレータ部分はCPUの物理I/Fのソフトウェア実装 • 電気信号のプロトコル(API)のエミュレート • Z80マニュアルに書いてあるとおりに信号線を上げ下げする • 参考: 「PHPから見たハードウェア制御」 (PHP Conference Japan 2021) • CPUエミュレータ部分はCPU機能のソフトウェア実装 • 「エミュレート対象としてのCPU」と同じ 57
  122. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU ハードウェアエミュレータから見たCPU • 対象CPUを搭載したコンピュータ用に書かれたプログラムを 
 すべて動作させる必要がある電気回路

    + ソフトウェア • 命令実行部分は完全なエミュレートが要求される • ハードウェアI/F部分は周辺デバイスが割と忖度してくれる • 「我・CPU」みたいな態度でちょっと適当にやっても大丈夫(かも) 58
  123. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU ハードウェアエミュレータから見たCPU • 対象CPUを搭載したコンピュータ用に書かれたプログラムを 
 すべて動作させる必要がある電気回路

    + ソフトウェア • 命令実行部分は完全なエミュレートが要求される • ハードウェアI/F部分は周辺デバイスが割と忖度してくれる • 「我・CPU」みたいな態度でちょっと適当にやっても大丈夫(かも) • バスマスタ的な機能が付いたCPUだとそうはいかない 58
  124. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Future works 今後の展開 • 遅い

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

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

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

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

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

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

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

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

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

    • HB-F1XDJ(MSX2+パソコン)に刺して動かしたい • CPUアクセラレータとしての効果 • Raspberry Piのメモリをメインメモリに見せかけてさらなる高速化 • I/Oを乗っ取ってRaspberry Pi上のFDDイメージにアクセス • 小型化 • Raspberry Pi + フラットケーブル + CPUぐらいのサイズの基板 ぐらいにしてみたい • もうちょっといろいろやってみようと思います 60
  134. 長谷川智希 @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
  135. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU CLion JetBrainsのC/C++用IDE • 機能が PhpStorm

    と同じで快適 • Raspberry Pi に ssh 接続して 
 ctrl + r で実行・デバッグ • 気の利くWarningで 
 へたれC++プログラマに最高 64
  136. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU プログラムを「実行する」とは? php hoge.php php という名前のプログラムが①実行され

    
 php は hoge.php を読み込んで②実行する 67 ①実行 CPUがマシン語のプログラムを実行する ②実行 phpがPHP言語のプログラムを実行する
  137. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU プログラムを「実行する」とは? php hoge.php php という名前のプログラムが①実行され

    
 php は hoge.php を読み込んで②実行する 67 ①実行 CPUがマシン語のプログラムを実行する ②実行 phpがPHP言語のプログラムを実行する ①実行 と ②実行 は何が違う?
  138. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU マシン語の実行 • CPUはマシン語を実行する機械 (machine) •

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

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

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

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

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

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

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

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

    phpコマンドはマシン語のプログラム • 「PHPの変数をメモリ上に確保する」「PHPの関数コールを実行する」…が記述されてい る • hoge.phpをテキストファイルとして読み込んで構文解析し、実行しやすい形でメモリに 展開して、順番に書かれた処理を実行していく 72
  153. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU コンパイル 74 Javaのソースコード ➡ Javaバイトコード

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

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

    C言語のソースコード ➡ マシン語 どちらもコンパイル 違いは成果物がCPUでそのまま実行できるか否か javac hoge.java gcc hoge.c PHPもコンパイルという言葉を使う ➡ PHPのソースコードをPHP Opcodeにコンパイルする 
 (CPUでそのまま実行できない = PHPが実行する)
  156. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU アドレスバスとデータバス • アドレスバス • メモリなどのアドレスを指定する信号線の総称

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

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

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

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

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

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

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

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

    A, B, C, D, E, H, L を持っている • レジスタはCPUの内部なのでソフトウェアとして好きに実装すれば良い • Z80 ハードウェア エミュレータ では 
 Cpuクラスが Registersクラスのインスタンスを保持している • this->_cpu->registers.a = 0xff 81
  165. 長谷川智希 @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
  166. 長谷川智希 @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
  167. 長谷川智希 @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
  168. 長谷川智希 @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
  169. 長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU 命令のタイプ Z80の持つ命令はいくつかのタイプに分類できる • メモリとレジスタの間のロード •

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

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

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

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

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

    メモリとレジスタの間の演算 • 加算, 減算, シフト, 比較, ビット操作, 論理演算 … • ジャンプ, コール • ジャンプはPCレジスタに値を入れるだけ • 次の命令はPCレジスタが指すアドレスから読み込まれる • コールの場合、スタックに次のアドレスを入れてからジャンプする • リターン命令を実行するとスタックからアドレスを取り出してジャンプする = 元の場所に戻る • 特殊命令 • スタック操作, ブロック転送, I/O, … 83