2014-11-07 8 views
1

다음은 제 코드와 최종 테스트 사례입니다. main과 printStats가 둘 다 주어졌고 평균값 (아래쪽에 있음)을 표시해야하므로 문제가 있는지 살펴보십시오. 이 경우는 $ f, $ t, $ a 및 $ s에있는 모든 레지스터의 값을 변경하고 스택의 맨 위에 2 개의 항목을 추가하여 평균 메서드가 해당 메서드를 실행하는 데 필요한 값을 올바르게 유지하는지 확인합니다. printStats에서 $ jr 다음에 오는 계산.인수가 4 개 이상인 MIPS 프로그램

문제는 3 명의 타자가있는 몇 가지 테스트 케이스에서 반복됩니다. 배터 3은 임의로 큰 정수를 사용합니다.

# printStats puts two values at the top two spots in its stack. This is where 
# the number of homeruns and outs were placed when printStats 
# is called. A function is allowed to change its own stack. 

# Changes the $s registers used by main. The average function should be 
# getting arguments from the $a registers and the stack, and not relying 
# on what is in the $s registers. 

# From test12: 
# Tests if $t registers are preserved (if needed) by average. 
# printStats puts values into every $t register. 

# From test13: 
# Tests if $a registers used correctly when average calls printStats. 
# printStats changes the contents of $a1, $a2, and $a3 before returning 

# test with three batters, both average and slugging percentage 
# First batter has no hits, but does have outs 
# Second batter has hits and outs, with realistic values 
# Third hitter has large values for some of the hits and for the 
# outs. This means the hits and outs *have* to be converted from int's 
# to float's in order to get the right answer. 

.data 

mainNumBatters: 
    .word 3 

mainBatter1: 
    .word 27  # walks 
    .word 0  # singles 
    .word 0  # doubles 
    .word 0  # triples 
    .word 0  # home runs 
    .word 423  # outs 
mainBatter2: 
    .word 27  # walks 
    .word 101  # singles 
    .word 22  # doubles 
    .word 4  # triples 
    .word 10  # home runs 
    .word 423  # outs 

mainBatter3: 
    .word 102322 # walks 
    .word 8000000 # singles 
    .word  22 # doubles 
    .word 500000 # triples 
    .word  10 # home runs 
    .word 23000000 # outs 


.data 
mainNewline: 
     .asciiz "\n" 
mainBatterNumber: 
     .asciiz "Batter number: " 
mainBattingAverage: 
     .asciiz "Batting average: " 
mainSluggingPercentage: 
     .asciiz "Slugging percentage: " 
mainOnbasePercentage: 
     .asciiz "On-base percentage: " 

     .text 

main: 
     # Function prologue -- even main has one 
     addiu $sp, $sp, -24  # allocate stack space -- default of 24 here 
     sw $fp, 0($sp)  # save frame pointer of caller 
     sw $ra, 4($sp)  # save return address 
     addiu $fp, $sp, 20  # setup frame pointer of main 

     # for (i = 0; i < mainNumBatters; i++) 
     # compute batting average 
     # compute slugging average 

     la $s1, mainNumBatters 
     lw $s6, 0($s1)  # $s6 = number of batters 
     addi $s0, $zero, 0  # $s0 = i = 0 
     la $s1, mainBatter1 # $s1 = addr of current batter's stats 

