平成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時間以上かかったので、
誰も見ていなかったら泣いちゃいます( ;∀;)
どなたか見ている人いますか?いたら手を振って下さい(=^・^=)


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

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

平成21秋 問12 アセンブラ のプログラミング(コメント付き)

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

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

この問題は平成25年春の過去問と似ています。

この問題は、ビット列Aのある部分をビット列Bに置換するプログラムです。
具体例によると、ビット列Aの55ビット目(3語目の7ビット)から66ビット目(4語目の2ビット)までをB列に変えます。55ビット目をpとしてGR2に、B列の置換対象の12ビットをqとしてGR3に設定します。
ビット列Aの先頭アドレスはGR1に設定します。

ビット列Aの対象区間は、先頭を0ビットとして55ビットからなので、1語を16ビットとして、3語目の7ビット目~4語目の2ビット目までです。
ビット列Aの3語目、4語目を仮に「0101010101010101」
「0101010101010101」とします。

これをビット列Bである「1011000111010000」置き換えるので、ビット列Aは
操作前A:「0101010101010101」
     「0101010101010101」
操作後A:「0101010101100011」
     「1010010101010101」
と置換されます。

プログラムはこちらになります。
H21A_REPLACEという名前で作りました。
シミュレーターと過去問を解くまでの勉強に使った参考書はこちらです

先ほど2進数で書いた所は、全て16進数に直してプログラミングしています。
例えばビット列Aの「0101010101010101」は「#55」にしています。ビット列Aの先頭アドレスは「ARETSU」というラベルを貼りました。
そこに0語目~5語目までを格納しました。

では、動かして見ます。
シミュレーターを使って、少しくどいかもしれませんが、丁寧目にトレースしていきます。

まず、主記憶ですが、ビット列Aが入っているARETSUは、このようになっています。
先頭が#1020で、置換対象である3語目が#1023、4語目が#1024です。

レジスタはビットの状態が分かるように2進数表記にします。

GR1にビット列Aの先頭アドレスが入りました。

GR2に置換対象位置である55(0ビットを先頭として56番目)が入りました。

GR3に置換するビットの長さである12が入りました。

GR0にビット列Bが入りました。

副プログラム問題文のREPLACEを呼び出しました。

ビット位置の55をGR4に読み込みました。

55は何語目か求めるために、1語16なので55を16で割りました。
その為にSRL 4しています。55は3語目と求まりました。
(0語目、1語目、2語目、3語目)

GR1に3語先のアドレスを設定しました。

55は3語目の中で7ビット目だということが#000FとANDを取ることによって
求まりました。

GR4に、16が入りました。3語目の7ビット以降のビット数を求めるため、
16から7を減算します。

GR4に16から7を引いて、9と求まりました。

GR5にビット列Bを退避しました。
これはビット列Aの4語目の置換に使います。

GR6に置換に使うマスクを作る為に#8000が入りました。

マスクを作るのに論理シフトします。シフトするビット数を
12から1を引いて11と求まりました。

注意して頂きたいのが次に行うシフトは「算術シフト」です。
つまり、空いた所に先頭ビットと同じビットが入ります。

GR6が、#8000である「1000000000000000」を11ビット右に算術シフトして、「1111111111110000」になりました。

今作ったマスクを、GR7に退避します。
これはビット列Aの4語目の置換の作業に使うマスクになります。

GR0で、ビット列Bを右に7ビットシフトしました。

GR6で、マスクを右に7ビットシフトしました。

GR5で、4語目用にビット列Bを左に9ビット論理シフトしました。

GR7で4語目用にマスクを左に9ビットシフトしました。

GR2にビット列Aの3語目を読み込みました。

GR6「0000000111111111」にGR2の「0101010101010101」のANDを取りました。
結果は「0000000101010101」です。

GR2「0101010101010101」とGR6「0000000101010101」のXOR排他的論理和を取りました。
結果は「0101010000000000」です。

GR2に右シフトしたビット列BであるGR0「0000000101100011」を足しこみます。
結果は「0101010101100011」になります。

主記憶のビット列Aの3語目に格納されました。

GR2にビット列Aの4語目が読み込まれました。

GR7に「1110000000000000」とGR2「0101010101010101」のANDを取りました。結果は「0100000000000000」になりました。

