OSWORD parameter block address
OSWORD (CALL &FFF1) takes a parameter block whose address is passed in Y% and X%. In 8-bit versions of BBC BASIC this is a 16-bit address with the most-significant byte in Y% and the least-significant byte in X%; in 32-bit versions it is a 32-bit address with the MS 24-bits in Y% and the LS 8-bits in X%.
But there's a problem with 64-bit versions of BBC BASIC because this scheme is capable of passing only a 40-bit signed address (MS 32-bits in Y%, LS 8-bits in X%) and whilst this is often sufficient, it isn't always. So I've been wondering how best to resolve this.
Obviously Y%:X% is in principle capable of passing a 64-bit address (32+32) but I can't see an entirely reliable way of doing that whilst maintaining compatibility with other versions. The best I can come up with is a rule such as 'if X% is a sign-extended 8-bit number it's a 32 or 40-bit address and if not it's a 64-bit address'.
But that would fail in the (admittedly unlikely) case of a 64-bit address which by chance had bits 7 to 31 all the same. Can anybody think of a better way?
But there's a problem with 64-bit versions of BBC BASIC because this scheme is capable of passing only a 40-bit signed address (MS 32-bits in Y%, LS 8-bits in X%) and whilst this is often sufficient, it isn't always. So I've been wondering how best to resolve this.
Obviously Y%:X% is in principle capable of passing a 64-bit address (32+32) but I can't see an entirely reliable way of doing that whilst maintaining compatibility with other versions. The best I can come up with is a rule such as 'if X% is a sign-extended 8-bit number it's a 32 or 40-bit address and if not it's a 64-bit address'.
But that would fail in the (admittedly unlikely) case of a 64-bit address which by chance had bits 7 to 31 all the same. Can anybody think of a better way?
0
Comments
-
In Matrix Brandy, the only reliable way to call these MOS interfaces on 64-bit platforms is to do it the RISC OS way, via SYS "OS_Word", A%, block%% (SYS can take 64-bit values in 64-bit hardware).
That said, on RISC OS, while BASIC V intercepts the old MOS entry routines in CALL and USR, BASIC VI does not so the only way to call them is via SYS.0 -
In Matrix Brandy, the only reliable way to call these MOS interfaces on 64-bit platforms is to do it the RISC OS way, via SYS "OS_Word"
So, in general, SYS "function_name" doesn't help here. Admittedly SYS numeric_value isn't inherently limited to accessing an OS API function, so that could be used. And indeed the workaround I am currently adopting does involve using SYS that way, but I'd prefer the CALL &FFF1 approach to work as well if that was possible.
In the meantime I should probably amend the BBCSDL documentation to make it clear that CALL &FFF1 isn't reliable.0 -
If you want to use the SYS (number) approach, I would personally recommend using the same numbers used by RISC OS (and Matrix Brandy). The easiest way to get the number is, in Brandy, to do:
PRINT SYS("OS_Word") - in this case, 7.0 -
If you want to use the SYS (number) approach, I would personally recommend using the same numbers used by RISC OS (and Matrix Brandy).
RISC OS is quite exceptional in this regard (I suppose because it is based on the ARM CPU which has the SWI instruction) in taking not a function pointer but an index. The only similar feature I can think of on another CPU is the Z80's RST instruction.
In RISC OS BBC BASIC, how do you call a function in a shared library?
0 -
Richard_Russell wrote: »I don't have that freedom.
0 -
Sounds like a good plan to me - as you say, similar to the FFxx case, and in the case of making OS calls, a few extra microseconds is unlikely to be an issue.0
-
Sounds like a good plan to me - as you say, similar to the FFxx case, and in the case of making OS calls, a few extra microseconds is unlikely to be an issue.
I'm thinking particularly of things like the gfxlib library, which may make thousands of SYS calls every frame - turning a few extra microseconds into possibly several milliseconds, and the frame period is typically only 16.7 ms!
But as far as I'm concerned the overriding consideration is if it ain't broke don't fix it. If CALL &FFF1 cannot be made to work reliably on a 64-bit platform, my current workaround using SYS certainly does. So why change it?
0 -
Ah yes, graphics - I was thinking of file accesses. I bet it's not even microseconds though - a nanosecond to check a number against a constant, perhaps?0
-
Richard_Russell wrote: »I'm thinking particularly of things like the gfxlib library, which may make thousands of SYS calls every frame0
-
Another thought, since the names you pass are library function calls, can you create a new function inside BBCSDL (e.g. "bbcmos") so you could then do something like SYS "bbcmos", &FFF1, A%, block%%
That shouldn't add any overhead to your SYS handler.0 -
I bet it's not even microseconds though - a nanosecond to check a number against a constant, perhaps?
Suppose some particular program is within 1 millisecond of exceeding a frame period, but you didn't actually know that it was. Say I then make the modification you propose, and despite the small time penalty it pushes the total duration just over the limit. Now not only will there be dropped frames, but probably sound stutters too.
The only way you can be totally sure that a program that works now will continue to work is not to slow it down at all.
0 -
you could then do something like SYS "bbcmos", &FFF1, A%, block%%
I would reiterate my previous comment. My existing workaround for &FFF1 not being reliable on 64-bit platforms works fine. Why are you so determined to give me more work, and break compatibility with existing programs, by changing it to something else?0 -
Richard_Russell wrote: »My existing workaround for &FFF1 not being reliable on 64-bit platforms works fine.
So it's not as though I've devised something entirely new specifically for the &FFF1 workaround, but rather that I've extended an existing data structure, and made the new functions callable by SYS. I hope that might make you slightly less critical of this approach.
0 -
I wasn't critical of your approach, it was more like your first post appeared to be asking for ideas, a misinterpretation I unreservedly apologise for.
Can you give an example of how I would use this, as in my Note Quiz game I do use OSWORD, already for Matrix Brandy if detected I use the RISC OS type call for that very reason, and while I've not yet encountered a problem with the BBC style call on BBCSDL on 64 bits, as you say it can't be reliable. I am writing it to work on the BBC B and later machines, including modern 64-bit kit running BBCSDL or Matrix Brandy.0 -
I wasn't critical of your approach, it was more like your first post appeared to be asking for ideas
I was hoping that there might be some cunning way of reliably using Y%+X% for both 32-bit addresses and 64-bit addresses, which I had missed, but it seems that there isn't. Existing programs which contain Y% = parblk DIV 256 are bound to fail with a 'Number too big' error if the parameter block isn't at a reachable address.
I had already been forced into devising a workaround (using SYS as it happens) otherwise I would have been left with a non-working application; therefore I am not particularly looking for suggestions for alternative workarounds that don't involve CALL &FFF1.Can you give an example of how I would use this
It is undeniably true that the workaround I have adopted is messier and less compatible than had I added an @fn%() table entry corresponding to your SYS "OS_Word"; to be frank I had completely forgotten that SYS call existed. But it's no worse than dozens of other, avoidable, existing incompatibilities between Matrix Brandy and BBCSDL.
Although I was, of course, aware of most of the changes Sophie made in BBC BASIC for the Acorn Archimedes, having never owned or used a RISC OS machine I was almost entirely ignorant about how the OS impacted on BASIC. That was true from its introduction in 1986 or thereabouts to when I first encountered the RISC-OS compatibility layer in Matrix Brandy.0 -
Thank you for that, I'm updating Note Quiz to use this (Edit: That's in and working). However (and I could be wrong), in your OSWORD 10 example you're reserving 8 bytes in the DIM statement when I think you need to reserve 9 (character value + 8 bytes of character data). Yep, classic off by one error on my part. I knew arrays were zero based, but I totally forgot that reserving memory was also one more byte than specified. (Need to check if Matrix Brandy also does this ... Yes, it does.)But it's no worse than dozens of other, avoidable, existing incompatibilities between Matrix Brandy and BBCSDL.
I'm reminded back when I was claiming &4D for Matrix Brandy and JGH was decrying this "misuse" of it, you chimed in with the excellent point that once the program knows what interpreter it is running on, it can do more interpreter-specific things to identify what platform it's on and other things that depend much more strongly on the interpreter rather than whether it's running on Linux or Windows.0 -
I knew arrays were zero based, but I totally forgot that reserving memory was also one more byte than specified.
DIM a(8) DIM a 8
Each reserves memory from index 0 to 8 inclusive: a(0) to a(8) and a?0 to a?8. It can certainly be a source of confusion, but at least the most likely mistake will allocate too much memory rather than too little.
There is however a difference between my BASICs and ARM BASIC (and probably Brandy) which is that in mine the memory block isn't guaranteed to be aligned but in ARM BASIC it is (a will be a multiple of 4). This stems from ARM CPUs having strict alignment requirements but x86 CPUs not.
I do take special account of this in the ARM assemblers though: even if the memory block is not aligned, the assembled code is. But that can give rise to the slightly surprising result that code% and begin are not necessarily the same value here:DIM code% 1000 P% = code% [.begin nop
(begin is always aligned, in the case of ARM assemblers only; code% isn't necessarily).
0 -
Just one further comment on the OSWORD issue. The @fn%(19) - @fn%(21) table entries correspond to existing routines in the SDL2_gfxPrimitives library (the 2D graphics extension for SDL2). So it's not as though I have deliberately designed them to be incompatible.
Arguably one advantage they have over OSWORD is that when reading the character bitmaps (either the 8x8 characters in MODEs 0-6 or the 16x20 characters in MODE 7) you need to make just one SYS @fn%(19) call - it returns the base address of the font table - rather than one for each character.
You can similarly change the entire bitmap font in one SYS @fn%(20) call, by passing a pointer to a new table, although this isn't terribly useful if you just want to redefine a few characters (you would first have to make a copy of the old font and then modify just those characters).
You can do something silly like this though:MODE 6 IF POS REM SDL thread sync SYS @fn%(19) TO font%% SYS @fn%(20), font%% + 8, 8, 8 PRINT "Hello world!"
which prints:
0 -
Am I doing something wrong here? This workaround is crashing the WASM build.
0 -
This workaround is crashing the WASM build.
I fear that your expectation that they ought to work is a clash of cultures! I know that you are only too willing to release new versions of Matrix Brandy on a whim, with what I can only assume is minimal testing. But that's not how I do things: modifications get planned, implemented and only after extensive testing released. It's quite normal for the process to take 6-8 weeks.
I can expedite updating the in-browser edition if you like: at least that is something I have complete control over and doesn't need users to proactively download and update their copies. But normally it only gets updated at the same time as all the rest - Windows, MacOS, 32-bit Linux, 64-bit Linux, 32-bit PiOS, 64-bit PiOS, Android (all 4 ABIs) and iOS!0 -
No need to expedite it on my behalf - I'll roll back my .bbc file to use the CALL &FFF1 code for now, and that works fine in the browser.0
-
No need to expedite it on my behalf - I'll roll back my .bbc file to use the CALL &FFF1 code for now, and that works fine in the browser.
A 'universal' approach would be to use ON ERROR to trap the 'Number too big' error which will result from Y% = parblk DIV 256 if the address is unreachable, and only then switch to using the 64-bit workaround code.0 -
0
-
Thank you! I had worked around it by (rather than using ON ERROR) using @platform% to determine if the platform was 64-bit, but this may simplify the code.0
-
I had worked around it by (rather than using ON ERROR) using @platform%
It was only after a recent change in 64-bit Windows 11 that it stopped working and drew my attention to the issue, but of course I don't distribute a 64-bit Windows edition of BBCSDL! So nobody else is likely even to have encountered it, and may not unless other platforms change the way memory gets allocated.
So I prefer the ON ERROR method as continuing to use CALL &FFF1 almost always. Of course if you want the program to remain compatible with 6502 BBC BASIC you can't use ON ERROR LOCAL, and that does limit where and how you trap the error. I presume it's a requirement that your code runs on BASIC 1 and BASIC 2, hence it using ON GOSUB rather than the much nicer ON PROC (which is implemented in 6502 BASIC 4 I think).0 -
Yep, ON PROC works on my Master (indeed, I originally used ON PROC but then it failed when I loaded it into Elkulator), but because I'm targeting BASIC 2 on the BBC/Electron (not tried BASIC 1 yet, the notable differences there are no OSCLI, which I only use on non-BBC platforms, and the OPENIN/OPENUP/OPENOUT which changed in behaviour and I use all 3), I needed ON GOSUB instead. The program is already large enough that it has to be crunched pretty hard else it won't fit on a BBC with PAGE=&1900 and MODE 1's HIMEM=&3000 - and that's after all lines with "REM NotBeeb" being removed as it's imported from plaintext into B-Em.
It's certainly been quite an exercise in writing a fairly complex program that will work on the original Beeb and all the modern flavours, and handling the various quirks that may be encountered.0 -
OPENIN/OPENUP/OPENOUT which changed in behaviour and I use all 3
Since you'll almost certainly want to use a tokenised program for the Beeb anyway (because it can be crunched more aggressively and still work) you can probably achieve compatibility with BASIC 1 by using OPENUP everywhere you currently use OPENIN. When loaded into BASIC 1 those OPENUPs will list as OPENINs.0 -
Yep, just trying that now actually, just put together a custom machine model in B-Em with a BBC B, DFS and BASIC 1.
Update: It works on DFS, but B-Em's VDFS creates a new file! I suspect that to be a B-Em or VDFS bug.
I've raised a bug report for this.0