Index

Here is the program itself and the program metadata.

Both of 30.chip8 and 30.mmc are available under the CC0 Public Domain Dedication.

This is documentation for the Rule 30 program I've written. Wanting to use my MMC more and waiting no longer for the sixth OctoJam event, I decided it was past time to write another program and I'll simply improve this program for the event. As with my other programs, 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 █ ▀  ▄█▄ A287 41607           begin I ← from
204-205 0516-0517 ▀██▀▀█▀▄ FE65 65125             bar Load V0→VE; I ← I + 15
206-207 0518-0519 ▀ ▀  ▄▀  A204 41476                 I ← bar
208-209 0520-0521 ██▄▀  ▀▄ D2E1 53985                 Draw 08×01 at V2,VE; VF ← XOR
20A-20B 0522-0523 ▀▀▀▀█▀▄▀ FD0A 64778           input VD ← key
20C-20D 0524-0525 ▀ ▀  ▄▀  A204 41476                 I ← bar
20E-20F 0526-0527 ██▄▀  ▀▄ D2E1 53985                 Draw 08×01 at V2,VE; VF ← XOR
210-211 0528-0529  ▀  ▀▀▄▀ 4D02 19714                 Skip next if VD <> 002
212-213 0530-0531 ▄██████▄ 7EFF 32511                 VE ← VE + 255
214-215 0532-0533  ▀  █▀ ▀ 4D08 19720                 Skip next if VD <> 008
216-217 0534-0535  ▀▀▀▀▀▀▄ 7E01 32257                 VE ← VE + 001
218-219 0536-0537 ▀  ▄▀▀█  8E12 36370                 VE ← VE AND V1
21A-21B 0538-0539  ▀  ██▄█ 4D0F 19727                 Skip next if VD <> 015
21C-21D 0540-0541   ▄█▄▄▀  123C 04668                 Jump to automata
21E-21F 0542-0543 ██▄▀  ▀▄ D2E1 53985                 Draw 08×01 at V2,VE; VF ← XOR
220-221 0544-0545   ▀▀▀█ █ 3D05 15621                 Skip next if VD = 005
222-223 0546-0547    ▀▄ █  120A 04618                 Jump to input
224-225 0548-0549 █ █▄████ AFBF 44991                 I ← 4031
226-227 0550-0551 ▀▀▀████  FE1E 65054                 I ← I + VE
228-229 0552-0553 ▀██▀ ▄ ▄ F065 61541                 Load V0→V0; I ← I + 01
22A-22B 0554-0555 █ █▄████ AFBF 44991                 I ← 4031
22C-22D 0556-0557 ▀▀▀████  FE1E 65054                 I ← I + VE
22E-22F 0558-0559 ██▄▀  ▀▄ D2E1 53985                 Draw 08×01 at V2,VE; VF ← XOR
230-231 0560-0561 ▀▄    ▄▄ 8043 32835                 V0 ← V0 XOR V4
232-233 0562-0563 ▀█▀█ ▄ ▄ F055 61525                 Save V0→V0; I ← I + 01
234-235 0564-0565 █ █▄████ AFBF 44991                 I ← 4031
236-237 0566-0567 ▀▀▀████  FE1E 65054                 I ← I + VE
238-239 0568-0569 ██▄▀  ▀▄ D2E1 53985                 Draw 08×01 at V2,VE; VF ← XOR
23A-23B 0570-0571    ▀▄ █  120A 04618                 Jump to input
23C-23D 0572-0573 ▀▀▀█ ▄▀█ F315 62229        automata delay ← V3
23E-23F 0574-0575 ▄██▄███▄ 6EFF 28415                 VE ← 255
240-241 0576-0577  ▀▀ ▀▀   6C00 27648                 VC ← 000
242-243 0578-0579  ▀▀▀  ▀▄ 7201 29185                 V2 ← V2 + 001
244-245 0580-0581  █▄▄▄ ▀  4278 17016                 Skip next if V2 <> 120
246-247 0582-0583 ▄███▄▄▀  72FC 29436                 V2 ← V2 + 252
248-249 0584-0585  ▀▀▀▀▀▀▄ 7E01 32257           prime VE ← VE + 001
24A-24B 0586-0587 █ █▄████ AFBF 44991                 I ← 4031
24C-24D 0588-0589 ▀▀▀████  FE1E 65054                 I ← I + VE
24E-24F 0590-0591 ▀██▀ ▄ █ F165 61797                 Load V0→V1; I ← I + 02
250-251 0592-0593 ▀   ▀▀▀▀ 8F00 36608  rule 30 begins VF ← V0
252-253 0594-0595 ▀  ▄   ▄ 8011 32785                 V0 ← V0 OR V1
254-255 0596-0597 █▄    ▄▄ 80C3 32963                 V0 ← V0 XOR VC
256-257 0598-0599 █▄▄▄▀▀   8CF0 36080    rule 30 ends VC ← VF
258-259 0600-0601 █ █▄████ AFBF 44991                 I ← 4031
25A-25B 0602-0603 ▀▀▀████  FE1E 65054                 I ← I + VE
25C-25D 0604-0605 ▀█▀█ ▄ ▄ F055 61525                 Save V0→V0; I ← I + 01
25E-25F 0606-0607  ▄▀▀▀▀▀  3E40 15936                 Skip next if VE = 064
260-261 0608-0609  ▄ ▀▄ ▀  1248 04680                 Jump to prime
262-263 0610-0611  ▀▀ ▀▀▀  6E00 28160                 VE ← 000
264-265 0612-0613 █ █▄████ AFBF 44991            draw I ← 4031
266-267 0614-0615 ▀▀▀████  FE1E 65054                 I ← I + VE
268-269 0616-0617 ██▄▀▄▄█▄ D2EF 53999                 Draw 08×15 at V2,VE; VF ← XOR
26A-26B 0618-0619  ▀▀▀███▄ 7E0F 32271                 VE ← VE + 015
26C-26D 0620-0621   ████▀  3E3C 15932                 Skip next if VE = 060
26E-26F 0622-0623  ▄▄▀ ▄▀  1264 04708                 Jump to draw
270-271 0624-0625 █▄█▄█▀██ AFFB 45051                 I ← 4091
272-273 0626-0627 ██▄▀ ▄▀  D2E4 53988                 Draw 08×04 at V2,VE; VF ← XOR
274-275 0628-0629 ▀▀▀▀▀███ FF07 65287           delay VF ← delay
276-277 0630-0631 █▀█  ▀ ▄ E4A1 58529                 Skip next if V4 <> key
278-279 0632-0633 ▄▄▄▄▄▄ ▄ 00FD 00253                 Exit program
27A-27B 0634-0635   ▀▀▀▀▀▀ 3F00 16128                 Skip next if VF = 000
27C-27D 0636-0637  ▄▄█ ▄▀  1274 04724                 Jump to delay
27E-27F 0638-0639  █▄▄ ▄█▄ 4277 17015                 Skip next if V2 <> 119
280-281 0640-0641 ▄▄▄▄▄▄   00FC 00252                 Scroll ← by 04
282-283 0642-0643   ▄█▄▄▀  123C 04668                 Jump to automata
284-285 0644-0645 ▄▄▄      00E0 00224         restart Clear the screen
286-287 0646-0647    ▀  █  1202 04610!           from Jump to begin
288     0648        ██████   3F   063
289     0649       ███ █     74   116
28A     0650          █ █    0A   010
28B     0651             █   01   001

The register usage is as follows:

  1. V0 Cell manipulation.
  2. V1 Cell manipulation; hold a boundary.
  3. V2 Horizontal positioning of all drawing.
  4. V3 Hold the delay register delay value.
  5. V4 Hold a constant for cell manipulation and a key code.
  6. V5 Unused.
  7. V6 Unused.
  8. V7 Unused.
  9. V8 Unused.
  10. V9 Unused.
  11. VA Unused.
  12. VB Unused.
  13. VC Store a previous cell.
  14. VD Store a key.
  15. VE Vertical positioning of all drawing.
  16. VF Store a temporary result.

As this program was written by me, I will discuss the history of the program to a point, as opposed to being a more bare examination. This is the only Rule 30 program written in CHIP-8 I'm aware of. One goal of this program was being small and making novel use of some CHIP-8 particulars.

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 Unused.
  13. VC Distance from lower registers.
  14. VD Distance from lower registers.
  15. VE Distance from lower registers.
  16. VF Unimportance and distance from lower registers.

The program begins by instating Super CHIP-8 mode and initializing all registers to their decided values or zero. Note that register fifteen isn't initialized purely because the constant FE was to be used as part of the interface and it was recognized early that modifying this instruction would result in the desired constant; by using FE for the interface, the drawing code is simplified:

