基本情報技術者 2013年 春期 午後 問12
次のアセンブラプログラムの説明及びプログラムを読んで、設問1〜4に答えよ。
〔プログラム1の説明〕
連続する2語から成るビット列αについて、左端のビット位置を0としたとき、ビット位置pから始まるqビットを、別のビット列βで置き換える副プログラムBREPである。ここで、0 ≦ p < 16、1 ≦ q ≦ 16とする。置換えの概要を図1に示す。

(1) ビット列αの先頭アドレスはGR1に、pはGR2に、qはGR3に、それぞれ設定されて主プログラムから渡される。
(2) ビット列βはGR0に左詰めで設定され、GR0の残りの部分は0で埋められて主プログラムから渡される。
(3) 副プログラムから戻るとき、汎用レジスタGR1〜GR7の内容は元に戻す。

設問1:
問題文を見る プログラム1中のに入れる正しい答えを、解答群の中から選べ。
aに関する解答群
ア:=#0001
イ:=#000F
ウ:=#7FFF
エ:=#8000
オ:=#F000
カ:=#FFFF
bに関する解答群
ア:AND
イ:LD
ウ:OR
エ:SUBA
オ:SUBL
模範解答
a:エ、b:ウ
解説
解答の導き方
この副プログラムは、ビット列αの位置からビット分を、ビット列βの内容に置き換えます。αは連続する2語なので、置き換える範囲が1語目と2語目の境目をまたぐこともあります。
まず、置き換える位置を示すマスクを作り、その位置にβのビットを入れる流れを確認します。マスクとは、処理したいビットの位置を「1」で示すビット列です。
aには、マスクの元になる値が入ります。
1語は16ビットで、左端のビット位置は0です。マスクの元になる値を#8000とすると、左端のビットだけが1になります。6行目でGR3をにし、7行目のSRA(算術右シフト、Arithmetic Shift Right:右へずらし、左端には元の符号ビットを補う命令)で、その値を右へビットずらします。
#8000の左端は1なので、右へずらすと左端には1が補われます。たとえばなら、3ビットずらした結果は#F000です。左端から4ビットが1になり、置換するビット分のマスクができます。なら#8000、なら#FFFFとなります。
したがって、元の値は#8000です。解答群ではエに当たります。#F000を選びたくなるかもしれませんが、これはの場合にシフトした後の値です。
次に、作ったマスクとβを、置換範囲が1語目と2語目のどちらにあるかに合わせます。
- 11行目では、βを右へビットずらして、1語目の置換位置に合わせます。
- 12行目では、βを左へビットずらして、2語目の置換位置に合わせます。
- 13行目と14行目でも同じずらし方をして、それぞれの語に対応するマスクを作ります。
SRL(論理右シフト、Logical Shift Right)とSLL(論理左シフト、Logical Shift Left)は、ビットをそれぞれ右、左へずらす命令です。範囲が語の境目をまたぐ場合でも、1語目用と2語目用の両方を作ることで置換できます。
bには、ORが入ります。
置換では、元のビットを残す範囲と、βのビットを入れる範囲を分ける必要があります。15〜19行目の処理を順に見ると、その理由が分かります。
- 16行目で、マスクの各ビットを反転します。XOR(排他的論理和、Exclusive OR)で全ビットが1の値と比較すると、各ビットが反転します。
- 17行目で、元の語と反転したマスクをAND(論理積)します。ANDは、両方のビットが1のときだけ結果を1にする処理です。これにより、置換範囲の元のビットを0にし、それ以外のビットは残します。
- 18行目でβをOR(論理和)します。ORは、どちらか一方でもビットが1なら結果を1にする処理です。置換範囲にβのビットを入れられます。
元のビットを先に0にしておかないと、βのビットが0の位置に元の1が残ってしまいます。そのため、マスクで置換範囲を消してから、ORでβを入れます。20〜24行目も、2語目に対して同じ処理をしています。
よって、18行目と23行目に入るのはORです。解答群ではウに当たります。
誤りやすいポイント
- #F000は、常に使うマスクの元の値ではありません。たとえばのときに、#8000をシフトした結果です。
- マスクは置換したい範囲を示すため、左端の1を算術右シフトで広げます。論理右シフトでは左端に0が入るため、必要な形のマスクになりません。
- ORだけでは置換できません。βのビットが0でも元の1が残るため、先にANDで置換範囲を0にします。
- 置換範囲が1語目だけに収まるとは限りません。1語目用と2語目用の両方に処理があることを見落とさないようにします。
FAQ
Q: なぜマスクの元の値は#8000なのですか?
A: 左端の1を算術右シフトで広げると、必要なビット数だけ1が並ぶからです。シフト量をにすることで、1の数が個になります。
A: 左端の1を算術右シフトで広げると、必要なビット数だけ1が並ぶからです。シフト量をにすることで、1の数が個になります。
Q: なぜANDの後にORを使うのですか?
A: ANDで置換範囲の元のビットを消し、その後ORでβのビットを入れるためです。先に消さないと、βの0に元の1が残ることがあります。
A: ANDで置換範囲の元のビットを消し、その後ORでβのビットを入れるためです。先に消さないと、βの0に元の1が残ることがあります。
Q: 2語目にも処理があるのはなぜですか?
A: 置換範囲が1語目の終わりを越える場合があるためです。1語目に入る部分と2語目に入る部分を分けて処理します。
A: 置換範囲が1語目の終わりを越える場合があるためです。1語目に入る部分と2語目に入る部分を分けて処理します。
関連キーワード: ビット列、ビットマスク、算術右シフト、論理シフト、論理演算、ビット置換
設問2:
問題文を見る 次の記述中のに入れる正しい答えを、解答群の中から選べ。
主プログラムから渡されたp、qの値及びビット列βが、次のとおりであった。
p (GR2):12
q (GR3):10
β (GR0):#D6C0
このとき、プログラム1の行番号14のSLL命令を実行した直後におけるGR4の内容はcであり、GR6の内容はdである。
c, dに関する解答群
ア:#0000
イ:#000D
ウ:#000F
エ:#0035
オ:#003F
カ:#FFC0
キ:#FFF0
ク:#FFFF
模範解答
c:イ、d:ウ
解説
解答の導き方
求めるのは、行番号14のSLL命令を実行した直後のGR4とGR6です。行番号14で更新されるのはGR7なので、GR4とGR6は、それぞれ行番号11と行番号13で設定された値のままです。まず、そこまでの値を順に追います。
GR4の値
問題文には、ビット列βはGR0に左詰めで設定されるとあります。GR0は#D6C0なので、行番号3でGR4にも#D6C0が設定されます。
行番号11では、GR4をpビットだけ論理右シフトします。論理右シフトは、右にずれた分を0で埋める操作です。pは12なので、#D6C0を12ビット右にずらします。
#D6C0を2進数で表すと、1101 0110 1100 0000です。これを12ビット右にずらすと、下位の4ビットである1101が残り、GR4は#000Dになります。
GR6の値
行番号5では、GR6にMASKパターン生成のための値が設定されます。この処理では、最上位ビットだけが1の#8000を基にします。
行番号6ではGR3から1を引くため、GR3はになります。行番号7の算術右シフトは、左端を元の符号ビットで埋める操作です。#8000は最上位ビットが1なので、9ビット算術右シフトすると、10個の1が並ぶマスク#FFC0になります。
次に行番号10で、GR3はになります。行番号13ではGR6を12ビット論理右シフトするため、#FFC0は#000Fになります。
行番号14でシフトされるのはGR7です。GR6は変更されないので、行番号14の直後もGR6は#000Fのままです。
誤りやすいポイント
- 行番号14でGR6も変わると思わないようにします。この命令の対象はGR7です。
- GR4は左にずらすのではなく、行番号11で12ビット右にずらします。そのため、#D6C0の下位4ビットに当たる#000Dが残ります。
- 算術右シフトと論理右シフトを混同しないようにします。行番号7の算術右シフトでは左端を1で埋めますが、行番号11や行番号13の論理右シフトでは左端を0で埋めます。
FAQ
Q: なぜGR6を#8000から算術右シフトするのですか?
A: 最上位ビットの1を右に広げ、置換え対象のビット数に合ったマスクを作るためです。今回は9ビット算術右シフトし、10個の1を含む#FFC0を作ります。
A: 最上位ビットの1を右に広げ、置換え対象のビット数に合ったマスクを作るためです。今回は9ビット算術右シフトし、10個の1を含む#FFC0を作ります。
Q: 行番号13でGR6を12ビット右にずらす目的は何ですか?
A: 置換え対象の範囲を、1語目の位置に合わせるためです。今回は#FFC0が#000Fになり、GR6には下位4ビットが1のマスクが残ります。
A: 置換え対象の範囲を、1語目の位置に合わせるためです。今回は#FFC0が#000Fになり、GR6には下位4ビットが1のマスクが残ります。
Q: 行番号14の直後にGR4とGR6の値が変わらないのはなぜですか?
A: 行番号14のSLL命令はGR7を対象にしているためです。GR4とGR6には影響しません。
A: 行番号14のSLL命令はGR7を対象にしているためです。GR4とGR6には影響しません。
関連キーワード: 算術右シフト、論理右シフト、論理左シフト、ビットマスク、16ビット演算
設問3:
問題文を見る プログラム1の行番号16、17を、同じ効果をもつ次の命令で置き換えた。に入れる正しい答えを、解答群の中から選べ。
16 GR6,GR2
17 XOR GR2,GR6
解答群
ア:AND
イ:LD
ウ:OR
エ:SUBA
オ:SUBL
カ:XOR
模範解答
ア
解説
解答の導き方
この設問では、行16、17の処理を別の命令に置き換えても、元の処理と同じ結果になる方法を考えます。
まず、行15でGR2に読み込まれる置換え前の語を、行13で作られてGR6に入っているマスクをとします。ビットマスク(処理するビット位置を選ぶための値)では、置換える位置が1、それ以外の位置が0になっています。
元の行16では、GR6と「=#FFFF」をXOR(Exclusive OR:排他的論理和)しています。「=#FFFF」は16ビットすべてが1の値なので、GR6の各ビットが反転し、の0と1が入れ替わります。続く行17のAND(論理積)は、両方のビットが1のときだけ1にする演算です。その結果、GR2には次の値が入ります。
つまり、置換える位置のビットを0にし、それ以外のビットはそのまま残します。置換文字列を後から重ねるため、先に元のビットを消しているのです。
同じ結果を、マスクを反転させずに作る方法があります。行16でGR6にとのANDを行うと、GR6はになります。続く行17でGR2とGR6のXORを行うと、置換える位置だけが0になります。
表のとおり、どの組合せでも元の処理と同じ結果になります。したがって、行16にはGR6とGR2のANDを行う命令が入ります。選択肢ではア:ANDです。
行20以降の2語目の処理でも、同じ考え方で既存のビットを消してから置換えます。
誤りやすいポイント
- 行16のANDは、マスクと元の語を組み合わせて、置換える位置の元のビットだけを取り出す処理です。行17のXORで、そのビットを0にします。
- XORは、片方だけが1のときに1になります。置換える位置では、元のビットと同じ値をXORするため、結果は0になります。
- 元の処理と置換え後の処理では、行16だけを比べても同じ結果かどうかは判断できません。行17まで続けて、GR2の値が一致するかを確認します。
FAQ
Q: 置換える位置の元のビットがすでに0でも、処理は正しく動きますか?
A: 正しく動きます。元のビットが0なら、行16のANDの結果も0です。行17で0と0をXORするので、結果も0のままです。
A: 正しく動きます。元のビットが0なら、行16のANDの結果も0です。行17で0と0をXORするので、結果も0のままです。
Q: なぜ置換える位置を先に0にするのですか?
A: 先に元のビットを消してから新しいビットを重ねるためです。古いビットが残ったままだと、新しい値を入れたときに意図しない結果になることがあります。
A: 先に元のビットを消してから新しいビットを重ねるためです。古いビットが残ったままだと、新しい値を入れたときに意図しない結果になることがあります。
Q: 2語目も同じ考え方で処理できますか?
A: できます。行21、22も、行16、17と同じく、マスクを使って既存のビットを消す処理です。
A: できます。行21、22も、行16、17と同じく、マスクを使って既存のビットを消す処理です。
関連キーワード: ビット演算、論理積、排他的論理和、ビットマスク、ビット反転
設問4:
問題文を見る ビット列αを連続するn語(n > 1)から成るビット列とした場合に同様の置換えを行う副プログラムXBREPを、BREPを使用して作成した。ここで、0 ≦ p < 16 × (n − 1)、1 ≦ q ≦ 16とし、それ以外の仕様はBREPと同じとする。プログラム2中のに入れる正しい答えを、解答群の中から選べ。

