
MIPS_primery_zadach / dandamudi05gtr guide risc processors programmers engineers
.pdf
266 |
Guide to RISC Processors |
140:sb $t1,($a0)
141:addu $a0,$a0,1
142:b lower_loop
143:done_lower:
144:jr $ra
145:
146:#-----------------------------------------------------
147:# TO_FLIP_CASE receives a pointer to a string in $a0
148:# and returns the string with uppercase letters
149:# replaced by lowercase letters and vice versa
150:#-----------------------------------------------------
151:to_flip_case:
152:
153:flip_loop:
154:lbu $t1,($a0)
155: |
beqz $t1,done_flip |
# if NULL, we are done |
156:bgtu $t1,’z’,skip_flip
157:bgeu $t1,’a’,convert
158:bgtu $t1,’Z’,skip_flip
159:bgeu $t1,’A’,convert
160:b skip_flip
161:convert:
162:xor $t1,$t1,0x20
163:skip_flip:
164:sb $t1,($a0)
165:addu $a0,$a0,1
166:b flip_loop
167:done_flip:
168: jr $ra
The string reverse procedure we used here is the same as that in Program 13.4 on page 238. The only modification is that we add an additional condition for the termination of the first loop on lines 86–91. This is because, when the string entered is smaller than the buffer length, the read_string system call includes a linefeed (0xA) character. Thus, we terminate the loop if a linefeed (line 88) or NULL (line 89) is encountered.
The procedure to_upper converts all lowercase letters to uppercase. It is based on Program 10.3 (page 178). The lowercase conversion is done by the to_lower procedure. It is very similar to the uppercase conversion procedure with a few minor changes.
The flip case conversion procedure uses exclusive-or (xor) to flip the case. Because the uppercase and lowercase letters differ in the 6th bit from right, we can flip this bit to change the case. For example, the ASCII value for letter “A” is 01000001. The corresponding value for letter “a” is 01100001. Thus, if we use 00100000 as the mask and perform the xor operation, we flip the case. This is what is done in this procedure. Once we check to make sure that the character is a letter (a–z, or A–Z), we use the xor instruction to do the case conversion (line 162).

Chapter 14 • Conditional Execution |
267 |
Summary
We discussed the unconditional and conditional jump instructions as well as compare instructions in detail. These assembly language instructions are useful in implementing high-level language selection and iteration constructs such as if-then-else and while loops. Through detailed examples, we discussed how these high-level decision structures are implemented in the assembly language.
In the previous chapters, we extensively used direct jump and procedure call instructions. In this chapter, we introduced the indirect jumps and procedure calls. In the indirect jump and procedure call instructions, the target of the jump is specified indirectly via a register. By means of examples, we have shown how they are useful in implementing indirect jumps and procedure calls.

15
Logical and Shift
Operations
This chapter looks at the logical, shift and rotate instructions provided by MIPS. The MIPS instruction set provides four logical instructions: and, or, xor, and nor. There is no not instruction. This operation can be synthesized from the nor operation. We have introduced some of these instructions in Chapter 10. The logical instructions are useful to implement high-level language logical expressions. In addition, they can be used for bit manipulation. The shift and rotate instructions are useful in bit shift operations. We give several examples to illustrate the use of these instructions. We end the chapter with a summary.
Introduction
As we have seen in the last chapter, high-level languages provide several conditional and loop constructs. These constructs require Boolean or logical expressions to specify conditions. In principle, only a single bit is needed to represent the Boolean data. However, such a representation, although compact, is not convenient, as testing a variable involves isolating the corresponding bit.
Most high-level languages use a byte to represent the Boolean data. If the byte is zero, it represents false; otherwise, true. Note that any value other than 0 can be used to represent true. In C, which does not provide an explicit Boolean data type, any data variable can be used in a logical expression to represent Boolean data. The rules mentioned above apply.
Assembly language provides several logical instructions, which are useful in implementing logical expressions of high-level languages. For example, C provides the following logical operators.
269