GR2に「0101010101010101」とGR7の「0100000000000000」の排他的論理和XORを取ります。結果は「0001010101010101」になりました。

GR2に「0001010101010101」と左シフトしたビット列Bの「1010000000000000」のORを取ります。
結果は「1011010101010101」になります。

ビット列Aの4語目に格納されました。

トレースは以上になります。
今度受けるので、自分の勉強になりました。
どなたかのお役に立てたらうれしいです。
誰か見ている人いますか?いたら手を振って下さい(=^・^=)

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

<<プログラム>>

H21A START
RPUSH
LAD GR1,ARETSU
LD GR2,=55 ;pの位置55
LD GR3,=12 ;qの長さ
LD GR0,=#B1D0 ;B列に置換語を読み込む
CALL REPLACE
RPOP
RET
ARETSU DC #0000 ;A列0語目
DC #0000
DC #0000
DC #5555 ;A列3語目(置換対象)
DC #5555 ;A列4語目(置換対象)
DC #0000


REPLACE
RPUSH
LD GR4,GR2 ;GR4←p置換開始位置を設定
SRL GR4,4 ;GR4←p/16 A列の先頭語から何語後ろかを求めている
ADDA GR1,GR4 ;GR1を置換対象後(この場合第3語)に位置付ける
AND GR2,=#000F ;第3語目の何ビットから置換するのか(7ビット)求めている
LD GR4,=16 ;第3語で置換する分のビット数の計算の為
SUBA GR4,GR2 ;16-7で3語目の対象ビットは9ビット
LD GR5,GR0 ;置換するB列を退避
LD GR6,=#8000 ;置換する時に使うマスクを作る
SUBA GR3,=1 ;マスクを作る時にシフトするビットの調整
SRA GR6,0,GR3 ;注意!SRAで「算術」シフトだから空いた所に1が入る
LD GR7,GR6 ;マスクを退避する
SRL GR0,0,GR2 ;置換するB列を7ビット右にシフトする
SRL GR6,0,GR2 ;置換に使うマスクを7ビットシフトする
SLL GR5,0,GR4 ;ビット列Aの4語目の置換に使用
SLL GR7,0,GR4 ;ビット列Aの4語目の置換に使用
LD GR2,0,GR1 ;ビット列Aの3語目を読み込む
AND GR6,GR2 ;ビット列Aの置換対象の前の部分をマスクで0にする
XOR GR2,GR6 ;排他的論理和で置換対象の部分を0にする
OR GR2,GR0 ;ビット列Bを足しこむ
ST GR2,0,GR1 ;ビット列Aの3語目に格納する
LD GR2,1,GR1 ;ビット列Aの4語目を読み込む
AND GR7,GR2 ;ビット列Aの置換対象の語の後ろの部分をマスクで0にする
XOR GR2,GR7 ;排他的論理和で置換対象の部分を0にする
OR GR2,GR5 ;ビット列Bの退避しておいた部分を足しこむ
ST GR2,1,GR1 ;ビット列Aの4語目に格納する
RPOP
RET
END

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

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

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

平成21春 問12 アセンブラ のプログラミング(コメント付き)

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

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

基本情報技術者試験がコロナで中止や延期になり、中々プログラミングのスキルも身に付かずに悶々としていたので、思い切って過去問を頼りにプログラミングをして見ることにしました。第一回は平成21年春の問題です。

プログラムMULSは、被乗数(かけ「られる」数)32ビットと、乗数(かける数)16ビットの計算をして、その結果である積32ビットを返します。
被乗数と乗数のどっちがどっちか分からなくなりそうなので、被乗数のラベルをかけ「られる」数から、RARERU、乗数をKERU、積をSEKIと名付けてプログラミングしました。GR1にはRARERUの先頭アドレス、GR2にはRERUそのもの、GR3にはSEKIの先頭アドレスを設定しています。

具体例として、被乗数RARERUの上位語には16進数で「2」、下位語には16進数で「6」、乗数KERUには16進数「3」とします。
プログラミングの名前はH21SMULSとします。

プログラミングは下記になります。
シミュレーターと過去問を解くまでの勉強に使った参考書はこちらです

