diff options
| author | Miquel Sabaté Solà <msabate@suse.com> | 2023-10-24 17:40:19 +0200 |
|---|---|---|
| committer | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-02-04 20:58:36 +0100 |
| commit | 149020464517ff3d021eef5ccd50d3939ad463e6 (patch) | |
| tree | 056ec1919fe0c0d515e7a0a414916307b768ef84 /examples/input.s | |
| parent | be2414f5b11b182998fca7e87712ff0502c8ee93 (diff) | |
| download | code.nes-149020464517ff3d021eef5ccd50d3939ad463e6.tar.gz code.nes-149020464517ff3d021eef5ccd50d3939ad463e6.zip | |
Lay out a proper structure for the project
Let's divide things by topic instead of a broad "examples" directory.
This will allow for simple files to co-exist together with full-blown
projects.
Signed-off-by: Miquel Sabaté Solà <msabate@suse.com>
Diffstat (limited to 'examples/input.s')
| -rw-r--r-- | examples/input.s | 170 |
1 files changed, 0 insertions, 170 deletions
diff --git a/examples/input.s b/examples/input.s deleted file mode 100644 index 25b17b0..0000000 --- a/examples/input.s +++ /dev/null @@ -1,170 +0,0 @@ -;; -;; 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. -;;; - -;;; -;; 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 "STARTUP" - -.segment "CODE" - -nmi: -irq: - rti - -reset: - sei - cld - ldx #$40 - stx $4017 - - ldx #$ff - txs - - inx - stx $2000 - stx $2001 - stx $4010 - -@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 - -.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 a - 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 - - rts -.endproc - -.segment "CHARS" |
