If you don't know what a B_CALL does, look for it on WikiTI or in TI's official documentation. Most of the important ones are documented, including _CreateRList. It's actually documented in both, but I can only directly link to WikiTI's documentation (which is slightly better anyways).
Do you actually need to extract the first three characters as a substring, or are you merely interested in checking if it starts with a specific three-character-long string?
If it's the latter, Matrefeytontias is partially correct in suggesting that there's a command for that. The Equ►String() command checks if two strings passed as arguments are equal, returning zero if so and nonzero otherwise. The reason why he's only partially correct is because, as you can see from that description, the command isn't made to check if one string starts with another. But if you're comfortable using the technically undefined return value when the strings aren't equal, you can check this. With the current implementation, when the two strings differ, the return value is actually a pointer to the first character in the second string that differs from the character at the same position in the first string. So the following code would work to check if a string starts with "PTR", but isn't guaranteed to work in future versions of Axe:
"PTR"→Str0 !If Equ►String(<string>,Str0)?-3-Str0 .Starts with "PTR" End
For reference, the second line is an optimized version of: If (Equ►String(<string>,Str0)=0) or (Equ►String(<string>, Str0)=(Str0+3)).
If it's the former, extracting a substring of predetermined length is somewhat straightforward, despite Axe lacking a built-in substring command. Extracting a substring simply comes down to copying the characters you want to a new area of memory and making sure the new substring data ends with a null terminator byte. So to extract a 3-byte substring from the front of a string, you'd need to reserve 4 bytes of memory and copy it, perhaps like this:
Allocate the buffer inside the program with something like Buff(256)→Str0. Note that this will not work if you compile your code as an application, and that Buff( is really the det( token renamed.
Allocate the buffer externally by using a free static RAM reference like L1 in place of Str0, or make Str0 refer to the reference, like L1→Str0. As long as you can find the free RAM space for it, this is generally the preferred option. Note that you do not perform any active allocation; the "allocation" simply entails making a note that nothing else should be trying to use that area of RAM at the same time.
Allocate the buffer externally by asking the OS to allocate space for the buffer at runtime, like GetCalc("tmpBUF",256)→S. Note that since this is allocated at runtime, you have to save the reference in a variable instead of a static pointer like Str0. This may also fail if the space cannot be allocated due to not having enough free user RAM (in which case S will be zero), a problem which does not affect the other two options. tmp is really the w token (2nd+9), added in Axe 1.2.0, which results in the variable automatically being deleted when your program finishes.
I personally don't see much point unless the browser allows windows to remain always on top, though. Else if it goes in the background when clicking on a maximized window, then it pretty much defeats the point of having a pop out option instead of fullview
I do exactly this, I have a utility that always-on-top-ifies windows.
Request: change the "Full View" option to "Pop-out", or add it as a new option. Full view mainly seems useful when you want a separate OmnomIRC window to look at, but this:
I'm assuming that you're using 8x8, Link's Awakening-style graphics. If not, disregard this post entirely.
I would suggest grabbing as much as you can from this thread, or any similar threads you can find, and filling in anything left with placeholder graphics. That should allow you to get pretty far in development before needing to come back and spend more time on the graphics.
Okay, I think I've implemented a fix for the A=-64 behavior. Grab the new code (I made a number of changes, so I'd recommend just re-grabbing the whole thing) and try again?
Whoops, I think I see where I went wrong. Try changing jr c,Mul_A_DE_Custom_ANeg64 (third instruction after Mul_A_DE_Custom_ANeg) to jr z,Mul_A_DE_Custom_ANeg64 and see if that fixes it, at least partially.
So here's what I came up with. My experience with multiplication routines told me that a LUT in this case might be more trouble than it's worth, so I didn't try that. Instead, I mirrored a lot of the logic in Xeda's routine, but added even more case-specific optimizations; namely, handling each of A=64 and A=-64 specially to make them faster and to implement the clamping of 64*512 and -64*-512 to 32767.
It's probably pretty unfair to compare my routine to Xeda's original, because I'm guessing Xeda whipped up her routine in like 10 minutes and didn't optimize for speed that crazily, whereas I took more like 100 minutes, was optimizing for speed crazily, and had her code as a reference. But I'll compare them anyways.
A
Runer
Xeda
A==-64
7*(DE<0)+133
248
-64<A<0
6*bitcount(A)+(9*(A%2))+201
6*bitcount(A)+(9*(A%2))+236
A==0
52
25
A==1
96
136
A==2
112
143
A==3
127
158
0<A<64
16*lg(A)+(6*bitcount(A))+(9*(A%2))+97
16*lg(A)+(6*bitcount(A))+(9*(A%2))+121
A==64
7*(DE<0)+95
223
So about 25-40 cycles faster for most cases and about 100 cycles faster for A=-64 and A=64, but about 25 cycles slower for A=0. And don't forget that this routine also clamps to 32767, whereas the previous did not. So overall, I'd say the speed optimization was quite a success. And with all the speed optimization and the added clamping, I only increased the size from 65 to 89 92 bytes, so not too bad. I just hope it actually works, because I haven't tested it one bit! I've debugged it a fair amount now and it might fully work!
Before I try my hand at this, is there some distribution that can be expected of the input values? Because if you really want this micro-optimized, any input tendencies should be known so they can possibly be taken advantage of.
Both Freq() and Pause have been around for a long time and have been used by a lot of people with success, so I'm pretty sure they aren't buggy. I suspect the bug was something else.
And a helpful reminder: in all of these cases, make sure the string always ends in a zero byte before you try to perform any operations like display or length(), or the results could be quite unexpected!
But buffer overflows are fun!
That aside, have you ever thought about writing some advanced documentation on how Axe works at a lower level? I'm sure many people would find the deeper knowledge they could glean from that quite useful.
That sounds like it would take a lot of time and effort, which is probably why I haven't ever thought about doing it. But I tend to leave these mega-posts in lots of question topics, going way more in depth than was asked. Maybe all of my mega-posts could be compiled into some semblance of what you describe.
Somebody should do that
* Runer112 looks around, seeing nobody and realizing that that somebody is probably himself
And a helpful reminder: in all of these cases, make sure the string always ends in a zero byte before you try to perform any operations like display or length(), or the results could be quite unexpected!
But buffer overflows are fun!
That aside, have you ever thought about writing some advanced documentation on how Axe works at a lower level? I'm sure many people would find the deeper knowledge they could glean from that quite useful.
That sounds like it would take a lot of time and effort, which is probably why I haven't ever thought about doing it. But I tend to leave these mega-posts in lots of question topics, going way more in depth than was asked. Maybe all of my mega-posts could be compiled into some semblance of what you describe.
Due to the challenges and costs that would be entailed by dynamic memory allocation, strings and other data types that might seem like they should be dynamically sized are in fact not. They will only have as much space available as you allocate for them.
In this case, you've allocated enough memory for a string of length zero (which is actually one byte, due to the zero byte that marks the end of the string). As you can imagine, this is not particularly useful, and as soon as you start trying to "append" to this string, you start overwriting whatever comes after it in memory. If you try to "append" the string "HELP", the 'H' will overwrite the zero byte that marks the end of the string, and the characters 'E', 'L', and 'P' will overwrite whatever three bytes come next in memory. In this case, they happen to be the next three bytes of data in your program: the first three bytes of the string "Unknow command" (Side note: the correct spelling is "unknown"). So when you later try to print that string, the first three bytes have been overwritten with "ELP" and that's what you see.
The usual way to fix this is to allocate a fixed size for the string buffer ahead of time (and don't allow the string to go over that size). There are three primary options:
Allocate the buffer inside the program with something like Buff(256)→Str0. Note that this will not work if you compile your code as an application, and that Buff( is really the det( token renamed.
Allocate the buffer externally by using a free static RAM reference like L1 in place of Str0, or make Str0 refer to the reference, like L1→Str0. As long as you can find the free RAM space for it, this is generally the preferred option. Note that you do not perform any active allocation; the "allocation" simply entails making a note that nothing else should be trying to use that area of RAM at the same time.
Allocate the buffer externally by asking the OS to allocate space for the buffer at runtime, like GetCalc("tmpBUF",256)→S. Note that since this is allocated at runtime, you have to save the reference in a variable instead of a static pointer like Str0. This may also fail if the space cannot be allocated due to not having enough free user RAM (in which case S will be zero), a problem which does not affect the other two options. tmp is really the w token (2nd+9), added in Axe 1.2.0, which results in the variable automatically being deleted when your program finishes.
If you want a dynamically-sized string, you can do that by either storing it in an OS variable and resizing it, or using the OS edit buffer. Both are much more complicated options, and unless you absolutely cannot use a fixed-size buffer, I would steer clear of them for now.
And a helpful reminder: in all of these cases, make sure the string always ends in a zero byte before you try to perform any operations like display or length(), or the results could be quite unexpected!
When I tested it, it seemed like you only allowed 16 different angles per quadrant. You could easily get 16 unique lines out of that by either extending the line a bit or using a custom fixed-point coordinate line routine.
EDIT: Apparently the number is 32. Still might be feasible.