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

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

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

シミュレーターと過去問を解くまでの勉強に使った参考書はこちらです
バブルソートの自作サンプルプログラム

この問題のブログ記事を書く前に久々にサザエさんを見たら、ほっこり出来た上に、最後のじゃんけん、勝ちました!!(どやっ(=^・^=)!!)という訳で、ノリノリで過去問のプログラミングとトレース行きます!!
今回はバブルソートの問題です。


主プログラムで配列ARRAYの先頭アドレス(ARRAY+0)をGR1に設定して、
ソートする数をGR2に設定します。ソート前、後でOUT命令で出力する様にしたので、文字数4をOLEN(OUT LENの略)でGR2に読み込ませるようにしました。
具体例は設問2の例を使います。
設定が終わったら、プログラミング1のSORTを呼び出します。
トレースしながら設問1、2同時に答えられるのでやって行きます。

配列ARRAYに「2、4、1、3」が格納され、それを「1、2、3、4」に並び変えながら設問に回答します。
普通のバブルソートはおケツからソートしますが、この問題では頭からソートしていきます。「2、4」の大小関係は小さい方が前だからそのまま交換無し、交換が無い時に「空欄a」で分岐して交換処理を飛ばし、
次に「4、1」の大小関係の比較…とと続いて行きます。
それではプログラミングをして、実際にシミュレーターで動かしながらトレースをやって行きます。

ARRAYの先頭アドレスARRAY+0(我が家の環境でのアドレス値)と、バブルソートを行う数値の数の4が入りました。
プログラム1が呼び出されました。

GR2の外ループカウンタが1つ減って4から3になりました。

外ループ、並び替えのターンの区切り線を見やすいように出力しました。

内ループカウンタがGR3に入りました。

GR4に、ARRAYの先頭アドレスARRAY+0の我が家の環境でのアドレスが退避されました。

ARRAY「2、4、1、3」の「2」がGR5に退避されました。

CPLで「2」と「4」が比べられて、2の方が小さいのでSFに1が入りました。・・・・7行目の1回目

並び替えの必要が無いので、空欄aの分岐により並び替えの処理を飛ばしてCONTに分岐しました。
GR3の内ループのカウンタが1つ減って、GR4のアドレスがARRAY+1になりました。

内ループ1回目を終えた状態が入りました。

ループ2へ戻って次の比較をします。
「2、4、1、3」の「4」がGR5に退避されました。

CPLで「4」と「1」が比べられて、4の方が大きいのでSFに0が入りました。・・・・7行目の2回目
その為2つの要素の入れ替えは飛ばさずに入れ替え処理を行います。

「1」がGR6に退避されました。

「4」が1つ後ろに格納されました。
「1」が1つ前に格納して交換が終わりました。・・・・11行目の1回目
GR3の内ループカウンタが1つ減って、GR4のアドレスがARRAY+2になりました。

現在の配列の様子が2行目に出力されました。
「2、1、4、3」になっています。

ループ2へ戻って次の比較をします。
「2、1、4、3」の「4」がGR5に退避されました。

CPLで「4」と「3」が比べられて、4の方が大きいのでSFに0が入りました。・・・・7行目の3回目
その為2つの要素の入れ替えは飛ばさずに入れ替え処理を行います。

「3」がGR6に退避されました。

「4」が1つ後ろに格納されました。
「3」が1つ前に格納して交換が終わりました。・・・・11行目の2回目
GR3の内ループカウンタが1つ減って0になり、GR4のアドレスがARRAY+3になりました。

現在の配列の様子が2行目に出力されました。
「2、1、3、4」になっています。

GR3の内ループのカウンタが0になったので、次のターンに行きます。
GR2の外ループカウンタが1つ減りました。

ループ1へ戻って次のターン用に区切り線を引きました。

外ループカウンタの2がうちループカウンタに入りました。

GR4に配列の先頭アドレスARRAY+0が入りました。

「2、1、3、4」の「2」がGR5に退避されました。

CPLで「2」と「1」が比べられて、2の方が大きいのでSFに0が入りました。・・・・7行目の4回目
その為2つの要素の入れ替えは飛ばさずに入れ替え処理を行います。

GR6に「1」が退避されました。

「2」が後ろに行って、退避した「1」が前に格納されました。・・・・11行目の3回目、設問2空欄「d」は3回でした。
GR4のアドレスが1つ後ろのARRAY+1、GR3の内ループカウンタが1つ減りました。

現在の配列の状態が出力されました。
「1、2、3、4」

ループ2に戻りました。
CPLで「2」と「3」が比べられて、2の方が小さいのでSFに1が入りました。・・・・7行目の5回目

並べ替えは行わずにCONTへ分岐して、GR4のアドレスがARRAY+2になって、内ループのカウンタが1つ減りました。

出力結果は変わらず「1、2、3、4」です。

内ループが0になったので、外ループが1つ減りました。

次のターンへ処理するのでループ1へ分岐します。
区切り線が引かれました。

GR2の外ループのカウンタがGR3の内ループのカウンタに入りました。

GR4に先頭アドレスARRAY+0が入りました。

「1、2、3、4」の「1」がGR5に退避され比較します。・・・・7行目の6回目
設問2空欄「c」は6回でした。

並び替えは行わないのでCONTに分岐します。
GR4のアドレスがARRAY+1になってGR3の内ループカウンタが0になりました。

出力結果です。

内、外ループカウンタ、共に0になりました。

プログラム1が終わりました。

;平成26年秋バブルソート
;主プログラム
MAIN START
RPUSH
LAD GR1,ARRAY ;GR1に配列ARRAYの先頭アドレスを設定する
LD GR2,OLEN ;GR2に並び替える数4を読み込む
CALL SORT ;プログラム1SORTを呼ぶ
RPOP
RET
ARRAY DC ‘2413’
OLEN DC 4
BUF DS 256
;プログラム1SORT
SORT RPUSH
SUBA GR2,=1 ;ループのカウンタ1を設定(外ループ)
LOOP1 OUT LINE,LLEN ;ターンの区切り線
LD GR3,GR2 ;ループのカウンタ2を設定(内ループ)
LD GR4,GR1 ;GR4←比較する要素のアドレス
LOOP2 LD GR5,0,GR4 ;現在のアドレス内の数を取り出す
CPL GR5,1,GR4 ;↑と次の要素を比較‥‥設問2「c」
JMI CONT ;空欄「a」交換が発生しない場合に分岐
LD GR6,1,GR4 ;2つの要素を入れ替え。後ろの要素をGR6に退避
ST GR5,1,GR4 ;現在の要素を後ろへ格納
ST GR6,0,GR4 ;退避した要素を前に格納
CONT ADDA GR4,=1 ;比較する位置を後ろに移動
SUBA GR3,=1 ;内ループカウンタを減らす
OUT ARRAY,OLEN ;途中の並び替えを出力
JPL LOOP2 ;次の比較へ
SUBA GR2,=1 ;外ループを減らして次のターンへ
JPL LOOP1 ;空欄「b」残っている場合はLOOP1へ
RPOP
RET
LINE DC ‘———-‘
LLEN DC 10
END

では、設問3へ行きます。
具体例では、入力ウィンドウでBUFに4桁の5つの数値を出力してそれを数字列から数値にして並び替えて出力します。
1つ目の数字列は「298」「3(文字数)」と入力します。
これを2進化10進数、「298」でしたら「0298」なので、
0…「0000」
2…「0010」
9…「1001」
8…「1000」
と変換して、ARRAY+0に格納します。
次は「30」「2(文字数)」を入力して同じように変換してARRAY+1に格納…というのを5つ目の数字をARRAY+4に格納する
所まで行います。

GR1にARRAY+0を読み込んでプログラム1のSORTを呼び出します。

並び替え終わったら、一番小さい数字を数字列(文字)に変換して出力します。
変換の仕方は000Fと論理積を取り、文字コードを+30して文字にして、それをBUFに格納します。
4桁終わったら次の数字列に行きます。

数字列の入力で、-1が入ったら入力処理を終えるようにします。

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

プログラム2を作りましたので動かして見ます。

まだ数字を1つも入力していないので、GR2に0が入ります。

まず、最初の数値「298」を入力します。

Enterを押して入力を終えます。

「298」は3桁なのでGR0に桁数の3が入りました。

配列に格納される内容が初期化されました。
あとで数字列から数値に変換する時に使います。

GR4にBUFのアドレスが入りました。
数値化の変換する位置の指定に使います。

「298」の「2」がGR5に読み込まれました。

「2」が数値に変換されました。

次の桁用に左シフトされました。
GR3は0なので値は変わりません。

2進化10進数に変換する為にGR5の0002がGR3に加算されました。

「298」の「9」を読むために進めました。

GROの処理待ち桁が1つ減りました。

ループ4に戻ります。

以下、「9」、「8」が読み込まれる処理を行います。
9が数値化され、格納される前に、GR3が4ビット右へシフトされました。
このシミュレーターは16進数表示にしてあるので、2進数の4桁で16進数の1桁が左に1つ移動したことになります。
0002から0020に移動して右端が0になりました。

0になった所に「9」が入って0029になりました。

「298」の「8」が読み込まれて数値化されました。
0029から0290に左にシフトされました。

290の空いた0の所に「8」が入って0298になりました。

数値変換処理が終わって、配列ARRAY+0に格納されました。

以上の処理が終わったので、処理済みの数字列の数が1つ加算されました。

同様に、「30」、「9」、「3240」、「508」を処理します。
(略)

何も入力せずEnterで5つの数字列を入力する処理を追えました。
以降、ソート処理になります。

CALLでプロうグラム1のソートを呼び出して、5つの数字列をバブルソートします。
プログラム1の所は省略します。
(略)
「9」、「30」、「298」、「508」、「3240」に並び替えらえれました。

主プログラムに戻りました。
バブルソートによる並べ替えが終わって出力処理に入ります。
GR4に空白文字が読み込まれました。

最も小さい「9」から数字列に変換します。
GR3に入りました。

下一桁が取り出され、(空欄e)数字列に変換されました。

この「9」がバッファ4桁のうちの1番右BUF+3に入りました。

0009が右にシフトされ、0000になりました。
(空欄f)
なので4桁分3桁空いてしまったので(0009だから、「△△△9」にする。△は空白。)ループ7で3つ分の△を埋める空白処理を行います。

空白を埋める処理が終わって、一番小さい数が出力されました。

以下、同様の処理をするので、ステップ実行から一括実行に切り替えて一気に表示します。

昇順に表示されました。

これで終わりましたので、プログラム2とノートを掲載します。

;平成26年秋バブルソート
;プログラム2主プログラム
MAIN START
RPUSH
LD GR2,=0 ;数字列のカウンタを初期化
LOOP3 IN BUF,ILEN ;数字列の長さ
LD GR0,ILEN ;GR0に長さを読み込んで配列格納の位置に使用する
JZE EOF ;何も入れなかったら入力処理を終える
LD GR3,=0 ;配列に格納する内容を初期化
LAD GR4,BUF ;GR4に入力に使用した領域BUFの先頭アドレスを入れる
LOOP4 LD GR5,0,GR4 ;GR5←数字
AND GR5,=#000F ;数字の数値化
SLL GR3,4 ;処理済の内容を桁上げ
OR GR3,GR5 ;空いた右端4ビットに数値を格納
ADDA GR4,=1 ;アドレスを1つ先へ
SUBA GR0,=1 ;格納する桁を1つ前へ
JNZ LOOP4 ;桁分の処理がある場合はLOOP4へ
ST GR3,ARRAY,GR2 ;ソート用に格納
ADDA GR2,=1 ;ソート用に格納する位置を1つ進める
JUMP LOOP3
EOF LAD GR1,ARRAY ;マイナスが入力されたらソートへ
CALL SORT
LD GR4,=’ ‘ ;空白文字を設定(4桁に満たない場合)
LOOP5 LD GR0,0,GR1 ;出力用に読み込む
LD GR5,=3 ;ループのカウンタを設定
LOOP6 LD GR3,GR0 ;数字に変換するために退避
AND GR3,=#000F ;「空欄e」下一桁を取り出す
OR GR3,=#0030 ;数値の数字化
ST GR3,BUF,GR5 ;バッファに数字を設定
SUBA GR5,=1 ;バッファ格納位置を1つ前へ移動
JMI WRITE ;格納が終わったら出力へ
SRL GR0,4 ;「空欄f」上の桁の数字化用に右シフト
JNZ LOOP6
LOOP7 ST GR4,BUF,GR5 ;バッファに空白を設定
SUBA GR5,=1
JMI WRITE
JUMP LOOP7
WRITE OUT BUF,OLEN ;4桁出力
LAD GR1,1,GR1 ;次の数値の数字化と出力処理へ
SUBA GR2,=1 ;処理待ち分を減らす
JNZ LOOP5
RPOP
RET
BUF DS 256 ;入出力領域
ILEN DS 1 ;入力桁数
OLEN DC 4 ;4文字出力
ARRAY DS 100 ;バブルソート用
;プログラム1SORT
SORT RPUSH
SUBA GR2,=1 ;ループのカウンタ1を設定(外ループ)
LOOP1
LD GR3,GR2 ;ループのカウンタ2を設定(内ループ)
LD GR4,GR1 ;GR4←比較する要素のアドレス
LOOP2 LD GR5,0,GR4 ;現在のアドレス内の数を取り出す
CPL GR5,1,GR4 ;↑と次の要素を比較‥‥設問2「c」
JMI CONT ;空欄「a」交換が発生しない場合に分岐
LD GR6,1,GR4 ;2つの要素を入れ替え。後ろの要素をGR6に退避
ST GR5,1,GR4 ;現在の要素を後ろへ格納
ST GR6,0,GR4 ;退避した要素を前に格納
CONT ADDA GR4,=1 ;比較する位置を後ろに移動
SUBA GR3,=1 ;内ループカウンタを減らす
JPL LOOP2 ;次の比較へ
SUBA GR2,=1 ;外ループを減らして次のターンへ
JPL LOOP1 ;空欄「b」残っている場合はLOOP1へ
RPOP
RET
END

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
頑張って書いたので、誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)
要領悪すぎにゃ~~~~~~( ;∀;)(=^・^=)( ;∀;) (^O^)/

シミュレーターと過去問を解くまでの勉強に使った参考書はこちらです
バブルソートの自作サンプルプログラム

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

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

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

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

シミュレーターと過去問を解くまでの勉強に使った参考書はこちらです
この問題は平成30年春のアセンブラの問題と似ています。

文字列の中から単語を切り出して、「その文字列の先頭アドレス、文字数、全部数字か英文字も含まれているかの種別」を単語管理テーブルに収めるプログラムです。

文字列の領域をMOJI、先頭アドレスをMOJI+0として、この問題の環境ではMOJI+0が100番地になるようです。
種別は全部数字の時は0、英字を含む時は1です。

単語管理テーブル領域はKANRI、先頭アドレスをKANRI+0とします。
問題文のプログラム1、GETTKNは主プログラムはGR1にMOJI+0、GR2にKANRI+0を設定してから呼びます。