200-201 0512-0513 ▄▄▄▄▄▄▄▄ 00FF 00255                 Enable extended mode
202-203 0514-0515 █ ▀  ▄█▄ A287 41607           begin I ← from
204-205 0516-0517 ▀██▀▀█▀▄ FE65 65125             bar Load V0→VE; I ← I + 15

Following that, the bar is drawn at the top of the screen and in the same position that will be used for all drawing in the pattern entry routine:

206-207 0518-0519 ▀ ▀  ▄▀  A204 41476                 I ← bar
208-209 0520-0521 ██▄▀  ▀▄ D2E1 53985                 Draw 08×01 at V2,VE; VF ← XOR

Pattern entry involves accepting a key, moving up for two, moving down for eight, and changing the value of a cell for five; the initial value of register one is used for wrapping bounds protection; observe that the bar is erased even when nothing else takes place:

20A-20B 0522-0523 ▀▀▀▀█▀▄▀ FD0A 64778           input VD ← key
20C-20D 0524-0525 ▀ ▀  ▄▀  A204 41476                 I ← bar
20E-20F 0526-0527 ██▄▀  ▀▄ D2E1 53985                 Draw 08×01 at V2,VE; VF ← XOR
210-211 0528-0529  ▀  ▀▀▄▀ 4D02 19714                 Skip next if VD <> 002
212-213 0530-0531 ▄██████▄ 7EFF 32511                 VE ← VE + 255
214-215 0532-0533  ▀  █▀ ▀ 4D08 19720                 Skip next if VD <> 008
216-217 0534-0535  ▀▀▀▀▀▀▄ 7E01 32257                 VE ← VE + 001
218-219 0536-0537 ▀  ▄▀▀█  8E12 36370                 VE ← VE AND V1

Key fifteen is used to end pattern entry and I believe this is a nice key for it:

21A-21B 0538-0539  ▀  ██▄█ 4D0F 19727                 Skip next if VD <> 015
21C-21D 0540-0541   ▄█▄▄▀  123C 04668                 Jump to automata

The bar is then redrawn in its new position, which may be the same position, and what remains of the input routine is dedicated to key five, cell modification:

21E-21F 0542-0543 ██▄▀  ▀▄ D2E1 53985                 Draw 08×01 at V2,VE; VF ← XOR
220-221 0544-0545   ▀▀▀█ █ 3D05 15621                 Skip next if VD = 005
222-223 0546-0547    ▀▄ █  120A 04618                 Jump to input

The proper cell is loaded into register zero by initializing I to the base and then adding what is the current vertical coordinate; due to the implicit movement of I by loading, it must be set again. The location of 4031 was chosen in the same way I choose the last three locations for the decimal representation storage; it is chosen because I can't run out of space by using this location and it requires no adjustment based on other program changes:

224-225 0548-0549 █ █▄████ AFBF 44991                 I ← 4031
226-227 0550-0551 ▀▀▀████  FE1E 65054                 I ← I + VE
228-229 0552-0553 ▀██▀ ▄ ▄ F065 61541                 Load V0→V0; I ← I + 01
22A-22B 0554-0555 █ █▄████ AFBF 44991                 I ← 4031
22C-22D 0556-0557 ▀▀▀████  FE1E 65054                 I ← I + VE

