uxn notes

Tags:tech,uxn

(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 useful

uxn assembly reference
uxn emulator page - has some documentation of the devices
uxn homepage
uxn

Using the tools

Invocations:

./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:

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.

Doing graphics

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.

Screen size

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.

Doing Sound

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 notes

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

Tips

Scoping

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`.