Porting ARM32 BBC BASIC to ARM64
Rick Murray (539) 13742 posts |
Isn’t that exactly how it always is?
What manipulating strings? It’s basically a byte array and fiddling that is slightly more readable than doing it in assembler. ;) Speaking of plain-C strings, I had to bodge together my own string copy routine as I forgot that you can’t even rely upon strncpy() to hand back valid strings and I forgot to add a terminator. So I made a function to do that so I need to only call that (in place of strncpy) and it’ll always hand back a valid string.
Never! 1 I’m talking about the standard C library, not Acorn’s implementation of it. |
tymaja (278) 137 posts |
The white space thing is so annoying though! (and worse, the needing to use the ‘same’ type of white space (tabs versus space) or you get errors that make no immediate sense!) |
tymaja (278) 137 posts |
.bq “!Zap running on ARM 64 :-))” That is definitely something that needs a C conversion, or an emulator! 🤪 :) |
Chris Mahoney (1684) 2160 posts |
By default, yes, but it has a thing called “native AOT” which (apparently) compiles to native code. I’ve never had a need to actually try that myself. I believe it can compile to a self-contained executable that doesn’t require a separate runtime.
I did say I couldn’t imagine writing RISC OS in it :) |
tymaja (278) 137 posts |
I do agree (and always have since I first got the ARMv8 manual years ago (IIRC around the time of the iPhone 5S release!); I do think there is scope for ARM64 to be programmed cleverly; one thing that caught my eye is the bitmask immediates – I’m really only using them for variable length %111111s, but there is scope for repeating patterns. I feel such patterns could be useful for masking out repeating bit patterns in video codecs, 3d graphics etc. But I do agree it has lost some of the ‘magic’. And I just came up against the ‘LSL/LSR by register uses the low 6 bits to decide on shift’ thing. LSL X1, where X1=66, will shift left by two. Great fun for floating point! The port continues. I cannot believe how much progress I have made (even assembling and calling ARM64 code from BASIC) and most keywords are now implemented, as is most of floating point. After this, I will only use ARM64 for speed critical inner loops! 😀 |
Clive Semmens (2335) 3274 posts |
😀 I only ever used ARM26 for speed critical inner loops! 😀 (I’ve only ever used ARM32 for tiny little fragments of code to test that I understood how it worked, to make sure I documented it correctly…) |
tymaja (278) 137 posts |
A link to an image if embedded one doesn’t work: It runs faster than the same program on my Pi4 too. A challenge is the integration with the host OS. I want it to remain as close to ARM32 BBC BASIC as possible, so I am doing more work on the ‘SWI code’. I am also aiming to maintain compatibility with the VDU drivers, which is a big job – it requires nearly half the kernel workspace among other things!. All code beyond the core BASIC code itself is being done in C :) |
Clive Semmens (2335) 3274 posts |
I remember, long, long ago, creating that image (probably at somewhat lower resolution…) on a BBC Model B. I forget how long it took, but it wasn’t very long. I can probably find photos of the screen, possibly of the program, too. |
tymaja (278) 137 posts |
Mandelbrot sets are definitely ‘good value’ for producing something interesting from a small amount of code! My deliberately unoptimised code in the screenshot has a few landmarks for my BASIC-Aarch64: Lines 40-90 (using ‘VDU’ to read OS_ReadVduVariables’) actually work properly, as they would on RISC OS (MODE 60 is 1280×400×8bpp, with eigenvalues like MODE 15). The ‘VDU drivers’ used in the screenshot above are my own, and support all RISC OS numbered MODEs (as well as some extra ones I made after setting maxmode to 63). The VDU drivers support coloured text etc, and also palettes (the flashing colours in MODE 2, MODE 12 work as expected); I am currently rewriting the VDU drivers to be more RISC OS-like, after which I will add graphics support (DRAW etc). I am glad I used a ‘SWI’ macro throughout my ARM64 BASIC code, as it makes such changes easier. The VDU drivers are in C (actually C++ because I use a class in one place, but everything else is pure C, and I will replace that class soon). Everything except the core BASIC code itself is in C. This has been a good way to finally learn C / C++. Next steps are: Learning C (and jumping back and forth between C and ARM64) has been really interesting so far. One advantage of coding BASIC into ARM64 from real ARM (ARM32) is that I am getting a good understanding of how ARM BBC BASIC works. Unfortunately, my work is useless for RISC OS itself (although, if a 64-bit Kernel was to appear, I could port my code to (whatever is equivalent to the 32-bit ARM SWI interface) in a day or two, so we could the have ARM BBC BASIC added to the 64-bit kernel, which could be useful (as it was back in 1985 – BASIC predates even Arthur!) Once I have BBC BASIC running well, without glitches etc, I am going to convert almost all of it to C code, leaving only a few parts in ARM64 code (the bits that jump around in ways that C really wouldn’t like). Once I get to this stage, I will post back in my thread (about adding long strings etc to ARM32 BBC BASIC). I am aiming to have ARM BBC BASIC, with all the nuances (such as undocumented behaviours when doing %0101001 (with over 32 bits listed), or stuff such as variable = variable + 1 (not causing an error as you would expect, rather initialising the variable to zero!) ported into C with a small amount (a few %) in ARM code. This could then actually run on RISC OS :) |
Alan Adams (2486) 1140 posts |
variable = variable is a valuable way to ensure a variable exists, avoiding en error, and with a known value (zero, or "" if a string). I hadn’t met the example you quoted though, and I would have expected that to end up with one. |
tymaja (278) 137 posts |
I will check out variable = variable to see bow that works (I wasn’t aware of that); What variable = variable + 1 does is set variable to ‘1’ (it initialises variable to 0, then adds 1). It the. Works as expectd (incrementing by 1). I spent ages trying to figure out where I messed up my code, then powered up the Pi4 and tested it out – and it also did it on RISC OS itself! |
Clive Semmens (2335) 3274 posts |
Has every version of BBC BASIC always done that? It’s something I’ve never tried, because it’s horrible code – if I’d written the spec for the language, it’d throw an error at that point if variable hadn’t already been assigned a value. Or, being mischievous, give it an FP value of “undefined”, or if that’s not available, “NaN”. Or, even more mischievously, a random FP value… |
Steve Fryatt (216) 2095 posts |
I think so: Which is why I find |
tymaja (278) 137 posts |
I haven’t looked at that bit of the code recently, but I only found it out when debugging (I thought it was a fault in my understanding, or a messed up carry flag – took a few hours to try it out on RISC OS!); If I recall correctly (and I may be wrong, as I have been studying the VDU drivers recently, rather than BASIC), but I think the var=var+1 thing goes something like: var=var + 1 What is interesting is that the variable is created even if there is a fault later, so … string$ = LIST RENUMBER -&12+SQR(-1) ends up with string$=“” when you do LVAR (I think. If not, there are other examples and I can find them again!) |
Rick Murray (539) 13742 posts |
Yes, it is. And I agree with tymaja that BASIC probably does “this is an assignment, let’s make somewhere to put the result” followed by “look up this variable” and it just happens that the one being looked up is the one it just created. This is, of course, likely another of those edge cases that falls into the “because you can <> you should”. |
Chris Hall (132) 3544 posts |
Presumably fred = var + 1 does give an error ‘No such variable’ as does var = var + 1 – it is only var+=1 or var+=0 that creates the variable. |
Clive Semmens (2335) 3274 posts |
BASIC V – Acorn, 1989 as running on my Pi4, does indeed not barf at var = var + 1, and does indeed set var to 1. It does, however, barf at var += 1 if var doesn’t already exist. |
Steve Fryatt (216) 2095 posts |
Are you sure? I was under the impression that it was only
Indeed. As I previously noted, the only place that I’ve seen this used before is in the One Line Programs from Acorn User. There, the fact that I can just about see the appeal of
to ensure that a variable exists in something like a library, but can’t help but think that there are probably better ways in most cases… |
tymaja (278) 137 posts |
I am still intrigued as to what ‘var% = var%’ does? I would guess that it does ‘var% remains unchanged if it exists, or is created and initialised to zero if it doesn’t exist’? (if so, it is another example of ‘nuances / undefined behaviour in BBC BASIC that have to stay or they will break older software’); It would be easy to add an ‘official’ new syntax to check if a variable exists though, which could work with any variable (I will test on RISC OS basic what happens if you do array()=array() where array() doesn’t exist. That must generate an error??! Variable handling in BASIC works by looking up a new variable name using a function ‘LV’, which returns either (the variable data directly or via a pointer), or (the registers set up to create a new variable). You can tell which it is via the processor flags 😂, which are set so you can tell whether the result is either At this point. You can use the data, or throw ‘no such variable’. It could be fairly trivial to ‘overload’ an existing token/ keyword to check if a variable exist#; it would just need to call LV, and return TRUE or FALSE depending if it exists or not. One step furtner could be ‘is it a potentially valid name, or not); I won’t propose which keyword or syntax, but for example, you could choose any keyword that would normally throw an error (and it is easy to check in the code to make sure you aren’t breaking anything, by choosing one that invariably throws an error if used in this way). I haven’t checked the code, and wouldn’t use RUN for this! but : exists% = RUNvariable% exists%= RUN array() |
Clive Semmens (2335) 3274 posts |
That’s certainly the behaviour in the one version of BBC BASIC I’m able to check. A wee wrinkle I’ve not yet checked (anyone who cares can check themselves?) would be whether the resident integers ( |
Rick Murray (539) 13742 posts |
I believe that was an intended use back in the Beeb days. |
Rick Murray (539) 13742 posts |
Found it. BBC User Guide page 66:
|
Clive Semmens (2335) 3274 posts |
How about CTRL-BREAK? Or SHIFT-BREAK? Yup, I wrote “my guess” but “my recollection” would have been more accurate wording. That’s surely what “Resident” means in this context? I think (but again I haven’t checked) that you don’t need A% = A% to ensure that A% exists – I think you can assume it exists and is zero if it hasn’t already been set to some other value in the current program or any earlier one. |
Steve Pampling (1551) 8124 posts |
Two taken at random from the boot sequence. B% —→ !boot.resources.configure.fontchange V% —→ runimage Anyone want a live programming grenade to play with? |
Rick Murray (539) 13742 posts |
I think… ^Break does a memory clear at OS level, doesn’t it? The values should remain after a Shift-Break as there’s simply telling the machine to reset and auto boot. There were some programs that used to reprogram the Break key to do this, so pressing Break (because on the Beeb it wasn’t possible to disable, which is why (some?) later versions had a little thingy you could turn to stop the key from being pressed) would restart the program from where you left off. Yes, A% to @% always exist. You can use LVAR on RISC OS to view them. |