I know that when you read %r0 in SPARC CPU (and MIPS), always return 0, but I like to know Why ?
What design decision is behind this and why ?
It's just the way the CPU was designed. Ensuring that r0
is always set to zero is, for one thing, a way to avoid potentially costly memory accesses for a very common value.
On one hand (reading), it's handy to have a register set aside to contain the value of zero so that you can use it. Otherwise, you would have to load zero into a register yourself.
Many RISC processors tend to favour data manipulation in registers, accessing memory only for load and store operations. That's not a hard and fast rule of RISC, more of a tendency. Setting aside a register so that you always have zero available can be useful - it's a trade-off since you get one less register to use for general purpose values but the MIPS designers obviously thought it was worth it.
On the other hand (writing), because r0
is tied to the value zero, you can put what you want in there and it will make no difference - it will remain at zero. That means you can use it as a target if you want to throw the value away.
Again, this has to do with the philosophy behind RISC. It tends to favour a very small number of instruction formats such as the MIPS R
, I
and J
formats (register, immediate and jump). As an example, rather than having multiple instruction formats depending on whether you want to store the result or not, you can have one set which stores the result always, then just store it into r0
if you don't care about it.
Hence, if you wanted to check if adding two registers would result in an overflow but didn't want to store the result anywhere, you could use:
add $0, $7, $8 ; r0 <- r7 + r8, but r0 remains at 0.
The MIPS documentation, MIPS32 Architecture for Programmers Volume I: Introduction to the MIPS32 Architecture
, confirms the above:
R0 is hard-wired to a value of zero, and can be used as the target register for any instruction whose result is to be discarded. R0 can also be used as a source when a zero value is needed.
The main reason from instruction-set-design point of view is that the existance of a /dev/null
-register allows for certain "condensing" of what otherwise would have to be two (or more) different instructions into a single one. Few examples:
call
and return
, using link registers, can be done with a single instruction:
jmp <tgtreg>,<pc>,<linkreg>
jmp
is an atomic mov <pc>,<linkreg>; mov <tgtreg>,<pc>
), andjmp <linkreg>,<nullreg>,<nullreg>
cmp
or tst
can be a simple sub <a>,<b>,<nullreg>
Complete tables of these can be found from Oracle's documentation, SPARC synthetic instructions and sparcv9 synthetic instructions; most of these involve %g0
somewhere.