RISC OS 64bit OSLib
Charles Ferguson
gerph at gerph.org
Tue Aug 26 02:42:40 BST 2025
On Thu, 19 Jun 2025, David Ruck wrote:
> On 18/06/2025 23:41, Charles Ferguson wrote:
> > A small note to say that the parser now has support for generating
> > CMHG headers and a stub C module source from the definitions. Now
> > available at:
> >
> > https://github.com/gerph/riscos-oslib-parser/releases/tag/v0.02
>
> Your efforts are appreciated, even if I don't have time to make use of it
> right now.
Thanks; it's been something of a slog getting this all right but... I
think I'm nearly there now. I've updated the AArch64 veneer generation
in the specific riscos64-oslib repository, and this now looks like it's
generating the veneers properly.
https://github.com/gerph/riscos64-oslib/releases/tag/v0.06
The more general parser repository has all the other parts in it, and
that's not really changed other than to import the AArch64 API code.
https://github.com/gerph/riscos-oslib-parser/releases/tag/v0.03
Basically, I got around to spending more time with the veneers and working
out what I had done wrong before. The veneers are much more correct (ie
they work in places they didn't before) and named properly, and I've
finally got the non-X variants working too.
I *finally* understood what the `!` means in the exit register definitions
- it means that the register indicated is to be returned as the return
value of the function when the non-X variant is called (but for the
X-variant, it's just a regular return pointer).
I discovered I'd been using the return registers wrongly, too - I hadn't
realised that the return pointer can be NULL to discard the register.
That also meant that I could use the CBZ instruction, which isn't as nice
as having arbitrary conditions, but is still quite cute.
The other fun thing with the registers was realising that I'm using
AArch64 and don't need to constrain myself to just the low registers -
I've got up to x17 that I can use in the veneer without needing to
spill on to the stack. This means that all the functions are now less
stack-happy, and saved an instruction per return value. And yes, I know
that it's not at all important for performance as the cost of a SWI call
is way higher, but it makes tracing easier if nothing else.
The names of the functions also weren't quite right as my simplistic
underscore insertion code wasn't doing the same as OSLib's DefMod. With
that now fixed, I think I've got everything done for AArch64.
All of this means that we now have simple veneers that are relatively
nice. A simple SWI like XColourTrans_SetGCOL comes out like this:
----
.section .text.xcolourtrans_set_gcol
.global xcolourtrans_set_gcol
signature xcolourtrans_set_gcol
xcolourtrans_set_gcol:
// => R0 = colour (OS_Colour)
// R3 = flags (ColourTrans_GCOLFlags)
// R4 = action (OS_Action)
// <= R0 = gcol (OS_GCOL)
// R2 = log2_bpp (.Int)
// R3 corrupted
STP x29, x30, [sp, #-16]!
MOV x29, sp
// Prepare output registers
MOV x15, x3 // output gcol
MOV x14, x4 // output log2_bpp
// Prepare input registers
MOV x4, x2 // action
MOV x3, x1 // flags
// x0 = colour
// Call SWI
MOV x10, #1859
MOVK x10, #6, LSL 16
SVC #0 // XColourTrans_SetGCOL (&40743)
CSEL x17, xzr, x0, VC
// Store output registers
CBZ x15, xcolourtrans_set_gcol_noreg_3
STR x0, [x15] // output gcol
xcolourtrans_set_gcol_noreg_3:
CBZ x14, xcolourtrans_set_gcol_noreg_4
STR w2, [x14] // output log2_bpp
xcolourtrans_set_gcol_noreg_4:
MOV x0, x17 // Error pointer (or NULL)
LDP x29, x30, [sp], #16
RET
----
and then there are fun ones like XOS_CreateDynamicArea for the Create (0)
reason code:
----
.section .text.xosdynamicarea_create
.global xosdynamicarea_create
signature xosdynamicarea_create
xosdynamicarea_create:
// => R0 = &0 (constant)
// R1 = area (OS_DynamicAreaNo)
// R2 = size (.Int)
// R3 -> base_address (.Data)
// R4 = flags (.Bits)
// R5 = size_limit (.Int)
// R6 -> handler (.Asm)
// R7 = workspace (&Void)
// R8 -> description (.String)
// <= R1 = area_out (OS_DynamicAreaNo)
// R3 -> base_address_out (.Data)
// R5 = size_limit_out (.Int)
STP x29, x30, [sp, #-16]!
MOV x29, sp
// Prepare output registers
// output area_out: arg 8 on caller stack at offset 0 * 8
// output base_address_out: arg 9 on caller stack at offset 1 * 8
// output size_limit_out: arg 10 on caller stack at offset 2 * 8
// Prepare input registers
MOV x8, x7 // description
MOV x7, x6 // workspace
MOV x6, x5 // handler
MOV x5, x4 // size_limit
MOV x4, x3 // flags
MOV x3, x2 // base_address
MOV x2, x1 // size
MOV x1, x0 // area
MOV x0, #0
// Call SWI
MOV x10, #102
MOVK x10, #2, LSL 16
SVC #0 // XOSDynamicArea_Create (&66)
CSEL x17, xzr, x0, VC
// Store output registers
LDR x10, [x29, #16 + 0 * 8] // output area_out
CBZ x10, xosdynamicarea_create_noreg_8
STR x1, [x10] // output area_out
xosdynamicarea_create_noreg_8:
LDR x10, [x29, #16 + 1 * 8] // output base_address_out
CBZ x10, xosdynamicarea_create_noreg_9
STR x3, [x10] // output base_address_out
xosdynamicarea_create_noreg_9:
LDR x10, [x29, #16 + 2 * 8] // output size_limit_out
CBZ x10, xosdynamicarea_create_noreg_10
STR w5, [x10] // output size_limit_out
xosdynamicarea_create_noreg_10:
MOV x0, x17 // Error pointer (or NULL)
LDP x29, x30, [sp], #16
RET
----
All of which is to say... yay! I think I have finally got to the bottom of
how the OSLib interface definitions work, and the parser is mostly able to
handle them (still doesn't handle the comments so well... but there's
always scope for improvement), and hopefeully OSLib will be useable in
some real things soon. I built DrawFile with it a little while back, but
it crashed badly, so maybe this'll help.
--
Charles Justin Ferguson
[ My thoughts are my own. And sometimes they're not even sane. ]
More information about the oslib-user
mailing list