We've chosen this name, for now. We intend to improve on o32 with something simpler, but which prefers being trouble-free for the MIPS programming community over ground-breaking innovation.
Unfortunately there can't be just one NUBI. We believe there are three basic choices (related to the hardware) which will create NUBI variants, but which it's essential to support:
- Endianness: big- and little-endian programs are wholly incompatible. However, with some care this document covers both. When we need to distinguish them we'll use a suffix L or B for little/big-endian.
- Use of 64-bit integer instructions: whether the software is restricted to a MIPS32 instruction set (NUBI32), or can use the whole of MIPS64 (NUBI64). If you only ever use MIPS32 instructions all general-purpose registers might as well be 32-bits wide. Even NUBI32 software is assumed to have access to double-precision floating point operations,
- Size of basic C types: we need to recognise a variant of NUBI64 with 64-bit pointers and long. I'm going to use NUBI64W (W for wide) to denote this for now. Better suggestions welcomed.
In the medium term we expect the narrow 64-bit ABI which uses 32-bit pointers and long type to be more popular.
That leads to the following list of six main variants: NUBI32L, NUBI32B, NUBI64L, NUBI64B, NUBI64WL and NUBI64WB. We'll use NUBI32 to mean NUBI32L and NUBI32B, and - at a pinch - NUBI-L to mean NUBI32L and NUBI64L.
How's NUBI different from o32?
- More argument registers : eight instead of four.
- Argument registers shared with return-value registers : helps avoid having too many registers with pre-defined roles.
- Adds a thread pointer : for efficient TLS.
- o32 was stack based, NUBI is register-based: at bottom o32 used a stack-based calling convention, though it's disguised because the first, notional, 4Ã—32-bit locations of the underlying stack argument structure are left unwritten, with the real data passed in four argument registers.
At the time o32 was introduced C programs were frequently written without function prototypes to describe the types of the arguments expected by an external function. Without any prototypes calls to functions with non-standard arguments or (worse) with a variable number of arguments, like printf(), were difficult to get right. The underlying stack structure helped; a troubled function could save the four registers onto the stack to obtain a completely predictable memory structure for its arguments.
The stack-based structure also made it possible to pass data of derived types (structures, principally) by value. This has advantages: sometimes the data types you think are obscure turn out to be common.
In o32's generation, the critical example of this was the Fortran complex-number data type (which is a pair of floating point values).
However, in NUBI32's time the problem is more likely to be that we'd like to handle long long arguments and return values more efficiently. This might be worth a special case (which would cover complex and double-precision floating point numbers too).
- o32 was irredeemably 32-bit, NUBI makes interworking possible: a call between a NUBI64 program and a NUBI32 program will always need gasket code, but a gasket which is automatically produced would be a useful tool for complicated applications which are migrating from 32-bit to 64-bit, and where not all the components are recompiled together.
The v0.16 from September , 2005 can be downloaded at ftp://ftp.linux-mips.org//pub/linux/mips/doc/NUBI/MD00438-2C-NUBIDESC-SPC-00.16.pdf.
- Since the normal 32-bit MIPS register set treats pretty much all registers the same, the MIPS16e constraint should be unproblematic.