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

Writing NES games! with assembly!!

Writing NES games! with assembly!!

Talk given at !!Con 2017.

I’d like to take you on a stroll down memory lane and dig into the internals of the Nintendo Entertainment System (NES) to figure out how it works. While we’re there, we’ll see how to build a game for the NES using 6502 assembly with the help of a few modern tools. We’ll gain a new respect for ’80s developers and an appreciation for the high-level languages we have today!

Christian Joudrey

May 06, 2017
Tweet

More Decks by Christian Joudrey

Other Decks in Programming

Transcript

  1. View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. PRG ROM
    CHR ROM

    View Slide

  8. chr rom

    View Slide

  9. View Slide

  10. View Slide

  11. View Slide

  12. View Slide

  13. PRG ROM
    CHR ROM
    battery
    RAM

    View Slide

  14. Milestone 1

    View Slide

  15. NO WAY! OMG
    omg!! it works!!!
    is it normal that we are this excited about displaying a ball?

    View Slide

  16. NO WAY! OMG
    omg!! it works!!!
    is it normal that we are this excited about displaying a ball?

    View Slide

  17. NO WAY! OMG
    omg!! it works!!!
    is it normal that we are this excited about displaying a ball?

    View Slide

  18. NO WAY! OMG
    omg!! it works!!!
    is it normal that we are this excited about displaying a ball?

    View Slide

  19. NO WAY! OMG
    omg!! it works!!!
    is it normal that we are this excited about displaying a ball?

    View Slide

  20. View Slide

  21. 00008000: 20 8e 10 40 2c 02 20 2c 02 20 10 fb 8a 95 00 9d
    00008010: 00 01 9d 00 03 9d 00 04 9d 00 05 9d 00 06 9d 00
    00008020: 07 e8 d0 e9 a9 ff 9d 00 02 e8 d0 fa 2c 02 20 10
    00008030: fb 4c b6 80 a9 01 85 02 a9 01 85 03 a9 70 8d 03
    00008040: 02 a9 70 8d 00 02 a9 00 8d 02 02 a9 01 8d 01 02
    00008050: 60 e6 00 e6 01 a5 00 8d 03 02 a5 01 8d 00 02 60
    00008060: a9 01 8d 16 40 85 05 4a 8d 16 40 ad 16 40 29 03
    00008070: c9 01 26 04 ad 17 40 29 03 c9 01 26 05 90 ec 60
    00008080: a5 05 85 07 a5 04 85 06 20 70 80 a5 05 85 09 a5
    00008090: 04 85 08 20 70 80 a2 01 b5 04 d5 08 f0 04 b5 06
    000080a0: 95 04 ca 10 f3 60 a9 3f 8d 06 20 a9 00 8d 06 20
    000080b0: a9 0f 8d 07 20 a9 3f 8d 06 20 a9 11 8d 06 20 a9
    000080c0: 30 8d 07 20 a9 0f 8d 07 20 8d 07 20 20 44 80 a9
    000080d0: 18 8d 01 20 a9 80 8d 00 20 a9 01 85 0e 20 90 80
    000080e0: a5 04 f0 03 20 00 81 20 61 80 20 25 81 4c e9 80
    000080f0: a5 04 29 0c f0 0c a5 04 29 08 f0 03 e6 03 60 c6
    00008100: 03 60 a5 04 29 03 f0 0b a5 04 29 02 f0 03 c6 02
    00008110: 60 e6 02 60 60 e6 11 a5 11 d0 fc 60 48 8a 48 98
    00008120: 48 a5 0e f0 0a a9 00 8d 03 20 a9 02 8d 14 40 a5
    00008130: 0f f0 08 2c 02 20 20 24 81 c6 0f a5 10 f0 17 a5
    00008140: 0b 8d 01 20 a5 0a 8d 00 20 2c 02 20 a5 0c 8d 05
    00008150: 20 a5 0d 8d 05 20 a9 00 85 11 68 a8 68 aa 68 40

    View Slide

  22. cc65 toolchain
    asm
    asm
    asm ca65 ld65
    asm
    asm
    obj ines

    View Slide

  23. 69
    70 main:
    71 ; Set universal background color ($3F00) to black ($0F)
    72 ; Set PPU address to $3F00
    73 lda #$3F
    74 sta PPUADDR
    75 lda #$00
    76 sta PPUADDR
    77 ; Write $0F to that PPU address
    78 lda #$0F
    79 sta PPUDATA
    80
    81 ; Set sprite palette 0 ($3F11-$3F13) to white ($30), black ($0F), black ($0F)
    82 ; Set PPU address to $3F11
    83 lda #$3F
    84 sta PPUADDR
    85 lda #$11
    86 sta PPUADDR
    87 ; Write $30, $0F, $0F to PPU
    88 lda #$30
    89 sta PPUDATA ; PPUADDR will increase by 1 each time we write to it
    90 lda #$0F
    91 sta PPUDATA
    92 sta PPUDATA
    93
    94 jsr ballSetup
    95
    96 ; Enable sprite and background rendering
    97 lda #%00011000
    98 sta PPUMASK
    99
    100 ; Enable NMI
    101 lda #%10000000
    102 sta PPUCTRL
    103

    View Slide

  24. 6502 assembly
    LDA STA
    memory
    ADC SBC
    INC DEC
    arithmetics
    AND ORA
    CMP
    compare
    BCC BCS BEQ
    BMI BNE BPL
    branch

    View Slide

  25. 6502 assembly
    LDA STA
    memory
    ADC SBC
    INC DEC
    arithmetics
    AND ORA
    CMP
    compare
    BCC BCS BEQ
    BMI BNE BPL
    branch

    View Slide

  26. 6502 assembly
    LDA STA
    memory
    ADC SBC
    INC DEC
    arithmetics
    AND ORA
    CMP
    compare
    BCC BCS BEQ
    BMI BNE BPL
    branch

    View Slide

  27. 6502 assembly
    LDA STA
    memory
    ADC SBC
    INC DEC
    arithmetics
    AND ORA
    CMP
    compare
    BCC BCS BEQ
    BMI BNE BPL
    branch

    View Slide

  28. 6502 assembly
    LDA STA
    memory
    ADC SBC
    INC DEC
    arithmetics
    AND ORA
    CMP
    compare
    BCC BCS BEQ
    BMI BNE BPL
    branch

    View Slide

  29. $0600: LDA $05
    $0602: CMP #$08
    $0604: BEQ $060b
    $0606: INC $05
    $0608: JMP $0600
    $060b: RTS
    PC

    View Slide

  30. Milestone 2
    !

    View Slide

  31. Milestone 2
    !

    View Slide

  32. picture processing unit

    View Slide

  33. 256px
    240px

    View Slide

  34. View Slide

  35. 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
    10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
    20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
    30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
    nes palette

    View Slide

  36. View Slide

  37. View Slide

  38. View Slide

  39. y tile attrs x
    23 01 00 01
    64 x

    View Slide

  40. PPU registers
    $2000-$2007

    View Slide

  41. !
    Milestone 3
    "
    "
    "

    View Slide

  42. OMG! Wait... Is that real?
    yeah!!!
    NO WAY!!
    yeah!!!

    View Slide

  43. OMG! Wait... Is that real?
    yeah!!!
    NO WAY!!
    yeah!!!

    View Slide

  44. OMG! Wait... Is that real?
    yeah!!!
    NO WAY!!
    yeah!!!

    View Slide

  45. OMG! Wait... Is that real?
    yeah!!!
    NO WAY!!
    yeah!!!

    View Slide

  46. OMG! Wait... Is that real?
    yeah!!!
    NO WAY!!
    yeah!!!

    View Slide

  47. OMG! Wait... Is that real?
    yeah!!!
    NO WAY!!
    yeah!!!

    View Slide

  48. video frame
    vertical blank

    View Slide

  49. video frame
    vertical blank

    View Slide

  50. nmi interrupt

    View Slide

  51. loop:
    INC $05
    JMP loop
    nmi:
    ; Do stuff
    RTI
    PC

    View Slide

  52. loop:
    INC $05
    JMP loop
    nmi:
    ; Do stuff
    RTI
    PC

    View Slide

  53. loop:
    INC $05
    JMP loop
    nmi:
    ; Do stuff
    RTI
    PC

    View Slide

  54. loop:
    INC $05
    JMP loop
    nmi:
    ; Do stuff
    RTI
    PC

    View Slide

  55. loop:
    INC $05
    JMP loop
    nmi:
    ; Do stuff
    RTI
    PC

    View Slide

  56. loop:
    INC $05
    JMP loop
    nmi:
    ; Do stuff
    RTI
    PC

    View Slide

  57. loop:
    INC $05
    JMP loop
    nmi:
    ; Do stuff
    RTI
    PC

    View Slide

  58. loop:
    INC $05
    JMP loop
    nmi:
    ; Do stuff
    RTI
    PC

    View Slide

  59. loop:
    INC $05
    JMP loop
    nmi:
    ; Do stuff
    RTI
    PC

    View Slide

  60. Milestone 4
    #
    #
    "

    View Slide

  61. controllers
    $4016-$4017

    View Slide

  62. View Slide

  63. 0 0 0 0 0 0 0 0
    a B se st

    View Slide

  64. $
    1 0 0 0 0 0 0 0
    a B se st

    View Slide

  65. $
    $
    1 0 0 0 0 0 0 1
    a B se st

    View Slide

  66. LDA controller1
    AND #%10000000
    BEQ notPressed

    ; A is pressed
    notPressed:
    RTS

    View Slide

  67. LDA controller1
    AND #%10000000
    BEQ notPressed

    ; A is pressed
    notPressed:
    RTS
    1 0 0 0 0 0 0 0
    a B se st

    View Slide

  68. Milestone 5
    # #
    "
    %
    &
    "

    View Slide

  69. wine + fceux

    View Slide

  70. View Slide

  71. lua scripting

    View Slide

  72. emu.frameadvance()
    memory.readbyte(0x0000)
    memory.writebyte(0x0001, 0x30)

    View Slide

  73. emu.registerafter(function()
    ballX = memory.readbyte(0x0000)
    ballY = memory.readbyte(0x0001)
    gui.text(
    10,
    30,
    string.format('Ball: %02x,%02x', ballX, ballY)
    )
    end)

    View Slide

  74. View Slide

  75. '

    View Slide

  76. '
    (
    lua

    View Slide

  77. !
    )

    View Slide

  78. function TestBall:test_ball_moves_down()
    memory.writebyte(ballYAddress, 0x30)
    memory.writebyte(ballYDirection, 0x01)
    emu.frameadvance()
    ballY = memory.readbyte(ballYAddress)
    luaunit.assertEquals(ballY, 0x31)
    end

    View Slide

  79. View Slide

  80. View Slide

  81. View Slide

  82. Read the source code
    when in doubt

    View Slide

  83. View Slide

  84. NExt steps

    View Slide

  85. @cjoudrey

    View Slide