2012年8月31日金曜日

AC'97 Codecを制御してみる

AtlysボードにはNational SemiconductorのLM4550というAC'97 Codecが搭載されている。
Wikipediaによると、AC'97はIntelが提唱したサウンドインタフェースの標準規格で機能的には論理コントローラとアナログコーデックがありこれらがAC-Linkという5線式の双方向シリアルインターフェースバスで接続される。 LM4550は機能的にはアナログコーデックであり、今回これを制御する論理コントローラを作ってみようという訳だ。
LM4550のブロック図をデータシートから以下に引用する。




出力はLINE_OUT~MONO_OUTの3系統、入力はMIC~PHONEの7系統があるが、Atlysボードで使用できるのは出力はLINE_OUTとHP_OUT、入力はLINE_INとMIC1のみとなっている。


AC_LinkはBIT_CLK、SYNC、SDATA_OUT、SDATA_IN、RESET#からなるシリアルインターフェースで、SDATA_xxxがデータ信号であり、IN/OUTは論理コントローラ側からみた方向付けになっている。つまり、SDATA_OUTは論理コントローラ→コーデック、SDATA_INはコーデック→論理コントローラ。BIT_CLKは文字通りのビットクロックでSDATA_xxxはこのクロックに同期して転送される。このクロック信号はコーデックが駆動する。 SDATA_xxxで送受されるデータは以下のようなフレーム構造で全体のビット長は256ビットである。通常はフレーム周期は出力側のサンプリングレートに一致するので、BIT_CLKはサンプリングレートの256倍の周波数になる。

SDATA_OUTラインのデータフレーム構造は以下のようになっている。
1フレームは13個のSLOTで構成され、SLOT0は16ビット長のTAG情報、SLOT1~12は20ビット長で図に示す情報となっている。オーディオ情報とコーデック制御情報が多重化されていて、フレームサイズは固定長であるが、TAG SLOTのビットで有効・無効を表示できるようになっている。



SDATA_INラインのデータフレームは以下のようになっている。


今回は、以前作成したDDS IPからコーデックに出力したりDRAM上に何か音楽データを置いてコーデックに出力(再生)させたり、LINE_INにアナログ信号を入れてキャプチャしてみたりしてみたいと考えている。
AC'97の論理コントローラIPについて確固としたイメージを持っている訳でも無く、どちらかというとDAC/ADCとして使う感じなので、このプロジェクトのタイトルは「AC'97 IPの作成」とはしていない。

まずは、AC-Link I/Fのシリパラ変換部を作る必要がある。


2012年8月26日日曜日

近況

毎日、暑い日が続きますなー
そのせいか、ここのところ体調がvery bad conditionで異常な疲労感に襲われている。
この土日も殆ど寝て過ごしてしまった。

8月も終わるのでさすがの暑さも和らぐだろうと期待している。
なんとか体調回復させて活動再開したい。


2012年8月7日火曜日

next theme

さーて、年に一度の夏休みも終わったので活動を再開しよう。
次のテーマは、IPという形にはならないかも知れないがAtlysボードに載っているAC97 Codec (LM4550)の制御をやってみようと思う。


2012年7月31日火曜日

cross gcc for zumi32 9

画面に胡麻塩のようなノイズが描画されたり時間が経過するとハングアップしてしまうのは、zumi32のバグだった。
構造上、割込みによる分岐でも遅延スロットが発生してしまうがこの場合の遅延スロットは無効にしているつもりだったのだがその処理が不完全だった。いやーややこしい。
zumi32_exec.vの該当個所を以下のような感じに修正した。


修正の結果正常動作するようになった。
以下はAtlysとDE0で同じFreeRTOSプログラムを動作させている様子だ。OSのTickTimerの時定数はAtlys用(100MHzクロックで1msec)になっていて、まったく同じバイナリをDE0でも動作させている(DE0側は80MHzクロック)ため、DE0側のLEDの動きが遅くなっているが、どちらも正常に動作している。(ディスプレイのアナログ側で表示されているのがDE0のVGA出力、デジタル側がAtlysのDVI出力) また、DE0のLCDに表示されている文字列はEPCSに入っているプログラムによるものだ。 DE0起動後、fpgaデータのsofを直接Cyclon IIIにダウンロードし、プログラムでもLCDは触っていないため、起動時に表示された文字列がそのまま残ってしまっている。

今回のバグはホントにややこしくて、何故か条件分岐命令のbnzを使った場合ハングアップし、それ以外の分岐命令、例えばbzとbrの組み合わせで代用したりした場合はハングアップし無かったりという現象の見せ方をしたりしていて手間取ってしまった。でも、何とか修正できたのでよかった。

先日公開したsnapshot版は修正版に更新した。
今回はFreeRTOS部も含めたのでファイルサイズが18MBになってしまった。

