標準TTLだけ(!)でCPUをつくろう!(組立てキットです!)
(ホントは74HC、CMOSなんだけど…)
[第224回]

●DAA命令の回路の説明です

前回お見せした回路図をもとにして、説明を始めようとしていましたら、回路図にミスがあることに気がついてしまいました。

前回の回路でも、十進補正は正しく行われます。
問題は特定の条件での、結果のフラグが正しく出ないということです。
C(キャリー)フラグにばかり気がいってしまって、S(サイン)フラグとZ(ゼロ)フラグが正しくセット、リセットされないことまでは、気がつきませんでした。
一応の動作テストはしたのですけれど、気にかけていないところは、結局見落としてしまいます。

今回はそのあたりも含めて、説明を始めます。

まずはDAAというニーモニックについて。
DAAは十進補正を行う命令です。Decimal Adjust(デシマルアジャスト)の略だなあと理解していました。
でも最初のDとAはわかるけれど、最後のAは何?って、つまらないことが気になりました。

以前に読者の方から教えていただいてダウンロードした「8080 User’s Manual」([第78回]参照)で確認してみました。
Decimal Adjust Accumulatorと書いてありました。納得。

ついでに、BCD(2進化十進数)は、Binary coded Decimalの略であることがわかりました。なるほどね。これも納得です。

●DAA命令の回路の考え方です

前回に書きましたように、これについては、[第13回]の「●以上のまとめ」、のところで下のように書いてあります。

補正前の数の、
1)下位桁がA〜Fの場合は、下位桁に6を加算する
2)下位桁が0〜3で、かつHフラグが立っているときも、下位桁に6を加算する
3)上位桁がA〜Fの場合は、上位桁に6を加算する
4)上位桁が0〜3で、かつCフラグが立っているときは、上位桁に6を加算後、Cフラグをセットする
5)上位桁が9で下位桁がA〜Fの場合には、66を加算する

この考え方に基いて描いたのが、前回の回路図です。

じつは今回のはじめの部分で書いた、回路のミスの訂正も含めて、もう少し簡単にできることがわかりました。
さきほどの、DAAの意味を確認するために、「8080 User’s Manual」を読んで、そのことに気がつきました。
なんだ。もっと簡単に考えればよかったんだ。

でも、[第16回]に書きましたように、DAAの回路をうんうんうなりながら考えたのは、昨年(2008年)の5月のこと。まだ「8080 User’s Manual」は入手していなかったので、仕方がありませんでした。
って、それは言い訳です。本当は、その位のことは、User’s Manualを読まなくったって、気がつかなければいけませんでした。

前回お見せした回路図をもとにして、とりあえずの説明をしていくつもりでしたが、ミスがあったり、もっと簡単にできることがわかったのに、もとのままの回路図で説明をするのもなんだかなあ、ということですから、ともかく新しい回路図にしてしまいます。

●改良後のDAA命令の回路図です

ずいぶんすっきりしてしまいました。前回の回路図と見比べてみてください。
どこをどのようにしたのか、ということについては順をおって説明していきます。

DAA命令の考え方は、上で書いたとおりで、つまりは、Aレジスタの値とフラグ(CフラグとHフラグ)の状態によって、そのAレジスタの値に、06か60か66を加算する、というものです。
したがって、前回のタイミングチャートにもありますように、ほとんどADD命令と同じです。
違うのは、ALUのレジスタ”B”にレジスタなどの値を置く代わりに、06か60か66を置くようにしているところだけです。

まずは、回路図の上の方で、M2でregRDをアクティブにします。でもs0〜s3は出力されませんから、s0〜s3=”1111”なので、Aレジスタの値が内部アドレスバスに読み出されます。
それをT4でreg”A”WRをアクティブにして、ALUのレジスタ”A”に書き込みます。

次はALUのレジスタ”B”ですが、ここがちょいと複雑なところです。
回路図の下の方で、内部データバスの値(ここはM2の期間、Aレジスタの値になっています)によって、ALUのレジスタ”B”にセットすべき値(06か60か66か)を決定しています。

