MIPS-16

Figure 3: Mapping compressed MIPS-16 instructions
The MIPS-16 ISA is the 16-bit ISA derived from the 32-bit MIPS I ISA.
It supports the full range of MIPS ISAs. To fit into 16 bits, the MIPS-16
uses 5-bits for its major op code field and function field (they were 6-bits),
3-bits for the register fields (they were 5 bits). Additionally, the MIPS-16
uses only two register fields, rather than the three of the MIPS I ISA.
And it shrinks the immediate value field from 16- to 5-bits. Figure 3 compares the MIPS-32 and MIPS-16 instruction fields.
The 16-bit ISA's restricted register set directly effects compiler register
allocation strategy. With the normal MIPS-32 ISA, when the compiler allocates
registers for a complex expression, it normally feels free to allocate
a new register any time one is needed. Usually there are enough registers,
and if there are not enough, if too many registers are needed, some are
merged or spilled to the stack. In the MIPS-16 ISA, which has fewer registers
than the 32-bit ISA, the compiler is forced to use argument registers as
temporary registers.
Other changes include adding a special stack pointer instead of using
a general register. The MIPS-16 only has 8 general registers, too few to
use on as designated stack pointer. Figure 4
shows the MIPS-16 and MIPS-32 register usage.

Figure 4: MIPS register mapping
Switching between the MIPS-16 and 32-bit MIPS I ISAs is done through
the jump and link instructions: JALX, JALR (Jump And
Link eXchange). JALX jumps and saves the next address in a link
register and is used for subroutine calls. The JALR returns to
the address in the link register. Using JALX, a 32-bit ISA routine
can call a 16-bit ISA routine and vice versa. JALR and JR
(jump return) can also set or reset the ISA mode bit. The ISA mode bit
can also be changed when an exception occurs. Generally exceptions are
handled by the system in full 32-bit ISA mode.
There were some interesting consequences of implementing a 16-bit MIPS
ISA. For example, the MIPS-16 ISA dos not permit access to the floating-point
registers. This becomes a problem since the MIPS calling convention is
meant to pass floating-point values in the floating-point registers. This
could be a real problem when a 32-bit MIPS-32 function calls a 16-bit MIPS-16
function and passes a floating-point argument. The MIPS-16 code cannot
access that value.
We fixed the problem by making sure that the compiler emits a 32-bit
stub for any 16-bit function that took a floating-point argument. The stub
copies the floating-point register into regular argument registers, and
that then jump to the 16-bit function. The linker arranges for all calls
from 32-bit functions to go to the 32-bit stub. If the 32-bit stub is never
called, the linker deletes it.
When a 16-bit function calls a function with a floating-point argument,
the compiler adds a 32-bit stub. The linker arranges the function call
to go through the stub if calling a 32-bit function; it will go
directly to a 16-bit function.
|