A Documenting of my Fizzbuzz CHIP-8 Program
This is documentation for the fizzbuzz program I've written for the fifth OctoJam event.
Firstly, follows is a view of the program when it is first loaded into the tool; as this program was
written in the tool, it will only be shown fully annotated with all metadata loaded as well:
[32m200-201 [31m0512-0513 [34m▀▄█ █ A262 41570 [39m I ← from
[32m202-203 [31m0514-0515 [34m▀██▀▀█▀█ FF65 65381 [39m Load V0→VF; I ← I + 16
[32m204-205 [31m0516-0517 [34m▀▀▀█ █ █ F515 62741 [33m start[39m delay ← V5
[32m206-207 [31m0518-0519 [34m ▀▀▀ ▀ 3900 14592 [33m fizz[39m Skip next if V9 = 000
[32m208-209 [31m0520-0521 [34m █ ▄▀ 1214 04628 [39m Jump to buzz
[32m20A-20B [31m0522-0523 [34m▀▄▀▄ ▄█ A256 41558 [39m I ← fi
[32m20C-20D [31m0524-0525 [34m█▀ █▀▄ █ D995 55701 [39m Draw 08×05 at V9,V9; VF ← XOR
[32m20E-20F [31m0526-0527 [34m▀▄█ ▀ A260 41568 [39m I ← zz
[32m210-211 [31m0528-0529 [34m█▀ █ ▄▀█ D395 54165 [39m Draw 08×05 at V3,V9; VF ← XOR
[32m212-213 [31m0530-0531 [34m ▀▀ ▀██ 6E06 28166 [39m VE ← 006
[32m214-215 [31m0532-0533 [34m ▀▀▀ ▀ 3A00 14848 [33m buzz[39m Skip next if VA = 000
[32m216-217 [31m0534-0535 [34m ▄▀ █ 1222 04642 [39m Jump to n
[32m218-219 [31m0536-0537 [34m▀▄▀▄▄ █▄ A25B 41563 [39m I ← bu
[32m21A-21B [31m0538-0539 [34m██▄▀▀▄▀▄ DAE5 56037 [39m Draw 08×05 at VA,VE; VF ← XOR
[32m21C-21D [31m0540-0541 [34m▀▄█ ▀ A260 41568 [39m I ← zz
[32m21E-21F [31m0542-0543 [34m██▄▀ ▄▀█ D3E5 54245 [39m Draw 08×05 at V3,VE; VF ← XOR
[32m220-221 [31m0544-0545 [34m ▀▀ ▀██ 6E06 28166 [39m VE ← 006
[32m222-223 [31m0546-0547 [34m ▀▀▀▀▀ 3E00 15872 [33m n[39m Skip next if VE = 000
[32m224-225 [31m0548-0549 [34m ▄█▄ ▀ 1238 04664 [39m Jump to finish
[32m226-227 [31m0550-0551 [34m█▄█▄██▀█ AFFD 45053 [39m I ← 4093
[32m228-229 [31m0552-0553 [34m▀▀██▀ ▄▄ F833 63539 [39m V8 as BCD stored from I
[32m22A-22B [31m0554-0555 [34m▀██▀ ▄▀▄ F265 62053 [39m Load V0→V2; I ← I + 03
[32m22C-22D [31m0556-0557 [34m▀▀█▀▄ ▄ F029 61481 [39m I ← digit sprite of V0
[32m22E-22F [31m0558-0559 [34m██▄▀▀█▀▄ DEE5 57061 [39m Draw 08×05 at VE,VE; VF ← XOR
[32m230-231 [31m0560-0561 [34m▀▀█▀▄ █ F129 61737 [39m I ← digit sprite of V1
[32m232-233 [31m0562-0563 [34m██▄▀ ▄▀█ D3E5 54245 [39m Draw 08×05 at V3,VE; VF ← XOR
[32m234-235 [31m0564-0565 [34m▀▀█▀▄ ▀▄ F229 61993 [39m I ← digit sprite of V2
[32m236-237 [31m0566-0567 [34m██▄▀ █ ▄ D4E5 54501 [39m Draw 08×05 at V4,VE; VF ← XOR
[32m238-239 [31m0568-0569 [34m ▀▀▀▀ ▄ 7801 30721 [33m finish[39m V8 ← V8 + 001
[32m23A-23B [31m0570-0571 [34m ▀▀▀▀ █ 7901 30977 [39m V9 ← V9 + 001
[32m23C-23D [31m0572-0573 [34m ▀▀▀▀ ▀▄ 7A01 31233 [39m VA ← VA + 001
[32m23E-23F [31m0574-0575 [34m ▀▀ ▀▀▀ 6E00 28160 [39m VE ← 000
[32m240-241 [31m0576-0577 [34m ▀ ▀ 4800 18432 [39m Skip next if V8 <> 000
[32m242-243 [31m0578-0579 [34m ▄ ▀ █ 1242 04674 [33m end[39m Jump to end
[32m244-245 [31m0580-0581 [34m ▀ ▀ ▄█ 4903 18691 [39m Skip next if V9 <> 003
[32m246-247 [31m0582-0583 [34m ▀▀ ▀ ▀ 6900 26880 [39m V9 ← 000
[32m248-249 [31m0584-0585 [34m ▀ ▀▄▀▄ 4A05 18949 [39m Skip next if VA <> 005
[32m24A-24B [31m0586-0587 [34m ▀▀ ▀ ▀ 6A00 27136 [39m VA ← 000
[32m24C-24D [31m0588-0589 [34m▀▀▀▀ ▄▄▄ F007 61447 [33m delay[39m V0 ← delay
[32m24E-24F [31m0590-0591 [34m ▀▀ 3000 12288 [39m Skip next if V0 = 000
[32m250-251 [31m0592-0593 [34m ▄ ▀▄▄▀ 124C 04684 [39m Jump to delay
[32m252-253 [31m0594-0595 [34m▄▄▄ 00E0 00224 [39m Clear the screen
[32m254-255 [31m0596-0597 [34m ▀ ▄▀ 1204 04612 [39m Jump to start
[32m256 [31m0598 [34m███ ███ EE 238 [33m fi
[32m257 [31m0599 [34m█ █ 84 132
[32m258 [31m0600 [34m██ █ C4 196
[32m259 [31m0601 [34m█ █ 84 132
[32m25A [31m0602 [34m█ ███ 8E 142
[32m25B [31m0603 [34m███ █ █ EA 234 [33m bu
[32m25C [31m0604 [34m█ █ █ █ AA 170
[32m25D [31m0605 [34m██ █ █ CA 202
[32m25E [31m0606 [34m█ █ █ █ AA 170
[32m25F [31m0607 [34m███ ███ EE 238
[32m260 [31m0608 [34m███ ███ EE 238 [33m zz
[32m261 [31m0609 [34m █ █ 22 034
[32m262 [31m0610 [34m █ █ 44 068 [33m from
[32m263 [31m0611 [34m█ █ 88 136
[32m264 [31m0612 [34m███ ███ EE 238
[32m265 [31m0613 [34m █ 08 008
[32m266 [31m0614 [34m █ 10 016
[32m267 [31m0615 [34m ████ 1E 030
The register usage is as follows:
V0 Load from I and then BCD display; manipulating the delay register.
V1 Load from I and then BCD display.
V2 Load from I and then BCD display.
V3 Horizontal positioning of second sprite for display.
V4 Horizontal positioning of third sprite for display.
V5 Hold the delay register delay value.
V6 Unused.
V7 Unused.
V8 Hold the current number for numerical display.
V9 Hold the current number modulo three for fizz display.
Horizontal or vertical positioning of fizz sprites.
VA Hold the current number modulo five for buzz display.
Horizontal positioning of bu sprite.
VB Unused.
VC Unused.
VD Unused.
VE Horizontal or vertical positioning of several sprites.
Flag to indicate number modularity.
VF Unused.
As this program was written by me, it will contain some history of the tool, rather than simply
being a more bare exploration. This is the only fizzbuzz program written in CHIP-8 that I'm aware
of. A goal with this was assuming little about peculiars of the environment and being small.
The registers were chosen for the following reasons:
V0 Ease of access and unimportance.
V1 Ease of access.
V2 Ease of access.
V3 Ease of access.
V4 Ease of access.
V5 Ease of access.
V6 Unused.
V7 Unused.
V8 The V9 and VA were being used and this is contiguous with them.
V9 The V3 was already used and nine is a multiple of three.
VA The V9 was being used and ten is a multiple of five.
VB Unused.
VC Unused.
VD Unused.
VE The VF was to be used, but this was chosen on a whim and away from other values.
VF Unused.
The program begins by loading the first registers to unimportant values; loading registers three,
four, and five to their only values; and loading all remaining registers to zero:
[32m200-201 [31m0512-0513 [34m▀▄█ █ A262 41570 [39m I ← from
[32m202-203 [31m0514-0515 [34m▀██▀▀█▀█ FF65 65381 [39m Load V0→VF; I ← I + 16
The program was originally written to load the delay register and wait at the end of the work, but
adding this single instruction before the work required no effort, sans shifting code by two, and
improves the timing as much as is possible; the delay is half a second:
[32m204-205 [31m0516-0517 [34m▀▀▀█ █ █ F515 62741 [33m start[39m delay ← V5
The fizz case is handled first. If register nine is zero, this case is skipped; if not, the fi and
zz sprites are drawn, using register nine as a zero register, and register fourteen is set to
indicate this and also adjust the drawing of any buzz:
[32m206-207 [31m0518-0519 [34m ▀▀▀ ▀ 3900 14592 [33m fizz[39m Skip next if V9 = 000
[32m208-209 [31m0520-0521 [34m █ ▄▀ 1214 04628 [39m Jump to buzz
[32m20A-20B [31m0522-0523 [34m▀▄▀▄ ▄█ A256 41558 [39m I ← fi
[32m20C-20D [31m0524-0525 [34m█▀ █▀▄ █ D995 55701 [39m Draw 08×05 at V9,V9; VF ← XOR
[32m20E-20F [31m0526-0527 [34m▀▄█ ▀ A260 41568 [39m I ← zz
[32m210-211 [31m0528-0529 [34m█▀ █ ▄▀█ D395 54165 [39m Draw 08×05 at V3,V9; VF ← XOR
[32m212-213 [31m0530-0531 [34m ▀▀ ▀██ 6E06 28166 [39m VE ← 006
The buzz case is handled next. If register ten is zero, this case is skipped; if not, the bu and zz
sprites are drawn, using register ten as a zero register, and using register fourteen for vertical
positioning below any potential fizz sprites. Register fourteen is then set, regardless:
[32m214-215 [31m0532-0533 [34m ▀▀▀ ▀ 3A00 14848 [33m buzz[39m Skip next if VA = 000
[32m216-217 [31m0534-0535 [34m ▄▀ █ 1222 04642 [39m Jump to n
[32m218-219 [31m0536-0537 [34m▀▄▀▄▄ █▄ A25B 41563 [39m I ← bu
[32m21A-21B [31m0538-0539 [34m██▄▀▀▄▀▄ DAE5 56037 [39m Draw 08×05 at VA,VE; VF ← XOR
[32m21C-21D [31m0540-0541 [34m▀▄█ ▀ A260 41568 [39m I ← zz
[32m21E-21F [31m0542-0543 [34m██▄▀ ▄▀█ D3E5 54245 [39m Draw 08×05 at V3,VE; VF ← XOR
[32m220-221 [31m0544-0545 [34m ▀▀ ▀██ 6E06 28166 [39m VE ← 006
The last case is that of drawing the number, which only occurs if register fourteen is zero; if not,
I is set to write the three decimal digits to the very end of the memory space using register eight,
the first three registers are loaded with this, and that is then used for display, using register
fourteen as a zero register. Note that the program reuses the offsets for the other sprites; this
is done to save space and still looks nice:
[32m222-223 [31m0546-0547 [34m ▀▀▀▀▀ 3E00 15872 [33m n[39m Skip next if VE = 000
[32m224-225 [31m0548-0549 [34m ▄█▄ ▀ 1238 04664 [39m Jump to finish
[32m226-227 [31m0550-0551 [34m█▄█▄██▀█ AFFD 45053 [39m I ← 4093
[32m228-229 [31m0552-0553 [34m▀▀██▀ ▄▄ F833 63539 [39m V8 as BCD stored from I
[32m22A-22B [31m0554-0555 [34m▀██▀ ▄▀▄ F265 62053 [39m Load V0→V2; I ← I + 03
[32m22C-22D [31m0556-0557 [34m▀▀█▀▄ ▄ F029 61481 [39m I ← digit sprite of V0
[32m22E-22F [31m0558-0559 [34m██▄▀▀█▀▄ DEE5 57061 [39m Draw 08×05 at VE,VE; VF ← XOR
[32m230-231 [31m0560-0561 [34m▀▀█▀▄ █ F129 61737 [39m I ← digit sprite of V1
[32m232-233 [31m0562-0563 [34m██▄▀ ▄▀█ D3E5 54245 [39m Draw 08×05 at V3,VE; VF ← XOR
[32m234-235 [31m0564-0565 [34m▀▀█▀▄ ▀▄ F229 61993 [39m I ← digit sprite of V2
[32m236-237 [31m0566-0567 [34m██▄▀ █ ▄ D4E5 54501 [39m Draw 08×05 at V4,VE; VF ← XOR
Registers eight, nine, ten, and fourteen are then set to their new values:
[32m238-239 [31m0568-0569 [34m ▀▀▀▀ ▄ 7801 30721 [33m finish[39m V8 ← V8 + 001
[32m23A-23B [31m0570-0571 [34m ▀▀▀▀ █ 7901 30977 [39m V9 ← V9 + 001
[32m23C-23D [31m0572-0573 [34m ▀▀▀▀ ▀▄ 7A01 31233 [39m VA ← VA + 001
[32m23E-23F [31m0574-0575 [34m ▀▀ ▀▀▀ 6E00 28160 [39m VE ← 000
If a full looping of the count has occured, the program ends; note that it would be possible to have
the program instead loop indefinitely by simply changing the byte at location 243 to zero. As the
program doesn't assume register values or anything of such a sort, it can restart in this way.
[32m240-241 [31m0576-0577 [34m ▀ ▀ 4800 18432 [39m Skip next if V8 <> 000
[32m242-243 [31m0578-0579 [34m ▄ ▀ █ 1242 04674 [33m end[39m Jump to end
The remainder of the count for moduli three and five is then computed and assigned:
[32m244-245 [31m0580-0581 [34m ▀ ▀ ▄█ 4903 18691 [39m Skip next if V9 <> 003
[32m246-247 [31m0582-0583 [34m ▀▀ ▀ ▀ 6900 26880 [39m V9 ← 000
[32m248-249 [31m0584-0585 [34m ▀ ▀▄▀▄ 4A05 18949 [39m Skip next if VA <> 005
[32m24A-24B [31m0586-0587 [34m ▀▀ ▀ ▀ 6A00 27136 [39m VA ← 000
Lastly the remaining delay, if any, is exhausted before the screen is cleared and the next iteration
is performed:
[32m24C-24D [31m0588-0589 [34m▀▀▀▀ ▄▄▄ F007 61447 [33m delay[39m V0 ← delay
[32m24E-24F [31m0590-0591 [34m ▀▀ 3000 12288 [39m Skip next if V0 = 000
[32m250-251 [31m0592-0593 [34m ▄ ▀▄▄▀ 124C 04684 [39m Jump to delay
[32m252-253 [31m0594-0595 [34m▄▄▄ 00E0 00224 [39m Clear the screen
[32m254-255 [31m0596-0597 [34m ▀ ▄▀ 1204 04612 [39m Jump to start
The program ends with the sprites for fi, bu, and zz, followed by the three important values
assigned to registers three, four, and five. As the first three registers are assigned no important
values from here, they are filled with part of the zz sprite:
[32m256 [31m0598 [34m███ ███ EE 238 [33m fi
[32m257 [31m0599 [34m█ █ 84 132
[32m258 [31m0600 [34m██ █ C4 196
[32m259 [31m0601 [34m█ █ 84 132
[32m25A [31m0602 [34m█ ███ 8E 142
[32m25B [31m0603 [34m███ █ █ EA 234 [33m bu
[32m25C [31m0604 [34m█ █ █ █ AA 170
[32m25D [31m0605 [34m██ █ █ CA 202
[32m25E [31m0606 [34m█ █ █ █ AA 170
[32m25F [31m0607 [34m███ ███ EE 238
[32m260 [31m0608 [34m███ ███ EE 238 [33m zz
[32m261 [31m0609 [34m █ █ 22 034
[32m262 [31m0610 [34m █ █ 44 068 [33m from
[32m263 [31m0611 [34m█ █ 88 136
[32m264 [31m0612 [34m███ ███ EE 238
[32m265 [31m0613 [34m █ 08 008
[32m266 [31m0614 [34m █ 10 016
[32m267 [31m0615 [34m ████ 1E 030[39m
It was originally figured that an adjustable delay would be implemented, for interactivity, but this
wasn't done once size become a greater issue. Also note that the middle of the screen was to be
used for display, but using location 0,0 was not only easier and looked nice but also permitted
greater reuse of coordinates among sprites, as did displaying fizzbuzz vertically rather than
horizontally. The program was originally to reuse a coordinate for the delay, but this delay was
16/60 of a second and the program was 103 bytes; to improve the delay and pad to an even number, an
explicit delay was used.