平成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

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

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

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

表計算?それともCASL2アセンブラ!?どっちがいいの!?基本情報技術者試験のプログラミング言語の選択について

この記事では主にプログラミング未経験者の基本情報技術者試験の言語の選び方について書きます。未経験者ですと、表計算かアセンブラの2択になると思います。

「表計算タイプ」、「アセンブラタイプ」の判別基準や、人気講師の方の記事リンクを掲載して、実際に問題を解きながら選択できる内容となっております。

メインメニューに戻る
資格トップへ
基本情報技術者試験トップへ
令和2年度(令和3年1月)合格報告

私は仕事でExcelを使っていることや、MOSのExcelExpertの取得者ということもあって、当然のことながら表計算を選びました。

しかし、表計算の問題文の文章の量が多すぎて、どうしたものか悩んでいました
また、実務や自主的にExcelを学んだ来たからこそ基本情報技術者試験の表計算の問題になんともいえないモヤモヤした違和感を持ってしまいました。

そこでアセンブラを試しにやってみた所、ハードウェアの勉強にもなりますし、とにかく面白かったです。なんというか、名探偵コナンなどの推理アニメとかに出て来そうな暗号解読みたいなワクワク感がありました。

そこで表計算からアセンブラに言語を切り替えました。

どっちか選ぶのに迷っている方は、1時間ぐらい両方やってみて、
自分にどっちが合うのか決めると、決めやすくなると思います。

本当に合わない場合は、1時間も持たないと思うので、その分決断が速くなるかもしれません。

とは言え両方の教材を同時に揃えるのは難しいので、受験ナビさんの記事で
CASL2は意外と短時間で学習できる
CASL2で必要となる2進数の知識
表計算(1)
表計算(2)
の記事が選択の基準になるかもしれません。


これから書く「表計算タイプ」、「アセンブラタイプ」は、あくまで参考程度にとどめて下さい。

●表計算タイプ
・長文読解が得意
・三度の飯よりExcelらぶらぶ
・今さら何か新しい言語を学ぶのもなんだか難しい

●アセンブラタイプ
・表計算の得点に伸び悩み
・2進数や16進数が好き
・試験後に何らかのプログラミング言語を学ぶ予定がある

関連記事
シミュレータと参考書

表計算とアセンブラのお薦め参考書

メインメニューに戻る
資格トップへ
基本情報技術者試験トップへ
令和2年度(令和3年1月)合格報告

平成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に演算結果が求められました。

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

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

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

C言語 文字コードで相性占い

子どもの頃、電卓を使って好きな子との相性を占いする遊びをしました。
「あ」が「1」、「い」が「2」・・・・というふうに50音と対応する数字を割り当てて、それを2り続けて行って、最初に100以下になった所が好きな人と自分との相性という、相性占いの遊びです。

これ、やったことある人いますか??

では、それをC言語を使って、文字コードでやってみたいと思います。
太郎さんの「T」、花子さんの「H」でやってみます。
標準入力する時は、「T,H」と入力します。
シフトJISコードの文字コードは、「A」を41、「B」を42・・・・として16進数で割り当てていきます。
太郎さんの「T」は「54」、花子さんの「H」は「48」です。
それを足すと「9C」になり、それを10進数で表すと「156」です。
この数字を2で割って行って、最初に100%以下になる所の数字を相性診断に使います。

こちらが太郎さんと花子さんの相性です。

では、プログラムになります。

#include <stdio.h>
int main(){


//イニシャルの文字コード用
char yourname;
char oaite;
int sum;
double aishou;

//あなたのイニシャルの文字コード
printf(“あなたのイニシャルとお相手のイニシャルを\n[,]で区切って入力してください\n例:A,B—>”);
scanf(“%c,%c”,&yourname,&oaite);

//あなたのイニシャルの文字と文字コードを表示する
printf(“あなたのイニシャル[%c]の文字コードは[%02X]です。\n\n”,yourname,yourname);

//お相手のイニシャルの文字と文字コードを表示する
printf(“お相手のイニシャル[%c]の文字コードは[%02X]です。\n\n”,oaite,oaite);

//2人のイニシャルの文字コードの合計
sum=yourname+oaite;
printf(“合算値は16進数で[%02X]で、10進数で[%d]です。\n”,sum,sum);

//相性診断
printf(“2人の相性を計算します。\n”);
aishou=sum;
while(aishou>100){
aishou/=2;
}
printf(“2人の相性は、[%.2f]パーセントです!!お幸せに!\n”,aishou);
return 0;
}

このプログラムを作るのに参考にした本です。

風呂グラミング(入浴剤紹介)

メインメニューへ
これからプログラミングをはじめる方へ
プログラミングと資格
自己紹介

