平成30春の過去問問12 アセンブラ のプログラミング(コメント、トレースのノート付き)

この記事では、過去問のアセンブラの問題に載っているプログラムを実際に自分の環境で作成して動かすのに使ったコードと、トレースのノートを掲載しています。
この記事を通してアセンブラだけでなくアルゴリズムのトレース力向上にもお役立て下さい。

アセンブラ過去問プログラミング
アセンブラ自作サンプルへ
基本情報技術者試験トップへ
令和2年度(令和3年1月合格報告)

シミュレーターと過去問を解くまでの勉強に使った参考書はこちらです

この問題は平成26春のアセンブラの問題に似ています。
また、自作の2進数の乗算プログラムもあります。

この記事は、この記事は基本情報技術者試験の選択言語でアセンブラ言語を選んだ方と、似顔絵に興味のある方でしたら、ちょっとした暇つぶしになるのかもしれません。え、暇なんて無い???そんなぁ、ちょっとだけ見て行ってよ( ;∀;)(途中途中に、似顔絵が登場します。)

平成30年春のアセンブラの問題は、これもアセンブラ色が強いと思いました。
数字列を数値に変換して、管理テーブルと呼ばれるテーブルに格納して、それをかけ算するといった処理を行います。かけ算の仕方は頻出だと思うので(特に乗数の下一桁が0かどうかとか)真剣に書きたいと思います。

ではまず、数字列を数値に変換するプログラム1に入ります。
この具体例はそのまま使えると思います。

数字列「567」を数値にするとは、文字コード「0035」を数値の5である「0005」に変換して、数値なので演算をして100倍、文字コード「0036」を数値の6に変換して10倍、文字コード「0037」を数値の7に変換して合計して数値の「567」にします。

この時、10倍のやり方について少し見てみます。
例えば5を10倍すると50になりますが、まず5を2倍した10と、その10をどっかに退避して、退避した分を2倍すると20、更に2倍すると40(元の数5の8倍)となり、
それを元の数を2倍した10の所にこの40を足すと50になります。

この、まず2倍にして、2倍にした数を退避して、
退避した数を4倍すると元の数の8倍になり、元の数の2倍と足しこんで結果10倍にするというやり方も、
アセンブラ色が強い、かなり有力なパターンなのではと思いました。

プログラム1を呼び出すメインプログラムに、数字列の入った領域の先頭のアドレスを指定します。数字列の入った領域の名前は「SUUJI」とします。GR1が「SUUJI+0」を指します。「SUUJI+0」に数字5の文字コード0035、「SUUJI+1」に数字6の文字コード0036、「SUUJI+2」に数字7の文字コードが入っています。
また、文字数はこの具体例の倍は3文字なので、3をGR2に読み込みます。
戻り値である567はGR0に読み込んでメインプログラムに戻ります。

ここまでの内容をノートにまとめました。

実際に数字列「567」を数値「567」に変換するプログラムを過去問を参考にして作ってシミュレーターで動かしてみます。

主記憶に数字列「567」が入りました。数字列SUUJIの「5」が入っている所の先頭アドレスは「SUUJI+0」です。うちの環境では101Cになっています。

GR1にSUUJIの先頭アドレスが入って、GR2に文字数が入りました。

GR2にSUUJIのアドレスに文字数の3が加算され、「SUUJI+3」になりました。

数字列を数値に変換した数(戻り値)を格納するGR0を初期化しました。

GR1の「SUUJI+0」はGR2の「SUUJI+3」よりも小さいので、SFが1になりましたので、まだ変換処理が終わっていないです。

GR4に数字列の「5」が読み込まれました。

数値の「5」に変換されました。
GR0の0が10倍されます。ここは値が変わらないので、このループでは略して、
次からトレースします。

戻り値に使うレジスタGR0に数値の「5」が格納されました。

GR1のアドレスが「SUUJI+1」になりました。
ループに戻ります。

