CASL U - 合計の計算
 前へ 目次へ 次へ

合計の計算

 整数データの合計を計算する副プログラムGOUKEIを作成する。合計値は−32768〜32767の範囲に収まるものとする。ここでは、次の2通りについて作成する。

(1) データが格納された領域の先頭アドレスと、データの個数を副プログラムに渡す。
(2) データが格納された領域の先頭アドレスだけを副プログラムに渡す。


(1)の方法 副プログラムGOUKEI1
 データが格納された領域の先頭アドレスをGR1に、データの個数をGR2に格納して副プログラムに渡し、合計値をGR0に格納して戻る。手順は次のとおりである。

  1. レジスタGR0(合計用)を0で初期化する。
  2. GR1番地(データ領域)のデータをレジスタGR3に格納する。
  3. 合計用GR0とデータGR3を加算する。(結果はGR0に格納される。)
  4. GR1番地に1を加算する。
  5. データ個数GR2から1を減算する。
  6. 0でなければ 2. へ移動する。0ならば次へ。
  7. 呼び出し元に戻る。
MAIN1    START
         LAD     GR1, AREA
         LD      GR2, KOSUU
         CALL    GOUKEI1
         ST      GR0, ANS
         RET
KOSUU    DC      10
AREA     DC      5,4,3,2,1,10,9,8,7,6
ANS      DS      1
         END
GOUKEI1  START
         RPUSH
         LAD     GR0, 0         ;1.
LOOP     LD      GR3, 0, GR1    ;2. データをGR3に格納.
         ADDA    GR0, GR3       ;3. 合計.
         LAD     GR1, 1, GR1    ;4. アドレス1加算.
         SUBA    GR2, =1        ;5. 個数を1減.
         JNZ     LOOP           ;6. 0でなければLOOPへジャンプ.
         RPOP
         RET                    ;7.
         END

2. GR1番地(データ領域)のデータをレジスタGR3に格納する。
 レジスタに記憶された値を番地として、その番地のデータを取り出すにはアドレスを0として、レジスタの値を指標レジスタとして使う。したがって、番地としてレジスタに記憶させるときは、GR1〜GR7の指標レジスタとして使えるレジスタを選択する。

4. GR1番地に1を加算する。
 GR1にはデータ領域の先頭アドレスを記憶している。すなわち、値をアドレスとして利用している。したがって、GR1に対しては論理加算をするのが適当である。論理加算命令ADDLを使うと、ADDL    GR1, =1 となり、LAD命令を使った場合よりメモリ使用量が増えてしまうからである。

5. データ個数GR2から1を減算する。
 SUBA命令の代わりにLAD命令を使って、LAD  GR2, -1, GR2 でもGR2から1を減じることはできる。しかし、次の 6. で判定(条件ジャンプ)をしているので、フラグFRが変化しないLAD命令は使えない。


 加算するデータを5, 6, 7 の3つとしたときトレースすると次のようになる。
    KOSUU  DC    3
    AREA     DC    5, 6, 7

命令 GR0 GR1 GR2 GR3 動作
  ? AREA 3 ? MAIN1.でGR1とGR2にデータを格納して副プログラムを呼び出す。
   RPUSH GR1〜GR7をスタックする。
    LAD  GR0, 0 0 1 1. GR0を0で初期化する。
LOOP  GR3, 0, GR1 5 2. GR1(AREA)番地の内容をGR3に記憶する。
    ADDA  GR0, GR3 5 3. 合計を計算する。 GR0+GR3をGR0に記憶する。
    LAD  GR1, 1, GR1 AREA+1 4. GR1に1を加算する。GR1を次の番地にする。
    SUBA  GR2, =1 2 5. 個数GR2から1を減算する。 GR2-1をGR2に記憶する。
    JNZ  LOOP 6. 個数(GR2)が0でなければ 2. へ移動する。0ならば次へ。
