replaced asterisk with caret to indicate shorts

This commit is contained in:
sejo 2021-09-15 12:49:48 -05:00
parent 96b39462b8
commit 7fd039a874
3 changed files with 89 additions and 87 deletions

View File

@ -10,7 +10,7 @@ here we will generalize a similar procedure into a draw-tiles subroutine that dr
a reminder that we are using the convention of adding a caret (^) after the name of a value to indicate it's a short, and an asterisk (*) to indicate it's a short working as a pointer (i.e. an address in program memory)
we will detail how to get to two versions of this subroutine, one that relies on heavy stack wrangling, and other one that uses variables. this in order to compare both approaches and give us clues of the procedures that we will develop afterwards today.
we will detail how to get to two versions of this subroutine, one that relies on heavy stack wrangling, and other one that uses variables. this in order to compare both approaches and give us a broader view of the possibilities within uxntal.
## setting up
@ -104,7 +104,7 @@ now, let's say we want to have the previous code work with any given initial x a
we can even think of it as a subroutine by itself with the following signature:
```
@draw-tiles-in-a-row ( x* width* -- )
@draw-tiles-in-a-row ( x^ width^ -- )
```
let's assume for the moment that the address of the sprite was already set, in order to focus in x and width.
@ -116,19 +116,19 @@ we can use these two values to calculate the limit, that we can stash in the ret
one way of achieving that, noting the state of the working stack after each instruction, could be:
```
( initial state: ws: x* width* )
OVR2 ( ws: x* width* x* )
ADD2 ( ws: x* limit* )
STH2 ( ws: x* / rs: limit* )
( initial state: ws: x^ width^ )
OVR2 ( ws: x^ width^ x^ )
ADD2 ( ws: x^ limit^ )
STH2 ( ws: x^ / rs: limit^ )
```
another one:
```
( initial state: ws: x* width* )
ADD2k ( ws: x* width* limit* )
STH2 ( ws: x* width* / rs: limit* )
POP2 ( ws: x* / rs: limit* )
( initial state: ws: x^ width^ )
ADD2k ( ws: x^ width^ limit^ )
STH2 ( ws: x^ width^ / rs: limit^ )
POP2 ( ws: x^ / rs: limit^ )
```
remember that we are showing the top of the stacks at their right.
@ -140,11 +140,11 @@ the last change that we would need is to replace our hardcoded limit with a STH2
our subroutine would then look as follows:
```
@draw-tiles-in-a-row ( x* width* -- )
@draw-tiles-in-a-row ( x^ width^ -- )
( calculate and save limit )
OVR2 ( ws: x* width* x* )
ADD2 ( ws: x* limit* )
STH2 ( ws: x* / rs: limit* )
OVR2 ( ws: x^ width^ x^ )
ADD2 ( ws: x^ limit^ )
STH2 ( ws: x^ / rs: limit^ )
.Screen/x DEO2 ( set initial x )
&loop-x
@ -187,10 +187,10 @@ the following shows our program in context, completely filling the first row of
;draw-tiles-in-a-row JSR2
BRK
@draw-tiles-in-a-row ( x* width* -- )
OVR2 ( ws: x* limit* x* )
ADD2 ( ws: x* limit* )
STH2 ( ws: x* / rs: limit* )
@draw-tiles-in-a-row ( x^ width^ -- )
OVR2 ( ws: x^ limit^ x^ )
ADD2 ( ws: x^ limit^ )
STH2 ( ws: x^ / rs: limit^ )
.Screen/x DEO2 ( set initial x )
&loop-x
@ -251,7 +251,7 @@ why? because the idea for our draw-tiles subroutine is that it should be able to
this should be the signature for our subroutine:
```
@draw-tiles ( x* y* width* height* addr* -- )
@draw-tiles ( x^ y^ width^ height^ addr* -- )
```
we can approach this problem either with some "stack wrangling", or with "variables".
@ -269,8 +269,8 @@ in principle we could just manipulate the items given in the stack, stashing the
first of all, the tile address is the value at the top of the stack. we can just consume it and forget about it:
```
( initial ws: x* y* width* height* addr* )
.Screen/addr DEO2 ( ws: x* y* width* height* )
( initial ws: x^ y^ width^ height^ addr* )
.Screen/addr DEO2 ( ws: x^ y^ width^ height^ )
```
thinking about the vertical loop, we need to calculate its limit adding height to y, and we need to set the initial y.
@ -278,51 +278,51 @@ thinking about the vertical loop, we need to calculate its limit adding height t
we could do the following:
```
ROT2 ( ws: x* width* height* y* )
DUP2 ( ws: x* width* height* y* y* )
ROT2 ( ws: x^ width^ height^ y^ )
DUP2 ( ws: x^ width^ height^ y^ y^ )
( set initial y: )
.Screen/y DEO2 ( ws: x* width* height* y* )
.Screen/y DEO2 ( ws: x^ width^ height^ y^ )
( calculate and stash vertical limit )
ADD2 ( ws: x* width* limit-y* )
STH2 ( ws: x* width* / rs: limit-y* )
ADD2 ( ws: x^ width^ limit-y^ )
STH2 ( ws: x^ width^ / rs: limit-y^ )
```
now, we might be able to stash also the width and 'x', as we need them afterwards in their original order (first x, then width )
```
STH2 ( ws: x* / rs: limit-y* width* )
STH2 ( ws: / rs: limit-y* width* x* )
STH2 ( ws: x^ / rs: limit-y^ width^ )
STH2 ( ws: / rs: limit-y^ width^ x^ )
```
in theory, the first part of our subroutine could look like:
```
@draw-tiles ( x* y* width* height* addr* -- )
@draw-tiles ( x^ y^ width^ height^ addr* -- )
( set tile address )
.Screen/addr DEO2 ( ws: x* y* width* height* )
.Screen/addr DEO2 ( ws: x^ y^ width^ height^ )
ROT2 ( ws: x* width* height* y* )
DUP2 ( ws: x* width* height* y* y* )
ROT2 ( ws: x^ width^ height^ y^ )
DUP2 ( ws: x^ width^ height^ y^ y^ )
( set initial y )
.Screen/y DEO2 ( set initial y, ws: x* width* height* y* )
.Screen/y DEO2 ( set initial y, ws: x^ width^ height^ y^ )
( calculate and stash limit-y )
ADD2 ( ws: x* width* limit-y* )
STH2 ( ws: x* width* / rs: limit-y* )
ADD2 ( ws: x^ width^ limit-y^ )
STH2 ( ws: x^ width^ / rs: limit-y^ )
( stash width and x )
STH2 STH2 ( ws: / rs: limit-y* width* x* )
STH2 STH2 ( ws: / rs: limit-y^ width^ x^ )
&loop-y
( prepare and draw row )
( retrieve x )
STH2r ( ws: x* / rs: limit-y* width* )
STH2r ( ws: x^ / rs: limit-y^ width^ )
( retrieve width )
STH2r ( ws: x* width* / rs: limit-y* )
STH2r ( ws: x^ width^ / rs: limit-y^ )
;draw-tiles-in-a-row JSR2
```
@ -334,7 +334,7 @@ we can think we could replace these instructions with STH2kr:
&loop-y
( prepare and draw row )
( retrieve x )
STH2kr ( ws: x* / rs: limit-y* width* x* )
STH2kr ( ws: x^ / rs: limit-y^ width^ x^ )
```
but then we can't retrieve the width because the x is still at the top of the return stack!
@ -344,35 +344,35 @@ oh, many difficulties, but for the sake of the stack wrangling example, let's co
how can we put the width at the top of the return stack? maybe with a swap applied to the return stack:
```
SWP2r ( ws: x* / rs: limit-y* x* width* )
SWP2r ( ws: x^ / rs: limit-y^ x^ width^ )
```
then we can then retrieve the width and use it:
```
STH2kr ( ws: x* width* / rs: limit-y* x* width* )
;draw-tiles-in-a-row JSR2 ( ws: / rs: limit-y* x* width* )
STH2kr ( ws: x^ width^ / rs: limit-y^ x^ width^ )
;draw-tiles-in-a-row JSR2 ( ws: / rs: limit-y^ x^ width^ )
```
what's next? add 8 to y, and check if it's less than the limit. the first part goes without problems:
```
.Screen/y DEI2 #0008 ADD2 DUP2 ( add 8 to y; ws: y* y* / rs: limit-y* x* width* )
.Screen/y DEO2 ( store new y; ws: y* / rs: limit-y* x* width* )
.Screen/y DEI2 #0008 ADD2 DUP2 ( add 8 to y; ws: y^ y^ / rs: limit-y^ x^ width^ )
.Screen/y DEO2 ( store new y; ws: y^ / rs: limit-y^ x^ width^ )
```
in order to get the limit into the working stack for the comparison, we have to rotate the return stack:
```
ROT2r ( ws: y* / rs: x* width* limit-y* )
STH2kr ( ws: y* limit-y* / rs: x* width* limit-y* )
ROT2r ( ws: y^ / rs: x^ width^ limit-y^ )
STH2kr ( ws: y^ limit-y^ / rs: x^ width^ limit-y^ )
```
but ah, before doing the comparison and jumping, we should rearrange the return stack so that it corresponds to the ordering we had at the beginning of the loop:
```
SWP2r ( ws: y* limit-y* / rs: x* limit-y* width* )
ROT2r ( ws: y* limit-y* / rs: limit-y* width* x* )
SWP2r ( ws: y^ limit-y^ / rs: x^ limit-y^ width^ )
ROT2r ( ws: y^ limit-y^ / rs: limit-y^ width^ x^ )
```
now we can do the comparison and jump:
@ -390,43 +390,43 @@ POP2r POP2r POP2r
after all this, our subroutine would look like the following:
```
@draw-tiles ( x* y* width* height* addr* -- )
@draw-tiles ( x^ y^ width^ height^ addr* -- )
( set tile address )
.Screen/addr DEO2 ( ws: x* y* width* height* )
.Screen/addr DEO2 ( ws: x^ y^ width^ height^ )
ROT2 ( ws: x* width* height* y* )
DUP2 ( ws: x* width* height* y* y* )
ROT2 ( ws: x^ width^ height^ y^ )
DUP2 ( ws: x^ width^ height^ y^ y^ )
( set initial y )
.Screen/y DEO2 ( set initial y, ws: x* width* height* y* )
.Screen/y DEO2 ( set initial y, ws: x^ width^ height^ y^ )
( calculate and stash limit-y )
ADD2 ( ws: x* width* limit-y* )
STH2 ( ws: x* width* / rs: limit-y* )
ADD2 ( ws: x^ width^ limit-y^ )
STH2 ( ws: x^ width^ / rs: limit-y^ )
( stash width and x )
STH2 STH2 ( ws: / rs: limit-y* width* x* )
STH2 STH2 ( ws: / rs: limit-y^ width^ x^ )
&loop-y
( prepare and draw row )
( retrieve x )
STH2kr ( ws: x* / rs: limit-y* width* x* )
STH2kr ( ws: x^ / rs: limit-y^ width^ x^ )
( retrieve width )
SWP2r ( ws: x* / rs: limit-y* x* width* )
STH2kr ( ws: x* width* / rs: limit-y* x* width* )
;draw-tiles-in-a-row JSR2 ( ws: / rs: limit-y* x* width* )
SWP2r ( ws: x^ / rs: limit-y^ x^ width^ )
STH2kr ( ws: x^ width^ / rs: limit-y^ x^ width^ )
;draw-tiles-in-a-row JSR2 ( ws: / rs: limit-y^ x^ width^ )
.Screen/y DEI2 #0008 ADD2 DUP2 ( add 8 to y )
.Screen/y DEO2 ( store new y )
( retrieve limit-y )
ROT2r ( ws: y* / rs: x* width* limit-y* )
STH2kr ( ws: y* limit-y* / rs: x* width* limit-y* )
ROT2r ( ws: y^ / rs: x^ width^ limit-y^ )
STH2kr ( ws: y^ limit-y^ / rs: x^ width^ limit-y^ )
( rearrange return stack )
SWP2r ( ws: y* limit-y* / rs: x* limit-y* width* )
ROT2r ( ws: y* limit-y* / rs: limit-y* width* x* )
SWP2r ( ws: y^ limit-y^ / rs: x^ limit-y^ width^ )
ROT2r ( ws: y^ limit-y^ / rs: limit-y^ width^ x^ )
LTH2 ,&loop-y JCN ( jump if x is less than the limit )
@ -461,8 +461,8 @@ we'll declare the following labels for our variables, after the RTN that ends th
now, we start the subroutine in the same way as before, setting the address for our sprite:
```
( initial ws: x* y* width* height* addr* )
.Screen/addr DEO2 ( ws: x* y* width* height* )
( initial ws: x^ y^ width^ height^ addr* )
.Screen/addr DEO2 ( ws: x^ y^ width^ height^ )
```
then, we just store the next values in relative addresses:
@ -482,12 +482,12 @@ we can then set the initial y and calculate the vertical limit, using the values
```
( set initial y )
,&y LDR2 DUP2 ( ws: y* y* )
.Screen/y DEO2 ( ws: y* )
,&y LDR2 DUP2 ( ws: y^ y^ )
.Screen/y DEO2 ( ws: y^ )
( calculate limit-y )
,&height LDR2 ( ws: y* height* )
ADD2 ( ws: limit-y* )
,&height LDR2 ( ws: y^ height^ )
ADD2 ( ws: limit-y^ )
,&limit-y STR2 ( ws: )
```
@ -517,9 +517,9 @@ compare this with the "concrete" version we developed above, it's very similar i
the complete subroutine would look like the following:
```
@draw-tiles ( x* y* width* height* addr* -- )
@draw-tiles ( x^ y^ width^ height^ addr* -- )
( set tile address )
.Screen/addr DEO2 ( ws: x* y* width* height* )
.Screen/addr DEO2 ( ws: x^ y^ width^ height^ )
( store values )
,&height STR2
@ -528,12 +528,12 @@ the complete subroutine would look like the following:
,&x STR2
( set initial y )
,&y LDR2 DUP2 ( ws: y* y* )
.Screen/y DEO2 ( ws: y* )
,&y LDR2 DUP2 ( ws: y^ y^ )
.Screen/y DEO2 ( ws: y^ )
( calculate vertical limit )
,&height LDR2 ( ws: y* height* )
ADD2 ( ws: limit-y* )
,&height LDR2 ( ws: y^ height^ )
ADD2 ( ws: limit-y^ )
,&limit-y STR2 ( ws: )
&loop-y