この記事で紹介している入浴剤は

・入浴剤にはちょっとこだわりたい方
・頑張っている人のご褒美
・自粛疲れのリフレッシュ
・受験生
・プログラマー

に向けて、オススメ入浴剤を紹介しています。



プログラミングをやっていて困りごとは、エラーが出ること、そして、アイディアが浮かぶ時と浮かばない時があることです。
煮詰まった時には私はお風呂に入ります。

本当はパソコンを持って日本全国の温泉旅館に泊まってプログラミングと写真漬けの日々を過ごしたいのですが、流石に現実的ではありません。
では、どうしたらそれに近いことが出来るのか考えたところ、ネットで入浴剤を購入することに致しました。

プログラミングを快適に行うには健康である必要がある。
健康には風呂が大事。リラックス出来る。

という訳で、入浴剤を紹介します。

まずはこれ。

■ 北見ハッカ通商 入浴剤Sel de Menthe(セル・デ・メンタ) ■

風呂の色はマイルドでミルキーなブルーです。
ハッカの香りもマイルドなので、10月に入って肌寒くなった今の時期にも
ゆっくり温まりながらリフレッシュできます。
気分爽快なので、これはプログラマだけでなく、受験生にもおススメします(=^・^=)

この入浴剤で、北見ハッカ通商さんのファンになりました。
ハッカ油や馬油(ミントクリーム)などをこちらのページで紹介しています。
ハッカ愛からハッカー!?

続いては、本格的な入浴剤!!
■ アース製薬 温素 柚子の香り 15包 入浴剤 ■

アルカリ性のお湯でお湯の色は無色透明です。
入浴中はゆずの柔らかい香りに癒され、入力後は身体がポカポカします。
特に寒い冬の時期、冷え性、肩コリに悩む方におススメ。
アルカリ性のお湯なので、ヌルヌルっとした感じが少しあり、
湯上りはお肌が滑らかです。
プログラマは勿論、働く女性の頑張ったご褒美にも良いのかも。

■ アース製薬 アルカリ温泉成分 温素 琥珀の湯(とろさら美肌湯)600グラム ■

※浴槽がやや滑りやすくなります。
琥珀色のお湯で、植物がたっぷり入った和漢の上品な甘さのある香りがします。
トロっとした感じのアルカリ性のお湯です。
疲労回復の効果があります。
睡眠のことで悩んでいる方におススメのお風呂です。

メインメニューへ
これからプログラミングをはじめる方へ
プログラマこそストレッチ(子ども&大人向け)
自己紹介

C言語で芸能人の結婚について心の準備をしておく

石原さとみさんが一般男性の方と結婚しましたね。
私はそのことを知って、「おめでとう」、「お幸せに!!」って思います。

すみません、完全に他人ごとですよね。
もしも私が応援している推しが結婚したらどうしよう、って思ってファンとして心の準備することにいたしました。

早速、C言語を使って心の準備を致します。

配列jyunbiは5個の要素を持つchar型配列です。
要素は[0]-[4]です。この5つの中に、推しがもしも結婚したらファンとしてどうやって心の準備をしようか、
そのストックを入れます。

そして、ループで要素0から5未満(4まで)を取り出して表示させました。

実行結果です。

プログラムです。

#include <stdio.h>
int main(){


char *jyunbi[5]; //心の準備のストック用配列
//配列に準備しておくことを格納する
jyunbi[0]=”そのお相手にはプレッシャーがかかる”;
jyunbi[1]=”ファンを敵に回すかも!?”;
jyunbi[2]=”家にある推しの写真はワガハイのものにゃ”;
jyunbi[3]=”その写真を使って妄想できる”;
jyunbi[4]=”妄想をこれでもかってぐらいに爆発させる!!”;

//ループで配列の要素を取り出して表示させる
for(int i=0;i<5;i++){
printf(“%d.%s\n”,i+1,jyunbi[i]);
}

}

C言語を学んでいる方にはお子さまもいるので表現はだいぶ気を付けました。
というか抑えました。
う~~~~ん、これぐらいだったら大丈夫かな??

推しの方、いつもお世話になっております。
本当にありがとうございます。
具体的に何でお世話になっているかと申しますと、仕事しながらプログラミングや資格の勉強は、好きでやっていることとは言え集中力がぐらつくことがあります。
そういう時に好きな芸能人の方って本当に支えになるなって思うんです。

今まで体調を崩したりで勉強しか取り柄が無い私が勉強出来ずに困っていたこともあるので、自分の人生の残りの時間を全て投じてでも後れを取り戻します!!
何かお礼出来ることがあれば良いのですが、色々可能性を考えながら恩返ししたいです。