<<プログラミング>>
H21SMULS START
RPUSH
LAD GR1,RARERU ;かけ「られる」数の先頭アドレスをGR1
LD GR2,KERU ;かける数自体をGR2
LAD GR3,SEKI ;積の先頭アドレスをGR3
LAD GR6,0 ;積 上位語の初期化
LAD GR7,0 ;積 下位語の初期化
LD GR4,0,GR1 ;被乗数 上位語の取出し
LD GR5,1,GR1 ;被乗数 下位語の取出し
LP SRL GR2,1 ;乗数を1ビット右にシフト
JOV ADD32 ;「a」最下位桁がゼロかどうかで分岐する
JZE FIN ;全部乗数が0だったら押しマシ
JUMP NEXT ;加算処理をスキップ(下位桁が0だった場合)
ADD32 ADDL GR6,GR4 ;被乗数の上位語を足す
ADDL GR7,GR5 ;被乗数の下位語を足す
JOV ADJ1 ;「b」下位語の加算で桁上りした場合に分岐
JUMP NEXT ;下位語の桁上げが無いので桁上げ処理をスキップ
ADJ1 ADDL GR6,=1 ;桁上げ処理(下位桁オーバーフローで上位桁へ)
NEXT SLL GR4,1 ;被乗数の上位語を1ビット左にシフト
SLL GR5,1 ;「c」被乗数の下位語を1ビット左にシフト
JOV ADJ32 ;左シフトによって桁上りした下位語の分を上位語へ
JUMP LP ;次の計算処理へ
ADJ32 OR GR4,=1 ;上位語に下位語からの桁上りを足しこむ
JUMP LP ;次の計算処理へ
FIN ST GR6,0,GR3 ;乗算結果(上位語)の格納
ST GR7,1,GR3 ;乗算結果(下位語)の格納
RPOP
RET
RARERU DC #2
DC #6
KERU DC #3
SEKI DS 2
END

それでは動かして見ます。


GR1、GR2、GR3にそれぞれ被乗数先頭アドレス、乗数、積の先頭アドレスが入り、
GR4に被乗数の上位語、GR5に被乗数の下位語、GR6、GR7に積の値のゼロによる初期化が入りました。

ループ1回目
GR2が1ビット右シフトしました。また、OFが1なので、オーバーフローしました。

GR6、GR7に被乗数の上位語下位語が足されました。

GR4、GR5に被乗数が左に1ビットされて2倍になりました。

ループ2回目

GR2に乗数が右に1ビットされ、OF、ZFが1になりました。

GR6、GR7に被乗数の上位語下位語とシフトした分が足されました。

GR4、GR5に被乗数が左に1ビットされて2倍になりました。

ループ3回目
ゼロフラグが1になりました。

では次に、プログラム2のMULを作ります。
名前をH21SMULにします。

プログラムMULは、被乗数(かけ「られる」数)32ビットと、乗数(かける数)32ビットの計算をして、その結果である積32ビットを返します。
被乗数のラベルをかけ「られる」数から、RARERU2、
乗数をKERU2、積をSEKI2と名付けてプログラミングしました。
GR1にはRARERU2の先頭アドレス、GR2にはRERU2の先頭アドレス、GR3にはSEKI2の先頭アドレスを設定しています。
また、領域SVは、計算結果の退避につかいます。

具体例として、被乗数RARERU2の上位語には16進数で「2」、下位語には16進数で「6」、乗数KERU2には上位語「3」、下位語「5」とします。
プログラミングの名前はH21SMULとします。

プログラミングは下記になります。
先ほどのH21SMULSを副プログラムとして呼び出して使用します。
その際の渡す値は主プログラムから渡されるので、副プログラムの方は消しました。

