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.
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:
byte x = 0
for byte i, i < 8, i++ do
x += i
#00 ,&x STR
NIP ( get rid of &x )
,&x STR ( store incremented value in x )
GTHk ,&loop_begin JMP
while x < 8 do
#00 ,&x STR
GTHk POP ,&while_begin JMP ( Pop gets rid of x from DUP )
byte x = 0
if x == 1 do
x = 3
x = 1
#00 ,&x STR
#01 EQU ,&if_true JMP
( if false )
#01 ,&x STR
#03 ,&x STR
return 3 + 1
#03 #01 ADD ( i mean optimizer would evaluate this but you get the idea )
-- FUNCTION W/ ARGUMENTS
def my_func(byte x, byte y)
return x + y
byte x = 4
#04 ,&x STR
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.
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!
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