Here is the program itself and the program metadata.
Both of 30i.chip8 and 30i.mmc are available under the CC0 Public Domain Dedication.
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:
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:
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 27, 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 27-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
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