トレースは、時間短縮の為、設問1、設問2が一気に解けるように、設問2の具体例を使います。スペースを△と表すので、「△1A2B△C3.」をMOJI領域に入れて、KANRIは「101,4,1,106,2,1,-1」となります。
最初の文字列「1A2B」は101番地から始まって4文字、英字を含むから種別が1で「101,4,1」次の文字列「C3」は106番地から始まって2文字で英字を含むから種別が1で「106,2,1」、最後が終端マークで「-1」が入ります。

では、主プログラムとプログラム1のGETTKNをプログラミングしてトレースをします。単語管理テーブルKANRIは、とりあえず10個ぐらいの領域を用意します。

では、主プログラムとプログラム1のプログラミングが終わりましたので、シミュレーターを動かしながらトレースをして設問1、2を解きます。
文字列の領域MOJIに、「△1A2B△C3.」が入りました。文字コードが入っています。この問題のアドレス100番地が、私のお家の環境ですと、MOJIの左を見ていくと「101C」に当たります。

次に、単語管理テーブルの領域を10個用意しました。

GR1に100番地に当たるアドレス101Cが入りました。

GR2にKANRI+0番地が入りました。

GR3に種別の初期化の「-1」が入りました。

ループLPに入る前にアドレスが調整されました。
99番地に当たる101Bが入りました。

ループLPに入り、アドレスが+1され、100番地に当たる101Cが入りました。

GR4に文字列「△1A2B△C3.」から、最初の「△」が取り出されました。

文字コード0020

GR3が0かどうかみます。
-1なので何もしないです。

文字列のアドレスが1つ先に進み、101番地にあたる101Dを指しました。

GR4に文字列「△1A2B△C3.」から「1」が取り出されました。

文字コード0031

文字列の取り出し処理が開始になるので、GR3に0が読み込まれました。
種別が0で数字だけからなるになりました。

処理開始の文字列のアドレス101番(101D)がGR6に退避されました。
これは後でアドレスの差から文字数を求めるのに使います。

文字列のアドレスが1つ先に進み、102番地にあたる101Eを指しました。

GR4に文字列「△1A2B△C3.」から「A」が取り出されました。

文字コード0041

英文字を含むのでGR3に1が設定されました。

文字列のアドレスが1つ先に進み、103番地にあたる101Fを指しました。

GR4に文字列「△1A2B△C3.」から「2」が取り出されました。

文字コード0032

文字列のアドレスが1つ先に進み、104番地にあたる1020を指しました。

GR4に文字列「△1A2B△C3.」から「B」が取り出されました。

文字コード0042

文字列のアドレスが1つ先に進み、105番地にあたる1021を指しました。

GR4に文字列「△1A2B△C3.」から2つ目の「△」が取り出されました。

文字コード0020

△なので、格納処理に進みます。
文字列「△1A2B△C3.」の先頭の「1」、101番地に当たる101Dが管理テーブルの先頭に格納されました。

現在の文字列を指すアドレス105番に当たる1021がGR5に退避されました。

105番地から(1021)101番地(101D)を引いた4が文字数としてGR5に求まりました。

文字数の4と、英数字混合の文字種1が単語管理テーブルに格納されました。

次の文字切り出し用にGR3を-1で初期化しました。

単語管理テーブルのアドレスが3つ進んで、次の単語切り出し用の準備になりました。

文字列のアドレスが1つ先に進み、106番地にあたる1022を指しました。

GR4に文字列「△1A2B△C3.」から2つ目の「C」が取り出されました。

文字コード0043・・・設問2

フラグが-1から0になりました。
処理中として、暫定的に全て数字を表す0が入りました。

GR6に今指しているアドレス、106番地に当たる1022が入りました。

「C」は9より大きいので英文字が含まれるため、GR3のフラグが1になりました。

文字列のアドレスが1つ先に進み、107番地にある1023を指しました。

GR4に文字列「△1A2B△C3.」から2つ目の「3」が取り出されました。

文字コード0033

文字列のアドレスが1つ先に進み、108番地にある1024を指しました。

GR4に文字列「△1A2B△C3.」から2つ目の「.」が取り出されました。

文字コード002E

「.」なので終了処理に入ります。

単語管理テーブルに文字列「C3」の先頭のアドレスが入りました。

GR5に文字列の現在指しているアドレス108番地に当たる1024が入りました。

アドレス108番地に当たる1024から、アドレス106番地に当たる1022を引いて2が文字数として求まりました。

「C3」のアドレス、文字数、種別が入りました。

終端マークの-1が入りました。

以上でプログラム1、設問1、2のトレースを終わります。

プログラミングのコードとトレースに使ったノートの写真です。

;平成26春主プログラムとプログラム1
;設問1、2
;主プログラム
MAIN START
RPUSH
LAD GR1,MOJI ;設問2の具体例の文字列を用意
LAD GR2,KANRI ;単語管理テーブルの領域をとりあえず10個確保
CALL GETTKN ;プログラム1を呼ぶ
RPOP
RET
MOJI DC ‘ 1A2B C3.’ ;文字列
KANRI DS 10 ;単語管理テーブル
;プログラム1
GETTKN
RPUSH
LD GR3,=-1 ;単語種別の初期化
LAD GR1,-1,GR1 ;文字列の位置調整
LP LAD GR1,1,GR1 ;MOJIの位置を順番に指す
LD GR4,0,GR1 ;1文字取り出す(↑で指した位置の中身を入れる)
CPL GR4,=’.’ ;比較
JZE FIN ;[.]なら終わり
CPL GR4,=’ ‘ ;比較
JNZ ALNUM ;[△]なら格納処理へ
CALL SETTKN ;単語管理テーブルへの格納処理へ
JUMP LP ;文字の取り出し処理へ「空欄a」
ALNUM LD GR3,GR3 ;0ですか?(単語の処理中?)
JPL LP ;処理中の単語が英字を含む場合はLPへ
JZE ACHK ;処理中の単語が数字だけからなる場合はACHKへ
LD GR3,=0 ;次の単語の処理開始
;単語種別を”数字だけからなる”に設定
LD GR6,GR1 ;先頭アドレスを退避(後で文字数の計算に使う)
ACHK CPL GR4,=’9′ ;9よりデカかったら文字決定!
JPL NEXT ;英字を含む処理へ
CPL GR4,=’0′ ;0より小さかったら文字決定!
JMI NEXT ;文字記号を含む処理へ
JUMP LP ;取り出した文字が数字の場合はLPへ
NEXT LD GR3,=1 ;単語種別を”英字を含む”に設定
JUMP LP
FIN CALL SETTKN ;単語管理テーブルへの格納処理へ
LD GR5,=-1
ST GR5,0,GR2 ;終端マークを格納
RPOP
RET
SETTKN LD GR3,GR3 ;0ですか?
JMI FIN2 ;単語処理中でなければ何もしない
ST GR6,0,GR2 ;単語の先頭アドレスを単語管理テーブルに格納
LD GR5,GR1 ;文字列の今のアドレスを入れる
SUBL GR5,GR6 ;今のアドレス-先頭アドレス=文字数が求まる「空欄b」
ST GR5,1,GR2 ;単語の長さを格納
ST GR3,2,GR2 ;単語の種別を格納
LD GR3,=-1 ;単語種別を初期化(処理中状態を解除)
LAD GR2,3,GR2 ;次の語のために単語管理テーブルを進める
FIN2 RET
END

設問3では具体例「12×3」を計算します。
文字列で表すとMOJIに「12△*△3△.」が入ります。
プログラム2のCALCでは、12と3はそれぞれGETTKNを使って数字列を切り出して、
その数字列を2進数の数値に変換して計算するので、DTOBという副プログラムを使って2進数にしてから計算します。
GETTKNを呼ぶ時、単語管理テーブルとして使う領域はCTBLという風呂敷を使って主記憶の場所取りをします。
単語管理テーブルのCTBLは「MOJI+0、2、0、MOJI+3、1、1、MOJI+5、1、0、-1」となります。「MOJI+0、2、0」で、「12×3」の「12」の先頭アドレスと文字数の2、数字だけなので文字種別が0、「MOJI+3、1、1」は、「12×3」の「×」の先頭アドレスと文字数の1、英数字含むので種別が1、「MOJI+5、1、0」は、「12×3」の「3」の先頭アドレスと文字数の1、数字だけの0、最後が終端マークの-1です。

計算するのに使うDTOBでは、数字列の12でしたら2進数で1100に、3でしたら、0011に変換します。×はで表します。演算子は「、+、ダミー、-」の順で領域LTBLに入っています。「MULT、PLUS、ダミー、MINUS」
この順番は文字コードを使って対応させています。
先頭である「*」は、アドレスLTBLの0番値目で0番地という位置は文字コードの差を使っています。*の文字コードは2Aで2A-2Aは0だから0番地、「+」は文字コード2Bで2B-2Aは1だから1番地、ダミーは2Cは、演算とは関係のない文字(,)で2C。2C-2Aは2だから2番地はダミー、「-」は文字コード2Dで2D-2Aは3だから3番地、とそれぞれ対応付けています。

参考 文字コード

設問3の流れをノートに書きました。

では、プログラム2を含めたプログラミングが終わったのでトレースをします。
実行すると主記憶のMOJIに「12△*△3△.」が入りました。

主プログラムでGR1に文字列アドレスMOJI+0が入ってCALCを呼び出します。

GR2に単語管理テーブルのアドレスCTBL+0が入ってGETTKNプログラム1のを呼び出します。「12」と「*」と「3」を切り出し、GR2で指す単語管理テーブルに切り出した単語それぞれの、「先頭アドレス、文字数、種別」が入ります。
CALCに戻って最初の文字「12」のGR2に入っている先頭アドレスをGR1に移して、
DTOBを呼びます。

数字列「12」を数値にして後ろから2×1、1×10を計算して足して数値12にします。
12を表すCが入ってCALCに戻りました。

演算子「*」の文字コードが読まれました。

文字コードから「」の2Aが引かれました。 この場合、なので2A-2Aで0が求まり、演算子テーブルの1番目のMULTを指すのに使います。

2番目の数字列を指す先頭アドレスがGR1に読み込まれて再びDTOBを呼びます。

「3」を数値に変換しました。

CALCに戻って、「12」がGR4、「3」がGR5に入りました。

MULTに分岐しました。
GR4×GR5で、「12×3」を求めます。


36(16進数表記で24)が求まりました。

プログラム2を含むコードと、トレースに使ったノートです。


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

;平成26春主プログラムとプログラム1、2
;設問3;主プログラム
MAIN START
RPUSH
LAD GR1,MOJI ;計算に使う数字列を含む文字列
CALL CALC ;プログラム2を呼ぶ
RPOP
RET
MOJI DC ’12 * 3 .’ ;文字列「12×3」を求める
;プログラム2
CALC
RPUSH
LAD GR2,CTBL ;管理テーブルの先頭アドレス
CALL GETTKN ;プログラム1を呼んで2つの数字列を切り出す
LD GR1,GR2 ;「空欄c」2進数変換につかうDTOBを呼ぶ準備
CALL DTOB ;数字文字列1を2進数に変換して
LD GR4,GR0 ;GR4に設定する。
LD GR1,3,GR2 ;演算子を取り出す
LD GR3,0,GR1 ;GR3←演算子の文字コード
SUBL GR3,=’*’ ;文字コードの差から分岐による演算処理を調べる
LAD GR1,6,GR2
CALL DTOB ;数字文字列2を2進数に変換して
LD GR5,GR0 ;GR5に設定する。
LD GR3,LTBL,GR3 ;「空欄d」どの演算をするのかLTBLの位置から求めて分岐
JUMP 0,GR3 ;演算して指定された処理にジャンプ
MULT LD GR0,=0 ;乗算MULTに分岐
LD GR5,GR5 ;乗数は0ですか?
LPM JZE FINC
LD GR3,GR5
AND GR3,=#0001 ;乗数の最下位ビットのチェック
JZE NEXTC
ADDL GR0,GR4 ;最下位ビットが0では無かったら加算
NEXTC SLL GR4,1 ;被乗数を1ビット左論理シフト
SRL GR5,1 ;乗数を1ビット右論理シフト
JUMP LPM
PLUS ADDL GR4,GR5 ;加算PLUSに分岐
LD GR0,GR4
JUMP FINC
MINUS SUBL GR4,GR5 ;減算MINUSに分岐
LD GR0,GR4
FINC RPOP
RET
CTBL DS 10 ;GETTKN用単語管理テーブル
LTBL DC MULT ;演算の分岐先アドレステーブル
DC PLUS
DS 1 ;ダミー
DC MINUS
;二進数変換プログラムDTOBでは1の桁(後ろから)から変換していく
DTOB RPUSH
LD GR5,=0
LD GR4,1,GR1 ;文字数を入れる
LAD GR6,KETA ;2進数に直す時の桁が入っているテーブル
LP2
SUBL GR4,=1 ;文字数マイナス1
JMI FINK2 ;これがマイナスになったら終了
LD GR3,0,GR1 ;切り出した文字のアドレスが入る
ADDL GR3,GR4 ;アドレスに文字数マイナス1を加える
LD GR3,0,GR3 ;↑の中身
SUBL GR3,=’0′ ;数値に変換
KAKERU LD GR0,=0 ;乗算処理の初期化
LD GR2,0,GR6 ;乗数になる桁が入っているテーブルの桁を読み込む
JZE FINK
LPK LD GR7,GR2 ;最下位ビットチェックの為に退避
AND GR7,=#0001 ;乗数の最下位ビットのチェック
JZE NEXTD
ADDL GR0,GR3 ;最下位ビットが0では無かったら加算
NEXTD
SLL GR3,1 ;被乗数を1ビット左論理シフト
SRL GR2,1 ;乗数を1ビット右論理シフト
JZE FINK
JUMP LPK
FINK
ADDL GR5,GR0 ;前の桁に今回の桁での演算結果を加える
LAD GR6,1,GR6 ;桁テーブルを1つ進める
JUMP LP2
FINK2 LD GR0,GR5 ;2進数に変換した値を退避
RPOP
RET
KETA DC 1,10,100 ;桁テーブル
;プログラム1
GETTKN
RPUSH
LD GR3,=-1 ;単語種別の初期化
LAD GR1,-1,GR1 ;文字列の位置調整
LP LAD GR1,1,GR1 ;MOJIの位置を順番に指す
LD GR4,0,GR1 ;1文字取り出す(↑で指した位置の中身を入れる)
CPL GR4,=’.’ ;比較
JZE FIN ;[.]なら終わり
CPL GR4,=’ ‘ ;比較
JNZ ALNUM ;[△]なら格納処理へ
CALL SETTKN ;単語管理テーブルへの格納処理へ
JUMP LP ;文字の取り出し処理へ「空欄a」
ALNUM LD GR3,GR3 ;0ですか?(単語の処理中?)
JPL LP ;処理中の単語が英字を含む場合はLPへ
JZE ACHK ;処理中の単語が数字だけからなる場合はACHKへ
LD GR3,=0 ;次の単語の処理開始
;単語種別を”数字だけからなる”に設定
LD GR6,GR1 ;先頭アドレスを退避(後で文字数の計算に使う)
ACHK CPL GR4,=’9′ ;9よりデカかったら文字決定!
JPL NEXT ;英字を含む処理へ
CPL GR4,=’0′ ;0より小さかったら文字決定!
JMI NEXT ;文字記号を含む処理へ
JUMP LP ;取り出した文字が数字の場合はLPへ
NEXT LD GR3,=1 ;単語種別を”英字を含む”に設定
JUMP LP
FIN CALL SETTKN ;単語管理テーブルへの格納処理へ
LD GR5,=-1
ST GR5,0,GR2 ;終端マークを格納
RPOP
RET
SETTKN LD GR3,GR3 ;0ですか?
JMI FIN2 ;単語処理中でなければ何もしない
ST GR6,0,GR2 ;単語の先頭アドレスを単語管理テーブルに格納
LD GR5,GR1 ;文字列の今のアドレスを入れる
SUBL GR5,GR6 ;今のアドレス-先頭アドレス=文字数が求まる「空欄b」
ST GR5,1,GR2 ;単語の長さを格納
ST GR3,2,GR2 ;単語の種別を格納
LD GR3,=-1 ;単語種別を初期化(処理中状態を解除)
LAD GR2,3,GR2 ;次の語のために単語管理テーブルを進める
FIN2 RET
END

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
この記事を書くのに丸二日もかかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)
要領悪すぎにゃ~~~~~~( ;∀;)(=^・^=)( ;∀;) (^O^)/

