Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Z80 ハードウェア エミュレータ • Z80で動いているシステムからZ80を抜いて 
 自作のハードウェアを挿入して動作させる 15

Slide 44

Slide 44 text

長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Z80 ハードウェア エミュレータ • Z80で動いているシステムからZ80を抜いて 
 自作のハードウェアを挿入して動作させる 15

Slide 45

Slide 45 text

長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Z80 ハードウェア エミュレータ • Z80で動いているシステムからZ80を抜いて 
 自作のハードウェアを挿入して動作させる 15 Z80を抜く

Slide 46

Slide 46 text

長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Z80 ハードウェア エミュレータ • Z80で動いているシステムからZ80を抜いて 
 自作のハードウェアを挿入して動作させる 15 Z80を抜く

Slide 47

Slide 47 text

長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU Z80 ハードウェア エミュレータ • Z80で動いているシステムからZ80を抜いて 
 自作のハードウェアを挿入して動作させる 15 Z80を抜く 自作ハードウェアを 挿入して動作させる

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

長谷川智希 @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言語

Slide 67

Slide 67 text

長谷川智希 @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言語

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

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

Slide 109

Slide 109 text

長谷川智希 @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; }

Slide 110

Slide 110 text

長谷川智希 @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になる)を待つ

Slide 111

Slide 111 text

長谷川智希 @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. アドレスバスに読み込むアドレスを出力する

Slide 112

Slide 112 text

長谷川智希 @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になる)を待つ

Slide 113

Slide 113 text

長谷川智希 @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にする)

Slide 114

Slide 114 text

長谷川智希 @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になる)のを待つ

Slide 115

Slide 115 text

長谷川智希 @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. データバスの信号を読み取る

Slide 116

Slide 116 text

長谷川智希 @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にする)

Slide 117

Slide 117 text

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

Slide 118

Slide 118 text

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

Slide 119

Slide 119 text

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

Slide 120

Slide 120 text

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

Slide 121

Slide 121 text

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

Slide 122

Slide 122 text

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

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

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

Slide 125

Slide 125 text

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

Slide 126

Slide 126 text

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

Slide 127

Slide 127 text

長谷川智希 @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); } }

Slide 128

Slide 128 text

長谷川智希 @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); } }

Slide 129

Slide 129 text

長谷川智希 @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); } }

Slide 130

Slide 130 text

長谷川智希 @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); } }

Slide 131

Slide 131 text

長谷川智希 @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); } }

Slide 132

Slide 132 text

長谷川智希 @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); } }

Slide 133

Slide 133 text

長谷川智希 @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); } }

Slide 134

Slide 134 text

長谷川智希 @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); } }

Slide 135

Slide 135 text

長谷川智希 @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); } }

Slide 136

Slide 136 text

長谷川智希 @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); } }

Slide 137

Slide 137 text

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

Slide 138

Slide 138 text

長谷川智希 @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(); } }

Slide 139

Slide 139 text

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

Slide 140

Slide 140 text

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

Slide 141

Slide 141 text

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

Slide 142

Slide 142 text

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

Slide 143

Slide 143 text

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

Slide 144

Slide 144 text

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

Slide 145

Slide 145 text

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

Slide 146

Slide 146 text

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

Slide 147

Slide 147 text

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

Slide 148

Slide 148 text

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

Slide 149

Slide 149 text

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

Slide 150

Slide 150 text

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

Slide 151

Slide 151 text

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

Slide 152

Slide 152 text

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

Slide 153

Slide 153 text

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

Slide 154

Slide 154 text

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

Slide 155

Slide 155 text

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

Slide 156

Slide 156 text

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

Slide 157

Slide 157 text

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

Slide 158

Slide 158 text

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

Slide 159

Slide 159 text

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

Slide 160

Slide 160 text

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

Slide 161

Slide 161 text

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

Slide 162

Slide 162 text

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

Slide 163

Slide 163 text

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

Slide 164

Slide 164 text

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

Slide 165

Slide 165 text

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

Slide 166

Slide 166 text

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

Slide 167

Slide 167 text

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

Slide 168

Slide 168 text

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

Slide 169

Slide 169 text

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

Slide 170

Slide 170 text

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

Slide 171