<<プログラミング>>
H21SMUL START
RPUSH
LAD GR1,RARERU2 ;かけ「られる」数の先頭アドレスをGR1
LAD GR2,KERU2 ;かける数自体をGR2
LAD GR3,SEKI2 ;積の先頭アドレスをGR3
PUSH 0,GR3 ;積の上位語のアドレスをスタックに積む
PUSH 0,GR2 ;乗数の上位語のアドレスをスタックに積む
LD GR2,1,GR2 ;乗数の下位語を読み込む
CALL H21SMULS ;プログラム1を呼ぶ 被乗数×乗数下位語→積A
POP GR2 ;スタックから乗数の先頭アドレスを取り出す
LD GR2,0,GR2 ;「d」乗数の上位語を読み込む
LAD GR3,SV ;結果(積B)の格納先として作業領域SVの先頭アドレスを設定
CALL H21SMULS ;プログラム1を呼ぶ 被乗数×乗数上位語→積B
LD GR6,1,GR3 ;「e」積Bの下位語であるSV+1の値を読み込む
POP GR3 ;積Aの上位語のアドレスを取り出す
ADDL GR6,0,GR3 ;積Aの上位語と積Bの下位語を加算
ST GR6,0,GR3 ;加算結果をGR3に格納
RPOP
RET
SV DS 2 ;積Bの2語分(結果退避用)
RARERU2 DC #2 ;被乗数(かけられる数)上位語
DC #6 ;被乗数(かけられる数)下位語
KERU2 DC #3 ;乗数(かける数)上位語
DC #5 ;乗数(かける数)下位語
SEKI2 DS 2 ;積の2語分


H21SMULS
RPUSH
LAD GR6,0 ;積 上位語の初期化
LAD GR7,0 ;積 下位語の初期化
LD GR4,0,GR1 ;被乗数 上位語の取出し
LD GR5,1,GR1 ;被乗数 下位語の取出し
LP SRL GR2,1 ;乗数を1ビット右にシフト
JOV ADD32 ;「a」最下位桁がゼロかどうかで分岐する
JZE FIN ;全部乗数が0だったら押しマシ
JUMP NEXT ;加算処理をスキップ(下位桁が0だった場合)
ADD32 ADDL GR6,GR4 ;被乗数の上位語を足す
ADDL GR7,GR5 ;被乗数の下位語を足す
JOV ADJ1 ;「b」下位語の加算で桁上りした場合に分岐
JUMP NEXT ;下位語の桁上げが無いので桁上げ処理をスキップ
ADJ1 ADDL GR6,=1 ;桁上げ処理(下位桁オーバーフローで上位桁へ)
NEXT SLL GR4,1 ;被乗数の上位語を1ビット左にシフト
SLL GR5,1 ;「c」被乗数の下位語を1ビット左にシフト
JOV ADJ32 ;左シフトによって桁上りした下位語の分を上位語へ
JUMP LP ;次の計算処理へ
ADJ32 OR GR4,=1 ;上位語に下位語からの桁上りを足しこむ
JUMP LP ;次の計算処理へ
FIN ST GR6,0,GR3 ;乗算結果(上位語)の格納
ST GR7,1,GR3 ;乗算結果(下位語)の格納
RPOP
RET
END

それでは動かして見ます。
GR1、GR2、GR3にそれぞれ被乗数、乗数、積のアドレスが入りました。

スタックにGR3、GR2にそれぞれ設定したアドレスが積まれました。

GR2に乗数(かける数)の下位語である「5」が入りました。

副プログラムMULSを呼び出しました。

GR6、GR7が積の計算結果の初期化されました。

GR4、GR5に被乗数の上位語、下位語が入りました。

下位語積Aのループ1回目
GR2に乗数かける数が右シフトされました。

GR6、GR7に、計算結果が加算されました。

GR4、GR5で被乗数かけられる数の上位語、下位語が左シフトされました。

下位語積Aのループ2回目

GR2が右シフトされました。
下位桁が0なので、加算はスキップします。

GR4、GR5が左シフトされました。

下位語積Aのループ3回目
GR2で乗数が右シフトしました。
オーバーフローしたので、下位桁が1です。

GR6、GR7で、積の計算結果に加算されました。

GR4、GR5で被乗数(かけられる数)をシフトします。

呼び出し元に戻ります。
GR2に、乗数(かける数)の上位語(先頭)アドレスが入ります。

GR2に乗数の上位語が入ります。

GR3に計算結果退避領域の先頭アドレスが入ります。

副プログラムが呼び出されました。

以下、重複はなるべく避けてトレースします。

上位語積Bのループ1回目

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


計算結果が加算されました。

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

上位語積Bのループ2回目
乗数が右シフトされました。

計算結果に足しこまれました。

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

呼び出し元に戻りました。

GR6にGR3(積Bの計算結果)の下位語が入りました。

GR3にSEKI2の先頭アドレス(積Aの計算結果上位語を指す)が入りました。

GR6に演算結果が求められました。

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

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

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

アセンブラCASL2でクール、クーラー、クーリッシュな暗号

