2012-10-09 79 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的东西。)