270 |
|
|
Guide to RISC Processors |
|
|
|
|
|
C operator |
Meaning |
|
|
|
|
|
|| |
logical OR |
||
&& |
logical AND |
||
! |
logical NOT |
||
|
|
|
|
The logical instructions are also useful in implementing bitwise logical operations. For example, the following four bitwise logical operators are available in C.
C operator |
Meaning |
| Bitwise-OR
&Bitwise-AND
ˆBitwise-XOR
˜Bitwise-NOT
The MIPS architecture also provides several shift instructions. These instructions are useful in implementing bitwise shift operations. For example, C provides the following two shift operators.
C operator |
Meaning |
>>Right-shift
<<Left-shift
In addition to the shift instructions, two rotate instructions are also available. These are actually pseudoinstructions supported by the assembler.
We have discussed some of these instructions in Chapter 10. This chapter complements the material presented on the logical and shift instructions in that chapter. We begin our discussion with the logical instructions.
Logical Instructions
Logical instructions manipulate logical data just as the arithmetic instructions manipulate arithmetic data (e.g., integers) with operations such as addition and subtraction. The logical data can take one of two possible values: true or false.
Assembly language provides logical operators in the logical family of instructions. MIPS supports four logical operations: and, or, nor, and xor. We have already seen the and and or instructions in Chapter 10. The truth tables for the remaining two operatiors are given in Table 15.1.
Notice that the MIPS instruction set does not have a not instruction. This missing operation is supported by a pseudoinstruction, which can be easily implemented using the nor instruction as

