6. Hawk Shift Instructions
the Hawk Manual
6.1. Shift Format
6.2. Left Shift
6.3. Right Shift
6.4. Bit Testing
|1 0 - -||dst||s1||s2|
The three register arithmetic format instructions are 16 bits each, specifying a source register (s1), a destination register (dst) and a shift count s derived from (s2).
Note that shift counts from 1 to 15 use the conventional binary encoding, but a count of zero is interpreted as meaning 16. Assemblers should reverse this, taking counts from 1 to 16 and encoding 16 as zero.
|1 0 1 1||dst (x)||s1 (nz)||s2 (16)||MOVESL||dst,s1,s||r[dst] = r[s1]«s|
|1 0 1 0||dst (nz)||s1 (0)||s2 (16)||ADDSL||dst,s1,s||r[dst] = r[dst]«s + r[s1]|
|MOVESL||N = r[dst]:31||— result is negative|
|Z = (r[dst] = 0)||— result is zero|
|V = (r[dst]:31 ≠ r[src]':31)|
|C = (r[s1]'«s) > 232-1|
|ADDSL||N = r[dst]:31|
|Z = (r[dst] = 0)|
|V = ( r[dst]:31 ⊕ ( r[dst]':31 ≡ r[s1]':31 ))|
|C = (r[dst]'«s + r[s1]') > 232-1|
The MOVESL (move and shift left) instruction moves an operand from register to register while shifting left. ADDSL (add and shift left) first shifts the destination register left and then adds in the source.
After MOVESL and ADDSL, the conditon codes will be set to reflect the result; if any one bits are shifted out of r[dst] or if the add results in a carry out, the C bit will be set; if the sign of r[dst] is different from the expected sign, the V bit will be set, and N and Z will be set if the result is negative or zero.
Note that when the source operand of the ADDSL instructions is R0, it simply shifts the destination register. Assemblers should support the SL symbolic opcode names for this use:
|1 0 1 0||dst (nz)||0 0 0 0||s2 (16)||SL||dst,s||r[dst] = r[dst] « s|
The ADDSL instructions allow fast multiplication and array indexing. Given that R1 points to an array and R2 contains a displacement into the array, if array elements have sizes that are powers of two, ADDSL R1,R2,X can be used to compute the address of the correct array element in R1. Single ADDSL instructions can be used to multiply by many common constants:
SL R1,1 ; multiply by 2 ADDSL R1,R1,1 ; multiply by 3 SL R1,2 ; multiply by 4 ADDSL R1,R1,2 ; multiply by 5 SL R1,3 ; multiply by 8 ADDSL R1,R1,3 ; multiply by 9
For more details on multiplication, see the discussions in the chapter on multiplication and division.
|1 0 0 1||dst (x)||s1 (0)||s2 (16)||ADDSR||dst,s1,s||r[dst] = (r[dst]+r[s1])»s|
|1 0 0 0||dst (x)||s1 (0)||s2 (16)||ADDSRU||dst,s1,s||r[dst] = (r[dst]+r[s1])›»s|
| ADDSR |
|N = r[dst]:31||— result is negative|
|Z = (r[dst] = 0)||— result is zero|
|V = ((r[dst]' + r[s1]'):s-1:0 ≠ 0)|
|C = (r[dst]' + r[s1]'):s-1|
The ADDSR (add and shift right) and ADDSRU (add and shift right, unsigned) instructions both add r[src] to r[dst] and then shift r[dst] to the right. ADDSR uses a signed shift, duplicating the sign bit, while ADDSRU uses an unsigned shift, shifting zeros into the left end of the result. The intermediate result between the add and shift is a 33 bit quantity, and as a result, overflow will not occur.
After ADDSR and ADDSRU, the N and Z bits will be set as usual. The V bit will be set if any one bits are shifted out of the result, and the C bit will be set to the last bit shifted out.
Note that when the second operand of the ADDSR instructions is R0, these instructions simply shift their first operand. Assemblers should support the SR (shift right) and SRU (shift right, unsigned) symbolic opcode names for these uses:
|1 0 0 1||dst (x)||0 0 0 0||s2 (16)||SR||dst,s||r[dst] = r[dst] » s|
|1 0 0 0||dst (x)||0 0 0 0||s2 (16)||SRU||dst,s||r[dst] = r[dst] ›» s|
The SR instructions allow fast division by powers of two, and the ADDSR instructions allow for division by other small constants. Note that the SR instruction, when applied to negative values where the remainder after division is nonzero, produces results that are not necessarily intuitive. For example, –3 shifted one place right is –2, while a knowledge of elementary school arithmetic suggests that (–3)/2 should be –1 with a remainder of –1. The quotient –2 is correct under a different rule: The remainder is alwasys between zero and the divisor, which is to say, it is positive, requiring the quotient to be rounded down instead of rounded toward zero.
SR R1,1 ; signed divide by 2, truncating downward SRU R1,1 ; unsigned divide by 2, truncated SR R1,2 ; signed divide by 4, truncating downward SRU R1,4 ; unsigned divide by 8, truncated
For details on more general multiplication and division, see the discussions in the chapter on multiplication and division. See the ADJUST instruction for a tool to restore the expected value of negative quotients.
Any bit in a register can be tested using one of three instructions: To test bits 0 to 15, use ADDSR to move this bit to the C condition code. To test bits 16 to 30, use MOVESL to move this bit to the N condition code. To test bit 31, use MOVECC to move this bit to the N condition code. In each case, the test can be done with register zero as the destination register. It is confusing that a different condition code is set when testing the high bits of a word than when testing the low bits. Nonetheless, assemblers should support the BITTST symbolic opcode name for this function, allowing a bit number b between 0 and 31:
|1 0 0 1||0 0 0 0||s1 (0)||s2 (16)||BITTST||dst,s-1||0 ≤ b ≤ 15: s = b + 1|
|1 0 1 1||0 0 0 0||s1 (nz)||s2 (16)||BITTST||s1,31-s||16 ≤ b ≤ 30: s = 31 - b|
|1 1 1 1||0 0 0 0||1 1 1 0||x||BITTST||x,31||b = 31|
The assembler should generate one or the other of the above BITTST instructions, depending on the bit number provided, so that BITTST r,0 tests the least significant bit and BITTST r,31 tests the most significant bit. Because the condition code to be tested depends on the bit that was tested, BITTST should define or redefine the BBS (branch on bit set) instruction to be equivalent to either BCS or BNS, and the BBR (branch on bit reset) instruction to be equivalent to either the BCR or BNR instruction, depending on the bit tested. Thus, BITTST followed immediately by BBS or BBR will always check the correct condition code.