N.Y.Cityのまちかど

CASL_vs_Z80

CASL IIとZ80

はじめに

私のアセンブラ言語歴は、高校の授業で学んだZ80アセンブラ(と、趣味でちょこっとだけ本を読んだIntelアセンブラ)だけなのだが、専門学校の教員になって、CASL IIを教えるようになった。(CASL IIは基本情報技術者試験のために作られた仮想言語なので、これをアセンブラ言語歴と言っていいのかはやや疑問ではあるが・・・)

高校で学んだZ80を思い出しながらCASL IIの授業をしていたら、設計思想が異なるために微妙に異なる挙動をしていたり、うっかりミスするポイントがあったので、反省がてらこのページに記録しておく。(他にもあったら教えてください)

シフト演算の扱い

シフト演算を用いると、乗算器・除算器を持たないCPUで乗除演算を高速化することができる。なぜならば二進数を1ビット左シフトすることは値を2倍することに相当し、1ビット右シフトすることは値を半分にすることに相当するからで、シフト命令を使えば2のべき乗倍(2,4,8,…倍)または2のべき乗分の1(2,4,8,…分の1)の計算を高速に処理することができる。

対象レジスタの全ビットを左右にシフトする命令を「論理シフト命令」と言い、符号なし数のみを扱う場合にはこれだけで話は済む。例えば(100)10=(01100100)2を左1ビット論理シフト・右1ビット論理シフトすると

(100)100=(01100100)2
(01100100)2 ← 1 = (11001000)2=(200)10
(01100100)2 → 1 = (00110010)2=(50)10

となり、たしかに2倍・半分になっている。

ところが、符号付数を利用して、負の数に右論理シフトを行うと矛盾が生じる。符号付数は最上位ビットを符号ビットとして、符号ビットが1の値は二の補数で表現された負の数と解釈するから、(-32)100を半分にして(-16)100を得るつもりで右シフトすると

(-32)100=(11100000)2
(11100000)2 → 1 = (01110000)2 = (112)100

となってしまう。この現象の原因は負の数を半分にしても負のままであるはずなのに、符号ビットに0が入ってきた(=正の数として解釈される)ためである。

そのため、単純に全ビットを左右にシフトするのではなく、符号ビットを保護する機能を備えた「算術シフト命令」が存在する。この算術シフト命令の扱いが、CASLとZ80で異なっている。

CASL IIの場合

CASL IIは、算術/論理および左/右をそれぞれ組み合わせた、4つのシフト命令を持っている。

左(Left) 右(Right)
論理(Logical) SLL
[Shift Left Logical]
左論理シフト
《符号ビット残さない》
SRL
[Shift Right Logical]
右論理シフト
《符号ビット残さない》
算術(Arithmetic) SLA
[Shift Left Arithmetic]
左算術シフト
《符号ビット残す》
SRA
[Shift Right Arithmetic]
右算術シフト
《符号ビット残す》

左算術シフトでは、最上位ビット(符号ビット)は動かさず、残りの0番ビット~14番ビットまでを左シフトする。この時、空いた最下位ビットには0が入る。

右算術シフトでは、最上位ビット(符号ビット)は動かさず、残りの14番ビット~0番ビットまでを右シフトする。この時、空いた上位ビットには、「符号ビットがコピー」される。そのため、元の値が正の値(=符号ビットが0)なら0が埋まり、元の値が負の値(=符号ビットが1)なら1が埋まって、常に演算後の符号が正しく残るようになっていて、「値をいくら倍・半分にしても符号は元の値と同じ」という原則を維持している。

Z80の場合

Z80の場合、CASL IIと違って「SLL[Shift Left Logical]=左論理シフト」が存在しない。その代り、SLA[Shift Left Arithmetic]=左算術シフト」が符号ビットを考慮しない「左論理シフト」と同じ動きをする。

左(Left) 右(Right)
論理(Logical) ―― SRL
[Shift Right Logical]
右論理シフト
《符号ビット残さない》
算術(Arithmetic) SLA
[Shift Left Arithmetic]
左算術シフト
《符号ビット残さない》
SRA
[Shift Right Arithmetic]
右算術シフト
《符号ビット残す》

その結果、Z80で負の値を左算術シフト(SLA)していくと、計算結果が突然正の値に変わる可能性がある。逆に左算術シフト(SLA)していくと、計算結果が突然負の値に変わる可能性がある。これは「値をいくら倍・半分にしても符号は元の値と同じ」という原則に反している。その代わり、左算術シフトした結果符号が反転してしまった時、それは計算結果がオーバフローして正しく表現できなくなってしまったことを意味する。

非負ジャンプの扱い

条件付きジャンプ命令の中に「(直前の演算結果が)負でない時にジャンプする」命令が、CASL IIにもZ80にも存在する。

CASL IIの場合

非負ジャンプ命令は「JPL[Jump on PLus]」を利用する。JPL命令は「SFとZFが共に0」、すなわち直前の演算結果が「正の値である」かつ「0でない」時にジャンプする。従って演算結果が0の時はジャンプ「しない」。

Z80の場合

非負ジャンプ命令は「JP P,nn」を利用する。第1オペランドのPは「Sフラグが0」、すなわち直前の演算結果が「正の値である」時にジャンプする。したがって演算結果が0の時はジャンプ「する」。


現在ご覧のページの最終更新日時は2018/03/11 21:09:32です。

Copyright (C) N.Y.City ALL Rights Reserved.

Email: info[at]nycity.main.jp