一番下のORとANDで、下位4ビットがA〜Fの場合を選択しています。A〜Fは、ビット3が1で、さらに、すくなくともビット2かビット1のどちらかが1である数ですから、こうなります。
そのとき8ビットのラッチ74HC373の入力のビット1とビット2が1になります。
74HC373の入力のビット0とビット3は0に固定されていますから、6(”0110”)が入力されることになります。
それ以外に74HC373のビット0〜ビット3の入力が6になるのは、HF(ハーフキャリーフラグ)がセットされているときです。
前回の回路図では、ここが複雑になっていました。
ここは、上で書いた十進補正の考え方の2)の下位4ビットが0〜3で、H(ハーフキャリー)フラグがセットされているとき、という条件を回路にしたものです。
新しい回路図では、「下位4ビットが0〜3で」のところがなくなって、H(ハーフキャリー)フラグがセットされていることだけが条件になってしまいました。
ここのところが、「8080 User’s Manual」を読んで気がついたところです(それについては、のちほど説明します)。

上位4ビットについても同様で、ちょっと、間の回路を飛ばして上にいくと、一番下と同じ回路があります。
ここはHF(ハーフキャリーフラグ)ではなくてCF(キャリーフラグ)になっています。
上位4ビットがA〜Fであるか、CF(キャリーフラグ)がセットされているときに、74HC373の入力の上位4ビットが6(”0110”)になります。

で、ちょいと抜かした、間の回路なのですが、ここは、十進補正の考え方の5)の上位4ビットが9で下位4ビットがA〜Fのとき、を選択しているところです。
下位4ビットがA〜Fのときは、74HC373の入力の下位4ビットは6になりますが、上位4ビットが9のときは、そのままでは74HC373の入力の上位4ビットは6になりませんから、この回路で上位に6をセットします。

このようにしてセットされた74HC373の入力データは、内部アドレスバスが変化してしまうと、こちらも変わってしまいますから、Aレジスタの値が出力されているM2の期間(T4+T5)に、T4のタイミングで74HC373にラッチされます。
そして、次のM3のときに、74HC373の値が内部データバスに読み出され、T6のタイミングでALUのレジスタ”B”に書き込まれます。

あとはADD命令などと同じで、加算された結果を、M4のADDrdで読み出して、T8のregWRでAレジスタに書き込みます。

ところで、回路図の中ほどにCF(キャリーフラグ)をラッチしている、Dフリップフロップ(74HC74)があります。
何をしているのでしょう?
ここも前回の回路図と、大きく変わっています。
ここは、十進補正の考え方の4)の、上位桁が0〜3で、かつCフラグが立っているときは、上位桁に6を加算後、Cフラグをセットする、に対応している回路です。
ここも「上位桁が0〜3」という条件がなくなって、「Cフラグが立っているとき」のみになっています。
前回の回路図は、この部分でミスをしていました。

結構ややこしいことを考えていました。
4)の場合、加算の結果、C(キャリー)フラグはクリアされてしまいます。
そこで、4)の条件のときには、加算結果のフラグは無視するように考えたのです。
すると加算前のC(キャリー)フラグがそのまま残りますから、C(キャリー)フラグについてはうまくいきます。
ところが、S(サイン)フラグとZ(ゼロ)フラグまで加算結果が反映されなくなってしまうことに気がつきませんでした。

前回の回路図では、Dフリップフロップの出力は、数値演算命令回路([第191回])につながっていました(DAAFon信号です)。
ここでフラグの出力をコントロールしています。ADDFenblの先にCF(キャリーフラグ)とHF(ハーフキャリーフラグ)のset、reset回路があります([第191回]加算回路)。
DAAFonを禁止することでADDFenblも禁止されますが、同時にSFenbl、ZFenblも禁止されてしまいます。

今回の回路では、ADD命令などと同じように、加算結果のフラグを有効にするために、数値演算命令回路([第191回])のDAAFon信号の入力を、DAAに変更します。DAA命令のときは、加算結果のフラグをそのまま各フラグに反映させます。
すると、さきほどの4)のときに、維持しなければならないC(キャリー)フラグが加算の結果、クリアされてしまいます。
4)では補正前の上位4ビットは0〜3ですから、ここに6を加算しても、桁上がりは発生しませんから、C(キャリー)フラグはクリアされてしまうのです。

そこで今回の回路では、加算前のCF(キャリーフラグ)をT4のタイミングでラッチしておいて、T9のときに、その値によってCFsetをアクティブにして、C(キャリー)フラグをセットします。
加算結果のフラグは、T8のときに、各フラグに反映されますから、そのあとのT9のときに、T8でクリアされたC(キャリー)フラグを再セットするようにしたのです。

