abi

Proposed psABI for w65

View on GitHub

w65 ABI

Types

Alignment

Each Primitive Type shall have an alignment equal to its size, up to a maximum fundamental alignment of 4.

Type Sizes

The sizes of scalar types are given as follows:

uint_fast8_t

The uint_fast8_t typedef corresponds to a special type which has size 2, and the following properties:

The int_fast8_t typedef corresponds to a special type with the same properties as above, except that it shall be capable of storing and exactly representing any value of type signed char.

Signed Integer Representation

This document defines that signed integers shall be represented using 2s complement.

Floating Point Representation

The type float shall be represented as an IEEE 754 binary single precision floating-point value. The type double shall be represented as a binary double precision value. The type long double shall be represented as an IEEE 754 binary double precision value, as an IEEE 754 quad precision value, or as an 80-bit extended double precision value. It is implementation-defined which type long double represents.

If the implementation may define an extended __float16 or _Float16 type, it shall be represented as an IEEE 754 binary half precision value. If the implementation may define an extended __float128 or _Float128 type, it shall be represented as an IEEE 754 quad precision value, and shall be compatible with the long double type if long double is represented as an IEEE 754 quad precision value.

Support for 80-bit floating-point arithmetic is not defined by this document.

Atomics

Atomic operations of size 16 or 8 shall be treated as always lock free. Other sizes of atomics are never treated as lock free. Accessing an non-lock free atomic from an interrupt handler other than BRK or COP has undefined behavior if the interrupt handler interrupts any non-lock free atomic operation.

As a suggested extension, implementations are recommended to implement non-lock free atomics such that the IRQ handler may additionally access non-lock free atomics as though they were lock free. Implementations are recommended to document when this is the case.

va_list

The va_list type shall be an array of 1 element containing a pointer to void. The va_start macro shall initialize the list with a pointer to the first variadic parameter on the stack, and the va_arg macro shall increment by the size of the type, rounded up to 2, after aligning to the proper alignment by incrementing the pointer

jmp_buf

The jmp_buf type shall be an array of 1 element containing the following exposition-only structure type

struct __jmp_buf{
    unsigned long __regs[3];
    unsigned int _S;
    unsigned int _D;
    unsigned int _PC;
    unsigned char _K;
    unsigned char __pad;
};

The setjmp macro shall initialize the __jmp_buf as follows:

The longjmp function shall restore each register from the given __jmp_buf, and store it’s second argument in the return value.

The __builtin_setjmp function shall be defined by the implementation, with the signature int __builtin_setjmp(struct __jmp_buf*), which performs the behaviour specified above for the setjmp macro, treating the return value as the instruction immediately following the setjmp macro.

fenv_t

The fenv_t type shall be an alias of the long type.

The fexception_t type shall be an alias of the int type.

(Note: The fenv_t type may be extended in future versions, and thus should not be passed across an abi boundery by-value)

The fegetenv function shall be an alias for the __float_getenv function, and the fesetenv function shall be an alias for the __float_setenv function.

The value loaded by __float_getenv and stored by __float_setenv is the 32-bit value given as follows:

The Floating-Point exception mask in fenv_t and fexception_t is given by the following table | Bit | Exception | |—–|————-| | 0 | FE_DIVBYZERO| | 1 | FE_UNDERFLOW| | 2 | FE_OVERFLOW | | 3 | FE_INEXACT | | 4 | FE_INVALID |

