Assembly 用移位法显示二进制数
我制作了一个程序,试图显示用户输入的数字的二进制形式。但是程序没有正确地进行掩蔽。我该怎么解决它 用户输入(单位:s0美元)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
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
的低位(零扩展)。