C(キャリー)フラグについては、もうひとつ、前回の回路図では、T4のときにADDFFclrを出力していましたが、今回はそれも削除しました。
ADDFFは、[第191回]加算回路で、加算前のC(キャリー)フラグをラッチしておいて、加算時にそれを加えるためのフリップフロップで、ADDFFclrはそのキヤリーを加算させないようにするためのものです。
ADCではなくて、ADDのための機能です。
DAAもADCではなくて、ADDの計算をしますから、ここはクリアしておくのが正解、ということで旧回路には、そのための出力があったのです。
では、それを削除してしまったのは、なぜ?

このことも、今回のいろいろで、回路図をあらためて見ていて気がついたことです。
[第191回]加算回路では、加算前のC(キャリー)フラグを加算させないために、ADDやSUB命令のOPコードに注目し、OP4=0、OP3=0のときには、C(キャリー)の加算を行わないようにしてあります。

ところで、DAAのOPコードなのですが、じつは、27(00100111)なのです。
OP4=0、OP3=0ですから、わざわざフリップフロップをクリアしなくても、そのままでも、C(キャリー)の加算は行われないことがわかったのです。それが、今回の削除の理由です。

●「8080 User’s Manual」を読んで気がついたこと

DAAの説明のところには、次のように書かれていました。

1) If the value of the least significant 4 bits of the accumulator is greater than 9 or if the AC flag is set,6 is added to the accumulator.
2)If the value of the most significant 4 bits of the accumulator is now greater than 9, or if the CY flag is set,6 is added to the most significant 4 bits of the accumulator.

え。たった、これだけぇ?
なお、1)の文で、ACとあるのはHF(ハーフキャリーフラグ)のことです。2)の文のCYはCF(キャリーフラグ)のことです。

この文を読んで、ああそうか、と初めて気がついたのです。
私は、下位4ビットが0〜3で、かつHF(ハーフキャリーフラグ)がセットされていたときは…、と考えてしまったのですが、じつは、下位4ビットが4以上で、かつHF(ハーフキャリーフラグ)がセットされるような計算は、十進ではありえないのでした。
結果が4以上で、かつ桁上がりが発生する、ということは、4ビットの16進数同士を加算した結果が14以上である、ということです(9+9でも、12にしかなりません。ADDですから16進の加算ですよ。お間違えなく)。

つまり、わざわざ条件をつけなくても、HF(ハーフキャリーフラグ)やCF(キャリーフラグ)が立っていて補正前の数が4以上のときは、その前に行われた加算がBCD数の加算ではなかったことになりますから、「その場合の補正はまともにはおこなわれません」という但し書き文に含まれてしまいますから、気にすることはなかったのです。

しかし、この英文では、十進補正の考え方の5)の、上位桁が9で下位桁がA〜Fの場合には、66を加算する、というところがありません。
うう。おかしいじゃないの。

しばし、沈思黙考…。
そこで、また、ああ、そうか、と気がつきました。

じつは上記英文2)の、nowが気になっていたのです。
なんじゃい。この、nowは…。
[注記]「8080 User’s Manual」には色はついていません。nowに色をつけたのは、筆者です。以上、念のため。

じつは、DAAの説明の、上記の文の前には、
…by the following process
という文があったのです。

そうか、そうだったのかぁ。

上の英文を、私は、2つの独立した文だと思っていました。
しかし、そうではなかったのです。
まずはじめに、1)のプロセス(下位4ビットの加算補正)を行い、次に、2)のプロセス(上位4ビットの加算補正)を行う、という意味だったのです。
するとnowの意味がわかってきます。

補正前の数が、9A〜9Fの場合、まず下位桁のみを補正するために、6を加算すると、必ず上位桁へのキャリーが発生するため、加算の結果、上位桁はAに変わります。
そこで、nowなのです。
つまり補正前の上位桁の値ではなくて、1)のプロセスを済ませたあとの、今(now)の上位桁の値が、9よりも大きければ、という意味だったのです。
うーん。なっとく。納得。

この文から推察するに、8080では、DAAはそういう2段階の回路になっていたんでしょうねぇ。
なるほど。そういう考え方もあるのか。
いやあ。なかなかに、奥が深いですねぇ。
2009.5.12upload

前へ
次へ
ホームページトップへ戻る