Slide 171 text

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

Slide 172

Slide 172 text

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

Slide 173

Slide 173 text

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

Slide 174

Slide 174 text

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

Slide 175

Slide 175 text

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

Slide 176

Slide 176 text

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

Slide 177

Slide 177 text

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

Slide 178

Slide 178 text

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

Slide 179

Slide 179 text

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

Slide 180

Slide 180 text

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

Slide 181

Slide 181 text

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

Slide 182

Slide 182 text

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

Slide 183

Slide 183 text

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

Slide 184

Slide 184 text

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

Slide 185

Slide 185 text

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

Slide 186

Slide 186 text

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

Slide 187

Slide 187 text

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

Slide 188

Slide 188 text

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

Slide 189

Slide 189 text

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

Slide 190

Slide 190 text

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

Slide 191

Slide 191 text

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

Slide 192

Slide 192 text

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

Slide 193

Slide 193 text

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

Slide 194

Slide 194 text

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

Slide 195

Slide 195 text

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

Slide 196

Slide 196 text

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

Slide 197

Slide 197 text

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

Slide 198

Slide 198 text

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

Slide 199

Slide 199 text

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

Slide 200

Slide 200 text

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

Slide 201

Slide 201 text

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

Slide 202

Slide 202 text

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

Slide 203

Slide 203 text

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

Slide 204

Slide 204 text

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

Slide 205

Slide 205 text

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

Slide 206

Slide 206 text

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

Slide 207

Slide 207 text

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

Slide 208

Slide 208 text

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

Slide 209

Slide 209 text

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

Slide 210

Slide 210 text

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

Slide 211

Slide 211 text

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

Slide 212

Slide 212 text

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

Slide 213

Slide 213 text

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

Slide 214

Slide 214 text

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

Slide 215

Slide 215 text

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

Slide 216

Slide 216 text

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

Slide 217

Slide 217 text

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

Slide 218

Slide 218 text

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

Slide 219

Slide 219 text

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

Slide 220

Slide 220 text

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

Slide 221

Slide 221 text

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

Slide 222

Slide 222 text

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

Slide 223

Slide 223 text

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

Slide 224

Slide 224 text

長谷川智希 @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有効化はまとめて同じタイミングで出力する

Slide 225

Slide 225 text

長谷川智希 @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有効化はまとめて同じタイミングで出力する • クロックを見ない

Slide 226

Slide 226 text

長谷川智希 @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が「もういいよ」を表現するまで 
 データを提示し続ける

Slide 227

Slide 227 text

長谷川智希 @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が「もういいよ」を表現するまで 
 データを提示し続ける • 他のシステムでも通用するかはわからない

Slide 228

Slide 228 text

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

Slide 229

Slide 229 text

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

Slide 230

Slide 230 text

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

Slide 231

Slide 231 text

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

Slide 232

Slide 232 text

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

Slide 233

Slide 233 text

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

Slide 234

Slide 234 text

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

Slide 235

Slide 235 text

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

Slide 236

Slide 236 text

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

Slide 237

Slide 237 text

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

Slide 238

Slide 238 text

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

Slide 239

Slide 239 text

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

Slide 240

Slide 240 text

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

Slide 241

Slide 241 text

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

Slide 242

Slide 242 text

長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU ハードウェアエミュレータから見たCPU • 対象CPUを搭載したコンピュータ用に書かれたプログラムを 
 すべて動作させる必要がある電気回路 + ソフトウェア 58

Slide 243

Slide 243 text

長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU ハードウェアエミュレータから見たCPU • 対象CPUを搭載したコンピュータ用に書かれたプログラムを 
 すべて動作させる必要がある電気回路 + ソフトウェア • 命令実行部分は完全なエミュレートが要求される 58

Slide 244

Slide 244 text

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

Slide 245

Slide 245 text

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

Slide 246

Slide 246 text

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

Slide 247

Slide 247 text

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

Slide 248

Slide 248 text

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

Slide 249

Slide 249 text

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

Slide 250

Slide 250 text

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

Slide 251

Slide 251 text

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

Slide 252

Slide 252 text

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

Slide 253

Slide 253 text

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

Slide 254

Slide 254 text

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

Slide 255

Slide 255 text

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

