Search This Blog

Sunday, December 18, 2005

Q1 Register Set

As mentioned previously, the Q1 has 32 32-bit general purpose registers, as well as the instruction pointer, instruction register, and various flags. I've adopted the MIPS register naming convention (registers 0-31 being $0 to $31), because it elegantly allows the use of register nicknames: aliases for certain registers, based on the designated function of the register (we'll come back to this in a couple paragraphs).

Of these 32, 31 are truly general purpose - the software can do anything it wants with them, and the CPU doesn't care. Register 0, however, has a very special purpose: it is the zero register (a concept I read about in the MIPS architecture, and found particularly useful). The zero register always contains the value 0, regardless of what is written to it; this allows the value 0 to always be available to the program, as well as allowing unneeded values (such as the result of subtraction, when all you really care about is the value of the flags - for a conditional branch) to be discarded without overwriting another register.

$31 is nicknamed $ra - the return address. This register is supposed to hold the return address for the current function (at least when the function returns). If the function calls other functions, it must be sure to save and restore its own $ra. As with all the registers that follow, this is not a hardware restriction (as it was in the case of $ra on MIPS), but a software convention that should be followed so that all code remains compatible.

$30 is $sp: the stack pointer. As previously described, the stack is a software structure on Q1; however, as it's integral to the operation of functions, it must be standardized. As with MIPS, $sp always points to the NEXT available stack location (rather than the first occupied stack location, as with x86).

$29 is $gp: the global pointer. This is more of a reserve for function use. Well-behaved Q1 programs should not hard-code the addresses of their global variables. Rather, they are expected to, should they need to access global variables, construct a pointer to their global variables by adding a (negative) offset to the instruction pointer (which can be obtained with the LRA - load relative address - instruction). The global variables can then be accessed through $gp + offset. This variable is nonvolatile; if a function uses it, it must save and restore the previous value, so that it does not overwrite the previous function's $gp.

$2-$5 are $p0-$p3: the first four 32-bit (or smaller) parameters passed to a called function. On return, $2 is $rv: the return value (if the function has a return value of or less than 32 bits).

$2-$15 are also $v0-$v14: the volatile registers. Functions may use these registers however they like, without regard to saving previous values. Thus, if a function needs a value preserved while calling another function, it must either use a different register, or save the value on the stack. These registers allow for functions to do short-term calculations (where the intermediate values are inconsequential, and may be overwritten, and only the end result is important) without the need to save registers on the stack.

$16-$25 are $n0-$n9: the nonvolatile registers. Functions may use these functions however they like, but must save and restore the previous values of any registers they use. These registers are thus saved across function calls, and may be used to store values needed after the call, without the need to save the registers to the stack.

Having both volatile and nonvolatile registers allows for best-of-both-worlds optimization. Intermediate values that will not be needed more than a few instructions later (and not across a function call) can be placed in the volatile registers, and no prolog or epilog code is needed to clean them up. On the other hand, important values can be placed in nonvolatile registers, where cleanup overhead is only needed if the called function actually uses the registers (a probability that is decreased by the fact that the volatile registers are available for quick computations).

The remaining 4 registers are reserved, at this time. The register set isn't 100% final, and I may yet find a use for them.

No comments: