基礎実験1 UNIX・アセンブラ実習 5

2007423

実習内容

  プログラムにバグがあるとき,レジスタやメモリの変化を観察したり,68000エミュレータの機能であるブレークポイントを使って,バグを解決するための手がかりを得ることができます.今日の実習では、自分でアセンブラプログラムを入力し、そのプログラムのテスト実行とバグの発見,デバックを行います。

 

1.プログラムの入力

プログラムの入力には前回までの実習で使ったemacsを使います。今回、実行するプログラムのファイル名はfact.sです。そこで、Terminalのウインドウ上で、「emacs fact.s & と入力しましょう。

 


$ emacs fact.s & Enterキー>

 

emacs のウインドウが開くのを待ちます。

それでは、実際に下記のプログラムファイルfact.semacsを使って作成しましょう.このプログラムは,バグの発見とデバッグを練習するために故意に間違いを入れてあります。

(注意)PascalCのような高級言語だと、たったの1行で済むような処理でも、アセンブラプログラムでは、何行にもなりプログラムも読みづらくなる。そのため、見やすい(読みやすくて分かりやすい)プログラムを心掛ける事が重要となる(アセンブラに限ったことではないが)。例えば、コメント文の活用、インデント(行頭の位置)の調節、シンボル名の付け方、Tabを使った単語の位置整列などを利用すると良い。

 


/* sample program fact.s 階乗  d1 := d0 ! (d0 >= 0)*/

.org  0x0000

.dc.l 0x5000

.dc.l start

 

.org  0x0400

start:

      moveq #1,%d1       /* d1 := 1; */

      cmp   #0,%d0       /* d00 なら最後へ*/

      beq   end_of_program

      move.l %d0,%d2      /* d2はカウンター*/

loop:                   

      mulu  %d2,%d1      /* d1 := d1 * d2; */

      subq  #1,%d2       /* d2 := d2 - 1; */

      cmp   #0,%d2       /* d20を比較 */

      bge   loop         /* d20になるまでループ */

end_of_program:

      .dc.w 0x4848

      stop  #0           /* 終了 */

 

入力が終わったらファイルを保存しましょう。emacs上で、

 


Ctrl-x Ctrl-s(上書き保存) または Ctrl-x Ctrl-w(別名で保存)

 

ファイルの中身をjlessなどのコマンドで確認しましょう。

 


$ less fact.s <Enterキー>

 

 


課題1.プログラムfactのフローチャートを考えて、解答せよ。

 

 

 

 

2. アセンブラ

前回の演習と同様に,m68k-asコマンドを使って,アセンブラソースプログラムファイルfact.sをアセンブルしましょう。kterm上で次のコマンドを実行してみましょう。

 


              $ m68k-as fact.s <Enterキー>

 

もし,文法的な間違いがある場合は,以下のようなエラーメッセージが出ます(あくまで例です)。その場合は,エラーメッセージを手がかりにemacsfact.sファイルを修正しましょう。

      fact.s: Assembler messages:

fact.s:9: Error: parse error -- statement `cmp #0.%d0' ignored

fact.s:12: Error: Unknown operator -- statement `loop ' ignored

エラーメッセージがなくなったら、実行ファイルが出来ているかlsコマンドで確認しましょう。

 


              % ls fact.* <Enterキー>

      fact.LIS     fact.abs     fact.map     fact.s

 

(単に「ls Enterキー>」と実行すると関係ないファイルも表示されるため、「fact」で始まるファイルだけを表示させた)

             

3. エミュレータ

次に,68000エミュレータ(m68k-emu)を実行しましょう。

 

% m68k-emu & Enterキー>

 

Fileメニューから、Load Programを実行し実行したいプログラムを選びます。ここでは、fact.absを選択してください。Windowメニューの、Memory Viewer Program Listingを実行すると、アセンブラプログラムの実行の様子がモニターできます。

このプログラムは、レジスタd0の値の階乗を計算しレジスタd1に格納します。レジスタの値は画面の左にあるレジスタをダブルクリック(2度続けてマウスのボタンをたたく)し、値を入力することによって値が変更できます(下図)。3の階乗を計算させて見ましょう。d03を設定します。

2.希望の値を入力(ここでは3を入力)

 

1.D0をダブルクリック

 
 

Runボタンを押して実行してみましょう。計算結果が格納されるレジスタD1は0になってしまいました。プログラムが期待通りには動いていないことが分かりました.プログラム中にバグが残っています.データレジスタD1が0になってしまう原因を,これから探していきます.

実行したところ、本当は6(3)という結果になるはずなのに、0になってしまった

 

 

4.ブレークポイント

プログラムを実行する際に、実行途中でメモリやレジスタの値を確認したい場合には、ブレークポイントを利用すると便利です。ブレークポイントを設定するとRunボタンを押したときにブレークポイントを設定した箇所で、プログラムは一時的に停止します。

