- What the heck is Collapse OS?
- Let’s build it
- Baby steps
- Where to begin?
- Arithmetic / Bits
- Uhhh apparently I can’t scroll?
- But can I at least clear the screen?
- Aight now where was I…?
- So what have we learned?
So I guess people actually read my zany hot takes on Hacker News, because on a whim I visited the Collapse OS website and noticed right there on the homepage that apparently I’m so good at answering questions about things I learned about 5 minutes prior that Collapse OS’ creator namedropped me for, well, doing a “good job” answering questions about a thing I learned about 5 minutes prior.
Those comments were more than a year ago, and I only noticed this a few months ago. Naturally, I felt kinda obligated to join the mailing list. And naturally, after reading the various interesting things on the mailing list, I felt obligated to, you know, actually try out Collapse OS.
This post will probably be all over the place, because I’m literally writing it as I go through the process of obtaining, firing up, and exploring Collapse OS.
What the heck is Collapse OS?
So for those who are looking at this word “Collapse OS” and wondering what in tarnation I’m talking about, the basic elevator pitch is that it’s a minimal operating system designed for a specific kind of global supply chain catastrophe - one in a sort of “goldilocks zone” where the world has gone just sour enough that nobody’s making computer chips anymore, but not quite so south that everyone’s ignoring computers entirely and just hunting each other for sport. It’s written in Forth, and targets a handful of 8-bit chips that are both widespread and easy to scavenge off other things - the main one being the good ol’ Zilog Z80.
But we have so many smartphones and laptops and desktops already; surely we’d be able to get by on those, right?
Sure, but those will all start to break down eventually. Smartphones are hardly built for longevity, and the thermal paste in your average laptop or desktop eventually degrades (and unless you stocked up on a whole bunch of the stuff or maybe some mineral oil for immersion cooling, you’re gonna have a bad time there). Your average Z80 or 8080 or other piddly 8-bit CPU doesn’t really have that problem.
Plus, if things get really bad and we run out of 8-bit CPUs to scavenge… well I tell ya hwat I’d sure rather be handwiring something like a Z80 than anything 16-bit, let alone 32 or 64.
Let’s build it
There’s apparently a JS version of Collapse OS, but I want some semblance of the real deal. Unfortunately, I don’t happen to have any Z80 hardware nearby to scavenge, and I’m too lazy right now to get up and hunt something down, but there’s apparently a virtual machine written in C (creatively named “cvm”) that ships with the Collapse OS download, so I guess I’ll start there, right?
I’m typing this post on a Linux machine, so the process should be pretty
straightforward: download the tarball, extract it, and
make it, right?
northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802> ls arch blk.fs CONTRIBUTING cvm emul Makefile sloc.sh tools AUTHORS CHANGES COPYING doc extras README TODO northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802> make find arch cvm emul tools -name Makefile -execdir make clean \; make: Entering directory '/home/northrup/opt/collapseos-20210802/arch/8086/pcat' rm -f *.bin make: Leaving directory '/home/northrup/opt/collapseos-20210802/arch/8086/pcat' make: Entering directory '/home/northrup/opt/collapseos-20210802/arch/z80/ti84' rm -f *.bin *.rom *.8xu make: Leaving directory '/home/northrup/opt/collapseos-20210802/arch/z80/ti84' make: Entering directory '/home/northrup/opt/collapseos-20210802/arch/z80/trs80-4p' rm -f *.bin make: Leaving directory '/home/northrup/opt/collapseos-20210802/arch/z80/trs80-4p' make: Entering directory '/home/northrup/opt/collapseos-20210802/arch/z80/sms' rm -f os.sms make: Leaving directory '/home/northrup/opt/collapseos-20210802/arch/z80/sms' make: Entering directory '/home/northrup/opt/collapseos-20210802/arch/z80/rc2014' rm -f os.bin make: Leaving directory '/home/northrup/opt/collapseos-20210802/arch/z80/rc2014' make: Entering directory '/home/northrup/opt/collapseos-20210802/arch/z80/z80mbc2' rm -f os.bin make: Leaving directory '/home/northrup/opt/collapseos-20210802/arch/z80/z80mbc2' make: Entering directory '/home/northrup/opt/collapseos-20210802/arch/6809/coco2' rm -f os.bin make: Leaving directory '/home/northrup/opt/collapseos-20210802/arch/6809/coco2' make: Entering directory '/home/northrup/opt/collapseos-20210802/cvm' rm -f stage cos-serial cos-grid *.o grid.bin blkfs make: Leaving directory '/home/northrup/opt/collapseos-20210802/cvm' make: Entering directory '/home/northrup/opt/collapseos-20210802/emul/8086' rm -f forth pcat cpu.o forth.bin make: Leaving directory '/home/northrup/opt/collapseos-20210802/emul/8086' make: Entering directory '/home/northrup/opt/collapseos-20210802/emul/z80' rm -f forth rc2014 sms ti84 *.o *.bin make: Leaving directory '/home/northrup/opt/collapseos-20210802/emul/z80' make: Entering directory '/home/northrup/opt/collapseos-20210802/tools' rm -f memdump upload ttysafe pingpong exec blkpack blkunpack blkup blkdown common.o make: Leaving directory '/home/northrup/opt/collapseos-20210802/tools' find . -name memdump -or -name "*.core" -delete
Well that didn’t do much. Maybe I need to just
make cvm directly?
northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802> cd cvm northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802/cvm> make cc -c -std=c89 vm.c -o vm.o make -C ../tools blkpack make: Entering directory '/home/northrup/opt/collapseos-20210802/tools' cc -c common.c -o common.o cc blkpack.c common.o -o blkpack make: Leaving directory '/home/northrup/opt/collapseos-20210802/tools' cat ../blk.fs ../extras/emul6809.fs ../extras/tests.fs | ../tools/blkpack > blkfs Block 0 encountered. Bumping current blkid to 530. Block 0 encountered. Bumping current blkid to 550. cc -std=c89 -DFBIN_PATH=\"`pwd`/serial.bin\" -DBLKFS_PATH=\"`pwd`/blkfs\" stage.c vm.o -o stage cc -std=c89 -I. -DFBIN_PATH=\"`pwd`/serial.bin\" -DBLKFS_PATH=\"`pwd`/blkfs\" cos-serial.c vm.o -o cos-serial cat common.fs grid.fs | ./stage > grid.bin Using blkfs /home/northrup/opt/collapseos-20210802/cvm/blkfs Collapse OS ok \ This is xcomp code that is common to both serial and grid ok \ binaries. ok 3 VALUES PS_ADDR $fffa RS_ADDR $ff00 HERESTART 0 ok RS_ADDR $90 - VALUE SYSVARS ok SYSVARS $80 + VALUE GRID_MEM ok ASM ok CREATE nativeidx 0 , ok : NATIVE nativeidx @ DUP C, 1+ nativeidx ! ; ok XCOMPL XCOMPH 201 202 203 204 205 ok ok HERE TO ORG ok $15 ALLOT0 ok ( END OF STABLE ABI ) ok CODE EXIT NATIVE ok CODE (br) NATIVE ok CODE (?br) NATIVE ok CODE (loop) NATIVE ok CODE (b) NATIVE ok CODE (n) NATIVE ok CODE (s) NATIVE ok CODE >R NATIVE ok CODE R> NATIVE ok CODE 2>R NATIVE ok CODE 2R> NATIVE ok CODE EXECUTE NATIVE ok CODE ROT NATIVE ok CODE DUP NATIVE ok CODE ?DUP NATIVE ok CODE DROP NATIVE ok CODE SWAP NATIVE ok CODE OVER NATIVE ok CODE AND NATIVE ok CODE OR NATIVE ok CODE XOR NATIVE ok CODE NOT NATIVE ok CODE + NATIVE ok CODE - NATIVE ok CODE * NATIVE ok CODE /MOD NATIVE ok CODE ! NATIVE ok CODE @ NATIVE ok CODE C! NATIVE ok CODE C@ NATIVE ok CODE PC! NATIVE ok CODE PC@ NATIVE ok CODE I NATIVE ok CODE I' NATIVE ok CODE J NATIVE ok CODE BYE NATIVE ok CODE ABORT NATIVE ok CODE QUIT NATIVE ok CODE = NATIVE ok CODE = NATIVE ok CODE < NATIVE ok CODE FIND NATIVE ok CODE 1+ NATIVE ok CODE 1- NATIVE ok CODE TICKS NATIVE ok CODE ROT> NATIVE ok CODE CRC16 NATIVE ok CODE CARRY? NATIVE ok CODE >> NATIVE ok CODE << NATIVE ok CODE >>8 NATIVE ok CODE <<8 NATIVE ok CODE 'S NATIVE ok CODE 'R NATIVE ok CODE FILL NATIVE ok CODE MOVE NATIVE ok CODE MOVE- NATIVE ok COREL 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 ok : (key?) 0 PC@ 1 ; ok : _ ( n blk( -- ) SWAP ( blk( n ) ok ( n ) L|M 3 PC! 3 PC! ( blkid ) ok ( blk( ) L|M 3 PC! 3 PC! ( dest ) ; ok : (blk@) 1 3 PC! ( read ) _ ; ok : (blk!) 2 3 PC! ( write ) _ ; ok BLKSUB 230 231 232 233 234 ok : INIT BLK$ ; ok ( fork between grid and serial begins here ) ok : COLS $03 PC@ ; : LINES $04 PC@ ; ok : CURSOR! ( new old -- ) ok DROP COLS /MOD 6 PC! ( y ) 5 PC! ( x ) ; ok : CELL! ( c pos -- ) 0 CURSOR! 0 PC! ; ok : NEWLN ( ln -- ln ) 1+ DUP LINES = IF 1- 0 7 PC! THEN ; ok GRIDSUB 240 241 ok : INITG INIT GRID$ ; ok XWRAP INITG 226 227 228 229 ok ORG HERE BYE SP fff6 (ffdc) RS ff04 (ff2c) cc -std=c89 -DFBIN_PATH=\"`pwd`/grid.bin\" -DBLKFS_PATH=\"`pwd`/blkfs\" cos-grid.c vm.o -lcurses -o cos-grid /usr/lib64/gcc/x86_64-suse-linux/11/../../../../x86_64-suse-linux/bin/ld: cannot find -lcurses collect2: error: ld returned 1 exit status make: *** [Makefile:33: cos-grid] Error 1
Well shit. I have openSUSE’s
ncurses-devel package installed; maybe it wants
northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802/cvm> sudo zypper in ncurses5-devel [sudo] password for root: Loading repository data... Reading installed packages... Resolving package dependencies... The following 2 NEW packages are going to be installed: libncurses5 ncurses5-devel 2 new packages to install. Overall download size: 955.0 KiB. Already cached: 0 B. After the operation, additional 1.8 MiB will be used. Continue? [y/n/v/...? shows all options] (y): Retrieving package libncurses5-6.2.20210724-24.1.x86_64 (1/2), 608.3 KiB ( 1.2 MiB unpacked) Retrieving: libncurses5-6.2.20210724-24.1.x86_64.rpm ...............[done (11.8 KiB/s)] Retrieving package ncurses5-devel-6.2.20210724-24.1.x86_64 (2/2), 346.7 KiB (693.5 KiB unpacked) Retrieving: ncurses5-devel-6.2.20210724-24.1.x86_64.rpm .........................[done] Checking for file conflicts: ....................................................[done] (1/2) Installing: libncurses5-6.2.20210724-24.1.x86_64 ..........................[done] (2/2) Installing: ncurses5-devel-6.2.20210724-24.1.x86_64 .......................[done] northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802/cvm> make cc -std=c89 -DFBIN_PATH=\"`pwd`/grid.bin\" -DBLKFS_PATH=\"`pwd`/blkfs\" cos-grid.c vm.o -lcurses -o cos-grid /usr/lib64/gcc/x86_64-suse-linux/11/../../../../x86_64-suse-linux/bin/ld: cannot find -lcurses collect2: error: ld returned 1 exit status make: *** [Makefile:33: cos-grid] Error 1
Dang nabbit. Maybe I just need to force it to use
northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802/cvm> cp Makefile Makefile.old northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802/cvm> sed 's/lcurses/lncurses/g' Makefile.old > Makefile northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802/cvm> make cc -std=c89 -DFBIN_PATH=\"`pwd`/grid.bin\" -DBLKFS_PATH=\"`pwd`/blkfs\" cos-grid.c vm.o -lncurses -o cos-grid northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802/cvm> ls blkfs cos-grid.c grid.bin Makefile.old serial.fs vm.c common.fs cos-serial grid.fs README stage vm.h cos-grid cos-serial.c Makefile serial.bin stage.c vm.o
Ayyy that seemed to do it! …but now what?
makewill yield 3 executables:
cos-serial: a Collapse OS prompt running in serial mode. It’s the simplest way to run Collapse OS, but it can’t run Grid applications such as the Visual Editor. However, it can be used non-interactively, that is, you can pipe commands to interpret to it.
cos-grid: Emulates a 80x32 grid using the “curses” library and runs Collapse OS within it. It can run Grid applications such as the Visual Editor.
stage: special binary used to compile and spit. Instead of spitting contents to stdout, it does so on stderr, and at the end of its run, pops the 2 last elements of the PSP, considers it a spitting range, and dumps the contents of its memory within that range.
To play around, you’ll almost always want to run “make && ./cos-grid”.
Oh, okay, maybe I should’ve read that first…
northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802/cvm> make && ./cos-grid ┌────────────────────────────────────────────────────────────────────────────────┐ │Collapse OS ok │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ SP fff8 (fff0) RS ff10 (ff1a)
Well hot diggity damn, it’s runnin’!
So it’s Forth, right? Might as well make sure.
1 1 + ok . 2 ok
Yep, sure is Forth. What else can I do in here? Quick glance at
Where to begin?
If you’re reading this and don’t know where to begin, you’re likely to have access to a modern computer. The best place to begin is to build the C VM of Collapse OS in /cvm. You can then begin playing with it with the help of usage.txt and impl.txt.
Aight, let’s check out
If you already know Forth, start here. Otherwise, read primer.txt first.
But this and
doc/impl.txt seem to be mostly implementation details and other
specifics around Collapse OS’ Forth dialect, so fine, I guess I’ll go peruse
42 $8000 C! $8000 C@ .
This writes the byte “42” at address $8000, and then reads back that byte from the same address and print it.
Well that’s neat.
The cell size in Collapse OS is 16 bit, that is, each item in stacks is 16 bit, @ and ! read and write 16 bit numbers. Whenever we refer to a number, a pointer, we speak of 16 bit.
To read and write bytes, use C@ and C!.
Nice. So if I do…
: read8000 $8000 C@ ; ok : write8000 $8000 C! ; ok 123 write8000 ok read8000 . 123 ok read8000 . 123 ok
Cool, so I can store stuff outside the stack. That’ll surely come in handy.
Starting Forth by Leo Brodie explains all of this in detail. Read this if you can. If you can’t, well, let this sink in for a while, browse the dictionary (dict.txt) and try to understand why this or that word is immediate. Good luck!
Aight, let’s look for some cool stuff in
Arithmetic / Bits
Oh cool, I can do math.
1 3 mod mod word not found ok
Oh. I guess Collapse OS is case-sensitive. Makes sense.
1 3 MOD . 1 ok
Uhhh apparently I can’t scroll?
Didn’t take long for me to hit the bottom of the “grid”, and it seems there’s no
autoscroll. Hmmm… maybe
doc/grid.txt has something to say about that?
…nope, but it does say:
AT-XY ( x y – ) moves the cursor to the specified position. It is equivalent to setting XYPOS directly, but uses separate X and y numbers.
And whaddya know, blindly typing in
0 0 AT-XY did indeed move the cursor back
up top. Doesn’t clear the line automatically when I’m in it, though.
The clearing of the newly entered line is usually only desirable when in “shell” mode. In “graphical” mode, we usually don’t want this to happen. XYMODE is a flag to indicate whether the grid system is in “graphical” mode. When its value is nonzero, NEWLN is not called when entering a new line.
XYMODE . XYMODE word not found ok
NEWLN stack underflow ok 0 NEWLN ok
Well that didn’t do much, either.
But can I at least clear the screen?
CELLS CELLS word not found ok : CELLS COLS LINES * ; ok CELLS . 2560 ok
Well that’s promising.
'? CLEAR . 0 ok
Alright, cool, name ain’t taken. So…
: CLEAR CELLS 1 - 0 DO ' ' I CELL! LOOP 0 0 AT-XY ; ok CLEAR ok
Well it didn’t hang, but it didn’t clear my dang screen, either.
' ' 1 CELL! ok
And that sure did turn the second character on the grid into some character my terminal’s font can’t comprehend. I guess a space ain’t a space? Or maybe I just don’t know the syntax there. Let’s test the other part of the function…
: FOO CELLS 1 - 0 DO I . SPC> LOOP ; ok FOO ( yeah it's just a bunch of numbers, y'all )
Oh wait a second, maybe it is auto-scrolling. Is my terminal just not tall enough?
Aight, still looks ugly, but at least I can see what I’m typing when I hit the bottom. Still wanna clear the screen, though…
: CLEAR 0 0 AT-XY CELLS 1 - 0 DO SPC> LOOP 0 0 AT-XY ; ok CLEAR ok
And the screen’s clear! Well, except for the status line being a bit up in the air at the moment, but still, good enough.
Aight now where was I…?
Right, I was playing around a bit with
3 3 MOD . 0 ok 5 5 MOD . 0 ok 15 3 MOD . 0 ok 15 5 MOD . 0 ok
: IS-FIZZ 3 MOD 0 = ; br ovfl ok
What the heck does that mean?
3 IS-FIZZ . 1 ok
Works anyway, I guess. Onward…
: IS-BUZZ 5 MOD 0 = ; ok : IS-FIZZBUZZ IS-FIZZ IS-BUZZ AND ; ok 5 IS-BUZZ . 1 ok 3 IS-BUZZ . 0 ok 3 IS-FIZZBUZZ . 0 ok 5 IS-FIZZBUZZ . stack underflow ok
Whoops! Got a bit lost with my stack there, I guess. Easy enough to fix.
: IS-FIZZBUZZ DUP IS-FIZZ SWAP IS-BUZZ AND ; ok 3 IS-FIZZBUZZ . 0 ok 5 IS-FIZZBUZZ . 0 ok 15 IS-FIZZBUZZ . 1 ok
How do strings work, though?
LIT" fizz" ok . stack underflow ok
W" fizz" ok . stack underflow ok ," fizz" ok . stack underflow ok
Oh wait a sec…
." fizz" STYPE stack underflow ok
LIT" fizz" STYPE stack underflow ok
Maybe I should just look at some actual code? Hmmm… oooh, the memory editor has this little ditty:
: status 0 COLS nspcs 0 0 AT-XY ." A: " ADDR .X SPC> ." C: " POS .X SPC> ." S: " SCNT ?DUP IF 0 DO 'S I << + @ .X SPC> LOOP THEN POS pos! ;
…wait, have I just been overthinking this the whole time?
: foo ." fizz" ; ok foo fizz ok
You motherf- you know, kinda silly to blame a little 8-bit Forth machine for my own ineptitude, right? Let’s just forget that all happened and put it all together.
: FIZZBUZZ ok 100 1 DO ok I IS-FIZZ IF ." fizz" ok ELSE I IS-BUZZ IF ." buzz" ok ELSE I IS-FIZZBUZZ IF ." fizzbuzz" ok ELSE I ok THEN ok THEN ok THEN ok LOOP ok ; ok FIZZBUZZ
And it was at that precise moment that
cvm came crashing down, leaving me with
SP ff8a (ff84) RS ff08 (ff22) and my terminal prompt.
But I just realized that this was no Collapse OS bug, but rather me forgetting a
. and (I’m guessing) blowing out the poor little VM’s stack. So
let’s fire it back up, and I wanna try the non-grid VM this time.
northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802/cvm> make && ./cos-serial make: Nothing to be done for 'all'. Using blkfs /home/northrup/opt/collapseos-20210802/cvm/blkfs Collapse OS ok : IS-FIZZ 3 MOD 0 = ; ok : IS-BUZZ 5 MOD 0 = ; ok : IS-FIZZBUZZ DUP IS-FIZZ SWAP IS-BUZZ AND ; ok : FIZZBUZZ 100 1 DO I IS-FIZZ IF ." fizz" ELSE I IS-BUZZ IF ." b ok
Aight that was weird. Let’s clean up and try again…
. 4556 ok . 4549 ok . 4531 ok . stack underflow ok . stack underflow ok : FIZZBUZZ 100 1 DO ok I IS-FIZZ IF ." fizz" ok ELSE I IS-BUZZ IF ." buzz" ok ELSE I IS-FIZZBUZZ IF ." fizzbuzz" ok ELSE I . THEN THEN THEN LOOP ; ok FIZZBUZZ 12fizz4buzzfizz78fizzbuzz11fizz1314fizz1617fizz19buzzfizz2223fizzbuzz26fizz2829fizz3132fizz34buzzfizz3738fizzbuzz41fizz4344fizz4647fizz49buzzfizz5253fizzbuzz56fizz5859fizz6162fizz64buzzfizz6768fizzbuzz71fizz7374fizz7677fizz79buzzfizz8283fizzbuzz86fizz8889fizz9192fizz94buzzfizz9798fizz ok
Oi, forgot spaces. And I messed up the order of the fizzbuzz checks.
And… wait, can I pipe into
cos-serial, right? Let’s make a
: IS-FIZZ 3 MOD 0 = ; : IS-BUZZ 5 MOD 0 = ; : IS-FIZZBUZZ DUP IS-FIZZ SWAP IS-BUZZ AND ; : FIZZBUZZ 100 1 DO I IS-FIZZBUZZ IF ." fizzbuzz" ELSE I IS-BUZZ IF ." buzz" ELSE I IS-FIZZ IF ." fizz" ELSE I . THEN THEN THEN SPC> LOOP ; FIZZBUZZ
And the moment of truth…
northrup@DESKTOP-H5JOODG:~/opt/collapseos-20210802/cvm> ./cos-serial <fizzbuzz.forth Using blkfs /home/northrup/opt/collapseos-20210802/cvm/blkfs Collapse OS ok : IS-FIZZ 3 MOD 0 = ; ok : IS-BUZZ 5 MOD 0 = ; ok : IS-FIZZBUZZ DUP IS-FIZZ SWAP IS-BUZZ AND ; ok : FIZZBUZZ ok 100 1 DO ok I IS-FIZZBUZZ IF ." fizzbuzz" ok ELSE I IS-BUZZ IF ." buzz" ok ELSE I IS-FIZZ IF ." fizz" ok ELSE I . ok THEN ok THEN ok THEN ok SPC> LOOP ok ; ok FIZZBUZZ 1 2 fizz 4 buzz fizz 7 8 fizz buzz 11 fizz 13 14 fizzbuzz 16 17 fizz 19 buzz fizz 22 23 fizz buzz 26 fizz 28 29 fizzbuzz 31 32 fizz 34 buzz fizz 37 38 fizz buzz 41 fizz 43 44 fizzbuzz 46 47 fizz 49 buzz fizz 52 53 fizz buzz 56 fizz 58 59 fizzbuzz 61 62 fizz 64 buzz fizz 67 68 fizz buzz 71 fizz 73 74 fizzbuzz 76 77 fizz 79 buzz fizz 82 83 fizz buzz 86 fizz 88 89 fizzbuzz 91 92 fizz 94 buzz fizz 97 98 fizz ok BYE SP fffa (ffe6) RS ff04 (ff16)
Alright, I can officially add Forth and Collapse OS to my résumé now!
So what have we learned?
Collapse OS is pretty cool so far. It’s a fun little system, but just as importantly, it’s definitely gonna be a tool in my post-apocalyptic toolbox. Just as importantly as that, though, is that I can see this having some use before then; why wait for the world to end when folks can start whipping up apocalypse-ready hardware and software?
I haven’t gotten to any of the built-in programs yet; there’s apparently a memory editor and two text editors at the very least. I also haven’t gotten around to doing anything with persistent storage yet. Maybe next time!