├── devices.md ├── devices ├── controller.md └── mouse.md ├── index.md ├── readme.md └── uxn.md /devices.md: -------------------------------------------------------------------------------- 1 | # Uxn device model 2 | 3 | The Uxn CPU has 256 bytes of separate memory dedicated to interacting with I/O devices. 4 | The CPU uses the DEI and DEO opcodes to interact with this memory in a similar manner 5 | to the LDZ/STZ opcodes. 6 | 7 | # Varvara 8 | 9 | Varvara is a specification for a specific device mapping attached to a Uxn cpu core. 10 | In Varvara's specification the device page is further subdivided into 16 discrete devices, 11 | each occupying 16 bytes of the page. 12 | 13 | Each device specifies how its 16 bytes are used. A single value/variable is referred to as a "port". 14 | 15 | The official ( somewhat terse ) specification for each device's ports is at . 16 | Check there if this documentation is missing a definition. 17 | 18 | ## Input/Output 19 | 20 | Ports in a device's page will often be meant only for reading, or only for writing. 21 | For example, the console device has a port for reading from stdin, as well as a port for writing out to stdout. 22 | 23 | In a typical implementation, whenever the host language sees that there is a character waiting to be read, it triggers the console device's vector, and copies the character to the "read" port. 24 | Similarily, when the uxn program writes to the "write" port, the host language will take this byte and write it out to the console synchronously. 25 | 26 | ## Vectors 27 | 28 | The Varvara specification asserts that the Uxn CPU core is non-interruptible. 29 | That is, the CPU is left to run on its current task until it hits a BRK instruction, 30 | even if some event happens in the host system ( such as the mouse moving ) 31 | Once the CPU stops executing, the next event can be serviced. 32 | 33 | Each [device specification](devices/) outlines the conditions under which the device vector will be triggered. 34 | Execution begins at the device's "vector" address. If this address is equal to 0x0000, then no code is executed. 35 | By convention, the first 2 bytes of each device store the device's vector address as a short. 36 | 37 | The initial vector that gets run by the emulator at startup is hardcoded to be address 0x0100. -------------------------------------------------------------------------------- /devices/controller.md: -------------------------------------------------------------------------------- 1 | # Controller - Device 0x80 2 | 3 | The controller device maps both an NES-style gamepad and ASCII keyboard input. 4 | 5 | ## Ports 6 | 7 | ### 0x82 - Gamepad buttons 8 | 9 | TODO: nice glyph drawing here 10 | 11 | ### 0x83 - Keyboard key 12 | 13 | Set to the ASCII key that was typed. 14 | If a key was released, then set to 0x00 15 | 16 | ## Vector 17 | 18 | The vector triggers whenever: 19 | 20 | - One of the gamepad buttons is pressed or released 21 | - A keyboard key is pressed 22 | - A keyboard key is released 23 | - In this case, the keyboard byte will be 0x00 -------------------------------------------------------------------------------- /devices/mouse.md: -------------------------------------------------------------------------------- 1 | # Mouse - Device 0x90 2 | 3 | ## Ports 4 | 5 | ### 0x92 - Mouse X 6 | 7 | A short that gives the mouse's current X position. 8 | 9 | ### 0x94 - Mouse Y 10 | 11 | A short that gives the mouse's current Y position. 12 | 13 | ### 0x96 - Buttons 14 | 15 | A byte that gives the current state of the mouse buttons. Each bit of the byte represents 16 | a single mouse button, starting with the least significant bit. If a mouse button is released, 17 | the vector will trigger and the corresponding bit is cleared. 18 | 19 | e.x. 20 | 21 | If mouse button 1 and mouse button 2 are being held down, the byte will be 22 | 23 | 0b0000 0011 = 0x03 24 | 25 | If mouse button 3 and mouse button 5 are being held down, the byte will be 26 | 27 | 0b0001 0100 = 0x14 28 | 29 | If mouse button 5 is released, the byte will now be 30 | 31 | 0b0000 0100 = 0x04 32 | 33 | ### 0x9a - Scroll X 34 | 35 | TODO 36 | 37 | ### 0x9c - Scroll Y 38 | 39 | TODO 40 | 41 | ## Vector 42 | 43 | The mouse vector triggers whenever: 44 | 45 | - The mouse changes position 46 | - Your host's mouse position may be a fractional value or may otherwise not map 1-1 47 | to the varvara screen. For performance, the vector should only be triggered when 48 | the mouse's integer position changes. 49 | - A mouse button is pressed 50 | - A mouse button is released 51 | - The scroll wheel moves 52 | -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | # ! This repo is very out of date and I have not kept it up to date with any changes to the spec since January 2022 ! 2 | I have lost interest in this project and am unlikely to update it any time soon. The instruction set itself has changed and I believe there have been lots of changes to various devices in the interim. Take everything still here with a grain of salt. 3 | 4 | # Uxn implementation guide 5 | 6 | Uxn is a stack-based virtual machine that describes an [Instruction Set Architecture](https://en.wikipedia.org/wifi/Instruction_set_architecture). 7 | Varvara is a specification for a set of I/O devices connected to a Uxn cpu. 8 | 9 | is the reference implementation of Uxn+Varvara. 10 | 11 | ## Index 12 | 13 | ### The Basics 14 | - - Information on the CPU core and instruction set 15 | - - The device interrupt model of the Uxn CPU 16 | 17 | ### Varvara device spec 18 | - - Byte stream device 19 | - - 8-bit sampled audio channels 20 | - - System to poll the real-world time 21 | - - Keyboard/gamepad input device 22 | - - Access to external data sources 23 | - - The graphics system. 24 | 25 | ## Porting the C code 26 | 27 | The reference implementation uses SDL 2 and C89. 28 | 29 | uxn.c implements the CPU core and can be copied into your project without modifications. 30 | 31 | uxnemu.c contains SDL event handling code and window management. 32 | It also contains all of the "glue" code to set up the CPU core and initialize memory with 33 | ROM contents. 34 | 35 | If your target has SDL support then the project may build on its own. 36 | Otherwise, you will have to re-implement the [devices](devices/) and glue code 37 | for your target platform. The device implementations are mixed between uxnemu.c and the 38 | "device" subdirectory. 39 | 40 | ## Porting to a new language 41 | So you want to port Uxn to a new programming language? 42 | 43 | The first thing you should do is read as well as [the Uxntal overview](https://wiki.xxiivv.com/site/uxntal.html). 44 | These provide an overview of the guts of the virtual machine and its instructions. 45 | also contains more detail where it is lacking in the official references. 46 | You'll need to implement a stack as well as some sort of buffer that can store 64Kb of data. 47 | 48 | Depending on the bitwise support in your language of choice, it may be useful to create 49 | some helper methods to translate between shorts and bytes. 50 | 51 | ### Opcodes 52 | 53 | Once you have the basic data structures implemented, you should move on to the [Uxn instruction set reference](https://wiki.xxiivv.com/site/uxntal_reference.html). 54 | This reference describes each of the Uxn instructions in detail with examples of what the 55 | stack should look like for each operation. 56 | 57 | As you implement the different opcodes, you may find it helpful to run [these test programs](https://github.com/DeltaF1/uxn-instruction-tests). 58 | Each test program covers one set of related opcodes and should help find errors if one of 59 | your opcodes is not implemented correctly. 60 | 61 | By the end of this process your CPU implementation should be able to take in a 62 | 16-bit address and execute opcodes from memory until it hits a BRK opcode ( 0x00 ) 63 | 64 | ### Devices 65 | 66 | 67 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | index.md -------------------------------------------------------------------------------- /uxn.md: -------------------------------------------------------------------------------- 1 | # Uxn CPU core 2 | 3 | Uxn defines some internal data structures and a set of opcodes to work upon those data structures. 4 | 5 | ## The stacks 6 | 7 | Uxn has two 256 byte stacks, called WST ( Working Stack ) and RST ( Return Stack ) 8 | 9 | By convention the return stack is used to keep track of return addresses for subroutine calls. 10 | 11 | By default most opcodes operate on the working stack. The JSR and STH opcodes operate 12 | on the working stack and return stack at the same time. 13 | 14 | ## Memory 15 | 16 | Uxn can address 64K ( 65536 bytes ) of memory. 17 | Most programs assume that this memory is initialized to 0 before the program begins. 18 | 19 | ### Zero-page 20 | 21 | The first 256 bytes are called the "zero-page". This region of memory can be addressed 22 | with single byte offsets through the LDZ and STZ instructions. 23 | 24 | ## Device memory 25 | 26 | See and for more information. 27 | 28 | ## Modes 29 | 30 | Every opcode in Uxn can be modified with three different mode bits. These modes can be 31 | combined or ommitted as desired, for a total of 256 possible operations in the VM. 32 | 33 | ### Keep mode 34 | 35 | In "keep" mode, an opcode takes in some data from the stack as usual, 36 | but does not update the stack pointer. This means that the result of an operation is 37 | appended to the existing stack without taking anything off. 38 | 39 | For example, adding two numbers would usually take two numbers off the stack, then 40 | push the result in their place. 41 | 42 | a b -- a+b 43 | 44 | In keep mode the operands are left on the stack and the result is appended as follows: 45 | 46 | a b -- a b a+b 47 | 48 | This can be slightly less intuitive for certain stack manipulation operations. For example, 49 | OVRk would have the following signature: 50 | 51 | a b -- a b a b a 52 | 53 | ### Return mode 54 | 55 | Return mode causes the opcode to operate on the Return Stack instead of the Working Stack. 56 | This means that the opcode will pull data from the return stack and push the results onto 57 | the return stack. 58 | 59 | For the opcodes that already operate on the Return stack in default mode, the stacks 60 | they work on swap. For example, JSR2r will jump to an address off of the Return Stack, 61 | then push the current instruction pointer to the Working stack. 62 | 63 | ### Short mode 64 | 65 | Unless an opcode specifies that a specific operand is always a byte by ( marking it with the 66 | caret ^ symbol ) , putting the opcode into short mode will cause all operands pulled from and 67 | pushed to the stack to be 16-bit shorts rather than 8-bit bytes. 68 | --------------------------------------------------------------------------------