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

≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡
    
dec 5: memory & stack detection

just a few things today:

 - determined that memory mirroring was working
 - wrote ROM to detect memory size
 - determined that smaller stacks are not working yet

i'm not sure if ROMs will actually want to be adaptive or not,
but it's nice to at least demonstrate the capability.

≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

dec 6: limited stack is working

i got the limited stack sizes for wst and rst working.

this means that the new detection ROM is working.

one interesting data point is electrum, which does
use the experimental subprocess support from uxn11.
i was able to run it successfully under muxn602
(16384 bytes of memory, 16 byte stacks) which is
pretty cool.



at this point i think the muxn program is working well
enough to shift to some of my other ideas. i can revisit
the screen layers later.

≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

dec 7: offpunk detour

i took a detour today to look into an issue with offpunk.

offpunk seems exactly like my kind of project, but the last
time i tried to use it i ran into some issues. in particular, it
can't render my homepage properly:

    http://plastic-idolatry.com/erik/

looking into it, the issue is that i put all my content inside a
<pre> tag. this works in browsers but seems to confuse offpunk.
it renders the entire site as text and doesn't detect the links.

today i spent about an hour hacking on its python code and i got
something that seemed to basically work for my site:

    rough demo-quality patch

i also noticed that my friend sandra's homepage doesn't render
properly either. the issue there seems to be related: most of her
links are inside a <ul> tag. i didn't yet figure out how to patch
offpunk to work better for sandra's site.

if i can get a handle on the codebase i will submit a patch that
does a better job catching these links.

(i'd like to use offpunk more but currently it doesn't work well
for some of these sites i care about.)
    
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

dec 8: links detour

after sleeping on the offpunk issues i started wondering why it
implements its own HTML rendering. i fired up man links just to
see if there were any built-in options that might do the same
thing.

it turns out that (to my eyes at least), i can get a much more
consistent rendering with:

    links -dump -html-numbered-links 1 <URL>

that even produces a nice footer with numbered hyperlinks!

i feel like maybe instead of patching offpunk you could just write
a lightweight HTTP proxy, then point links at that instead. then
you could get all the local behavior you want (caching, archiving)
along with nicer HTML rendering.

(i think offpunk tries also does some fancy stuff with colors
and ANSI art image rendering, but i don't really need those.)
    
≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

dec 9: pause

no adventure today, wasn't feeling great.

might put some stickers on my netbook later...

≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

...

≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

dec 17: restarting this log

after a couple of days break i actually got back into the adventure,
but failed to update the log. i think this is a reasonable trade-off
but now i'm going to try to go back and update those entries.

the current state of muxn.rom is that it can run simple programs
but is still not passing the complete opctest.rom test suite.

i knew that the previous DEO/DEI implementations were
sketchy, so i went ahead and cleaned those up. more to come...

≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

dec 18: passing opctest.rom!

celebratory fedi post

i'm happy it all works. the existing opctest.rom wrapping tests
still work fine with smaller memory/stacks, which sort of validates
the idea of muxn (existing ROMs should work without modification
if at all possible).

as far as being able to actually run "real" ROMs there's more to do:

 - stop hardcoding the ROM path in muxn.rom
 - stop hardcoding the muxn params (e.g. "640") in muxn.rom
 - translate and register device vectors

once that's all done i think we'll have enough to run most simple,
graphical ROMs.

(then the real fun begins: multiplexing 2+ graphical ROMs in a
single underlying emulator.)

≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

dec 19: glitchy catclock achieved

you vs the catclock she told you not to worry about

the basic code for letting ROMs draw to the screen is in place,
but horribly broken. that said it's still exciting to see an
image.

≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

dec 20: running catclock.rom

single instance of catclock is running correctly!

(while this is sort of interesting on its own, the real test
will be multiplexing more than one ROM in the same emulator.)

≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

dec 21: multiplexing demo!

multiplexing six copies of catclock.rom



there are still some bugs, both with this ROM and also with
others i've tested. known issues:

 - not supporting cmdline args yet
 - avoid hardcoding ROM offsets/layout
 - need to multiplex mouse/controller
 - fix screen drawing bugs
 - implement virtual fill operator correctly
 - add subprocess locks/guards
 - add file multiplexing

≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡

Mon Dec 22 12:08:21 AM EST 2025