1. ホーム
  2. assembly

[解決済み] ビットシフト演算子を使って10進数を2進数で表示するMIPS

2022-02-14 16:56:23

質問事項

このトピックに関するスレッドをここやネット上の他の場所で数多く読みました。 ビットシフトに関する素晴らしいトピック(必ずしもAssemblyに関連するものではありませんが、一般的なトピックは以下の通りです。 ビットシフト(bit-shift)演算子とは何ですか、またその仕組みは? OPのコードをここにコピー&ペーストするところまでやってみました。 入力された整数を2進数で表示するには? また、返信者が提案した変更を加えても、何をやってもゼロの文字列が生成されます。

ビットシフトとは何か、その仕組みは理解しています。 右に'n'シフトすると2^nで割り、左にシフトすると2^nで乗算します。

私は先週締め切られたラボを持っていて、その3番目の部分は、ユーザーの入力を受けて、その2進バージョン、そして16進バージョンをプリントアウトするプログラムを提供するというものでした。 それが終わると、プログラムは文字列の中心にある特定のビットをプリントアウトし、その2進数と16進数のバージョンも生成することになっていました。

私が最初に考えたのは、文字列を受け取って、0x01とANDして、その結果の「1」または「0」をプリントし、それを「1」だけ右にビットシフトすることでした。 これはループに含まれていて、カウンタが'32'の要件を満たすまで続けられ、それで終了します。 しかし、なぜすべて'0'をプリントしてしまうのか、非常に困っています。 他のバージョンも試してみたのですが、以下のような感じです。

  • ユーザー入力を31だけ左にシフトし、各ビットに対してループを実行するが、ループ内では(ビットの逆順にするために)右にシフトしていた - 失敗 - 再びすべて0になる

  • 上記と逆の操作を行う - 再び失敗、すべてゼロになる

頭では分かっているのですが、このようなことをしたいのです。

(NOT CODE OBVIOUSLY)
User input is: 25 <-- store at $t0 
    Binary rep is: 0000 0000 0000 0000 0000 0000 0001 1001 # 25 in $t0

LOOP:
    AND with 0x01: 0000 0000 0000 0000 0000 0000 0000 0001 #saved to $t1

    Produces:      0000 0000 0000 0000 0000 0000 0000 0001 #saved to $t2

    Print to Console: 1 #send contents of $t2 to syscall

    Shift $t0 Right 1: 0000 0000 0000 0000 0000 0000 0000 1100 #

j LOOP (until the beq branch was met and I left the loop)

と思っていたのですが、これならうまくいきそうです。 たとえ結果が逆向きになったとしても、生成された文字列の中に'1'が含まれていたはずで、それに気づいて適切に対処できたと思います(数字全体を左にシフトして $t0 を'31'差引いた後、上記の指示を実行しました。 まだ全部'0'です・・・。

これが私のコードです。 今また、私の数々の試行錯誤と変更により、破損してしまいました。 上記の私のアプローチが完全に的外れなのか、またこれを修正するために以下のサンプルコードに何ができるのか、理解するための手助けをお願いしたいのです。

この課題は提出済みで、私が混乱していたために完了しなかったことを理解してください。 私はこれをさらに理解したいと思っています。 この部分でつまずいたので、コード全体を完成させませんでした。 だから、この課題の最初の部分だけお願いします。

#Read integer A from user and store it into a register
#Display the integer in binary
#Display the integer in Hex
#set Register $a0 to contain only bits 12,13,14,15 of $a0
#Display the integer in binary contained in $a0
#Display the integer in hex contained in $a0

.data

    userInput: .asciiz "Please enter your integer:\n"
    binaryInput: .asciiz "Here is the input in binary: "
    nl: .asciiz "\n\n"
    hexInput: .asciiz "Here is the input in hexidecmal: "
    binaryOutput: .asciiz "Here is the output in binary: "
    hexOutput: .asciiz "Here is the output in hexidecimal: "

.text
    main:

    #ask end-user to submit an integer value
    li $v0, 4
    la $a0, userInput
    syscall

    #read user-input
    li $v0, 5
    syscall

    #enter user input into $t0
    move $t0, $v0
    add $t1, $zero, $zero       #counter
    addi $t2, $zero, 32     #target
    sll $s1, $t0, 31        #shift left number 31 bits to s1
    li $v0, 4
    la $a0, binaryInput     #print out string to user
    syscall


loop:
    andi $s2, $s1, 1        #and 0x01 with s1 to s2
    srl $s1, $s1, 1         #shift right s1 by 1 bit
    li $v0, 1
    la $a0, ($s2)           #print digit held in s2 to screen
    syscall
    add $t1, $t1, 1         #add 1 to counter
    bne $t1, $t2, loop      #check if counter is equal to target, if not continue loop

    #exit the program 
    li $v0, 10
    syscall

解決方法は?

ここで、あなたの基本的なアプローチとは少し異なる方法を紹介します。バイナリ出力と16進出力を共通の出力関数に対するパラメータとして扱います。ビットマスク/ビットシフトは似ていますが、マスクとビット幅は可変です。

# Read integer A from user and store it into a register
# Display the integer in binary
# Display the integer in Hex
# set Register $a0 to contain only bits 12,13,14,15 of $a0
# Display the integer in binary contained in $a0
# Display the integer in hex contained in $a0

    .data
userInput:  .asciiz     "Please enter your integer: "
binaryInput:    .asciiz "Here is the input in binary: "
nl:         .asciiz     "\n"
hexInput:   .asciiz     "Here is the input in hexadecimal: "
binaryOutput:   .asciiz "Here is the output in binary: "
hexOutput:  .asciiz     "Here is the output in hexadecimal: "
hexDigit:   .asciiz     "0123456789ABCDEF"
obuf:       .space      100
obufe:

    .text
    .globl  main
main:
    # ask end-user to submit an integer value
    li      $v0,4
    la      $a0,userInput
    syscall

    # read user-input
    li      $v0,5
    syscall
    move    $s0,$v0

    # output original in binary
    la      $a0,binaryInput
    li      $a1,32
    jal     prtbin

    # output original in hex
    la      $a0,hexInput
    li      $a1,32
    jal     prthex

    # isolate bits 12,13,14,15
    srl     $s0,$s0,12
    andi    $s0,$s0,0x0F

    # output isolated in binary
    la      $a0,binaryOutput
    li      $a1,4
    jal     prtbin

    # output isolated in hex
    la      $a0,hexOutput
    li      $a1,4
    jal     prthex

    # exit the program
    li      $v0,10
    syscall

# prtbin -- print in binary
#
# arguments:
#   a0 -- output string
#   a1 -- number of bits to output
prtbin:
    li      $a2,1                   # bit width of number base digit
    j       prtany

# prthex -- print in hex
#
# arguments:
#   a0 -- output string
#   a1 -- number of bits to output
prthex:
    li      $a2,4                   # bit width of number base digit
    j       prtany

# prtany -- print in given number base
#
# arguments:
#   a0 -- output string
#   a1 -- number of bits to output
#   a2 -- bit width of number base digit
#   s0 -- number to print
#
# registers:
#   t0 -- current digit value
#   t5 -- current remaining number value
#   t6 -- output pointer
#   t7 -- mask for digit
prtany:
    li      $t7,1
    sllv    $t7,$t7,$a2             # get mask + 1
    subu    $t7,$t7,1               # get mask for digit

    la      $t6,obufe               # point one past end of buffer
    subu    $t6,$t6,1               # point to last char in buffer
    sb      $zero,0($t6)            # store string EOS

    move    $t5,$s0                 # get number

prtany_loop:
    and     $t0,$t5,$t7             # isolate digit
    lb      $t0,hexDigit($t0)       # get ascii digit

    subu    $t6,$t6,1               # move output pointer one left
    sb      $t0,0($t6)              # store into output buffer

    srlv    $t5,$t5,$a2             # slide next number digit into lower bits
    sub     $a1,$a1,$a2             # bump down remaining bit count
    bgtz    $a1,prtany_loop         # more to do? if yes, loop

    # output string
    li      $v0,4
    syscall

    # output the number
    move    $a0,$t6                 # point to ascii digit string start
    syscall

    # output newline
    la      $a0,nl
    syscall

    jr      $ra                     # return