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