Index  Comments

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:

  1. V0 Set the right pattern boundary; store a key; cell manipulation.
  2. V1 Cell manipulation; hold a boundary.
  3. V2 Hold a constant for cell manipulation; horizontal positioning of most drawing.
  4. V3 Hold a boundary
  5. V4 Hold a key code.
  6. V5 Unused.
  7. V6 Unused.
  8. V7 Unused.
  9. V8 Unused.
  10. V9 Unused.
  11. VA Unused.
  12. VB A zero source for horizontal positioning of some drawing.
  13. VC Store a previous cell.
  14. VD Manipulating the delay register
  15. VE Vertical positioning of all drawing.
  16. 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:

  1. V0 Ease of access.
  2. V1 Ease of access.
  3. V2 Ease of access.
  4. V3 Ease of access.
  5. V4 Ease of access.
  6. V5 Unused.
  7. V6 Unused.
  8. V7 Unused.
  9. V8 Unused.
  10. V9 Unused.
  11. VA Unused.
  12. VB Unimportance and distance from lower registers.
  13. VC Unimportance and distance from lower registers.
  14. VD Unimportance and distance from lower registers.
  15. VE Unimportance and distance from lower registers; sprite happenstance.
  16. 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 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