この記事では、アセンブラ言語の「配列や文字列の扱い」について簡単な例題で学べます。配列の添字と文字を対応づけている、簡易的な暗号文です。

<<関連記事>>

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

少し前に竹内涼真さんが出演されているアイスのCMを
見ました。
「クール、クーラー、クーリッシュ」っていうアレです。
TVのCMは、聴いているうちに、耳に残る上、
あのアイスの広告が、通勤電車にもあったので、
時々、「クール、クーラー、クーリッシュ」と、
独り言を言ってしまいます。

そこで、アイスをCOMET2のアセンブラ、CASL2で作ろうと思いました。
この様な配列があります。

0番目はA、1番目はB、2番目はC…という風に
暗号を解読するような感じで、数値を文字に当てはめていきます。
例えば、ICEの「I」は8、「C」は2、「E」は4になります。

なので、最初は「8」を入力します。

すると、「8」は文字コードで「38」なので、
レジスタに38と入ります。

GR2に38と入りました。
これを8にする為には、
文字コード30の「0」を使って減算します。

GR2が8になりました。

今度はこの8をアイスの「I」に変換します。
配列MOJIの先頭アドレスをGR3に入れます。

GR3には配列MOJIの先頭アドレスが
ここでは1045と入りました。

このアドレスを8加算(先頭アドレスから8だけ右に移動)すると、
「I」のアドレスになります。

アドレス1045に8を加えて104Dになりました。

レジスタGR4にIを納めます。
Iの文字コードは49です。

この「I」を、出力用の配列DASUの先頭アドレスに格納します。

格納済み文字数をGR1に設定します。

この文字数が3になったらループを抜けて出力します。

同様に、ICEの残りの文字「C」は2、「E」は、4を入力して、
格納します。

出力結果です。
暗号文みたいなプログラムを作ってみたいのと、
「クール、クーラー、クーリッシュ」がループしていたので、
これを作ってみました。

全然汎用性がないのですが、
アイスの売り上げに貢献出来るかも??

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

TEST START
RPUSH


LAD GR1,0 ;出力用配列に格納する場所と格納文字数

LOOP IN KEY,LEN ;文字に変換する数字入力用
LD GR2,KEY
SUBA GR2,=’0′ ;文字から数値に変換
LAD GR3,MOJI
ADDA GR3,GR2 ;変換した数値分右に移動
LD GR4,0,GR3
ST GR4,DASU,GR1
LAD GR1,1,GR1
CPA GR1,=3
JZE FIN
JUMP LOOP

FIN
OUT DASU,LEN2

RPOP
RET

KEY DS 1
LEN DC 1
MOJI DC ‘ABCDEFGHIJ’
DASU DS 3
LEN2 DC 3

END

読んで下さってありがとうございました。

この記事を書くのに勉強になった本を紹介します。
多分この記事を読んで面白かったと思われた方は、きっとハマると思います。

◆アルゴリズム問題がちゃんと解ける本
アルゴリズム学習の定番。
アルゴリズムが苦手で何とかしたい方におススメ

◆アルゴリズムはじめの一歩完全攻略
実際に作って学べます。
Javaを使っています。
私はJava初めてでしたが、
それでも、ハッシュ関数の所までは、
どうにかついていけました。
もっと頑張ります。

◆速習言語CASL2
CASL2、何それ、テーマパークの絶叫マシーン
みたいな名前だね、ぐらいだった私でも、入門書として楽しく読めた本です。

◆プログラミング入門CASL2
入門が卒業出来たら、ガシガシ例題解いて、
演習問題を解いて、力を付けたいという時に
読む本です。

<<関連記事>>

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

アセンブラCASL2で「再帰呼び出し」を作ってみた

この記事ではアセンブラで、簡単な足し算を使った再帰呼び出しを学習します。
再帰呼び出しは基本情報技術者試験で午前午後問わず出題させる可能性が高いです。

<<関連記事>>

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

2020年からの基本情報技術者試験は、
言語とアルゴリズムの配点が高くなります。
なので、プログラミング未経験の事務員の私は、
非常に焦っています。

そこで、疑似言語によるアルゴリズムを
CASL2で再現してみたら、両方学べて
一石二鳥なのではと思い、今回は「再帰呼び出し」を
作ってみました。