Slide 256

Slide 256 text

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

Slide 257

Slide 257 text

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

Slide 258

Slide 258 text

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

Slide 259

Slide 259 text

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

Slide 260

Slide 260 text

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

Slide 261

Slide 261 text

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

Slide 262

Slide 262 text

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

Slide 263

Slide 263 text

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

Slide 264

Slide 264 text

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

Slide 265

Slide 265 text

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

Slide 266

Slide 266 text

長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU CLion JetBrainsのC/C++用IDE • 機能が PhpStorm と同じで快適 • Raspberry Pi に ssh 接続して 
 ctrl + r で実行・デバッグ • 気の利くWarningで 
 へたれC++プログラマに最高 64

Slide 267

Slide 267 text

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

Slide 268

Slide 268 text

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

Slide 269

Slide 269 text

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

Slide 270

Slide 270 text

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

Slide 271

Slide 271 text

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

Slide 272

Slide 272 text

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

Slide 273

Slide 273 text

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

Slide 274

Slide 274 text

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

Slide 275

Slide 275 text

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

Slide 276

Slide 276 text

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

Slide 277

Slide 277 text

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

Slide 278

Slide 278 text

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

Slide 279

Slide 279 text

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

Slide 280

Slide 280 text

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

Slide 281

Slide 281 text

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

Slide 282

Slide 282 text

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

Slide 283

Slide 283 text

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

Slide 284

Slide 284 text

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

Slide 285

Slide 285 text

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

Slide 286

Slide 286 text

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

Slide 287

Slide 287 text

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

Slide 288

Slide 288 text

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

Slide 289

Slide 289 text

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

Slide 290

Slide 290 text

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

Slide 291

Slide 291 text

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

Slide 292

Slide 292 text

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

Slide 293

Slide 293 text

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

Slide 294

Slide 294 text

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

Slide 295

Slide 295 text

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

Slide 296

Slide 296 text

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

Slide 297

Slide 297 text

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

Slide 298

Slide 298 text

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

Slide 299

Slide 299 text

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

Slide 300

Slide 300 text

長谷川智希 @tomzoh 続CPUとは何か - ハードウェアエミュレータから見たCPU うそだ! 
 PHPはコンパイルするんだろ? 73

Slide 301

Slide 301 text

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

Slide 302

Slide 302 text

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

Slide 303

Slide 303 text

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

Slide 304

Slide 304 text

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

Slide 305

Slide 305 text

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

Slide 306

Slide 306 text

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

Slide 307

Slide 307 text

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

Slide 308

Slide 308 text

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

Slide 309

Slide 309 text

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

Slide 310

Slide 310 text

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

Slide 311

Slide 311 text

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

Slide 312

Slide 312 text

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

Slide 313

Slide 313 text

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

Slide 314

Slide 314 text

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

Slide 315

Slide 315 text

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

Slide 316

Slide 316 text

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

Slide 317

Slide 317 text

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

Slide 318

Slide 318 text

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

Slide 319

Slide 319 text

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

Slide 320

Slide 320 text

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

Slide 321

Slide 321 text

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

Slide 322

Slide 322 text

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

Slide 323

Slide 323 text

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

Slide 324

Slide 324 text

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

Slide 325

Slide 325 text

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

Slide 326

Slide 326 text

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

Slide 327

Slide 327 text

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

Slide 328

Slide 328 text

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

Slide 329

Slide 329 text

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

Slide 330

Slide 330 text

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

Slide 331

Slide 331 text

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

Slide 332

Slide 332 text

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

Slide 333

Slide 333 text

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

Slide 334

Slide 334 text

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

Slide 335

Slide 335 text

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

Slide 336

Slide 336 text

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

Slide 337

Slide 337 text

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

Slide 338

Slide 338 text

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

Slide 339

Slide 339 text

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

Slide 340

Slide 340 text

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

Slide 341

Slide 341 text

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

Slide 342

Slide 342 text

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

Slide 343

Slide 343 text

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

Slide 344

Slide 344 text

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

Slide 345

Slide 345 text

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

Slide 346

Slide 346 text

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

Slide 347

Slide 347 text

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

Slide 348

Slide 348 text

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

Slide 349

Slide 349 text

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