mainLoopBegin: 
     slt $t0, $s0, $s6  # $t0 = i < number of batters 
     beq $t0, $zero, mainDone 

     la $a0, mainBatterNumber 
     addi $v0, $zero, 4 
     syscall 
     addi $a0, $s0, 1 
     addi $v0, $zero, 1 
     syscall 
     la $a0, mainNewline 
     addi $v0, $zero, 4 
     syscall 

     # Compute the batting average 
     addi $a0, $zero, 1  # $a0 = 1 = compute batting average 
     lw $a1, 0($s1)  # $a1 = walks 
     lw $a2, 4($s1)  # $a2 = singles 
     lw $a3, 8($s1)  # $a3 = doubles 
     lw $s2, 12($s1)  # $s2 = triples 
     lw $s3, 16($s1)  # $s3 = home runs 
     lw $s4, 20($s1)  # $s4 = outs 

     sw $s4, -4($sp)  # put outs at top of average's stack 
     sw $s3, -8($sp)  # put homeruns 2nd fm top of average's stack 
     sw $s2, -12($sp)  # put triples 3rd fm top of average's stack 
     jal average 

     # Print the batting average 
     mtc1 $v0, $f12   # get result fm $v0 before we print string 
     la $a0, mainBattingAverage 
     addi $v0, $zero, 4 
     syscall 
     addi $v0, $zero, 2  # print the average 
     syscall 
     la $a0, mainNewline 
     addi $v0, $zero, 4 
     syscall 
     syscall 

     # do it for the slugging percentage 
     addi $a0, $zero, 2  # $a0 = 2 = compute slugging average 
     lw $a1, 0($s1)  # $a1 = walks 
     lw $a2, 4($s1)  # $a2 = singles 
     lw $a3, 8($s1)  # $a3 = doubles 
     lw $s2, 12($s1)  # $s2 = triples 
     lw $s3, 16($s1)  # $s3 = home runs 
     lw $s4, 20($s1)  # $s4 = outs 

     sw $s4, -4($sp)  # put outs at top of average's stack 
     sw $s3, -8($sp)  # put homeruns 2nd fm top of average's stack 
     sw $s2, -12($sp)  # put triples 3rd fm top of average's stack 
     jal average 

     # Print the slugging percentage 
     mtc1 $v0, $f12   # get result fm $v0 before we print string 
     la $a0, mainSluggingPercentage 
     addi $v0, $zero, 4 
     syscall 
     addi $v0, $zero, 2  # print the percentage 
     syscall 
     la $a0, mainNewline 
       addi $v0, $zero, 4 
     syscall 
     syscall 

     # do it again for the on-base percentage 
     addi $a0, $zero, 3  # $a0 = 3 = compute slugging average 
     lw $a1, 0($s1)  # $a1 = walks 
     lw $a2, 4($s1)  # $a2 = singles 
     lw $a3, 8($s1)  # $a3 = doubles 
     lw $s2, 12($s1)  # $s2 = triples 
     lw $s3, 16($s1)  # $s3 = home runs 
     lw $s4, 20($s1)  # $s4 = outs 

     sw $s4, -4($sp)  # put outs at top of average's stack 
     sw $s3, -8($sp)  # put homeruns 2nd fm top of average's stack 
     sw $s2, -12($sp)  # put triples 3rd fm top of average's stack 

     jal average 

     # Print the slugging percentage 
     mtc1 $v0, $f12   # get result fm $v0 before we print string 
     la $a0, mainOnbasePercentage 
     addi $v0, $zero, 4 
     syscall 
     addi $v0, $zero, 2  # print the percentage 
     syscall 
     la $a0, mainNewline 
     addi $v0, $zero, 4 
     syscall 
     syscall 

     addi $s0, $s0, 1  # i++ 
     addi $s1, $s1, 24  # $s1 = addr of next batter's stats 
     j  mainLoopBegin 

mainDone: 
     # Epilogue for main -- restore stack & frame pointers and return 
     lw $ra, 4($sp)  # get return address from stack 
     lw $fp, 0($sp)  # restore frame pointer for caller 
     addiu $sp, $sp, 24  # restore frame pointer for caller 
        jr $ra    # return to caller 

.data 
printStatsOuts: 
     .asciiz "Outs:  " 
printStatsWalks: 
     .asciiz "Walks:  " 
printStatsSingles: 
     .asciiz "Singles: " 
printStatsDoubles: 
     .asciiz "Doubles: " 
printStatsTriples: 
     .asciiz "Triples: " 