Chapter 15 • Logical and Shift Operations |
271 |
Table 15.1 Truth tables for the xor and nor logical operations
xor operation
Input bits |
Output bit |
|
source1 |
source2 |
destination |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
0 |
|
|
|
nor operation
Input bits |
Output bit |
|
source1 |
source2 |
destination |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
0 |
0 |
1 |
1 |
0 |
|
|
|
nor Rdest,Rsrc,$0
A summary of these instructions is given in Table 15.2. All operations, except not, take two source operands and a destination operand. The not instruction takes one source operand and one destination operand. As with most instructions, all operands must be in registers. However, and, or, and xor instructions can take one immediate operand.
Assembler pseudoinstructions use the same mnemonics for the logical operations and, or, and xor but allow the second source operand to be either a register or a 16bit immediate value. Next we look at some typical uses for the logical operators.
The and Instruction
The and instruction is useful mainly in these situations:
1.To support compound logical expressions and bitwise and operations of high-level languages;
2.To clear one or more bits;
3.To isolate one or more bits.
The use of the and instruction to express compound logical expressions and to implement bitwise and operations is discussed later using examples. Here we concentrate on how and can be used to clear or isolate selected bits of an operand.
Clearing Bits If you look at the truth table of the and operation (see Table 10.4 on page 170), you will notice that source1 acts as a masking bit: if the masking bit is 0, the output is 0, no matter what the other input bit is; if the masking bit is 1, the other input bit is passed to the output. Consider the following example.
$t0 = 10010011 00001111 01110010 11010110 ← operand $t1 = 11111111 11111111 11111111 11111100 ← mask $t2 = 10010011 00001111 01110010 11010100
272 |
|
Guide to RISC Processors |
||
|
|
Table 15.2 MIPS logical instructions |
||
|
|
|
|
|
|
Instruction |
Description |
||
|
and |
Rdest,Rsrc1,Rsrc2 |
Bitwise AND of Rsrc1 and Rsrc2 is stored in |
|
|
|
|
Rdest. |
|
|
andi |
Rdest,Rsrc1,imm16 |
Bitwise AND of Rsrc1 and a 16-bit imm16 is stored |
|
|
|
|
in Rdest. The 16-bit imm16 is zero-extended. |
|
|
or |
Rdest,Rsrc1,Rsrc2 |
Bitwise OR of Rsrc1 and Rsrc2 is stored in Rdest. |
|
|
ori |
Rdest,Rsrc1,imm16 |
Bitwise OR of Rsrc1 and a 16-bit imm16 is stored in |
|
|
|
|
Rdest. The 16-bit imm16 is zero-extended. |
|
|
not† |
Rdest,Rsrc |
Bitwise NOT of Rsrc is stored in Rdest. |
|
|
xor |
Rdest,Rsrc1,Rsrc2 |
Bitwise XOR of Rsrc1 and Rsrc2 is stored in |
|
|
|
|
Rdest. |
|
|
xori |
Rdest,Rsrc1,imm16 |
Bitwise XOR of Rsrc1 and a 16-bit imm16 is stored |
|
|
|
|
in Rdest. The 16-bit imm16 is zero-extended. |
|
|
nor |
Rdest,Rsrc1,Rsrc2 |
Bitwise NOR of Rsrc1 and Rsrc2 is stored in |
|
|
|
|
Rdest. |
|
|
|
|
|
|
Here, $t0 contains the operand to be modified and $t1 contains a set of masking bits. Let us say that we want to force the least significant two bits to 0 without altering any of the remaining 30 bits. We select our mask in $t1 such that it contains 0s in those two bit positions and 1s in the remainder of the bit positions. With this mask, we use the following instruction to get the desired result in $t2.
and $t2,$t1,$t0
Here is an example that utilizes the bit clearing capability of the and instruction.
Example 15.1 Even-parity generation (partial code).
Let us consider generation of even parity. Assume that the most significant bit of a byte represents the parity bit; the rest of the byte stores the data bits. The parity bit can be set or cleared so as to make the number of 1s in the whole byte even.
If the number of 1s in the least significant seven bits is even, the parity bit should be 0. Assuming that the byte to be parity-encoded is in the $t0 register, the statement
and $t0,$t0,0x7F
clears the parity bit without altering the remaining bits. |
|
Chapter 15 • Logical and Shift Operations |
273 |
Isolating Bits Another typical use of the and instruction is to isolate selected bits for testing. This is done by masking all the other bits, as shown in the next example.
Example 15.2 Determining odd or even number.
In this example, we want to find out if the unsigned number in the $t0 register is an odd or even number. A simple test to determine this is to check the least significant bit of the number: if this bit is 1, it is an odd number; otherwise, an even number.
Here is the code to perform this test using the and instruction.
and |
$t1,$t0,1 |
; mask = 0...000001 |
beqz $t1,even_number |
||
odd_number: |
|
|
|
. . . |
|
<code for processing odd number> |
||
|
. . . |
|
even_number: |
|
|
|
. . . |
|
<code for processing even number> |
||
|
. . . |
|
If $t0 has an even number, the least significant bit of $t0 is 0. Therefore, and $t1,$t0,1
would produce a zero result in $t1. The beqz instruction is then used to test the result in $t1 and to selectively execute the appropriate code fragment. This example shows the use of and to isolate a bit, the least significant bit in this case. We use this test later in a programming example.
The or Instruction
Like the and instruction, the or instruction is useful in several situations:
1.To support compound logical expressions and bitwise or operations of high-level languages;
2.To set one or more bits;
3.To load a constant into a register.
The use of the or instruction to express compound logical expressions and to implement bitwise or operations is discussed later using examples. We now discuss how the or instruction can be used to set a given set of bits and to load a constant.
Setting Bits As you can see from the truth table for the or operation (see Table 10.4 on page 170), when source1 is 0, the other input is passed on to the output; when source1 is 1, the output is forced to take a value of 1 irrespective of the other input. This property is used to set bits in the output. This is illustrated in the following example.
274 |
|
|
Guide to RISC Processors |
||
$t0 |
= 11110000 01010101 00110011 |
11010110B |
← operand |
||
$t1 |
= 00000000 00000000 00000000 |
00000011B |
← mask |
||
|
|
|
|
|
|
$t2 |
= 11110000 01010101 00110011 |
11010111B |
|
The value in $t2 is produced by the instruction:
or $t2,$t1,$t0
The mask value in $t1 causes the least significant two bits to change to 1. Here is an example that illustrates the use of the or instruction.
Example 15.3 Even-parity encoding (partial code).
Consider the even-parity encoding discussed in Example 15.1. If the number of 1s in the least significant 7 bits is odd, we have to make the parity bit 1 so that the total number of 1s is even. This is done by
or $t0,$t0,0x80
assuming that the byte to be parity-encoded is in the $t0 register. The or operation forces the parity bit to 1 without altering the remaining bits.
Loading a Register MIPS does not provide instructions to move data into registers. As we have seen in Chapter 10, the li pseudoinstruction can be used for this purpose. This pseudoinstruction is implemented by using the or instruction. As an example, look at the following li instruction.
li $t0,0x30
This instruction is implemented as
ori $8,$0,50
Note that $t0 maps to $8 and register $0 is hardwired to zero.
Cutting and Pasting Bits The and and or instructions together can be used to “cut and paste” bits from two or more operands. We have already seen how the and can be used to isolate selected bits, analogous to the “cut” operation. The or instruction can be used to “paste” the bits. For example, the following code creates a new byte in $t2 by combining odd bits from $t0 and even bits from $t1 registers.
and |
$t0,$t0,0x55 |
; cut odd bits |
and |
$t1,$t1,0xAA |
; cut even bits |
or |
$t2,$t1,$t0 |
; paste them together |
The first and instruction selects only the odd bits from the $t0 register by forcing all even bits to 0. The second and instruction selects the even bits by using the mask 0xAA. The or instruction simply pastes these two bytes together to produce the desired byte in the $t2 register.
Chapter 15 • Logical and Shift Operations |
275 |
The xor Instruction
The xor instruction is useful mainly in these situations:
1.To support compound logical expressions of high-level languages;
2.To toggle one or more bits.
The use of the xor instruction to express compound logical expressions is similar to the and or operations. Here we focus on the use of xor to toggle bits.
Toggling Bits Using the xor instruction, we can toggle a specific set of bits. To do this, the mask should have 1 in the bit positions that are to be flipped. The following example illustrates this application.
Example 15.4 Parity conversion.
Suppose we want to change the parity encoding of incoming data: if even parity, change to odd parity and vice versa. To accomplish this change, all we have to do is flip the parity bit, which can be done by
xor $t0,$t0,0x80
Thus, an even-parity encoded ASCII character A in $t0—01000001—is transformed into odd-parity encoding, as shown below:
01000001 |
|
← even-parity encoded ASCII character A |
|
xor 10000000 |
← mask |
||
|
|
|
← odd-parity encoded ASCII character A |
|
11000001 |
In the above example, we have shown only the least significant byte of $t0. Notice that if we perform the same xor operation on odd-parity encoding of A, we get back the even-parity encoding! This is an interesting property of the xor operation: xoring twice gives back the original value. This is not hard to understand, as xor behaves as the not operation does by selectively flipping bits. This property is used in the following example to encrypt a byte.
Example 15.5 Encryption of data.
Data encryption is useful in applications that deal with sensitive data. We can write a simple encryption program by using the xor instruction. The idea is that we use the encryption key as the mask byte of the xor instruction as shown below. Assume that the byte to be encrypted is in the $t0 register and the encryption key is 0x26.
; read a data byte into $t0
xor $t0,$t0,0x26
; write the data byte back from $t0

