$30 off During Our Annual Pro Sale. View Details »

PHPで学ぶ コンピュータアーキテクチャ

PHPで学ぶ コンピュータアーキテクチャ

PHPカンファレンス福岡2016の発表資料です。

この話は何回しても楽しいので再放送希望の方、お声がけください!

HASEGAWA Tomoki

May 21, 2016
Tweet

More Decks by HASEGAWA Tomoki

Other Decks in Technology

Transcript

  1. PHPで学ぶ
    コンピュータアーキテクチャ
    Learning: computer architecture with PHP
    長谷川智希
    HASEGAWA Tomoki

    View Slide

  2. 今日のテーマ
    Learning: computer architecture with PHP
    PHPで学ぶ
    コンピュータアーキテクチャ
    Today’s theme

    View Slide

  3. View Slide

  4. 今風のカッコいいPHPの書き方
    Modern style PHP coding.

    View Slide

  5. 今風のカッコいいPHPの書き方
    Modern style PHP coding.

    View Slide

  6. 今風のカッコいいPHPの書き方
    Modern style PHP coding.
    クールなライブラリやフレームワーク
    Cool libraries / frameworks.

    View Slide

  7. 今風のカッコいいPHPの書き方
    Modern style PHP coding.
    クールなライブラリやフレームワーク
    Cool libraries / frameworks.

    View Slide

  8. 今風のカッコいいPHPの書き方
    Modern style PHP coding.
    クールなライブラリやフレームワーク
    Cool libraries / frameworks.
    PHPをそんな風に使うのか!という驚き
    Exciting PHP usage.

    View Slide

  9. 今風のカッコいいPHPの書き方
    Modern style PHP coding.
    クールなライブラリやフレームワーク
    Cool libraries / frameworks.
    PHPをそんな風に使うのか!という驚き
    Exciting PHP usage.

    View Slide

  10. 今風のカッコいいPHPの書き方
    Modern style PHP coding.
    クールなライブラリやフレームワーク
    Cool libraries / frameworks.
    PHPをそんな風に使うのか!という驚き
    Exciting PHP usage.
    ゲームボーイの仕様の知識
    Knowledge of GAMEBOY specs.

    View Slide

  11. 今風のカッコいいPHPの書き方
    Modern style PHP coding.
    クールなライブラリやフレームワーク
    Cool libraries / frameworks.
    PHPをそんな風に使うのか!という驚き
    Exciting PHP usage.
    ゲームボーイの仕様の知識
    Knowledge of GAMEBOY specs.

    View Slide

  12. View Slide

  13. この資料は後ほど公開します
    This slide will be published later.

    View Slide

  14. ライフワーク: Web / iOSアプリ開発, ビール, IoT,

    サッカー観戦, レンタルカートレース, …
    長谷川 智希
    Web / iOS App Development, Beer, IoT,
    Watch soccer match, Rental Kart Racing, …
    デジタルサーカス株式会社 副団長CTO
    Digital Circus, Inc. Vice-master CTO
    Tokyo, Japan
    Lifework:
    @tomzoh

    View Slide

  15. View Slide

  16. View Slide

  17. WE ARE HIRING!!
    Web Development
    Mobile App Development
    ( )
    (iOS, Android)
    http://www.dgcircus.com
    Omotesando, Tokyo

    View Slide

  18. 今日のテーマ
    Learning: computer architecture with PHP
    PHPで学ぶ
    コンピュータアーキテクチャ
    Today’s theme

    View Slide

  19. 今年2月23日
    23, February

    View Slide

  20. View Slide

  21. View Slide

  22. terminal-gameboy-emulator

    View Slide

  23. #Z5SBOTGSPN+1&(WFSTJPOBOESFNPWFXIJUFCBDLHSPVOE0SJHJOBMCZ&WBO"NPT.FEJB(BNF#PZ'-KQH
    1VCMJD%PNBJO IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE
    terminal-gameboy-emulator

    View Slide

  24. #Z5SBOTGSPN+1&(WFSTJPOBOESFNPWFXIJUFCBDLHSPVOE0SJHJOBMCZ&WBO"NPT.FEJB(BNF#PZ'-KQH
    1VCMJD%PNBJO IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE
    terminal-gameboy-emulator

    View Slide

  25. terminal-gameboy-emulator

    View Slide

  26. エミュレータ
    エミュレータとは、機械装置やコンピュータのハードウェア
    (PC、ゲーム機など)の構造を、別の装置やソフトウェアで
    模倣することで実現させたもの。
    In computing, an emulator is hardware or software that enables one
    computer system to behave like another computer system.
    Emulator
    terminal-gameboy-emulator

    View Slide

  27. terminal-gameboy-emulator

    View Slide

  28. terminal-gameboy-emulator
    ??

    View Slide

  29. demo

    View Slide

  30. !?

    View Slide

  31. SUGOI

    View Slide

  32. EXCITING

    View Slide

  33. View Slide

  34. View Slide

  35. It’s

    View Slide

  36. We are er.

    View Slide

  37. WE CAN READ IT!!

    View Slide

  38. View Slide

  39. ゲームボーイのCPU
    CPU of GAMEBOY

    View Slide

  40. ゲームボーイのCPU
    CPU of GAMEBOY
    IUUQTFOXJLJQFEJBPSHXJLJ(BNF@#PZ

    View Slide

  41. ゲームボーイのCPU
    CPU of GAMEBOY
    IUUQTFOXJLJQFEJBPSHXJLJ(BNF@#PZ

    View Slide

  42. #Z%SJLOBQBMN౤ߘऀࣗ਎ʹΑΔ࡞඼ $$දࣔܧঝ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE
    #Z$$3+1(NPSJLPVEFSJWBUJWFXPSL6CDVMF͜ͷϑΝΠϧͷ೿ੜݩ$$3+1( ύϒϦοΫɾυϝΠϯ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE
    #Zʢ:LBUTV UBML
    ʣ:LBUTV UBML
    TpMF ύϒϦοΫɾυϝΠϯ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE

    View Slide

  43. #Z%SJLOBQBMN౤ߘऀࣗ਎ʹΑΔ࡞඼ $$දࣔܧঝ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE
    #Z$$3+1(NPSJLPVEFSJWBUJWFXPSL6CDVMF͜ͷϑΝΠϧͷ೿ੜݩ$$3+1( ύϒϦοΫɾυϝΠϯ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE
    #Zʢ:LBUTV UBML
    ʣ:LBUTV UBML
    TpMF ύϒϦοΫɾυϝΠϯ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE

    View Slide

  44. レジスタ
    Registers
    Instructions
    命令
    Memory access and I/O
    メモリアクセスとI/O

    View Slide

  45. 命令
    Instructions

    View Slide

  46. LR35902の命令セット
    Instruction set of LR35902
    http://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html

    View Slide

  47. LR35902 CPUのプログラム
    Program of CPU LR35902
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    0200 42 E0 43 E0 A4 E0 41 E0 01 E0 02 EA 00 D0 EA 01
    0210 D0 3E 80 E0 40 F0 44 FE 94 20 FA 3E 03 E0 40 3E
    0220 E1 E0 47 E0 48 3E E5 E0 49 21 26 FF 3E 80 32 3E
    0230 FF 32 36 77 21 06 FF 3E BF 22 3E 04 77 3E 01 EA
    0240 00 20 31 FF CF AF 21 FF DF 06 00 32 05 20 FC 21
    0250 FF CF 0E 10 06 00 32 05 20 FC 0D 20 F9 21 FF 9F
    0260 0E 20 AF 06 00 32 05 20 FC 0D 20 F9 21 FF FE 06

    View Slide

  48. プログラムの実行
    Program execution
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0

    View Slide

  49. プログラムの実行
    Program execution
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0

    View Slide

  50. プログラムの実行
    Program execution
    AF
    21 DF FF
    0E 10
    06 00
    32
    05
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0

    View Slide

  51. プログラムの実行
    Program execution
    AF
    21 DF FF
    0E 10
    06 00
    32
    05
    XOR A
    LD HL, 0xFFDF
    LD C, 0x10
    LD B, 0x00
    LD (HL-), A
    DEC B
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0

    View Slide

  52. プログラムの実行
    Program execution
    AF
    21 DF FF
    0E 10
    06 00
    32
    05
    XOR A
    LD HL, 0xFFDF
    LD C, 0x10
    LD B, 0x00
    LD (HL-), A
    DEC B
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    AをAでXOR
    HLに0xffdfを入れる
    Cに0x10を入れる
    Bに0x00を入れる
    HLが指すアドレスにAの値を入れる
    Bを-1する
    Load 0xffdf into HL
    XOR A with A
    Load 0x10 into C
    Load 0x00 into B
    Load a value A has into memory address HL points at
    Decrement B

    View Slide

  53. レジスタ
    Registers

    View Slide

  54. SHARP LR35902 のレジスタ
    SHARP LR35902 registers
    ʜ ʜ
    " '
    # $
    ) -
    ʜ ʜ
    41 4UBDL1PJOUFS

    1$ 1SPHSBN$PVOUFS

    8bit / 16bit registers
    16bit registers
    Flag register

    ; / ) $
    •Z - Zero Flag
    •N - Subtract Flag
    •H - Half Carry Flag
    •C - Carry Flag
    •0 - Not uses, always zero
    レジスタ: CPUが持つ、プログラム言語で言う変数
    Registers: Variables in programing language.

    View Slide

  55. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    PC

    View Slide

  56. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    PC

    View Slide

  57. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    PC

    View Slide

  58. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    PC

    View Slide

  59. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    PC

    View Slide

  60. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    PC

    View Slide

  61. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    AF
    21 DF FF
    0E 10
    06 00
    32
    05
    XOR A
    LD HL, 0xFFDF
    LD C, 0x10
    LD B, 0x00
    LD (HL-), A
    DEC B
    PC

    View Slide

  62. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    AF
    21 DF FF
    0E 10
    06 00
    32
    05
    XOR A
    LD HL, 0xFFDF
    LD C, 0x10
    LD B, 0x00
    LD (HL-), A
    DEC B
    PC

    View Slide

  63. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    AF
    21 DF FF
    0E 10
    06 00
    32
    05
    XOR A
    LD HL, 0xFFDF
    LD C, 0x10
    LD B, 0x00
    LD (HL-), A
    DEC B
    PC

    View Slide

  64. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    AF
    21 DF FF
    0E 10
    06 00
    32
    05
    XOR A
    LD HL, 0xFFDF
    LD C, 0x10
    LD B, 0x00
    LD (HL-), A
    DEC B
    PC

    View Slide

  65. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    AF
    21 DF FF
    0E 10
    06 00
    32
    05
    XOR A
    LD HL, 0xFFDF
    LD C, 0x10
    LD B, 0x00
    LD (HL-), A
    DEC B
    PC

    View Slide

  66. プログラムカウンタ
    Program Counter
    +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
    01E0 01 E0 85 E1 D1 C1 F1 D9 AF 21 FF DF 0E 10 06 00
    01F0 32 05 20 FC 0D 20 F9 3E 0D F3 E0 0F E0 FF AF E0
    現在実行中の命令のアドレスを指す特殊なレジスタ。
    A special register that contains the address of the instruction being executed now.
    AF
    21 DF FF
    0E 10
    06 00
    32
    05
    XOR A
    LD HL, 0xFFDF
    LD C, 0x10
    LD B, 0x00
    LD (HL-), A
    DEC B
    PC

    View Slide

  67. LR35902 の命令 - LD
    LR35902 instructions - LD
    LD BC, 0x1234
    BCレジスタに0x1234を入れる。
    Load BC register with 0x1234.
    LD (BC), A
    BCレジスタの指し示すメモリアドレスにAレジスタ
    の内容を入れる。
    Load a value A register has into memory BC register points at.

    View Slide

  68. LR35902 の命令 - JP / CD
    LR35902 instructions - JP / CD
    JP 0x5678
    0x5678番地にジャンプする。
    Jump to location 0x5678.
    CALL 0x8181
    スタックに現在のアドレスを入れて0x8181番地に
    ジャンプする。
    Push current address to stack pointer, then jump to 0x8181.
    RET
    スタック先頭のアドレスにジャンプする。
    Jump to the location of top of stack pointer.

    View Slide

  69. レジスタ
    Registers
    Instructions
    命令
    Memory access and I/O
    メモリアクセスとI/O

    View Slide

  70. メモリアクセスとI/O
    Memory access and I/O

    View Slide

  71. ゲームボーイのハードウェアコンポネント
    CPU
    I/O
    Keys Sound
    Video Display
    Com Port
    Memory
    • RAM
    • Game 

    Cartridge
    • Video RAM
    Hardware components of GAMEBOY

    View Slide

  72. GAMEBOYのメモリマップ
    Memory map of GAMEBOY
    $FFFF Interrupt Enable Flag I/O
    $FF80-$FFFE Zero Page - 127 bytes RAM
    $FF00-$FF7F Hardware I/O Registers I/O
    $FEA0-$FEFF Unusable Memory
    $FE00-$FE9F OAM - Object Attribute Memory Video RAM
    $E000-$FDFF Echo RAM - Reserved, Do Not Use
    $D000-$DFFF Internal RAM - Bank 1-7 (switchable - CGB only) RAM
    $C000-$CFFF Internal RAM - Bank 0 (fixed)
    $A000-$BFFF Cartridge RAM (If Available) Cartridge
    $9C00-$9FFF BG Map Data 2 Video RAM
    $9800-$9BFF BG Map Data 1
    $8000-$97FF Character RAM
    $4000-$7FFF Cartridge ROM - Switchable Banks 1-xx Cartridge
    $0150-$3FFF Cartridge ROM - Bank 0 (fixed)
    $0100-$014F Cartridge Header Area
    $0000-$00FF Restart and Interrupt Vectors ROM
    IUUQXXXIVDLpOHBNFTDPN QJE
    #Z5SBOTGSPN+1&(WFSTJPOBOESFNPWFXIJUFCBDLHSPVOE0SJHJOBMCZ&WBO"NPT.FEJB(BNF#PZ'-KQH
    1VCMJD%PNBJO IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE

    View Slide

  73. GAMEBOYのメモリマップ
    Memory map of GAMEBOY
    $FFFF Interrupt Enable Flag I/O
    $FF80-$FFFE Zero Page - 127 bytes RAM
    $FF00-$FF7F Hardware I/O Registers I/O
    $FEA0-$FEFF Unusable Memory
    $FE00-$FE9F OAM - Object Attribute Memory Video RAM
    $E000-$FDFF Echo RAM - Reserved, Do Not Use
    $D000-$DFFF Internal RAM - Bank 1-7 (switchable - CGB only) RAM
    $C000-$CFFF Internal RAM - Bank 0 (fixed)
    $A000-$BFFF Cartridge RAM (If Available) Cartridge
    $9C00-$9FFF BG Map Data 2 Video RAM
    $9800-$9BFF BG Map Data 1
    $8000-$97FF Character RAM
    $4000-$7FFF Cartridge ROM - Switchable Banks 1-xx Cartridge
    $0150-$3FFF Cartridge ROM - Bank 0 (fixed)
    $0100-$014F Cartridge Header Area
    $0000-$00FF Restart and Interrupt Vectors ROM
    IUUQXXXIVDLpOHBNFTDPN QJE
    #Z5SBOTGSPN+1&(WFSTJPOBOESFNPWFXIJUFCBDLHSPVOE0SJHJOBMCZ&WBO"NPT.FEJB(BNF#PZ'-KQH
    1VCMJD%PNBJO IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE

    View Slide

  74. エミュレータのCPU命令実装
    CPU instructions implementation of emulator

    View Slide

  75. CPU実装のソースファイル
    Source file of CPU implementation

    View Slide

  76. CPU実装のソースファイル
    Source file of CPU implementation

    View Slide

  77. class Opcode
    {
    public static function run(Core $core, $address)
    {
    $function = 'opcode'.$address;
    return Opcode::$function($core);
    }
    public static function opcode0(Core $core)
    {
    // Do Nothing...
    }
    public static function opcode1(Core $core)
    {
    $core->registerC = $core->memoryRead($core->programCounter);
    $core->registerB = $core->memoryRead(($core->programCounter + 1) & 0xFFFF);
    $core->programCounter = ($core->programCounter + 2) & 0xFFFF;
    }
    Opcodeの実装
    Implementation of opcodes

    View Slide

  78. class Opcode
    {
    public static function run(Core $core, $address)
    {
    $function = 'opcode'.$address;
    return Opcode::$function($core);
    }
    public static function opcode0(Core $core)
    {
    // Do Nothing...
    }
    public static function opcode1(Core $core)
    {
    $core->registerC = $core->memoryRead($core->programCounter);
    $core->registerB = $core->memoryRead(($core->programCounter + 1) & 0xFFFF);
    $core->programCounter = ($core->programCounter + 2) & 0xFFFF;
    }
    Opcodeの実装
    Implementation of opcodes
    0x00 NOP

    View Slide

  79. class Opcode
    {
    public static function run(Core $core, $address)
    {
    $function = 'opcode'.$address;
    return Opcode::$function($core);
    }
    public static function opcode0(Core $core)
    {
    // Do Nothing...
    }
    public static function opcode1(Core $core)
    {
    $core->registerC = $core->memoryRead($core->programCounter);
    $core->registerB = $core->memoryRead(($core->programCounter + 1) & 0xFFFF);
    $core->programCounter = ($core->programCounter + 2) & 0xFFFF;
    }
    Opcodeの実装
    Implementation of opcodes
    0x01 LD BC, nn

    View Slide

  80. LD BC, 0x1234
    BCレジスタに0x1234を入れる。
    Load BC register with 0x1234.

    View Slide

  81. public static function opcode1(Core $core)
    {
    $core->registerC =

    $core->memoryRead($core->programCounter);
    $core->registerB = 

    $core->memoryRead(($core->programCounter + 1) & 0xFFFF);
    $core->programCounter = 

    ($core->programCounter + 2) & 0xFFFF;
    }
    LC BC, nn の実装
    Implementation of LD BC, nn
    PC PC + 1
    0x01 0x01 0x03
    LD BC, nn 0x0301
    Data
    Address

    View Slide

  82. public static function opcode1(Core $core)
    {
    $core->registerC =

    $core->memoryRead($core->programCounter);
    $core->registerB = 

    $core->memoryRead(($core->programCounter + 1) & 0xFFFF);
    $core->programCounter = 

    ($core->programCounter + 2) & 0xFFFF;
    }
    LC BC, nn の実装
    Implementation of LD BC, nn
    PC PC + 1
    0x01 0x01 0x03
    LD BC, nn 0x0301
    Data
    Address
    BCレジスタに指定したアドレスのメモリの値を入れる。
    Load BC register with nn.

    View Slide

  83. public static function opcode1(Core $core)
    {
    $core->registerC =

    $core->memoryRead($core->programCounter);
    $core->registerB = 

    $core->memoryRead(($core->programCounter + 1) & 0xFFFF);
    $core->programCounter = 

    ($core->programCounter + 2) & 0xFFFF;
    }
    LC BC, nn の実装
    Implementation of LD BC, nn
    PC PC + 1
    0x01 0x01 0x03
    LD BC, nn 0x0301
    Data
    Address
    PCを次の命令まで進める。
    Move PC register to next instruction.

    View Slide

  84. public static function opcode1(Core $core)
    {
    $core->registerC =

    $core->memoryRead($core->programCounter);
    $core->registerB = 

    $core->memoryRead(($core->programCounter + 1) & 0xFFFF);
    $core->programCounter = 

    ($core->programCounter + 2) & 0xFFFF;
    }
    LC BC, nn の実装
    Implementation of LD BC, nn
    PC PC + 1
    0x01 0x01 0x03
    LD BC, nn 0x0301
    Data
    Address

    View Slide

  85. QUIZ

    View Slide

  86. $core->memoryRead($core->programCounter);
    //
    //Main RAM, MBC RAM, GBC Main RAM, VRAM, etc.
    //
    //Main Core Memory
    public $memory = [];
    Core.php

    View Slide

  87. $core->memoryRead($core->programCounter);
    //
    //Main RAM, MBC RAM, GBC Main RAM, VRAM, etc.
    //
    //Main Core Memory
    public $memory = [];
    Core.php
    メインメモリは配列になっている。
    Main memory is defined as array.


    View Slide

  88. $core->memoryRead($core->programCounter);
    //
    //Main RAM, MBC RAM, GBC Main RAM, VRAM, etc.
    //
    //Main Core Memory
    public $memory = [];
    Core.php
    メインメモリは配列になっている。
    Main memory is defined as array.

    なぜ $core->memory[$core->programCounter] ではない?
    Q
    Why not $core->memory[$core->programCounter] ?

    View Slide

  89. GAMEBOYのメモリマップ
    Memory map of GAMEBOY
    $FFFF Interrupt Enable Flag I/O
    $FF80-$FFFE Zero Page - 127 bytes RAM
    $FF00-$FF7F Hardware I/O Registers I/O
    $FEA0-$FEFF Unusable Memory
    $FE00-$FE9F OAM - Object Attribute Memory Video RAM
    $E000-$FDFF Echo RAM - Reserved, Do Not Use
    $D000-$DFFF Internal RAM - Bank 1-7 (switchable - CGB only) RAM
    $C000-$CFFF Internal RAM - Bank 0 (fixed)
    $A000-$BFFF Cartridge RAM (If Available) Cartridge
    $9C00-$9FFF BG Map Data 2 Video RAM
    $9800-$9BFF BG Map Data 1
    $8000-$97FF Character RAM
    $4000-$7FFF Cartridge ROM - Switchable Banks 1-xx Cartridge
    $0150-$3FFF Cartridge ROM - Bank 0 (fixed)
    $0100-$014F Cartridge Header Area
    $0000-$00FF Restart and Interrupt Vectors ROM
    IUUQXXXIVDLpOHBNFTDPN QJE
    #Z5SBOTGSPN+1&(WFSTJPOBOESFNPWFXIJUFCBDLHSPVOE0SJHJOBMCZ&WBO"NPT.FEJB(BNF#PZ'-KQH
    1VCMJD%PNBJO IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE

    View Slide

  90. GAMEBOYのメモリマップ
    Memory map of GAMEBOY
    $FFFF Interrupt Enable Flag I/O
    $FF80-$FFFE Zero Page - 127 bytes RAM
    $FF00-$FF7F Hardware I/O Registers I/O
    $FEA0-$FEFF Unusable Memory
    $FE00-$FE9F OAM - Object Attribute Memory Video RAM
    $E000-$FDFF Echo RAM - Reserved, Do Not Use
    $D000-$DFFF Internal RAM - Bank 1-7 (switchable - CGB only) RAM
    $C000-$CFFF Internal RAM - Bank 0 (fixed)
    $A000-$BFFF Cartridge RAM (If Available) Cartridge
    $9C00-$9FFF BG Map Data 2 Video RAM
    $9800-$9BFF BG Map Data 1
    $8000-$97FF Character RAM
    $4000-$7FFF Cartridge ROM - Switchable Banks 1-xx Cartridge
    $0150-$3FFF Cartridge ROM - Bank 0 (fixed)
    $0100-$014F Cartridge Header Area
    $0000-$00FF Restart and Interrupt Vectors ROM
    IUUQXXXIVDLpOHBNFTDPN QJE
    #Z5SBOTGSPN+1&(WFSTJPOBOESFNPWFXIJUFCBDLHSPVOE0SJHJOBMCZ&WBO"NPT.FEJB(BNF#PZ'-KQH
    1VCMJD%PNBJO IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE
    A. メモリアクセスはそのアドレスに
    よって動作が違うから。
    A. Because a result of memory access
    depends on its location. 


    View Slide

  91. エミュレータのI/O実装
    I/O implementations of emulator

    View Slide

  92. ゲームボーイのハードウェアコンポネント
    CPU
    I/O
    Keys Sound
    Video Display
    Com Port
    Memory
    • RAM
    • Game 

    Cartridge
    • Video RAM
    Hardware components of GAMEBOY

    View Slide

  93. ゲームボーイのハードウェアコンポネント
    CPU
    I/O
    Keys Sound
    Video Display
    Com Port
    Memory
    • RAM
    • Game 

    Cartridge
    • Video RAM
    Hardware components of GAMEBOY
    CPUはキーにI/O経由でアクセスする
    CPU accesses keys through the I/O

    View Slide

  94. 実行のメインループ
    $keyboard = new Keyboard($core);
    while (true) {
    $core->run();
    $keyboard->check();
    }
    boot.php
    Main loop of excution

    View Slide

  95. 実行のメインループ
    $keyboard = new Keyboard($core);
    while (true) {
    $core->run();
    $keyboard->check();
    }
    boot.php
    メインループ
    Main loop.

    Main loop of excution

    View Slide

  96. キー状態の取得
    public function __construct(Core $core)
    {
    $this->core = $core;
    exec('stty -icanon -echo');
    $this->file = fopen('php://stdin', 'r');
    stream_set_blocking($this->file, false);
    }
    public function check()
    {
    $key = fread($this->file, 1);
    if (!empty($key)) {
    $this->keyDown($key);
    } elseif (!empty($this->keyPressing)) {
    $this->keyUp($this->keyPressing);
    }
    $this->keyPressing = $key;
    }
    Get key status

    View Slide

  97. キー状態の取得
    public function __construct(Core $core)
    {
    $this->core = $core;
    exec('stty -icanon -echo');
    $this->file = fopen('php://stdin', 'r');
    stream_set_blocking($this->file, false);
    }
    public function check()
    {
    $key = fread($this->file, 1);
    if (!empty($key)) {
    $this->keyDown($key);
    } elseif (!empty($this->keyPressing)) {
    $this->keyUp($this->keyPressing);
    }
    $this->keyPressing = $key;
    }
    Get key status
    標準入力を開いて…
    Open standard in and...


    View Slide

  98. キー状態の取得
    public function __construct(Core $core)
    {
    $this->core = $core;
    exec('stty -icanon -echo');
    $this->file = fopen('php://stdin', 'r');
    stream_set_blocking($this->file, false);
    }
    public function check()
    {
    $key = fread($this->file, 1);
    if (!empty($key)) {
    $this->keyDown($key);
    } elseif (!empty($this->keyPressing)) {
    $this->keyUp($this->keyPressing);
    }
    $this->keyPressing = $key;
    }
    Get key status
    標準入力を開いて…
    Open standard in and...

    fread()で1文字取る!
    Get a character with fread!

    View Slide

  99. I/O 読み込み
    public function memoryRead($address)
    {
    if ($address < 0x4000) {
    } elseif ($address >= 0xFF00) {
    switch ($address) {
    case 0xFF00:
    return 0xC0 | $this->memory[0xFF00];
    break;
    I/O read

    View Slide

  100. I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00

    View Slide

  101. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00

    View Slide

  102. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00

    View Slide

  103. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00

    View Slide

  104. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00

    View Slide

  105. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00

    View Slide

  106. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00
    7 6 5 4 3 2 1 0
    A B Select Start → ← ↑ ↓
    $this->JoyPad:

    View Slide

  107. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00
    7 6 5 4 3 2 1 0
    A B Select Start → ← ↑ ↓
    $this->JoyPad:

    View Slide

  108. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00
    7 6 5 4 3 2 1 0
    A B Select Start → ← ↑ ↓
    $this->JoyPad:

    View Slide

  109. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00
    7 6 5 4 3 2 1 0
    A B Select Start → ← ↑ ↓
    $this->JoyPad:

    View Slide

  110. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00
    7 6 5 4 3 2 1 0
    A B Select Start → ← ↑ ↓
    $this->JoyPad:

    View Slide

  111. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00
    7 6 5 4 3 2 1 0
    A B Select Start → ← ↑ ↓
    $this->JoyPad:

    View Slide

  112. public function memoryWrite($address, $data)
    {
    if ($address < 0x8000) {
    //I/O Registers (GB + GBC):
    } elseif ($address == 0xFF00) {
    $this->memory[0xFF00] = ($data & 0x30) |
    (((($data & 0x20) == 0) ? ($this->JoyPad >> 4) : 0xF) &
    ((($data & 0x10) == 0) ? ($this->JoyPad & 0xF) : 0xF));
    } elseif ($address == 0xFF02) {
    I/O 書き込み
    I/O write
    7 6 5 4 3 2 1 0
    - - P15 out P14 out P13 in P12 in P11 in P10 in
    - - 0 1 A B Select Start
    - - 1 0 → ← ↑ ↓
    I/O port 0xFF00
    7 6 5 4 3 2 1 0
    A B Select Start → ← ↑ ↓
    $this->JoyPad:

    View Slide

  113. 結論
    Conclusion

    View Slide

  114. エミュレータのソースを読むのは楽しい

    View Slide

  115. Webアプリとも

    フレームワークとも
    フロントエンドの非同期アプリとも

    違う感じのコード群

    View Slide

  116. ハードウェアの動作を
    ソフトウェアで表現

    View Slide

  117. とても面白い

    View Slide

  118. 皆さんも是非読んでみてください

    View Slide

  119. Thanks
    WE ARE HIRING
    Drupal / Mobile App Engineer

    Digital Circus, Inc. Tokyo, Japan
    @tomzoh

    View Slide

  120. Appendix

    View Slide

  121. セットアップ
    How to run
    $ git clone https://github.com/gabrielrcouto/php-
    terminal-gameboy-emulator.git
    $ cd php-terminal-gameboy-emulator
    $ composer install -o
    $ bin/php-gameboy drmario.rom

    View Slide

  122. ROMいずこ
    How to get ROM file

    View Slide

  123. ROMいずこ
    How to get ROM file

    View Slide

  124. ROMいずこ
    How to get ROM file
    _人人人人人人人_
    > drmario.gb <
     ̄Y^Y^Y^Y^Y^Y ̄

    View Slide

  125. ROMいずこ
    How to get ROM file

    View Slide

  126. ROMいずこ
    How to get ROM file

    View Slide

  127. ROMいずこ
    How to get ROM file
    $rom = base64_decode(file_get_contents($argv[1]));
    $rom = file_get_contents($filename);

    View Slide

  128. ボトルネックはどこか
    PHP5.5.30 OSX Native
    FPS: 4
    PHP7.0.1 VirtualBox
    FPS: 14
    We need more FPS

    View Slide

  129. エミュレータのビデオ実装
    Video implementations of emulator

    View Slide

  130. タイルでの色表現
    ゲームボーイは4色出せるが1色&パターンで表現している。
    GAMEBOY has 4 color display. PHP version uses only 1 color.
    Color using tile pattern

    View Slide

  131. Pentiumのアドレスバスとデータバス
    IUUQEPXOMPBEJOUFMDPNEFTJHOQFOUJVNEBUBTIUTQEG
    $$දࣔܧঝ IUUQTDPNNPOTXJLJNFEJBPSHXJOEFYQIQ DVSJE
    D0〜D63
    A3〜A31
    Data bus and address bus of Pentium

    View Slide

  132. ノイマン型コンピュータ
    http://e-words.jp/w/ノイマン型コンピュータ.html
    von Neumann architecture
    プログラムをデータとして記憶装置に格納し、

    これを順番に読み込んで実行するコンピュータ。
    "DPNQVUFSXIJDIIBTBNFNPSZBOE$165IJT$16DBOJOUFSQSFUUIF
    DPOUFOUTPGNFNPSZFJUIFSBTJOTUSVDUJPOTPSBTEBUBBDDPSEJOHUPUIF
    GFUDIFYFDVUFDZDMF
    http://www.dictionary.com/browse/von-neumann-architecture

    View Slide

  133. エンディアン
    Endian
    UTF-16のBOM = Byte Order Mark
    = ビッグエンディアンかリトルエンディアンか

    View Slide

  134. ストリームの非ブロックモード
    public function __construct(Core $core)
    {
    $this->core = $core;
    exec('stty -icanon -echo');
    $this->file = fopen('php://stdin', 'r');
    stream_set_blocking($this->file, false);
    }
    public function check()
    {
    $key = fread($this->file, 1);
    if (!empty($key)) {
    $this->keyDown($key);
    } elseif (!empty($this->keyPressing)) {
    $this->keyUp($this->keyPressing);
    }
    $this->keyPressing = $key;
    }
    Non-blocking mode on a stream

    View Slide

  135. ストリームの非ブロックモード
    public function __construct(Core $core)
    {
    $this->core = $core;
    exec('stty -icanon -echo');
    $this->file = fopen('php://stdin', 'r');
    stream_set_blocking($this->file, false);
    }
    public function check()
    {
    $key = fread($this->file, 1);
    if (!empty($key)) {
    $this->keyDown($key);
    } elseif (!empty($this->keyPressing)) {
    $this->keyUp($this->keyPressing);
    }
    $this->keyPressing = $key;
    }
    Non-blocking mode on a stream

    View Slide

  136. ストリームの非ブロックモード
    public function __construct(Core $core)
    {
    $this->core = $core;
    exec('stty -icanon -echo');
    $this->file = fopen('php://stdin', 'r');
    stream_set_blocking($this->file, false);
    }
    public function check()
    {
    $key = fread($this->file, 1);
    if (!empty($key)) {
    $this->keyDown($key);
    } elseif (!empty($this->keyPressing)) {
    $this->keyUp($this->keyPressing);
    }
    $this->keyPressing = $key;
    }
    Non-blocking mode on a stream
    ストリームのモードを非ブロックに設定
    Set non-blocking mode on a stream.


    View Slide

  137. リンク
    • http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf
    • https://en.wikipedia.org/wiki/Game_Boy
    • http://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html
    • http://gbdev.gg8.se/wiki/articles/The_Cartridge_Header
    • http://gameboy.mongenel.com/dmg/asmmemmap.html
    • http://www.z80.info/z80inst.txt
    Resources

    View Slide