GR1は「SUUJI+1」とGR2の「SUUJI+3」よりも小さいのでSFが1です。
まだ処理をします。

GR4に数字列の「6」が読み込まれました。

GR4の所が数値の「6」になりました。

GR0の所で、さっき処理した「5」が2倍され「10」(A)になりました。

10がGR5に退避されました。

10が4倍されて40になりました。(28は2×16+8)

5の2倍と5の8倍が足されて50になりました。
(32は3×16+2)

今数値に変換された6が足されました。

GR1が指している先が「SUUJI+2」になりました。

GR1の「SUUJI+2」はGR2の「SUUJI+3」より小さいのでSFが1になり処理中です。

GR4に数字列の「7」が読み込まれました。

数値の「7」に変換されました。

GR0が2倍されました。

2倍された数が退避されました。

2倍された数が4倍され、8倍になりました。

2倍された数に8倍された数が足されて10倍になりました。

ここに今数値に変換された7が足しこまれました。
これで567になったのですが、表示を10進数に切り替えて見てみます。

10進数表示で567になりました。
GR1のアドレスが「SUUJI+3」になり、ループに戻ります。
(表示を16進数に戻しました。)


GR1もGR2も「SUUJI+3」になったので、ZFが1になりました。

終了しました。
お疲れ様です。

主プログラムとプログラム1のプログラミングとノートを掲載します。

;平成30春 数字列を数値に変換して管理テーブルに格納してかけ算するプログラム
;メインプログラム
MAIN START
RPUSH
LAD GR1,SUUJI
LD GR2,=3
CALL DTOB
RPOP
RET
SUUJI DC ‘567’


;プログラム1
DTOB RPUSH
ADDL GR2,GR1 ;アドレスを文字数分だけ進めて終了条件の判定に使う
LAD GR0,0 ;戻り値の初期化
LPDT CPL GR1,GR2 ;変換終了?
JZE FINDT
LD GR4,0,GR1 ;数字1文字の取り出し
SUBL GR4,=’0′ ;1桁を数値に変換
SLL GR0,1 ;GR0を10倍してGR4を加算。まずここで2倍
LD GR5,GR0 ;2倍した数を退避
SLL GR5,2 ;空欄「a」退避した数を4倍(元の数の8倍)
ADDL GR0,GR5 ;8倍した結果を2倍した数に足しこむ
ADDL GR0,GR4 ;読み込んだ数値を足す
LAD GR1,1,GR1 ;次の数値を読み込むので1つ進める
JUMP LPDT ;ループへ
FINDT RPOP
RET
END

プログラム2のGETWDでは、さっきのDTOBを使って数字列を数値に変換したらそれを管理テーブルと呼ばれる保存領域に格納します。管理テーブルの領域を「KANRI+0」にします。

まんまじゃん。

JAROのマギラワシ編

GETWDでは、SUUJIの数字列の具体例は問題より一部簡略化して(オーバーフローを防ぐため)数字列SUUJI「△△1234△567△△△9876△.」をプログラム1のDTOBを使って数値に変換して、その際に空白文字△で区切って数値に変換します。
管理テーブルKANRIのKANRI+0、KANRI+1、KANRI+2‥‥と格納していきます。
KANRIの大きさは仮に4、つまりKANRI+3までとします。

さっきと同じようにGR1でSUUJI+0を、GR2でKANRI+0を指して、DTOBを呼ぶのに文字数を求める必要があるので、計算の為にGR1、GR2のアドレスをGR6、GR7に退避してアドレスの差から文字数を求めます。
それが求まったらDTOBを呼びます。数値に変換した後にGETWDに戻ります。
KANRIのアドレスを1つ先に進めて、変換及び格納処理に戻ります。
最後に「.」の時に「-1」を格納して終了の目印にします。

ここまでの流れをノートにまとめました。

このプログラム2の名前、GETWDで、TM NETWORKさんの『Get Wild』のサビが浮かんできました。
同じような人いるかな??