FreeRTOSも動くようになったので今後の展開としては、あんなことやこんなことそんなことまで色々考えられるがソフトばかりだとつまらないので、ここらでgccの移植は一休みにして今度は別のテーマをやろうかなと考えている。一晩寝たらまた気が変わるかも知れないが・・・


2012年7月23日月曜日

cross gcc for zumi32 8

割込みも問題なく動いたのに気をよくして、リアルタイムモニタの移植に挑戦してみている。
移植するリアルタイムモニタはFreeRTOSというものだ。
FreeRTOSはWikipediaによれば組み込みシステム用のリアルタイムオペレーティングシステムだそうで、多数のマイクロコントローラに移植されている。
ライセンスはGPLで、ソースはhttp://www.freertos.org/から入手できる。
ただし、ドキュメントは購入しなければならないようだ。上記freertos.orgかまたはアメリカのamazonで購入可能のようだが、私のカードは非対応のため購入できなかった。日本のamazonでも買えるようにしてくれたらいいのに。。
しかたがないので、ソースツリーの各種マイクロコントローラ用の実装例を参考にして移植を進めることにした。また、FreeRTOSの使い方(PIC32MX版)というページが見つかったので、そちらのページを参考にさせていただいた。
で、何とか動き出すところまできた。
現状、マンデルブロー描画タスクとナイトライダータスク(LEDをナイトライダー風に点灯させるタスク)の2タスクを作って動かしてみている。tickタイマーの周期は10msecとしている。

以下はマンデルブロー描画タスク部、時間待等はせずにひたすら描画処理を行う。

以下はナイトライダータスク部、vTaskDelayを利用して100msec周期に起床して動作する。

以下はmain関数
ハードウェア初期化後上記2タスクの生成後、スケジューリングを開始している。
2タスクとも同じ優先度にしている。


このプログラムをビルドしたところ、コードサイズが命令メモリの容量を越えてしまったため、メモリサイズを倍の16KBに拡張した。

以下は動作の様子
LEDの点滅と平行して描画処理も動作している。

一見うまく動いているように見えるのだが、描画の方をよく見ると胡麻塩ノイズのような点々があり何か変だ。また、この状態でしばらく放置しておくと停止(ハングアップ?)してしまった。
時間経過でハングすることからスタックまわりの移植がバグっているのかも知れない???
さーて、あたしゃどうやってこれをデバッグすればいいんでしょう。。(-_-);
でも、、、、楽しい。ムフフフフ・・・


2012年7月17日火曜日

cross gcc for zumi32 7

DE0にも実装してみた。

システムアーキテクチャは以下のようにした。


プログラムは以下のとおり


プログラムはAtlysで動かした物と基本的には同じだが、DE0はLCDがあるのでそこへの文字列出力もするようにした。また、DE0ではコアクロックが80MHzになるため、タイマーへの設定値も変えている。(pwm_init内部で換算している。)

以下動作している様子

コンパイラの方はまだ改善の余地があると思っているが、この辺でスナップショット版を公開することにした。
例によって以下に置いた。(表の最上段)

http://www.hi-ho.ne.jp/bravo-fpga/

コンパイラはパッチのみで、GCC自体のソースは含んでいない。
ビルド手順はREADMEに書いてある。

詳細ドキュメントは・・・そのうち書きたい。


2012年7月15日日曜日

cross gcc for zumi32 6

zumi32には4種の例外がある。reset例外、address error例外、interrupt例外、syscall例外だ。
reset例外はzumi32が動作を開始するときに発生する例外で0x0番地から命令を実行する。address error例外はワード境界以外で命令フェッチが発生したときに発生する例外で0x40番地から命令を実行する。interrupt例外は割込み例外で0x20番地から命令を実行する。syscall例外はsyscall命令により発生する例外で0x80番地から命令を実行する。reset例外以外の例外発生時は戻り番地がEPCレジスタに退避される。EPCレジスタの値はld_epc命令で汎用レジスタにロードすることが出来る。また、除算命令を実装していないので、0除算例外は組み込んでいない。今回はハードウェア割込みを使ったプログラムがちゃんと動くかを見てみた。割込み機能はCAN IPの実機検証時にも使ったので動作するだろうと思っていたのだが、zumi32のw_interrupt信号の生成論理にバグが見つかり、条件によってはEPCに正しい戻り番地が退避されない場合があることがわかった。いやーハマったハマった。
以下は修正後の論理。


上記修正後、正常動作するようになった。
Cのプログラムは以下のようにした。


