Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Class 11.2 Set Instructions and more Branch Instructions. Set Instructions This chapter describes two additional branch instructions and several conditional set instructions. Set instructions set a register to 1 or 0 depending on whether a condition is true or false. These new instructions help you to implement loops and branches. Branch on Less than Zero, Branch on Greater than Zero MIPS has several ways to implement relational operators. Here are two more branch instructions. These instructions compare the contents of a register to zero. The register's contents is assumed to be in two's complement representation. bltz s,label bgez s,label # # # # # # Branch if the two's comp. integer in register s is < 0 A branch delay slot follows the instruction. Branch if the two's comp. integer in register s is >= 0 A branch delay slot follows the instruction. The first instruction branches if the integer is strictly less than zero. The other branches if the integer is greater than or equal to zero. Both of these instructions are followed by a branch delay slot. This means that the instruction in that slot will always execute, and the branch (if it happens) will not happen until after that instruction finishes. Set on Less Than The set instructions are used to implement relational operators. However, they do not in themselves alter the flow of control. They set a register to 1 or 0 to show the relation between two values. The slt instruction is used with two's complement integers: slt d,s,t # # # # # # # $s and $t contain two's comp. integers if ( $s < $t ) d <-- 1 else d <-- 0 1 The sltu instruction is used with unsigned integers: sltu d,s,t # # # # # # # $s and $t contain unsigned integers if ( $s < $t ) d <-- 1 else d <-- 0 These instructions be used with character data. If the characters to be compared are loaded in the low-order byte of two registers, and the rest of the bits are zero, either instruction could be used. Set on Less Than Immediate The other two set instructions compare an operand register with an immediate value in the instruction. There is a version for two's complement: slti d,s,imm # # # # # # # $s and imm contain two's comp. integers if ( $s < imm ) d <-- 1 else d <-- 0 And a version for unsigned integers: sltiu d,s,imm # # # # # # # $s and imm contain unsigned integers if ( $s < imm ) d <-- 1 else d <-- 0 How is the 16-bit immediate field extended to 32 bits for the comparison? slti: by sign extension. sltiu: by zero extension. 2 Temperature Range Tester Say that you are writing a control program for a robot spray painter. The allowed temperature range for the paint is 30 degrees to 55 degrees Celsius. The device driver for the temperature sensor puts the temperature in register $2. Your program will test if the unsigned integer in register $2 is in range. If it is in range, register $3 is set to 1, otherwise to 0. The flowchart for the program is at right. The trick of setting a flag to a default value in advance of the test is common. The range test is in two parts. The first part (in this program) tests if temp is less than or equal to 55. However, the machine instruction is "set on less than". If temp is out of range a branch is taken to out. The branch is followed by a no-op for the branch delay. The immediate operand used in the set instruction is changed to 56 to implement "less than or equal". Notice that the assembly language uses decimal numbers for temperatures. This is fine. The assembler translates the decimal representation of the source file into the correct bit pattern for the machine instruction. The next part of the program tests if temp is less than 30. Be careful with the branch instruction so that it branches for the correct condition. Here is the complete program, suitable to copy to a file and to run with SPIM. When you run it, set the PC to 0x400000 (as usual) and also use the set value menu to set R2 to a temperature. Run the program with different temperatures and check that $3 is set correctly. 3 ## ## ## ## ## ## ## ## ## tempRange.asm Check that 30 <= temp <= 55 Set flag to 1 if in range, to 0 if out of range Registers: $2 --- temperature $3 --- in/out range indicator flag $8 --- scratch .text .globl main # Set range indicator to 1 main: ori $3,$0,1 # Test # set to 1 30 <= temp <= 55 sltiu $8,$2,56 beq $8,$0,out sll $0,$0,0 # # # $8=1 if temp <= 55 0? out of range delay sltiu beq sll # # # $8=1 if temp < 30 0? in range delay $8,$2,30 $8,$0,cont $0,$0,0 # Out of Range: set range indicator to 0 out: ori $3,$0,0 # clear to 0 cont: sll ## End of file $0,$0,0 # target for the jump Delay Slot Bug The program can be made slightly shorter by removing the no-op instruction filling the first delay slot. The instruction following it (the sltiu) will always execute, sometimes uselessly, but never will do damage. The second no-op, however, is essential. If it is missing, the next instruction, the ori sets the flag to zero regardless of the branch instruction. This is a common bug, and can be very frustrating because sometimes the result is correct. 4 Counting Loop A common program loop is controlled by an integer that counts up from an initial value to an upper limit. Such a loop is called a counting loop. The integer is called a loop control variable. Loops are implemented with the conditional branch, jump, and conditional set instructions. A loop has three parts that must be correct: 1. The counter must be initialized. 2. The test must end the loop on the correct count. 3. The counter must be increased. It is easy to get these wrong in a high-level programming language. It is remarkably easy to get them wrong in assembly language. Usually you want a top-driven loop such as the one at right, where the test is performed at the top before control enters the loop body. Be clear about the loop you want before you program it, because assembly language allows any sort of weird loop. Here is the loop in C. It is intended to execute 10 times starting at zero. int j; j = 0; while ( j < 10 ) { . . . j++ ; } Here is an assembly version of the counting loop: # # branch delay slots filled # init: ori $8,$0,0 # count = 0 test: sltiu beq sll $9,$8,10 $9,$0,endLp $0,$0,0 # count < 10 # end loop if count >= 10 # delay # do stuff endLp: addiu j sll $8,$8,1 test $0,$0,0 # count++ ; sll $0,$0,0 # branch target # delay 5 The no-op at endLp is not filling a branch delay slot. It is there for convenience in running the program with SPIM. We could modify the program to compute the sum of the integers 0 through 9. The loop is already correct for the problem. Computing the sum is done by adding just two statements: ## sumint.asm ## ## Sum of integers 0 .. 9 ## ## Registers: ## $8 --- loop control ## $9 --- scratch ## $10 --- sum init: test: endLp: ori ori sltiu beq sll $10,$0,0 $8,$0,0 $9,$8,10 $9,$0,endLp $0,$0,0 # # # # # sum = 0 count = 0 count < 10 end loop if count >= 10 delay addu $10,$10,$8 # sum += count addiu j sll $8,$8,1 test $0,$0,0 # count++ ; sll $0,$0,0 # jump target # delay In the Settings menu of SPIM set Bare Machine ON, Allow Pseudo Instructions OFF, Load Trap File OFF, Delayed Branches ON, Delayed Loads ON. Run the programs by setting the value of the PC to 0x400000 and then single stepping (pushing F10) or by multiple stepping (push F11 and enter a number of steps). Observing the results in the SPIM window. 6