MIPS_primery_zadach / dandamudi05gtr guide risc processors programmers engineers
.pdf236 |
Guide to RISC Processors |
19: .space 11 20:
21:#################### Code segment ########################
22:.text
23:.globl main
24:main:
25: |
la |
$a0,prompt |
# prompt user for input |
26:li $v0,4
27:syscall
29: |
la |
$a0,in_number |
# |
read input string |
30: |
li |
$a1,11 |
# |
buffer length in $a1 |
31:li $v0,8
32:syscall
34:la $a0,in_number
35:jal convert_int
36:move $t0,$v0
37: |
|
|
|
38: |
la |
$a0,out_msg |
# write output message |
39:li $v0,4
40:syscall
42: |
move $a0,$t0 |
# output integer |
43:li $v0,1
44:syscall
46: |
la |
$a0,newline |
# write newline |
47:li $v0,4
48:syscall
50: |
li |
$v0,10 |
# exit |
51: |
syscall |
|
|
52: |
|
|
|
53:#----------------------------------------------------
54:# CONVERT_INT receives a pointer to a string in $a0
55:# and returns the number in $v0.
56:# $t1 - used as a temporary
57:#----------------------------------------------------
58:convert_int:
59: |
li |
$v0,0 |
# number = 0 |
60: |
loop: |
|
|
61: |
lbu |
$t1,($a0) |
|
62: |
beq |
$t1,0xA,done |
# if linefeed or |
63: |
beqz |
$t1,done |
# NULL, we are done |
64: |
and |
$t1,$t1,0xF |
# mask off upper bits |
65: |
mulou |
$v0,$v0,10 |
# number = number * 10 |
Chapter 13 • |
Arithmetic Instructions |
|
237 |
|
66: |
addu |
$v0,$v0,$t1 |
# |
add the current digit |
67: |
addu |
$a0,$a0,1 |
# |
update pointer |
68: |
b |
loop |
|
|
69:done:
70: jr $ra
The convert_int procedure uses $v0 to keep the number. It is initialized to zero on line 59. The conversion loop consists of lines 60–68. Each character from the input string is read into $t1 (line 61). Note that the input string, read by the read_string syscall, may consist of the linefeed (0xA) character if the number of characters entered is less than the buffer length. On the other hand, if 10 digits are entered, there will not be a linefeed character. In both cases, the string is terminated by a NULL character. Thus, the end-of-string test should check for a linefeed or NULL character. These two conditions are tested on lines 62 and 63. If either of them is true, the conversion process is done.
The character in $t1 is converted to its numeric equivalent by masking the upper four bits (line 64). The required multiplication (by 10) is done on line 65 and the numeric value of the current digit (in $t1) is added on line 66. The index is updated on line 67. When the loop is terminated, we simply return as the value is in the $v0 register.
Example 13.3 Number-to-string conversion to display an integer.
Our objective here is to write a procedure that displays a signed 32-bit integer. In order to do this, we have to separate individual digits of the number to be displayed and convert each digit to its ASCII representation. The steps involved are illustrated by the following example, which assumes that the number is 108.
separate 1 → convert to ASCII → 0x31 → display separate 0 → convert to ASCII → 0x30 → display separate 8 → convert to ASCII → 0x38 → display
Separating individual digits is the heart of the procedure. This step is surprisingly simple! All we have to do is repeatedly divide the number by 10, as shown here:
|
|
Quotient |
Remainder |
108/10 |
= |
10 |
8 |
10/10 |
= |
1 |
0 |
1/10 |
= |
0 |
1 |
The only problem with this step is play. Therefore, we need to buffer pseudocode for the process_int
that the digits come out in the reverse order of disthe digits and reverse them before displaying. The procedure is shown below:
238 |
Guide to RISC Processors |
process_int (number, Buffer) |
|
index := 0 |
|
if (number is negative) |
|
then |
|
Buffer[index] := ’−’ |
|
index := index + 1 |
{get absolute value} |
number := ABS(number) |
|
end if |
|
repeat |
{integer division} |
quotient := number/10 |
|
remainder := number % 10 |
{% is modulo operator} |
{save the ASCII character equivalent of remainder} Buffer[index] := remainder OR 0x30
index := index + 1 number := quotient
until (number = 0) string_reverse (Buffer) return
end process_int
The program listing is given in Program 13.4. As in the other programs, the main program handles the user interface. It reads the input number using the read_int system call (lines 29–31). It passes the integer in $a1 and a buffer pointer in $a0 to the process_int procedure.
Program 13.4 A program to output 32-bit integers
1: # Converts an integer to a digit string |
PUTINT.ASM |
2:#
3:# Objective: Converts an integer into a string of digits.
4:# Input: Requests an integer.
5:# Output: Outputs the digit string.
6:#
7:# $a0 - used to pass the string pointer
8:# $a1 - used to pass the number
9:#
10:################### Data segment #######################
11:.data
12:prompt:
13: |
.asciiz |
"Please enter a positive integer: \n" |
14:out_msg:
15: |
.asciiz |
"The number is: " |
16:newline:
17:.asciiz "\n"
Chapter 13 • Arithmetic Instructions |
239 |
18:out_number:
19: .space 11 20:
21:################### Code segment #######################
22:.text
23:.globl main
24:main:
25: |
la |
$a0,prompt |
# prompt user for input |
26:li $v0,4
27:syscall
29: |
li |
$v0,5 |
# read number into $a1 |
30:syscall
31:move $a1,$v0
33: |
la |
$a0,out_number |
# |
$a0 = string pointer |
34: |
jal |
process_int |
|
|
35: |
|
|
|
|
36: |
la |
$a0,out_msg |
# |
write output message |
37:li $v0,4
38:syscall
40: |
la |
$a0,out_number |
# output number |
41:li $v0,4
42:syscall
44: |
la |
$a0,newline |
# write newline |
45:li $v0,4
46:syscall
48: |
li |
$v0,10 |
# exit |
49: |
syscall |
|
|
50: |
|
|
|
51:#----------------------------------------------------
52:# PROCESS_INT receives a pointer to a string and an
53:# integer. It converts the number to string form and
54:# returns it in the string.
55:# $a0 - string pointer
56:# $a1 - integer to be converted (also quotient)
57:# $t0 - pointer to string for string reverse
58:# $t1 - remainder
59:#----------------------------------------------------
60:process_int:
61: |
sub |
$sp,$sp,4 |
# save $ra |
62: |
sw |
$ra,0($sp) |
|
63: |
|
|
|
64: |
# $t0 |
keeps string pointer (for string reverse) |
240 |
Guide to RISC Processors |
65:# if the number is +ve, this is the value passed
66:# if -ve, $t0 is advanced past the -ve sign
67:move $t0,$a0
68:
69:bgez $a1,positive
70:abs $a1,$a1
71: |
li |
$t0,’-’ |
# $t0 is used as a temp |
72:sb $t0,($a0)
73:addu $a0,$a0,1
74:# save this position for string reverse
75:move $t0,$a0
76:
77:positive:
78: |
li |
$t2,10 |
# $t2 = divisor |
79:loop:
80:divu $a1,$t2
81:# div leaves quotient in LO and remainder in HI
82:mflo $a1
83:mfhi $t1
84: |
or |
$t1,$t1,0x30 |
# convert digit to char. |
85:sb $t1,($a0)
86:addu $a0,$a0,1
87: |
bnez |
$a1,loop |
# if quotient is not 0, |
|
88: |
|
|
# |
loop |
89: |
sb |
$a1,($a0) |
# |
append NULL ($a1=0) |
90: |
|
|
|
|
91:# now reverse the string (excluding the -ve sign)
92:move $a0,$t0
93:jal string_reverse
94: |
|
|
|
95: |
lw |
$ra,0($sp) |
# restore $ra |
96:add $sp,$sp,4
97:jr $ra
98:
99:#------------------------------------------------------
100:# STRING_REVERSE receives a pointer to a string in $a0
101:# and reverses the string
102:#------------------------------------------------------
103:string_reverse:
104: |
move $t1,$a0 |
# $t1 points to string |
105:loop1:
106:lbu $t2,($t1)
107: |
beqz $t2,done |
# if NULL, we are done |
108:addu $t1,$t1,1
109:b loop1
110:done:
111: |
sub $t1,$t1,1 |
# $t1 = end of string |
Chapter 13 • Arithmetic Instructions |
241 |
112:reverse_loop:
113:bleu $t1,$a0,done_reverse
114: |
lbu $t2,($a0) |
# |
|
115: |
lbu $t3,($t1) |
# exchange |
|
116: |
sb |
$t2,($t1) |
# characters |
117: |
sb |
$t3,($a0) |
# |
118:addu $a0,$a0,1
119:subu $t1,$t1,1
120:b reverse_loop
121:done_reverse:
122: jr $ra
The process_int procedure follows the logic of the pseudocode. The code on lines 70–75 is executed if the number is negative. This test is done by bgez on line 69. The repeat loop is implemented on lines 79–87. Because the divide instruction (on line 80) leaves the quotient and remainder in the LO and HI registers, we use mflo and mfhi to move these values to general registers (lines 82 and 83). The loop termination condition (i.e., quotient = 0) is tested on line 87. After exiting the loop, it calls the string_reverse procedure to reverse the string for output.
The string_reverse procedure follows the pseudocode shown below:
string_reverse (Buffer) left := 0
right := 0
{Move right to the end of string} while (Buffer[right] =NULL)
right := right + 1 end while
right := right − 1 {back up to point to the end of string} while (left < right)
Buffer[left] Buffer[right] {exchange} left := left + 1
right := right − 1 end while
return
end string_reverse
The left index is initialized to point to the left-hand side of the string. The right index is moved to the last digit in the string by the first while loop. Once the left and right are pointing to the beginning and end of the string, we exchange the values. Then the indexes left and right are updated (left is incremented and right is decremented). We repeat this process as long as left is less than right (the continuation condition for the second while loop). The string_reverse procedure implements this algorithm in
242 |
Guide to RISC Processors |
a straightforward way. The first while loop is implemented on lines 105–109 and the second while loop on lines 112–120.
Summary
We have presented details on the arithmetic instructions. The MIPS instruction set supports the basic add, subtract, multiply, and divide operations. The multiply and divide instructions place the result in special HI and LO registers. The instruction set provides instructions that move data between these registers and the general registers. Although add and subtract instructions work on both signed and unsigned numbers, multiply and divide operations have separate instructions to work on signed and unsigned numbers. We have used several examples to illustrate the application of these instructions.
14
Conditional Execution
Conditional execution is important to alter the control flow from the default sequential execution. The MIPS architecture provides several instructions to facilitate conditional execution. We have already seen some of these instructions including the unconditional and conditional branch instructions. In addition, procedure invocation and return also alter control flow. We briefly introduced some of these instructions in previous chapters. This chapter gives a complete discussion of these instructions.
The target address of these flow-altering instructions can be specified either directly in the instruction or indirectly via a register. In previous chapters, we used direct specification for jumps and procedure calls. However, we used indirect specification to return from a procedure. Most jumps and procedure calls use the direct specification. However, sometimes it is useful to specify the target address indirectly via a register. We discuss such indirect jumps and procedure calls toward the end of the chapter. We conclude the chapter with a summary.
Introduction
Modern high-level languages provide a variety of decision structures. These structures include selection structures such as if-then-else and iterative structures such as while and for loops. Assembly language, being a low-level language, does not provide these structures directly. However, assembly language provides several basic instructions that could be used to construct these high-level language selection and iteration structures. For example, the following code
li $t2,50
loop:
addu $t0,$t0,$t1 sub $t2,$t2,1 bnez $t2,loop
implements a loop that iterates 50 times.
243
244 |
Guide to RISC Processors |
In this example, we implemented the loop using a conditional branch instruction. Some instruction architectures provide loop instructions to implement the iterative construct. For example, the Intel IA-32 architecture provides a loop instruction that decrements the loop index and jumps to the target if it is not zero. Thus, the loop instruction essentially is equivalent to the two-instruction sequence sub/bnez in our code. In fact, on Pentium, the two-instruction sequence is faster than the single loop instruction. As a result, the loop instruction is not used to optimize the code. This example reinforces the reasons we discussed in Chapter 3 for not using complex instructions.
The MIPS assembly language provides instructions for unconditional and conditional jumps, procedure calls, and so on. We briefly introduced some of these instructions in Chapters 10 and 11. Our discussion in this chapter complements that discussion.
There are two distinct ways by which the target address of an instruction such as branch can be specified: direct and indirect. In direct specification, the target address is specified directly as part of the instruction. For example, the conditional branch instruction (bnez) in the previous code fragment is encoded as
bne $10,$0,−8
where −8 is the relative offset of the branch instruction. In indirect target specification, the address is given via a register. We have used indirect jumps to return from a procedure. For example, we used the instruction
jr $ra
to return from a procedure where the return address is in the $ra register. In general, we can use any register for indirect jumps. Similarly, procedures can also be invoked via indirect target specification. We look at this topic towards the end of the chapter.
The MIPS assembly language also provides several compare instructions. These instructions are discussed next.
Comparison Instructions
Several comparison pseudoinstructions are available. All these instructions compare the contents of two registers and if the specified condition such as “less than” is true, the destination register is set to 1; otherwise, it is cleared to zero. For example, the instruction slt (Set on Less Than)
slt† Rdest,Rsrc1,Rsrc2
sets Rdest to one if the contents of Rsrc1 are less than the contents of Rsrc2; otherwise, Rdest is set to zero. This instruction treats the contents of Rsrc1 and Rsrc2 as signed numbers. To test for the “less than” relationship, slt subtracts contents of Rsrc2 from the contents of Rsrc1.
Chapter 14 • Conditional Execution |
245 |
||||
|
|
Table 14.1 MIPS comparison instructions |
|
|
|
|
|
|
|
|
|
|
Instruction |
Description |
|
|
|
|
seq† |
Rdest,Rsrc1,Src2 |
Rdest is set to one if contents of Rsrc1 and Src2 |
||
|
|
|
are equal; otherwise, Rdest is set to zero. |
|
|
|
sgt† |
Rdest,Rsrc1,Src2 |
Rdest is set to one if contents of Rsrc1 are greater |
||
|
|
|
than Src2; otherwise, Rdest is set to zero. Source |
||
|
|
|
operands are treated as signed numbers. |
|
|
|
sgtu† |
Rdest,Rsrc1,Src2 |
Same as sgt except that the source operands are |
||
|
|
|
treated as unsigned numbers. |
|
|
|
sge† |
Rdest,Rsrc1,Src2 |
Rdest is set to one if contents of Rsrc1 are greater |
||
|
|
|
than or equal to Src2; otherwise, Rdest is set to |
||
|
|
|
zero. Source operands are treated as signed numbers. |
||
|
sgeu† |
Rdest,Rsrc1,Src2 |
Same as sge except that the source operands are |
||
|
|
|
treated as unsigned numbers. |
|
|
|
slt† |
Rdest,Rsrc1,Src2 |
Rdest is set to one if contents of Rsrc1 are less |
||
|
|
|
than Src2; otherwise, Rdest is set to zero. Source |
||
|
|
|
operands are treated as signed numbers. |
|
|
|
sltu† |
Rdest,Rsrc1,Src2 |
Same as slt except that the source operands are |
||
|
|
|
treated as unsigned numbers. |
|
|
|
sle† |
Rdest,Rsrc1,Src2 |
Rdest is set to one if contents of Rsrc1 are less than |
||
|
|
|
or equal to Src2; otherwise, Rdest is set to zero. |
||
|
|
|
Source operands are treated as signed numbers. |
|
|
|
sleu† |
Rdest,Rsrc1, Src2 |
Same as sle except that the source operands are |
||
|
|
|
treated as unsigned numbers. |
|
|
|
sne† |
Rdest,Rsrc1,Src2 |
Rdest is set to one if contents of Rsrc1 and Src2 |
||
|
|
|
are not equal; otherwise, Rdest is set to zero. |
|
|
|
|
|
|
|
|
The second operand can be a 16-bit immediate value. In this case, use slti (set on less than immediate) as shown below:
slti† Rdest,Rsrc1,imm
For unsigned numbers, use sltu for the register version and sltiu for the immediateoperand version. As a convenience, the assembler allows us to use slt and sltu for both register and immediate-operand versions.
The assembler provides several comparison instructions to test for equal, not equal, greater than, greater than or equal, and less than or equal relationships. Table 14.1 summa-