printStatsHomeruns: 
     .asciiz "Home runs: " 
printStatsNewline: 
     .asciiz "\n" 

.text 
printStats: 
     # Function prologue 
     addiu $sp, $sp, -32  # allocate stack space 
     sw $a3, 20($sp)  # save $a0 thru $a3 
     sw $a2, 16($sp) 
     sw $a1, 12($sp) 
     sw $a0, 8($sp) 
     sw $ra, 4($sp)  # save return address 
     sw $fp, 0($sp)  # save frame pointer of caller 
     addiu $fp, $sp, 28  # setup frame pointer of average 

     # printStats expects to find the following: 
     # $a0 = walks 
     # $a1 = singles 
     # $a2 = doubles 
     # $a3 = triples 
     # 5th argument = homeruns 
     # 6th argument = outs 

     # print the outs 
     la $a0, printStatsOuts 
        syscall 
     lw $a0, 0($fp)  # the outs are at the top of our stack 
     addi $v0, $zero, 1 
     syscall 
     la $a0, printStatsNewline 
     addi $v0, $zero, 4 
     syscall 

     # print the walks 
     la $a0, printStatsWalks 
     addi $v0, $zero, 4 
     syscall 
     lw $a0, 8($sp)  # the walks were passed in $a0 
     addi $v0, $zero, 1 
     syscall 
     la $a0, printStatsNewline 
     addi $v0, $zero, 4 
     syscall 

     # print the singles 
     la $a0, printStatsSingles 
     addi $v0, $zero, 4 
     syscall 
     addi $a0, $a1, 0  # the singles were passed in $a1 
     addi $v0, $zero, 1 
     syscall 
     la $a0, printStatsNewline 
     addi $v0, $zero, 4 
     syscall 

     # print the doubles 
     la $a0, printStatsDoubles 
     addi $v0, $zero, 4 
     syscall 
     addi $a0, $a2, 0  # the doubles were passed in $a2 
     addi $v0, $zero, 1 
     syscall 
     la $a0, printStatsNewline 
     addi $v0, $zero, 4 
     syscall 

     # print the triples 
     la $a0, printStatsTriples 
     addi $v0, $zero, 4 
     syscall 
     addi $a0, $a3, 0  # the doubles were passed in $a3 
     addi $v0, $zero, 1 
     syscall 
     la $a0, printStatsNewline 
     addi $v0, $zero, 4 
     syscall 

     # print the homeruns 
     la $a0, printStatsHomeruns 
     addi $v0, $zero, 4 
     syscall 
     lw $a0, -4($fp)  # the homeruns are 4 bytes below the top of our stack 
     addi $v0, $zero, 1 
     syscall 
     la $a0, printStatsNewline 
     addi $v0, $zero, 4 
     syscall 

     # Put -1 in $t0, then copy that value to each of the $f registers 
     addi $t0, $zero, -1 
     mtc1 $t0, $f0 
     mtc1 $t0, $f1 
     mtc1 $t0, $f2 
     mtc1 $t0, $f3 
     mtc1 $t0, $f4 
     mtc1 $t0, $f5 
     mtc1 $t0, $f6 
     mtc1 $t0, $f7 
     mtc1 $t0, $f8 
     mtc1 $t0, $f9 
     mtc1 $t0, $f10 
     mtc1 $t0, $f11 
     mtc1 $t0, $f12 
     mtc1 $t0, $f13 
       mtc1 $t0, $f14 
     mtc1 $t0, $f15 
     mtc1 $t0, $f16 
     mtc1 $t0, $f17 
     mtc1 $t0, $f18 
     mtc1 $t0, $f19 
     mtc1 $t0, $f20 
     mtc1 $t0, $f21 
     mtc1 $t0, $f22 
     mtc1 $t0, $f23 
     mtc1 $t0, $f24 
     mtc1 $t0, $f25 
     mtc1 $t0, $f26 
     mtc1 $t0, $f27 
     mtc1 $t0, $f28 
     mtc1 $t0, $f29 
     mtc1 $t0, $f30 
     mtc1 $t0, $f31 

     # Put various values in the $t registers 
     addi $t0, $zero, -1111 
     addi $t1, $zero, -2222 
     addi $t2, $zero, -3333 
     addi $t3, $zero, -4444 
     addi $t4, $zero, -5555 
     addi $t5, $zero, -6666 
     addi $t6, $zero, -7777 
     addi $t7, $zero, -8888 
     addi $t8, $zero, -9999 
     addi $t9, $zero, -1111 

     # Put various values in the $a registers. 
     addi $a0, $zero, -1111 
     addi $a1, $zero, -1111 
     addi $a2, $zero, -2222 
     addi $a3, $zero, -3333 
        # Put two values at the top two spots in our stack. This is where 
     # the number of homeruns and outs were placed when printStats 
     # is called. A function is allowed to change its own stack. 
     addi $t7, $zero, -1234 
     sw $t7, 0($fp) 
     sw $t7, -4($fp) 

