デジタル回路で遊んでると、必ずブチあたる問題、それが2進数とか16進数とかいうヤツね。
まぁ慣れりゃフツーに使えるし、英語覚えるよりはずっと簡単だじょ(^^;
けど、場合によっては、やっぱ10進数の方が使い易い場合だってある。
というワケで、10進数と16進数の変換回路を源内CADで書いてみた。
しっかし、例のごとく、普通じゃない回路に仕上がってるから、冗談だと思って見てちょ(^^;
|
そもそも10進数とか16進数とかって、いったい何ナノヨ、ってトコロから始めると、話がヤヤこしい。
けどまぁ、復習くらいは、やっておこうかねぇ。
というワケで、この絵の中にリンゴは何個あるでしょう。

こんなん、数えりゃ判るよね、23個だ。。。あれ、あー24個だった(^^;
当然ながら、「24」って数字は、10進数だ。
10進数ならなんで「24」って数字になるかってぇと、

こんな具合に、10個入りの箱が2つと、残りが4個。2箱+4個で、24個だ。
これを16進数で数えると、こんなんなる。

16個入りの箱が1つと、残り8個。1箱+8個で、18個だ、16進数で。
ほかには、こんな数え方もある。最近はあんまり聞かないかね、ダースって言う数え方。
何故かは知らないけど、1箱12個入りになるんだ。

どの方法でも、リンゴの数は変わっちゃいないよ。
単に、数の表現方法が違うってダケのこと。
「リンゴ」=「林檎」=「apple」ってのも、似たよなモンだ(笑)
|
話を先に進める前に、このページでの数の表現方法を決めておくかね。混乱しないようにね。
16進数表記の場合は、数字の前に「0x」をつける。
10進数表記の場合は、数字の前に「0d」をつける。
あんまり0d付けまくると鬱陶ぉしぃんで、何も付いてない数字は10進数だと思ってくれ。
ついでに、2進数表記の場合は、数字の前に「0b」をつける。
と、こういうコトにしておこう。
10進数を示す「0d」の「d」は、decimalのdだ。
2進数は当然、binaryのbだ。
16進数の「x」ってのは何だろうねぇ。
あんまし自信ないけど、たぶんhexadecimalの途中にあるxだ。
なんで頭のhにしないかってぇと、16進数のためにhを使っちゃうと、後で6進数(hexa)表記が必要になった時に困るから(笑)
まぁ6進数なんて要らないよって人は、16進数に堂々とhを使っちゃう場合も、ある。
この表記方法って、このページ内での定義であって、万国共通語じゃぁない。
16進数の頭に「8'h」なんて付ける書き方もあるし、「$」とか「&H」ってのを付ける場合もある。
|
さて、10進数を16進数に変換する回路の話になるんだが。。。
上のリンゴの絵を見れば判るとおり、10進→16進変換って、単に箱の詰め替え作業だよ。
0d10個入りの箱から0d10個のリンゴを出して、0d16個入りの箱に詰め替えると、0d6個分の空きが出来る。
それに、0d10個入りの箱をもう1箱空けてリンゴを出して詰めると、0d16個入りの箱が埋まって、リンゴが0d4個余る。
これを、もっとも素直に実現する回路を作ると、こんなんなる。
IN01ってのは入力する10進数の「1の桁」、In10ってのは入力する10進数の「10の桁」を示す。
なお、C4A、C4B、C4Cっていう出力は、これ無いとエラーになるから付けてるダケで、回路動作とは関係ない。

回路の中で使ってる「Adder4」っていう部品は、全加算回路。
源内CADのQ&Aコーナーに、昔松下先生が載せた回路をそのまま使ってる。
この回路の中身は、こんなんだ。

ちなみにこの回路は、16進数4bit+16進数4bit+キャリー1bitを加算して、16進数4bitと桁上げキャリーを出力するモノだからね。
加算機とかカウンタとかって単純に作っちゃうと、普通に2進数ベースになっちゃって、
それを4bit単位でマトメると、普通に16進数ベースになっちゃうんだよねぇ。
んで、この場合の「桁上げキャリー」ってのは、「16個入りの箱が一つ満杯になったよ」ってコトを意味する信号になる。
さて、実際に動作を見てみようかね。シミュレーション結果は、こんなんだ。

入力を0d00、0d11、0d22、0d33・・と変化させて、Outに出てくる結果を見てる。
0d00 ⇒ 0x00
0d11 ⇒ 0x0B
0d22 ⇒ 0x16
0d33 ⇒ 0x21
0d44 ⇒ 0x2C
0d55 ⇒ 0x37
0d66 ⇒ 0x42
0d77 ⇒ 0x4D
0d88 ⇒ 0x58
0d99 ⇒ 0x63
ちゃんと16進数になってるっぽい。
|
この回路の逆、つまり16進数を10進数に直す回路も、同じように作れる。。。。ハズだ(^^;
ただ、ちょこっと面倒なのは、上で使ったAdder4がそのまま使えないコト。
Adder4は、素直に作った4bit全加算回路だからねぇ、16進数ベースの回路になっちゃってる。
だからまず、Adder4を改造して、10進数ベースの4bit全加算回路を作らにゃならん。
で、作ってみたのが、この回路。名前はAdderBCDって付けてある。

うーん、Adder4を2個も使っちゃって、「手を抜くにも限度ってもんがあるだろー」とか言いたくなる回路だ(笑)
簡単に動作を説明すると、
左のAdder4で、入力された値を、とりあえず16進数ベースのままで加算しちゃう。
真ん中にある3つのゲートで、左のAdder4の出力が0x9を越えたことを判定する。
右のAdder4で、0x9を越えた場合に、0x6を足す。
こんだけだ。
もちっと具体的に言うと、例えば0d5+0d5の場合、
左のAdder4の出力は0xAになって、0x9を越えてるから、右のAdder4で0x6を足して、0x10にする。
0x10って数字の上1桁を10進数の10の桁、下1桁(4bit)を10進数の1の桁として読むと、0d10ってことになる。
何かインチキくさいけど、だってそうなんだもーん(笑)
もちっと考えたい人は、「BCD」ってキーワードで検索かけて、探してみよう。
BCDとは、Binary Coded Decimal、つまり「2進数で表した10進数」ってな意味だ。
で、このAdderBCDを使って作った16進⇒10進変換回路が、これ。

Inに入力される8bit長の16進数(2進数でも一緒だけど)を、3桁半の10進数に変換する。
Out0001ってのが10進数の1の桁、Out0010ってのが10の桁、Out0100ってのが100の桁、Out1000ってのが1000の桁。
1000の桁が1bitしか無いから、4桁って言わずに、3桁半っていう中途半端な言い方してる(^^;
でも実は、入力の最大値が0xFF=0d255なんだから、Out1000が'1'を出力することは在り得なかったりする(^^;
シミュレーション結果は、こんなふう。

最近飽きっぽくなったせいか、もう飽きて来たんで、けっこう手抜きだ(^^;
値も、たぶん合ってるから、適当に検算してみてくれ(^^;
ちなみに、このシミュレーション結果の水色の部分は、「計算中」(笑)
回路がバタバタ動いてて、結果がまとまってなくて、出力が激しく変化する様子を、源内CADは水色で表示するらしい(^^;
実際この回路、シミュレーション実行ボタンを押してから結果が出るまで、かなり時間かかった。PCが固まったかと思うほど。
まぁ、ゲート数むちゃくちゃ多いもんな。
AdderBCDを9個使ってて、1個のAdderBCDの中にはAdder4が2個とゲートが4個、
んでさらに、1個のAdder4の中にはゲートが20個入ってる。つまり、総ゲート数は396個だ。
ゲート396個の回路なんて普通に書く気にゃならないけど、「階層構造を使った部品化」すりゃ楽だよね。
もし回路動作を高速化させたいなら、「キャリー ルックアヘッド」ってキーワードで検索してくれぃ。
|
ずっと上のほうで、10進数と16進数との間の変換は、箱の詰め替え作業だって書いた。
すぐ上に、2つの変換回路を載せたけど、どこがどう箱の詰め替えなのか、判るかな?
入力される信号を1本づつに分解して、Adder4またはAdderBCDに入力する配線が、入力される箱をバラす作業だよ。
例えば、16進⇒10進変換回路の「IN16」って信号は、'1'で"16個のリンゴがある"ことを示す信号だ。
この信号が"1"の時、上段のAdderBCDのB0が"1"で、下段のAdderBCDのB1とB2が"1"になる。
この配線パターンが、1箱10個入りの箱(AdderBCD)に、0d16という数を入力してあげている。
で、AdderBCDが、入力される数値を、1箱10個入りの箱にリンゴを詰めなおしているんだ。
この理屈が理解できれば、もう16進数も恐くないよね。
入力から加算器までの配線を全部消しといて、「適切に接続しなさい」なんて問題が出ても、大丈夫だよねぇ(^^;
|
今回作った2つの回路、10進数や16進数の原理原則に従った、とっても素直な回路だと思うんだけどなぁ。
でも、普通はこんな回路構成にゃしないよなぁ。。。
加算器ばっかしズラズラ繋げた回路って、入力から出力までの遅延が長くなるから、
今時の同期設計の回路の中に組み込むと全体の性能劣化を引き起こすんだよねぇ。。。(^^;
ま、それは置いといて(^^;
Adder4やAdderBCDの入力端子の半数以上がGND直結で"0"固定になってる、ってのが、ちょっとモッタイナイかなぁ。
'0'固定になってる入力端子を上手く活用すれば、加算器の数は半分以下に減るぞ、きっと。
でも、ヘタに手作業で合理化して回路をレビューしにくくするよりは、無駄を承知でこういう回路にしたほうがいい。
そのほうが、Totalでバグが減る。バグった時のチェックも容易だ。
「回路を描く」だけじゃなく、「回路の動作を検証して、動く 回路を完成させる」とこまで考えると、このほうが合理的なのさ。
見た目のゲート数が多いなんて、たいした問題じゃぁない。
そんなんどうせ、FPGAやLSIのCADが自動的に組み替えて合理化してくれる。
あー、汎用ロジックを使ってジャンパ線半田付けで組み立てるんなら、回路図レベルで合理化したほうがいいかも(^^;
だって、半田付けって面倒だもんね(^^;
|