シミュレーターと過去問を解くまでの勉強に使った参考書はこちらです
この問題は平成30年春のアセンブラの問題と似ています。

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

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

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

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

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

この過去問を解いたのは2020年(令和2年)11月8日から9日にかけてです。
丸2日もかかってしまったので、今後時間内に解けるかどうか心配です。
今は丁寧すぎるぐらいにトレースして、それをプログラミングにしたり、ノートに図を描いたりして、力を付けて行って、自信も付けたいです。

後手後手にしていた年末調整、やっと終わりましたので(褒めて褒めて!!)、安心して過去問に取り掛かれました。

さて、過去問に入ります。この過去問題も、アセンブラ色強いな、と思いました。
時間の換算の問題です。
例えば「12分34秒」を秒に直します。これは12×60+34で754秒になります。時間から秒がプログラム1(TOSEC)、逆に秒から時間がプログラム2(TOTIME)、これらを使ってランナーの平均タイムを求めるのがプログラム3(AVERAGE)です。

アセンブラ色が強いな、と思ったのは、特にプログラム1の時間換算で10倍にする処理が出て来て、10バイトは2倍×2倍×2倍の8倍に 2倍を加えた計算が出て来る所で、右シフト左シフトを使ってオーバーフローした場合の分岐が出て来る所です。

個人的にはプログラム1>プログラム3>プログラム2
の順で大変でした。プログラム2は少し楽に感じました。
とは言えボリューミーなので、無理せず休憩を取りながらこの記事を読んで頂けたら嬉しいです(=^・^=)

では、実際に見ていきます。
[プログラム1]は、具体例として数字列「1234」を時間「m1,m2,s1,s2」に当てはめて、12分34秒を754秒と計算する例でトレースしていきます。

主プログラムを呼び出して、主記憶のJIKANに数字列「1234」が1つずつ入りました。

レジスタGR0に0、GR1に数字列JIKANの先頭アドレスが入りました。

プログラム1のTOSECが呼び出されました。
GR2に桁数分のループカウンタが入りました。

秒に換算するのに使うVALUE1の先頭アドレスがGR3に入りました。
数字列の先頭の「1」がGR0に文字コード0031として入りました。

AND演算で数字列0031が1と数値に変換されました。

GR2の所で、桁数カウンタが4から3になりました。

GR4に秒数換算で10倍するのに使う10が入りました。

GR4で10倍の10が右シフトされて5倍になりました。

GR0で数値の1が2になりました。

ループ2へ

GR4で掛ける数の5倍から2倍になりました。
オーバーフローしたので設問2で問われている19行目に飛びます。

GR5に1×2=2が加算されました・・・19行目が1回目

GR0に数値2が更に2倍されて4になりました。

ループ2へ

GR4でかける数2倍が右シフトされて1倍になりました。

GR0で数値4が2倍されて8になりました。

ループ2へ

GR4で1倍が右シフトされ0になりました。
オーバーフローしたので19行目に飛びます。

GR5の2倍とGR0の8倍が加算されGR5の所で10倍になります。・・・19行目が2回目

GR0が2倍され16になりますが、これは後で次の数字列に上書きされます。

ループ2へ
GR4に0フラグが立ちました。

GR3でVAUE1、GR1でJIKANのアドレスが1つ先に進んで次の数字列の処理に入ります。

ループ1へ

GR0に数字列「2」の0032が読み込まれました。

数値の2に変換されました。

GR0にGR0の2とGR510が加算され、12になりました。

GR2の桁数のカウントが1つ減りました。

GR4にVALUE1のかける数6が読み込まれました。

計算の為にGR5が初期化されました。

ループ2

GR4のかける数が右シフトで6から3になりました。

GR0で12が2倍され24になりました。

ループ2へ

かける数が3から1に右シフトされました。
オーバーフローしたので19行目へ

GR5に24が加算されました。・・・19行目が3回目

GR0が2倍され48になりました。

ループ2
GR4のかける数が右シフトされて1から0になり、オーバーフローしました。
19行目に飛びます。

GR5の24ににGR0の48が加算されて、72になりました。・・・19行目が4回目
これで、12×6が実行されました。

GR0が2倍されますが、これは次の数字列に上書きされます。
ループ2へ
かける数にゼロフラグが立ちました。
次の数字列用にGR3のVALUE1とGR1のJIKANが1つ先へ進みます。

ループ1へ

GR0の数字列「3」の0033が入りました。

数字列0033から数値の3に換算されました。

GR0にGR0の3とGR5の72が加算されて75になりました。

GR2で桁数のカウンタが2から1に減りました。

GR4にかける数10倍の10が入りました。

75を10倍する為の計算用レジスタGR5が初期化されました。

GR4でかける数の10倍が右シフトされ5倍になりました。
(色が変わったタイミング逃してしまったので、急遽枠でくくりました。)

GR0で75が2倍されて150になりました。

ループ2へ

GR4でかける数が5倍から右シフトされ2倍になり、オーバーフローしたので
19行目に飛びます。

GR5に150が加算されました。・・・19行目が5回目

GR0の150が2倍され300になりました。

ループ2へ

GR4のかける数2倍が右シフトされて、1倍になりました。

GR0の300が2倍されて600になりました。

ループ2へ
GR4のかける数1倍が右シフトされて0になりました。
オーバーフローしたので19行目に飛びます。

GR5の150にGR0の600が加算されて750になりました。・・・19行目が6回目
ここで、設問2のdの答えが6回になりました。

GR0が2倍されますが、次の文字が上書きされます。
ループ2へ
次の文字用にGR3のVALUE1とGR1のJIKANが1つ先に進み、ループ1へ

GR0に数字列「4」の0034が読み込まれました。

GR0で数字列4から数値4に変換されました。

GR0にGR5が加算され754になりました。

ちょっと数が大きくなったので、10進数表記にします。

また2進数に戻します。
GR2の桁数カウンタが1つ減って0になりました。

では、プログラム1です。

;平成25年秋メインプログラム、プログラム1
;メインプログラム1
MAIN START
RPUSH
LD GR0,=0
LAD GR1,JIKAN
CALL TOSEC
RPOP
RET
JIKAN DC ‘1234’


;プログラム1
TOSEC RPUSH
LD GR5,=0 ;秒の加算処理用
LD GR2,=4 ;ループ回数
LAD GR3,VALUE1 ;掛ける数用
LOOP1 LD GR0,0,GR1 ;GR0←時間の1桁
AND GR0,=#000F ;数字列から数値に換算
ADDA GR0,GR5 ;加算乗算用
SUBA GR2,=1 ;カウンタのデクリメント
JZE FIN
LD GR4,0,GR3 ;GR4←掛ける数
LD GR5,=0 ;加算処理初期化
LOOP2 SRL GR4,1 ;GR0×GR4
JOV INCR ;設問2で問われる19行目へ
JNZ CONT ;空欄a
LAD GR3,1,GR3 ;掛ける数のアドレスを1つ先へ
LAD GR1,1,GR1 ;JIKAN(時間)の数字列を1つ先へ
JUMP LOOP1
INCR ADDA GR5,GR0 ;19行目
CONT SLL GR0,1 ;乗算
JUMP LOOP2
FIN RPOP
RET
VALUE1 DC 10,6,10
END

ノートです。

終了しました。
チョット疲れたからお気に入りのお茶、コーン茶を飲んでプログラム2に入ります。
ついでにストレッチしてトイレも済ましておこう。

コーン茶です。個人的にはとても美味しいと思いますが、どうなんでしょうね。

では、プログラム2へ行きます。

[プログラム2] TOTIME
設問2の具体例を使います。この例を使ったトレースで、10行目の処理の回数を求めるからです。あと、このプログラム2にはシフト演算が無いので、最初から10進数で表示します。レジスタごとに表示を変えられると便利とか思ったのですが、そうなると混乱する場合も。274秒を4分34秒、0434に変換します。
その結果を見やすくする為に、出力ウィンドウに出力させました。
では、プログラム2のトレースに入ります。

GR0に274秒が入りました。

GR1にJIKAN(時間)の先頭アドレスが入り、プログラム2のTOTIMEが呼び出されました。ループカウンタ3が入りました。

割る数の先頭アドレスが入り、10分の600秒が入りました。

計算に使うGR5が初期化されました。

274秒と600秒が比較され、サインフラグが1、つまり10分の桁分が無かったと判断されます。

0が数字列「0」になりました。48と入っていますが、これは16進数で0030です。
16×3なので。(16×1が16だから16進数で10、16×2が32だから16進数で20)

「0」が格納されました。

GR3の割る数VALUE2が1つ先に進み、GR1の格納領域JIKANも1つ進み、ループ回数が1つ減りました。

ループ3へ

割る数に60が入りました。

演算結果が初期化されました。

1分60秒と比較して、274秒の方が多いので、サインフラグが0です。

1分の分がカウントされました。

GR0の274からGR4の60が減算され、GR0が214になりました。・・・10行目の1回目

ループ4へ

1分60秒と比較して、214秒の方が多いので、サインフラグが0です。

2分の分がカウントされました。

GR0の214からGR4の60が減算され、GR0が154になりました。・・・10行目の2回目

ループ4へ

1分60秒と比較して、154秒の方が多いので、サインフラグが0です。

3分の分がカウントされました。

GR0の154からGR4の60が減算され、GR0が94になりました。・・・10行目の3回目

ループ4へ
1分60秒と比較して、94秒の方が多いので、サインフラグが0です。

4分の分がカウントされました。

GR0の94からGR4の60が減算され、GR0が34になりました。・・・10行目の4回目

ループ4へ
1分60秒と比較して、34秒の方が少ないので、サインフラグが1になりました。

4が数字列「4」になりました。52と入っていますが、これは16進数で0034です。
16×3=48、それに4を足して52です。

「4」が格納されました。

GR3の割る数VALUE2が1つ先に進み、GR1の格納領域JIKANも1つ進み、ループ回数が1つ減りました。

ループ3へ

割る数の10が入りました。残りの秒数34を10×3で「3」、余りの分の「4」にする為に、この割る数10を使います。

計算用レジスタのGR5が初期化されました。

10秒と比較して、34秒の方が多いので、サインフラグが0になりました。

10秒1つ分がカウントされました。

GR0の34からGR4の10が減算され、GR0が24になりました。・・・10行目の5回目

ループ4へ
10秒と比較して、24秒の方が多いので、サインフラグが0になりました。

10秒2つ分がカウントされました。

GR0の24からGR4の10が減算され、GR0が14になりました。・・・10行目の6回目

ループ4へ
10秒と比較して、14秒の方が多いので、サインフラグが0になりました。

10秒3つ分がカウントされました。

GR0の14からGR4の10が減算され、GR0が4になりました。・・・10行目の7回目

これより、設問2のeは7回になります。

ループ4へ
10秒と比較して、4秒の方が少ないので、サインフラグが1になりました。

3が数字列「3」になりました。51と入っていますが、これは16進数で0033です。
16×3=48、それに3を足して51です。

「3」が格納されました。

GR3の割る数VALUE2が1つ先に進み、GR1の格納領域JIKANも1つ進み、ループ回数が1つ減って0になりました。なので、分岐せず下に行きます。

GR0の4が数字列「4」になりました。52と入っていますが、これは16進数で0034です。16×3=48、それに4を足して52です。

「4」が格納されました。

メインプログラムに戻ります。

数字列が表示されました。

プログラム2はこちらになります。

;平成25年秋メインプログラム、プログラム2
;メインプログラム2
MAIN START
RPUSH
LD GR0,=274
LAD GR1,JIKAN
CALL TOTIME
LAD GR1,JIKAN
OUT JIKAN,LEN
RPOP
RET
JIKAN DS 4
LEN DC 4


;プログラム2
TOTIME RPUSH
LD GR2,=3 ;ループ回数
LAD GR3,VALUE2 ;秒を分などに換算する割り算領域
LOOP3 LD GR4,0,GR3 ;GR4←割る数
LD GR5,=0
LOOP4 CPA GR0,GR4 ;GR0÷GR4
JMI NEXT
ADDA GR5,=1
SUBA GR0,GR4 ;割る数分引いていく
JUMP LOOP4
NEXT OR GR5,=’0′ ;数値を数字列に換算
ST GR5,0,GR1 ;JIKANに格納
LAD GR3,1,GR3 ;割り算の割る数の位置を進める
LAD GR1,1,GR1 ;時間を格納する数字列を進める
SUBA GR2,=1 ;ループ回数を減算
JNZ LOOP3
OR GR0,=’0′ ;残りの秒数を数字列に変換
ST GR0,0,GR1 ;残りの秒を格納
RPOP
RET
VALUE2 DC 600,60,10
END


↑下手字御免m(__)m
ノートNO.7下の方が見辛いです( ;∀;)
ちょっと疲れたので、また少し休んでからプログラム3に行きます。

・・・・で、結局寝て次の日になりました(=^・^=)

プログラム3のAVERAGEは、選手4人のタイムの平均を求めます。
まずはメインプログラムに下記の設定をします。
タイムは選手1さんは「1234」、選手2さんは「1235」、選手3さんは「1236」、選手4さんは「1237」とします。
4人分のタイムを下記のように選手1さんはRUNNER1、…選手4さんはRUNNER4に格納します。

RUNNER1 ‘1234’…(RUNNER1+0に数字列の「1」、RUNNER1+1に数字列の「2」、RUNNER1+2に数字列の「3」、RUNNER1+3に数字列の「4」)
RUNNER2 ‘1235’…(RUNNER2+0に数字列の「1」…RUNNER2+3に数字列の「5」)
RUNNER3 ‘1236’…(RUNNER3+0に数字列の「1」…RUNNER3+3に数字列の「6」)
RUNNER4 ‘1237’…(RUNNER4+0に数字列の「1」…RUNNER4+3に数字列の「7」)

これらの先頭アドレスを領域ALLに格納します。

ALL+0 RUNNER1+0
ALL+1 RUNNER2+0
ALL+2 RUNNER3+0
ALL+3 RUNNER4+0

RUNNER1のアドレスはGR1、ALLのアドレスはGR3を使用します。