printStatsDone: 
     # Epilogue for printStats -- restore stack & frame pointers and return 
     lw $ra, 4($sp)  # get return address from stack 
     lw $fp, 0($sp)  # restore frame pointer for caller 
     addiu $sp, $sp, 32  # restore frame pointer for caller 
     jr $ra    # return to caller 

# Your code goes below this line 

average: 
    #takes 7 arguments 
    #Arguments $a0-$a3 are put on the Caller's stack 
    #arguments 5-7 are put on the Callee's stack and called 

# Prologue: set up stack and frame pointers for average 
     addiu $sp, $sp, -36 # allocate stack space -- 36 needed here 
     sw  $fp, 0($sp)  # save caller's frame pointer 
     sw  $ra, 4($sp)  # save return address 
     # save parameter values $a0-$a3 on the stack 
     sw  $a0, 8($sp) # designates which calculation to do 
     sw  $a1, 12($sp) # walks 
     sw  $a2, 16($sp) # singles 
     sw  $a3, 20($sp) # doubles 
     addiu $fp, $sp, 32 # setup average frame pointer 

    #Allocate proper locations of arguments for printStats 
    #arguments 5 and 6 (home runs and outs will be placed on stack) 
    addi $t5, $a0, 0 #$t5 designates which calculation to run 
    addi $a0, $a1, 0 #walks of printStats 
    addi $a1, $a2, 0 #singles of printStats 
    addi $a2, $a3, 0 #doubles of printStats 
    lw $a3, 24($sp) #triples of printStats 
    lw $t1, 28($sp) #home runs of printStat 
    sw $t1, -8($sp) #home runs now 2nd from top of stack 
    lw $t2, 32($sp) #outs of printStats 
    sw $t2, -4($sp) #out now top of stack 
    jal printStats 

    #restore registers used in average 
    lw $t2, 32($sp) #outs 
    lw $t1, 28($sp) #homeruns 
    lw $a3, 24($sp) #triples 
    lw $a2, 20($sp) #doubles 
    lw $a1, 16($sp) #singles 
    lw $a0, 12($sp) #walks 
    lw $t5, 8($sp) #compare which calculation to run 

    #convert outs to float 
    mtc1 $t2, $f4 #outs = $f4 

    #hits 
     #hits = singles + doubles + triples + home runs 
     add  $t3, $a1, $a2 # hits = singles + doubles 
     add  $t3, $t3, $a3 # hits = $t3 + triples 
     add  $t3, $t3, $t1 # hits = $t3 + home runs 
    mtc1 $t3, $f1  #convert hits to float $f1 

     #atBats 
     #atBats = hits + outs 
     add.s $f2, $f1, $f4 # atBats = hits + outs 
    mfc1 $t4, $f2  #convert atBats to int for compare 

    #Compare $t5 
    #if $t5 == 1, computer batting average 
    #if $t5 == 2, compute slugging percentage 
    #if $t5 == 3, compute on-base percentage 

    addi $t0, $zero, 1 #$t0 = 1 
    beq $t5, $t0, averageBattingAverage 

    addi $t0, $zero, 2 #$t0 = 2 
    beq $t5, $t0, averageSluggingPercentage 

    addi $t0, $zero, 3 #$t0 = 3 
    beq $t5, $t0, averageOnBasePercentage 

