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