フォアグランドではマンデルブロートの描画を行わせる。バックグランドは10msec毎にタイマー割込みが発生し、その割込みルーチンで計時しsprintfで時計表示形式の文字列に変換しdraw_strで画面表示する。 sprintfはコードサイズを小さくしたかったので自作版を使った。これは浮動小数関係をサポートしていないが、その代わりコンパクトだ。 また、interrupt例外からhw_interruptへ至る部分はアセンブラで書いている。例外時のアドレス間隔をもっと広くすればinterrupt_entry部のコードをそこに置けるようになるのだが、それだと例外を使わない簡単なプログラムの場合もその領域を空ける必要がある。アクセス速度の関係で命令用メモリはFPGAの内蔵RAMを使いたいので、なるべく無駄な領域は取りたくない。ということでこの様な実装になっている。


以下は動いている様子




割込みが動くようになったので、簡単なリアルタイムモニタなら動かせるかも知れないな。


2012年7月10日火曜日

cross gcc for zumi32 5

ASCII文字のFONT ROMを追加して、文字列の描画をやってみた。

以下はプログラム

以下はその結果

Cでの開発環境ができればプログラムの作成効率が格段に上がると予想してはいたのだが想定以上だ。 普通にコードを書いてコンパイルしてFPGA側にダウンロードすれば普通に動く。この過程で躓く箇所は全くない。PC上でプログラムを作って動かす感覚と何ら変わらない。
なんか不思議な気分だ。


2012年7月7日土曜日

cross gcc for zumi32 4

幾つかプログラムを作成して実機で走らせてみた。
実機はSpartan6用DDR2 SDRAMコントローラの時に作成したDigilent Atlys用RTLを使用した。


まずは簡単な物からということで、LEDをナイトライダーのように点滅させるプログラムを試してみた。


コンパイルされたtest.elfから .text セクションと .rodata セクションをobjcopyで抽出し、これを、
odコマンドで32bit hex形式のテキストデータ列に変換している。


命令用メモリとデータ用メモリは上記のシステム図からも判るとおりバックドアからも読み書きできるようになっており、ローダプログラムでこのデータ列をダウンロードしzumi32を起動する。
で、無事動作した。


次に、LEDの動きに合わせてDVIの画面に垂直線を描画するようにしてみた。




これだけだと、何だか物足りない (^^);

そこで、マンデルブロー集合を描画させてみることにした。
プログラムは「C言語によるアルゴリズム事典」という本を参考にした。
演算は固定小数方式にした。


ここで、bootstrapルーチンでbss領域のゼロクリアを忘れていたり、gccの__mulsi3という整数乗算用関数をバグっていたりという初歩的なミスが発覚したりして手間取ったが最終的に以下のように描画させることが出来た。



表示画像(4:3)とディスプレイ(16:9)のアスペクト比が合っていないため横方向に膨らんで見えているが、アスペクト比が合って入れば以下のように見えるはずだ。
 → ディスプレイの設定を変更してアスペクト比を自動で変えるようにした。色味が上(撮影画像)と下(期待値・・・プログラムでppm形式のファイルを生成し、それをjpegに変換した)とで違うのは撮影に使用したデジカメの設定の問題だ。目視では下の期待値と同じ色味で見えている。



このプログラムでは乗算があるが、zumi32は乗算器を持っておらずソフトウェアでエミュレートしている。そのせいもあると思うが一画面描画するのに結構時間がかかる。画素数 1024 x 768 で演算のmax iteration数は64で1分30秒位だ。 gccのmachine descriptorもまだ全然洗練されてなくて、-O2オプションでコンパイルして生成されるコードも今一な出来なのでそのせいもあるのかも知れない。もっと効率の良いコードが出力されるmdファイルを書けるようになりたいもんだ。

でも、ここまで出きるようにはなった。  やったー \(^_^)/


2012年7月3日火曜日

cross gcc for zumi32 3

なんとか、zumi32用gccのビルドが通るようになった。
gccのソースは全部込みの場合、fortranやjavaやobjc, ada等も含まれるが、今回はgcc-coreとgcc-g++のみを対象にしている。また、newlib-1.19.0もビルドした。



試しに以下のプログラムのコンパイルをしてみた。



生成されたa.outを逆アセンブルして確認。



良さげな雰囲気だ。 (^_^)

でも、多分まだ実装漏れや間違いがあると思うが、そこそこのプログラムはコンパイル出来そうな気がする。後は使いながらバグ出し&修正するしかないかな?

2012年6月24日日曜日

cross gcc for zumi32 2