Other bits may be defined and used by future versions, but are otherwise reserved, and are set to 0 by __float_getenv, and ignored (masked) by __float_setenv`.

The <fenv.h> header shall define constants with the names given in the above table, corresponding to the value (1<<Bit), where Bit is the corresponding bit for the exception given in the above table.

The Rounding Mode in bits 18-21 (rnd) is given by the following table: | Value | Mode | |——-|————–| | 0 | FE_TONEAREST | | 1 | FE_DOWNWARD | | 2 | FE_UPWARD | | 3 | FE_TOWARDZERO|

Other rounding mode values are not defined, and will not be produced by __float_getenv. The behaviour of setting such a mode is undefined.

The FE_DEF_ENV macro shall expand to a pointer to the symbol __float_defenv. The value of __float_defenv is unspecified, except that no exceptions shall be indicated by it and rnd shall be FE_TONEAREST.

If the implementation provides a _Reset implementation that calls the main function, then prior to calling the main function, the _Reset implementation shall execute the equivalent of __float_setenv(&__float_defenv). Otherwise, it is unspecified whether the floating-point environment is intialized prior to the first call to __float_setenv.

Extended (in-memory) Registers

This ABI requires that implementations define 8 Extended Registers as symbols, which are available in Bank 0, for storing 4-byte values and additional 8-byte values. These registers shall be stored contiguously in memory, in ascending numerical order, with no padding between each register, and shall be aligned to 4 bytes (and even numbered registers shall be aligned to 8). The registers are indicated by __rn where n is the register number from 0 to 7.

Given each register, there shall be 3 additional sub-registers, which access part of the memory allocated for the extended register. These registers shall be indicated as __rnw, which accesses the lower 2-bytes of __rn, __rnh, which access the high byte of __rnw, and __rnl, which accesses the lowest order byte of __rn.

Calling Conventions

C Calling Convention (Main/Default/Extern C)

Registers

The e flag, as well as the S, PC, K registers, and the __r6, __r7, and __r8 extended register are all callee saved (non-volatile). All other registers are caller saved (volatile).

Upon entry or exit of a function, the direct page register shall be set to an unspecified value for which all extended registers are reachable from. Upon calling a function, the m flag shall be set. Upon return from a function, the x flag shall be clear.

Parameter and Return Value ABI

Small Types
Other Structs/Unions/Large Values

No parameters are passed to any function with an empty parameter list and that returns either void, or does not return.

A regular function which has external linkage, or for which a pointer is created, shall be called with the jsl (Jump to Subroutine Long, opcode $22) instruction and return with the rtl (return from subroutine long, opcode $6B) instruction.

Interrupt Calling convention

A special convention is defined to be suitable for use in defining native mode interrupt handlers. Such interrupt handlers must have an empty parameter list and return void.

The behavior is undefined if an interrupt handler function is called, except by an interrupt vector. Implementations are encouraged to diagnose such violations.

Interrupt Handlers shall save any register, other than the status register, used by the handler (including any caller saved registers whenever it calls a function). If __atomic_reset_enabled is set, the value in X shall be stored to the pointer at __r1. __atomic_reset_enabled shall then be cleared.

Returning from a function with this calling convention executes the RTI instruction.

The requirements imposed on interrupt handlers are the same as those imposed on asynchronous signal handlers within the C11 standard, except that the BRK and COP interrupts are treated as synchronous signal handlers (as though triggered by a call to raise/abort). The behaviour is undefined if an interrupt handler exits via an exception or unwinding panic.

The following symbols are defined to correspond with various interrupt vectors used in native mode, and shall be defined with this calling convention (no diagnostic is required):

The following symbols are defined to correspond with various interrupt vectors used in emulation mode:

Additionally, the following symbols are reserved. The behaviour of a program that defines a symbol with any such name is undefined:

Implementation Provided _Reset

If the _Reset symbol is not defined by the program, then the implementation may provide a definition of the _Reset symbol that calls a function by the name of main with no arguments, and that returns void. If it does so, the following is guaranteed to be performed:

It is implementation-defined whether the implementation provides the _Reset symbol if not user-defined. The definition shall handle returning from the main function, and terminate execution in an unspecified manner.

The implementation shall support unwinding out of the main function and doing so shall terminate execution in an unspecified manner.

Language ABIs

Itanium C++ ABI

C++ classes that are non-trivial for the purposes of calls use large value abi, regardless of size or alignment. Empty C++ classes that are not non-trivial for the purposes of calls are treated as zero sized types for the purposes of passing and returning values, otherwise are treated as though they have size 1 and alignment 1 (unless modified).

Pointer to Member Functions do not use the least significant bit to differentiate between vtable offsets and non-virtual function addresses. Rather, it uses the most significant bit. (This permits implementations to pack function definitions together, with no padding between, when space constraints would make requiring even addresses unreasonable). There are no changes to the this-adjustment offset, nor any other changes to the layout of a Pointer-to-member function.

Rust

This section applies to all rust implementations that conform to this abi.

The extern”C” and extern”system” abis are equivalent to the C Calling Convention documented above. The extern”platform-intrinsic” abi is reserved for future extensions, but should otherwise be treated as equivalent. Rust implementations shall define the extern”w65-interrupt” abi, to correspond to the Interrupt Calling Convention defined above. All other abis are not specified by this document and excluding the extern”Rust”, extern”rust-call”, and extern”rust-intrinsic” abi, programs that conform to this ABI shall not use such abis. This ABI imposes no requirements that implementations forbid or diagnose the use of such abis.

LCRust Versioned ABI

This section applies only to rust implementations that implement the LCRust ABI, version 0, or any later version subject to changes in those versions, documented here.

extern"Rust" is equivalent to the C Calling Convention described above.

The hash algorithm used for computing the hash-part of TypeId shall be FNV-1a 32-bit.

The correspondence of types, for the purposes of Mangling According to the section following are as follows:

ELF Files

65816 Common

65816 ELF Files may use the e_machine value EM_65816, 257.

The class for 65816 elf files is ELFCLASS32; the order is ELFDATA2LSB (Little Endian). Use of ELFCLASS64 or ELFDATA2MSB is not specified.

By default, 65816 ELF Files are recommended to use either ELFOSABINONE (Sys-V) or ELFOSABISTANDALONE. Use of other abis is not specified.

Use of EOSABINONE is recommended if and only if produced by a compiler (or hand-written assembly) which subscribes to the above defined ABI.

65816 Relocatable ELF Files may use the following relocations. If a relocation occurs across a bank boundary, the behaviour is undefined.

When an implementation emits relocations 10-15, it shall also emit valid relocations (as necessary) for the explicitly generated code. Use of relocations 10-15 is advisory only, an implementation need not perform any replacement indicated by any such relocation, and may choose to ignore such relocations instead.

Additional Requirements

Pointer to Function Trampoline

The implementation shall define a function _FnPtrTrampoline. The program should not call this function directly. It must be called with JSL. When called with a function pointer in __r8, it shall perform a tailcall to that function. Otherwise, the behaviour of the function is undefined.

Extended Arithmetic

The implementation shall, for each value N in 8, 16, 32, 64, and optionally 128, the define each of the following functions with the given prototypes and behaviour (where the N in the symbol name and in the prototypes are replaced with the integer):

intN_t __add_intN(intN_t a, intN_t b)

uintN_t __add_uintN(uintN_t a, uintN_t b)

_Fixed intN_t __add_fixedN(_Fixed intN_t a, _Fixed intN_t b);

intN_t __sub_intN(intN_t a, intN_t b)

uintN_t __sub_uintN(uintN_t a, uintN_t b)

_Fixed intN_t __sub_fixedN(_Fixed intN_t a, _Fixed intN_t b);

intN_t __mul_intN(intN_t a, intN_t b)

uintN_t __mul_uintN(uintN_t a, uintN_t b)

_Fixed intN_t __mul_fixedN(_Fixed intN_t a, _Fixed intN_t b);

intN_t __lsh_intN(intN_t a, intN_t b)

uintN_t __lsh_uintN(uintN_t a, uintN_t b)

_Fixed intN_t __lsh_fixedN(_Fixed intN_t a, _Fixed intN_t b);

intN_t __rsh_intN(intN_t a, intN_t b)

uintN_t __rsh_uintN(uintN_t a, uintN_t b)

_Fixed intN_t __rsh_fixedN(_Fixed intN_t a, _Fixed intN_t b);

int_divN_t __div_intN(intN_t a, intN_t b)

uint_divN_t __div_uintN(uintN_t a, uintN_t b)

_Fixed intN_t __div_fixedN(_Fixed intN_t a, _Fixed intN_t b);

Where the uint_divN_t type is an expostion-only type which has the following definition:

struct uint_divN_t{
    uintN_t quotient;
    uintN_t remainder;
};

And the int_divN_t type is defined the same but using intN_t instead of uintN_t.

Whether or not any particular symbol is defined by the implementation for N=128 is implementation-defined. Every symbol defined by this section is reserved [Note: this includes the 128-bit forms even if the implementation chooses not to define them].

If any operation, other than fixed point division or multiplication, defined in this section overflows, the integer operation wraps mod 2^N. If fixed point division or multiplication overflows, the result is unspecified.

Floating Point Operations

For each N in 16, 32, 64, and 128, an implementation optionally defines the following symbols wit the following prototypes, where _FloatN has meaning as follows:

_FloatN __float_addN(_FloatN x,_FloatN y);

_FloatN __float_subN(_FloatN x, _FloatN y)

_FloatN __float_mulN(_FloatN x,_FloatN y);

_FloatN __float_divN(_FloatN x,_FloatN y);

_FloatCmpResult __float_cmpN(_FloatN x,_FloatN y);

The type _FloatCmpResult is an exposition-only type defined as though by the C++ enumeration definition:

enum _FloatCmpResult : signed char{
    Less = -1,
    Greater = 1, 
    Equal = 0,
    Unordered = 0x7f
}

int __float_getenv(long* env);

int __float_setenv(const long* env);

const long __float_defenv;

All operations described within this section shall operate according to the IEC 559/IEEE 754 standard, and according to Annex G of ISO 9899. The result of the function shall fall within half the Unit of Least Precision which the implementation may support.

It is implementation-defined whether any symbol defined within this section is made available. Any symbol defined within this section is reserved, regardless of whether or not the implementation makes the symbol available.

Feature Test Symbols

The following symbols shall be defined by the implementation as follows, otherwise the symbol shall be undefined. If no particular value is given, then the value of the symbol shall be an unspecified non-zero value that fits in an unsigned 16-bit value.

It is implementation-defined whether feature testing as defined within this section is supported. Implementations are permitted to define symbols within this section to non-zero values reguardless of whether it support feature testing.

Extensions to this ABI

Space Constrained Environments

In a space constrained environment, it may be infeasible to allocate space for Extended registers. In such environments, it is permissible to use only the first 4 extended registers, or none at all. Implementations should document when this is the case, or may be made available. If extended registers are not used, then the Direct Page register is Caller Saved.

Future Directions

Position Independent Code

The symbol with the name _GLOBAL_OFFSET_TABLE_ is reserved for future use pertaining to position independent code. The symbol _DYNAMIC_ is reserved for future use pertaining to position independent code.

Additional Extended registers

The symbols of form __r, followed by a decimal positive integer are reserved for additional extended registers.

Any symbol of a form reserved by this section followed by the letters w, l, or h are also reserved.

Address Space Extensions

The 8 most significant bits of any valid pointer value are reserved for use in extensions that provide an extended address space. User code should not rely on any particular value in future versions, except that no function will have an address with the most significant bit set.

Reserved Symbol Glossary

The following is a list of every symbol reserved by this specification.

Reserved Symbols may be specified as user-defineable (IE. Interrupt Handler Functions). If so, restrictions for each symbol are given. The result of defining the symbol may affect generated code. Otherwise, Reserved Symbols may be defined with a prototype presented by this document. If a definition is provided by this document, then compliant code may use the symbol according to it’s definition. Otherwise, compliant code may only reference the symbol by name as a weak symbol to determine whether the symbol exists, except that complaint code may not reference any local symbol form.

Local Symbol Forms

If a symbol is reserved by this ABI, or is the name of a function defined by the C Standard, then any symbol that starts with that name followed by a . is reserved.

Main Function

The symbol main is reserved for use by an Implementation provided _Reset symbol, unless the program defines the _Reset symbol. Complaint programs may define this symbol as a function with the signature void main(void);

Reserved as Interrupt Handler Functions

These functions are reserved as the name of interrupt handler functions. Complaint Programs may define these symbols according to the requirements prescribed in Interrupt Calling convention:

Additionally the following symbols are reserved and may not be defined:

Reserved For Feature Testing

The symbols of either of the following forms are reserved for use with feature testing:

The following symbol forms are additionally reserved for specific use and will not be defined by this psABI or a future version thereof:

Reserved For Code Generation

Arithmetic Operations

Any symbol that is a valid C identifier and starts with one of the following prefixes, and ends with a decimal integer, is reserved for generating code handling integer and floating-point operations:

Atomic Operations

The following symbols are reserved for generating code handling atomic operations:

Position Independent Code

The following symbols are reserved for future use related to position-independent code:

Misc

The following symbols are reserved for miscellaneous code generation use:

Hardware Floating-Point

The following symbols are reserved for future use related to operating hardware-floating point

Reserved for Register Memory Locations

Any symbol __rn, where n is a decimal number is reserved. Any symbol __rnw, __rnl, or __rnh is reserved.

Reserved for Previous Use

The following symbols were previously used by the specification and are reserved: