A Documenting of my Rule 30 Improved CHIP-8 Program This is a documenting of the Rule 30, Improved, program I've written. If you've not read my article documenting the Rule 30 program, 2019-08-18, then I suggest you do so. This program was written for the Octo Jam VI event and is a rewrite and heavy improvement of the previous program. As with those other programs of mine, only the fully annotated view will be shown here and so follows is a view of the program when it is first loaded into the tool: 200-201 0512-0513 ▄▄▄▄▄▄▄▄ 00FF 00255 Enable extended mode 202-203 0514-0515 ▄▄▄ 00E0 00224 Clear the screen 204-205 0516-0517 █ █ ████ AFAF 44975 I ← 4015 206-207 0518-0519 ▀██▀▀█▀█ FF65 65381 Load V0→VF; I ← I + 16 208-209 0520-0521 ▀█▀█▀█▀█ FF55 65365 Save V0→VF; I ← I + 16 20A-20B 0522-0523 ▀█▀█▀█▀█ FF55 65365 Save V0→VF; I ← I + 16 20C-20D 0524-0525 ▀█▀█▀█▀█ FF55 65365 Save V0→VF; I ← I + 16 20E-20F 0526-0527 ▀█▀█▀█▀█ FF55 65365 Save V0→VF; I ← I + 16 210-211 0528-0529 ▀▀ 6000 24576 V0 ← 000 212-213 0530-0531 ▀█▀█ ▄ ▄ F055 61525 Save V0→V0; I ← I + 01 214-215 0532-0533 █ ▀▄ ▄▀▄ A295 41621 I ← from 216-217 0534-0535 ▀██▀▀█▀█ FF65 65381 Load V0→VF; I ← I + 16 218-219 0536-0537 ▀ █ ▄ ▀ A228 41512 entry I ← bar 21A-21B 0538-0539 ██▄▀▀ ▀█ DBE1 56289 Draw 08×01 at VB,VE; VF ← XOR 21C-21D 0540-0541 ▀▀▀▀▄ ▄ F00A 61450 key V0 ← key 21E-21F 0542-0543 ▀ █ ▄ ▀ A228 41512 I ← bar 220-221 0544-0545 ██▄▀▀ ▀█ DBE1 56289 Draw 08×01 at VB,VE; VF ← XOR 222-223 0546-0547 ▀ ▄▄▄▄ 400F 16399 Skip next if V0 <> 015 224-225 0548-0549 ▄ █ ▄▀ 1254 04692 Jump to phase 226-227 0550-0551 ▀ ▄ 4008 16392 Skip next if V0 <> 008 228-229 0552-0553 ▀▀▀▀▀▀▄ 7E01 32257 bar VE ← VE + 001 22A-22B 0554-0555 ▀ ▄ 4002 16386 Skip next if V0 <> 002 22C-22D 0556-0557 ▄██████▄ 7EFF 32511 VE ← VE + 255 22E-22F 0558-0559 ▀ ▄▀▀█ 8E12 36370 VE ← VE AND V1 230-231 0560-0561 ██▄▀▀ ▀█ DBE1 56289 Draw 08×01 at VB,VE; VF ← XOR 232-233 0562-0563 ▀▀ ▄ ▄ 3005 12293 Skip next if V0 = 005 234-235 0564-0565 █▄▄▀ 121C 04636 Jump to key 236-237 0566-0567 ▄▀ ▄▄█ 224E 08782 Call index 238-239 0568-0569 ▀██▀ ▄ ▄ F065 61541 Load V0→V0; I ← I + 01 23A-23B 0570-0571 ▄▀ ▄▄█ 224E 08782 Call index 23C-23D 0572-0573 ██▄▀▀ ▀█ DBE1 56289 Draw 08×01 at VB,VE; VF ← XOR 23E-23F 0574-0575 ▀ ▄ ▄▄ 8023 32803 V0 ← V0 XOR V2 240-241 0576-0577 ▄▀ ▄ ▀ 2248 08776 Call save 242-243 0578-0579 ▄▀ ▄▄█ 224E 08782 Call index 244-245 0580-0581 ██▄▀▀ ▀█ DBE1 56289 Draw 08×01 at VB,VE; VF ← XOR 246-247 0582-0583 █▄▄▀ 121C 04636 Jump to key 248-249 0584-0585 ▄▀ ▄▄█ 224E 08782 save Call index 24A-24B 0586-0587 ▀█▀█ ▄ ▄ F055 61525 Save V0→V0; I ← I + 01 24C-24D 0588-0589 ▄▄▄ ▄▄▄ 00EE 00238 Return 24E-24F 0590-0591 █ █▄████ AFBF 44991 index I ← 4031 250-251 0592-0593 ▀▀▀████ FE1E 65054 I ← I + VE 252-253 0594-0595 ▄▄▄ ▄▄▄ 00EE 00238 Return 254-255 0596-0597 █▄▄ ▀▀ ▀ 8DE0 36320 phase VD ← VE 256-257 0598-0599 ▄▄▄▄▄ ▄▄ 00FB 00251 scroll Scroll → by 04 258-259 0600-0601 ▀▀▀█▀█ █ FD15 64789 automata delay ← VD 25A-25B 0602-0603 ▀▀ ▀▀ 6C00 27648 VC ← 000 25C-25D 0604-0605 ▀▀ ▀▀▀ 6E00 28160 VE ← 000 25E-25F 0606-0607 ▄███▄▄█▄ 72FF 29439 V2 ← V2 + 255 260-261 0608-0609 ▀ ▄▄ █ 8232 33330 V2 ← V2 AND V3 262-263 0610-0611 ▄▀ ▄▄█ 224E 08782 prime Call index 264-265 0612-0613 ▀██▀ ▄ █ F165 61797 Load V0→V1; I ← I + 02 266-267 0614-0615 ▀ ▀▀▀▀ 8F00 36608 begin rule 30 VF ← V0 268-269 0616-0617 ▀ ▄ ▄ 8011 32785 V0 ← V0 OR V1 26A-26B 0618-0619 █▄ ▄▄ 80C3 32963 V0 ← V0 XOR VC 26C-26D 0620-0621 █▄▄▄▀▀ 8CF0 36080 end rule 30 VC ← VF 26E-26F 0622-0623 ▄▀ ▄ ▀ 2248 08776 Call save 270-271 0624-0625 ▀▀▀▀▀▀▄ 7E01 32257 VE ← VE + 001 272-273 0626-0627 ▄▀▀▀▀▀ 3E40 15936 Skip next if VE = 064 274-275 0628-0629 ▄▄▀ █ 1262 04706 Jump to prime 276-277 0630-0631 ▀▀ ▀▀▀ 6E00 28160 VE ← 000 278-279 0632-0633 ▄▀ ▄▄█ 224E 08782 draw Call index 27A-27B 0634-0635 ██▄▀▄▄█▄ D2EF 53999 Draw 08×15 at V2,VE; VF ← XOR 27C-27D 0636-0637 ▀▀▀███▄ 7E0F 32271 VE ← VE + 015 27E-27F 0638-0639 ████▀ 3E3C 15932 Skip next if VE = 060 280-281 0640-0641 ▄▄█▄ ▀ 1278 04728 Jump to draw 282-283 0642-0643 ▄▀ ▄▄█ 224E 08782 Call index 284-285 0644-0645 ██▄▀ ▄▀ D2E4 53988 Draw 08×04 at V2,VE; VF ← XOR 286-287 0646-0647 ▀▀▀▀▀███ FF07 65287 delay VF ← delay 288-289 0648-0649 █▀█ ▀ ▄ E4A1 58529 Skip next if V4 <> key 28A-28B 0650-0651 ▀ ▀ 1200 04608 Jump to 0512 28C-28D 0652-0653 ▀▀▀▀▀▀ 3F00 16128 Skip next if VF = 000 28E-28F 0654-0655 ▄ ▀ ▄█ 1286 04742 Jump to delay 290-291 0656-0657 ▀▀ ▀ 3200 12800 Skip next if V2 = 000 292-293 0658-0659 ▄ █▄ ▀ 1258 04696 Jump to automata 294-295 0660-0661 ▄ █ ▄█ 1256 04694! from Jump to scroll 296 0662 ██████ 3F 063 297 0663 █ 80 128 298 0664 ██ 03 003 299 0665 ███ 0E 014 The register usage is as follows; this omits usage of all registers at the beginning of the program: V0 Set the right pattern boundary; store a key; cell manipulation. V1 Cell manipulation; hold a boundary. V2 Hold a constant for cell manipulation; horizontal positioning of most drawing. V3 Hold a boundary V4 Hold a key code. V5 Unused. V6 Unused. V7 Unused. V8 Unused. V9 Unused. VA Unused. VB A zero source for horizontal positioning of some drawing. VC Store a previous cell. VD Manipulating the delay register VE Vertical positioning of all drawing. VF Store a temporary result; manipulating the delay register. As I'm the author of this program, I will discuss the history of it to a point, as opposed to a more bare examination. This and the previous are the only Rule 30 programs in CHIP-8 I'm aware of. This program was written with concerns other than a minimal size, although it's still rather small; to be efficient in drawing, as the opportunity for this is rare; and to make modification of those pattern boundaries simple. The registers were chosen for the following reasons: V0 Ease of access. V1 Ease of access. V2 Ease of access. V3 Ease of access. V4 Ease of access. V5 Unused. V6 Unused. V7 Unused. V8 Unused. V9 Unused. VA Unused. VB Unimportance and distance from lower registers. VC Unimportance and distance from lower registers. VD Unimportance and distance from lower registers. VE Unimportance and distance from lower registers; sprite happenstance. VF Unimportance and distance from lower registers. This program begins by entering Super CHIP-8 mode, clearing the screen, overwriting those sixty-five final bytes of memory with zeroes by loading all registers with memory obtained directly beforehand, and then initializing all registers from the end of the program. Note that the 6000 instruction may be modified to affect the right boundary of the pattern space; note that this adds four bytes to the program's size, as that memory can safely remain untouched, otherwise: 200-201 0512-0513 ▄▄▄▄▄▄▄▄ 00FF 00255 Enable extended mode 202-203 0514-0515 ▄▄▄ 00E0 00224 Clear the screen 204-205 0516-0517 █ █ ████ AFAF 44975 I ← 4015 206-207 0518-0519 ▀██▀▀█▀█ FF65 65381 Load V0→VF; I ← I + 16 208-209 0520-0521 ▀█▀█▀█▀█ FF55 65365 Save V0→VF; I ← I + 16 20A-20B 0522-0523 ▀█▀█▀█▀█ FF55 65365 Save V0→VF; I ← I + 16 20C-20D 0524-0525 ▀█▀█▀█▀█ FF55 65365 Save V0→VF; I ← I + 16 20E-20F 0526-0527 ▀█▀█▀█▀█ FF55 65365 Save V0→VF; I ← I + 16 210-211 0528-0529 ▀▀ 6000 24576 V0 ← 000 212-213 0530-0531 ▀█▀█ ▄ ▄ F055 61525 Save V0→V0; I ← I + 01 214-215 0532-0533 █ ▀▄ ▄▀▄ A295 41621 I ← from 216-217 0534-0535 ▀██▀▀█▀█ FF65 65381 Load V0→VF; I ← I + 16 The program displays the bar sprite at location 0,0; waits for a key; and afterwards erases the bar: 218-219 0536-0537 ▀ █ ▄ ▀ A228 41512 entry I ← bar 21A-21B 0538-0539 ██▄▀▀ ▀█ DBE1 56289 Draw 08×01 at VB,VE; VF ← XOR 21C-21D 0540-0541 ▀▀▀▀▄ ▄ F00A 61450 key V0 ← key 21E-21F 0542-0543 ▀ █ ▄ ▀ A228 41512 I ← bar 220-221 0544-0545 ██▄▀▀ ▀█ DBE1 56289 Draw 08×01 at VB,VE; VF ← XOR The next phase of the program is entered, if key fifteen has been pressed; otherwise, the bar sprite is moved up or down for keys two and eight, respectively, and the screen boundary is respected by an AND which provides wrap-around behavior. The bar is then redrawn; note that it is drawn and redrawn even in cases where it's not been moved; note that the bar sprite is taken from an instruction here, which is part of the reason register fourteen was used for this: 222-223 0546-0547 ▀ ▄▄▄▄ 400F 16399 Skip next if V0 <> 015 224-225 0548-0549 ▄ █ ▄▀ 1254 04692 Jump to phase 226-227 0550-0551 ▀ ▄ 4008 16392 Skip next if V0 <> 008 228-229 0552-0553 ▀▀▀▀▀▀▄ 7E01 32257 bar VE ← VE + 001 22A-22B 0554-0555 ▀ ▄ 4002 16386 Skip next if V0 <> 002 22C-22D 0556-0557 ▄██████▄ 7EFF 32511 VE ← VE + 255 22E-22F 0558-0559 ▀ ▄▀▀█ 8E12 36370 VE ← VE AND V1 230-231 0560-0561 ██▄▀▀ ▀█ DBE1 56289 Draw 08×01 at VB,VE; VF ← XOR The pattern toggle code is entered when key five has been pressed; otherwise, control returns to key collection. The index routine is called; the contents of the pattern array are loaded into register zero; the index routine is called again, due to implicit I movement; the pattern contents, which are zero or 2**7, are displayed once to erase them if necessary. The pattern is then toggled by XOR and the save routine is entered; index is called once more; and then the current pattern value is shown. After this, key collection resumes. Note that the pattern is displayed twice, as this is the method to ensure a live sprite is erased by itself before nothing is drawn; the other case poses no issues: 232-233 0562-0563 ▀▀ ▄ ▄ 3005 12293 Skip next if V0 = 005 234-235 0564-0565 █▄▄▀ 121C 04636 Jump to key 236-237 0566-0567 ▄▀ ▄▄█ 224E 08782 Call index 238-239 0568-0569 ▀██▀ ▄ ▄ F065 61541 Load V0→V0; I ← I + 01 23A-23B 0570-0571 ▄▀ ▄▄█ 224E 08782 Call index 23C-23D 0572-0573 ██▄▀▀ ▀█ DBE1 56289 Draw 08×01 at VB,VE; VF ← XOR 23E-23F 0574-0575 ▀ ▄ ▄▄ 8023 32803 V0 ← V0 XOR V2 240-241 0576-0577 ▄▀ ▄ ▀ 2248 08776 Call save 242-243 0578-0579 ▄▀ ▄▄█ 224E 08782 Call index 244-245 0580-0581 ██▄▀▀ ▀█ DBE1 56289 Draw 08×01 at VB,VE; VF ← XOR 246-247 0582-0583 █▄▄▀ 121C 04636 Jump to key For size efficiency, the save and index routines exist. The save routine calls index and then saves register zero to the resulting location. The index routine merely positions I according to register fourteen; there is no name for address 4031, as this is the last valid location for it to begin, and so there will never be a need to move it: 248-249 0584-0585 ▄▀ ▄▄█ 224E 08782 save Call index 24A-24B 0586-0587 ▀█▀█ ▄ ▄ F055 61525 Save V0→V0; I ← I + 01 24C-24D 0588-0589 ▄▄▄ ▄▄▄ 00EE 00238 Return 24E-24F 0590-0591 █ █▄████ AFBF 44991 index I ← 4031 250-251 0592-0593 ▀▀▀████ FE1E 65054 I ← I + VE 252-253 0594-0595 ▄▄▄ ▄▄▄ 00EE 00238 Return The next phase of the program assigns the vertical coordinate of the bar sprite to register thirteen to act as the delay; the bar isn't displayed at this point in the program and the speed maps cleanly to height due to larger vertical coordinates being lower being longer delays. The screen is shifted to the right by four and the next main routine is entered by beginning the delay; register twelve is used to represent the left boundary of the pattern space and then later the leftmost cell. Register fourteen is initialized to zero; register two is set to the next horizontal coordinate; the usage of register two is interesting, as I wanted to take advantage of the binary cycling of zero to three and so sought to avoid a conditional setting of the horizontal coordinate register; mistakenly I used register two, at first thinking I would need initialize a register to four for the purpose; I noticed that 2**7-1 AND 3 would provide the desired cycle of three, two, one, and zero and so gladly I used this register for the purpose and avoided storing another byte: 254-255 0596-0597 █▄▄ ▀▀ ▀ 8DE0 36320 phase VD ← VE 256-257 0598-0599 ▄▄▄▄▄ ▄▄ 00FB 00251 scroll Scroll → by 04 258-259 0600-0601 ▀▀▀█▀█ █ FD15 64789 automata delay ← VD 25A-25B 0602-0603 ▀▀ ▀▀ 6C00 27648 VC ← 000 25C-25D 0604-0605 ▀▀ ▀▀▀ 6E00 28160 VE ← 000 25E-25F 0606-0607 ▄███▄▄█▄ 72FF 29439 V2 ← V2 + 255 260-261 0608-0609 ▀ ▄▄ █ 8232 33330 V2 ← V2 AND V3 Index is called, the rightmost two cells loaded, and the Rule 30 algorithm begins. Register fifteen stores the future leftmost cell, the new cell is calculated by V0 OR V1 XOR VC, and the new leftmost cell is stored for the next iteration. The new cell is then saved: 262-263 0610-0611 ▄▀ ▄▄█ 224E 08782 prime Call index 264-265 0612-0613 ▀██▀ ▄ █ F165 61797 Load V0→V1; I ← I + 02 266-267 0614-0615 ▀ ▀▀▀▀ 8F00 36608 begin rule 30 VF ← V0 268-269 0616-0617 ▀ ▄ ▄ 8011 32785 V0 ← V0 OR V1 26A-26B 0618-0619 █▄ ▄▄ 80C3 32963 V0 ← V0 XOR VC 26C-26D 0620-0621 █▄▄▄▀▀ 8CF0 36080 end rule 30 VC ← VF 26E-26F 0622-0623 ▄▀ ▄ ▀ 2248 08776 Call save Register fourteen is incremented and the program loops until all new cells are calculated: 270-271 0624-0625 ▀▀▀▀▀▀▄ 7E01 32257 VE ← VE + 001 272-273 0626-0627 ▄▀▀▀▀▀ 3E40 15936 Skip next if VE = 064 274-275 0628-0629 ▄▄▀ █ 1262 04706 Jump to prime Drawing begins; register fourteen is reinitialized to zero, index is called, and an eight-by-fifteen sprite is drawn four times, in a loop which draws the firsty sixty cells of the pattern. Drawing is more efficient with eight eight-by-eight sprites, rather than this four eight-by-fifteen followed by one eight-by-four, but this is more efficient and such an opportunity is rarely applicable. This is another set of four bytes that is unnecessary but was chosen due to size not being the only concern: 276-277 0630-0631 ▀▀ ▀▀▀ 6E00 28160 VE ← 000 278-279 0632-0633 ▄▀ ▄▄█ 224E 08782 draw Call index 27A-27B 0634-0635 ██▄▀▄▄█▄ D2EF 53999 Draw 08×15 at V2,VE; VF ← XOR 27C-27D 0636-0637 ▀▀▀███▄ 7E0F 32271 VE ← VE + 015 27E-27F 0638-0639 ████▀ 3E3C 15932 Skip next if VE = 060 280-281 0640-0641 ▄▄█▄ ▀ 1278 04728 Jump to draw 282-283 0642-0643 ▄▀ ▄▄█ 224E 08782 Call index 284-285 0644-0645 ██▄▀ ▄▀ D2E4 53988 Draw 08×04 at V2,VE; VF ← XOR Finally, the delay is exhuasted and interleaved with checking four key fourteen to end the automata; key fourteen is unnecessary as I was going to use register three's value of three, but was chosen to pad to an even size and originally to use key fifteen, to be similar to the pattern entry, but I had troubles with a CHIP-8 implementation and how it registered key presses, so using a different key is the best way to solve that issue and avoid unintended multiple presses. An advantage of my desiring to avoid depending on initial register values of zero is that the program is more easily re-entered. When the delay is exhausted, the automata routine is entered again or, after four iterations, scroll is entered: 286-287 0646-0647 ▀▀▀▀▀███ FF07 65287 delay VF ← delay 288-289 0648-0649 █▀█ ▀ ▄ E4A1 58529 Skip next if V4 <> key 28A-28B 0650-0651 ▀ ▀ 1200 04608 Jump to 0512 28C-28D 0652-0653 ▀▀▀▀▀▀ 3F00 16128 Skip next if VF = 000 28E-28F 0654-0655 ▄ ▀ ▄█ 1286 04742 Jump to delay 290-291 0656-0657 ▀▀ ▀ 3200 12800 Skip next if V2 = 000 292-293 0658-0659 ▄ █▄ ▀ 1258 04696 Jump to automata 294-295 0660-0661 ▄ █ ▄█ 1256 04694! from Jump to scroll Those reading this in a terminal with color note that the code for orange is subtly incorrect. Many terminal emulators don't properly parse these extended colors and this failure of such a basic thing is disgusting to me, but one should expect this from incompetent and foolish programmers; they don't read even the standards they claim to implement, yet then insist on continued incorrect behavior for backwards compatibility. I read and follow relevant standards, and yet I may be less of a bother in some cases, as such programmers tend to have pet standards they will ironically defend to no ending. This program ends with the continuation of the from name, 661, for those initial values of registers one through four: 296 0662 ██████ 3F 063 297 0663 █ 80 128 298 0664 ██ 03 003 299 0665 ███ 0E 014 .