Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

MIPS_primery_zadach / dandamudi05gtr guide risc processors programmers engineers

.pdf
Скачиваний:
65
Добавлен:
11.05.2015
Размер:
1.39 Mб
Скачать

236

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)

sltRdest,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:

sltiRdest,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-

Соседние файлы в папке MIPS_primery_zadach