eに関する解答群
ア:SLL GR2,4
イ:SLL GR3,4
ウ:SLL GR7,4
エ:SRL GR2,4
オ:SRL GR3,4
カ:SRL GR7,4
fに関する解答群
ア:=#0001
イ:=#000F
ウ:=#7FFF
エ:=#8000
オ:=#F000
カ:=#FFFF
模範解答
e:カ、f:イ
解説
解答の導き方
XBREPは、複数の語から成るビット列の中で置換えを始める位置を、BREPが処理できる形に直してから呼び出します。
BREPは「連続する2語」の中で置換えを行います。そのため、XBREPでは、ビット位置 を次の2つに分ける必要があります。
- 何語目から置換えを始めるか
- その語の中の何ビット目から始めるか
1語は16ビットなので、 を16で割った商が語の移動数、余りが語の中のビット位置です。つまり、 と表すと、 が語の移動数、 が語内の位置になります。
プログラム2の LD GR7,GR2 で、もとの をGR7にもコピーしています。元の を使って語内の位置も求めるため、コピーを別に用意しています。
まず、GR7から語の移動数を求めます。16で割ることは、ビットを右に4つずらすことに相当します。したがって、選択肢は カ:SRL GR7,4 です。SRLは、ビットを右へずらす論理右シフトです。これにより、GR7には を16で割った商が入ります。
この商を ADDL GR1,GR7 でGR1に加えます。GR1はビット列の先頭アドレスなので、GR1は置換えを始める語のアドレスになります。たとえば なら、 です。語を1つ進め、語内の位置は4ビット目となります。
次に、語内の位置を求めます。 を16で割った余りは、 の下位4ビットで表せます。そのため、GR2と「下位4ビットだけが1」のマスクをANDで組み合わせます。該当するマスクは =#000F なので、fは イ:=#000F です。これにより、GR2には0〜15の語内の位置が残ります。
この処理の後、BREPには、置換えを始める語のアドレスがGR1に、語内の位置がGR2に設定されます。GR3の置換えるビット数 と、GR0の置換えるビット列はそのまま渡されるので、BREPを呼び出して処理できます。
誤りやすいポイント
-
GR7を左にシフトする
語の移動数を求めるには、 を16で割る必要があります。左シフトではなく、右に4ビットずらすSRLを使います。 -
GR2を右にシフトする
GR2には、後で語内の位置を残す必要があります。GR7にコピーした値から語の移動数を求め、GR2はマスクで下位4ビットを取り出します。 -
マスクを=#FFFFにする
#FFFFでは全ビットが残り、語内の位置だけに絞れません。下位4ビットだけを残す=#000Fを使います。 -
GR1に をそのまま加える
GR1は語単位のアドレスです。加えるのはビット位置 ではなく、 を16で割った商です。
FAQ
Q: なぜ を16で割った余りが、語内の位置になるのですか?
A: 1語が16ビットだからです。16ビットごとに次の語へ進むため、16で割った余りが、現在の語の中での位置になります。
A: 1語が16ビットだからです。16ビットごとに次の語へ進むため、16で割った余りが、現在の語の中での位置になります。
Q: #000FとのANDで、どうして下位4ビットだけが残るのですか?
A: #000Fは、16ビットのうち下位4ビットが1で、それ以外が0の値です。ANDでは、両方の値が1のビットだけが残るため、GR2の下位4ビットを取り出せます。
A: #000Fは、16ビットのうち下位4ビットが1で、それ以外が0の値です。ANDでは、両方の値が1のビットだけが残るため、GR2の下位4ビットを取り出せます。
Q: GR3の値はなぜ変更しないのですか?
A: GR3には置換えるビット数 が設定されています。語の移動数や語内の位置を求めても は変わらないため、そのままBREPに渡します。
A: GR3には置換えるビット数 が設定されています。語の移動数や語内の位置を求めても は変わらないため、そのままBREPに渡します。
関連キーワード: ビット列、ビット位置、論理右シフト、ビットマスク、剰余



