;;;
;; This example shows how to read from one controller and set it into the $20
;; memory address. The `Main` subroutine will call the `ReadController`
;; subroutine and then increment the value on $42 if the right arrow was
;; pressed. When running this ROM, watch for the following RAM addresses:
;;
;;  - $20: the bitmap of the current status of the controller (notice that since
;;         we are constantly polling it and filling it, the value will move constantly).
;;  - $21: the previous status of the right arrow.
;;  - $42: the counter which is incremented on each press of the right arrow button.
;;
;; Whenever you are done with this example, hop into the `shared/joypad.s` file,
;; which brings some other considerations when reading from controllers. That
;; is, the algorithm shown below is not entirely "safe" due to a hardware bug
;; which might give unreliable inputs on some spikes.

;;;
;; You can safely ignore all of this up until the `ReadController` subroutine.
;; This is boilerplate that is explained on the `sprite.s` example.

.segment "HEADER"
    .byte 'N', 'E', 'S', $1A
    .byte $02
    .byte $01
    .byte $00
    .byte $00

.segment "VECTORS"
  .addr nmi
  .addr reset
  .addr irq

.segment "CODE"

;; Unused
.proc nmi
    rti
.endproc

;; Unused
.proc irq
    rti
.endproc

.proc reset
    sei
    cld
    ldx #$40
    stx $4017

    ldx #$FF
    txs

    inx
    stx $2000
    stx $2001
    stx $4010

    bit $2002
@vblankwait1:
    bit $2002
    bpl @vblankwait1

    ldx #0
    lda #0
@ram_reset_loop:
    sta $000, x
    sta $100, x
    sta $200, x
    sta $300, x
    sta $400, x
    sta $500, x
    sta $600, x
    sta $700, x
    inx
    bne @ram_reset_loop

@vblankwait2:
    bit $2002
    bpl @vblankwait2

    jmp main
.endproc

.proc ReadController
  ;; The status of the eight buttons fits into a single byte. We start the whole
  ;; dance by setting the first bit of the position we are storing this info
  ;; ($20). This bit will act as a guard in the following code.
  lda #1
  sta $20

  ;; The 4021 chip is the one responsible to bring the input from the controller
  ;; into the NES. The console reserves two addresses on the memory for the
  ;; controllers: $4016 and $4017 (see
  ;; https://www.nesdev.org/wiki/Input_devices). If you write into one of them
  ;; first with a #1 and then with a #0, we activate the latch for the
  ;; controller, and it will start to send a bit representing the state for each
  ;; button upon each read.
  ;;
  ;; Thus, since we conveniently now have #1 into the 'a' register, we send this
  ;; value to the 4021 chip, and we follow it by sending #0. This way we tell
  ;; the controller to start to deliver the data.
  sta $4016
  lda #0
  sta $4016

  ;; The status of the buttons will be provided one by one following a specific
  ;; order. The algorithm goes as follows:
  ;;
  ;;   1. Load the bit you get from the 4021 chip into `a`. After performing
  ;;      this read the controller will send the next one so it's ready for the
  ;;      next iteration.
  ;;   2. Shift the value right so to set the carry flag as its comes (note:
  ;;      overflowing from the right also sets the carry flag on!).
  ;;   3. Rotate one bit left from $20: C <- [$20] <- C. This way, we always get
  ;;      the result we put on the carry register at the right-most part of the
  ;;      byte on $20, and we clear the carry flag (the previous left-most bit
  ;;      moves into the carry register, which is 0 until we reach the one we
  ;;      planted as a guard).
  ;;   4. We jump back into `read_loop` if the carry flag is clear. This is the
  ;;      case for most of the time until the #1 that we set at the very
  ;;      beginning as a guard flows into the carry flag as expected from the
  ;;      `rol` instruction. At this point, we have already read the full byte.
read_loop:
  lda $4016
  lsr
  rol $20
  bcc read_loop

  rts
.endproc

;; The main function will run indefinitely and it will continuously poll from
;; the controller and increment the value on $42 each time the user performs a
;; new press on the right arrow (that is, we want to count new presses on this
;; button, and we don't want to increment this value while the right arrow is
;; being pressed).
.proc main
  ;; Initialize the value on $21 (previous state) and on $42 (counter).
  lda #0
  sta $42
  sta $21

loop:
  jsr ReadController

  ;; Was the right arrow being pressed? If that's the case, then jump into the
  ;; `pressed` label to compare it with the previous state.
  lda #1
  and $20
  bne pressed

  ;; The right arrow was not being pressed. Thus, we need to update the previous
  ;; state to #0 before we read the controller again.
  lda #0
  sta $21
  jmp loop

pressed:
  ;; Now the right arrow is being pressed, and we have the guarantee that `a =
  ;; 1` (because of the `and $20` instruction returning a non-zero result). Now
  ;; do the same with the previous state. If it's a non-zero result, then it
  ;; means that the previous state was already of pressed. Hence, at this point
  ;; we can return into the main loop. If this was not the case, then it's a new
  ;; press.
  and $21
  bne loop

  ;; It's a new press, set $21 to #1 accordinly and increment the counter on $42.
  inc $21
  inc $42

  ;; There and back again.
  jmp loop
.endproc

.segment "CHARS"
.byte $00