The current value of the cell is then drawn, in order to erase any live cells; it has no effect on cells already dead. The current value is then flipped by the one stored in register four and it is stored back:

22E-22F 0558-0559 ██▄▀  ▀▄ D2E1 53985                 Draw 08×01 at V2,VE; VF ← XOR
230-231 0560-0561 ▀▄    ▄▄ 8043 32835                 V0 ← V0 XOR V4
232-233 0562-0563 ▀█▀█ ▄ ▄ F055 61525                 Save V0→V0; I ← I + 01

The I is then set again, as before, and used to draw the new value properly, again only having an effect if the cell is living. The input routine then loops to the beginning:

234-235 0564-0565 █ █▄████ AFBF 44991                 I ← 4031
236-237 0566-0567 ▀▀▀████  FE1E 65054                 I ← I + VE
238-239 0568-0569 ██▄▀  ▀▄ D2E1 53985                 Draw 08×01 at V2,VE; VF ← XOR
23A-23B 0570-0571    ▀▄ █  120A 04618                 Jump to input

The automata routine is the next and final stage of the program. It begins by setting a delay and initializing the higher registers to appropriate values; note that register two was previously used for the horizontal position of the initial pattern and so can simply be incremented; this is part of the simplification that comes about from using the FE bar pattern for the pattern entry interface:

23C-23D 0572-0573 ▀▀▀█ ▄▀█ F315 62229        automata delay ← V3
23E-23F 0574-0575 ▄██▄███▄ 6EFF 28415                 VE ← 255
240-241 0576-0577  ▀▀ ▀▀   6C00 27648                 VC ← 000
242-243 0578-0579  ▀▀▀  ▀▄ 7201 29185                 V2 ← V2 + 001

If the horizontal position has reached its end, it is decremented by four:

244-245 0580-0581  █▄▄▄ ▀  4278 17016                 Skip next if V2 <> 120
246-247 0582-0583 ▄███▄▄▀  72FC 29436                 V2 ← V2 + 252

The prime routine implements the core of the cellular automata, with the automata routine merely being the initialization and looping around it. The vertical position is incremented and again used to collect the appropriate cells. Note that location 4031 is used instead of location 4032 so that the last memory address accessed is 4095, the end of memory:

248-249 0584-0585  ▀▀▀▀▀▀▄ 7E01 32257           prime VE ← VE + 001
24A-24B 0586-0587 █ █▄████ AFBF 44991                 I ← 4031
24C-24D 0588-0589 ▀▀▀████  FE1E 65054                 I ← I + VE
24E-24F 0590-0591 ▀██▀ ▄ █ F165 61797                 Load V0→V1; I ← I + 02

These four instructions form the core of the program and can be modified to change the particular cellular automata implemented. The current cell value is stored in register fifteen as a temporary place; the current cell is compared with the right cell and register twelve stores the left cell; after this, the old current cell is stored as the new left cell, for the next iteration. In doing this, the pattern can be manipulated in-place, yet as if it was modified all at once:

250-251 0592-0593 ▀   ▀▀▀▀ 8F00 36608  rule 30 begins VF ← V0
252-253 0594-0595 ▀  ▄   ▄ 8011 32785                 V0 ← V0 OR V1
254-255 0596-0597 █▄    ▄▄ 80C3 32963                 V0 ← V0 XOR VC
256-257 0598-0599 █▄▄▄▀▀   8CF0 36080    rule 30 ends VC ← VF

The new current cell value is then stored and the prime routine is entered again if not all cells have been updated:

258-259 0600-0601 █ █▄████ AFBF 44991                 I ← 4031
25A-25B 0602-0603 ▀▀▀████  FE1E 65054                 I ← I + VE
25C-25D 0604-0605 ▀█▀█ ▄ ▄ F055 61525                 Save V0→V0; I ← I + 01
25E-25F 0606-0607  ▄▀▀▀▀▀  3E40 15936                 Skip next if VE = 064
260-261 0608-0609  ▄ ▀▄ ▀  1248 04680                 Jump to prime