では、プログラミングしてトレースします。

数字列SUUJI「△△1234△567△△△9876△.」が主記憶に読まれました。
先頭のアドレス「SUUJI+0」はうちの環境では101Cになっています。

管理テーブルKANRIの領域が確保されました。
先頭アドレス「KANRI+0」はうちの環境では102Fになります。

SUUJI+0とKANRI+0をセットしてGETWDを呼びます。

SUUJI+0をGR6、KANRI+0をGR7に退避しました。

処理状態のフラグが初期化されました。

位置調整の為にSUUJI-1になりました。

SUUJI+0になりました。
0番目の数字の処理になるのでインデックスと一致します。

GR4にSUUJI+0番目の「△」が読まれました。
何もせずに次に行きます。
次のSUUJI+1も「△」なので何もせずに次に行きます。

SUUJI+2は「1」です。

処理中フラグが0になりました。

GR1にSUUJI+2が退避されました。

GR4にSUUJI+3の数字列2が読まれました。

GR4にSUUJI+4の数字列3が読まれました。

GR4にSUUJI+5の数字列4が読まれました。

GR4にSUUJI+6の数字列△が読まれました。
空白なので格納処理に移ります。

GR2にSUUJI+6が格納されました。

GR2にアドレスの差から「SUUJI+6」-「SUUJI+2」で4文字と求められました。
これでGR1に「1234」の先頭の「SUUJI+2」、GR2に文字数の「4」が入ったので、プログラム1のDTOBを呼ぶ設定が完了しました。
DTOBを呼びました。数字列「1234」を数値の「1234」に変換します。
処理はプログラム1と同じなので省略して、GETWDに戻った所からトレースします。

10進数に直すと1234にあたる04D2がGR0に格納されました。

主記憶の管理テーブルのKANRI+0に格納されました。

数字列の処理中フラグが解除されました。

あと同様に「△△1234△567△△△9876△.」の567~進めて、
最後の「.」で終了処理の「-1」を格納します。
結果のみを表示します。

このようになりました。
表示は10進数表示にしました。

終了しました。お疲れ様です。
では、プログラムとノートです。

まいう~~~

プログラム1は同じなので画像は省略します。

;平成30春 数字列を数値に変換して管理テーブルに格納してかけ算するプログラム
;メインプログラム
MAIN START
RPUSH
LAD GR1,SUUJI ;数字列の先頭アドレス
LAD GR2,KANRI ;管理テーブルの先頭アドレス
CALL GETWD
RPOP
RET
SUUJI DC ‘ 1234 567 9876 .’ ;数字列
KANRI DS 4 ;管理テーブル


;プログラム2
GETWD
RPUSH
LD GR6,GR1 ;数字列の先頭アドレスを退避
LD GR7,GR2 ;管理テーブルの先頭アドレスを退避
LD GR3,=-1 ;数字列の処理状態フラグの初期化
LAD GR6,-1,GR6 ;ループ前の数字列を指す位置調整
LPGE LAD GR6,1,GR6 ;処理中の数字列の位置
LD GR4,0,GR6 ;1文字取り出し
CPL GR4,=’.’ ;ピリオドですか?
JZE FINGE
CPL GR4,=’ ‘ ;空白ですか?
JNZ NUM ;空欄「b」処理中のフラグのチェック
CALL SETWD ;管理テーブルに格納する処理
JUMP LPGE
NUM LD GR3,GR3 ;数字列の処理中?
JZE LPGE
LD GR3,=0 ;数字列の処理中フラグの設定
LD GR1,GR6 ;数字列の先頭アドレスを退避
JUMP LPGE
FINGE CALL SETWD
LD GR2,=-1 ;終了の目印
ST GR2,0,GR7 ;↑数値の終わりを示す印を格納
RPOP
RET
SETWD LD GR3,GR3 ;0(=処理中)ですか?
JNZ FIN2 ;空欄「c」違ったら何もせずに戻る
LD GR2,GR6 ;処理をしていた位置を読み込む
SUBL GR2,GR1 ;位置の差から文字数を求める
CALL DTOB ;数字列を数値に変換
ST GR0,0,GR7 ;数値を管理テーブルに格納する
LD GR3,=-1 ;数字列の処理中状態を解除
LAD GR7,1,GR7 ;空欄「d」管理テーブルを1つ先に進める
FIN2 RET