LOOP  GR3, 0, GR1 6 2. GR1(AREA+1)番地の内容をGR3に記憶する。
    ADDA  GR0, GR3 11 3. 合計を計算する。 GR0+GR3をGR0に記憶する。
    LAD  GR1, 1, GR1 AREA+2 4. GR1に1を加算する。GR1を次の番地にする。
    SUBA  GR2, =1 1 5. 個数GR2から1を減算する。 GR2-1をGR2に記憶する。
    JNZ  LOOP 6. 個数(GR2)が0でなければ 2. へ移動する。0ならば次へ。
LOOP  GR3, 0, GR1 7 2. GR1(AREA+1)番地の内容をGR3に記憶する。
    ADDA  GR0, GR3 18 3. 合計を計算する。 GR0+GR3をGR0に記憶する。
    LAD  GR1, 1, GR1 AREA+3 4. GR1に1を加算する。GR1を次の番地にする。
    SUBA  GR2, =1 0 5. 個数GR2から1を減算する。 GR2-1をGR2に記憶する。
    JNZ  LOOP 6. 個数(GR2)が0でなければ 2. へ移動する。0ならば次へ。
    RPOP AREA 3 ? スタックからデータをGR1〜GR7に戻す。
    RET 18 AREA 3 ? 最終結果。  7. 呼出し元へ戻る。




(2)の方法 副プログラムGOUKEI2
 データが格納された領域の先頭アドレスをGR1に格納して副プログラムに渡し、合計値をGR0に格納して戻る。手順は次のとおりである。

  1. レジスタGR0(合計用)を0で初期化する。
  2. GR1番地(データ領域)のデータをレジスタGR3に格納する。
  3. 取りだしたデータ(GR3)と終わりのデータ'#'と比較する。
  4. 一致したら 8. へ移動する。
  5. 合計用GR0とデータGR3を加算する。(結果はGR0に格納される。)
  6. GR1番地に1を加算する。
  7. 2. へ移動する。
  8. 呼び出し元に戻る。
MAIN2    START
         LAD     GR1, AREA
         CALL    GOUKEI2
         ST      GR0, ANS
         RET
AREA     DC      5,4,3,2,1,10,9,8,7,6,'#'
ANS      DS      1
         END
GOUKEI2  START
         RPUSH
         LAD     GR0, 0         ;1.
LOOP     LD      GR3, 0, GR1    ;2. データをGR3に格納.
         CPL     GR3, ='#'      ;3. データ終わりの判定.
         JZE     OWARI          ;4. 判定結果によってジャンプ.
         ADDA    GR0, GR3       ;5. 合計.
         LAD     GR1, 1, GR1    ;6. アドレス1加算.
         JUMP    LOOP           ;7. LOOPへジャンプ.
OWARI    RPOP
         RET                    ;8.
         END

 データの個数が変わっても、データの終わりである'#'が見つかるまで処理される。



 加算するデータを5, 6, 7 の3つとしたときトレースすると次のようになる。
    AREA     DC    5, 6, 7, '#'

命令 GR0 GR1 GR3 動作
  ? AREA ? MAIN1.でGR1にデータを格納して副プログラムを呼び出す。
    RPUSH GR1〜GR7をスタックする。
    LAD  GR0, 0 0 1. GR0を0で初期化する。
LOOP  GR3, 0, GR1 5 2. GR1(AREA)番地の内容をGR3に記憶する。
    CPL  GR3, ='#' 3. データ終わり判定。 GR3と'#'を比較する。
    JZE  OWARI 4. 一致したときOWARI番地へ移動する。一致しなければ次へ。
    ADDA  GR0, GR3 5 5. 合計を計算する。 GR0+GR3をGR0に記憶する。
    LAD  GR1, 1, GR1 AREA+1 6. GR1に1を加算する。GR1を次の番地にする。
    JUMP  LOOP 7. LOOP番地へ移動する。
