<?xml version="1.0"?>
<!DOCTYPE riscos-prm PUBLIC "-//Gerph//DTD PRM documentation 1.03//EN"
                            "http://gerph.org/dtd/103/prm.dtd">

<riscos-prm>
<chapter title="Interfaces in 64 bit RISC OS">
<section title="Technical details">
<p>
RISC OS was designed initially for code written in assembler, and for use by BASIC. Its legacy of the BBC MOS influenced many of the interfaces that were used in the earliest systems, and these are not as suited to modern systems.
Because of this, and to take advantage the opportunity to re-work some interfaces, some of the interfaces in 64 bit RISC OS differ from those in the 32 bit variant.
</p>

<p>
    The differences relate primarily to entry and exit conditions for
    SWI calls and vectors. The changes will allow easier use of the system
    calls from high level languages, and may allow for easier transition
    to other architectures.
</p>

<subsection title="Areas which have changed">
<subsubsection title="Registers">
<p>
    Where registers between R0 and R9 are used for vectors, SWIs, upcalls,
    events and other interfaces, these map directly to the registers
    X0 to X9. Initially these registers should be expected to contain
    values which are 32 bit (despite the 64 bit nature of these registers).
</p>
<p>
    Register R12, which is usually passed to extension interfaces as a
    private word pointer, or context value, is passed in X12.
</p>
</subsubsection>

<subsubsection title="Processor flags">
<p>
    Some interfaces in RISC OS, like OS_ReadC, return part of their state
    in ARM processor flags. This made them easier to call in assembler,
    but does not work as well with high level languages. The convention
    of returning with the overflow (V) flag set to indicate a call error,
    with an error pointer in the first register is retained, however.
</p>
<p>
    Instead of returing state in the carry, zero, or negative flags,
    RISC OS 64 bit interfaces return the additional state in an extra
    register, or with a modified return in an existing register.
</p>
<p>
    Rarely, there are interfaces which have different state on entry.
    The vector CnPV is an example of this. These interfaces have been
    updated to include an additional register on entry to perform different
    operations.
</p>
</subsubsection>
</subsection>

<subsection title="Interface changes">

<subsubsection title="Modules">
    <category title="Multiple instantiation">
        <p>
            Multiple instantiation of modules is not supported under
            64-bit RISC OS.
        </p>
        <p>
            Multiple instantiation is a feature which
            allows the same module code to be used for different purposes.
            The FileCore module uses it to create separate instances for
            each module is it providing a file system for, for example.
            However, multiple instantiation of modules also brings with
            it a penalty in that the behaviour of modules which are given
            priority changes by the commands that are processed by them.
            Additionally, the features provided by multiply instantiated
            modules are also reproducible with a single instance, so the
            benefit is reduced. The feature is not widely used.
        </p>
        <p>
            In 26-bit and 32-bit RISC OS, the ability to multiply instantiate modules was given special features within the
            compiler to allow separate data areas for an execution.
            This used the 'stack entrails' (data at the bottom of the
            current stack chunk) to find the data area. This was a
            special compiler feature for RISC OS, and had to be given
            special consideration when using compilers such as GCC.
            In APCS for 32-bit,
            this could have also been provided through the use of
            relocatable code using a 'static base'.
        </p>
        <p>
            In AArch64, there is no provision for a 'static base'. All
            code is expected to be link-time resolved and use a Global
            Object Table to locate data regions. This does not work well
            with the traditional form of referencing workspace used for
            multiple instantiation. As building custom compilers for
            RISC OS is unnecessary work, and would further limit the
            support for the system, the ability to multiply instantiate
            modules is no longer supported in 64-bit RISC OS.
        </p>
        <p>
            Module workspace may still be used, but it is expected that
            all modules will have their data located within the module itself, and the zero-initialised data region will be
            automatically allocated by the Kernel on module load. The
            size of this zero-initialised area is indicated in the module
            feature data.
        </p>
    </category>
    <category title="Initialisation offset">
        <p>
            Within 64-bit RISC OS, the module initialisation offset must
            have bit 30 set. This prevents the module from loading on
            non-64-bit systems. The module feature flags must also contain
            bits to indicate the module's architecture.
        </p>
    </category>
    <category title="Command handler">
        <p>
            Within 64 bit RISC OS, the module command handler does not need to
            set the V flag to indicate an error. The error pointer is returned
            in X0. If no error occurs, X0 must be set to 0.
        </p>
    </category>
    <category title="Module feature data">
        <p>
            Within 64-bit RISC OS, the module feature flags contain new bits to indicate features of the module.
            Bits 4-7 indicate the architecture of the module, which must
            be used in conjunction with bit 30 in the module initialisation
            offset. Bit 2 indicates that the zero-initialisation data byte
            is present.
        </p>
        <p>
            The feature data has the following format:
        </p>
        <p>
            <offset-table>
                <offset number="0">
                    <p>Module feature flags:</p>
                    <p>
                        <bitfield-table>
                            <bit number="0">Module is 32-bit safe (only has meaning for architecture 0)</bit>
                            <bit number="1">Module is initialised early in the module chain (pre-initialisation)</bit>
                            <bit number="2">Module zero-initialisation data size is supplied</bit>
                            <bit number="3" state="reserved"/>
                            <bit number="4-7">
                                <p>Module architecture type:</p>
                                <p>
                                    <value-table>
                                        <value number="0">ARM 32 bit (A32)</value>
                                        <value number="1">ARM 64 bit (A64)</value>
                                        <value number="2">x86 64 bit (x86-64)</value>
                                        <value number="3-14">Reserved</value>
                                        <value number="15">Python (RISC OS Pyromaniac) </value>
                                    </value-table>
                                </p>
                            </bit>
                            <bit number="8-31" state="reserved"/>
                        </bitfield-table>
                    </p>
                </offset>
                <offset number="4">Zero-initialisation data size (if bit 2 set)</offset>
            </offset-table>
        </p>
        <p>
            Zero-initialisation data follows on after the module, and will
            be allocated in excess of the module size by the Kernel.
        </p>
    </category>
