Assembly 用移位法显示二进制数

Assembly 用移位法显示二进制数,assembly,mips,bit-shift,pcspim,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,$t

我制作了一个程序,试图显示用户输入的数字的二进制形式。但是程序没有正确地进行掩蔽。我该怎么解决它

用户输入(单位: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
如果有人能帮我解决这个问题,那就太好了

关于

这里有一个问题:

bgtu  $t0, 0, Check
li    $t0, 0
j     Loop
如果它是零,则不会显示它,因为您正在跳转到
Loop
,而不是
Disp
。哦,看,
Disp
是在这个指令之后立即编写的!解决方案:完全摆脱跳转

这是另一个问题,正如dbrank0所描述的:

Disp:
li $v0,1
syscall
这将以整数形式显示
$a0
的内容。但是如果位是1,
$a0
的值将是0x8000000,而不是1!当您尝试打印0x8000000时,它会将其视为有符号整数,并改为打印-2147483648

还有一个问题:

beq $t1,31,Exit
首先,该指令处于一个尴尬的位置。为什么在
换档后检查退出条件?你应该检查它在开始或结束,而不是在中间。此外,您需要检查32位,因为有32位,您需要在打印每个位之前进行检查。目前,最后一位将因此被切断


有一种聪明的方法可以让你的程序做的工作比它需要的少。利用从左到右显示的事实(即,最重要的位首先显示)。设置MSB时,可以将其视为2的补码中的负数

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:

给定一个指向
$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次,因此它不会打印前导零

此算法是basic的base2特例
do{digit=a%base;}而(a/=base)

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

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

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

屏蔽可能已经正确完成,但在打印输出之前,您可能需要将要打印的位转换为可表示的位(通过将其向右移动31个位置将其转换为0/1,或者通过添加额外的0x30将其转换为“0”/“1”).我为什么要那样做。我正在显示存储在$t0中的结果,如果两个数字的MSB都匹配,则结果可以是1;如果两个数字的MSB都不匹配,则结果可以是0。t0包含0或0x8000000。如果要打印0或1,应在打印前将此31位移位。(但不要想当然地认为我的话,我编程MIPS已经很久了)。通常每一位上有条件的分支都会对性能造成影响。但MIPS已将
SLT
设置为小于(已签名)。(). 因此
slt$a0、$s0、$zero
$s0
的符号位提取到
$a0
的低位(零扩展)。