LOOP  GR3, 0, GR1 6 2. GR1(AREA)番地の内容をGR3に記憶する。
    CPL  GR3, ='#' 3. データ終わり判定。 GR3と'#'を比較する。
    JZE  OWARI 4. 一致したときOWARI番地へ移動する。一致しなければ次へ。
    ADDA  GR0, GR3 11 5. 合計を計算する。 GR0+GR3をGR0に記憶する。
    LAD  GR1, 1, GR1 AREA+2 6. GR1に1を加算する。GR1を次の番地にする。
    JUMP  LOOP 7. LOOP番地へ移動する。
LOOP  GR3, 0, GR1 7 2. GR1(AREA)番地の内容をGR3に記憶する。
    CPL  GR3, ='#' 3. データ終わり判定。 GR3と'#'を比較する。
    JZE  OWARI 4. 一致したときOWARI番地へ移動する。一致しなければ次へ。
    ADDA  GR0, GR3 18 5. 合計を計算する。 GR0+GR3をGR0に記憶する。
    LAD  GR1, 1, GR1 AREA+3 6. GR1に1を加算する。GR1を次の番地にする。
    JUMP  LOOP 7. LOOP番地へ移動する。
LOOP  GR3, 0, GR1 '#' 2. GR1(AREA)番地の内容をGR3に記憶する。
    CPL  GR3, ='#' 3. データ終わり判定。 GR3と'#'を比較する。
    JZE  OWARI 4. 一致したときOWARI番地へ移動する。一致しなければ次へ。
OWARI  RPOP AREA ? スタックからデータをGR1〜GR7に戻す。
    RET 18 AREA ? 最終結果。  7. 呼出し元へ戻る。


−=* ポイント *=−
 あるデータ領域に格納されているデータを1つずつ順に取り出して調べる方法。

 (1) データ領域の先頭アドレスとデータ個数を設定する。
 (2) データ領域の先頭アドレス設定し、データの終わりに番兵(終わりの目印)を付ける。
の2つの方法がある。どちらの場合も、データの取り出し、アドレスの加算は次のように行う。



課題1 (1)の方法で合計を計算するプログラムで、合計値が−32768〜32767の範囲を超えた(オーバーフロー)とき、エラーメッセージを出して終わるようなプログラムを作成せよ。


 加算するデータを AREA  DC  10000,20000,30000,…というように変えてエラーメッセージが出るか確認せよ。同じように AREA  DC  -10000,-20000,-30000,…というように変えてエラーメッセージが出るか確認せよ。



 副プログラムにエラー処理を考える。

 計算結果である合計値は、−32768〜32767の全範囲の場合が想定されるので、オーバーフローを起こしたときにエラーの値として「0や-1(#FFFF)を返却する」とすることはできない。
 オーバーフローを起こしたかどうかは、FR(フラグレジスタ)のOF(オーバーフロー フラグ)を調べればわかる。合計を計算した後でJOV命令で判定ができる。

(1)の場合 (2)の場合
          ADDA    GR0, GR3
         JOV      ERR1ERR1     RPOP
         RET
         END
          ADDA    GR0, GR3
         JOV      OWARI
         …
OWARI    RPOP
         RET
         END

 エラーが起こった場合、JOV、OUT、RPOP、RET命令の順で実行されて呼出し元へ戻る。この4つの命令は実行してもFRが変化しないので、呼出し側でもOFを調べるようにする。

MAIN1    START
         LAD     GR1, AREA
         LD      GR2, KOSUU
         CALL    GOUKEI1         ;CALL    GOUKEI2
         JOV     ERROR
         ST      GR0, ANS
         RET
ERROR    OUT     EMSG, MLEN
         RET
KOSUU    DC      10
AREA     DC      5,4,3,2,1,10,9,8,7,6
ANS      DS      1
EMSG     DC      'Ove(2)rflow'
ELEN     DC      8
         END


 前へ 目次へ 次へ
 CASL U Copyright © 2003,2017  Hiroshi Masuda

 

 

inserted by FC2 system