アドレスがところどころで突然0に戻る。途中で書き込みが終わってしまうときもある。CSにノイズが入っているのか。これまでにない難関にぶちあたってしまったようだ。聞いてみるものだ(8/12/2010)この5日間、悩み続けたFPGAの謎は、「すん」さんの掲示板に上げた質問に、いつもお世話になっているkugaさんが助言してくれて、いっぺんに解決した。HDLはプログラムではない回路だと考えろなどと少し偉そうなことを書いていたが、所詮はソフト屋である。同じループ内にあれば、全てのステートメントは間違いなく実行されるものと信じていた。ところがループを駆動するタイミングと判断する信号の間が非同期の場合は、その動作は保証されないという、FPGAでは極く初歩(だろうと思う)の常識を知らなかった。SPIスレーブは相手マスターからの同期クロックで動くメイン側から見れば典型的な非同期回路である。これを気楽にアドレスカウンターのインクリメントのトリガーに使っていたために、アドレスやカウンターのインクリメントが不定になっていたのである。アドレスカウンターは256Kワードなので18ビットである。データカウンターも18ビット、計36ビットをSPIのデータレディをトリガーにすれば、マスタークロックのタイミングと必ずいずれどこかでぶつかって、そのときの値は不定になってしまう。夜中、恐る恐る「こんなことってあるのか」などと大層なタイトルで掲示板に上げたら、ものの1時間もしないうちにkugaさんから回答があった。最初、非同期ということがわからず、反論でもないけれどロジアナのチャートを見せて「どこかでカウンターをこわしているやつがいる」的な主張をしたら、kugaさんから「18段のDFF(D-FlipFlop)を同時に動かすとき」という言葉で目が覚めた。これまでのブログをお読みになれば分かるように、当研究所のFPGAの勉強は基礎からやっていない。7セグLEDやUART、カラーバーなどが思ったより順調に動いたものだから、つい甘く見ていた。基礎からの勉強の必要性を痛感した。疑っていたFPGAさんごめんなさい。メインモジュールのマスタークロックの一行をspi入力モジュールにつけるだけで、ほぼ正しくデータがSRAMに入るようになった。いやあ、やっとトンネルを越えた。最初のfpga4funからもらったSPIはマスタークロックで動いていた。それがどうしてうまく行かなかったのだろう。試しに、fpga4funのコードを入れた見た。これはどういうことだ。どちらのルーチンもまだ細かい誤データが出る。8ビットの頭のビット(MSB)を間違え、1が半角のア、2がイになる。ビットマップの画像データは文字データほどシビアではないとはいえ、こんなところでゴミは入れたくない。戦いはまだ終われない。最後のエラーはUART送信のバグだった(8/14/2010)ロジアナを入れっぱなしにし、ソースを少しづつ変えながらUART端末を2つ立ち上げて、ファイルを送っては、チャートを調べ、出力データをチェックする作業を続ける。一息なのだけれど、まだ完全にERRORなしのデータは送れない。fpga4funの方のソースのSCKの立ち上がりを2ビットでなく、3ビットまで読んで立ち上がりとみなすというロジックに換えて(01Xでなく011で立ち上がり)、かなりエラーは少なくなった。サンプリングするところがSCKの立ち上がりから1クロック分あとになる方がエラーが少なくなるようだ。ARMの方にも少し心配が残っている。CS(ChipSelect)を別個のGPIOで出しているのだが、データを送り終える前に、デアサートされてしまう。最後の1バイトはエラーになるし、受信側(FPGA)のレジスターは途中で中断され悪影響が心配である。CSをデアサートする前に、SPIのビジービットがリセットされるのを監視するロジックを加える。これでエラー状況が好転するかと淡い期待を持っていたが、残念ながら全く影響はなかった。データカウントがファイルのデータ長と一致したのが唯一の収穫。この程度のエラー率(1KB送って数バイト)を許容して先に進むかどうかである。QVGAの8ビットカラーなら77KB、16ビットなら154KB、画面が汚れるだろう。全体のエラーがどれくらいになるか、調べてみよう。FPGAのUARTの部分に機能を追加して、スペースキーを押せば、SRAMのデータを一定量づつ際限なく表示するロジックを加えた。ここの部分は、複数データを任意にUART出力できるように改善して大分モニターらしくなっている。簡単に機能が追加できた。すると驚くべき事実が判明した。同じSRAMアドレス上のデータが、表示するたびに変わるのである。あーあーあ、何故これをもっと早くやらなかったのか。これまでSPIのエラーだと思っていたのは、すべてUART送信側のエラーだったのである。SPIはしっかりデータを送っていたのだ。これまで疑っていたSPIのみなさん大変失礼しました。これで、プロセッサーからFPGAに画像データを送るルートは確立された。次のステップはいよいよ液晶モニターに画像を表示するステップである。買ってきたデジタル液晶はワイド液晶なので、ピクセルクロックに30Mhz以上を要求されている。これは少しきついので、これまでのアナログ液晶に簡単なラダー抵抗のDACを加えて、とりあえず8ビットカラーにしてみようかとも考えている。フォトフレームプロジェクトは山場を迎える。STM32基板のSPIでFPGAにデータが送れたSPI動き出す(8/1/2010)CQ-STARM基板(STM32F103VB6)のSPIインターフェースである。慣れてきたとはいえ、ARMのディバイスをちゃんと動かすのは8ビットマシンと違って設定が大変である。手元にはFatFSというお手本があるのだが、このSDカードのSPIはDMAを使った複雑な構成で、こちらはまだDMAを使うだけのスキルがない。このソースを簡単に流用出来ない。新しくSPIを定義するだけで大変だ(CQ-STARMはSPIを3つ持っている)。構造的には、AVRのものと変わらないが、設定するレジスターが半端な数ではない。あちこち叱られながら、日曜一日で、今までのコード例を参考に、やっと2つめのSPI2が動き始めた(SPI1がSDカードアクセス)。出力チェックは最初、オシロでやり、動作を確認してからロジアナに切り替えた。デバッグのためUARTと一緒に動かしているので飛び飛びのデータだが、それらしい波形が出てきた。CS(チップセレクト)が動いていないが、ロジアナで見たところでは、ほぼ想定どおりだ。簡単なファイルを読ませて、シリアルデータを追う。よし、前のAVRと違って、全く問題なくクロックとデータが一致している。あとは正確なCSが出れば、結合テストに進むことが出来る。シリアルデータを可視化できるロジックアナライザーが欲しくなってきた。今使っているオプティマイズのロジアナは、100Mhz分解能で、32チャンネル、128Kビットのサンプリングが出来、安くてもハードとしては十分な性能だが、ソフトがいまいちでパラレルは16進に変換できてもシリアルは出来ない。秋月や、ストロベリーリナックスで出しているロジアナが良さそうだが、現在のロジアナのハード性能を上回る機種は4万近くになるので迷っている。SPIのチップセレクトを作るのに成功した(8/2/2010)気持ちの良い達成感。ことで画像ファイルを送るルーチンが完成した。最初、SPIのデータは出たが、ファイル転送のトリガーになるチップセレクトが言うことを聞かなかった。Select)ピンを使っている。このピンを出力にしておけば、マスターで送信するとき必ず0になり、いちいち設定する手間が省けるということだ。ロジアナで見ると、送信前から0になったままで変化しない。それならというので、SPI_SSOutputCmdというコマンドで、強制的に動かそうとしたが、これも変化がない。Webで調べると、この状況は、STマイクロのフォーラムでERRATAではないかと話題になっている問題であることが分かった。ここのサイトによれば、STM32F103のSPIにはデータを送るときや、マスタースレーブの切り替えで、自動的にチップセレクトをアサート(負論理なので0)する機能がついているはずなのだが、これが動かないらしい。こちらも動かそうといろいろやったが変化がない。途方に暮れたとき急に思いついた。これまでのFatFSのSDカードのSPIでは、この問題をどうやって解決したのだろう。あわてて、ソースを見てみた。何とこのピンを全く使わず別の普通のGPIOピンを使って制御していた。始めからこうすればよかったのだ。再配線が面倒なので、元のNSSピンを汎用のGPIOに設定し(だいぶSTMライブラリに慣れてきた)、送信の前後に、0(アサート)、1(デアサート)するステートメントを挟む。よーし、ロジアナで送信の前後にちゃんとCSがでることを確認した。やれやれやっと動いた。フラッシュのサイズが80KB近い。LFNをはずすと、もう少し減るかもしれないが、JPEGライブラリが入るかどうか心配になってきた。STマイクロのペリフェラルライブラリの使い方を簡単に紹介(8/3/2010)だいぶSTM32の汎用ピンの設定に慣れて、その構造がわかってきたので、これからSTM(マイクロ)の標準入出力ライブラリを使ってARMのペリフェラルを開発する人のために、使い方を簡単にまとめておこうと思う(自分のためでもある)。これを理解するまで大変だったのだ(ライブラリのバージョンは3.1.2)。STマイクロのライブラリの使い方は、日本語では、ここに結構詳しく載っているが、専門家向けすぎて良くわからないところがある。これから紹介する方法は、理論的でもなく一部の例だけなので全体を理解するのには役立たないかもしれないが、実践的なことが強みである。ひとつ通してしまえば他への応用が効くと思う。ARMのペリフェラル(ディバイス群のこと)や、GPIO(汎用入出力ピン)の設定は、AVRのように簡単ではない。GPIOは、単純なことをやりたいだけなのにとても面倒である。AVRなどではI/Oポートの設定は、入出力か、プルアップか、初期値が0か、くらいの設定しかなく、設定レジスターも2つしかないので初期化は気が抜けるほど簡単だが、ARMはそうはいかない。ARMは、ピンごとに詳細な仕様をことこまかに設定する必要がある。したペリフェラルの設定は、ARMにもAVRと同じように各設定レジスターの全パラメータを定義したヘッダーファイル(stm32f10x.h)が用意されているので、これを使ってレジスター単位にひとつづつ設定していっても良い(もちろん直に即値を入れてもかまわない)が、ソースコードの視認性と移植性、メンテナンス性は格段に落ちるだろう。いうのは、各機能ごとに膨大な数のレジスターがあり、特に別機種への移植を考えると、こうした情報隠蔽化や抽象化をしておかないととんでもない時間がかかってしまう。メーカーにとっては、同じソースコードを最小の変更で使い回しできるので断然有利だが、アマチュアにとってみれば、調べることがかえって増えるので、それほどのメリットはないかもしれない。いやそれにしてもLEDを点滅させるだけでも大変な手順を踏む必要がある。これに輪をかけてタイマーの設定は複雑だ。今流用させてもらっているソースFatFSにも良い例(リエントラントで動くインターバルタイマー)があるので、これはあとでじっくり勉強する予定だ。ARMのペリフェラルとGPIOの設定方法である。GPIOとSPIの例を下にあげる。他のペリフェラルも細かい設定は異なっても、手順は共通のようだ。ここでは開発環境については詳しく触れない。STマイクロから提供されるライブラリをコンパイルの時どこに置くかは、Makefileで定義するが、このあたりは先人の環境をそっくり真似て、そこへ新しいソースを置くか、これまでのmain.cに付け加える。最初のうちはこの方法が一番楽だ(今度も「ねむい」さんの環境をそっくり真似た)。それでは、新しいディバイスを設定していこう。ARMではペリフェラルが使うピンだけではなく、それぞれのピンの属するバスを調べて、このバス単位に各ピンのクロックをENABLEにするところから始めなければならない。これは完全に機種依存で、それぞれのチップのデータシートで調べる。CQ-STARMのSTM32F103VB6は、SPI1は、APBバスの2番で、SPI2は、APBバスの1番だったりするので気をつけないといけない。次に、各ペリフェラルに固有のパラメーター設定のための構造体を定義する。例はGPIOで、構造体の定義は各ディバイス単位のヘッダーファイルstm32f10x_gpio.hにあるのでその型(GPIO_InitTypeDef)で、自分の構造体を作る。この構造体のメンバーに、それぞれのパラメーターを定義していく。パラメーター名はヘッダーファイルに#defineで出ている。Function、SPIやUARTなどの特定機能)PP(プッシュプル、普通の出力ピン、他にオープンドレインやプルアップの入力などがある)にする。このように、STM32では、各ピン単位に相当きめ細かい設定が出来る。して設定されたパラメーターを次のコマンドで初期化する。これはGPIOBつまりポートBの初期化である。&GPIO_InitStructure);(このコマンドは、何度も実行可能。同一ピンに対しては最新が有効)5.GPIOはこれでやっと下記の関数を使って、0、1にすることが出来る。//pin12を0にする6.SPIなどのペリフェラルは、さらに2と同じように初期化構造体をつくり、パラメーターを設定していく。インスタンスを作るSPI_InitStructure2がその構造体のインスタンスの名前。GPIOと同じようにここへパラメーターをメンバーとして定義していく。このパラメーターも、次の関数で初期化。これで終わりではない。動作を始めるために、次の関数で有効にする。ENABLE);9.これでやっと、定義と初期化が終わった。このあとディバイス所定の関数を使うとディバイスが動き始める。//SPI2へ、c16にある16ビットデータを送る。気をつけなければならないのは、この各ペリフェラルの設定だけでは動かないことだ。3.のように、そのペリフェラルが使うピンに対してもGPIOの設定をしなければならない。GPIOモードのAF_PP(汎用ピンとして使うなら、Out_PP)などである。したピンは固定されているのでペリフェラルの定義だけで動きそうだが、これがないと実際の入出力をしてくれない。これを知らずにはまった人は沢山いるだろう(かくいう私もそうである)。FPGAにデータは送れたが(8/6/2010)ARMでSDカードのファイルのデータをSPIで送るところまで成功した。次はいよいよFPGAがこのデータを正しく受け取り、SRAMに展開してくれるかをテストする段階である。XP2基板を取り出す。XP2基板に加え、UARTモジュール2つ(秋月USB-UARTモジュールと、自作COM1-TTLアダプター)、Latticeのパラレルライターと基板5つが勢ぞろいし壮観である。XP2基板は、UARTでSRAMに読み書きするコードが書き込まれている。これを、SPIで読んだデータだけを単純に出力するコードに書き換える。ARMのCOM1端末から、ファイル名を指示し、送った後、XP2のもうひとつのUART端末でキーを押せば、入っただけのデータがこのUART画面に出力されるという勘定である。デバッグのためオシロやロジアナで調べやすいようブレッドボードでSPIやUARTケーブルを中継する。すべての結線は済んだ。ARMでファイルを指定しキーを押す。何事もなく送信が終わった。次は、データが正しくSRAMに書かれたかどうかを確かめる。FPGA(XP2)のUARTのリターンキーを押した。高揚した気分が一気に坂道を転げ落ちる。これはいつものことだ。何度かやるうち、送っているときにFPGAのLEDが点くのを発見した。FPGAのSPIコードにはLEDが点くステートメントが入っていたのを思い出した。おお、FPGAのSPIはデータは読んでいるようだ。気を取り直して、FPGAのソースをチェックする。チップセレクトが下がればSPIのクロックを監視することにして、上がれば受信を中止し、次の受信のためカウンターを0に戻している。おーっと、また初歩的ミスだ。これでは、折角受信をしても終了のチップセレクトが上がったとたんにカウンターが0になりデータがないことになってしまう。急いで、ここをなおし再度テスト。それらしいデータがあらわれた。LFとCRキャラクターの関係で行がずれたりしているけれど、確かにSDカードのデータだ。テストしたファイルは小さなファイルだったので、今度は少し大きめのファイルを送る。いけない、UARTが暴走を始めた。SRAMの中味ではないようだ。不思議なことに、一旦暴走してFPGAをリセットした後は、最初成功した小さなファイルも表示できなくなった。電源を切ってSRAMの中味が完全に消えると元に戻るが、どこが悪いか見当がつかない。FPGAのデバッグは難しい。送られたデータ数をカウントしている変数ctrの内容がわかれば、暴走の原因はつかめるのだが、プロセッサーと違って、FPGAの中の変数を簡単にソースコードを加えて表示することが出来ない。プロセッサーからFPGAにデータを送るところまでは動いたようだ。このあとは、じっくり調べていくことにして、とりあえずはここまでの状況を報告しておくことにする。(日)XP2の外付けSRAM双方向アクセスに成功UARTのソースコードを換えてみる(7/10/10)FPGAによるフォトフレームプロジェクトは山場を迎えた。外付けSRAM(ビデオRAM)にSPIインターフェースを通してデータを送り込み、そのデータを読んでRGBインターフェースへ画像データを出力する段階の開発である。これが動くとFPGAの機能は、ほぼ完成する(このあとはプロセッサーでのJPEGデコード機能などの開発)。気持ちに余裕がでてきたので、SPIを組み込む前に、この前、感動したwww.fpga4funのUART(このサイトではRS-232Cと言っている)を実際に動かしてみたくなった。コードはこちらが作ったもの(これも雑誌からの借り物だが)よりかなりコンパクトになっている。リソースはそれに比例して少なくなっているのだろうか。サイトの記事に出ているソースコードは抜粋で、実際のソースコードはzipファイルで落とせるようになっている。ダウンロードして解凍する。うーむ、サイトに出ているもの較べるとコード量が多い。エラー処理などの機能が追加されているようだ。クロック周波数、ボーレートなどを調整し、エラー処理などを簡略化して、これまでのUARTテストプログラムに入れて動かしてみた。ありゃあ、うんともすんとも言わない。ネットに公開されているコードが動かないということはまずあり得ない。自分が直したところがいけないに違いない。気を落ち着けて、最初からひとつづつ調べていく。その結果、単純な入力ミス(ボーレートが一桁多かった)、インターフェースミス(論理が逆だった)などが見つかる。これを直してfpga4funのUART送受信コードは無事動いた。気になるリソース使用量はどうだっただろうか。元のUARTのスライスが165だったのに対し、138まで下がった。一時は、96まで下がり、すごいと思っていたが、一行記載漏れがあり(これが原因で送信が最後まで動かなかった)、これを補うと動いたものの、スライスは大きく増えてしまった。それでも15%以上のリソース削減である。エラー処理などは少し残してあるので、これを削ればスライスはもっと少なくなるかもしれない。受信は、まだ不具合が残っており、ファイル転送などでデータを一気に送ると受信ミスがある。これは本筋と関係ないので、これ以上関わるのはやめることにする。SPIとSRAMアクセスの間にバッファーが要るか(7/12/2010)SPIインターフェースの詳細設計に入る。この第5ステップの開発には実はSPI受信機能より、もっと重要な機能の開発がある。間断なく続くビデオインターフェースへのデータ転送の合間に、双方向でSPIからのデータをSRAMへ書き込む処理と、SPI読み込みとSRAM書き込みの間の非同期処理である。この間はバッファーを設ける必要があるだろう。これをどの段階で、どの程度の深さ(バッファー量)が必要なのか見極めなければならない。SPIはプロセッサー側がマスター、FPGAはスレーブなので、送信を待たせるわけにはいかない。Select)を上げて、クロックを動かせば、どんなことがあってもデータを読まなければならない。プロトコルを作って送信を待たせることも出来るが、この程度のしかけでは大げさすぎる。SRAMのアクセスは、ピクセルクロック単位に時刻が決められた待ったなしの読み込みなので、これまたこれを邪魔してはいけない。FPGAは同時処理なので両者を同時に動かせるが、非同期なので、そこを通るデータは正確に受け渡す必要がある。リングバッファーなどと呼ばれる。いうシステムの設計でこのあたりが最も難しく、また最も面白い部分である。FPGAは完全な並列マシンなので、だいぶ気楽だ。これがプロセッサーのマルチタスク構造だと、やれプリエンプティブだの、ノンプリエンティティブだの、タスクスイッチオーバーヘッドと言ったOSの機能を気にしなければならないが、FPGAは基本的には全く独立して並行に動くので、データの動きにさえ気を遣っておればよい。それと、QVGAなのでピクセルクロックと、SRAMアクセスの間に余裕がある。SRAMが書き込み中で読めなくても、2クロック後には、SRAMが空くので、そのときまで待って(5クロックくらい余裕がある)、読めばよい(ピクセルが少しずれるか?)。テストベンチは、SPIのデバッグのためUARTインターフェースを残し、プロセッサー側からSPIでデータを送った後、UARTコマンドで送り返して検証することにする。FIFOは要らないことがわかった(7/13/2010)少し意気込んで詳細設計に入ったが、SRAMのアクセス時間30ns(現在の33Mhzマスタークロック)、ピクセルクロックの間隔196ns、SPIの読み取り間隔などを詳しく計算しているうち、どうもFIFOなどの大掛かりな仕掛けは必要なさそうな感じがしてきた。SRAMのアクセス時間は、8ビットがクロック1サイクル30nsで読み書きできる。VGAインターフェースへの読み出しと、SPIからの書き込みがかぶっても、それぞれ2クロック以内にSRAMはあく。SPIの方はもっと余裕がある。SPIのシフトレジスターは、データが連続していれば、1フレーム(8ビット)のあとも次のデータは55ns後に来るが、読んだ8ビットデータをラッチするバッファーを一つ置いておけば、次の440ns後まで次のデータは来ない。1バイトのバッファーさえおいておけば、FIFOのようなしかけは不要だ。ピクセルクロックでの読み出しと、SPIのバッファー取り込みが、かぶったとしても、次のドットは196ns後なので、余裕でデータを読み込める。詳細設計に自信が出来てきたので、ソースコードを整理し始める。これまで分割してきたソースを統合する。UARTとビデオインターフェースのソースは別々だったので、これをまず総合する。そのあとSPIモジュールを足し、SPIからのデータをSRAMに書き込むプロセスを書き加える。www.fpga4fun.comで新しいHDLの書き方を覚えたが、alwaysを分けた簡明なコーディングは難しい。相互に関係する変数が多く、プログラム言語と違って外部変数を複数のモジュールで勝手にいじれないので(外部変数は参照のみ)、モジュールを分けるのは一苦労だ。7セグLEDから始まって、UART、SRAM、カラーバーと、沢山モジュールを開発してきたが、結局、1つのalwaysループに殆ど全てのプロセスを含める必要が出てきた。このあたりがIPコアプロセッサーが幅を利かせている理由なのだろう。メインループは350ステップを越えてしまった。論理合成でエラーが出る。Latticeの論理合成ステップは一風変わっていて、ソースコードをSAVEした時点で軽いエラーチェックが入り、Synplifyの論理合成でもう一回、Place&Routeという次のステップでも、もういちど結線上の論理エラーを出してくる。ところが、このPlace&Routeでのエラーメッセージは、どこでこのエラーが起きているのか教えてくれないので弱った。これは、このあとメッセージの中にステートメント番号が入っているところを見つけたが、最初は途方に暮れていた。SRAM双方向アクセスが通った(7/16/10)ソースが大きくなりすぎ苦労している。コンパイルにあたる論理合成が通らない。SRAMのアドレス操作が難しい。SPIによる書き込みと、ビデオインターフェースが間断なく読み込む処理は、頻繁にアドレスを換えて動く。複数のモジュールでひとつの変数をいじることが出来ない制約が重くのしかかる。気分転換に別のことをやって再度挑戦するということの繰り返しである。ことでソースコードが完成した。テストに入る気にならない。今度のモジュールはほぼ完成形で、SPIもビデオインターフェースもすべて組み込んである。SPIの送り側はまだ開発していないのでテスト手順が難しい。メモに書いてある手順をもういちど確認して、恐る恐る動かし始めた。オシロで出力を見るが、ビデオインターフェースが全く動いていない。UARTは動いている。SRAMから出てくるデータはめちゃめちゃである。ビデオインターフェースが動いていないのに何故だろう。規模の大きなプログラムが動かないときの原因究明の常套手段は、分割してひとつづつ動かしてみることである。新しく入れたルーチンを次々にコメントアウトしていく。結局、最後のUARTまでになっても、SRAMの書き込みがうまくいかない。UARTはデバッグ用なのだけど、キーボードから入れたデータはゴミになって返ってくる。UARTにこだわっているわけではない。双方向でそれぞれが別のアドレスを指示しながらSRAMを読み書きできなければフォトフレームは動かない。UARTが動いていなければSRAM双方向アクセスの検証ができず、先に進めないからだ。アドレスを共通にするとUARTはちゃんとSRAMにデータを書き込み、正常に読み出せる。読み込みと書き込みのアドレスは、次のassign文で区別しているのだが、これがどうにもうまく動かない。読み込みアドレス結局、ロジックアナライザーに出馬を願うことにした。ICプローブがFPGA基板にうまく接続できないので使用をためらっていたが、ロジアナでなければこれ以上の解析は無理だ。シミュレーターもあるが準備が大変だ。考えた末、基板のピンのパッドに10ミリくらいの0.5ミリ錫メッキ線を半田付けしてスタブを作り、そこへプローブをつける。アドレス線と、WriteEnableで5本のスタブを出した。苦労した甲斐があって、一発で原因が判明した。プログラムは思ったようには動かない、書いたように動くという好例だ。アドレスの切り替えに余裕を持たせて1クロック待ってから、Enableを出したつもりだったが、ロジアナで見てみると、Enableの前でアドレスが切り替わってしまっている。何だ、考えてみれば、assign文は組み合わせ回路なので遅延がない。さっきの書き込みの切り替えは、書き込みリクエストのフラグではなく、じかにWriteEnableにするだけで良いのだ。わかってしまえば、なんでもない話だった。ソースを作り替えて論理合成。おお、全く問題なくUARTが動く。懸案だったSRAMの双方向アクセスがやっと完成した。ロジアナさまさまである。ビデオインターフェースがまだ動かないが、これはwireとかreg変数の受け渡しか何かのミスだろう。FPGAでの開発は一山越したように思う。残るSPIの検証は、送り側の開発が必要である。久しぶりにSDカードの付いたAVRのMega128基板を取り出して、テストベンチの開発を準備する。うーむ、プログラミング言語は楽で良い。