When all cells have been updated, drawing is performed. Register fourteen is set to zero and loops quatrice, displaying the tallest sprite, fifteen high, in order to display the first sixty cells of the new pattern. Note that eight loopings of eight high would've resulted in shorter code, however this is maximally efficient and it is so rare to be able to draw an entire column of the screen in the most efficient five drawings that I opted to do so:

262-263 0610-0611  ▀▀ ▀▀▀  6E00 28160                 VE ← 000
264-265 0612-0613 █ █▄████ AFBF 44991            draw I ← 4031
266-267 0614-0615 ▀▀▀████  FE1E 65054                 I ← I + VE
268-269 0616-0617 ██▄▀▄▄█▄ D2EF 53999                 Draw 08×15 at V2,VE; VF ← XOR
26A-26B 0618-0619  ▀▀▀███▄ 7E0F 32271                 VE ← VE + 015
26C-26D 0620-0621   ████▀  3E3C 15932                 Skip next if VE = 060
26E-26F 0622-0623  ▄▄▀ ▄▀  1264 04708                 Jump to draw

As it's a constant which cells are those last four, I is set explicitly rather than indirectly by register fourteen and those last four are drawn:

270-271 0624-0625 █▄█▄█▀██ AFFB 45051                 I ← 4091
272-273 0626-0627 ██▄▀ ▄▀  D2E4 53988                 Draw 08×04 at V2,VE; VF ← XOR

The remaining delay is then exhausted in turn with checking for key one, as that's a good value that was readily available in register four; pressing that key ends the program:

274-275 0628-0629 ▀▀▀▀▀███ FF07 65287           delay VF ← delay
276-277 0630-0631 █▀█  ▀ ▄ E4A1 58529                 Skip next if V4 <> key
278-279 0632-0633 ▄▄▄▄▄▄ ▄ 00FD 00253                 Exit program
27A-27B 0634-0635   ▀▀▀▀▀▀ 3F00 16128                 Skip next if VF = 000
27C-27D 0636-0637  ▄▄█ ▄▀  1274 04724                 Jump to delay

The screen is scrolled if the horizontal position is at its end and the automata routine loops; it's noteworthy that this scrolling behavior is what influenced the idea of implementing such a cellular automata program initially:

27E-27F 0638-0639  █▄▄ ▄█▄ 4277 17015                 Skip next if V2 <> 119
280-281 0640-0641 ▄▄▄▄▄▄   00FC 00252                 Scroll ← by 04
282-283 0642-0643   ▄█▄▄▀  123C 04668                 Jump to automata

These instructions are not currently used, but will be later; the remainder of the program are those initial values for the lower registers. Note here that the from is overlapped with this ending jump and this case warrants a special display mechanism, indicating that from is not of location 0646 but 0647; orange is the chosen color to contrast nicely with yellow and I noticed a pleasant orange form of decreasing powers of two with one subtracted, RGB 255 127 63:

284-285 0644-0645 ▄▄▄      00E0 00224         restart Clear the screen
286-287 0646-0647    ▀  █  1202 04610!           from Jump to begin
288     0648        ██████   3F   063
289     0649       ███ █     74   116
28A     0650          █ █    0A   010
28B     0651             █   01   001

I was initially wanting to wait to write this, to write it for the sixth OctoJam, but decided I'd already waited too long to write another program with my MMC, so long that I'd needed to relearn my own key tables. Instead, this is an initial implementation and I will improve it for that event. It will be noticed that the I adjustment could be made a routine, that the speed could be made able to be changed interactively, that the interface could have a notice, that the cellular automata does not draw on the rightmost column, and that a discovered peculiarity results in an unpleasant pattern eventually overtaking the screen and that I intend to correct this by experimenting with behavior in having the edges of the pattern both be living or only one of which would be living. These changes and perhaps others will be made during that event. It was refreshing to write this program over the time that I did, making a few changes or advancements over many days instead of writing it all in a lone sitting. It was nice to finally implement the hidden address name display in my MMC for this, also.