Chapter 3 3.7 loop: lw $v1, 0($a0) addi $v0, $v0, 1 sw $v1, 0($a1) addi $a0, $a0, 1 addi $a1, $a1, 1 bne $v1, $zero, loop Instructions Format OP rs rt Imm lw $v1, 0($a0) I 35 4 3 0 addi $v0, $v0, 1 I 8 2 2 1 sw $v1, 0($a1) I 43 5 3 0 addi $a0, $a0, 1 I 8 4 4 1 addi $a1, $a1, 1 I 8 5 5 1 bne $v1, $zero, loop I 5 3 0-6 3.9 loop: add $t1, $3, $3 add $t1, $t1, $t1 add $t1, $t1, $s6 ;$s6-> base address of save[] lw $t0, 0($t1) beq $t0, $s5, loop ;change from bne to beq add $s3, $s3,$s4 ;$s4->j, $s3->i, executed in delay slots 11*6=66 instructions are executed if save[i+j*l]=k for l=0,1,2,, 9 3.10 Pseudoinstructions What is accomplished Min sequence of Mips Move $t5, $t3 $t5=$t3 Add $t5, $t3,$zer0 Clear $t5 $t5=0 Xor $t5, $t5, $t5 Li $t5, small $t5=small Addi $t5, $zero, small Li $t5,big $t5=big Lui $t5, big[31:16] Ori $t5, $t5, big[15,0] Lw $t5, big($t3) $t5=mem[$t3+big] Lui $t5, big[31:16] Ori $t5, $t0, big[15,0] Add $t3, $t3,$t5 Lw $t5, 0($t3) Addi $t5, $t3,big $t5=$t3+big Lui $t5, big[31:16] ori $t5, big[15,0] addi $t5,$t5,$t3 Beq $t5, small, L If $t5=small, branch to L Addi $at,$zero, small Beq $t5, $at, L Beq $t5, big, L If $t5=big, branch to L Lui $at, big[31:16] ori $at, big[15,0] beq $at,$t5,l Ble $t5, $t3,l If $t5<=$t3, branch to L Slt $at, $t3, $t5 Beq $at,$zero, L Bge $5, $t3, L If $t5>=$t3, branch to L Slt $at, $t5, $t3 Beq $at,$zero, L Bgt $5, $t3, L If $t5>$t3, branch to L Slt $at, $t3, $t5 Bne $at,$zero, L
3.17 ( (100 - (x * 22)) / 100) ) * 110% = 1 Solving: x = (100 - (1/(110%) * 100)) / 22 = 41% 3.22 One MIPS implementation: Procedure written without pseudoinstructions, assuming delayed branches and loads: atoi: or $v0, $zero, $zero # int product = 0; ori $t2, $zero, 10 # const int ten = 10; _loop: lb $t0, 0($a0) # { char c = str[i] or $zero, $zero, $zero # nop beq $t0, $zero, _done # if (c invalid) error; slti $t1, $t0, '0' # bne $t1, $zero, _error # slti $t1, $t0, '9'+1 # beq $t1, $zero, _error # subi $t0, $t0, '0' # int digit = c 0 ; mult $v0, $t2 # product *= 10; mflo $v0 # j _loop # add $v0, $v0, $t0 # product += digit; } _error: ori $v0, $zero, -1 # if (error) product = -1; _done: jr $ra # return product; or $zero, $zero, $zero # nop 3.26 fib: addiu $v0, $zero, 0 #initialize the return value beq $a0, $zero, exit #if n= =0, exit ori $zero, $zero, 0 #nop addiu $v0, $zero, 1 beq $a0, $v0, exit #if n= =1, exit ori $zero, $zero,0 #nop addiu $sp, $sp, -12 sw $a0, 0($sp) sw $ra, 4($sp) sw $s0, 8($sp) addiu $a0, $a0, -1 jal fib addiu $s0, $v0, 0 #store fib(n-1) to $s0 lw $a0, 0($sp) #recover $a0 addiu $a0, $a0, -2 #$a0=n-2 jal fib addiu $v0, $v0, $s0 lw lw $ra, 4($sp) $s0, 8($sp)
addiu $sp, $sp, 12 exit: jr $ra ori $zero, $zero, 0 3.27 Notice that parameters for fib_iter are stored in $a0,$a1 and $a2. fib_iter: addiu $v0,$zero, $a1 #initialize the return value to be $a1 beq $a3, $zero, exit #if count= = 0, exit addiu $sp, $sp 16 #store parameter for recursive call sw $a0, 0($sp) sw $a1, 4($sp) sw $a2, 8($sp) sw $ra, 12($sp) addiu $t0, $a0,0 #store $a0 into $t0 temporally add $a0, $a0, $a1 #a0=$a0+$a1 addiu $a1, $t0, 0 #$a1=$a0 addiu $a2, $a2,-1 #count=count-1 jal fib_iter lw $a0, 0($sp) #pop out of stack lw $a1, 4($sp) lw $a2, 8($sp) lw $ra, 12($sp) addiu $sp, $sp, 16 exit: jr $ra #return ori $zero, $zero, 0 3.29 sbn temp, temp,.+1 # temp = 0; sbn temp, b,.+1 # temp = -b; sbn a, temp,.+1 # a = a (-b) = a + b; 3.30 sbn neg_a, neg_a,.+1 # neg_a = 0; sbn neg_a, a,.+1 # neg_a = -a; sbn c, c,.+1 # c = 0; loop: sbn b, one,.+1 # do { b = b 1; sbn c, neg_a,.+1 # c = c + a; sbn temp, temp,.+1 # temp = 0; sbn temp, b, loop # } while (b > 0); Note (1) This solution does not work if b = 0, because the problem description said to assume that a and b are greater than 0. Perfectionist students are likely to write solutions that do work for b = 0 though, so their answers would be an instruction or too long. A4.ktext 0x80000080 addiu $at, $at, -28 #assume that $at stores the kernel stack pointer swc0 $12, 0($at) #store status register swc0 $13, 4($at) #store cause register
swc0 $14, 8($at) #store EPC sw $a0, 12($at) sw $a1, 16($at) sw $k0, 20($at) sw $k1,24($at) mfc0 $k0, $12 ori $k0, $k0, 0xF001 #set interrupt enable and interrupt mask lwc0 $12, $k0 #turn on interrupt enable here mfc0 $k0, $13 mfc0 $k1, $14 mov $a0, $k0 #set parameters mov $a1, $k1 #set parameters sgt $v0, $k0, 0x44 #check if the exception is caused by interrupt bgtz $v0, interrupt jal print_excp #non interrupt exception j done #ready to return interrupt: jal interrupt_proc #if it is interrupt, call interrupt procedure done:.kdata lwc0 $12, 0($at) #restore status register lwc0 $13, 4($at) #restore cause register lwc0 $14, 8($at) #restore EPC lw $a0, 12($at) lw $a1, 16($at) lw $k0, 20($at) lw $k1,24($at) addiu $at, $at, 28 #restore the kernel stack pointer addiu $k1, $k1,4 rfe Save0:.word 0 save1:.word 0 save2:.word 0 save3:.word 0 save4:.word 0 Notice that the Cause register, Status reg, EPC and those registers used by exception handler should be stored in kernel stack, where $at stores the kernel stack pointer. In kernel mode, $sp could not be used for possible mem error exception. Also, the inerrupt priority is assumed to be handled by hardware. A5.ktext 0x80000080 sw $a0, save0 sw $a1, save1 mfc0 $k0, $13 # Move Cause into $k0 mfc0 $k1, $14 # Move EPC into $k1 addiu $v0, $zero, 0x44
slt $v0, $v0, $k0 # Ignore interrupts bgtz $v0, _restore mov $a0, $k0 # Move Cause into $a0 mov $a1, $k1 # EPC into $a1 jal print_excp # Print exception error msg _restore: lw $a0, save0 lw $a1, save1 lw $k0, -4($k1) # $k0 = previous instruction srl $k0, $k0, 26 # $k0 = opcode of prev instr ori $k1, $zero, 2 # opcode of j beq $k0, $k1, _delayslot # ori $k0, $zero, 4 # opcode of beq beq $k0, $k1, _delayslot # and so on for: jr, jal, bne, bltz, bgezal, bczt... _done: mfc0 $k1, $14 # reload EPC into $k1 addiu $k1, $k1, 4 # Do not reexecute fault instr rfe # done in delay-slot of jr _delayslot: mfc0 $k1, $14 # reload EPC into $k1 addiu $k0, $k1, -4 # $k0 = EPC - 4 addiu $k1, $k1, 4 # $k1 = EPC + 4 jr $k0 # poke at branching instr j _check _check: rfe or $zero,$zero,$zero.kdata Save0:.word 0 save1:.word 0 This problem is hard. The basic idea of this solution is to do everything possible in order not to touch the instruction that caused the exception. We need a way to poke the branching instruction, that is, execute the instruction without executing any instructions around it. This procedure works by calling the branching instruction with jr, but putting a j in the delay-slot of the jr, so that we will jump back after executing the branching instruction and not execute its regular delay-slot. If it turns out that the branch is not taken (which may happen with a bne or beq), then we jump back to EPC+4. Note: this solution assumes that j in branch delay slots will NOT executed if branch is taken! Other elegant solutions will be highly appreciated