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
The 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.
The ADDC
instruction treats the T flag as a carry flag: It is added to the sum, and it receives the carry of the result.
The 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.
The special 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.
Condition | Meaning |
---|---|
EQ |
equal |
HS |
high or same |
GE |
greater or equal |
HI |
high |
GT |
greater than |
PZ |
plus or zero |
PL |
plus |
STR |
string |
It took me a while to come up with a plausible explanation for HS
.
Exercise 1: Synthesize the SETT
and CLRT
instructions.
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.
The comparison mnemonics come from the Motorola 68000's branch instructions. Hitachi was a major second source of 68Ks, so it's not much of a suprise that they borrowed from it.
CMP/STR is handy when searching for any byte, not just zeroes. Just replicate the byte value in the register. If you're looking for ASCII 'a', you would compare with 0x61616161.
Answer to exercise 1:
SETT -> CMP/EQ R0, R0
CLRTT -> CMP/NE R0, R0
Answer...
> T receives signed underflowAn underflow is when a floating point number is too small to be representable. A negative overflow is still an overflow.
> It took me a while to come up with a plausible explanation for
HS
.I think ARM uses
HS
as a synonym forCS
(carry set). (But then again it use a single comparison operator corresponding to (most of) these with multiple conditions on instructions.)I think this will work for exercise 2, but I’m not certain that I’ve understood the meaning of “borrow” correctly:
I had to look up the exact semantics too. The ISA description gives it as follows (this will look awful I’m sure but I hope it’ll be readable)
Exercise 1:
CMP/EQ r0, r0 => T = 1
CMP/HI r0, r0 => T = 0
Exercise 2:
CMP/PL Rx => T = Rx > 0…but won’t work for negative Rx. Can’t think of way to solve without destroying Rx.