再帰呼び出しって、RPGで言うとダンジョンの中の迷路に迷って、
HPが0になったらゲームオーバーして魂が抜ける
みたいなイメージがあるのですが、皆さまどうですか??

HPをNとして、N=5(って、よわよわじゃん)だったら、
魂が抜ける前に5を宝箱に移動して、
魂が4になって、それを宝箱に入れて宝箱が
5+4=9になって、また魂が1つ減って3になって、
それを宝箱に入れて箱が5+4+3=12になって、
また魂が1つ減って2になって、宝箱に入れて、
箱が5+4+3+2=14になって、魂が1になって、
箱が5+4+3+2+1=15になって、魂が0になったら
ゲームオーバーで、身体は迷路の中、魂は天国に行って、
お姫様と幸せに暮らしましたとさ、って感じで、
F(N)=N+F(N-1)
の再帰呼び出しを行います。

全然ハッピーエンドじゃないのかな。
でも、天国で幸せならいいか。
話を再帰呼び出しに戻します。

N=5の時は、
F(5)=5+4+3+2+1=15
になり、16進数表記では「F」になります。
そのプログラムを作りました。

フローチャートです。


以下、トレースを行います。

レジスタは、
Nの値をGR1、F(5)を計算する合計をGR2、
出力ウィンドウに表示する文字コード用にGR3を使います。

GR1に「5」、GR2とGR3に「0」を設定します。

文字コード出力用にGR1の値をGR3にコピーします。

+30して文字コードにしました。
(この処理の説明は以下略します。)

「5+」
と表示されました。

GR2にGR1の値を加算します。

GR1の値を1つ減らして「4」にします。

GR1>0なので、
サブルーチン、SAIKIの中で再帰呼び出しを行います。

「4+」
と表示されました。

GR2の値が5から+4されて、9になりました。

GR1の値を1つ減らして「3」にします。

GR1>0なので、
サブルーチン、SAIKIの中で再帰呼び出しを行います。

「3+」と表示されました。

GR2の値が9から+3されて12になりました。
16進数では12は「C」です。

GR1の値を1つ減らして「2」にします。

GR1>0なので、
サブルーチン、SAIKIの中で再帰呼び出しを行います。

「2+」と表示されました。

GR2の値はC(12)から+2されてE(14)になりました。

GR1の値を1つ減らして「1」にします。

GR1>0なので、
サブルーチン、SAIKIの中で再帰呼び出しを行います。

「1+」と表示されました。

GR2の値はE(14)から+1されてF(15)になりました。

GR1の値を1つ減らして「0」にします。

GR1>0が偽になったので、
サブルーチン、SAIKIを抜けます。

メインに戻って、
「GR1=0になったので 抜けます にゃ!!」
と表示してプログラムを終了します。

プログラムはこちらです。

MAIN START
RPUSH


LAD GR1,5
LAD GR2,0
LAD GR3,0

CALL SAIKI
OUT MOJI,LEN0
RPOP
RET

MOJI DC ‘GR1=0 NI NATTANODE NUKEMASU NYA!!’
LEN0 DC 33

SAIKI
LD GR3,GR1
ADDA GR3,=’0′
ST GR3,KAZU
OUT KAZU,LEN
ADDA GR2,GR1
SUBA GR1,=1
CPA GR1,=0
JZE FIN

CALL SAIKI

FIN
ADDA GR2,GR1

RET

KAZU DS 1
TASU DC ‘+’
LEN DC 2
END

読んで下さってありがとうございました。

この記事を書くのに勉強になった本を紹介します。
多分この記事を読んで面白かったと思われた方は、きっとハマると思います。

◆アルゴリズム問題がちゃんと解ける本
アルゴリズム学習の定番。
アルゴリズムが苦手で何とかしたい方におススメ

◆アルゴリズムはじめの一歩完全攻略
実際に作って学べます。
Javaを使っています。
私はJava初めてでしたが、
それでも、ハッシュ関数の所までは、
どうにかついていけました。
もっと頑張ります。

◆速習言語CASL2
CASL2、何それ、テーマパークの絶叫マシーン
みたいな名前だね、ぐらいだった私でも、入門書として楽しく読めた本です。

◆プログラミング入門CASL2
入門が卒業出来たら、ガシガシ例題解いて、
演習問題を解いて、力を付けたいという時に
読む本です。

<<関連記事>>

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