これでプログラム3の(AVERAGE)を呼びます。
プログラム1(TOSEC)を使って秒にして、GR0に選手1の秒を求め、プログラム3(AVERAGE)に戻り、GR4に退避します。繰返し呼び出し、GR0に選手1人分求めたらそれを戻ってGR4に足していきます。
そうするとGR4に4人分の合計の秒数が求まります。そうしたらその値を右に2つシフトして、4で割って平均を求めます。
それからその秒をプログラム2(TOTIME)を使って時間を求めてプログラム3に戻って平均時間を出力します。

ここまでの説明をノートにまとめました。

今回は、シミュレーターの一括実行(このシミュレーターの場合は「実行メニューから」)で行い、出力結果はこのようになりました。

以下がプログラムになります。

プログラム1,2は変わらないので、画像は省略します。

;平成25年秋メインプログラム、プログラム1,2,3
;メインプログラム3
MAIN START
RPUSH
LAD GR3,ALL ;選手4人の先頭アドレスが格納された領域「ALL」の先頭アドレス
LAD GR1,RUNNER1 ;選手1のタイムが格納されている領域の先頭アドレス
ST GR1,0,GR3 ;ALLの先頭に↑を格納する
LAD GR1,RUNNER2 ;選手2のタイムが格納されている領域の先頭アドレス
ST GR1,1,GR3 ;ALL+1に↑を格納する
LAD GR1,RUNNER3 ;選手3のタイムが格納されている領域の先頭アドレス
ST GR1,2,GR3 ;ALL+2に↑を格納する
LAD GR1,RUNNER4 ;選手4のタイムが格納されている領域の先頭アドレス
ST GR1,3,GR3 ;ALL+3に↑を格納する
LAD GR1,ALL ;ALLの先頭アドレスを指定する
CALL AVERAGE ;プログラム3を呼ぶ
RPOP
RET
RUNNER1 DC ‘1234’ ;選手1のタイム
RUNNER2 DC ‘1235’ ;選手2のタイム
RUNNER3 DC ‘1236’ ;選手3のタイム
RUNNER4 DC ‘1237’ ;選手4のタイム
ALL DS 4 ;4人分のタイムの先頭アドレスを入れる領域


;プログラム3
AVERAGE RPUSH
LD GR2,=4 ;加算人数4人の処理待ち人数のカウンター
LD GR3,GR1 ;先頭アドレスを格納
LD GR4,=0 ;4人分の秒の加算領域の初期化
LOOP5 LD GR1,0,GR3 ;4人分のタイムの先頭アドレスを読み込む
CALL TOSEC ;「空欄f」プログラム1を呼ぶ
ADDA GR4,GR0 ;選手の秒換算した分を足していく
LAD GR3,1,GR3 ;ALLのアドレスを先に進める
SUBA GR2,=1 ;処理待ち人数カウンタを1減らす
JNZ LOOP5
SRL GR4,2 ;「空欄g」
LD GR0,GR4 ;プログラム2を呼ぶ準備
LAD GR1,RESULT ;プログラム2を呼ぶ準備
CALL TOTIME ;プログラム2を呼ぶ
OUT RESULT,LEN4 ;出力
RPOP
RET
LEN4 DC 4
RESULT DS 4


;プログラム1
TOSEC RPUSH
LD GR5,=0 ;秒の加算処理用
LD GR2,=4 ;ループ回数
LAD GR3,VALUE1 ;掛ける数用
LOOP1 LD GR0,0,GR1 ;GR0←時間の1桁
AND GR0,=#000F ;数字列から数値に換算
ADDA GR0,GR5 ;加算乗算用
SUBA GR2,=1 ;カウンタのデクリメント
JZE FIN
LD GR4,0,GR3 ;GR4←掛ける数
LD GR5,=0 ;加算処理初期化
LOOP2 SRL GR4,1 ;GR0×GR4
JOV INCR ;設問2で問われる19行目へ
JNZ CONT ;空欄a
LAD GR3,1,GR3 ;掛ける数のアドレスを1つ先へ
LAD GR1,1,GR1 ;JIKAN(時間)の数字列を1つ先へ
JUMP LOOP1
INCR ADDA GR5,GR0 ;19行目
CONT SLL GR0,1 ;乗算
JUMP LOOP2
FIN RPOP
RET
VALUE1 DC 10,6,10


;プログラム2
TOTIME RPUSH
LD GR2,=3 ;ループ回数
LAD GR3,VALUE2 ;秒を分などに換算する割り算領域
LOOP3 LD GR4,0,GR3 ;GR4←割る数
LD GR5,=0
LOOP4 CPA GR0,GR4 ;GR0÷GR4
JMI NEXT
ADDA GR5,=1
SUBA GR0,GR4 ;割る数分引いていく
JUMP LOOP4
NEXT OR GR5,=’0′ ;数値を数字列に換算
ST GR5,0,GR1 ;RESULTに格納
LAD GR3,1,GR3 ;割り算の割る数の位置を進める
LAD GR1,1,GR1 ;時間を格納する数字列を進める
SUBA GR2,=1 ;ループ回数を減算
JNZ LOOP3
OR GR0,=’0′ ;残りの秒数を数字列に変換
ST GR0,0,GR1 ;残りの秒を格納
RPOP
RET
VALUE2 DC 600,60,10
END

トレースノートはこちらです。

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
この記事を書くのに丸二日もかかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)
要領悪すぎにゃ~~~~~~( ;∀;)(=^・^=)( ;∀;) (^O^)/

長々とまとまらなかったり、色々と下らないことも書いて失礼もあったかもしれませんが、ここまでお付き合い頂き本当にありがとうございました。

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

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

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

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

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

令和2年度から比重が多くなる言語で、悪戦苦闘しておりますが、今日解いた過去問は、比較的易しくて正直ホッとしました。
何故易しく感じたのかと申すと、以前解いた、平成21年秋過去問アセンブラ問12と非常に似ていたからです。