</subsubsection>

<subsubsection title="Code variables">
    <p>
        Code variables have a different definition and API within 64-bit RISC OS
        to allow them to be used more easily with high level languages.
    </p>
    <category title="Code variable definition">
        <p>
            Code variables are defined with a 16 byte block which contains the
            address of the entry points for the code variables.
        </p>
        <p>
            <offset-table>
                <offset number="0" data-size='8'>Address of the variable's write entry point</offset>
                <offset number="8" data-size='8'>Address of the variable's read entry point</offset>
            </offset-table>
        </p>
        <p>
            Both entry points may point to the same routine, in which case the type of
            call can be differentiated by the value in X0 on entry. Register X1-X15
            may be corrupted by the entry points.
        </p>
    </category>

    <category title="Write entry point">
        <p>
            Register X0 contains the value to write.
            Register X1 contains the length of the value.
            Register X2 contains the workspace pointer for the code variable.
        </p>
        <p>
            The handler does not need to set the V flag to indicate an error.
            The error pointer is returned in X0. If no error occurs, X0 must be set to 0.
        </p>
    </category>

    <category title="Read entry point">
        <p>
            Register X0 contains 0.
            Register X1 contains 0.
            Register X2 contains the workspace pointer for the code variable.
        </p>
        <p>
            On exit, X1 will contain a pointer to the read data, and X2 contains the size.
        </p>
        <p>
            The handler does not need to set the V flag to indicate an error.
            The error pointer is returned in X0. If no error occurs, X0 must be set to 0.
        </p>
    </category>
</subsubsection>

<subsubsection title="SWI calls">
<p>
    Within 64 bit RISC OS, SWI calls are issued through the
    <code>SVC</code> (supervisor call) instruction, using parameter 0.
    The SWI number is passed in register X10.
</p>
</subsubsection>

<subsubsection title="Input SWIs">
    <category title="OS_ReadC">
        <p>
            In 64 bit RISC OS, OS_ReadC does not return the
            escape state in processor flags.
        </p>
        <p>On exit, X1 will be set to the following values:
        </p>
        <p>
            <value-table>
                <value number="0">A character was read (value in X0)</value>
                <value number="1">An escape condition occurred (value in X0 is 27)</value>
            </value-table>
        </p>
    </category>

    <category title="OS_ReadLine">
        <p>
            In 64 bit RISC OS, OS_ReadLine does not return the
            escape state in processor flags.
        </p>
        <p>On exit, X0 will be set to the following values:
        </p>
        <p>
            <value-table>
                <value number="0">A line was read</value>
                <value number="1">An escape condition occurred (no line was read)</value>
            </value-table>
        </p>
    </category>

    <category title="OS_ReadEscapeState">
        <p>
            In 64 bit RISC OS, OS_ReadEscapeState does not return the
            escape state in processor flags.
        </p>
        <p>On exit, X0 will be set to the following values:
        </p>
        <p>
            <value-table>
                <value number="0">No escape condition has occurred</value>
                <value number="1">An escape condition has occurred</value>
            </value-table>
        </p>
    </category>

    <category title="OS_Byte 129">
        <p>
            In 64 bit RISC OS, OS_Byte 129 (read key state)
            does not return the read state in processor flags.
            The state of the carry flag had not been documented
            in the PRMs, and is not carried forward into 64 bit RISC OS.
        </p>
    </category>

    <category title="OS_Confirm">
        <p>
            In 64 bit RISC OS, OS_Confirm does not return the escape and
            acknowledgement state in processor flags.
        </p>
        <p>On exit, X1 will be set to the following values:
        </p>
        <p>
            <value-table>
                <value number="-1">An escape condition was detected</value>
                <value number="0">A negative response was given (not 'y')</value>
                <value number="1">A positive response was given</value>
            </value-table>
        </p>
    </category>