;プログラム1
DTOB RPUSH
ADDL GR2,GR1 ;アドレスを文字数分だけ進めて終了条件の判定に使う
LAD GR0,0 ;戻り値の初期化
LPDT CPL GR1,GR2 ;変換終了?
JZE FINDT
LD GR4,0,GR1 ;数字1文字の取り出し
SUBL GR4,=’0′ ;1桁を数値に変換
SLL GR0,1 ;GR0を10倍してGR4を加算。まずここで2倍
LD GR5,GR0 ;2倍した数を退避
SLL GR5,2 ;空欄「a」退避した数を4倍(元の数の8倍)
ADDL GR0,GR5 ;8倍した結果を2倍した数に足しこむ
ADDL GR0,GR4 ;読み込んだ数値を足す
LAD GR1,1,GR1 ;次の数値を読み込むので1つ進める
JUMP LPDT ;ループへ
FINDT RPOP
RET
END

プログラム3MULTは掛け算をします。具体例として、数字列「2△3.」からプログラム1のDTOBを使って数字列から数字に「2」と変換して、GETWDを使って管理テーブルCTBL+0に格納して次に「3」も同様にしてCTBL+1に格納します。それをMUTに戻ってかけ算をします。

では、数字列「2△3.」を数値「2」と「3」変換する所までのトレースはプログラム1と2と同じなので省略して、メインのかけ算プログラムのトレースを重点的に行います。

ここまでの流れをノートにまとめました。

管理テーブルに数値に変換して格納されました。
ここからはレジスタを2進数表示にしてトレースします。

GR4に被乗数の「…0010」、GR5に乗数の「…0011」が入りました。

GR0が初期化されました。

乗数は0では無いのでZFは0です。

最下位ビットを調べるので退避しました。

0001と論理積を取って最下位ビットを調べました。
0??  ち、が、う、だ、ろ!!

なので、加算処理を行います。

「2」が入りました。

被乗数が「2」が左に1ビット論理シフトして「4」になりました。

乗数「3」が右に1ビット論理シフトして「1」になりました。

乗数1は最下位ビットが「1」なので、加算処理を行います。

GR4の「4」がGR0の「2」と加算されて「6」になりました。

GR4が1ビット左に論理シフトされて2倍されました。

GR5が1ビット右に論理シフトされて「0」になりました。
計算は終了して呼び出し元のメインプログラムに戻ります。

プログラムが終了しました。

お疲れ様でした。

プログラム3とノートです。

画像はプログラム1、2は共通なので省略します。

;平成30春 数字列を数値に変換して管理テーブルに格納してかけ算するプログラム
;メインプログラム


MAIN START
RPUSH
LAD GR1,SUUJI ;数字列の先頭アドレス
CALL MULT
RPOP
RET
SUUJI DC ‘2 3.’ ;数字列


;プログラム3
MULT
RPUSH
LAD GR2,CTBL ;管理テーブルの先頭アドレスを読み込む
CALL GETWD ;数値を管理テーブルに格納する処理
LD GR4,0,GR2 ;GR4←被乗数
LD GR5,1,GR2 ;GR5←乗数
LD GR0,=0 ;計算結果を初期化
LD GR5,GR5 ;乗数はゼロか?
LPMU JZE FINMU ;空欄「e」
LD GR3,GR5 ;乗数を退避
AND GR3,=#0001 ;乗数の最下位ビットのチェック
JZE NEXTMU ;↑ゼロだったら加算処理をスキップ
ADDL GR0,GR4 ;被乗数を結果に加算
NEXTMU SLL GR4,1 ;被乗数を1ビット左論理シフト
SRL GR5,1 ;空欄「f」乗数を1ビット右論理シフト
JUMP LPMU
FINMU RPOP
RET
CTBL DS 3 ;GETWD用管理テーブル

