december adventure 2025
the goal is to work on something small every day in december.
i'm making a specification for resource-constrained uxn systems.
i'm tenatively calling it μxn (i.e. muxn).
my rough plan is:
* flesh out vm specification
* produce some example code/ROMs
* fork an existing emulator to implement muxn limits
* explore alternative devices
* port uxn-agon to non-extended Z80 (e.g. muxn441)
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
december 2025 calendar
day 1 day 9 day 17 day 25
day 2 day 10 day 18 day 26
day 3 day 11 day 19 day 27
day 4 day 12 day 20 day 28
day 5 day 13 day 21 day 29
day 6 day 14 day 22 day 30
day 7 day 15 day 23 day 31
day 8 day 16 day 24
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
dec 1: introducing μxn
muxn systems differ from standard uxn in a few ways:
* instead of 64k of memory, they may have less (512-32k bytes)
* instead of 256 bytes of stack, they may have less (16-128 bytes)
* instead of 2 screen layers, they may have fewer (1 or 0 layers)
so muxn-abc means a system with:
* 2^a pages of memory (i.e. 2^a * 256 bytes)
* 2^b * 16 bytes of stack for wst and rst
* c screen layers
standard emulators (such as uxn11) can be described as muxn842:
64k memory, 256 bytes of stack, 2 screen layers
the current uxncli program can be described as muxn840,
since it lacks a screen.
the smallest possible muxn system is muxn100:
512 bytes of memory, 16 byte stacks, 0 screen layers
muxn000 would be a system whose only memory was the zero-page,
which is not useful since it would not have any program to run.
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
dec 2: μxn details and commentary
1. memory
muxn systems with less than 64k of memory must mask all 16-bit
addresses into their memory space:
* pages size mask
-----------------------------
8 256 65536 0xffff
7 128 32768 0x7fff
6 64 16384 0x3fff
5 32 8192 0x1fff
4 16 4096 0x0fff
3 8 2048 0x07ff
2 4 1024 0x03ff
1 2 512 0x01ff
one reason to do this is so programs can easily test to see how much
memory is available (TODO: give example). another reason is to avoid
undefined behavior; some ROMs may want to read all 64k of memory and
this allows those to work (more or less) correctly.
2. stacks
muxn systems with smaller stacks must support underflow by wrapping
around to the largest stack address. they may support overflow in
the same way, but may also crash on stack overflow instead.
when writing to System/wst or System/wst ports the 8-bit value must
be masked into the valid range of stack addresses:
* size mask
-----------------------------
4 256 0xff
3 128 0x7f
2 64 0x3f
1 32 0x1f
0 16 0x0f
underflow is a fairly common trick to easily get a zero, so we should
support it (and it should behave the same no matter the stack size).
overflow is a bit weirder -- some ROMs just push around the stack and
don't need to read back more than a few bytes; these will be fine.
but for any ROM that collects list data on the stack or does deep
recursion overflow will likely causes serious problems.
while testing a ROM for muxn-abc compatibility then error-on-overflow
is probably more useful; in other cases masking is best.
3. screen layers
ROMs with zero screen layers will just ignore all drawing. that's
already how uxncli works. (it would be nice to still allow the
Screen/vector to be used as a timer, unlike uxncli.)
ROMs with one screen layer are trickier.
any ROM that tries to draw transparent pixels to the foreground layer
(exposing a previously hidden background pixel) almost certainly won't
work correctly with only one screen layer.
there are several reasonable behaviors:
1. crash when drawing fg pixels
2. silently ignore fg pixels
3. draw both fg and bg pixels to the same layer
option (1) is most useful when testing compatibility; if a ROM runs
and doesn't crash then it works. if it does crash then there may be
issues.
option (2) is the best option when the fg is just used for something
like an optional mouse cursor. in that case, the cursor won't be
visible but the program will otherwise look and run fine.
option (3) might be the best default. if programs avoid transparent
fg pixels then they will work just as well with only one layer.
otherwise, they will cause various glitchy behavior (e.g. a trail
of "ghost cursors" as the mouse cursor is moved and redrawn).
ideally an muxn emulator would allow any of these behaviors
to be selected, but that adds complexity. i'll probably need to try
these out on some "real world" ROMs to form a better opinion.
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
dec 3: git repo, etc.
i set up a git repo for muxn:
https://git.phial.org/d6/muxn
in addition to a few text files i made a copy of uxn11
and started modifying it. the basic idea is to create
an emulator that can run in any of the various muxn
modes for testing ROM compatibility.
there's more to say about the work but i'm too tired
to say it. see you tomorrow!
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
dec 4: memory testing
didn't have a ton of time today.
i tested the muxn emulator's limited memory support.
first, i confirmed that ROMs failed when i gave them too
little memory, and then i tried to find their limits.
here are some results:
* memory notes
------------------------------
weredice 8 65536 uses entire ROM to store wordlist
m291 7 32768 playlist with just one song
kodiak 7 32768 could probably be optimized under 16k
julia 2 1024 ROM is 5 bytes over 512
i think the stack limiting code also works but it needs more
testing.
this weekend i want to write up some more of the "big ideas"
that i've been having. in more concrete terms here are a few
things i'd like to get done soon:
- test more ROMs to find their memory usage
- do some more stack testing
- write example code to let ROMs detect mem/stack size
- test some known edge cases
- document memory expansion support under muxn
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
Fri Dec 5 12:08:20 AM EST 2025