averageBattingAverage: 
    #batting average 
    #batting average = hits/atBats 
    #if atBats == 0, average = 0 

    #compare atBats 
    beq  $t4, $zero, averageBattingSluggingZero 

    #batting 
    div.s $f3, $f1, $f2 #batting average = hits/atBats 

    #Set to print 
    mfc1 $v0, $f3 #return $v0 the batting average 
    j averageDone #done 

averageSluggingPercentage: 
    #Slugging percentage 
    #slugging percentage = (singles + doubles*2 + triples*3 
    #   + home runs*4)/atBats 
    #if atBats == 0, percentage = 0 

    #compare atBats 
    beq  $t4, $zero, averageBattingSluggingZero 

    #slugging 
    add $t5, $a2, $a2 #doubles*2 
    add $t6, $a3, $a3 #$t6 = triples * 2 
    add $t6, $t6, $a3 #$t6 = triples * 3 
    add $t7, $t1, $t1 #$t7 = home runs * 2 
    add $t7, $t7, $t7 #$t7 = home runs * 4 
    add $t8, $a1, $t5 #$t8 = singles + doubles*2 
    add $t8, $t8, $t6 #$t8 = $t8 + triples*3 
    add $t8, $t8, $t7 #$t8 = $t8 + home runs*4 
    mtc1 $t8, $f1 #convert $t8 to float $f1 
    div.s $f3, $f1, $f2 #slugging percentage = $f1/atBats 

    #set to print 
    mfc1 $v0, $f3  #return $v0 the slugging percentage 
    j averageDone #done 

averageOnBasePercentage: 
    #On-base percentages 
    #on-base percentages = (hits + walks)/(atBats + walks) 
    #if atBats + walks is zero, percentage is zero 

    add $t6, $t3, $a0 #$t6 = hits + walks 
    add $t7, $t4, $a0 #$t7 = atBats + walks 

    #compare atBats + walks 
    beq $t7, $zero, averageOnBaseZero 

    #on-base 
    mtc1 $t6, $f1 #convert $t6 to float $f6 
    mtc1 $t7, $f2 #convert $t7 to float $f7 
    div.s $f3, $f1, $f2 #on-base percentage = $f6/$f7 

    #set to print 
    mfc1 $v0, $f3  #return $v0 the on-base percentage 
    j averageDone #done 

averageBattingSluggingZero: 
    #if atBats is zero, batting average and slugging 
    #percentage are both zero 

    addi $t0, $zero, 0 #$t0 = 0 
    mtc1 $t0, $f0 #convert 0 to float $f0 

    #set to print 
    mfc1 $v0, $f0  #return $v0 = 0 
    j  averageDone  #done 

averageOnBaseZero: 
    #if atBats + walks is zero, on-base percentage 
    # is also zero 

    addi $t0, $zero, 0 #$t0 = 0 
    mtc1 $t0, $f0 #convert 0 to float $f0 

    #set to print 
    mfc1 $v0, $f0  #return $v0 = 0 
    j  averageDone  #done 

averageDone: # Epilogue: restore stack and frame pointers and return 
     lw  $ra, 4($sp)  # get return address from stack 
     lw  $fp, 0($sp)  # restore the caller's frame pointer 
     addiu $sp, $sp, 36  # restore the caller's stack pointer 
     jr  $ra    # return to caller's code 

내 출력이 늘어지지 않아 그 이유가 표시되지 않습니다. 다음은 내 출력이 함께있어 여기에 타자 3.