;プログラム2
GETWD
RPUSH
LD GR6,GR1 ;数字列の先頭アドレスを退避
LD GR7,GR2 ;管理テーブルの先頭アドレスを退避
LD GR3,=-1 ;数字列の処理状態フラグの初期化
LAD GR6,-1,GR6 ;ループ前の数字列を指す位置調整
LPGE LAD GR6,1,GR6 ;処理中の数字列の位置
LD GR4,0,GR6 ;1文字取り出し
CPL GR4,=’.’ ;ピリオドですか?
JZE FINGE
CPL GR4,=’ ‘ ;空白ですか?
JNZ NUM ;空欄「b」処理中のフラグのチェック
CALL SETWD ;管理テーブルに格納する処理
JUMP LPGE
NUM LD GR3,GR3 ;数字列の処理中?
JZE LPGE
LD GR3,=0 ;数字列の処理中フラグの設定
LD GR1,GR6 ;数字列の先頭アドレスを退避
JUMP LPGE
FINGE CALL SETWD
LD GR2,=-1 ;終了の目印
ST GR2,0,GR7 ;↑数値の終わりを示す印を格納
RPOP
RET
SETWD LD GR3,GR3 ;0(=処理中)ですか?
JNZ FIN2 ;空欄「c」違ったら何もせずに戻る
LD GR2,GR6 ;処理をしていた位置を読み込む
SUBL GR2,GR1 ;位置の差から文字数を求める
CALL DTOB ;数字列を数値に変換
ST GR0,0,GR7 ;数値を管理テーブルに格納する
LD GR3,=-1 ;数字列の処理中状態を解除
LAD GR7,1,GR7 ;空欄「d」管理テーブルを1つ先に進める
FIN2 RET

;プログラム1
DTOB RPUSH
ADDL GR2,GR1 ;アドレスを文字数分だけ進めて終了条件の判定に使う
LAD GR0,0 ;戻り値の初期化
LPDT CPL GR1,GR2 ;変換終了?
JZE FINDT
LD GR4,0,GR1 ;数字1文字の取り出し
SUBL GR4,=’0′ ;1桁を数値に変換
SLL GR0,1 ;GR0を10倍してGR4を加算。まずここで2倍
LD GR5,GR0 ;2倍した数を退避
SLL GR5,2 ;空欄「a」退避した数を4倍(元の数の8倍)
ADDL GR0,GR5 ;8倍した結果を2倍した数に足しこむ
ADDL GR0,GR4 ;読み込んだ数値を足す
LAD GR1,1,GR1 ;次の数値を読み込むので1つ進める
JUMP LPDT ;ループへ
FINDT RPOP
RET
END

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
以前書き貯めて置いた(トレース中の落書き…)似顔絵イラストを入れて、遊び心を取り入れたりしたので、ウケなかったり、誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)
要領悪すぎにゃ~~~~~~( ;∀;)(=^・^=)( ;∀;) (^O^)/

シミュレーターと過去問を解くまでの勉強に使った参考書はこちらです

この問題は平成26春のアセンブラの問題に似ています。
また、自作の2進数の乗算プログラムもあります。

アセンブラ過去問プログラミング
アセンブラ自作サンプルへ
基本情報技術者試験トップへ
息抜きに、写真で癒し(=^・^=)

投稿者: nekosiestr

プログラミング学習中の発達障害者です。宜しくお願いします。 趣味で写真を撮っています。 プログラミングは、GAS/HTML/CSS/JavaScript/jQuery/PHP、 発達障害は、自閉症スペクトラムASD/ADHD、 写真は、以前はコンパクトデジカメ、現在は、OLYMPUSミラーレス一眼を使っています。