276 |
Guide to RISC Processors |
Suppose we have received character B, whose ASCII code is 01000010B. After encryption, the character becomes d in ASCII, as shown below.
01000010 ← ASCII character B
00100110 ← encryption key (mask)
01100100 ← ASCII character d
An encrypted data file can be transformed back into normal form by running the encrypted data through the same encryption process again. To continue with our example, if the above encrypted character code 64H (representing d) is passed through the encryption procedure, we get 42H, which is the ASCII code for character B.
The nor Instruction
The nor instruction is needed to implement not, as MIPS does not provide it. Its main use is in supporting logical expressions of high-level languages. Furthermore, in languages such as C, it can also be used to implement the bitwise not operation.
Another possible use for the not instruction is to compute negative numbers in the 1’s complement representation. Recall that the 1’s complement of a number is simply the complement of the number. However, most systems use the 2’s complement representation. The not instruction is not particularly useful for generating 2’s complement representation. A simple example illustrates this point clearly. In the 2’s complement representation, to negate the value in $t0, we have to use
not $t0,$t0 add $t0,$t0,1
However, we can do better than this by using a single sub instruction as shown here:
sub $t0,$0,$t0
This is precisely what the neg pseudoinstruction does.
Shift Instructions
As we have seen in Chapter 10, MIPS supports both leftand right-shift instructions to facilitate bit operations. We have already described the basic shift operations in Chapter 10, therefore we look at the remaining shift instructions in this section.
The number of bit positions to be shifted (i.e., shift count) can be specified as an immediate 5-bit value or via a register. If a register is used, only the least significant five bits are used as the shift count. In the basic left-shift instruction sll, the shift count is given as a 5-bit immediate value (see page 170).
The sllv (shift left logical variable) instruction
sllv Rdest,Rsrc1,Rsrc2