Data Types in Registers and Memory
MIPS32® CPUs define the following data formats:
- Bit (suffix b)
- Byte (8 bits, suffix B or b)
- Half Word (16 bits, suffix H or h)
- Word (32 bits, suffix W or w)
- Double-Word (64 bits, suffix D or d - available in implementations that include a 64-bit floating point unit)
These CPUs can load or store between 1-4 bytes in a single operation.
Integer Data Types
Byte and Half Word loads come in two flavors: sign-extending and zero-extending.
Sign-Extending instructions lb and lh load the value into the least significant bits of the 32-bit register, but fill the high-order bits by copying the sign bit (bit 7 of a byte, bit 15 of a halfword).
Unsigned, Zero-Extending instructions lbu and lbh zero-extend the data; they load the value into the least significant bits of a 32-bit register and fill the high-order bits with zeros.
For example, if the byte-wide memory location whose address is in t1 contains the value 0xFE (-2, or 254 if interpreted as unsigned), then:
will leave t2 holding the value 0xFFFFFFFE (-2 as signed 32-bit value) and t3 holding the value 0x000000FE (254 as signed or unsigned 32-bit value).
Data Types in Arithmetic Operations
The MIPS32® CPU ALU is designed to operate on 32-bit 2's complement numbers.
The CPU provides 2 kinds of arithmetic instructions to deal with potential overflow in arithmetic operations:
- Add (add), add immediate (addi), and subtract (sub) cause exceptions on overflow.
- Add unsigned (addu), add immediate unsigned (addiu), and subtract unsigned (subu) do not cause exceptions on overflow.
Because C ignores overflow, MIPS C compilers will always generate the unsigned versions of the arithmetic instructions addu, addiu, subu no matter what the type of the variables.
There are no byte or half-word arithmetic operations. Where a C program explicitly does arithmetic as short or char, a MIPS compiler must insert extra code to make sure that the results wrap and overflow as they would on a native 8- or 16-bit machine.
When porting code that uses small integer variables to a PIC32 MCU, you should consider identifying variables which can safely be changed to an int (32-bit integer on PIC32).
The MIPS32® CPU provides a pair of 32-bit registers to contain the 64-bit product, called HI and LO. (CPUs with the MIPS® DSP ASE Extension (such as PIC32MZ) provide an additional 3 HI/LO accumulators).
To produce a properly signed or unsigned product, MIPS has two instructions:
- Multiply (mult)
- Multiply unsigned (multu)
To fetch the integer 64-bit result, the programmer uses move from hi (mfhi) and move from lo (mflo) instructions.
Both MIPS multiply instructions ignore overflow, so it is up to the software to check to see if the product is too big to fit in 32-bits.
The MIPS32® CPU uses the same HI and LO registers for both multiply and divide operations. HI contains the remainder, and LO contains the quotient after the divide instruction completes. To fetch these results, the programmer uses move from hi (mfhi) and move from lo (mflo) instructions.
To handle both signed integers and unsigned integers, MIPS has two instructions:
- Divide (div)
- Divide unsigned (divu)
MIPS divide instructions ignore overflow, so it is up to the software to check to see if the quotient is too large. In addition to overflow, division can also result in an improper calculation: division by 0. Modern MIPS32® implementations (PIC32MX/MZ) provide an option to enable a trap exception in this case.