機械語命令とアセンブラ


  1. COMETII


    1. COMETII

      機械語プログラムは特定の構造に依存します。ここでは、計算機のモデルに基本情報技術者試験での機械語モデルに採用されているCOMETIIを紹介します。
       KOMETIIの主記憶は16ビット幅で、アドレスは16ビットで指定できる、0〜65535 です。プログラムは32本の汎用レジスタ GR0 〜 GR31 が利用できます。専用レジスタには下記があります。

      SP: スタックポインタ
      FR: フラグレジスタ

       フラグレジスタには、以下の状態(フラグ)があります。

      ZF; 演算結果が0になると1になる
      SF: 演算結果が負になると1になる
      OV: 演算結果がオーバーフローすると1になる

      演算命令でフラグレジスタのフラグ(ZF,SF)がセットされます。このフラグを利用して、分岐命令はこのフラグを分岐条件として利用します。オーバーフローとは、計算結果が上限(記憶できるビット数)を超えた場合に発生するエラー用のフラグです。
       スタックレジスタ SP はスタック機能を有効にします。PUSH,POP 命令やサブルーチン呼び出し(CALL)やサブルーチンからの戻り(RETURN)命令はスタックを利用します。



    2. アドレス指定

       メモリのアドレス指定は、GRによる index 指定が可能です。命令で指定したアドレスとGRから計算する
            指定アドレス+GR
      が実効アドレス(実際に読み書きする番地)となります。


      ST  GR3,DATA1,GR2;  GR3の内容を DATA1+ GR2 番地に保存する

    3. 演算命令

       16ビットの整数の加減算と論理演算が可能です。乗除算や少数演算機能はありません。他に、シフトと比較機能があります。

    4. 制御命令

       プログラムの実行番地を指定するには、分岐命令を利用します。分岐命令の条件にはフラグレジスタの状態フラグを利用します。


       JZE owari   ;ZF が1のとき owari に分岐(ジャンプ)

      他に、サブルーチン呼び出し(CALL)と戻り(RETURN)命令が利用できます。また、分岐先のアドレスにも index 修飾が可能です。

    5. IN,OUT命令

       これは機械語命令ではなく仮想的な命令です。
      IN命令は入力装置から命令で指定した番地(INBUF)を先頭に1行文字を読み込み、その長さを指定番地(INLNG)に記録します
           IN  INBUF,INLNG
      OUT命令は命令で指定した番地(OUTBUF)から指定した番地(OUTLEN)の数だけ出力装置に書き出します。
           OUT OUTBUF,OUTLEN

  2. CASLによるプログラム


    1. CASL

       機械語の命令は、計算機内部では、0,1 に変換されて記憶されますが、人が0,1の形式でプログラムを書くのはめんどうです。0,1の替わりに記号化した命令や番地、を利用します。これはアセンブリ言語といいます。CASLはCOMET用のアセブンブリ言語です。CASLには、機械語を生成しないアセンブラ命令と、1行が1語の機械語命令に変換される記号命令から構成されます。アセンブリ言語はアセンブラと呼ばれるプログラムで機械語に変換されます。アセンブルとは「組み立てる: assemble」意味で、記号から0,1の命令をを「組み立てる」意味です。

    2. アセンブラ命令

       アセンブラ命令は、CPUが直接実行する命令ではなく、アセンブラに対する指示になります。以下のような「命令」があります。
      • START 番地
         プログラムの開始とプログラムを記憶する先頭番地を指定します。

      • END
        プログラムの最後を示します。

      • DS サイズ
         サイズのメモリ領域を確保します。データ領域を確保するのに利用します。

      • DC データ1,データ2,.. ,データn
         指定したデータを2進データに変換し、順に記憶します。定数には、10進数、16進、文字列、を指定できます。

    3. 記号番地(ラベル)

       アセンブラでは、命令を記号で指定できるのが便利ですが、実は、もっと便利な点は番地の記号化です。命令では、LD 命令や 分岐命令で番地を指定しますが、この番地はプログラムを修正すると違った番地になってしまいます。そこで、参照したい番地に ラベル を付けておき、命令で番地を指定する替わりに、このラベルを指定します。例で説明します。

            LD   GR1,A

       A     DC  10

      この例で、アセンブラ命令 DC の先頭につけた A が記号番地です。LD 命令で A を指定することで、DC 10 (値10の入った番地) を指定できます。このようにすれば、LD 命令とDC命令の間に命令が追加され、A の値が変わってもアセンブラは A の番地を再計算し、正しいAの番地を生成してくれます。

    4. 記号命令

       アセンブラでは、以下の記号化した命令を利用します。

      命令コード オペランド 機能処理 記述例
      LD GRx ,[adr], [GRy] op を GRx に設定。 LD GR0 10
      ST GRx ,[adr], [GRy] (GRx)を op  が示す番地に格納。 ST GR0 10
      LAD GRx ,[adr], [GRy] op を GRx に設定。 LAD GR0 1
      ADDA GRx ,[adr], [GRy] (GRx)とopを加算して GRx に格納 ADDA GR0 GR1
      ADDL GRx ,[adr], [GRy] (GRx)とopを加算(符号なし)して GRx に格納 ADDL gr0,5,GR1
      SUBA GRx ,[adr], [GRy] (GRx)からopを減算して GRx に格納
      SUBL GRx ,[adr], [GRy] (GRx)からopを減算(符号なし)して GRx に格納
      AND GRx ,[adr], [GRy] (GRx)とopの論理積を GRx に格納。 AND GR0 GR1
      OR GRx ,[adr], [GRy] (GRx)とopの論理和を GRx に格納。 OR GR0 GR1
      XOR GRx ,[adr], [GRy] (GRx)とopの排他的論理和をGRxに格納。 XOR GR0 GR1
      CPA GRx ,[adr], [GRy] (GRx)とopの大小関係でFRをセット CPA GR0 GR1
      CPL GRx ,[adr], [GRy] (GRx)とopの大小関係(符号梨なし)でFRをセット
      JMI adr[,GRx] (SF)が1のときにadrの指す番地へ分岐 JMI 10
      JPL adr[,GRx] (SF)が0のときにadrの指す番地へ分岐 JPL ad,GR0
      JNZ adr[,GRx] (ZF)が0のときにadrの指す番地へ分岐
      JZE adr[,GRx] (ZF)が1のときにadrの指す番地へ分岐
      JOV adr[,GRx] (OF)が1のときにadrの指す番地へ分岐
      JMP adr[,GRx] 無条件にadrの指す番地へ分岐。 JMP
      PUSH adr[,GRx] adr をスタックに保存 PUSH 0,GR3
      POP GRx スタックからとりだしGRxにコピー POP GR3
      CALL adr[,GRx] adrを呼び出す CALL fun
      RET 戻る RET
      NOP なにもしない
      SVC num システムサービスを呼び出す SVC 1

  3. プログラム例


    1. 二つの数の和

      A と B の番地の値を加算して結果をCの番地に保存するプログラムです。最初の START はCPU が実行する命令でなく、アセンブラへの指令です。この場合、プログラムの「開始」を意味します。
      LD 命令は A(番地) の値を GR1(レジスタ) に移します。ST 命令は GR1 の値を C(番地) に保存する命令です。
       DC はアセンブラ命令でデータを定義します。この場合、5を A の番地に保存します。プログラムの最後は RET 命令で OS(管理プログラム) に戻るものとします。DS はメモリ領域を確保するアセンブラ命令です。
       最後の END でプログラムの最後を示します。
      SUM2   START
      ;二つの数の和
      ;
              LD      GR1,A
              ADDA    GR1,B
              ST      GR1,C
              RET
      ;
      A       DC      5
      B       DC      3
      C       DS      1
              END

      演習1
      上のプログラムに対応するC言語のプログラムを書いてください。

      演習2
       D=A+B-C
      に対応するCASLプログラムを書いてください。

    2. 1から10の和

      次は繰り返しループにより1から10までの和を求めています。先頭の XOR 命令は GR1 を0にしています(同じ値のXOR演算は0になります)。GR4に繰り返し数、GR2 に定数1、GR3 を 和の値を保存するレジスタにします。
       繰り返しの中で、まず、GR1を1増し、GR3 に次の数を加えています。CPA で比較判断をし、GR1<GR4 なら、LOOP に分岐をして繰り返しを行います。そうでなければ、GR3 をSUMに保存し、終了します。

      SUM10   START
      ;10までの和
      ;
              XOR     GR1,GR1 ;GR1=0
              LD      GR4,N ;GR4は繰り返しの数 N を記憶
              LAD     GR2,1 ;GR2は定数1
              XOR     GR3,GR3 ;GR3=0
      ;
      LOOP    ADDA    GR1,GR2 ;回数を増す
              ADDA    GR3,GR1 ;和を求める
              CPA     GR1,GR4 ;比較をして終了判断
              JMI     LOOP ;負なら繰り返す
      ;
              ST      GR3,SUM ;結果をSUMに保存
              RET
      ;
      SUM     DS      1 ;結果を保存する
      N       DC      10 ;回数を保存する
      ;
              END
      演習3
       上のプログラムに対応するC言語プログラムを書いてください。

      演習4
       Aを10回加える方法で、A*10 を計算するCASLプログラムを書いてください。

    3. 配列の和

      配列(データの並び)の和を求めます。ary から数字が7個ありますが、これをすべて加算するのが目的です。加算する数はNUM、合計した結果は SUM に保存します。
       繰り返しの方法は先の例と同じです。異なるのは、配列の値を加える部分です。
       ADDA GR2,ARY,GR1
      で、 「 ARY,GR1 」はインデックス修飾機能を利用し、ARY+GR1 番目のデータになります。GR1 を1つ増しながら繰り返せば、続く番地を加えていくことができます。

      ARYSUM  START
      ;配列の和を求める
              XOR     GR1,GR1 ;くりかえし回数
              XOR     GR2,GR2 ;合計
              LAD     GR3,1 ;定数1
              LD      GR4,NUM ;繰り返し限度
      ;
      LOOP    ADDA    GR2,ARY,GR1 ;配列の値を加える
              ADDA    GR1,GR3 ;繰り返し数を増加
              CPA     GR1,GR4 ;回数判断
              JMI     LOOP ;負なら繰り返す
      ;
              ST      GR2,SUM ;合計を保存
              RET
      ;
      SUM     DS      1 ;和
      NUM     DC      7 ;繰り返し上限
      ARY     DC      12,42,56,86,27,16,84 ;配列データ
      ;
              END

    4. 配列の最大値

      配列のデータの最大値を求めます。配列の和と同様に繰り返しを行いますが、配列の値がこれまでの仮の最大値より大きいとき、仮の最大値を新しい数と置き換えます。
      GR2が仮の最大値です。最初は配列の先頭の値に初期化します。
       繰り返しの中で、GR5 に配列の次の値を取り出します。先の例とどうよう、インデクス修飾を利用しています。GR5とGR2を比較し、GR5 が大きい場合、 JPL SKIP で分岐しませんから LD GR2,GR5 を行い、最大値を入れ替えます。
       繰り返しの中で、大小判断をするため、少し複雑な制御になっています。

      ARYMAX          START
      ;最大値を求める
              XOR     GR1,GR1 ;くりかえし回数
              LD      GR2,ARY;
              LAD     GR3,1 ;定数1
              LD      GR4,NUM ;繰り返し限度
      ;
      LOOP    LD      GR5,ARY,GR1 ;配列の値を取り出す
              CPA     GR2,GR5 ;仮の最大値と比較
              JPL     SKIP
              LD      GR2,GR5 ;最大値を交換する
      SKIP    ADDA    GR1,GR3 ;繰り返し数を増加
              CPA     GR1,GR4 ;回数判断
              JMI     LOOP ;負なら繰り返す
      ;
              ST      GR2,MAX ;最大値を保存
              RET
      ;
      MAX     DS      1 ;最大値
      NUM     DC      7 ;繰り返し上限
      ARY     DC      12,42,56,86,27,16,84 ;配列データ
      ;
              END

      演習5
       上のプログラムに対応するC言語プログラムを書いてください。

      演習6
       int ARY[10] = { 34,12,6,3,67,41,47,5,83,56}
       として、変数 N と同じ数があるときその配列の番号を返すCASLプログラムを作成して下さい。

    5. 乗算サブルーティン

       COMETには乗算命令はありません。乗算を行うサブルーティン(C言語の関数)を作成してみましょう。乗算は GR7=GR5*GR6 を計算します。簡単のため、GR6>=0 とします。GR<0 の場合は乗数と被乗数の双方の符号を反転する機能を追加する必要があります。また、この方法は時間がかかります。シフトを組み合わせた加算なら、ビットの繰り返しで計算できます。
       プログラムは、GR5とGR6に乗数と被乗数を設定し乗算サブルーティンMULTを CALL(呼び出し)します。 MULTでは、GR7を0に設定後、PUSH を行います。これはGR3をスタックに保存し、スバルーティンから戻すときに POP して元に戻します。一時保存するだけですから、ST GR3,TEMP とメモリに記憶しても良いのですが、PUSH 命令の方が簡単で高速です。
       MLOOP で乗数の数だけ被乗数を加算します(したがって乗数は正でなくてはいけません)。計算後 GR6 は0になってしまいます。GR6 もPUSH、POP するほうが良いかもしれません。
       サブルーティンの利点を生かすため、MULT を2回呼び出しています。
      FMULT   START
      ;乗算サブルーティン
              LD      GR5,A
              LD      GR6,B
              CALL    MULT ;GR7=GR5*GR6
              ST      GR7,C ;結果を保存
              LD      GR6,GR7 ;GR6=A*B
              CALL    MULT ;GR7=A*B*C
              ST      GR7,D ;結果を保存
              RET
      ;
      MULT    XOR     GR7,GR7 ;GR7=0
              PUSH    0,GR3 ;GR3を一時保存
              OR      GR6,GR6 ;GR6の判断
              JZE     EXIT ;0なら終了
              LAD     GR3,1 ;定数1
      ;
      MLOOP   ADDA    GR7,GR5 ;GR7=GR7+GR5
              SUBA    GR6,GR3 ;GR6=GR6-1
              JPL     MLOOP ;繰り返し
      ;
      EXIT    POP     GR3 ;GR3を戻す
              RET
      ;
      A       DC      16
      B       DC      16
      C       DS      1
      D       DS      1
      ;
              END

  4. 課題


     付録にCASLアセンブラとシミュレータの利用法を紹介しています。これらを用いてサンプルプログラムを実行してください。
     演習6で作成したCASLプログラムまたは乗算プログラムを実行し、実行結果を報告してください。
     
     期限:次回講義