以前から自作CPU zumi32用のgccのportingに挑戦しているのだが中々捗らない。情報が乏しく無茶苦茶難しいため、少しやっては放置しそのうち忘れるといったサイクルが続いている。が、そろそろ真面目に取り組もうと思ってporting作業を再開した。 gccのCコンパイラはCソースからアセンブリ言語列への翻訳を担当し、アセンブリ言語列からマシン語列への変換はbinutilsが担当する。 binutilsのportingに関しては一応昨年の8月に終わっていたので、(ただし、今回の作業でまだ不足があることが判った。)  今回はCコンパイラ部のportingに着手した。
Cコンパイラ部のportingの本質的な部分はgcc/config/配下にzumi32用のディレクトリを作成し、そこにMachine Descriptionファイル(以下mdファイルと略す)を作成することである。 (他にconfigure関係やMakefile関係の編集も必要)
例えばCソース側で、
  a = b;
のようなプログラムがある場合に、これをcpuのどういう命令で実現するかをmdファイルに記述する。 a, b はレジスタの場合も有るし、メモリの場合も有り、其々の場合で割り当てるcpuの命令は違ってくる。 char / short / int や signed / unsigned 等の型によっても命令を使い分けなければならない場合もある。 上記のようなデータの移動は以下のような記述になる。
(define_insn "movsi_insn"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,m,m,r,r,r,r")
        (match_operand:SI 1 "movsi_rhs_operand"     "m,r,r,J,K,L,U,Y"))]
  ""
  "@
   ld32     %0,%1
   mov      %0,%1
   st32     %0,%1
   st32     %0,r0
   ldsi     %0,%1
   ldui     %0,%1
   ldhi     %0,hi(%1)\n\tshli\t%0,%0,16
   ldhi     %0,hi(%1)\n\tshli\t%0,%0,16"
  [(set_attr "type" "load,arith,store,store,arith,arith,arith,arith")]
)
Machine DescriptionはRTL(Register Transfer Language)という言語というか記法で記述する。RTLの言語仕様はLispから影響を受けているらしい。 portingをする場合は、既存のcpu用のmdファイルを参考にするのが良いのは言うまでもなく資料にもそう書かれているのだが、RTLの言語仕様に関する知識がまったくない状態で、それらを見よう見まねしようとしてもほぼ無理だと思う。 各cpu固有のアーキテクチャがあり、また、書き方や構成も異なるため、定形の型が中々読み取れない。 そこで、ドキュメントを読んで学習する必要がある。ドキュメントはgccのソースツリーのgcc/doc配下にあるgccint.infoだ。 build時にmake pdfとするとgccint.pdfが作られるので、それを読むと良い。 ただ、このドキュメントが640ページもある上、ちょーーーーーー難解だ。 以前から挑戦しては挫折の繰り返しで、何回よんでも難解だ。難解だけに、・・・ぷぷっ   でも、今回はじっくり読んだこともあり、少しだけ理解が深まった気がする。また、mdファイルはLattice Mico32用のmdファイルをお手本にさせて貰った。 また、今回の作業でzumi32の命令も一部変更と追加をすることにした。 具体的には算術命令をsignedとunsigned用に分けるということと、条件分岐命令でbczとbcnzを追加等である。bcz, bnczは比較命令 ≧ や ≦ の実装の容易化の為に追加した。



悪戦苦闘の末、cc1でアセンブラソースの出力は出きるようにはなってきた。

以下ではポインタとfor ループの確認


以下では乗除算の確認、zumi32は乗除算関係の命令は持っていないので、GCCのbuiltin関数の利用しようと考えているが、自前の物に変えるかも知れない。
→ 少なくとも整数の乗除算、剰余算は自分で作る必要があるようだ。


以下はchar,short,int混在の演算の確認


以下はVRAMを単一色で塗りつぶす処理モデルをコンパイルしてみた。


zumi32(lm32等もそうだが)は32bit即値をそのままレジスタにロードすることが出来ない。これは命令を32bit固定としていることによる。そのため、32bitの即値をロードさせる場合は即値を上位と下位に分けて、ロード・合成する必要がある。上記のアセンブリ言語側のhi(...)やlo(...)はそれを表している。 上記では上位値をldsi命令でロードした後シフト命令でシフトしているが、Lattice Micoやmipsでは直接上位にロードする命令がある。 zumi32もその命令を追加すべきか思案中だ。
上記のような上位/下位に分けてロードする場合は即値は16bitの方が扱いやすいが、zumi32の即値ロード命令は20bitの即値になっており、この点も今一な仕様になってしまっている。
変えようかな。。。

portingに必要なGCCの情報を完全に理解しない状態で行っているのでゴールが近いのか遠いのかさえ見えていない状態だが、何とか完成させたい、それまでモチベーションが維持できればいいが。。。Cが使えればプログラムの作成効率は格段に上がるからなぁー。


ERROR: Failed to spawn fakeroot worker to run ...

なにかと忙しくてなかなか趣味の時間を確保できない。 ...orz  家の開発機のOSはLinux Mintなのだが、最近バージョンを22に更新したところ、myCNC用のpetalinuxをビルドできなくなってしまった。ビルドの途中で ERROR: Failed to spawn ...