Uxnemu is a Uxn emulator written in ANSI C, and SDL2.
The thin layer that is the Uxn emulator is the only part of this project needing to be ported to make the system available on a new platform. For that reason, Uxn was designed with a focus on portability and simplicity such that it welcomes anyone to try their hand at building their own implementation. The current emulator is 400 lines of C89, with SDL2 as its only dependecy.

Devices are external systems to the Uxn code such as the screen, the mouse, the keyboard, etc. There is a maximum of 16 devices, each device have 8 bytes to read from, and 8 bytes to write to.
Devices
An emulator implementation can choose which device to implement or to leave out, these are the suggested addresses and ports of this specific emulator.
device | i/o | Notes | ||
---|---|---|---|---|
0x00 | 0x08 | |||
0100 | system | vector* | red* | The system device's vector is automatically set by the emulator and is the first vector that is triggered in a program. |
green* | ||||
blue* | ||||
0110 | console | vector* | char | The console's vector is currently unused. |
byte | ||||
short* | ||||
string* | ||||
0120 | screen | vector* | x* | The screen device's vector is triggered 60 times per second, it is typically used to update pixels on the screen. |
width* | y* | |||
height* | addr* | |||
color | ||||
0130 | audio | wave* | volume | The APU multiplies two waveforms, defined by the wave and envelope vectors. In the main program, write the vectors, volume (left/right nibbles) and pitch (MIDI note number) to define the note, then the channel number to the play byte. |
envelope* | pitch | |||
play | ||||
value* | ||||
delay* | ||||
finish | ||||
0140 | controller | vector* | nil | The controller device's vector is triggered each time a key is pressed or released. |
button | ||||
key | ||||
0160 | mouse | vector* | nil | The mouse device's vector is triggered each time the mouse moved, or a button was pressed or released. |
x* | ||||
y* | ||||
state | ||||
chord | ||||
0170 | file | vector* | name* | The file's vector is currently unused. The reading/writing of a file will set the success short to the length of that data. |
success* | length* | |||
offset* | addr(r)* | |||
addr(w)* | ||||
0190 | midi | vector* | devicew | The midi device's vector is triggered when a midi note is received. |
devicer | byte1 | |||
byte1 | byte2 | |||
byte2 | ||||
01a0 | datetime | yearh* | refresh | The datetime's vector is currently unused. |
yearl* | ||||
dayh* | ||||
dayl* |
Screen Device(PPU)

Buffers | background | 64kb |
---|---|---|
foreground | 64kb |
The screen device is made of two screen buffers, that are combined to form the pixels on the screen. The sprite device can be written to with a x*
, y*
and color
.
The color byte defines the layer to draw on, the type of data to draw, and the colors to use. To paint a pixel on the first layer, use the #01
, to paint a pixel on the second layer, use the #11
.
* * M L D C B A | | | +---- Layer | | | +---- Blend | | +------ Mode | | +------ Blend | +-------- Nil | +-------- Blend +---------- Nil +---------- Blend
The device can also draw multiple bytes at once by writing the address* to a series of bytes in the screen's sprite address, to paint a 1-bit 8x8 sprite(8 bytes) on the first layer, use the #21
, to paint a 1-bit 8x8 sprite on the second layer, use the #31
. The blending mode 1, is demonstrated in the table below. To learn more about the sprite format, see .chr format.
high nibble | low nibble | |||||||
---|---|---|---|---|---|---|---|---|
0 | bg | pixel | 0 | 0 | 8 | 0 | 2 | |
1 | fg | 1 | 1 | 0 | 9 | 1 | 2 | |
2 | bg | 1-bit | 2 | 2 | 0 | a | 2 | |
3 | fg | 3 | 3 | 0 | b | 3 | 2 | |
4 | bg | 2-bit | 4 | 0 | 1 | c | 0 | 3 |
5 | fg | 5 | 1 | d | 1 | 3 | ||
6 | bg | nil | 6 | 2 | 1 | e | 2 | 3 |
7 | fg | 7 | 3 | 1 | f | 3 |
Audio Device(APU)

In the wave and envelope vectors, write the value (amplitude) and delay shorts to define the next part of the waveform. A delay of 0x8000
in the wave vector represents half the note's period: in the envelope vector, it represents half a second. The waveform is linearly interpolated between pairs of values. During these vectors, the channel number used for the note can be read from the play byte.
The wave and envelope vectors repeat until (a) no value/delay pairs are written to the device or (b) any value is written to the finish byte.
Controller Device
This button byte works similarly to a NES controller, where there the state of each one of the 8 buttons is stored as a bit in a single byte. The keys byte contains the ascii character that is currently pressed.
0x01 | Ctrl | 0x10 | Up |
0x02 | Alt | 0x20 | Down |
0x04 | Shift | 0x40 | Left |
0x08 | Escape | 0x80 | Right |

incoming(1): uxn
Last update on 15H04, edited 7 times. +24/40fh -----|