ブレークポイントを設定してみましょう。エミュレータのメインウィンドウにあるBreakpointsボタンを押して番地を設定することもできますが、Program Listingのウインドウでブレークポイントを設定したい命令をクリックする方が簡単です。ブレークポイントが設定されると、その命令箇所は赤い文字で表示されます。今回は、ループの分岐の際のレジスタを調べるために、ループの分岐命令(bge loop)をクリックしましょう。bge loopの行が赤くなりました。

クリックでブレークポイントを設定(赤くなる)

 
 

Resetボタンを押した後でRunボタンを押して実行しましょう。ブレークポイントの位置で実行がとまりました。この時点でレジスタは

D0: 3     D1: 3     D2: 2

でした。続けてRunボタンを1回ずつ押すと

D0: 3     D1: 6     D2: 1

D0: 3    D1: 6     D2: 0

D0: 3     D1: 0     D2: ffff

と変化しました。どうやらD20のときにもループしてしまいD10になってしまったようです。つまり、分岐の条件が間違っていたのです。

条件分岐の代表的なものをあげてみます。

bge            bgt         beq        ble         blt         bne

>=             >            =            <=          <           

bge loopを正しいものに置き換えて動かしてみましょう。

emacsでファイルを編集し、(終了していなければファイルを読み直しましょう)

 


              $ emacs fact.s & <Enterキー>

 

再度、アセンブラを実行し、

 


              $ m68k-as fact.s <Enterキー>

 

68000エミュレータを実行しましょう。(終了していなければファイルを読み直しましょう)

 


$ m68k-emu & Enterキー>

 

d03のときにd16になりましたか?

4!,2!,1!,0!についても試してみましょう。Resetボタンを押し、d0レジスタに値を入れた後で、Runボタンを押してください。4ではd118と表示されたと思います。これは16進数で表示されているため16*1+8=24=1*2*3*4で正解です。

 

5. CCRSR)と条件付分岐命令

今回のプログラムのサブルーチン中には,下のような条件付分岐命令が含まれている(1)。しかしながら,この条件分岐命令cmpは必要ではなく,(2)のように省くことができる.なぜか?

(1)

subq  #1,%d2

cmp.w #0,%d2

bge   loop

 

 

(2)

subq  #1,%d2

bge   loop

 

 
       

             

 

 

この理由を理解するためには、まずcmp命令の意味を理解する必要がある。cmp命令は実際にはデスティネーションオペランドからソースオペランドを減算している(命令表p.310を必ず見ること)。そして、その結果はCCR(コンディションコードレジスタ)に反映される。このCCRとは、SR(ステータスレジスタ)の下位8ビット(実際に使うのは5ビット)のことであり、エミュレータメインウィンドウ左のレジスタ一覧にも表示されている。このCCRの詳しい説明は以下のURLを参照すること

http://www.db.is.kyushu-u.ac.jp/rinkou/as/advanced/ccr.html

つまり、大小比較のため減算をし、その結果が負ならばCCRNのビットを1にし、結果が0ならばCCRZのビットを1に設定している。もちろん、結果が正の場合は、CCRNZのビットは0のままとなる。こうすることで、CCRを見れば、直前に行われた比較(減算)結果がどうであったかが分かる仕組みになっているのである。cmp命令がsub命令と違う点は、減算した結果がデスティネーションオペランドには格納されないという点だけであり、sub命令も減算の結果、cmp命令と同様にCCRに影響を及ぼす。

次に、条件付分岐命令bccccには不等号条件が設定される)(命令表p.372を必ず見ること)の意味について説明する。この命令は、CCRに応じて必要なロケーションへ制御を移行させるものである。そのため、本例の場合、レジスタd2から1を減算した結果が0でなければ、CCRZNのビットが0となり、bge命令はそのCCRを参照した結果、loopに制御を移行させるのである。そのため、(2)のプログラムのように,sub命令とbge命令の間のcmp命令を省くことができるのである。

この一連の流れを確認するために、分岐命令の箇所(1)を(2)のように変更し,条件分岐命令付近でのCCR(実際にはSRの下位5ビット)の変化を確認しましょう。

(注意)subq命令とsub命令の違い、moveq命令とmove命令の違いについては、命令表を自分で調べてみること。自分で積極的に試したり、調べることも実習の一部です。

 

<印刷方法> http://brain.is.kyushu-u.ac.jp/~matsuki/enshu/2007/print.htmを参考にすること

 

 


課題2fact.sを参考にして、分岐命令(繰り返し)を使ったプログラムを作成せよ.そして,その計算結果を報告せよ.

(1)105

(2)

 

今日の実習はここまでです。

 

参考Webページ: http://www.db.is.kyushu-u.ac.jp/kaneko/as/index.html