aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiquel Sabaté Solà <msabate@suse.com>2023-12-05 15:37:35 +0100
committerMiquel Sabaté Solà <msabate@suse.com>2023-12-08 12:41:31 +0100
commit57fde0bb5184371da33b212de6731c6e6829349f (patch)
tree916bf9ebfa6334b75ee91594b870de6ad1a0e9ec
parentc0d6966592a0aaeda220fff1171f057ef14a7ea6 (diff)
downloadaoc2023.nes-57fde0bb5184371da33b212de6731c6e6829349f.tar.gz
aoc2023.nes-57fde0bb5184371da33b212de6731c6e6829349f.zip
Implemented both parts of the second day
Signed-off-by: Miquel Sabaté Solà <msabate@suse.com>
-rw-r--r--Makefile4
-rw-r--r--README.md3
-rw-r--r--include/print.s89
-rw-r--r--src/1.s74
-rw-r--r--src/2.s637
5 files changed, 740 insertions, 67 deletions
diff --git a/Makefile b/Makefile
index 15c6c3c..37723c5 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,8 @@ CC65 ?= cl65
CCOPTS ?= --target nes
QUIET = @echo ' ' CC65 $@;
+SOURCES = $(shell find src/ -type f -name '*.s' -printf "%f\n")
+ROMS = $(SOURCES:%.s=out/%.nes)
.PHONY: all
all: clean deps build
@@ -18,7 +20,7 @@ deps:
@which $(CC65) >/dev/null 2>/dev/null || (echo "ERROR: $(CC65) not found." && false)
.PHONY: build
-build: out/1.nes
+build: $(ROMS)
out/%.nes: src/%.s
$(QUIET) $(CC65) $(CCOPTS) $< -o $@
diff --git a/README.md b/README.md
index bd759b1..93e462d 100644
--- a/README.md
+++ b/README.md
@@ -27,3 +27,6 @@ wiki](https://www.nesdev.org/wiki/Nesdev_Wiki) to get a better picture.
Released under the [GPLv3+](http://www.gnu.org/licenses/gpl-3.0.txt), Copyright
(C) 2023-<i>Ω</i> Miquel Sabaté Solà.
+
+All code under the `vendor` directory is directly taken from other people and
+not written by me. Attribution is done inside of each file.
diff --git a/include/print.s b/include/print.s
new file mode 100644
index 0000000..7a0ac23
--- /dev/null
+++ b/include/print.s
@@ -0,0 +1,89 @@
+.scope Print
+ ;; Print a "Please wait..." message to the screen. This message will be centered
+ ;; horizontally and slightly at the top of the screen. This function assumes
+ ;; that alphanumerical tiles are located in a similar fashion as for the
+ ;; `assets/alphanum.chr` file.
+ .proc show_wait_message
+ WRITE_PPU_DATA $2129, $2A
+ WRITE_PPU_DATA $212A, $26
+ WRITE_PPU_DATA $212B, $1F
+ WRITE_PPU_DATA $212C, $1B
+ WRITE_PPU_DATA $212D, $2D
+ WRITE_PPU_DATA $212E, $1F
+
+ WRITE_PPU_DATA $2130, $31
+ WRITE_PPU_DATA $2131, $1B
+ WRITE_PPU_DATA $2132, $23
+ WRITE_PPU_DATA $2133, $2E
+ WRITE_PPU_DATA $2134, $36
+ WRITE_PPU_DATA $2135, $36
+ WRITE_PPU_DATA $2136, $36
+
+ rts
+ .endproc
+
+ ;; TODO
+ .proc show_bcd_16_number
+ ;; Clear tiles that were written by `show_wait_message` and that are not re-used
+ ;; here.
+ WRITE_PPU_DATA $2129, $00
+ WRITE_PPU_DATA $212A, $00
+ WRITE_PPU_DATA $212B, $00
+ WRITE_PPU_DATA $212C, $00
+ WRITE_PPU_DATA $212D, $00
+ WRITE_PPU_DATA $2133, $00
+ WRITE_PPU_DATA $2134, $00
+ WRITE_PPU_DATA $2135, $00
+ WRITE_PPU_DATA $2136, $00
+
+ ;; And loop so PPU::ADDRESS $2E21-$2E32 has the data as stored on bcdResult,
+ ;; which is the binary to decimal conversion result when the final
+ ;; computation was done.
+ ldx #4
+ ldy #$2E
+ @loop:
+ ;; PPU address.
+ bit PPU::STATUS
+ lda #$21
+ sta PPU::ADDRESS
+ sty PPU::ADDRESS
+
+ ;; PPU data.
+ lda bcdResult, x
+ clc
+ adc #$10
+ sta PPU::DATA
+ dex
+ iny
+ cpy #$33
+ bne @loop
+
+ rts
+ .endproc
+
+ ;; Copies basic palettes into the proper PPU address.
+ .proc load_basic_palettes
+ PPU_ADDR $3F00
+
+ ldx #0
+ @load_palettes_loop:
+ lda palettes, x
+ sta PPU::DATA
+ inx
+ cpx #$20
+ bne @load_palettes_loop
+ rts
+ palettes:
+ ;; Background (only first one used)
+ .byte $0F, $30, $10, $00
+ .byte $0F, $00, $00, $00
+ .byte $0F, $00, $00, $00
+ .byte $0F, $00, $00, $00
+
+ ;; Foreground (unused)
+ .byte $0F, $00, $00, $00
+ .byte $0F, $00, $00, $00
+ .byte $0F, $00, $00, $00
+ .byte $0F, $00, $00, $00
+ .endproc
+.endscope
diff --git a/src/1.s b/src/1.s
index 202c3ee..d4cffa2 100644
--- a/src/1.s
+++ b/src/1.s
@@ -1,9 +1,9 @@
;;;
;; Day 1 https://adventofcode.com/2023/day/1
;;
-;; This program then iterates over the array on `data` and computes the value on
-;; each row, then accumulating it into a sum variable. The end result will be
-;; printed to the screen, which must be `54953`.
+;; This program iterates over the array on `data` and computes the value on each
+;; row, then accumulating it into a sum variable. The end result will be printed
+;; to the screen, which must be `54953`.
;; Luckily for us, good ol' NROM can fit the data set for this exercise :D
.segment "HEADER"
@@ -24,12 +24,14 @@
.segment "STARTUP"
.segment "CODE"
+.include "../vendor/bcd16.s"
+
.include "../include/apu.s"
.include "../include/oam.s"
.include "../include/ppu.s"
.include "../include/reset.s"
.include "../include/globals.s"
-.include "../vendor/bcd16.s"
+.include "../include/print.s"
;; "Variables" used by this program.
.scope Vars
@@ -276,10 +278,10 @@ nmi:
;; Otherwise print the given result.
bit Globals::m_flags
bvs :+
- jsr print_message
+ jsr Print::show_wait_message
jmp :++
:
- jsr print_result
+ jsr Print::show_bcd_16_number
:
;; Reset the scroll.
@@ -300,66 +302,6 @@ nmi:
@nmi_next:
rti
-;; Simply print "Please wait..." to the screen.
-.proc print_message
- WRITE_PPU_DATA $2129, $2A
- WRITE_PPU_DATA $212A, $26
- WRITE_PPU_DATA $212B, $1F
- WRITE_PPU_DATA $212C, $1B
- WRITE_PPU_DATA $212D, $2D
- WRITE_PPU_DATA $212E, $1F
-
- WRITE_PPU_DATA $2130, $31
- WRITE_PPU_DATA $2131, $1B
- WRITE_PPU_DATA $2132, $23
- WRITE_PPU_DATA $2133, $2E
- WRITE_PPU_DATA $2134, $36
- WRITE_PPU_DATA $2135, $36
- WRITE_PPU_DATA $2136, $36
-
- rts
-.endproc
-
-;; Print the result on screen. This assumes that `bcdResult` already contains
-;; the proper data.
-.proc print_result
- ;; Clear tiles that were written by `print_message` and that are not re-used
- ;; here.
- WRITE_PPU_DATA $2129, $00
- WRITE_PPU_DATA $212A, $00
- WRITE_PPU_DATA $212B, $00
- WRITE_PPU_DATA $212C, $00
- WRITE_PPU_DATA $212D, $00
- WRITE_PPU_DATA $2133, $00
- WRITE_PPU_DATA $2134, $00
- WRITE_PPU_DATA $2135, $00
- WRITE_PPU_DATA $2136, $00
-
- ;; And loop so PPU::ADDRESS $2E21-$2E32 has the data as stored on bcdResult,
- ;; which is the binary to decimal conversion result when the final
- ;; computation was done.
- ldx #4
- ldy #$2E
-@loop:
- ;; PPU address.
- bit PPU::STATUS
- lda #$21
- sta PPU::ADDRESS
- sty PPU::ADDRESS
-
- ;; PPU data.
- lda bcdResult, x
- clc
- adc #$10
- sta PPU::DATA
- dex
- iny
- cpy #$33
- bne @loop
-
- rts
-.endproc
-
;; Unused.
irq:
rti
diff --git a/src/2.s b/src/2.s
new file mode 100644
index 0000000..e4f0361
--- /dev/null
+++ b/src/2.s
@@ -0,0 +1,637 @@
+;;;
+;; Day 2 https://adventofcode.com/2023/day/2
+;;
+;; The enunciate has two parts and this program gives an answer to both parts
+;; in a single iteration.
+;;
+;; - Part 1: the answer will be printed on screen and the value is stored in
+;; RAM address: $00-$01 (`Vars::m_sum` in the code).
+;; - Part 2: the answer is bigger than what a 16-bit number can hold. For this
+;; reason I am not printing it on screen and instead you will have to
+;; inspect the 32-bit number stored in RAM address: $0B-$0E
+;; (`Vars::m_sum_2` in the code).
+
+.segment "HEADER"
+ .byte 'N', 'E', 'S', $1A
+
+ .byte $02
+ .byte $01
+
+ .byte $00
+ .byte $00
+
+.segment "VECTORS"
+ .addr nmi, reset, irq
+
+.segment "CHARS"
+ .incbin "../assets/alphanum.chr"
+
+.segment "STARTUP"
+.segment "CODE"
+
+.include "../vendor/bcd16.s"
+
+.include "../include/apu.s"
+.include "../include/oam.s"
+.include "../include/ppu.s"
+.include "../include/reset.s"
+.include "../include/globals.s"
+.include "../include/print.s"
+
+;; "Variables" used by this program.
+.scope Vars
+ ;; Maximum number for each color according to Part 1.
+ RED = 12
+ GREEN = 13
+ BLUE = 14
+
+ ;; The answer on part 1 will be accumulated on this address on each
+ ;; iteration.
+ ;;
+ ;; NOTE: 16-bit ($00-$01).
+ m_sum = $00
+
+ ;; Single byte temporary values. Named like this because they are mostly
+ ;; used on converting a three-sized string into a numerical value.
+ m_num_1 = $02
+ m_num_2 = $03
+ m_num_3 = $04
+
+ ;; The address where the current data row is located. This address will be
+ ;; incremented on each loop iteration so it always points to the first item
+ ;; of the needed row.
+ ;;
+ ;; NOTE: this is a full address and, therefore, is 16-bit. Because of this
+ ;; this is actually stored at $05-$06.
+ m_address = $05
+
+ ;; The ID of the current game being evaluated. This is actually not needed,
+ ;; but it's done this way for readability purposes.
+ m_game_id = $07
+
+ ;; This is a three-sized array that stores the maximum value that has been
+ ;; seen on each color on the current iteration (sorted by "rgb").
+ ;;
+ ;; NOTE: memory addresses being used: $08 (red), $09 (green), $0A (blue).
+ m_rgb_max = $08
+
+ ;; The answer on part 2 will be accumulated on this address on each
+ ;; iteration.
+ ;;
+ ;; NOTE: 32-bit ($0B-$0E). Note that 24-bit is enough, but tools like FCEUX
+ ;; go from 16-bit digits to 32-bit directly. Since we have a lot of spare
+ ;; memory, we don't care.
+ m_sum_2 = $0B
+
+ ;; Initialize some of the variables.
+ .proc init
+ lda #0
+ sta m_sum
+ sta m_sum + 1
+ sta m_sum_2
+ sta m_sum_2 + 1
+ sta m_sum_2 + 2
+ sta m_sum_2 + 3
+
+ lda #.LOBYTE(data)
+ sta Vars::m_address
+ lda #.HIBYTE(data)
+ sta Vars::m_address + 1
+
+ rts
+ .endproc
+.endscope
+
+;; The main function will be called at the end of the `reset` vector as defined
+;; in `include/reset.s`.
+.proc main
+ ;; Initialize palettes and variables being used for this program.
+ jsr Print::load_basic_palettes
+ jsr Vars::init
+
+ ;; This program uses two flags:
+ ;; - 7 (`render`): whether NMI-code can render stuff on screen.
+ ;; - 6 (`done`): whether the computation has been done.
+ ;; - 0 (`possible`): whether the last evaluated combination is
+ ;; possible or not.
+ ;; Note that we are setting the render flag so the initial message is
+ ;; shown.
+ lda #%10000000
+ sta Globals::m_flags
+
+ cli
+
+ lda #%10010000
+ sta PPU::CONTROL
+ lda #%00011110
+ sta PPU::MASK
+
+@loop:
+ jsr compute_next
+ jmp @loop
+.endproc
+
+;; Compute the next game if needed.
+.proc compute_next
+ ;; Skip everything if the `done` flag is set.
+ bit Globals::m_flags
+ bvs @end
+
+ jsr compute_row
+
+ ;; `compute_row` will actually move `y` to the end of the string. At this
+ ;; point, advance one byte more and we are at the start of the next one.
+ ;; With this, move the base address here since we don't want the poor 8-bit
+ ;; `y` register to overflow over time.
+ iny
+ tya
+ clc
+ adc Vars::m_address
+ sta Vars::m_address
+ lda #0
+ adc Vars::m_address + 1
+ sta Vars::m_address + 1
+
+ ;; Are we actually at the end of the exercise? If not, return early.
+ ldy #0
+ lda (Vars::m_address), y
+ cmp #$ED
+ bne @end
+
+ ;; Mark the `done` flag so future iterations don't go through all of this.
+ lda #%01000000
+ ora Globals::m_flags
+ sta Globals::m_flags
+
+ ;; Store the 16-bit number into `bcdNum` and call `bcdConvert` so it's
+ ;; converted into a format that can be displayed on screen.
+ lda Vars::m_sum + 1
+ sta bcdNum
+ lda Vars::m_sum
+ sta bcdNum + 1
+ jsr bcdConvert
+
+ ;; Because of the previous, we can set the `render` flag again.
+ SET_RENDER_FLAG
+@end:
+ rts
+.endproc
+
+;; Compute a given row (game). This will move the `y` register to the end of the
+;; string so the caller can take advantage of it.
+.proc compute_row
+ ;; Set the `possible` flag to true always. This will be set to false if it's
+ ;; found to be impossible.
+ lda #%00000001
+ ora Globals::m_flags
+ sta Globals::m_flags
+
+ ;; Initialize the `Vars::m_rgb_max` array by giving each color a maximum of
+ ;; exactly 1. Note that in all games each color always appears at least
+ ;; once.
+ lda #1
+ sta Vars::m_rgb_max
+ sta Vars::m_rgb_max + 1
+ sta Vars::m_rgb_max + 2
+
+ ;; NOTE: the following is actually not needed, but I find it more "formal"
+ ;; to actually parse the game ID than just increase a given number. That is,
+ ;; in the input all games are given sequentally. Thus, one could just
+ ;; increase a value on each iteration and assume that as the game ID.
+
+ ;; The format is "Game X: <whatever>". Thus, before the game ID there is
+ ;; always a space. Loop until we find it.
+ ldy #$FF
+@wait_until_space:
+ iny
+ lda (Vars::m_address), y
+ cmp #32
+ bne @wait_until_space
+ iny
+
+ ;; Now we are guaranteed to point to the game ID. Parse the number and store
+ ;; it. It will be used at the end.
+ jsr parse_number
+ sta Vars::m_game_id
+
+ ;; This is the main evaluation loop.
+@loop:
+ ;; Load the current byte. If this is a zero byte, then we are at the end of
+ ;; the string and we can go to the `@done` section. Otherwise, we should
+ ;; loop until we find a space character, because before the number for each
+ ;; color we are guaranteed to have a space character.
+ lda (Vars::m_address), y
+ beq @done
+ iny
+ cmp #32
+ bne @loop
+
+ ;; We can now parse the number we have ahead, and we will store it into
+ ;; `Vars::m_num_1`, which will act as a temporary value.
+ jsr parse_number
+ sta Vars::m_num_1
+
+ ;; `parse_number` will leave `y` to the character just after the last
+ ;; numerical digit. We are guaranteed to have this format `<number><1
+ ;; space><color identifier>`. Thus, we just need to increase `y` once to get
+ ;; into the first byte of the color identifier.
+ ;;
+ ;; Whenever we do this, we will compare the caracter with 'r', 'g', 'b' and
+ ;; jump to each color accordingly. Each color will do the same:
+ ;;
+ ;; 1. Set 'x' to the color index on the `Vars::m_rgb_max` array so it can
+ ;; be picked by the `set_max` function. This will set the maximum value
+ ;; by comparing whatever we have on this array and the value we have
+ ;; stored on `Vars::m_num_1` (stored when we parsed the number).
+ ;; 2. According to Part 1, we have to check whether the combination was
+ ;; possible. Thus, we need to compare the number we found for the color
+ ;; with the maximum that is allowed for it. If the value is lesser than
+ ;; what we have, then we go back at the beginning of the loop.
+ ;; Otherwise we do a final check on `@check_equal`.
+ iny
+ lda (Vars::m_address), y
+ cmp #114
+ beq @red
+ cmp #103
+ beq @green
+
+ ;; Blue
+ ldx #2
+ jsr set_max
+ lda Vars::m_num_1
+ cmp #Vars::BLUE
+ bcs @check_equal
+ jmp @loop
+@red:
+ ldx #0
+ jsr set_max
+ lda Vars::m_num_1
+ cmp #Vars::RED
+ bcs @check_equal
+ jmp @loop
+@green:
+ ldx #1
+ jsr set_max
+ lda Vars::m_num_1
+ cmp #Vars::GREEN
+ bcs @check_equal
+ jmp @loop
+
+ ;; We are coming from evaluating a color and realizing that the value is not
+ ;; strictly lesser than what we expected.
+@check_equal:
+ ;; Was it just equal? If so, we are on the safe side and we can go into the
+ ;; next iteration of the loop.
+ beq @loop
+
+ ;; No, the number is simply larger than what we expected! At this point set
+ ;; the `possible` flag to 0, so to mark that this game is actually
+ ;; impossible according to the enunciate of Part 1. After this, just go into
+ ;; the next iteration of the loop, since Part 2 requires us to check every
+ ;; single value of the game (before part 2 was unveiled, at this point we
+ ;; returned earlier).
+ lda #%11111110
+ and Globals::m_flags
+ sta Globals::m_flags
+ jmp @loop
+
+ ;; The loop is done, let's evaluate what we have found.
+@done:
+ ;; Regardless of whether the combination was possible according to Part 1,
+ ;; we still have to sum up the "powers" according to Part 2. Let's do this
+ ;; now.
+ jsr add_powers
+
+ ;; Was the game marked as not possible at any point of the loop. If that is
+ ;; the case, we don't have to do anything more and we return early.
+ lda Globals::m_flags
+ and #%00000001
+ beq @done_for_good
+
+ ;; The game was possible. Thus, according to Part 1 of the enunciate, we add
+ ;; the game ID to the 16-bit number that we are accumulating over for this.
+ lda Vars::m_game_id
+ clc
+ adc Vars::m_sum + 1
+ sta Vars::m_sum + 1
+ lda #0
+ adc Vars::m_sum
+ sta Vars::m_sum
+@done_for_good:
+ rts
+.endproc
+
+;; Parse the number that is currently pointed by `Vars::m_address` plus `y`. The
+;; evaluated number will be returned into the `a` register.
+.proc parse_number
+ ;; Initialize with a guard value.
+ lda #$FF
+ sta Vars::m_num_1
+ sta Vars::m_num_2
+ sta Vars::m_num_3
+
+@loop:
+ ;; Load the given byte. If this is not a numerical value, just go to @done.
+ lda (Vars::m_address), y
+ sec
+ sbc #48
+ bcc @done
+ cmp #10
+ bcs @done
+
+ ;; This is a numerical value! At this point we will set the number on
+ ;; `Vars::m_num_{1, 2, 3}` in order.
+ ldx Vars::m_num_1
+ cpx #$FF
+ beq @first
+ ldx Vars::m_num_2
+ cpx #$FF
+ beq @second
+ sta Vars::m_num_3
+ iny
+ jmp @done
+@first:
+ sta Vars::m_num_1
+ iny
+ jmp @loop
+@second:
+ sta Vars::m_num_2
+ iny
+ jmp @loop
+
+ ;; There are no more numerical digits, let's evaluate what we have parsed.
+@done:
+ ;; If we actually found three digits, we are guaranteed to have a value of
+ ;; exactly `100`. Let's set that and leave early.
+ lda Vars::m_num_3
+ cmp #$FF
+ beq @check_tenth
+ lda #100
+ rts
+@check_tenth:
+ ;; Let's check if we found two digits.
+ lda Vars::m_num_2
+ cmp #$FF
+ beq @just_unit
+
+ ;; If there are two digits, then `m_num_1` contains the tenth. Hence, we
+ ;; have to multiply this number by 10 and then add the unit stored in
+ ;; `m_num_2`.
+ lda Vars::m_num_1
+ asl
+ sta Vars::m_num_3
+ asl
+ asl
+ clc
+ adc Vars::m_num_3
+ clc
+ adc Vars::m_num_2
+ rts
+@just_unit:
+ ;; Only one digit, this is our value as is.
+ lda Vars::m_num_1
+ rts
+.endproc
+
+;; Set the maximum value from the given parameters into the `m_rgb_max` array on
+;; the given index. The value to be compared is expected to be stored at
+;; `m_num_1`, and `x` is expected to be initialized as the index from the
+;; `m_rgb_max` array to be used for both comparison and set.
+.proc set_max
+ lda Vars::m_rgb_max, x
+ cmp Vars::m_num_1
+ bcs @done
+ lda Vars::m_num_1
+ sta Vars::m_rgb_max, x
+@done:
+ rts
+.endproc
+
+;; Multiply the values on `m_rgb_max` and add the resulting value into
+;; `m_sum_2`. Note that `m_num_1` and `m_num_2` will change as a side-effect.
+.proc add_powers
+ ;; Initialize `m_num_1` and `m_num_2`, used as auxiliary values here.
+ lda #0
+ sta Vars::m_num_1
+ sta Vars::m_num_2
+
+ ;; Multiplying the values on `m_rgb_max` on a system with no `mul`
+ ;; instructions or anything like that is as simple as adding the same value
+ ;; N times. On this first loop, we will add the value on 'red' as many times
+ ;; as 'green'. The resulting value will be stored at `m_num_1` plus
+ ;; `m_num_2` on overflows (thus having a 16-bit result).
+ ldx Vars::m_rgb_max + 1
+@loop1:
+ lda Vars::m_rgb_max
+ clc
+ adc Vars::m_num_1
+ sta Vars::m_num_1
+ lda #0
+ adc Vars::m_num_2
+ sta Vars::m_num_2
+ dex
+ bne @loop1
+
+ ;; On the next loop we will multiply on factors of the previous result,
+ ;; which is a 16-bit value. We will temporarily store them into the `red`
+ ;; and `green` positions since we will need `m_num_1` and `m_num_2` again
+ ;; for multiplying a 16-bit integer.
+ lda Vars::m_num_1
+ sta Vars::m_rgb_max
+ lda Vars::m_num_2
+ sta Vars::m_rgb_max + 1
+
+ ;; Now we are selecting `blue`, which is the color we have not touched yet.
+ ldx Vars::m_rgb_max + 2
+ dex
+ ;; NOTE: if `blue` was simply '1', we are done. Note that we could not do
+ ;; this on the previous loop because of how initialization on the 16-bit
+ ;; integer had to happen.
+ beq @done
+@loop2:
+ lda Vars::m_rgb_max
+ clc
+ adc Vars::m_num_1
+ sta Vars::m_num_1
+ lda Vars::m_rgb_max + 1
+ adc Vars::m_num_2
+ sta Vars::m_num_2
+ dex
+ bne @loop2
+
+@done:
+ ;; At this point we are done: store each computed value into the proper
+ ;; memory addresses and that's it. Note that +3 and +2 positions are our
+ ;; actual value, while +1 is only meaningful for adding the carry (we expect
+ ;; the end result the be just a bit above the 16-bit limit). For this same
+ ;; reason we can guarantee that the most significant byte on this 32-bit
+ ;; number will always be zero, so we set it directly accordingly.
+ lda Vars::m_num_1
+ clc
+ adc Vars::m_sum_2 + 3
+ sta Vars::m_sum_2 + 3
+
+ lda Vars::m_num_2
+ adc Vars::m_sum_2 + 2
+ sta Vars::m_sum_2 + 2
+
+ lda #0
+ adc Vars::m_sum_2 + 1
+ sta Vars::m_sum_2 + 1
+
+ lda #0
+ sta Vars::m_sum_2
+
+ rts
+.endproc
+
+;; Non-Maskable Interrupts handler.
+nmi:
+ bit PPU::STATUS
+
+ ;; Skip rendering if the `render` flag is not set.
+ bit Globals::m_flags
+ bpl @nmi_next
+
+ ;; Backup registers.
+ pha
+ txa
+ pha
+ tya
+ pha
+
+ ;; If the result is not there yet, then we just print an initial message.
+ ;; Otherwise print the given result.
+ bit Globals::m_flags
+ bvs :+
+ jsr Print::show_wait_message
+ jmp :++
+:
+ jsr Print::show_bcd_16_number
+:
+
+ ;; Reset the scroll.
+ bit PPU::STATUS
+ lda #$00
+ sta PPU::SCROLL
+ sta PPU::SCROLL
+
+ ;; And unset the render flag so the `main` code is unblocked.
+ UNSET_RENDER_FLAG
+
+ ;; Restore registers.
+ pla
+ tay
+ pla
+ tax
+ pla
+@nmi_next:
+ rti
+
+;; Unused.
+irq:
+ rti
+
+.segment "RODATA"
+data:
+ .asciiz "Game 1: 19 blue, 12 red; 19 blue, 2 green, 1 red; 13 red, 11 blue"
+ .asciiz "Game 2: 1 green, 1 blue, 1 red; 11 red, 3 blue; 1 blue, 18 red; 9 red, 1 green; 2 blue, 11 red, 1 green; 1 green, 2 blue, 10 red"
+ .asciiz "Game 3: 3 blue, 2 red, 6 green; 4 blue, 6 green, 1 red; 11 green, 12 blue; 2 red, 6 green, 4 blue; 4 green"
+ .asciiz "Game 4: 10 red, 5 green, 5 blue; 3 red, 3 blue, 6 green; 2 blue, 9 red, 6 green; 8 green, 10 red, 4 blue; 9 red, 2 green, 3 blue; 1 blue, 5 red, 15 green"
+ .asciiz "Game 5: 11 green, 7 blue; 5 green, 5 red, 1 blue; 1 green, 1 red, 4 blue; 1 red, 1 blue, 4 green; 4 blue, 1 red, 10 green; 5 red, 6 green"
+ .asciiz "Game 6: 1 green, 1 red, 11 blue; 1 blue, 2 green; 1 red, 5 green, 9 blue; 7 blue; 1 red, 2 green, 9 blue; 12 blue, 1 red, 2 green"
+ .asciiz "Game 7: 1 blue, 10 red, 7 green; 14 blue, 10 green; 12 red, 2 green; 16 red, 13 blue, 1 green; 12 green, 10 red, 3 blue; 9 red, 19 blue, 11 green"
+ .asciiz "Game 8: 3 blue, 1 green, 3 red; 4 blue, 10 red, 6 green; 1 green, 10 red, 9 blue; 9 blue, 7 red, 8 green; 8 green, 12 red, 8 blue; 6 blue, 1 green, 13 red"
+ .asciiz "Game 9: 10 green, 2 blue, 11 red; 2 green, 2 red; 6 blue, 8 red, 13 green"
+ .asciiz "Game 10: 8 red, 3 blue, 5 green; 5 green, 7 blue, 1 red; 3 red, 10 blue, 6 green; 2 red, 6 green, 7 blue; 3 blue, 11 red, 4 green; 8 red, 8 blue, 4 green"
+ .asciiz "Game 11: 14 green, 9 red; 3 blue, 6 green, 8 red; 14 green"
+ .asciiz "Game 12: 10 red, 5 blue, 1 green; 4 blue, 8 red; 5 blue, 1 green, 6 red; 14 red, 4 blue; 1 green, 11 red, 3 blue"
+ .asciiz "Game 13: 1 blue, 16 green, 1 red; 6 red, 2 blue, 5 green; 2 blue, 12 red, 10 green; 3 red, 4 blue, 13 green; 14 red, 4 blue, 12 green; 7 red, 2 green"
+ .asciiz "Game 14: 17 red, 11 blue, 3 green; 16 red, 3 blue, 8 green; 3 green, 9 red, 13 blue; 4 green, 15 red, 14 blue"
+ .asciiz "Game 15: 7 blue, 2 red, 2 green; 1 green, 5 red, 6 blue; 3 green, 6 red, 2 blue"
+ .asciiz "Game 16: 3 red, 3 green; 6 green, 4 red, 3 blue; 3 red, 4 blue; 4 blue, 2 red, 4 green"
+ .asciiz "Game 17: 6 red, 1 blue, 5 green; 3 red, 1 green, 12 blue; 13 green, 1 blue; 5 blue, 7 green, 6 red; 5 blue, 14 green, 2 red; 4 green, 6 red, 10 blue"
+ .asciiz "Game 18: 4 red, 8 blue; 8 blue, 4 red; 12 blue, 1 green"
+ .asciiz "Game 19: 1 blue, 15 green, 9 red; 1 red, 3 green; 4 blue, 2 green, 1 red"
+ .asciiz "Game 20: 7 blue, 4 green, 12 red; 1 red, 9 green, 8 blue; 4 blue, 2 green; 13 green, 8 blue; 3 red, 4 green, 1 blue; 6 green, 7 red, 3 blue"
+ .asciiz "Game 21: 9 green, 4 blue, 8 red; 5 blue; 7 red, 8 blue, 1 green"
+ .asciiz "Game 22: 3 green, 4 red; 6 red, 3 green; 4 red, 1 blue, 1 green; 11 red, 3 green, 1 blue; 7 red, 1 blue"
+ .asciiz "Game 23: 3 blue, 4 green; 3 green, 1 red; 1 red, 2 blue, 4 green"
+ .asciiz "Game 24: 2 blue, 3 green; 9 red, 4 green; 2 blue, 9 red; 2 green, 10 red, 1 blue; 1 blue, 1 red, 5 green"
+ .asciiz "Game 25: 8 green, 4 blue; 9 blue, 7 red; 5 green, 15 blue, 11 red; 11 green, 14 red, 10 blue"
+ .asciiz "Game 26: 3 blue; 2 red, 1 green; 2 red, 3 blue; 10 blue, 1 red, 3 green; 1 green, 2 red; 1 green, 6 blue"
+ .asciiz "Game 27: 1 green, 6 blue; 2 green, 1 red, 6 blue; 1 red, 2 blue, 1 green"
+ .asciiz "Game 28: 8 blue, 1 red, 5 green; 1 red; 3 green, 4 red, 2 blue; 4 green, 2 red, 4 blue; 5 blue, 3 red, 7 green"
+ .asciiz "Game 29: 2 green, 4 blue; 7 blue, 4 red, 10 green; 7 blue, 9 green; 14 green, 7 red, 5 blue"
+ .asciiz "Game 30: 19 green, 3 red; 19 green; 1 blue, 14 green; 2 blue, 5 green; 3 red, 19 green"
+ .asciiz "Game 31: 3 red, 1 green, 4 blue; 10 blue; 3 red, 4 green, 5 blue; 10 blue, 1 red, 6 green"
+ .asciiz "Game 32: 19 red, 1 green, 2 blue; 1 blue, 6 green, 13 red; 10 green, 9 red; 11 red, 2 blue, 6 green; 8 green, 5 red"
+ .asciiz "Game 33: 2 red, 8 blue, 2 green; 1 red, 3 green; 9 red, 9 blue, 1 green; 6 red, 1 green; 9 blue, 1 green, 8 red; 5 green, 10 red, 8 blue"
+ .asciiz "Game 34: 1 red, 6 blue, 2 green; 7 red; 14 red, 13 blue; 13 red, 12 blue; 1 green, 9 red, 13 blue; 2 green, 15 blue"
+ .asciiz "Game 35: 8 blue, 2 red, 3 green; 2 green, 2 red; 3 red, 6 blue, 2 green; 2 green, 6 blue; 1 green, 5 blue, 4 red; 3 green, 6 blue"
+ .asciiz "Game 36: 3 red, 5 blue, 10 green; 1 red, 1 green, 7 blue; 2 blue, 2 green, 1 red"
+ .asciiz "Game 37: 8 red, 7 green; 5 green, 1 blue, 6 red; 7 red, 6 blue, 11 green"
+ .asciiz "Game 38: 4 green, 10 red, 9 blue; 12 green, 2 blue, 2 red; 6 red, 6 blue, 9 green; 1 blue, 1 green, 6 red; 3 blue, 1 red, 5 green; 5 blue, 2 red, 12 green"
+ .asciiz "Game 39: 1 blue, 2 red; 7 blue, 2 green, 1 red; 7 blue, 11 green, 3 red; 8 blue, 13 green, 1 red; 6 green, 6 blue, 3 red"
+ .asciiz "Game 40: 8 green, 5 blue; 5 green, 1 blue, 10 red; 9 green, 3 blue; 3 green, 7 red; 2 green, 3 blue, 5 red"
+ .asciiz "Game 41: 7 green, 8 red; 3 blue, 15 green, 7 red; 2 red, 2 green, 4 blue; 10 green, 4 red, 5 blue; 3 red, 8 blue, 9 green; 7 red, 8 green"
+ .asciiz "Game 42: 6 blue, 12 green; 3 red, 1 green; 1 red, 12 green, 3 blue; 10 red, 9 green; 9 red, 4 green, 5 blue"
+ .asciiz "Game 43: 11 red, 6 green; 2 blue, 11 red; 3 red, 1 blue; 3 green, 11 red, 2 blue; 4 red, 5 green, 1 blue; 8 green, 2 blue, 17 red"
+ .asciiz "Game 44: 2 green, 9 blue, 3 red; 7 blue, 1 green, 4 red; 1 green"
+ .asciiz "Game 45: 1 green, 10 red; 5 red, 10 green, 1 blue; 11 red, 3 green, 2 blue; 2 blue, 3 green, 4 red; 7 green, 3 red, 2 blue; 1 blue, 10 red"
+ .asciiz "Game 46: 1 green, 4 blue, 7 red; 13 blue, 2 green, 9 red; 7 blue, 3 red, 1 green"
+ .asciiz "Game 47: 4 blue; 2 green, 2 red, 1 blue; 1 green, 1 red, 4 blue; 1 green, 2 red, 2 blue; 2 blue, 2 red"
+ .asciiz "Game 48: 5 green, 10 red; 7 red, 5 green; 1 green, 11 red; 12 red, 11 green; 11 red, 1 blue, 1 green"
+ .asciiz "Game 49: 2 green, 1 red, 1 blue; 1 blue, 2 red; 2 green, 1 red, 2 blue; 1 blue, 1 red, 1 green"
+ .asciiz "Game 50: 5 green, 2 blue; 4 green, 4 blue, 3 red; 1 red, 7 green, 3 blue"
+ .asciiz "Game 51: 9 green, 1 red, 2 blue; 7 red, 3 blue, 6 green; 5 green, 4 blue, 5 red"
+ .asciiz "Game 52: 2 green, 4 blue, 1 red; 2 blue, 2 red, 13 green; 8 blue, 3 green; 3 green, 4 blue, 2 red; 2 green"
+ .asciiz "Game 53: 3 red; 4 blue, 4 red; 2 blue, 2 red; 6 blue, 1 red, 2 green; 1 red, 1 green, 6 blue; 2 blue, 4 red"
+ .asciiz "Game 54: 3 blue, 3 green, 18 red; 4 blue, 18 red, 3 green; 7 blue, 4 green"
+ .asciiz "Game 55: 1 green, 2 red, 3 blue; 1 red, 4 blue, 1 green; 3 blue, 2 red; 2 blue, 1 green; 3 blue, 2 red; 1 blue, 1 green, 1 red"
+ .asciiz "Game 56: 12 green, 2 red, 1 blue; 11 green, 16 red, 13 blue; 7 red, 5 blue, 12 green; 4 blue, 16 red; 5 red, 1 blue, 3 green"
+ .asciiz "Game 57: 5 green, 17 blue, 11 red; 6 blue, 1 green; 1 green, 5 blue, 8 red; 9 green, 11 red, 1 blue; 9 green, 11 blue, 7 red; 8 green, 4 blue"
+ .asciiz "Game 58: 5 red, 10 blue, 6 green; 5 green, 11 blue, 5 red; 9 green; 4 red, 2 green"
+ .asciiz "Game 59: 2 red, 6 blue, 1 green; 1 green, 12 blue; 2 red"
+ .asciiz "Game 60: 6 blue, 10 green, 9 red; 8 red, 19 blue, 2 green; 16 red, 10 green, 12 blue; 13 red, 12 blue, 6 green"
+ .asciiz "Game 61: 12 green, 1 red, 3 blue; 3 red, 4 blue, 19 green; 1 blue, 7 green"
+ .asciiz "Game 62: 7 red, 6 blue, 8 green; 10 blue, 3 green, 17 red; 13 blue, 3 red, 10 green; 13 red, 5 blue, 9 green; 12 blue, 4 red; 10 red, 4 green"
+ .asciiz "Game 63: 19 green, 4 red; 5 blue, 4 red, 1 green; 4 red, 2 blue, 15 green; 5 green, 4 red, 5 blue"
+ .asciiz "Game 64: 6 red, 3 green; 6 green, 3 red, 3 blue; 3 blue, 8 red, 5 green; 3 blue, 7 red, 1 green; 1 blue, 6 red, 6 green"
+ .asciiz "Game 65: 1 green, 9 blue; 6 blue, 4 green, 6 red; 6 blue, 5 green; 3 red, 1 blue, 4 green"
+ .asciiz "Game 66: 1 blue, 2 red; 2 green, 1 blue; 2 red, 1 blue, 1 green; 1 blue, 1 green"
+ .asciiz "Game 67: 16 blue, 1 green; 1 blue, 2 green, 2 red; 1 red, 9 blue; 12 blue, 4 green, 1 red; 6 green, 11 blue, 3 red"
+ .asciiz "Game 68: 6 blue, 2 red, 1 green; 2 blue, 2 green; 1 green, 7 red, 15 blue; 14 blue, 12 green, 3 red; 13 green, 10 red, 6 blue; 2 green, 5 blue, 1 red"
+ .asciiz "Game 69: 2 red, 1 blue, 2 green; 1 blue, 7 green, 1 red; 3 blue, 1 red, 7 green; 2 red, 1 blue, 11 green"
+ .asciiz "Game 70: 2 green, 9 red, 3 blue; 12 blue, 1 green, 13 red; 6 red, 1 green, 5 blue; 1 red, 17 blue"
+ .asciiz "Game 71: 7 red, 5 green, 6 blue; 5 blue, 5 green; 7 green, 4 blue; 2 green, 4 blue, 8 red; 10 red, 8 green; 3 blue, 13 red, 7 green"
+ .asciiz "Game 72: 13 red, 17 green; 9 red, 20 green, 3 blue; 1 green, 3 blue, 8 red"
+ .asciiz "Game 73: 1 blue, 7 red, 2 green; 2 green, 1 blue, 8 red; 1 blue, 2 red; 4 red, 7 green; 4 red, 5 green; 3 green, 7 red"
+ .asciiz "Game 74: 2 green, 14 blue; 1 red, 1 blue, 7 green; 1 red, 8 green, 11 blue; 4 green, 12 blue; 1 green, 5 blue"
+ .asciiz "Game 75: 12 blue, 1 red; 1 red, 7 blue, 4 green; 4 blue, 6 green; 4 green, 3 blue, 1 red"
+ .asciiz "Game 76: 7 green, 5 red, 6 blue; 18 red, 1 green; 14 green, 4 red, 15 blue; 4 blue, 6 red"
+ .asciiz "Game 77: 2 blue, 2 green, 2 red; 2 blue, 1 red, 1 green; 2 green, 1 red; 6 blue, 4 green; 1 red, 1 blue, 6 green"
+ .asciiz "Game 78: 5 red, 16 blue, 12 green; 11 blue, 3 red, 2 green; 13 blue, 4 red"
+ .asciiz "Game 79: 9 red, 11 green, 6 blue; 1 red, 3 green; 7 blue, 7 red, 11 green; 8 red, 9 blue, 11 green; 7 red, 11 green, 4 blue"
+ .asciiz "Game 80: 7 green, 5 red, 2 blue; 1 blue, 7 green, 1 red; 2 red, 2 blue; 1 red, 4 blue, 12 green; 4 green, 2 blue"
+ .asciiz "Game 81: 5 blue, 2 green, 12 red; 2 green, 1 blue, 5 red; 3 blue, 13 red, 3 green; 3 green, 9 blue, 3 red; 10 blue, 4 red, 3 green"
+ .asciiz "Game 82: 11 blue, 1 red, 9 green; 11 green, 1 blue, 12 red; 13 red, 6 blue, 19 green"
+ .asciiz "Game 83: 6 red, 5 blue, 16 green; 4 green, 17 blue, 9 red; 15 red, 2 green, 9 blue"
+ .asciiz "Game 84: 19 green, 11 blue, 3 red; 1 blue, 18 green, 6 red; 17 blue, 5 green, 4 red; 18 blue, 7 green, 3 red"
+ .asciiz "Game 85: 3 green, 15 blue; 12 blue; 2 green, 1 red; 1 red, 9 blue, 1 green; 12 blue, 3 red, 1 green"
+ .asciiz "Game 86: 3 green, 4 blue, 5 red; 9 red, 4 green, 1 blue; 6 green, 1 blue, 8 red; 3 green, 2 blue, 5 red"
+ .asciiz "Game 87: 2 red, 8 blue, 5 green; 3 red, 5 blue, 10 green; 2 red, 3 green"
+ .asciiz "Game 88: 16 green, 13 red; 7 green, 1 blue, 2 red; 7 red, 12 green; 5 red, 7 green, 2 blue; 2 blue, 10 green, 7 red; 8 red, 16 green"
+ .asciiz "Game 89: 1 blue, 8 red; 2 green, 10 red, 12 blue; 13 green, 14 blue; 10 blue, 15 red, 13 green; 2 green, 5 red, 13 blue"
+ .asciiz "Game 90: 16 blue, 7 red, 4 green; 4 green, 6 red, 11 blue; 2 red, 8 blue, 2 green; 5 green, 8 red, 10 blue; 4 red, 2 green, 7 blue; 4 green, 5 blue, 5 red"
+ .asciiz "Game 91: 4 red, 4 green, 1 blue; 3 blue, 2 green; 6 blue, 4 green, 5 red; 2 red, 6 blue, 4 green; 6 blue, 1 green"
+ .asciiz "Game 92: 1 red, 3 green; 3 blue, 6 green; 5 blue, 1 red, 11 green; 1 red; 3 green, 13 blue"
+ .asciiz "Game 93: 1 red, 14 blue, 6 green; 10 blue, 6 red; 9 green, 15 red, 17 blue; 9 red, 1 green, 9 blue"
+ .asciiz "Game 94: 3 red, 14 green; 3 blue, 15 green, 3 red; 2 red, 15 green"
+ .asciiz "Game 95: 4 blue, 13 red; 5 blue, 1 green, 11 red; 3 green, 3 blue, 10 red; 13 red, 6 blue; 2 green, 5 blue; 3 green, 11 red"
+ .asciiz "Game 96: 7 blue, 1 green; 1 green, 4 blue; 1 green, 2 red, 5 blue; 1 red, 2 blue, 1 green; 1 blue"
+ .asciiz "Game 97: 15 green, 9 blue; 14 blue, 14 red, 2 green; 18 red, 12 blue, 2 green"
+ .asciiz "Game 98: 1 green, 9 red; 1 red, 2 green, 7 blue; 8 red, 1 blue; 6 red, 2 green; 1 green, 6 blue"
+ .asciiz "Game 99: 1 green, 2 red, 6 blue; 6 red, 1 green, 5 blue; 11 blue, 6 red; 11 red, 1 green; 1 green, 11 red, 9 blue"
+ .asciiz "Game 100: 12 green, 8 blue, 2 red; 7 blue, 14 red, 8 green; 14 red, 1 blue, 4 green"
+ .byte $ED