(this is likely going to be outdated very quickly and might also be incorrect! uxn is under active development. This page was last updated at commit 743eaef )
uxn is a quirky little VM developed by Devine Lu Linvega. This page is me documenting my exploration of it, and things i think others might find usefuluxn assembly reference
uxn emulator page - has some documentation of the devices
Using the tools
./assembler [sourcefile] [rom] ./emulator [rom]
There is a built in debugger in the uxn emulator that can be accessed by pressing Ctrl-H. It shows the current state of the stack. It uses the pallete colors, so those need to be set in the application you're debugging (see below).
Assembly and archetecture
the uxn assembly is pretty well documented in xxiivv (the links at the top of this page). A few things I was confused by that I want to clarify:
- a short is 2 bytes. There is no seperate "types" of a short vs a byte, a short just takes two spaces on the stack (like a double in forth)
- The extra flags (short and return) on opcodes are pretty self explanatory - for versions that take 2 bytes vs 1, and versions that use the return stack.
- The rom file (the data stored on disk in your .rom) begins at address 0100.
When writing your own code, the blank.usm file in the examples folder of uxn is a very good starting point. When uxn starts, it executes what it finds at address 0100.
uxn has four colors and two graphics layers. It also has a sprite engine, which is well enough documented in xxiivv that I don't want to write about it.
Setting the pallete
Before any graphics can be done, you have to set the pallete that will be used. This is done by storing to the System.r, System.g and System.b values. Each hex digit of these values is the r,g,b of one of the 4 colors. For example:
#f0fa .System/r DEO2 #f2fa .System/g DEO2 #f0fa .System/b DEO2
would make color 0 be (f,f,f), color 1 be (0,0,0), color 2 be (f,2,f) and color 3 be (a,a,a).
Setting the graphics vector
The screen device has a vector, that needs to be set to an address. The code starting at this address will be called every 1/60th of a second. This needs to be set before you start doing graphics. For example:
|0100 #f0fa .System/r DEO2 #f2fa .System/g DEO2 #f0fa .System/b DEO2 ;on-frame .Screen/vector DEO2 BRK @FRAME ( graphics code here to run every frame ) BRK
Plotting a pixel
Plotting a pixel is done by setting the screen X and Y values, and then the color to set that x/y position to. The color is a single byte, with two hex digits. The first is the layer and mode (1=foreground pixel mode, 0=background pixel mode) and the second is the color (0-3). For example:
#0010 .Screen/x DEO2 #0010 .Screen/y DEO2 #01 .Screen/color DEO2
would plot a pixel at (0x10, 0x10), in the background, with color 1.
the uxn emulator doesn't have one preprogrammed display size! If you need the screen size, read it from the Screen.width and Screen.height addresses.
Setting up the audio device
uxn has 4 audio channels, and these are accessible as Audio0 to Audio3.
To set up an audio channel, you need to set the volume, address, length, and ADSR.
The ADSR is a short with each hex digit being one of the parameters. So #3ffb would be attack of 3, decay of f, sustain of f, and release of b.
volume is a byte with each hex digit being the volume in that channel, so #ff is full volume in both channels, #80 would be half volume left and no volume right, etc.
addr is the address to sample data in memory. The sample data is unsigned 8-bit with no header etc. length is the length of this sample. More info on the xxiivv page
Playing a note on the uxn audio chip requires setting the envelope and waveform (like described above) and then writing to the Audio.pitch register.
The audio.pitch register takes a single byte, that is the MIDI note value of the note you want to play. By default this plays the sample looped, but if the high bit is set, it plays as a one shot.
#3C .Audio0/pitch DEO
the official uxn assembler has local labels, which are used with `&` and scoped to the nearest global label (used with `@`). You can use this along with LDR/STR (load/store relative) to create "functions" with locals that are scoped within them. For example:
@foo &a $1 &run #10 ,&a STR ,&a LDR RTN
while a useless function, this demostrates the idea. foo has a local which cannot be accessed outside foo's scope (&a). To call it you would say `;foo/run JSR2`.