[解決済み] LC3で不正なベクター番号でトラップが実行されました。
質問
LC3で与えられた数値を異なる塩基に変換しなければならない課題をやっています。そのためには割り算をする必要があるのですが、これと同じことをする課題があったのですが、今回の割り算のアルゴリズムが違います。
この課題では、拡張除算を使うことが期待されています。基本的なアルゴリズムは
32ビットの数値が与えられたとき、最初の16ビットをあるメモリアドレスに格納し(上位分子と呼ぶ)、最後の16ビット(下位分子)を別のメモリアドレスに格納し、さらに16ビットの数値である除数を別のメモリアドレスに格納します。つまり、サブルーチンでは、メモリから数値を別のレジスタに取り込み、以下のようにアルゴリズムが動作することになります。
- 高分子と低分子のレジスタを一旦左にシフトします(低分子の高ビット(左端)が1であれば、高分子の低ビットに渡されます(シフトしているのであらかじめ0になっているはず)。
- 高分子は除数と比較されます。以上であれば、そこから除数を引き、低分子の低ビットを設定します。等しくなければ、何もしません(シフトを繰り返すうちに、最終的には大きくなります)。
- シフトとチェックを16回繰り返し、分子の下位ビット(右端)をセットする
- 最後に、分子の高い方のレジスタに除算の余りが、分子の低い方のレジスタに商が格納されます。
簡単のために、講師は高い分子に0を使わせています。そこで、このアルゴリズムを実現するために、次のような手順を思いつきました。
- まず、ARGLISTという名前の5つの.BLKWを宣言し、そこにすべての引数が格納されます。
- PRINTサブルーチンです。次に、ARGLISTのアドレスをレジスタにロードし、そこに低分子を格納し、インクリメントして高分子(0)と除数を格納します; 次に、BUFFERとDIGITSのポインタにロードして、指定したベースに変換した結果を格納します。そして、DIVIDEサブルーチンが呼ばれます。
- DIVIDEサブルーチン。ARGLISTのアドレスをレジスタにロードし(代入命令でR6)、必要なレジスタにロード、インクリメントして値を用意し、分子をシフトするループを16回行い(分子の下位ビットを得るためにx0080でマスクも行う)、DVRが上位分子以下となるたびに減算し、を繰り返しています。そして商と余りがR6が指す場所に格納され(もちろん次を得るためにインクリメントされる)、リターンします。
- PRINTに戻ると、R7が指す値からR2とR3(課題2からできるだけ多くのコードを再利用するために同じにしておきます)にロードし、それはまた今入力されるべきARGLISTを指すので、それから課題2と同じようにサブルーチンを続けます。
- バッファへの保存がすべて完了したら、ARGLIST の先頭に戻って低い方の分子を更新し、次の反復(次の除算)に備えるために商を指します。
以下は、私がこれまでに作成したコードの全容です。
.ORIG x3000
LEA R0, MPROMPT
TRAP x22
LOOP
JSR GETDEC ;Input an unsigned (decimal) integer
ADD R0, R0, #0 ;Exit if the input integer is 0
BRZ EXIT
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 10 (output base 10 DECIMAL)
ADD R1, R1, #10
JSR PRINT ;Print the integer in decimal
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 2 (output base 2 BINARY)
ADD R1, R1, #2
JSR PRINT ;Print the integer in binary
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 8 (output base 8 OCTAL)
ADD R1, R1, #8
JSR PRINT ;Print the integer in octal
JSR NEWLN ;Move cursor to the start of a new line
AND R1, R1, #0 ;R1 = 16 (output base 16 HEXADECIMAL)
ADD R1, R1, #15
ADD R1, R1, #1
JSR PRINT ;Print the integer in hexadecimal
JSR NEWLN ;Move cursor to the start of a new line
BRNZP LOOP
EXIT ;Loop exit point
TRAP x25 ;HALT program execution
MPROMPT .STRINGZ "Enter a sequence of unsigned integer values\nEnter 0 To Quit\n"
;Subroutine NEWLN*************************************************************
;Advances the console cursor to the start of a new line
NEWLN
ST R7, NEW7 ;Save working registers
ST R0, NEW0
LD R0, NL ;Output a newline character
TRAP x21
LD R0, NEW0 ;Restore working registers
LD R7, NEW7
RET ;Return
;Data
NL .FILL x000A ;Newline character
NEW0 .BLKW 1 ;Save area - R0
NEW7 .BLKW 1 ;Save area - R7
;Subroutine GETDEC************************************************************
;Inputs an unsigned integer typed at the console in decimal format
;The input value is returned in R0
GETDEC
;Save Values of ALL Registers that don't need to change
ST R1, GET1
ST R2, GET2
ST R3, GET3
ST R4, GET4
ST R5, GET5
ST R6, GET6
ST R7, GET7 ;Save R7 to be able to return to main
AND R3, R3, #0 ;Prepare a value
LEA R0, GPROMPT
TRAP x22
GETDKEY
TRAP x20 ;To input a keystroke
ADD R2, R0, #-10 ;Subtract new keystroke by 10 (new line, or enter)
BRZ GFINIS ;If R2 is 0 we just pressed enter, so we break out
TRAP x21 ;Echo keystroke
ADD R2, R0, #0 ;Get the number back
AND R2, R2, #15 ;We mask to only get the first four bits
ADD R3, R3, R3 ;1st addition: x + x = 2x
ADD R4, R3, #0 ;Store the 2x
ADD R3, R3, R3 ;2nd addition: 2x + 2x = 4x
ADD R3, R3, R3 ;3rd addition: 4x + 4x = 8x
ADD R3, R3, R4 ;4th addition: 8x + 2x = 10x
ADD R3, R3, R2 ;10x + new number
BRNZP GETDKEY ;Go back to get next number
GFINIS
ADD R0, R3, #0 ;Put number into R0
;Restore the values of registers that don't need change
LD R1, GET1
LD R2, GET2
LD R3, GET3
LD R4, GET4
LD R5, GET5
LD R6, GET6
LD R7, GET7 ;Get back the value of R7
RET
;Data
GPROMPT .STRINGZ "Enter an unsigned integer> " ;Input Prompt
GET1 .BLKW 1
GET2 .BLKW 1
GET3 .BLKW 1
GET4 .BLKW 1
GET5 .BLKW 1
GET6 .BLKW 1
GET7 .BLKW 1
;Subroutine PRINT*************************************************************
;Displays an unsigned integer in any base up to 16, e.g. binary, octal, decimal
;Parameters - R0: the integer - R1: the base
PRINT
ST R0, PR0
ST R1, PR1
ST R2, PR2
ST R3, PR3
ST R4, PR4
ST R5, PR5
ST R6, PR6
ST R7, PR7
LEA R7, ARGLIST ;Point to ARGLIST to start populating the args
STR R0, R7, #0 ;Put R0 to be the low numerator
AND R0, R0, #0 ;R0 is not needed after this, so it is cleared
ADD R7, R7, #1 ;Go down on pointer once to store next arg
STR R0, R7, #0 ;Put R0, now x0000, to be the high numerator
ADD R7, R7, #1
STR R1, R7, #0 ;Store the base, R1, to be the DVR
ADD R7, R7, #1 ;Have R7 point to Quotient
LEA R6, BUFFER
AND R5, R5, #0 ;To make sure R5 is cleared
LEA R4, DIGITS ;Prepare pointer to the digits
SDIV
JSR DIVIDE
LDR R2, R7, #0 ;Since the addresses should now be ready,
;R7 would point to quotient, passed to R2
LDR R3, R7, #1 ;Pass remainder to R3
ADD R3, R3, R4
LDR R5, R3, #0
ADD R6, R6, #-1 ;Decrement to get to the next one
STR R5, R6, #0 ;Store number into buffer
LEA R7, ARGLIST ;Go back to ARGLIST to store new numerator
STR R2, R7, #0
ADD R7, R7, #3 ;Point to quotient
ADD R0, R2, #0 ;Pass quotient into R0
BRP SDIV ;If number is at least 1, then divide again
ADD R0, R6, #0 ;If we got here, then we should have the converted number
TRAP x22 ;Last but not least we display
LD R0, PR0
LD R1, PR1
LD R2, PR2
LD R3, PR3
LD R4, PR4
LD R5, PR5
LD R6, PR6
LD R7, PR7
RET
;Data
DIGITS .STRINGZ "0123456789ABCDEF" ;Digits
.BLKW 18 ;Output Buffer
BUFFER .FILL x0000 ;Null
PR0 .BLKW 1
PR1 .BLKW 1
PR2 .BLKW 1
PR3 .BLKW 1
PR4 .BLKW 1
PR5 .BLKW 1
PR6 .BLKW 1
PR7 .BLKW 1
;Subroutine DIVIDE************************************************************
;Extended division is done here
DIVIDE
ST R1, DIV1
ST R2, DIV2
ST R3, DIV3
ST R4, DIV4
ST R5, DIV5
ST R6, DIV6
ST R7, DIV7
LEA R6, ARGLIST ;Point straight to where arguments start
LDR R5, R6, #0 ;Load NUMLOW into R5
ADD R6, R6, #1 ;Go down one step in pointer
LDR R4, R6, #0 ;Load NUMHIGH into R4
ADD R6, R6, #1 ;Go down once more
LDR R3, R6, #0 ;Load DVR into R3
ADD R6, R6, #1 ;Go down yet once more to be ready when we
;store results
LD R1, M8BIT ;Make R1 be equal to x0080 to get last bit
;from NUMLOW
AND R2, R2, #0 ;Set R2 as counter to decrement with each
ADD R2, R2, #10 ;iteration
ADD R2, R2, #6
ITER ADD R4, R4, R4 ;Shift NUMHIGH to the left once
AND R7, R5, R1 ;Masking. If R5[7] == 1, then R7 == x0080
BRNZ NOADD ;(or positive)
ADD R4, R4, #1 ;If this happens then R5[7] was set, so we're
;adding the bit that would be lost if R5
;shifts left
NOADD ADD R5, R5, R5 ;Shift NUMLOW to the left once
NOT R7, R3 ;Subtract NUMHIGH and DVR. If 0 or positive
ADD R7, R7, #1 ;then subtract and increment NUMLOW
ADD R7, R4, R7
BRN DECCNT ;If negative then DVR is greater than NUMHIGH,
;go straight to decrement the loop count
ADD R4, R7, #0
ADD R5, R5, #1
DECCNT ADD R2, R2, #-1
BRP ITER ;If count is positive, go back to ITER
STR R5, R6, #0 ;Store NUMLOW for the Quotient Address
ADD R6, R6, #1 ;Increment to store in the next one
STR R4, R6, #0 ;Store NUMHIGH for the Remainder Address
LD R1, DIV1
LD R2, DIV2
LD R3, DIV3
LD R4, DIV4
LD R5, DIV5
LD R6, DIV6
LD R7, DIV7
RET ;Return
;Data
ARGLIST .BLKW 5 ;Here we will put the LOWNUM, HIGHNUM,
;DVR, QUO, and REM
M8BIT .FILL x0080
DIV1 .BLKW 1
DIV2 .BLKW 1
DIV3 .BLKW 1
DIV4 .BLKW 1
DIV5 .BLKW 1
DIV6 .BLKW 1
DIV7 .BLKW 1
.END
アルゴリズムはうまくいっているはずなのですが、LC3で実行すると、次のようなエラーが発生します。
A trap was executed with an illegal vector number
そして、プロセッサは停止しています。なぜか、LC3で自分のコードをチェックすると、この行のすぐ後で消されてしまうことに気づきました。
ADD R0, R2, #0
これは、DIVIDEサブルーチンを再度呼び出すために分岐する直前の状態です。
なぜこのようなことが起こるのでしょうか?私が知る限り、レジスタの保存と復元はきちんと行っているのですが(前回、これと似たような問題が発生し、同じ.BLKWに保存していたためにエラーが発生したと指摘されました)、このエラーは続いているのです。どなたか誤動作に心当たりのある方、また必要な情報がありましたら教えてください。よろしくお願いします。
解決方法は?
解決しました。主なエラーは2つでした。
1) マスクを使用する必要がなかった。どちらかというと、レジスタが16ビットの値を保持するため、マスク自体が間違っていた。もしマスクを使いたいのであれば、より適切な値は次のようになります。
x8000
のオペコードなので、やはり使えません。
RTI
. あとは、分子の少ないレジスタであるR5を分岐計算に入れるようにすればよかったのです。もし、それが
negative
ということは、上位ビットは明らかに「1」です。
2) これがプログラムを壊していた原因です。注意すべきは
PRINT
関数を使っていましたが
LEA
と
R7
. これは、このレジスタが引数を指し示す責任を負っていたことを意味します。しかし、この後の数行で私は
JSR
:
JSR DIVIDE
このようなジャンプが発生した場合、通常のプログラム実行に戻るために必要なPCの値は、内部でレジスタに格納されていることを認識していませんでした。どこですか?R7. ということは、たとえ
DIVIDE
があったのですが
ST
と
LD
に戻ると、R7の値が復元されます。
PRINT
であったはずです。
次の命令のアドレス
へのポインタではなく
ARGLIST
. このプログラムを正しく実行するために必要なことは、単純な
LEA
を追加し、商と余りを指すように3を追加し、ポインタの操作を少し下に修正して、更新された低い分子を格納するようにしました。要するに
DIVIDE
の呼び出しは、次のようになります。
SDIV
JSR DIVIDE
LEA R7, ARGLIST
ADD R7, R7, #3
LDR R2, R7, #0 ;Since the addresses should now be ready,
;R7 would point to quotient, passed to R2
LDR R3, R7, #1 ;Pass remainder to R3
ADD R3, R3, R4
LDR R5, R3, #0
ADD R6, R6, #-1 ;Decrement to get to the next one
STR R5, R6, #0 ;Store number into buffer
LEA R7, ARGLIST ;Go back to ARGLIST to store new numerator
STR R2, R7, #0
ADD R0, R2, #0 ;Pass quotient into R0
BRP SDIV ;If number is at least 1, then divide again
ADD R0, R6, #0 ;If we got here, then we should have the converted number
TRAP x22 ;Last but not least we display
関連
-
[解決済み] テスト
-
[解決済み] 着信側セーブレジスタ、発信側セーブレジスタとは何ですか?
-
[解決済み] cmplとcmpの違いについて
-
[解決済み] error A2022: 命令オペランドは同じサイズでなければなりません。
-
[解決済み] エラーです。操作サイズが指定されていません - NASm
-
[解決済み] x86-64におけるmovqとmovabsqの違いについて
-
[解決済み] linuxのsys_readシステムコールを作ると、レジスタeaxに何が入るのでしょうか?
-
[解決済み] SRLとSRAの違いは何ですか?[重複しています]。
-
[解決済み] ワードptrとは何ですか?
-
[解決済み] アセンブルmov命令
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン