通过移位显示Binary中的数字

时间:2012-10-09 06:54:11

标签: assembly mips bit-shift pcspim

我制作了一个程序,我尝试在其中显示用户输入的数字的二进制形式。但该程序没有正确地进行掩蔽。我该怎么做才能解决它?

$ 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

更新 我按照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

如果有人可以帮我解决这个问题,那将是一件很棒的事。

此致

2 个答案:

答案 0 :(得分: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:

答案 1 :(得分: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次,因此它不会打印前导零。

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

如果您要按照生成的顺序打印数字,可以使用

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

这将为您提供@ JeffE代码的无分支版本。但是如果你关心效率,那么编写一个完整字符串的系统调用比编写32个整数的32个系统调用更有效。 (当然,真正的操作系统没有写入int系统调用;这是火星/ SPIM的事情。)