Pushes the value of the program counter to the return-stack […]
Is it possible to do this manually, without creating a new label? If so, I think it should be possible to create a combination macro of JCN and JSR, which might be pretty convenient.
okay, got it! The macro works, but I eschewed it in favor of just writing it normally because each loop call took like a dozen ops and .03% of memory or something like that.
If I have a zero-page variable that’s like @game state $8, is there a way I can LDZ and STZ all 8 bytes at once?
My goal for my training program is a simple conway’s game of life, and I was planning to store the cell states as 8 bytes of single bits to make an 8x8 grid, and use bit shifts to look at the neighbors (<<1, <<*, etc), but I can’t see how to load all the data in at once, or if I should go about it a different way. having labels for each row seems tedious.
Whenever you see something that looks like [ LIT &var $1 ], it means that I’m storing my variable directly in memory
What do you mean exactly? Is this a storage and definition simultaneously?
But I wouldn’t load all of the game state on the stack at once, but operate 8 cells at a time. But try it out for yourself, see what works best.
Game of Life is a cellular Automata, the means you need 2 game states, you read one and write onto the next frame. The way to do this fast usually, is by simply changing the state pointers, from one frame to the other, without ever clearing the world.
It might be a bit too advanced for now, let’s keep this for later.
I ended up making a somewhat verbose pseudo-linked list for each row. Now, how do I set a specific bit of a byte to be 0? I imagine it has to do with xor…
almost! to set a specific bit to 0 (in some contexts that’s called resetting the bit) you would use an AND “mask” with all 1s except for the target position.
the bits where the mask is 1 will be left as they are (0 AND 1 is 0, 1 AND 1 is 1) and the bit(s) where the mask is 0 will be forced to be 0 (0 AND 0 is 0, 1 AND 0 is 0)
e.g. to set the least significant bit to 0, you can do:
#fe AND ( reset the lsb )
EOR (XOR) would help you to toggle the bits where the “mask” is 1 (0 XOR 1 is 1, 1 XOR 1 is 0), and leave the other bits as they are (0 XOR 0 is 0, 1 XOR 0 is 1)
e.g. to toggle the least significant bit:
#01 EOR ( toggle the lsb )
and for the sake of completeness, ORA (OR) would allow you to set a specific bit to 1 (setting the bit, in some contexts), “forcing” it to be 1 where the mask is 1 (0 OR 1 is 1, 1 OR 1 is 1), leaving the other bits as they are (0 OR 0 is 0, 1 OR 0 is 1)
Ah nice. I remember seeing the “a clever hack” comment and not understanding what PC meant. I guess it didn’t occur to me to check if it was mentioned elsewhere in the article Maybe the comment can be changed to “a clever hack to get the current program counter” anyway?
I ended up with the following to do a conditional JSR2. Let me know if there is a better way!
perhaps this is a backwards way of figuring this out, but let me see if I understand the following structures in higher level programming translation into uxn properly:
-- FOR
byte x = 0
for byte i, i < 8, i++ do
x += i
end
&x $1
#00 ,&x STR
#08 #00
&loop_begin
,&x LDR
ADDk
NIP ( get rid of &x )
,&x STR ( store incremented value in x )
INC
GTHk ,&loop_begin JMP
POP2
-- WHILE
byte x
while x < 8 do
x++
end
&x $1
#00 ,&x STR
#08
&while_begin
,&x LDR
INC
DUP
,&x STR
GTHk POP ,&while_begin JMP ( Pop gets rid of x from DUP )
-- IF
byte x = 0
if x == 1 do
x = 3
else
x = 1
end
&x $1
#00 ,&x STR
,&x LDR
#01 EQU ,&if_true JMP
( if false )
#01 ,&x STR
&if_true
#03 ,&x STR
-- FUNCTION
def my_func()
return 3 + 1
end
...
my_func()
@my_func
#03 #01 ADD ( i mean optimizer would evaluate this but you get the idea )
JMP2r
...
;my_func JSR2
-- FUNCTION W/ ARGUMENTS
def my_func(byte x, byte y)
return x + y
end
...
byte x = 4
my_func(x, 6)
@my_func
ADD
JMP2r
...
&x $1
#04 ,&x STR
,&x LDR
#06
;my_func JSR2
of course, these are simple examples, more complex stuff would be much harder. gotta keep the stack under control…
So if I understand this, this is like, a foreach loop? it loads the value and then increments the address, and then loads the next byte? and then the $1 is a null byte at the end, which counts as a false for the JCN boolean?
I have a question.
The memory space of 10000h bytes, from 0000 to FFFF.
Is it an absolute requirement?
If implementing uxn on a device which itself has 10000h or less RAM available then this is not possible.
However most programs probably don’t need all memory.
Is there some convention used of how data is allocated in compiled programs? So that it would be safe to implement an uxn with less memory, skip some memory region, and expect at least some programs to work?
(I’m not actually considering implementing such a thing now. Just wondering.)
The convention is to use the most memory that you can, but like you said, most roms won’t be impacted by this at all. The convention is to use a page for the devices, but everything else is somewhat flexible.
For the arduino port, what I did is to use shallower stacks, so instead of a whole page, I use 80 bytes per stack, and only 1800 bytes of memory. It allows me to run most little roms.
Heyo, just dipping my toes into uxn with the lovely tutorial from compudanzas.net and having some trouble with the raw character rune. uxnasm returns “Unknown token: 'h” on the following bit of code.
( hello.tal )
|0100 LIT 'h #18 DEO
LIT 'e #18 DEO
LIT 'l #18 DEO
LIT 'l #18 DEO
LIT 'o #18 DEO
#0a #18 DEO ( newline )
If I change the single quote to double quotes it assembles just fine in uxnasm.
( hello.tal )
|0100 LIT "h #18 DEO
etc, etc.
Neither versions assemble in drifblim for me. the single quote version returns the same “Unknown token” error and the double quote version just returns an error with the name of the input file.
I’m trying to do this on Windows, so that is probably the root of the problem but any suggestions would be appreciated.
That’s a bit tricky, your drifblim file needs to look like this:
I haven’t written an interface to the project mode, it only writes this file directly in the zero-page. If this is all too cryptic, you should use the normal interface:
uxncli drifblim.rom input.tal output.rom
Ah! Yes, the ' and " were exactly the same behaviour, so I’ve removed the ' since it was creating confusion. Whenever you see single quotes in docs, you should use double-quotes, sorry about that.
Ah, I’ve got it. I also needed to rename drifblim.rom to launcher.rom and run it with uxnemu launcher.rom. Now whenever I want to refresh the screen I have to press F4 and the source gets assembled again. Great! I really love this development flow Thanks!
just updated the online tutorial to reflect this — i wasn’t aware the change had happened for sure!
thank you and sorry @A_Cormorant! i hope you enjoy what comes next
Is there any convention around clearing the screen every frame?
I noticed that none of the uxntal I’ve seen does a full redraw every frame (except in special cases). Instead, for moving sprites people do the pattern “clear sprite, update, draw new sprite.” Is it un-uxn to redraw everything every frame?
It’s totally fine to do it, there’s a few apps that do fullscreen clearing, like Turye, but not through the screen vector. Just don’t do it pixel-per-pixel, depending on your program, you can do 16 tiles vertically at once, and wipe horizontal sections of the screen. That should be fast enough for the DS and GBA to handle.
Left does a 8 tiles high fast wipe that you could inspire yourself from. Start by saving the screen size to wipe, at the beginning of your program, so you don’t recalculate each frame:
.Screen/height DEI2 #06 SFT2 NIP INC ;draw-textarea/height STA
.Screen/width DEI2 #03 SFT2 NIP ;draw-textarea/width STA