オリジナル4ビットCPUを用いてバイナリコードを学ぶ本連載。第11回では、1980年代の米国テレビドラマ「ナイトライダー」に登場するドリームカーの電飾の再現に挑戦する。
前回に引き続きオリジナル4ビットCPU「DL166」を用いてバイナリプログラミングの演習を始めます。皆さんは「ナイトライダー(Knight Rider)」をご存じでしょうか。1980年代に制作された米国テレビドラマです。その後日本でも放映されていました。主人公が「ナイト2000」というドリームカーに乗り悪を退治するという、ある意味ありきたりのパターンのドラマです。
そのドリームカーであるナイト2000のフロント部分、2つのヘッドライトの間に電飾が施されており、列状に並んだ赤い光が左右に動きながら点滅するのです。文字だけでその様子を説明するのは難しいので動画を見て頂ければ百聞は一見にしかずと思います。現在でもBSで再放送をやっていますし、YouTubeなどの動画サイトで検索すればきっと見つかるはずです。
当時既にLEDが使われていたかどうか筆者には定かではありません。それで今回の演習ではナイト2000のフロント部の電飾と同じように4列のLEDを順に点滅させ、それをまた逆方向にこれを繰り返すプログラムに挑戦してみたいと思います。われわれ世代の組み込み系エンジニアであれば、例えば開発中の組み込み機器が「異常系モードを発動したときは、LEDはナイトライダーにして」と言えば、そのプロジェクトの同僚はみんな意図を理解したものでした(知人談)。
DL166にはRotate命令というのがあって、これはレジスタのビットを上位ビットあるいは下位ビットに1つずつずらす命令です。桁あふれがあればそのレジスタの最下位ビットに転送されます。桁落ちがあった場合はそのビットは最上位ビットに転送されます。上位ビットにずらす場合は、レジスタの値は2倍になります。また下位ビットにずらす場合はレジスタの値は2分の1になります。
DL166は乗算命令や除算命令を持っていないので、Rotate命令などを組み合わせてこれらの算術命令を実現します。通常これらの演算はシフト命令を使って実現するのが一般的ですが、桁あふれや桁落ちが起こった際これらのビットは復活しないのです。これは、可逆的な命令ではないですよね。いわゆる群を乱す命令になるので、DL166ではRotate命令の方を実装することにしました。
Rotate命令にせよシフト命令にせよ除算乗算以外でもナイトライダーを実現するには最適な命令なのです。実はDL166では、ナイトライダーのために他の命令を削ってでもこれらの命令を実装しました。ナイトライダーはDL166にとっていわゆるキラーアプリなのです。……がしかし、連載第8回で紹介したこの夏の「セキュリティ・ネクストキャンプ2023」で、DL166を扱った講義の際にその設計思想を熱く語ったのですが、今どきの学生にこの思いはあまり響かなかったようです。
これまでと同様に「Tang Nano 9K(以下、Tang Nano)」にLEDドットマトリクスを搭載したものを用います。連載第4回記事『新たな教材となる「Tang Nano 9K」を使ってLEDマトリクスを制御する』を参考にしてください。また、LEDマトリクスの見方は前回の連載第9回記事が参考になります。
Tang Nano搭載のFPGAの製造元であるGOWIN SemiconductorのIDE(統合開発環境)も必要です。インストール時にドキュメントがダウンロードされますのでそれを参考にしてください。これらのドキュメントには日本語版も含まれています
本稿で紹介するVerilog-HDLやサンプルコードは以下のリポジトリから入手してください。
⇒DL166の命令セットのプロジェクトがあるGitHubのリポジトリはこちら
また、本記事で紹介するサンプルコードにおける命令セットの意味や使い方は、DL166の仕様を紹介した連載第1回記事『オリジナル4ビットCPU「DL166」はプログラミングの基礎学習に最適』を参考にしてください。
ナイトライダーのプログラムの前にRotateの基本動作を押さえておきましょう。最初のサンプルプログラムknight1a.asm(リスト1)は、上位ビット側にビットを移動させ桁あふれがあればそのビットはまた最下位に転送されます。この動作を繰り返すコードになります。
ram[0] <=8'b1010_0001; // mvi R0,1 ram[1] <=8'b01111_000; // urotate R0 ram[2] <=8'b1001_0001; // jmp 1
0番地ではレジスタR0に1を代入しています。この時点でLEDのドットマトリクスのR0を示す段の一番左側のLEDが点灯します。繰り返し処理が行われるので別にどこの桁でも大丈夫なのですが、とにかく4ビットあるうちのどこかのビットを1にしておく必要があります。全て0のままだとRotate命令を実行してもレジスタの値は何も変化しません。
1番地ではレジスタR0の値に対してRotate命令を実行します。この命令は上位ビット側にローテートします。以前はこの命令のことをLROTATEと呼んでいたのですが、これからはurotate(upper rotate)と呼ぶことにします。このコードを書いている時のビット列表記は、左が上位ビット、右が下位ビットになっています。しかしLEDドットマトリクスでレジスタの値が表示される時にはこれとは逆で左側が下位ビットになります。このようなビット列の並びをビッグエンディアンとかその逆をリトルエンディアンとか言ったりします。これはCPUのアーキテクチャによっても異なります。ですので右向きにローテート、右向きにローテートという表現を改めたいと思います。ちなみに今まで使っていたLROTATEはLeft Rotateの略でした。
2番地ではjmp命令で実行を1番地に戻します。これでローテートを繰り返すことになります。
それでは、実際に動かしてみましょう。/src/instructions.vの29〜31行目を以下のように書き換えます(リスト2)。
initial begin `include "knight1a.asm" end
GoWinのIDEを使って、SynthesizeとPlace & Routeそして最後にProgram DeviceでTang Nanoの評価モジュールに書き込んでください。
Copyright © ITmedia, Inc. All Rights Reserved.