View File

@ -463,18 +463,18 @@ additionally, it has a working loop! written in one of several ways of implement
the state of both the working (ws) and the return (rs) stacks is shown in the comments after almost every step. the top of the stacks is located at their right.
an asterisk (*) after a value name indicates that it corresponds to a short.
a caret (^) after a value name indicates that it corresponds to a short.
```
@draw-horizontal-line ( x* y* length -- )
@draw-horizontal-line ( x^ y^ length -- )
( beginning )
( ws: x* y* length / rs : )
( ws: x^ y^ length / rs : )
( store length in return stack )
STH ( ws: x* y* / rs: length )
STH ( ws: x^ y^ / rs: length )
( set initial coordinates )
.Screen/y DEO2 ( ws: x* / rs: length )
.Screen/y DEO2 ( ws: x^ / rs: length )
.Screen/x DEO2 ( ws: / rs: length )
( retrieve length from return stack )

View File

@ -378,16 +378,18 @@ let's build a subroutine that draws the 6 tiles of the paddle in the correspondi
we could have the subroutine receiving as argument the x and y position of its top left corner:
```
@draw-paddle ( x* y* -- )
@draw-paddle ( x^ y^ -- )
```
but let's add the color byte as well:
```
@draw-paddle ( x* y* color -- )
@draw-paddle ( x^ y^ color -- )
```
on one hand this would allow us to change colors when e.g. hitting the ball, but more importantly this will allow us to clear the paddle before moving it, as we have done in previous days.
a reminder that we are using the convention of adding a caret (^) after the name of a value to indicate it's a short, and an asterisk (*) to indicate it's a short working as a pointer (i.e. an address in program memory)
on one hand this second version would allow us to change colors when e.g. hitting the ball, but more importantly this will allow us to clear the paddle before moving it, as we have done in previous days.
in principle the subroutine should be straightforward: we have to set the x and y coordinates of each of the tiles, relative to the given x and y coordinates, and draw them with the given color.
@ -420,7 +422,7 @@ however, in this case i'll go for the first approach, and i'll manually set the
additionally, i'll save the color in the return stack:
```
@draw-paddle ( x* y* color -- )
@draw-paddle ( x^ y^ color -- )
( save color )
STH
@ -484,7 +486,7 @@ now we can call it in e.g. the following way and get our paddle drawn:
it would be up to discussion if there are more efficient ways of drawing it. for example, we could have a generalized draw-sprite that receives the initial address of a set of tiles, and the width and height in terms of number of tiles:
```
@draw-sprite ( x* y* width height addr* color )
@draw-sprite ( x^ y^ width height addr* color )
```
it could work similar to the draw-tiles subroutine we created above.
@ -1578,7 +1580,7 @@ RTN
## draw-paddle
```
@draw-paddle ( x* y* color -- )
@draw-paddle ( x^ y^ color -- )
( save color )
STH