2012-10-09 125 views
-1

我製作了一個程序,我嘗試顯示用戶輸入的數字的二進制形式。但該程序沒有正確執行掩碼。我應該怎麼做才能解決它?在$ S0通過移位顯示二進制數

用戶輸入

Loop: 

and $t0,$s0,2147483648 // anding it with this number because only its MSB is 1 all other bits are zero 

sll $s0,$s0,1 

move $a0,$t0 

li $v0,1 
syscall 

beq $t1,31,Exit 

addi $t1,$t1,1 
j Loop 

UPDATE: 我修改此代碼由dbrank0的建議,但現在它顯示的32位

Loop: 

and $t0,$s0,2147483648 

sll $s0,$s0,1 

beq $t1,31,Exit 

move $a0,$t0 

addi $t1,$t1,1 

bgtu $t0,0,Check 

li $t0,0 
j Loop 

Disp: 
li $v0,1 
syscall 

j Loop 

Check: 
li $t0,1 

j Disp 

它將僅一個位,而不是如果有人能夠幫助我解決這個問題,那就太好了。

問候

+0

屏蔽可能是正確完成的,但在打印出來之前,您可能需要將要打印的位(可以通過將其右移31個位置來實現0/1,或者通過移動另外的0x30來移入'0'/'1')。 – dbrank0

+0

我爲什麼要那樣做。我將顯示存儲在$ t0中的結果,該結果可以是兩個數字匹配的MSB中的1,如果兩個數字的MSB都不匹配,則爲0。 – Naruto

+0

t0包含0或0x80000000。如果要打印0或1,則應在打印之前將其移位31位。 (但是不要把我的話當成理所當然,從我編程MIPS起就已經過去了)。 – dbrank0

回答

3

這裏有一個問題:

bgtu $t0, 0, Check 
li $t0, 0 
j  Loop 

如果它是一個零,它不會顯示,因爲你跳到Loop,而不是Disp。哦,看,Disp無論如何寫在這個指令後立即!解決方案:完全擺脫跳躍。

下面是另一個問題,因爲描述dbrank0:

Disp: 
li $v0,1 
syscall 

這將顯示的$a0內容作爲一個整數。但是,如果該位爲1,則$a0的值將爲0x80000000,而不是1!當您嘗試打印0x80000000時,它會將其視爲有符號整數並打印-2147483648。

這裏的另一個問題:

beq $t1,31,Exit 

首先,該指令是在一個尷尬的位置。爲什麼在andshift之後檢查退出條件?你應該在開始或結束時檢查它,而不是在中間。此外,你需要檢查32位,因爲有32位,並且在打印每一位之前檢查。目前最後一位將被切斷。


有一個聰明的方法可以讓你的程序做的工作少於需要的。利用從左到右顯示的事實(即,首先顯示最重要的位)。當MSB被設置時,它可以被視爲二進制補碼中的負數!

li  $t0, 32 
li  $v0, 1 

Loop: 
bltz $s0, Bit1 
li  $a0, 0 
j  Disp 

Bit1: 
li  $a0, 1 

Disp: 
syscall 

Tail: 
subi $t0, $t0, 1 
beqz $t0, Exit 
sll $s0, $s0, 1 
j  Loop 

Exit: 
+0

通常情況下,每個位上的條件分支對性能而言會更差。但是MIPS的'SLT'設置小於(簽名)。 (http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html)。因此'slt $ a0,$ s0,$ zero'可以將'$ s0'的符號位提取到'$ a0'的低位(零擴展)。 –

0

給定一個指針到一個足夠大的緩衝區的末尾在$a1,並且在$a0輸入整數,此函數存儲ASCII數字以形成串。

這使用AND來提取低位。它的工作原理是從低位到高位,所以我們從緩衝區的末端向後存儲,在打印順序上留下一個ASCII字符串。

.globl to_base2_end # args: (unsigned a, char *buf_end) 
to_base2_end: 

    # Runs at least once, so we get "0" instead of the empty string for 0 
.loop:       # do { 
    andi $t0, $a0, 1   # extract the low bit 
    ori $t0, $t0, '0'   # ASCII digit 

    addiu $a1, $a1, -1 
    sb $t0, ($a1)   # *--buf = ASCII digit 

    srl $a0, $a0, 1   # a0 >>= 1 
    bne $a0, $zero, .loop  # }while (a0!=0); 

    move $v0, $a1   # return pointer to the first digit 
    jr $ra 

注意這第一家店之前遞減,所以你可以在緩衝區的末尾傳遞一個指向'\n'

您當然可以內聯該循環,而不是將其用作可調用函數。它在整數爲零時停止,而不是循環固定32次,因此它不打印前導零。

此算法是基本的
do { digit = a % base; } while(a /= base);的base2特例。

如果你要打印位數他們產生的順序,可以使用

slt $t0, $a0, $zero  # t0 = 0 or 1 = high bit of a0 
    sll $a0, $a0, 1 

這將使你的@ JeffE的代碼網點版本。但是如果你關心效率,一個寫入整個字符串的系統調用比32個系統調用寫入32個整數更有效率。 (當然,真正的操作系統沒有寫入系統調用;這是一個火星/ SPIM的東西。)