Batter number: 3 
Outs:  23000000 
Walks:  102322 
Singles: 8000000 
Doubles: 22 
Triples: 500000 
Home runs: 10 
Batting average: 0.26984200 

Outs:  23000000 
Walks:  102322 
Singles: 8000000 
Doubles: 22 
Triples: 500000 
Home runs: 10 
Slugging percentage: 0.30158967 

Outs:  23000000 
Walks:  102322 
Singles: 8000000 
Doubles: 22 
Triples: 500000 
Home runs: 10 
On-base percentage: 0.27220613 

을위한 올바른 출력 그리고! 불일치를 표시하기 위해

이 한 타자에 대한 나의 계산 방법은 무엇이며 어떻게 수정해야합니까?

+0

수정 됨. 같은 문제를이에 실수를 한단다 누군가를 위해 : 나는 mtc1의 $의 t, $ f를 cvt.sw의 $ f를, $ f를 # 같은 $ f를 등록 을 떠 INT를 사용 CVT를 int로 부상했다. ws $ f, $ f #same $ f 내 값을 보존하고 올바른 값을 얻기 위해 mfc1 $ t, $ f – user3466773

답변

1

여러 호출 규칙이 있으므로 어떤 규칙을 따르는 지 알아야합니다. 설명서가없는 경우 컴파일러에서 생성 한 어셈블리 코드를 보거나 디버거를 사용할 수 있습니다.

즉, 단 4 개의 인수 만 스택에 전달되었다고 판단 할 때 O32 호출 규칙을 사용하는 것 같습니다. 즉, 함수에 입력 할 때 스택에는 레지스터 $a0-$a3에 전달 된 처음 4 개의 인수를 저장하기위한 4 개의 인수 슬롯이 포함됩니다. 그 다음에 나머지 모든 주장들이 나옵니다. 따라서 함수에 등록하면 5 번째 인수 (레지스터를 통해 전달되지 않은 첫 번째 인수)는 주소 16($sp)이고 6 번째 값은 20($sp)이고 7 번째 값은 24($sp)입니다. (귀하의 주장은 각 단어가 1 단어라고 가정합니다.) 지역 주민을위한 공간을 만들기 위해 $sp에서 36을 뺍니다. 따라서 모든 오프셋이 그 양만큼 증가합니다. 즉, 5 번째 인수는 52($sp)입니다. 이 주소를 사용하여 액세스 할 수 있습니다.

$fp$sp + 32으로 설정하십시오. 컨벤션을 호출하는 것이 $fp에 대한 특정 값을 요구하지 않는다고 생각합니다. 이후에 $fp에 대한 귀하의 주장에 액세스하고 싶다면, 이번에는 상쇄하기 위해 오프셋을 다시 조정해야합니다. 이번에는 -32입니다. 따라서 다섯 번째 인수는 20($fp)에 있어야하며 나머지는 뒤에 나와야합니다.

+0

'24 ($ sp)'는 방금 할당 한 영역을 가리키며 의미가 없으므로 . 또한 기억에 연속적으로 인수를 넣는 것을 알고있는 모든 규칙을주의하십시오. 따라서 5 번째가 24 ($ sp)이고 6 번째가 28 ($ sp)이어야합니다. 그것이 아니라면, 그것은 당신도 5 일 잘못되었음을 의미합니다. – Jester

+0

다르게 말하면 안되지만 지금 가지고있는 라인을 사용합니다. lw $ a3, 24 ($ sp)는 모든 경우에 대해 트리플을 반환합니다. lw $ t1, 28 ($ sp)는해야 할 때 0을 반환합니다. 홈런을 반환. 테스트를 마쳤습니다. 바로 여기 서식을 지정하지 않았으므로 테스트/내 산출물을 원래 문제에 넣을 것입니다. – user3466773

+0

@MichaelPetch 내 대답에서 마지막 문장을 확인 했습니까? :) – Jester