あなたCPUなんか創ってどうするのかしら?! 第3章 第2節

~あんたCPUなんか創ってどうするのよ?! Vol.4~

2019/4/14
技術書典6
池袋サンシャインシティ 文化会館ビル2F 展示ホールD「う11」

第3章 第2節 LED表示時の不可解な動作

設計上、絶対に起こらない(としか思えない)現象が起こり、かなり悩みました。

TD4EX3およびTD4EX4のI/OユニットはメモリマップドI/Oを採用しており、LEDへの表示は以下の手順で行います。

  1. 0xE番地に出力したい数値を書き込む。
  2. 0xF番地に出力したいLED番号を書き込む。番号は最下位桁が0、最上位桁が2。

回路の設計上、0xF番地に書き込んだ番号に従って出力先が決定されるため、1個の命令では1つの桁にしか数値を表示できません。

ところが実際に試してみると、3桁あるLEDのうち最上位桁や中央桁に数値を表示させると、なぜか同じ数値が最下位桁にも表示されてしまうという現象が起きました。

写真6 左端の最上位桁に1を表示すると……
写真6 左端の最上位桁に1を表示すると……

写真7 なぜか右端の最下位桁にも1が表示される
写真7 なぜか右端の最下位桁にも1が表示される

実際には以下のようなプログラムを実行します。最後のMOV命令でなぜか最下位桁(1の位)と最上位桁(マイナス表示用)の両方に1が表示されます。

  MOV A, 0 ; 1桁目と2桁目に0を表示する。
  MOV [0xE], A  
  MOV [0xF], A  
  MOV B, 1  
  MOV [0xF], B  
  MOV A, 1 ; 3桁目に1を表示する。
  MOV [0xE], A  
  MOV B, 2  
  MOV [0xF], B ; この時点で最下位桁と最上位桁に1が表示される。

I/Oユニットの回路図をご覧頂くと分かりますが、LEDの選択には74HC138を使用しており、一度に書き込めるのはどれか1つの桁だけです。従って2つの桁に同時に書き込むことは理論上あり得ない筈です。にもかかわらず1桁目だけは何故か同時書き込みが行われてしまうのです。

いったい何故???

悩みました。

マジで悩みました。

最初はノイズを疑いましたが、あまりにも再現性が高すぎることと、電源周りにコンデンサを追加しても何の効果もなかったことから、たぶん違うだろうと判断しました。オシロスコープでバス周りを監視することも考えましたが、筆者の技術では問題を捉えられるかどうか自信がありません。

無い知恵だけを絞って解決するしかありません。TD4EX3の回路には論理的に問題があるに違いありません。

図15 LED表示時の不可解な動作
図15 LED表示時の不可解な動作

結局、原因はバスでした。
これもまたハードウエアに詳しい諸兄ならば、回路図を見ただけで瞬時に気付いたことでしょう。

実は前作Vol.3の「この世のCPUを食べ尽くすのだ!」では記載を忘れていたのですが、I/Oユニットのデータバスはプルダウンしてありました。

プルアップではなくプルダウンにした理由は、プルアップは負論理であり、素人には分かりにくいだろうと判断したからです。データバスに何も出力されていない状態は0を意味する、というプルダウンの考え方は素人には自然であり、理解し易いでしょう。

ところが、それが問題を引き起こしたのです。

図16 IOユニットのLED選択回路
図16 IOユニットのLED選択回路

表示対象となるLEDを選択するために0xF番地には74HC138が接続されていて、クロックが0になったタイミングで書き込み対象のLEDへ信号を送るようになっています。

ところがデータバスがプルダウンされているために、クロックが0になった瞬間のデータバスは0のままです。CPUから書き込む桁のデータが来るのは数ナノ秒後です。74HC138は非同期のICであるため、この数ナノ秒の遅延に反応してしまい、プルダウンによって0になっているデータバスに従って最下位桁に表示を行ってしまいます。そして数ナノ秒後に正しい桁番号を受け取ると、正しく表示するのです。

いわゆるヒゲという奴です。

筆者もヒゲに関する知識はありましたが、まさか自らヒゲを作り出してしまうとは思いもしませんでしたorz

ともあれ対策です。修正方法は何通りか考えられますが、一番簡単でバカバカしい手段で解決することにしました。データバスのプルダウンを止めて、プルアップすることにしたのです。
こうするとクロックが0になった瞬間のデータバスは0xFになります。しかし74HC138の該当するピン(Y7出力)には何も接続されていませんので問題は起きません。将来8桁の電卓を作ろうと思った時には面倒なことになるかも知れませんが、とりあえずはこれで解決です。