なので、この記事を書き終えたら後手後手になっている年末調整の書類に取り掛かれそうです。うちの会社年末調整の締め切りが11月2×日までです。といった全然関係無い話は置いておいて(というと、志村けんさんの「こっちへ置いといて…といって持ってくるコントを思い出す」。
こんなこと書いていたら今読んでいる方に突っ込まれるかな( ´艸`))、
ではでは、アセンブラのお話しに移ります。

この問題は、平成21年秋の過去問と同じように、ビット列の指定の部分を別のビット列に置換します。よくあるパターンなのかな??? 

試験問題の図1に、イラストが描いてありますね。
これを私が分かるように下記のようにノートにまとめました。
字が汚くて大変恐縮ですが、宜しかったらお目汚しに見てやってください(=^・^=)m

ビット列を置き換える所を黒丸で塗りつぶしています。
これも良くあるパターンの様ですが、GR1が対象ビットの先頭アドレスを指していますね。そして、置換開始位置pがGR2、対象ビットの長さqがGR3です。
元のビット列αですが、この具体例は載っていなかったので、ベタですが、
1語目も2語目も「0101010101010101」、16進数で#5555にしたいと思います。

問題を解く前に、ざっと(選択肢はちょっと重めに見て)この問12を見てみると下記のポイントに気づきました。

・設問2の具体例をトレースに利用するとラク
・ビット置換の問題はMASKの生成が好きみたい。特に「算術」右シフト!!!!!
・14行目のレジスタGR4とGR6が設問2で問われるから良く見ておこう!
・16行目と17行目の別の表現もあるんだ…。
・やっぱりアセンブラって、シフト好きだね。

という特徴を掴みかけました。
まだまだ未熟な学習過程ながら、今日気づけましたので記事にしました。

以上を踏まえて、汚いノートをご覧下さい( ;∀;)

では、プログラミングをして、実際にシミュレーターを動かして見ます。

主記憶にα2語、対象位置のp=12、対象ビット長の10、βに置換するビット列が入りました。αのアドレスは少し見辛いですが、左寄りに見ると、この環境では「#1020」です。

GR1にαのアドレスが入りました。(#1020の2進数表記)

GR2に置換対象位置のp=12が入りました。

GR3に置換ビット長の長さq=10が入りました。

置換する文字列、βの#D6C0の2進数表記で入りました。

プログラム1「BREP」が呼び出されました。

GR4にβが退避されました。
これは、置換するビット長10文字のうちの最初の4ビット用に使います。

GR5にβが退避されました。
これは、置換するビット長10文字のうちの残りの6ビット用に使います。

GR6にマスク生成に使う#8000が入りました。・・・空欄a
この問題は、ビット列αの一部をβに置き換えます。
なので、置き換える所を0にして置換するビット列をぶち込むように
色々準備が必要で、そのうちの1つだと以前の似たような過去問を解いた時に覚えました。

GR3が1減算され、10から9になりました。
これは何をしているのかというと、詳細は後述しますが、これもマスク生成の準備に必要な処理です。

GR6にマスクが入りました。
先頭の10ビットに1が入っています。これを作りたかったのですね。
シフトは算術シフトです。
午前でやったことが役に立ちました。
算術シフトなので、空いたビットには先頭ビットと同じビット、
この場合は「1」が入ります。9ビット右にシフトすることで、
先頭から10ビット、つまりビット長の分だけ1が入ります。
なんか、アセンブラのトリビアの泉みたいな話だと思いました。

マスクが2語目用に退避されました。

GR3に16が読み込まれました。アセンブラのレジスタは1語に16ビット格納するから、
それを後にビット開始位置調整に使うからの様です。

GR3に16からGR2の12が引かれて4が入りました。
これは置換処理のビット位置調整に使います。

最初の語の置換用に右に12ビットシフトされました。・・・空欄c

2語目の置換用に左に4ビットシフトされました。

1語目用に12ビット右シフトされました。・・・空欄d及び設問3

2語目用に4ビット左シフトされました。

元のビット列が読み込まれました。・・・設問3

マスクが排他的論理和XORで反転しました。

元のビット列αの、置換対象の部分がゼロクリアされました。
後にここに置換に使うβをぶち込みます。

ORで置換処理が実行されました。・・・空欄b及び設問3

主記憶のαの先頭に置換後のビット列が格納されました。

GR2にαの2語目が読み込まれました。

GR7のマスクが排他的論理和で反転しました。

GR2の置換対象部分に当たる所がゼロクリアされました。

ORで置換処理が実行されました。・・・空欄b

主記憶のαの先頭+1である2語目に置換後のビット列が格納されました。

ここまでで設問1、2、3が終わりました。

以下がプログラム1と、それを呼び出すのに使ったMAINです。
それとノートです。

;平成25年春プログラム1を含む設問1、2、3
;メインプログラム
MAIN START
RPUSH
LAD GR1,ALPHA ;αの設定
LD GR2,P ;置換開始位置の設定
LD GR3,Q ;置換対象文字長の設定
LD GR0,BETA ;βの設定
CALL BREP ;プログラム1を呼び出す
RPOP
RET
ALPHA DC #5555 ;問題文の具体例に沿ったデータを配置
DC #5555
P DC 12
Q DC 10
BETA DC #D6C0
;[プログラム1]の「BREP」のはじまりはじまり~~~~(^O^)/
BREP RPUSH
LD GR4,GR0 ;βを退避(10ビット中の最初の4ビット用)
LD GR5,GR0 ;βを退避(10ビット中の残りの4ビット用)
LD GR6,=#8000 ;MASKパターン生成の準備(7行目の「算術」シフト用)
LAD GR3,-1,GR3 ;MASKパターン生成の準備その2(シフトするビット数用)
SRA GR6,0,GR3 ;GR6←qビットのMASKパターン生成(くどいようですが「算術」シフト)
;「算術」シフトということは空いた所が1なら1が入るって午前対策でやった。
LD GR7,GR6 ;生成したマスクを後半6ビット用に読み込み
LD GR3,=16 ;開始位置を合わせる準備
SUBA GR3,GR2 ;GR3←16-p
SRL GR4,0,GR2 ;1語目用置換文字列の準備
SLL GR5,0,GR3 ;2語目用置換文字列の準備
SRL GR6,0,GR2 ;1語目用MASKパターン生成
SLL GR7,0,GR3 ;2語目用MASKパターン生成
LD GR2,0,GR1 ;1語目の処理
XOR GR6,=#FFFF ;置換用にビットを反転する
AND GR2,GR6 ;置換対象の所をゼロにして置く
OR GR2,GR4 ;↑でゼロにした所に置換対象の部分をぶち込む
ST GR2,0,GR1 ;置換後のビット列をαの1語目に格納する
LD GR2,1,GR1 ;2語目の処理
XOR GR7,=#FFFF ;置換用にビットを反転する
AND GR2,GR7 ;置換対象の所をゼロにして置く
OR GR2,GR5 ;↑でゼロにした所に置換対象の部分をぶち込む
ST GR2,1,GR1 ;置換後のビット列をαの2語目に格納する
RPOP
RET
END

では、設問4用にノートも用いて行います。
もっと長いビット列αも対応したいんだよ!!!っていう訳で追加のプログラムの様ですね。ちょっと疲れましたが、もう少し頑張ります。

すみません、深呼吸します。

・・・落ち着いた所で、設問4に入ります。
具体例として、n=4、4語分用意して、その中の3語目(α+2)と4語目を置換対象にしました。
αの置換開始位置をp=44です。(16+16+上記の設問と同じ12ビット)
qは同じで10にします。

では、ノートです。

では、プログラム2のトレースを行います。

主記憶で、αの領域を設問4用に多く(4語)場所取りしました。

GR2にビット開始の位置44が入りました。

ビット位置と指し示す語の位置の調整の為、GR7にp=44のビット開始位置が退避されました。

ビット位置44の44は00000000「0010」1100で、
「0010」を右端にシフトすることによって、3語目(α+2)を指すように調整しています。

これで、αの指し示す位置が2語先になりました。

ビット位置44の000000000010「1100」の「」の所のみにしたいので、
000Fとの論理積ANDを取りました。

ここからプログラム1のBREPを呼び出します。
重複する所は省いて、設問4に関係のある所のみを掲載します。

最初の置換ビット列がα+2の位置に格納されました。

最初の置換ビット列がα+3の位置に格納されました。

最後に、プログラム2を掲載します。

;平成25年春プログラム2及び1を含む設問4
;メインプログラム
MAIN START
RPUSH
LAD GR1,ALPHA ;αの設定
LD GR2,P ;置換開始位置の設定。設問4用。
LD GR3,Q ;置換対象文字長の設定
LD GR0,BETA ;βの設定
CALL XBREP ;プログラム2を呼び出す
RPOP
RET
ALPHA DC #5555 ;問題文の具体例に沿ったデータを配置
DC #5555
DC #5555 ;設問4用にαを追加(α+2)
DC #5555 ;設問4用にαを追加(α+3)
P DC 44 ;設問4用に3語目~4語目の先頭を0とした44ビットにする
Q DC 10
BETA DC #D6C0
;[プログラム2]の「XBREP」です(=^・^=)m
XBREP RPUSH
LD GR7,GR2 ;3語目を指し示すようにする
SRL GR7,4 ;α+2の2を作る為にシフトする
ADDL GR1,GR7 ;α+2にする
AND GR2,=#000F ;44の下位ビットを取り出す
CALL BREP ;プログラム1を呼び出す
RPOP
RET
;[プログラム1]の「BREP」のはじまりはじまり~~~~(^O^)/
BREP RPUSH
LD GR4,GR0 ;βを退避(10ビット中の最初の4ビット用)
LD GR5,GR0 ;βを退避(10ビット中の残りの4ビット用)
LD GR6,=#8000 ;MASKパターン生成の準備(7行目の「算術」シフト用)
LAD GR3,-1,GR3 ;MASKパターン生成の準備その2(シフトするビット数用)
SRA GR6,0,GR3 ;GR6←qビットのMASKパターン生成(くどいようですが「算術」シフト)
;「算術」シフトということは空いた所が1なら1が入るって午前対策でやった。
LD GR7,GR6 ;生成したマスクを後半6ビット用に読み込み
LD GR3,=16 ;開始位置を合わせる準備
SUBA GR3,GR2 ;GR3←16-p
SRL GR4,0,GR2 ;1語目用置換文字列の準備
SLL GR5,0,GR3 ;2語目用置換文字列の準備
SRL GR6,0,GR2 ;1語目用MASKパターン生成
SLL GR7,0,GR3 ;2語目用MASKパターン生成
LD GR2,0,GR1 ;1語目の処理
XOR GR6,=#FFFF ;置換用にビットを反転する
AND GR2,GR6 ;置換対象の所をゼロにして置く
OR GR2,GR4 ;↑でゼロにした所に置換対象の部分をぶち込む
ST GR2,0,GR1 ;置換後のビット列をαの1語目に格納する
LD GR2,1,GR1 ;2語目の処理
XOR GR7,=#FFFF ;置換用にビットを反転する
AND GR2,GR7 ;置換対象の所をゼロにして置く
OR GR2,GR5 ;↑でゼロにした所に置換対象の部分をぶち込む
ST GR2,1,GR1 ;置換後のビット列をαの2語目に格納する
RPOP
RET
END

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
この記事を書くのに6時間かかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)
要領悪すぎにゃ~~~~~~( ;∀;)(=^・^=)( ;∀;) (^O^)/

今回は、今までの記事と違って、下らないことも色々書いて失礼もあったかもしれませんが、ここまでお付き合い頂き、誠にありがとうございました。

あ、年末調整頑張ります!!

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

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

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

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

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

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

多項式の値を求める問題です。
この問題の具体例として、問題文の具体例よりも簡単になるように、計算しやすい例を用いました。
xを2、n=3として、
(2^3)+(2^2)+(2^1)+(2^0)=8+4+2+1=15を求めます。

では、プログラム1からトレースして行きます。

メインプログラムでx=2をGR2に、n=3をGR1に設定しました。

ここからプログラム1のPOLYを呼び出します。
演算結果を格納するGR4が初期化されました。

かける回数のカウンタが入りました。

被乗数(かけられる数)が初期化されました。

かけ算プログラムMULTが呼び出されました。
1×2=2が求まれれます。
被乗数(かけられる数)が入りました。
(乗数(かける数)はGR2に入っています。)

かけ算の結果が初期化されました。

乗数を退避して、下一桁が0かどうか調べます。

2は2進数で0010なので、0001をかけて下一桁が0であることが
判明しました。

被乗数が左シフト、乗数が右シフトされました。

乗数が退避されました。

演算結果が格納されました。

被乗数が左シフト、乗数が右シフトされました。

呼び出し元に戻りました。
かける回数が1つ減って2になりました。

かけられる数、かける数が設定され、2×2=4が求まります。
MULTが呼び出されました。
(かけ算処理は省略)

呼び出し元に戻って、かける回数が1回減りました。

かけられる数、かける数が設定され、4×2=8が求まります。
MULTが呼び出されました。
(かけ算処理は省略)

呼び出し元に戻りました。
GR3が0になり、かけ算処理が終わり、2の3乗の2×2×2=8がGR4に加算されました。

次は、2の2乗の4を求めてGR4に加算します。
(かけ算処理省略)

2の3乗の8に2の2乗の4が加算されて12(000C)になりました。

12(000C)に2の1乗の2が加算されて14(000E)になりました。

14(000E)に2の0乗の1が加算されて15(000F)になりました。

マイナスになったので多項式の演算処理が終了しました。

GR0に演算結果が求まりました。

プログラム1、プログラム2、トレースのノートはこちらになります。

;メインプログラム
MAIN START
RPUSH

;F(x,n)は問題文より少し簡単な「xに2」、「nに3」を設定する
LD GR2,X
LD GR1,N
CALL POLY
RPOP
RET
X DC 2
N DC 3
;プログラム1
POLY RPUSH
LD GR4,=0 ;計算結果格納レジスタの初期化
LP1 LD GR3,GR1 ;nをカウンタとして加算乗算に利用
JMI FIN ;0乗まで計算するのでマイナスになったら分岐
LD GR0,=1 ;x^nの計算開始(初期化)
LP2 LD GR3,GR3 ;0乗まで計算しましたか?
JZE BRK ;x^nの計算終了ならBRKへ
CALL MULT ;(GR0)←(GR0)×(GR2)
LAD GR3,-1,GR3 ;かける回数のカウンタを1つ減らす
JUMP LP2
BRK ADDL GR4,GR0 ;計算結果格納レジスタにx^nの値を加算
LAD GR1,-1,GR1 ;nから1を減じ、低次の項の計算へ
JUMP LP1
FIN LD GR0,GR4 ;計算結果を読み込む
RPOP
RET


;プログラム2
MULT ;シフトによる乗算
RPUSH
LD GR1,GR0
LD GR0,=0 ;乗算結果の初期化
LD GR2,GR2 ;乗数(かける数)は0ですか?
LP JZE FIN2
LD GR3,GR2 ;乗数を退避
AND GR3,=#0001 ;最下位ビットのチェック
JZE CONT
ADDL GR0,GR1
CONT
SLL GR1,1
SRL GR2,1
JUMP LP
FIN2 RPOP
RET
END

では、再帰呼び出しによるプログラム3のトレースを行います。
xとnが入ってPOLY2を呼び出します。

再帰処理が始まります。
スタックに呼び出し元アドレスが積まれました。

F(x,n)=x×F(x,n-1)+1 (n>=1)のn-1にあたるnの減算処理が行われました。

呼び出し元の1つ先のアドレスがスタックに積まれて再帰呼び出しに行きました。

n-1が行われました。

呼び出し元の1つ先のアドレスがスタックに積まれて再帰呼び出しに行きました。

n-1が行われました。

呼び出し元の1つ先のアドレスがスタックに積まれて再帰呼び出しに行きました。

n=0の時の処理が実行されました。

スタックから1つ取り出されて呼び出し元の1つ先のアドレスに行きました。


1×2が設定されMULTを呼び、かけ算処理を行います。

1×2の計算結果の2が求まりました。

スタックから1つ取り出されて呼び出し元の1つ先のアドレスに行きました。


2に1が加算され3になり、MULTを読んでかけ算処理を行います。

演算結果の2×3の6が求まりました。

1が加算され7になりました。

スタックから1つ取り出されて呼び出し元の1つ先のアドレスに行きました。
MULTを読んでかけ算処理を行います。

7×2=14が実行されました。

1が加えられました。

スタックから1つ取り出されて呼び出し元の1つ先のアドレスに行きました。

以上で終了になります。

プログラム1、プログラム2、トレースのノートはこちらになります。

;メインプログラム
;F(x,n)は問題文より少し簡単な「xに2」、「nに3」を設定する

MAIN START
RPUSH
LD GR2,X
LD GR1,N
CALL POLY2
RPOP
RET
X DC 2
N DC 3
POLY2
RPUSH
CALL RSUB ;再帰処理の本体を呼ぶ
RPOP
RET ;主プログラムに戻る
RSUB
LD GR1,GR1 ;n=0?
JNZ CONT3 ;n<>0ならCONT3へ
LD GR0,=1 ;GR0←F(x,0)の値(=1)
RET
CONT3 LAD GR1,-1,GR1 ;再帰呼び出しnの回数を1減らす
CALL RSUB ;F(x,n-1)を計算
CALL MULT ;かけ算処理
ADDL GR0,=1 ;被乗数(かけられる数に1加える)
RET


;プログラム2
MULT ;シフトによる乗算
RPUSH
LD GR1,GR0
LD GR0,=0 ;乗算結果の初期化
LD GR2,GR2 ;乗数(かける数)は0ですか?
LP JZE FIN2
LD GR3,GR2 ;乗数を退避
AND GR3,=#0001 ;最下位ビットのチェック
JZE CONT
ADDL GR0,GR1
CONT
SLL GR1,1
SRL GR2,1
JUMP LP
FIN2 RPOP
RET
END

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
この記事を書くのに6時間かかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)
要領悪すぎにゃ~~~~~~( ;∀;)(=^・^=)( ;∀;) (^O^)/

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

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

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

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

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

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

数字列の足し算プログラムです。
簡単だと思っていましたが、アセンブラのテクニックにタジタジしながら半分ぐらいしか解けなかった問題です。
検証にはだいぶ時間をかけて、このブログを書いている今は全て理解出来ました。

このテクニックがポイントなんですね。
例えば数字列の’1’、つまり#0031と数字列の’2’、つまり#0032を足す時、そのまま足すと’3’にはならず、#0063になってしまうんですね。
だからどちらか(この問題では数字列2)を#0032に#000Fの論理積をとって、#0002にしてから’1’の#0031を足して、

0033である’3’になるんですね。

これが時間測って解いている時は分からなくて、一度トレースを消してやり直したので、時間内に解き終わりませんでした。

では、設問1、設問2のプログラム1であるADDCをステップ実行でやってみます。
分かりやすいように数字列1、数字列2、加算結果をそれぞれ出力しています。

数字列1をBUF1に格納して、その先頭アドレスをGR1に設定します。文字数はGR4に設定します。
数字列2をBUF2に格納して、その先頭アドレスをGR2に設定します。文字数はGR5に設定します。
加算結果をBUF3に格納して、その先頭アドレスをGR3に設定します。文字数は実行後にGR0に格納されます。

入力ウィンドウに問題文の数字列1「9462」を入力してEnterを押します。

出力されました。

数字列1の文字数がGR4に入りました。

数字列2も問題文通り「673」と入力しました。

出力されました。

数字列2の文字数がGR5に入りました。

設問1、2の副プログラムADDCを呼び出しました。
文字数は数字列1の方が長いので、CONTに分岐しました。

数字列1の末尾の1つ後ろのアドレスが入りました。(配列は0から始まるので)

数字列2も同じように入りました。

桁上りフラグが設定されました。

スタックに加算結果の末尾の目印(番兵)となる0(#0000)が入りました。

数字列2の末尾のアドレスが入りました。
「’3’」を指しています。

数字列2の下一桁が入りました。
「’3’」が入りました。

数字から数値に変換されました。
「’3’」から「3」になりました。

数字列1の末尾のアドレスが入りました。
「’2’」を指しています。

数値に変換された数字列2と数字列1の下一桁が加算されました。

桁上げフラグも加算されました。
(0の為、値は変わらず)

桁上げチェックで、’9’である#0039を超えていないので、
分岐はしません。

加算結果がスタックに積まれました。

文字列1の残りが1つ減りました。デクリメントしてカウンタの役割をしています。

文字列2の残りが1つ減りました。デクリメントしてカウンタの役割をしています。

文字列2のアドレスが1つ前になりました。「’7’」を指しています。

「’7’」が読み込まれました。

「’7’」が「7」になりました。

文字列1のアドレスが1つ前になりました。「’6’」を指しています。

数値の「7」と数字列の「’6’」が加算されたので、
「#0007」と「#0036」が加算され、「#003D」になりました。


Dは16進数で13なんですよね。
私は「#0007」と「#0036」を足して、「#0043」だ、なんて思ってしまったのですが、怖いコワイ・・・。


こういう所、出たりするのかな??

では、次行きます。
下位桁からの繰上りが加算されました。0なので値変わらずです。

「’9’」である「#0039」と比較しました。「#003D」の方が大きいので分岐します。

桁上りのフラグが1に設定されました。・・・設問2の25行目1回目

「#003D」を1の桁「’3’」にするため、「#003D」から10を引いて、「#0033」になりました。

スタックに「’3’」が積まれました。

文字列1の残り文字数がデクリメントされました。

文字列2の残り文字数がデクリメントされました。

文字列2のアドレスが1つ前に移動して「’6’」を指しました。

「’6’」が読み込まれました。

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

文字列1のアドレスが1つ前に移動して、「’4’」を指しました。

加算されて「#003A」になりました。

桁上げ分が加算されて「#003B」になりました。

‘9’より大きいので桁上げ処理に分岐します。
桁上げフラグが1になりました。・・・設問2の25行目2回目
1の桁「#003B」から10を引いて「#0031」にします。

スタックに積まれました。

文字列1の残りがデクリメントされました。

文字列2の残りがデクリメントされて0になりました。

文字列2が終わったので、その分「0」が入って文字列1の加算準備をしました。

文字列1が1つ前に移動して、「’9’」を指しました。

‘9’が加算されました。

桁上り分が加算されて「#003A」ました。

‘9’より大きいので桁上りの分岐をします。
桁上げフラグが1になりました。・・・設問2の25行目3回目。設問2の答えは「3」
「#003A」から10を引いて、「#0030」になります。

スタックに積まれました。

数字列1の残りが0になりました。

左下の赤くなっている「ZF」が0、つまり、GR0は0では無いので、桁上げ分の’1’の処理をします。

‘1’を読み込みました。

‘1’が主記憶の、GR3の指し示すBUF3の先頭に格納されました。

結果を指し示すBUF3のアドレスが1つ先になりました。

スタックから取り出された’0’がGR1に格納されました。

結果の文字数の長さが1つ加算されました。

‘0’が主記憶の、GR3の指し示すBUF3の先頭に格納されました。

結果を指し示すBUF3のアドレスが1つ先になりました。

スタックから取り出された’1’がGR1に格納されました。

結果の文字数の長さが1つ加算されました。

‘1’が主記憶の、GR3の指し示すBUF3の先頭に格納されました。

結果を指し示すBUF3のアドレスが1つ先になりました。

スタックから取り出された’3’がGR1に格納されました。

結果の文字数の長さが1つ加算されました。

‘3’が主記憶の、GR3の指し示すBUF3の先頭に格納されました。

結果を指し示すBUF3のアドレスが1つ先になりました。

スタックから取り出された’5’がGR1に格納されました。

結果の文字数の長さが1つ加算されました。

‘5’が主記憶の、GR3の指し示すBUF3の先頭に格納されました。

結果を指し示すBUF3のアドレスが1つ先になりました。

スタックから取り出された「0(#0000)」がGR1に格納されました。
終わりの目印、番兵とかターミネーターとかの為に設定した「0」です。

終わって、主プログラムに戻りました。
加算結果が入りました。

これで、プログラム1の設問1と設問2は終わります。

プログラムです。


;平成24春プログラム1
;メインプログラム。プログラム1を呼ぶ設定をプログラム2を参考に作りました。
MAIN START
RPUSH
LAD GR1,BUF1 ;数字列1のポインタを設定
IN BUF1,LEN1 ;最初の数字列を入力し数字列1とする
OUT BUF1,LEN1 ;数字列1の表示
LD GR4,LEN1 ;数字列1の長さを設定
LAD GR3,BUF3 ;BUF3を数字列1と数字列2の和の領域として設定
LAD GR2,BUF2 ;数字列2のポインタを設定
IN BUF2,LEN2 ;数字列2を入力する
OUT BUF2,LEN2 ;数字列2の表示
LD GR5,LEN2 ;数字列2の長さを設定
CALL ADDC
ST GR0,LEN3
OUT BUF3,LEN3 ;計算結果の表示
RPOP
RET
BUF1 DS 256 ;数字列1の領域
BUF2 DS 256 ;数字列2
BUF3 DS 256 ;足し算の結果
LEN1 DS 1 ;数字列1の長さ
LEN2 DS 1 ;数字列2の長さ
LEN3 DS 1 ;数字列3の長さ


;設問1、設問2のプログラム
ADDC
RPUSH
CPA GR4,GR5 ;文字列1と文字列2ではどっちが長い?
JPL CONT ;文字列1の方が長かったら分岐
;文字列2の方が長かったら、長い方が1に交換する処理
;GR4>=GR5となるように数字列1と数字列2のポインタを入れ替え
PUSH 0,GR4 ;数字列1の長さをスタックに積む
LD GR4,GR5 ;数字列2の長さを読み込む
POP GR5 ;スタックに積んだ長さを取り出す
PUSH 0,GR1 ;数字列1をスタックに積む
LD GR1,GR2 ;数字列2を読み込む
POP GR2 ;スタックに積んだ数字列を取り出す
CONT ADDA GR1,GR4 ;数字列1の末尾番地+1(0番地から始まるから)
ADDA GR2,GR5 ;数字列2の末尾番地+1(0番地から始まるから)
LD GR0,=0 ;桁上げフラグを初期化
PUSH 0 ;スタックデータの終わりの目印
LOOP1 LAD GR2,-1,GR2 ;数字列2の末尾番地
LD GR6,0,GR2 ;数字列2の下1桁から加算
AND GR6,=#000F ;数字列(文字)から数字(数値)に変換
LOOP2 LAD GR1,-1,GR1 ;数字列1の末尾番地
ADDA GR6,0,GR1 ;数字列1も下一桁から足す(こっちは数値に変換しないから、数字列になる)
ADDA GR6,GR0 ;桁上げフラグも足す
CPA GR6,=’9′ ;’9’である「0039」より大きかったら桁上げ
JPL CARRY ;桁上げ分岐
LD GR0,=0 ;桁上げフラグを初期化
JUMP NEXT ;計算結果のスタック積み上げ処理に分岐
CARRY LD GR0,=1 ;桁上げフラグの設定
SUBA GR6,=10 ;スタックに下一桁を積めるように文字コードから10をマイナスする
NEXT PUSH 0,GR6 ;加算結果1桁を保存(スタックに積むツムツム)
SUBA GR4,=1 ;数字列1からデクリメントしてカウンタの役割を果たす
JZE END1 ;数字列1の加算処理が終了なら分岐
SUBA GR5,=1 ;数字列2からデクリメントしてカウンタの役割を果たす
JPL LOOP1 ;数字列1も文字列2も残っている場合に分岐
LD GR6,=0 ;数字列2が全部終わって文字列1のみが残っている時0を足す
JUMP LOOP2 ;0に数字列1の加算処理へ分岐
END1 LD GR0,GR0 ;左端を桁上げ?
JZE NOCARRY
LD GR1,=’1′ ;左端に’1’を追加
LOOP3 ST GR1,0,GR3 ;(スタックから取り出した数字を)結果格納
LAD GR3,1,GR3 ;結果格納領域をインクリメント
NOCARRY POP GR1 ;スタックに積んだ加算結果を取り出す
LD GR1,GR1 ;スタックに最初に積んだ目印の0(0000)だったら
JZE END2 ;全て積んだのでおしまい分岐
ADDA GR0,=1 ;結果の文字数をインクリメントでカウントアップ
JUMP LOOP3
END2 RPOP
RET
END

ノートです。

では設問3に行きます。

設問の具体例では5つの数字列の総和を求めます。

プログラム2はSUMCなので、LOOPやFINのあとに「S」を付けています。
LOOPから2行下の「JMI FIN1」で、数字列2の長さがマイナスだったら終了処理に分岐するのですが、
うちのシミュレーターではマイナスの長さというのを入力できないので、長さが「0」、
すなわち、何も入力しないでENTERを押した時に終了処理になるように致しました。

では、問題の具体例でプログラム2のポイントに関する所をステップ実行と最後の所のみ一括実行して
トレースしていきます。

最初の数字を入力して出力しました。

次の数字を入出力しました。

設問1、2で使った、副プログラムADDCを呼び出します。
加算処理が終わって、呼び出し元の設問3のSUMCが呼び出されました。
数字列1と数字列2の加算結果の文字数がGR4に読み込まれました。

ここから、加算結果を数字列1にして、再度呼び出して次の文字列を加算する準備に入ります。
その為に、GR3の結果のアドレスをGR1に読み込むのでプログラムのコメントのように総和(計算結果)と、
数字列1のポインタをスタックを使って入れ替えします。


この図の通り、今、GR1に格納されているGR1の数字列1の先頭アドレスは「#107E」番地です。
GR3の結果のアドレスは「#127E」です。
GR1に格納されたアドレスをスタックに格納します。

次に、GR3のアドレスをGR1に読み込みます。

スタックに積んでいたGR1に格納されていたアドレスが取り出されて、GR3に格納されました。


これで、数字列1に計算結果が入って、新たな数字列2の所に次の数字列を読み込んで、
繰返し計算が出来ます。

以下、一括実行で処理します。
計算結果になります。

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


;平成24春プログラム2
;メインプログラムのSUMC。プログラム1を呼ぶ。
SUMC START
RPUSH
LAD GR1,BUF1 ;数字列1のポインタを設定
IN BUF1,LEN1 ;最初の数字列を入力し数字列1とする
OUT BUF1,LEN1 ;数字列1の表示
LD GR4,LEN1 ;数字列1の長さを設定
LAD GR3,BUF3 ;BUF3を総和の和の領域として設定
LAD GR2,BUF2 ;数字列2のポインタを設定
LOOPS IN BUF2,LEN2 ;数字列2を入力する
OUT BUF2,LEN2 ;数字列2の表示
LD GR5,LEN2 ;数字列2の長さを設定
JZE FINS1 ;マイナスの値が入力されたら終了
CALL ADDC
LD GR4,GR0 ;合計の文字数を次の数字列1の文字数にする
;総和の領域のポインタと数字列1のポインタを入れ替え
PUSH 0,GR1 ;数字列1のアドレスをスタックに積む
LD GR1,GR3 ;結果のアドレスを読み込む
POP GR3 ;スタックに積んだ数字列1のアドレスをGR3へ
JUMP LOOPS
FINS1 LAD GR3,BUF3 ;結果の先頭アドレス
CPA GR1,GR3 ;総和の判定
JZE FINS2
ST GR4,LEN1
OUT BUF1,LEN1
JUMP FINS3
FINS2 ST GR4,LEN3
OUT BUF3,LEN3
FINS3
RPOP
RET
BUF1 DS 256 ;数字列1の領域
BUF2 DS 256 ;数字列2
BUF3 DS 256 ;足し算の結果
LEN1 DS 1 ;数字列1の長さ
LEN2 DS 1 ;数字列2の長さ
LEN3 DS 1 ;数字列3の長さ


;設3でも利用。設問1、設問2のプログラム
ADDC
RPUSH
CPA GR4,GR5 ;文字列1と文字列2ではどっちが長い?
JPL CONT ;文字列1の方が長かったら分岐
;文字列2の方が長かったら、長い方が1に交換する処理
;GR4>=GR5となるように数字列1と数字列2のポインタを入れ替え
PUSH 0,GR4 ;数字列1の長さをスタックに積む
LD GR4,GR5 ;数字列2の長さを読み込む
POP GR5 ;スタックに積んだ長さを取り出す
PUSH 0,GR1 ;数字列1をスタックに積む
LD GR1,GR2 ;数字列2を読み込む
POP GR2 ;スタックに積んだ数字列を取り出す
CONT ADDA GR1,GR4 ;数字列1の末尾番地+1(0番地から始まるから)
ADDA GR2,GR5 ;数字列2の末尾番地+1(0番地から始まるから)
LD GR0,=0 ;桁上げフラグを初期化
PUSH 0 ;スタックデータの終わりの目印
LOOP1 LAD GR2,-1,GR2 ;数字列2の末尾番地
LD GR6,0,GR2 ;数字列2の下1桁から加算
AND GR6,=#000F ;数字列(文字)から数字(数値)に変換
LOOP2 LAD GR1,-1,GR1 ;数字列1の末尾番地
ADDA GR6,0,GR1 ;数字列1も下一桁から足す(こっちは数値に変換しないから、数字列になる)
ADDA GR6,GR0 ;桁上げフラグも足す
CPA GR6,=’9′ ;’9’である「0039」より大きかったら桁上げ
JPL CARRY ;桁上げ分岐
LD GR0,=0 ;桁上げフラグを初期化
JUMP NEXT ;計算結果のスタック積み上げ処理に分岐
CARRY LD GR0,=1 ;桁上げフラグの設定
SUBA GR6,=10 ;スタックに下一桁を積めるように文字コードから10をマイナスする
NEXT PUSH 0,GR6 ;加算結果1桁を保存(スタックに積むツムツム)
SUBA GR4,=1 ;数字列1からデクリメントしてカウンタの役割を果たす
JZE END1 ;数字列1の加算処理が終了なら分岐
SUBA GR5,=1 ;数字列2からデクリメントしてカウンタの役割を果たす
JPL LOOP1 ;数字列1も文字列2も残っている場合に分岐
LD GR6,=0 ;数字列2が全部終わって文字列1のみが残っている時0を足す
JUMP LOOP2 ;0に数字列1の加算処理へ分岐
END1 LD GR0,GR0 ;左端を桁上げ?
JZE NOCARRY
LD GR1,=’1′ ;左端に’1’を追加
LOOP3 ST GR1,0,GR3 ;(スタックから取り出した数字を)結果格納
LAD GR3,1,GR3 ;結果格納領域をインクリメント
NOCARRY POP GR1 ;スタックに積んだ加算結果を取り出す
LD GR1,GR1 ;スタックに最初に積んだ目印の0(0000)だったら
JZE END2 ;全て積んだのでおしまい分岐
ADDA GR0,=1 ;結果の文字数をインクリメントでカウントアップ
JUMP LOOP3
END2 RPOP
RET
END

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
この記事を書くのに6時間かかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)
要領悪すぎにゃ~~~~~~( ;∀;)(=^・^=)( ;∀;) (^O^)/

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

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

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

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

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

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

割り算プログラムの問題です。
具体例として、被除数(以下、割られる数)を50、除数(以下、割る数)を20とします。そうすると、商が2、余りが10になります。

入力
GR1:#0000(割られる数の上位語)
GR2:#0032(割られる数の下位語で50)
GR3:割る数が格納してある領域「WARU」の先頭アドレス「WARU+0」
GR3+1:WARU+1
割る数には20の16進数表記#0014を入れました。

このプログラム1を実行すると、

出力
GR1:#0000(商の上位語)
GR2:#0002(商の下位語で2)
GR4:#0000(余りの上位語)
GR5:#000A(余り語下位語で10)

となります。

では、ステップ実行していきます。
実行すると、割る数の上位語下位語が入りました。下位語は20の16進数表記、#0014が入りました。

次に、割られる数の上位語#0000、下位語50の#0032が入りました。

ここで、メインプログラムから割り算プログラムのDIVが呼び出されました。
割れれる数の上位語下位語がそれぞれ退避されました。

商の上位語下位語が初期化されました。

ループに入り、割られる数の上位語下位語が退避されました。
これは余りを求めるのに使います。

割り算実行前の商が上位語、下位語ともに入りました。

1回目の割り算処理が実行されました。
50から20を引いて30になり、その16進数の#001Eが入りました。

1回目の割り算処理実行後の結果が退避されました。

商がカウントアップされました。

30から20を引いた余りの10が求まりました。

2回目の割り算処理実行後の結果が退避されました。

商がカウントアップされました。

余りの10から割る数の20を引いたらオーバーフローしました。

プログラム1が終わりました。

プログラム1はこちらになります。

トレースに使ったノートはこちらになります。

;平成23年秋…割り算プログラム1
;呼び出し元のメインプログラム
MAIN START
RPUSH
LD GR1,=#0000 ;割られる数の上位語
LD GR2,=#0032 ;その下位語で50
LAD GR3,WARU ;結果領域先頭後
CALL DIV
RPOP
RET
WARU DC #0000 ;割る数上位語
DC #0014 ;割る数下位語で20



;プログラム1
DIV
PUSH 0,GR6
PUSH 0,GR7
LD GR6,GR1 ;割られる数の上位語
LD GR7,GR2 ;割られる数の下位語
LD GR1,=#FFFF ;商の初期化
LD GR2,=#FFFF
LP LD GR4,GR6 ;割られる数の上位語
LD GR5,GR7 ;割られる数の下位語
ADDL GR2,=1 ;商のカウントアップ
JOV ADJ1 ;桁上り処理へジャンプ
JUMP CONT ;割り算実行
ADJ1 ADDL GR1,=1 ;桁上り処理実行
CONT SUBL GR6,0,GR3 ;引き算しながら割り算していく
JOV FIN
SUBL GR7,1,GR3 ;引き算しながら割り算していく
JOV ADJ2
JUMP LP
ADJ2 SUBL GR6,=1 ;繰り下がり処理
JOV FIN
JUMP LP
FIN POP GR7
POP GR6
RET
END

次にプログラム2、3では、割り算プログラムのプログラム1、DIVを利用して、
10進数の数字列に変換します。

GR1:#0000(変換する数の上位語)
GR2:#054D(変換する数の下位語、10進数で1357)

10000を16進数に直すと#2710、1000は#03E8、100は#0064、10は#000Aになります。
それをUDATに設定します。
結果を出力ウィンドウに表示します。

では、プログラム2を含めたステップ実行をして行きます。
丁寧にかつ、冗長な繰返しの所は要所要所省きながら行いました。

主記憶に1桁ずつ格納する結果領域KEKKAが用意されました。

数字列にする(割られる)数の上位語下位語が設定されました。
プログラム2、BTOD2が呼び出されました。

結果領域の先頭、末尾アドレスが入りました。

プログラム1、DIVが呼び出されました。

1357÷10000が実行されました。結果は0です。
プログラム2に戻りました。

商が数字列に変換されました。

結果領域の先頭アドレスに「0」が格納されました。

再びプログラム1、DIVが呼び出されました。
1357÷1000が実行されました。
1357から1000を引いて357、16進数に直すと#0165になりました。

商が1と求まりました。

数字列に変換され主記憶に格納されました。

357÷100が実行されました。
357-100で257、16進数で#0101が求まりました。


257-100で157、16進数で#009Dが求まりました。


157-100で57、16進数で#0039が求まりました。


商が3と求まりました。

主記憶に商の3が格納されました。

57は16進数で#0039です。
57÷10が実行されました。
57-10は47で、16進数では#002Fです。


47-10は37で16進数では#0025です。


37-10は27で16進数では#001Bです。


27-10は17で16進数では#0011です。

17-10は7です。

商が5と求まりました。

主記憶に格納されました。

7÷1が実行され、商の7が求められ、主記憶に格納されました。

出力結果です。

トレースに使ったノートはこちらになります。

;平成23年秋…割り算プログラム2
;呼び出し元のメインプログラム
MAIN START
RPUSH
LD GR1,=#0000 ;割られる数の上位語
LD GR2,=#054D ;その下位語で1357
LAD GR3,KEKKA ;結果領域先頭後
CALL BTOD2 ;プログラム2呼び出し
OUT KEKKA,LEN ;結果格納領域と文字数
RPOP
RET
KEKKA DS 5 ;結果格納領域
LEN DC 5 ;出力処理


;プログラム2
BTOD2
RPUSH
LD GR6,GR3
LAD GR7,4,GR3 ;結果格納領域の末尾アドレス
LAD GR3,UDAT ;除数の初期設定
LP2 CALL DIV ;プログラム1DIV呼び出し
OR GR2,=’0′ ;数字列に変換
ST GR2,0,GR6 ;10進数字1文字格納
CPL GR6,GR7 ;末尾まで処理したか
JZE FIN2
LAD GR6,1,GR6
LD GR1,GR4 ;割られる数の再設定
LD GR2,GR5 ;剰余をGR2へ
LAD GR3,2,GR3 ;割る数を2つ先へ
JUMP LP2
FIN2 RPOP
RET
UDAT DC 0
DC #2710
DC 0
DC #03E8
DC 0
DC #0064
DC 0
DC #000A
DC 0
DC 1

;プログラム1
DIV
PUSH 0,GR6
PUSH 0,GR7
LD GR6,GR1 ;割られる数の上位語
LD GR7,GR2 ;割られる数の下位語
LD GR1,=#FFFF ;商の初期化
LD GR2,=#FFFF
LP LD GR4,GR6 ;割られる数の上位語
LD GR5,GR7 ;割られる数の下位語
ADDL GR2,=1 ;商のカウントアップ
JOV ADJ1 ;桁上り処理へジャンプ
JUMP CONT ;割り算実行
ADJ1 ADDL GR1,=1 ;桁上り処理実行
CONT SUBL GR6,0,GR3 ;引き算しながら割り算していく
JOV FIN
SUBL GR7,1,GR3 ;引き算しながら割り算していく
JOV ADJ2
JUMP LP
ADJ2 SUBL GR6,=1 ;繰り下がり処理
JOV FIN
JUMP LP
FIN POP GR7
POP GR6
RET
END

最後にプログラム3です。
これは10ずつ割って行って工程が多いので、ステップ実行では無く、
一括実行で行います。

このシミュレーターの場合は、実行メニューから一括実行できます。

実行後の主記憶の状態です。


出力結果です。

トレースに使ったノートはこちらになります。

;平成23年秋…割り算プログラム3
;呼び出し元のメインプログラム
MAIN START
RPUSH
LD GR1,=#0000 ;割られる数の上位語
LD GR2,=#054D ;その下位語で1357
LAD GR3,KEKKA ;結果領域先頭後
CALL BTOD3 ;プログラム2呼び出し
OUT KEKKA,LEN ;結果格納領域と文字数
RPOP
RET
KEKKA DS 5 ;結果格納領域
LEN DC 5 ;出力処理

;プログラム3
BTOD3
RPUSH
LAD GR6,4,GR3 ;計算結果末尾のアドレス
LD GR7,GR3 ;計算結果先頭のアドレス
LAD GR3,DAT ;10で割って行く
LP3 CALL DIV ;プログラム1の呼び出し
OR GR5,=’0′ ;余りを数字列に変換
ST GR5,0,GR6 ;数字列を主記憶に格納する
CPL GR6,GR7 ;除算が先頭まで行ったか
JZE FIN3
LAD GR6,-1,GR6 ;除算を1つ前へ
JUMP LP3
FIN3 RPOP
RET
DAT DC 0
DC 10

;プログラム1
DIV
PUSH 0,GR6
PUSH 0,GR7
LD GR6,GR1 ;割られる数の上位語
LD GR7,GR2 ;割られる数の下位語
LD GR1,=#FFFF ;商の初期化
LD GR2,=#FFFF
LP LD GR4,GR6 ;割られる数の上位語
LD GR5,GR7 ;割られる数の下位語
ADDL GR2,=1 ;商のカウントアップ
JOV ADJ1 ;桁上り処理へジャンプ
JUMP CONT ;割り算実行
ADJ1 ADDL GR1,=1 ;桁上り処理実行
CONT SUBL GR6,0,GR3 ;引き算しながら割り算していく
JOV FIN
SUBL GR7,1,GR3 ;引き算しながら割り算していく
JOV ADJ2
JUMP LP
ADJ2 SUBL GR6,=1 ;繰り下がり処理
JOV FIN
JUMP LP
FIN POP GR7
POP GR6
RET
END

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
この記事を書くのに4時間かかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)

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

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

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

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

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

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

図形の回転の問題です。
設問1では漢数字の「五」を時計回りに回転させます。
このプログラムでは回転前の文字列が格納されている領域をBEFORE、回転後の領域をAFTERとしています。
GR1に回転前の先頭アドレス、GR2に回転後の結果格納領域の先頭アドレスを設定して、副プログラムを呼び出します。

回転前の先頭の語は、黒が1、白が0なので、1111111111111100となって、16進数ではFFFCです。それを16語分設定しました。

まず、設問1のプログラムを実行して見ます。

このようになりました。

プログラムとトレースのノートです。
プログラムは、メインプログラムから設問のプログラムとドット絵表示用のプログラムを呼び出しています。

;呼び出し元
MAIN START
RPUSH
LAD GR1,BEFORE ;回転前の領域の先頭アドレス
LD GR3,=16 ;ドット絵の表示用のループカウンタ
LOOPX
CALL DOT ;表示用プログラム「DOT」を呼び出す
LAD GR1,1,GR1 ;回転前の領域のアドレス+1で次の語へ
SUBL GR3,=1 ;処理待ち語数を減らす
JPL LOOPX ;16語まで繰り返す
OUT LINE,LLEN ;回転前と回転後のドット絵の区切り線
LAD GR1,BEFORE ;回転前の領域の先頭アドレス
LAD GR2,AFTER ;回転後の結果格納領域の先頭アドレス
CALL ROTATE ;設問1のプログラムを呼び出す
LAD GR1,AFTER ;回転処理後の先頭アドレスを移す
LD GR3,=16 ;ドット絵の表示用のループカウンタ
LOOPZ CALL DOT ;表示用プログラム「DOT」を呼び出す
LAD GR1,1,GR1 ;回転後の領域アドレス+1
SUBL GR3,=1
JPL LOOPZ
RPOP
RET


BEFORE DC #FFFC ;回転前の元のドット絵の先頭アドレス(1語目)
DC #FFFC
DC #FFFC
DC #0700
DC #0700
DC #0700
DC #FFFC
DC #FFFC
DC #FFFC
DC #071C
DC #071C
DC #071C
DC #FFFF
DC #FFFF
DC #FFFF
DC #0000


LINE DC ‘——————–‘
LLEN DC 20


AFTER
DC #0000 ;回転後の結果格納領域の先頭アドレス(1語目)
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
DC #0000
PRINT DS 16
LEN DC 16


;設問1のプログラム
ROTATE RPUSH
LD GR3,=16 ;処理する語数
LOOP1 LD GR4,=16 ;処理中の語のビット数
LD GR5,GR2 ;GR5←結果の領域のアドレス
LD GR6,0,GR1 ;GR6←元の図形の先頭語の内容
LOOP2 LD GR7,0,GR5 ;GR7←結果の領域の1語の内容
SRL GR7,1 ;結果のビットを右側へ
SLL GR6,1 ;「設問2」回転の変換をするビットを左にシフトで落とす
JOV ON ;1がこぼれたら分岐
JUMP CONT ;結果格納処理へ
ON OR GR7,=#8000 ;回転前の1を回転後へ転送
CONT ST GR7,0,GR5 ;処理した1語を結果の領域に格納
LAD GR5,1,GR5 ;結果格納領域を次の語に進める
SUBA GR4,=1 ;処理待ちビット数を減らす
JNZ LOOP2 ;処理中なら分岐
LAD GR1,1,GR1 ;次の語へ
SUBA GR3,=1 ;処理待ち語数を減らす
JNZ LOOP1 ;処理中の語があれば分岐
RPOP
RET


;ドット絵表示プログラム
DOT RPUSH
LAD GR6,PRINT ;表示用の領域の先頭アドレス
LD GR4,GR1 ;表示するドット絵の先頭アドレスを読み込む
LD GR3,=16 ;処理待ちビット数
LD GR4,0,GR4 ;表示する語を読み込む
LOOPY
SLL GR4,1 ;表示するビットを左シフトで落とす
JOV ONE ;1だったら分岐
LD GR5,=’◯’ ;0だったら白抜き丸
JUMP NEXT
ONE LD GR5,=’●’ ;1だったら黒抜き丸
NEXT
ST GR5,0,GR6 ;表示領域に丸を格納する
LAD GR6,1,GR6 ;表示領域を次の語へ
SUBL GR3,=1 ;処理待ちビットカウンタ
JPL LOOPY
OUT PRINT,LEN ;表示する
RPOP
RET
END

設問2では、プログラムの1部のシフトの向きを左から右シフトに変えます。
その場合での実行結果です。

設問3では、プログラムの一部を変えて、指定したビット分だけ回転させます。
ここでは回転させるビット数(n×n)を、5×5として見ました。

実行結果、プログラム、ノートです。

;設問3のプログラム
ROTATE RPUSH
LD GR3,=5 ;n(回転する部分)を5とする
ST GR3,N ;nを保存
LD GR4,GR3 ;GR4←n
LD GR5,GR1 ;GR5←元の図形のアドレス
LD GR6,GR2 ;GR6←結果の領域のアドレス
LD GR7,=16 ;回転しない部分の計算準備
SUBA GR7,GR3 ;GR7←16-n
SHIFT LD GR0,0,GR5 ;GR0←元の図形の1語の内容
SLL GR0,0,GR3 ;回転しない部分を左シフトで残す
ST GR0,0,GR6 ;結果の領域←GR0
LAD GR5,1,GR5 ;元の図形の1語のアドレス更新
LAD GR6,1,GR6 ;結果の領域の1語のアドレス更新
SUBA GR4,=1 ;n語処理済み?
JNZ SHIFT


COPY SUBA GR7,=1 ;残りの語の内容を結果の領域に複写
JMI LOOP1 ;処理待ち語がなくなったら分岐
LD GR0,0,GR5 ;回転しない語を読み込む
ST GR0,0,GR6 ;結果領域へ格納
LAD GR5,1,GR5
LAD GR6,1,GR6
JUMP COPY
N DS 1
LOOP1 LD GR4,N

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
この記事を書くのに丸2日かかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)


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

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

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

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

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

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

この問題は、浮動小数点の加算を扱っています。
指数の大きい方に合わせて加算処理を行い、計算結果を正規化して主記憶に格納します。
加算される方がX、加算する方がYです。

Xを-0.1×2^2 →
10000000100000011000000000000000

Yを0.11×2^3 →
00000000100000101100000000000000

という具体例を元にトレースします。

主記憶に、X、Yの具体例と、結果格納用のZが入りました。

GR1、GR2、GR3に具体例と計算格納結果のアドレスが入りました。

ここから副プログラムのFADDにを呼び出します。
スタックに結果格納の先頭アドレスが退避されました。

GR4にXの符号部、指数部が入りました。

AND演算で指数部だけ取り出しました。

GR5にYの符号部、指数部が入りました。
AND演算で指数部だけを取り出しました。
(値は変わらず)

GR6にXの仮数部が読み込まれました。

GR7にYに仮数部が読み込まれました。

GR3にXの指数部Exが読み込まれました。

GR4のEx、GR5のEyが比較されました。

指数部の大きい方であるE7がGR4に読み込まれました。

GR5にExとEyの差が求まりました。

GR6に指数部を合わせるために、Xの仮数部であるMxが1ビット右シフトされました。

Xの符号がプラスかマイナスかチェックします。

Yの符号がプラスかマイナスかチェックします。

Yの仮数部のMyが読み込まれました。

MyマイナスMxが求まりました。

仮数部がゼロかチェックします。
ゼロでは無いです。
仮数部がマイナスなので、正規化済であり、終了処理に分岐します。

退避していた計算結果の先頭アドレスがGR3に戻りました。

計算結果の符号部と指数部、仮数部を格納しました。

トレースに使ったノートです。

プログラムはこちらになります。

MAIN START
RPUSH
LAD GR1,X
LAD GR2,Y
LAD GR3,Z
CALL FADD
RPOP
RET
X DC #8081 ;Xの16進数先頭、符号部、指数部
DC #8000 ;Xの16進数先頭+1、仮数部
Y DC #0082 ;Yの16進数先頭、符号部、指数部
DC #C000 ;Yの16進数先頭+1、仮数部
Z DS 2 ;計算結果2語分


FADD RPUSH ;Z←X+Y
PUSH 0,GR3 ;結果Zの格納領域の先頭番地を退避
LD GR4,0,GR1 ;Xの先頭を読み込む
AND GR4,=#00FF ;Ex:xの指数
LD GR5,0,GR2 ;Yの先頭を読み込む
AND GR5,=#00FF ;Ey:yの指数
LD GR6,1,GR1 ;Mx:Xの仮数(2語目)
LD GR7,1,GR2 ;My:Yの仮数(2語目)

;加算前の準備(指数を揃える)
;GR4←MAX(Ex,Ey)大きい方がGR4に入る
;GR6←調整済Mx , GR7←調整済My
LD GR3,GR4 ;Exを読み込む
CPL GR4,GR5 ;ExとEyどっちが大きいか比べている
JZE MADD ;Ex=Eyの場合。指数の調整が不要な場合の分岐命令
JMI BIGEY ;Ex=0,Y<=0の場合
SUBL GR5,GR7 ;Mz←調整済みMx-調整済My
JUMP SCHECK ;加算終了後の符号部チェックへ分岐

;Xがマイナスの時
XMINUS LD GR2,0,GR2 ;Yの符号の検査
JMI YMINUS ;Yもマイナスだった時の分岐
LD GR5,GR7 ;Myを読み込む
SUBL GR5,GR6 ;Y-X
JUMP SCHECK ;加算終了後の符号部チェックへ分岐

;Yがマイナスの時の処理
YMINUS OR GR4,=#8000 ;Szに符号部を設定

;加算実行
ADDMXY LD GR5,GR6 ;Mxを読み込む
ADDL GR5,GR7 ;Mz←調整済Mx + 調整済My
JOV ADJST ;桁上りがある時の正規化
JUMP NORM ;加算後の正規化へ
SCHECK JOV NEGMZ ;Mzの符号を検査
JUMP NORM ;加算後の正規化へ
NEGMZ OR GR4,=#8000 ;Szに符号部を設定
XOR GR5,=#FFFF ;Mz←-Mz
ADDL GR5,=1 ;Mz←-Mz完了

;加算結果の正規化
NORM LD GR5,GR5 ;仮数部のゼロチェック
JNZ LOOP ;ゼロ以外は分岐
LD GR4,=0 ;Szの符号
JUMP FIN
LOOP LD GR5,GR5 ;正規化完了??
JMI FIN ;マイナスだったら仮数部の最上位が1だから正規化終了
SLL GR5,1 ;左に詰めて正規化へ
SUBL GR4,=1 ;正規化処理分の指数部を1つ減らす
JUMP LOOP ;正規化出来るまで繰り返す

;桁上りの処理
ADJST SRL GR5,1 ;加算結果の仮数部を1つ右へ
OR GR5,=#8000 ;Mzの最上位ビットを1に設定
ADDA GR4,1 ;桁上り分
FIN POP GR3
ST GR4,0,GR3 ;結果Zの格納(符号部、指数部)
ST GR5,1,GR3 ;結果Zの格納(符号部、指数部)
RPOP
RET
END

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
この記事の解説を理解するのに3時間以上かかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)

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

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

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

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

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


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

この問題はビット列を反転するプログラムを使って、その語内のビットや連続したビット、ビットの部分のみの反転をします。

図によるイメージが大事だと思うので、トレースに使ったノートを設問ごとに掲載します。まずこちらのトレースに使ったノート2ページ分をご覧下さい。

設問1では、プログラム1REVRSを使って、具体例としてビット列αを
実行前:「1011001111010001」
実行後:「1000101111001101」
と反転します。

レジスタはGR1にαの先頭アドレスを設定します。
メインプログラムからREVRSを呼び出します。

それでは一つずつ丁寧にトレースしていきます。
まず、主記憶のALPHAの所に、元のビット列αが入ります。

GR1にビット列αが格納されているアドレスが入りました。

プログラム1のREVRSを呼び出します。
反転するビットの結果用につかうGR4が初期化されました。

ループカウンタに使う処理待ちビット数の15がGR2に入りました。

元のビット列がGR3に退避されました。

ループ1回目
GR4が左シフトされましたが0なので変わりません。

GR3が右シフトされました。
OFが1になって末尾が1だった為、オーバーフローしました。

オーバーフローしたのでラベル「ON」に分岐しました。

16進数「0001」である、0000000000000001を結果用のGR4に加えます。

ループカウンタをデクリメントしました。
残14

ループ2回目

結果用のGR4が左シフトされました。

元のビット列が退避されたGR3が右シフトされました。

GR2のカウンタがデクリメントされました。
残13

ループ3回目

結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。

GR2のカウンタがデクリメントされました。
残12

ループ4回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。

GR2のカウンタがデクリメントされました。
残11

ループ5回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。
OFが1になり、ONに分岐します。

結果用のGR4に1加わりました。

GR2のループカウンタがデクリメントされました。
残10

ループ6回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。

GR2のループカウンタがデクリメントされました。
残9

ループ7回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。
OFが1になり、ONに分岐します。

結果用のGR4に1加わりました。

GR2のループカウンタがデクリメントされました。
残8

ループ8回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。
OFが1になり、ONに分岐します。

結果用のGR4に1加わりました。

GR2のループカウンタがデクリメントされました。
残7

ループ9回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。
OFが1になり、ONに分岐します。

結果用のGR4に1加わりました。

GR2のループカウンタがデクリメントされました。
残6

ループ10回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。
OFが1になり、ONに分岐します。

結果用のGR4に1加わりました。

GR2のループカウンタがデクリメントされました。
残5

ループ11回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。

GR2のループカウンタがデクリメントされました。
残4

ループ12回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。

GR2のループカウンタがデクリメントされました。
残3

ループ13回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。
OFが1になり、ONに分岐します。

結果用のGR4に1加わりました。

GR2のループカウンタがデクリメントされました。
残2

ループ14回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。
OFが1になり、ONに分岐します。

結果用のGR4に1加わりました。

GR2のループカウンタがデクリメントされました。
残1

ループ15回目
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。

GR2のループカウンタがデクリメントされました。
残0

ループ16回目(最後です。)
結果用のGR4が左シフトされました。

元のビット列退避用のGR3が右シフトされました。
OFが1になり、ONに分岐します。

結果用のGR4に1加わりました。

GR2のループカウンタがデクリメントされました。
残-1

マイナスになったのでループを抜け、FIN2に飛びます。
主記憶のαに反転したビットが格納されました。

こちらがプログラム1のコードになります。
尚、「1011001111010001」は16進数にすると
「#B3D1」になりますので、そのように表記しております。

MAIN START ;メインの始まり
RPUSH
LAD GR1,ALPHA ;αの先頭アドレスをGR1に読み込む
CALL REVRS ;プログラム1を呼び出す
RPOP
RET

ALPHA DC #B3D1 ;αにビット列を格納する

REVRS ;プログラム1
RPUSH
LD GR4,=0 ;結果のビット列を初期化
LAD GR2,15 ;ループカウンタ
LD GR3,0,GR1 ;GR3←ビット列
LOOP SLL GR4,1 ;結果のビット列を左シフト
SRL GR3,1 ;元のビット列を右シフト
JOV ON ;元のビット列の末尾が1だったらONに分岐する
JZE FIN1 ;元のビット列の残りのビットはすべてゼロ
JUMP OFF ;元のビット列の末尾がゼロだった時の分岐
ON OR GR4,=#0001 ;結果のビット列に1を加える
OFF SUBA GR2,=1 ;ループカウンタをデクリメントする
JMI FIN2 ;16ビット処理済み
JUMP LOOP ;LOOPへ繰り返し処理
FIN1 SLL GR4,0,GR2 ;結果のビット列を残りのビット数だけシフト
FIN2 ST GR4,0,GR1 ;結果のビット列を元のビット列に格納(上書き)する
RPOP
RET
END

では、設問2に行きます。
連続した語の並びを逆転するプログラムです。
まずノートをご覧下さい。

例として1語目から5語目までの連続した語を交換するとします。
1語目は1、2語目は2…5語目は5とします。

それではプログラム2のトレースをします。
(プログラム1のトレースは部分的に省略して、プログラム2は丁寧にトレースをします。)

まず主記憶でαの先頭アドレスからそれぞれ、1、2、3、4、5が格納されています。

GR1、GR2にαの先頭アドレス、語数の5語が設定されました。

αの先頭のアドレスがGR3にコピーされ、語数がGR4に入りました。

語数を末尾アドレスを指し示す為の準備として1減算します。(先頭アドレスがα+0、末尾がα+4になる為)

末尾のアドレスが入りました。

ループ LOOP1 1回目
GR5に1語目の「1」が入りました。
「0000000000000001」

GR6に5語目の「5」が入りました。
「0000000000000101」

主記憶のαの末尾に「1」が格納されました。

主記憶のαの先頭に「5」が格納されました。

「α+0」が「α+1」を指し、
「α+4が「α+3」」を指しました。

ループ LOOP1 2回目
「2」がGR5のα+1に入りました。

「4」がGR6のα+3に入りました。

「2」がα+3に格納されました。

「4」がα+1に格納されました。

「α+1」が「α+2」を、
「α+3」が「α+2」を指しました。

ループを抜けて次のループに入ります。
ループ LOOP2 1回目
プログラム1のREVRSを呼び出します。
先頭アドレスα+0に格納された「5」(0000000000000101)がGR3に入りました。

GR4に反転された結果が求まりました。(1010000000000000)
(この処理は以降のトレースでは省略)

その結果が主記憶α+0に格納されました。

反転の対象の語がα+1になりました。

反転する語の処理待ちが4になりました。

ループ LOOP2 2回目
反転するビットの「4」(0000000000000100)が入りました。

反転してビットが「0010000000000000」になってα+1に格納されました。

反転の対象の語がα+2になりました。

反転する語の処理待ちが3になりました。

ループ LOOP2 3回目
反転するビットの「3」(0000000000000011)が入りました。

反転してビットが「1100000000000000」になってα+1に格納されました。

反転の対象の語がα+3になりました。

反転する語の処理待ちが2になりました。

ループ LOOP2 4回目
反転するビットの「2」(0000000000000010)が入りました。

反転してビットが「0100000000000000」になってα+1に格納されました。

反転の対象の語が末尾のα+4になりました。

反転する語の処理待ちが1になりました。

ループ LOOP2 5回目
反転するビットの「1」(0000000000000001)が入りました。

反転してビットが「0100000000000000」になってα+1に格納されました。

終了しました。

こちらがプログラム2のコードになります。


MAIN START ;メインの始まり
RPUSH
LAD GR1,ALPHA ;αの先頭アドレスをGR1に読み込む
LD GR2,=5 ;全部で5語とする
CALL LREVRS ;プログラム2を呼び出す
RPOP
RET
;αにビット列を格納する
ALPHA DC #0001 ;1語目
DC #0002 ;2語目
DC #0003 ;3語目
DC #0004 ;4語目
DC #0005 ;5語目

LREVRS
RPUSH
LD GR3,GR1 ;αの先頭アドレスを読み込む
LD GR4,GR2 ;語数を読み込む。処理待ち語数カウンタ
SUBA GR4,=1 ;末尾アドレス用に減算
JZE LOOP2 ;単語数が1だったらREVRSを呼び出す
ADDA GR4,GR1 ;末尾アドレスを指す
LOOP1 LD GR5,0,GR3 ;先頭の語から格納する
LD GR6,0,GR4 ;末尾の語から格納する
ST GR5,0,GR4 ;交換処理
ST GR6,0,GR3 ;交換処理
LAD GR3,1,GR3 ;先頭の語のアドレスに1を加える
LAD GR4,-1,GR4 ;末尾の語のアドレスに1を減じる
CPA GR3,GR4 ;交換に使うアドレスの大小を比較
JMI LOOP1 ;先頭の語の方が小さかったら繰り返し処理に戻る
LOOP2 CALL REVRS ;プログラム1を呼び出す
LAD GR1,1,GR1 ;ビットを反転するアドレスを次の語へ進める
SUBA GR2,=1 ;処理待ち語数カウンタをデクリメントする
JNZ LOOP2 ;反転する語が残っている場合は繰返しに戻る
FIN3 RPOP
RET
REVRS ;プログラム1
RPUSH
LD GR4,=0 ;結果のビット列を初期化
LAD GR2,15 ;ループカウンタ
LD GR3,0,GR1 ;GR3←ビット列
LOOP SLL GR4,1 ;結果のビット列を左シフト
SRL GR3,1 ;元のビット列を右シフト
JOV ON ;元のビット列の末尾が1だったらONに分岐する
JZE FIN1 ;元のビット列の残りのビットはすべてゼロ
JUMP OFF ;元のビット列の末尾がゼロだった時の分岐
ON OR GR4,=#0001 ;結果のビット列に1を加える
OFF SUBA GR2,=1 ;ループカウンタをデクリメントする
JMI FIN2 ;16ビット処理済み
JUMP LOOP ;LOOPへ繰り返し処理
FIN1 SLL GR4,0,GR2 ;結果のビット列を残りのビット数だけシフト
FIN2 ST GR4,0,GR1 ;結果のビット列を元のビット列に格納(上書き)する
RPOP
RET
END

では、最後に設問3に行きます。
ビット列の中のある部分のみを反転するプログラムです。
具体例として、ビット列αを
10110011「110」10001の「110」の部分を「011」と反転して、
10110011「011」10001にします。
このビット列の先頭アドレスをGR1に設定します。
pが8でqが3になり、それぞれGR2、GR3に接てします。

まずノートをご覧下さい。

では、トレースをして行きます。
GR1からGR3までの設定です。

GR4に元のビット列が入りました。

プログラム1のREVRSを呼び出します。
ビットが反転されて主記憶に格納されました。

プログラム3に戻ります。
反転されたビット列がGR5に入りました。

反転する3ビット分の調整をします。
16がGR6に入りました。

16-3で13が求まりました。

反転されたビットが8ビット分右シフトされて右端に移動しました。

反転されたビットが13ビット左にシフトされました。

反転された部分が8ビット右にシフトされました。

マスクが準備されます。#8000が入りました。

算術シフトされ、空いたビットに1が入りました。

マスクが右に8ビット移動しました。

排他的論理はでビットが反転されました。

GR4とGR6の論理積をGR6に格納しました。
GR4「1011001111010001」
GR6「1111111100011111」
AND「1011001100010001」

その演算結果に反転した部分を足しこみます。
GR6「1011001100010001」
GR5「0000000001100000」
OR 「1011001101110001」

結果をαに格納しました。

こちらがプログラム3のコードになります。

MAIN START ;メインの始まり
RPUSH
LAD GR1,ALPHA ;αの先頭アドレスをGR1に読み込む
LD GR2,=8 ;先頭を0ビットとして8ビット目から反転の対象(p)
LD GR3,=3 ;3ビット分が反転の対象(q)
CALL PREVRS ;プログラム2を呼び出す
RPOP
RET
;αにビット列を格納する
ALPHA DC #B3D1 ;1011 0011 「110」1 0001
PREVRS
RPUSH
LD GR4,0,GR1 ;ビット列を保存
CALL REVRS ;ビット列のビットの並びの逆転
LD GR5,0,GR1 ;GR5←逆転したビット列
LD GR6 ,=16
SUBA GR6,GR3 ;GR6←16-q
SRL GR5,0,GR2 ;逆転した部分ビット列αを8ビットシフトして右端に移動
SLL GR5,0,GR6 ;逆転した部分ビット列αを13ビットシフトして左端に移動
SRL GR5,0,GR2 ;逆転した部分ビット列αをpビット右に移動
LD GR6,=#8000 ;逆転に使うマスク作成の準備
SRA GR6,-1,GR3 ;算術シフトによるマスク作成
SRL GR6,0,GR2 ;マスクをpの分だけ右シフト
XOR GR6,=#FFFF ;マスクを逆転対象の3ビット分を1にする為排他的論理和を取る
AND GR6,GR4 ;元のビット列中の部分ビット列αにゼロを設定
OR GR6,GR5 ;反転した部分を足しこむ
ST GR6,0,GR1 ;結果を格納する
RPOP
RET


REVRS ;プログラム1
RPUSH
LD GR4,=0 ;結果のビット列を初期化
LAD GR2,15 ;ループカウンタ
LD GR3,0,GR1 ;GR3←ビット列
LOOP SLL GR4,1 ;結果のビット列を左シフト
SRL GR3,1 ;元のビット列を右シフト
JOV ON ;元のビット列の末尾が1だったらONに分岐する
JZE FIN1 ;元のビット列の残りのビットはすべてゼロ
JUMP OFF ;元のビット列の末尾がゼロだった時の分岐
ON OR GR4,=#0001 ;結果のビット列に1を加える
OFF SUBA GR2,=1 ;ループカウンタをデクリメントする
JMI FIN2 ;16ビット処理済み
JUMP LOOP ;LOOPへ繰り返し処理
FIN1 SLL GR4,0,GR2 ;結果のビット列を残りのビット数だけシフト
FIN2 ST GR4,0,GR1 ;結果のビット列を元のビット列に格納(上書き)する
RPOP
RET
END

今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
この記事を書くのに3時間以上かかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)


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

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