</subsubsection>


<subsubsection title="Conversion SWIs">
    <category title="OS_GSTrans">
        <p>
            In 64 bit RISC OS, OS_GSTrans does not return the
            buffer overflow state in the processor flags.
        </p>
        <p>On exit, X1 will be set to 0, and X2 will be set to
           maxlen (the buffer length, without the flags present).
        </p>
    </category>
</subsubsection>


<subsubsection title="Buffering SWIs">
    <category title="OS_Byte 138/153">
        <p>
            In 64 bit RISC OS, OS_Byte 138/153
            (insert into buffer/insert into input buffer)
            does not return the insertion state in processor flags.
        </p>
        <p>On exit, X2 will be set to the following values:
        </p>
        <p>
            <value-table>
                <value number="0-255">Value was inserted</value>
                <value number="-1">Value could not be inserted</value>
            </value-table>
        </p>
    </category>

    <category title="OS_Byte 145/152">
        <p>
            In 64 bit RISC OS, OS_Byte 145/152 (read or examine buffer)
            does not return the read state in processor flags.
        </p>
        <p>On exit, X2 will be set to the following values:
        </p>
        <p>
            <value-table>
                <value number="0-255">Character read from, or available in, the buffer</value>
                <value number="-1">No character was available</value>
            </value-table>
        </p>
    </category>
</subsubsection>

<subsubsection title="File system SWIs">

    <category title="OS_BGet">
        <p>
            In 64 bit RISC OS, OS_BGet does not return the
            read state in processor flags.
        </p>
        <p>On exit, X0 will be set to the following values:
        </p>
        <p>
            <value-table>
                <value number="-1">No byte was read</value>
                <value number="0-255">Value read</value>
            </value-table>
        </p>
    </category>
</subsubsection>


<subsubsection title="Output SWIs">

    <category title="VDUXV">
        <p>
            In 64 bit RISC OS, VDUXV does not return the
            redirection to printer in the processor flags.
        </p>
        <p>On entry, X1 will be set to 0.</p>
        <p>On entry, X1 will be set to -1 to send to printer.</p>
    </category>

</subsubsection>


<subsubsection title="Graphics SWIs">

    <category title="OS_CheckModeValid">
        <p>
            In 64 bit RISC OS, OS_CheckModeValid does not return the
            validity state in processor flags.
        </p>
        <p>On exit, X0 will be set to the following values:
        </p>
        <p>
            <value-table>
                <value number="-1">Mode does not exist; X1 contains the mode to use, or -2 if no alternative exists</value>
                <value number="-2">Mode exists, but is not selectable</value>
                <value number="other">Mode exists and is selectable</value>
            </value-table>
        </p>
    </category>

    <category title="OS_ReadModeVariable">
        <p>
            In 64 bit RISC OS, OS_ReadModeVariable does not return the
            validity state in processor flags.
        </p>
        <p>On exit, X1 will be set to the following values:
        </p>
        <p>
            <value-table>
                <value number="-1">Mode or variable number is invalid</value>
                <value number="other">Mode and variable exist</value>
            </value-table>
        </p>
    </category>
</subsubsection>


<subsubsection title="Memory SWIs">

    <category title="OS_ValidateAddress">
        <p>
            In 64 bit RISC OS, OS_ValidateAddress does not return the
            validity state in processor flags.
        </p>
        <p>On exit, X0 will be set to the following values:
        </p>
        <p>
            <value-table>
                <value number="0">Memory is not valid</value>
                <value number="1">Memory is valid</value>
            </value-table>
        </p>
    </category>

</subsubsection>


</subsection>
</section>

<section title="System variables">

<sysvar-definition name="Sys$Arch"
                   description="Execution architecture for the system">
<use>

<p>The system variable <sysvar>Sys$Arch</sysvar> is provides information on the
architecture of the system.</p>

<p>The current values are defined.</p>
<p>
    <value-table>
        <value number="aarch32">ARM, 32-bit architecture (AArch32)</value>
        <value number="aarch64">ARM, 64-bit architecture (AArch64)</value>
    </value-table>
</p>
</use>

<related>

</related>
</sysvar-definition>
</section>

</chapter>

<!-- MetaData -->
<meta>
 <maintainer>
  <email name="Gerph" address="gerph@gerph.org" />
 </maintainer>
 <disclaimer>
    <p>
        &copy; Gerph, 2025.
    </p>
 </disclaimer>

 <history>
  <revision number="1" author="Gerph" date="23 Feb 2025" title="Initial documentation">
    <change>Documenting implementation within RISC OS Pyromaniac.</change>
  </revision>
 </history>
</meta>
</riscos-prm>
