The SuperH-3, part 4: Basic arithmetic
Okay, we’re ready to do some arithmetic. Due to the limited instruction encoding space, there isn’t room for any three-operand instructions.¹ All of the arithmetic instructions are two-operand, where the second source operand also acts as the destination.
ADD Rm, Rn ; Rn += Rm , no effect on T ADD #imm, Rn ; Rn += imm , no effect on T ADDC Rm, Rn ; Rn += Rm + T, T receives carry ADDV Rm, Rn ; Rn += Rm , T receives signed overflow
ADD instructions add two values and put the result in the second register. You can add two registers together, or you can add a signed 8-bit immediate to the destination register.
ADDC instruction treats the T flag as a carry flag: It is added to the sum, and it receives the carry of the result.
ADDV instruction treats the T flag as an overflow flag: It reports whether a signed overflow occurred.
Okay, subtraction is going to look really similar now.
SUB Rm, Rn ; Rn -= Rm , no effect on T SUB #imm, Rn ; Rn -= imm , no effect on T SUBC Rm, Rn ; Rn -= Rm + T, T receives borrow SUBV Rm, Rn ; Rn -= Rm , T receives signed underflow
Basically the same as addition, except you’re now subtracting. The SH-3 treats T as a borrow flag in the case of
SUBC, whereas for
SUBV it reports whether a signed underflow occurred.
Arithmetic negation is up next.
NEG Rm, Rn ; Rn = -Rm , no effect on T NEGC Rm, Rn ; Rn = -Rm - T, T receives borrow
There is no
NEGV, but overflow occurs only if the value is
0x80000000, so I guess you could test for that value specifically.
There is a special instruction for for decrementing a register:
DT Rn ; Rn = Rn - 1, T = (Rn == 0)
The decrement and test instruction decrements a register and compares the result against zero. This is presumably for counted loops.
Next come the comparison instructions.
CMP/EQ #imm, r0 ; T = (r0 == signed 8-bit immediate) CMP/EQ Rm, Rn ; T = (Rn == Rm) CMP/HS Rm, Rn ; T = (Rn ≥ Rm), unsigned comparison CMP/GE Rm, Rn ; T = (Rn ≥ Rm), signed comparison CMP/HI Rm, Rn ; T = (Rn > Rm), unsigned comparison CMP/GT Rm, Rn ; T = (Rn > Rm), signed comparison CMP/PZ Rn ; T = (Rn ≥ 0), signed comparison CMP/PL Rn ; T = (Rn > 0), signed comparison CMP/STR Rm, Rn ; T = 1 iff any corresponding bytes are equal
These instructions set the T flag according to a particular comparison. Note that the comparison is backward! For example,
CMP/GE r1, r2 does not check whether r1 ≥ r2; rather, it checks whether r2 ≥ r1. This takes a lot of getting used to.
You have the special ability to compare r0 for equality with a signed 8-bit immediate. Otherwise, you can compare two registers against each other, or a register against zero.
CMP/STR compares two registers to determine whether any of the four component bytes are equal. It’s clear from the mnemonic that the intended purpose is to search for a null terminator in a string. You set Rn to zero and then do a
CMP/STR against every longword in the string until it says, “Hey, I found a zero byte!” and then you can study that longword to see where the zero byte is.
The processor documentation doesn’t explain why they chose the names for the mnemonics, but I can guess.
|high or same|
|greater or equal|
|plus or zero|
It took me a while to come up with a plausible explanation for
Exercise 1: Synthesize the
Exercise 2: Perform the opposite of the
MOVT instruction: Set the T register to 0 if a register is zero, or 1 if the register is nonzero.
The last arithmetic instructions are the extension instructions.
EXTS.B Rm, Rn ; sign extend byte in Rm to Rn EXTS.W Rm, Rn ; sign extend word in Rm to Rn EXTU.B Rm, Rn ; zero extend byte in Rm to Rn EXTU.W Rm, Rn ; zero extend word in Rm to Rn
That’s it for the basic arithmetic instructions. We’ll start looking at the more complicated arithmetic instructions next time, starting with multiplication.
¹ Well, okay, you can have three-operand instructions if some of them are hard-coded! But that’s not what I mean. I mean three-operand instructions where the programmer can choose all three of the operands.