revision uxn tutorial day 5

This commit is contained in:
sejo 2022-01-07 16:45:18 -06:00
parent 0086bd73a5
commit 937e1cba8c
1 changed files with 39 additions and 19 deletions

View File

@ -312,10 +312,12 @@ let's meet an alternative, the "jump and stash" instruction!
# jump and stash
the jump and stash instruction, JSR, does the same as JMP (unconditionally jump to the address present in the working stack), with the additional action of pushing down into the return stack the address of the next instruction in memory.
the jump and stash instruction, JSR, does the same as JMP (unconditionally jump to the address present in the working stack), with the additional action of pushing down into the return stack the absolute address of what would be the next instruction in memory after the JSR.
in the normal mode, JSR takes a relative address (one byte) from the working stack, and in short mode, JSR2 takes an absolute address.
in both of these cases, JSR will push an absolute address (2 bytes) down into the return stack.
## relative jump
for example, our jumps could be re-written as follows. in the case of a relative jump:
@ -358,13 +360,23 @@ whenever this flag is set, uxn will perform the given instruction but using as s
in uxntal, we indicate that we want to set this flag adding the letter 'r' to the end of an instruction mnemonic.
as each of the modes is an independent bit, it is possible to combine them, e.g. activating the return mode and the short mode by using the suffix '2r'.
## a brief return stack example
for example, the following code would push two numbers down into the return stack, add them, and push the result back into the return stack:
```
LITr 01 LITr 02 ADDr
```
as each of the modes is an independent bit, it is possible to combine them, e.g. activating the return mode and the short mode by using the suffix '2r'.
or, combining the short and return modes in the LIT instruction:
```
LIT2r 0102 ADDr
```
now let's go back to our jumps :)
## jumping to return
@ -372,7 +384,7 @@ as we have discussed already, JMP will allow us to unconditionally jump to the a
JSR or JSR2 push down into the return stack the absolute address of the next instruction, a short, so that we can eventually return there.
how can we unconditionally jump to that absolute address in the return stack?
how can we unconditionally jump to that absolute address that is present in the return stack?
exactly!
@ -384,7 +396,7 @@ additionally, as the addresses pushed by JSR are shorts, we need to activate the
JMP2r ( jump to the absolute address at the top of the return stack )
```
normally, in uxntal programs you will see this instruction written as a macro, RTN (return)
in many uxntal programs you will see this instruction written as a macro, RTN (return)
```
%RTN { JMP2r }
@ -402,7 +414,7 @@ this is the hello-pointer.tal program, but using draw-pointer as a subroutine th
( devices )
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ]
|90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &wheel $1 ]
|90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &pad $3 &scrollx $2 &scrolly $2 ]
( macros )
%RTN { JMP2r }
@ -457,11 +469,15 @@ RTN
note that the draw-pointer label is accompanied by the stack state notation ( -- ) to indicate that, in this case, it doesn't consume or produce contents from or to the working stack.
also note how this subroutine ends with a RTN (JMP2r) that indicates that the flow of the program will return to the position after the subroutine was called.
## notes on subroutines as "functions"
keep in mind that a possible way of sending "arguments" to a subroutine would be to push them down into the working stack before calling it.
additionaly, a possible way of receiving the results of a subroutine would be to have it pushing them down into the working stack so that they are there to be consumed after returning.
additionaly, a possible way for a subroutine to "return" its results would be to have it pushing them down into the working stack.
these elements can then be consumed from the working stack after returning from the subroutine.
there might be other instances where using "variables" would make more logical and/or readable sense to pass arguments and results.
@ -471,7 +487,7 @@ having introduced the return stack and the return mode, another world of possibi
in order to achieve this, uxn has an instruction called STH, stash.
this is the last instruction we had to cover in this tutorial series! :)
this is the last instruction of uxn that we had to cover in this tutorial series! :)
## STH
@ -561,11 +577,11 @@ however, it shows how we can use these instructions to have a clean working stac
* have the subroutine draw a line made of sprites instead of single pixels
* modify the subroutine so that it can receive as an argument (in the working stack) the color of the sprites or pixels
* modify the subroutine so that it can receive as an argument (in the working stack) the address of the sprite to draw
* rewrite the subroutine so that it uses a short-sized length
* rewrite the subroutine so that it uses a short-sized length for the line, instead of a byte.
# the keep mode
the last element of uxntal that we can cover is its third mode for instructions: the keep mode.
the last basic element of uxntal that we have yet to cover is its third mode for instructions: the keep mode.
the keep mode is encoded in the 8th bit of an instruction byte, counting from right to left.
@ -608,7 +624,7 @@ actually, if you remember, on {uxn tutorial day 4} i shared with you a couple of
i said then that there was a more optimized set, and that we'd discuss it later.
now is that later moment!
now is that moment!
first of all, let's analyze what's happening with MOD. it is calculating what would be written in infix notation as follows, assumming that the slash (/) indicates an integer division
@ -618,9 +634,9 @@ a - ( a/b )*b
try for example replacing 'a' with 7 and 'b' with 3; the modulo or remainder should be 1
* a/b gives us the result of the integer division; 7/3 is 2
* (a/b)*b tries to get 'a' again, but possibly "fails" because of the remainder that was lost in the division; 2*3 is 6
* a - (a/b)*b calculates what's the difference between 'a' and the obtained result; 7-6 is 1
* a/b gives us the result of the integer division: 7/3 is 2
* (a/b)*b tries to get 'a' again, but possibly "fails" because of the remainder that was lost in the division: 2*3 is 6
* a - (a/b)*b calculates what's the difference between 'a' and the obtained result: 7-6 is 1
in our original macro, what happens goes as follows:
@ -634,9 +650,13 @@ SUB ( ws: 01 )
do you see a possibility for introducing the keep mode?
if you look carefully, you'll see that DUP2 is there in order to avoid losing the original values, so that we can perform the multiplication and subtraction later.
if you look carefully, you'll see that DUP2 is there in order to avoid losing the original values in the division, so that we can perform the multiplication and subtraction later.
therefore, DUP2 DIV is equivalent to... DIVk! a division that doesn't lose its operands!
but now, how can we perform the division without losing its operands and without using DUP2?
that's right!
DUP2 DIV is equivalent to... DIVk! a division that doesn't lose its operands!
```
#07 #03 ( ws: 07 03 )
@ -645,7 +665,7 @@ MUL ( ws: 07 06 )
SUB ( ws: 01 )
```
so our macro can have one byte less!
in this way, our macro can have one less byte!
we can generalize this behavior for the short mode, and obtain the optimal set of macros that i mentioned earlier:
@ -706,7 +726,7 @@ STHkr ( retrieve a copy from the return stack )
new and interesting uses for the keep mode are still being found :)
don't hesitate to share them with us! and keep an eye over here for more possibilities!
don't hesitate to share them with us!
# more exercises
@ -724,7 +744,7 @@ maybe start with drawing only when a button is pressed. change color and/or "bru
you can have different selectable "modes": maybe they change the brush you are using, the way the brush behaves (e.g. in mirror? kaleidoscope?), and/or the shapes that are drawn.
consider how you would select those modes: on screen buttons? keys from the keyboard?
consider how you would select those modes: on screen buttons? keys from the keyboard? chords with mouse buttons?
keep in mind that you can change a device's vector during runtime: you could have a different on-mouse subroutine depending on the mode you have selected :)
@ -736,7 +756,7 @@ basically, the gates for interactive visual applications in the varvara computer
will you create games? small applications, useful or not? an instrument for live visuals? programs targeting specific handheld devices?
some things might appear difficult to build, but fortunately, (i feel-think) there's nothing else in the workings of the machine that we haven't covered already.
some things might appear difficult to build, but fortunately, as of now there's nothing else in the workings of the machine that we haven't covered already.
you can go slowly, step by step, practicing your stack wrangling and exercising the postfix brain, and you'll get anywhere you want :)