hello! in this first section of the {uxn tutorial} we talk about the basics of the uxn computer called varvara, its programming paradigm in a language called uxntal, its architecture, and why you would want to learn to program it.
> The Uxn/Varvara ecosystem is a personal computing stack based on a small virtual machine that lies at the heart of our software, and that allows us to run the same application on a variety of systems.
uxn is the core of the varvara virtual computer. it is simple enough to be emulated by many old and new computing platforms, and to be followed by hand.
the uxn core is inspired by forth-machines in that it uses the recombination of simple components to achieve appropriate solutions, and in that it is a stack-based machine.
this implies that it is primarily based on interactions with a "push down stack", where operations are indicated using what is called postfix notation.
> Reverse Polish notation (RPN), also known as Polish postfix notation or simply postfix notation, is a mathematical notation in which operators follow their operands [...]
=> https://en.wikipedia.org/wiki/Reverse_Polish_notation Reverse Polish notation - Wikipedia
## postfix addition
in postfix notation, the addition of two numbers would be written in the following form:
``` 1 48 +
1 48 +
```
where, reading from left to right:
* number 1 is pushed down onto the stack
* number 48 is pushed down onto the stack
* + takes two elements from the top of the stack, adds them, and pushes the result down onto the stack
the book Starting Forth has some great illustrations of this process of addition:
=> https://www.forth.com/starting-forth/1-forth-stacks-dictionary/#The_Stack_Forth8217s_Workspace_for_Arithmetic The Stack: Forth’s Workspace for Arithmetic
## from infix to postfix
more complex expressions in infix notation, that require either parenthesis or rules of operator precedence (and a more complex system for decoding them), can be simplified with postfix notation.
for example, the following infix expression:
``` (2 + 16)/8 + 48
(3 + 5)/2 + 48
```
can be written in postfix notation as:
``` 3 5 + 2 / 48 +
3 5 + 2 / 48 +
```
we can also write it in many other ways, for example:
``` 48 2 3 5 + / +
48 3 5 + 2 / +
```
make sure these expressions work and are equivalent! you just have to follow these rules, reading from left to right:
note: in the case of the division, the operands follow the same left-to-right order. 3/2 would be written as:
``` 3 2 /
3 2 /
```
you'll start seeing how the use of the stack can be very powerful as it can save operands and/or intermediate results without us having to explicitly assign a place in memory for them (i.e. like using "variables" in other programming languages)
we'll come back to postfix notation and the stack very soon!
one of the perks of programming a computer at a low-level of abstraction, as we will be doing with uxn, is that we have to know and be aware of its internal workings.
binary words of 8-bits, also known as bytes, are the basic elements of data encoding and manipulation in uxn.
uxn can also handle binary words of 16-bits (2 bytes), also known as shorts, by concatenating two consecutive bytes. we'll talk more about this in the second day of the tutorial.
numbers in uxn are expressed using the {hexadecimal} system (base 16), where each digit (nibble) goes from 0 to 9 and then from 'a' to 'f' (in lower case).
each byte in the main memory has an address of 16-bits (2 bytes) in size, while each byte in the i/o memory has an address of 8-bits (1 byte) in size. both of them can be accessed randomly.
the first 256 bytes of the main memory constitute a section called the zero page. this section can be addressed by 8-bits (1 byte), and it is meant for data storage during runtime of the machine.
there are different instructions for interacting with each of these memory spaces.
the main memory stores the program to be executed, starting at the 257th byte (address 0100 in hexadecimal, or 256 in decimal). it can also store data.
the instruction will normally imply a change in the stack(s), and sometimes it may imply a change of the normal flow of the program counter: instead of pointing to the next byte in memory, it can be made to point elsewhere, "jumping" from a place in memory to another.
depending on your system, you might be able to launch the emulator (uxnemu) with a double-click, or you might need to use a console to navigate to its location and run it:
from there you will be able to run the other roms by clicking them, pressing Enter, or the Ctrl key. you can go back to the launcher by pressing the F4 key.
we were talking before about the uxn cpu and the 32 instructions it knows how to perform, each of them encoded as a single 8-bit word (byte).
that uxntal is an assembly language implies that there's a one-to-one mapping of a written instruction in the language to a corresponding 8-bit word that the cpu can interpret.
for example, the instruction ADD in uxntal is encoded as a single byte with the value 18 in hexadecimal, and corresponds to the following set of actions: take the top two elements from the stack, add them, and push down the result.
in forth-like systems we can see the following kind of notation to express the operands that an instruction takes from the stack, and the result(s) that it pushes down onto the stack:
```
ADD ( a b -- a+b )
```
this means that ADD takes first the top element 'b', then it takes the new top element 'a', and pushes back the result of adding a+b.
now that we are at it, there's a complementary instruction, SUB (opcode 19), that takes the top two elements from the stack, subtracts them, and pushes down the result:
note that the order of the operands in the subtraction is similar to the order for the division as we discussed above when talking about postfix notation: it is as if we moved the operator from between operands, to the end after the second operand.
uxn and the tools that have been built around it allow us to learn and develop completely within the system.
for instance, when you run the emulator you will see that you can open a program called left: a text editor!
=> https://100r.co/site/left.html 100R — left
open it, as we will write our first program there!
first of all, rename the file you are working on. you can use the visual menu or press Ctrl + r, then delete the current filename, replace it with hello.tal, and press Enter to confirm.
now write the following program:
```
( hello.tal )
|0100 LIT 68 LIT 18 DEO
```
save it using the visual menu or Ctrl + s, and then go back to the launcher by pressing F4.
you will see now that the listing in the launcher includes your newly created file, hello.tal!
note that this is a text file only, and it's not a rom yet. however, the launcher makes it very easy to convert it to a rom, or more precisely, to assemble it!
just click the hello.tal, or use the arrow keys to reach it and then press Enter or Ctrl: if everything went alright you will see that a hello.tal.rom file appears!
additionally, note that the accompanying console will print something like:
```
on-reset 0x0000
0x0004 lines of source code.
0x002e bytes of heap used, 0xa34e bytes free.
```
if there are errors during assembly, you will see them there.
now that you have hello.tal.rom you can run it from the launcher as any other rom!
when you run it you will see that the screen will be cleared and that the console will show the output of our program:
```
h
```
interesting, what is happening?
i invite you to try replacing the 68 in the code with, for example, 65.
to do that you'll have to open left again, rename the file to hello.tal so that it opens it, modify the file, save it, return to the launcher, assemble, and then run again!
### using another text editor and uxn tools
alternatively, you can use your favorite text editor and the uxn programs to replicate what we just did from within uxnemu.
you can write hello.tal using your text editor, and then save it along the other files bundled with the emulator:
the first line is a comment: comments are enclosed between parenthesis and there have to be spaces in between them. similar to other programming languages, comments are ignored by the assembler.
the second line has several things going on:
* |0100 : you may remember this number from before - this is the initial value of the program counter; the address of the first byte that the cpu reads. we use this notation to indicate that whatever is written afterwards, will be written in memory starting at this address.
* LIT : this appears twice; it is an uxn instruction that performs the following actions: it pushes the next byte in memory down onto the stack, and it makes the program counter skip that byte.
* DEO : another uxn instruction, that we could define as the following: output the given value (1 byte) into the given device address, both taken from the stack ( value address -- )
looking at the devices table from the varvara reference, we can see that the device with address 1 in the high nibble is the console (standard input and output), and that the column with address 8 in the low nibble corresponds to the "write" port.
note that the raw numbers that we wrote, 0100, 18 and 68, are written in hexadecimal using either 4 digits corresponding to two bytes, or 2 digits corresponding to one byte.
in uxntal we can only write numbers that are 2 or 4 hexadecimal digits long. if, for example, we were only interested in writing a single hexadecimal digit, we would have to include a 0 at its left.
important: remember that this rune (and the others with the word "literal" in their names) is a shorthand for the LIT instruction. this implies that uxn will push these values down into the stack.
if we just want to have a specific number in the main memory, without pushing it into the stack, we would just write the number as is, "raw". this is the way we did it in our first programs above.
even though right now we know that #18 corresponds to pushing the console write device port down onto the stack, for readability and future-proofing of our code it is a good practice to assign a set of labels that would correspond to that device and port.
we can see an absolute pad to address 10, that assigns the following items to that address. because the address consists of one byte only, uxnasm assumes it is for the i/o memory space or the zero page.
the square brackets are ignored, but included for readability.
next we have several sub-labels, indicated by the & rune, and relative pads, indicated by the $ rune. how do we read/interpret them?
* sublabel &vector has the same address as its parent label @Console: 10
* $2 skips two bytes (we could read this as &vector being an address to a 2-bytes long word)
* sublabel &read has the address 12
* $1 skips one byte (&read would be an address for a 1-byte long word)
* sublabel &pad has the address 13
* $5 skips the remaining bytes of the first group of 8 bytes in the device: these bytes correspond to the "inputs"
* sublabel &write has the address 18 (the one we knew already!)
* $1 skips one byte (&write would be an address for a 1-byte long word)
* sublabel &error has the address 19
none of this would be translated to machine code, but aids us in writing uxntal code.
the rune for referring to literal address in the zero page or i/o address space, is . (dot), and a / (slash) allows us to refer to one of its sublabels.
remember: as a "literal address" rune it will add a LIT instruction before the corresponding address :)
if you look at the ascii table, you'll see that the hexadecimal ascii code 30 corresponds to the digit 0, 31 to the digit 1, and so on until 39 that corresponds to digit 9.
define a PRINT-DIGIT macro that takes a number (from 0 to 9) from the stack, and prints its corresponding digit to standard output.
remember that the number would have to be written as a complete byte in order to be valid uxntal. if you wanted to test this macro with e.g. number 2, you would have to write it as 02:
in {uxn tutorial day 2} we start exploring the visual aspects of the varvara computer: we talk about the fundamentals of the screen device so that we can start drawing on it!