AVR互換コア rtavr の
SMP化 も一段落した。そろそろツールに着手しようかと思う。
『
FPGAライタの設計』で少し検討したが、これからはそれの実装がメイン。
作ろうとしているのは、
- 自作 ARTEMIS ボードの コンフィグ と SPI-FLASH への書き込みが同じ操作性でできる。
- ARTEMIS ボードに rtavr を入れた場合 ISP でプログラムだけの書き換えもできる。
- さらに rtavr と SPI で通信し printf デバッグができる。
- JTAG インターフェイスは、ARTEMIS ボードと接続できる AE-UM232R(ft232r) と自作の『AE-UM232Rピン互換ボード』(mega32u2)
- AE-UM232Rは、BitBang だが、AE-UM232Rピン互換ボードは自作の serjtag プロトコルを使う。
こういうもの。SPI-FLASH への書き込みは、一旦 FPGA を コンフィグ して行う。
コンフィグするものは、JTAG と SPI-FLASH を直結したものになる予定だが、rtavr を動かして接続するものも作ってみたい。
それ以外に
- エミュレータと結合して、rtavr 用プログラムのデバッグ環境にする。
verilator を使うと、完全なデバッグ環境を作れるかも知れない。ちなみに、verilator は構文チェックとしてだけ使っても有用だそうだ。
というのもやるつもり。SPI-FLASH への書き込みの方が後回し。
さらに、
も視野にいれる。リファレンスには、『
MachXO2 Pico Dev Kit』を予定。
... なんたる大風呂敷!という気がするが、どこまで出来るものなのか.. まぁやってみよう。
こういうツールはオープンソースのものを含めて多数あるわけだが、わざわざ作るのは、FT232R BitBang に対応したものがないし、serjtag に対応したものも当然ないため。avrdude でやったように ft232r/serjtag のドライバだけを作るのも手なのだが、上位レイヤでエミュレータを付けたりしたいので、ほとんど自分で作ることになる。
そもそも、したいのは rtavr を使うための環境作りであって、単にFPGAのコンフィグだけがしたいのではないから、既存のツールとは合わない。
参考にするものは、
このあたりがメイン。あと、『
USB-Blasterもどきの製作』の DDT#1付録LaticceXP2-5E書き込みソフト も参考にさせてもらおうかと思っている。
いままでも xulaload は見ていて、わからなくなったら xilprg も合わせて見る -- みたいなことをしている。mcs ファイルと bitstreame ファイルの読み込みコードはそれで作成済み。
CABLE ドライバ
前置きが長くなった。まずは、下位レイヤから設計を始めよう。
serjtag/ft232r の avrdude 用ドライバは既に持っているわけだ。open/close まわりはほぼそのまま使う。だが、インターフェイスは大幅に変える。serjtag のプロトコルに近いものにして、ft232r の方を合わせる方針。
方針はそれで良いとして... 機能の定義。単なる JTAG ならあまり悩まなくても良いのだが、付加機能がある。
接続されている信号 を列挙すると
FPGA um232r um162(mega32u2)
TMS D7/RI PB0(SS)
TCK D5/DSR PB1(SLCK)
TDI D6/DCD PB2(MOSI)
TDO D3/CTS PB3(MISO)
M1 CB0 PD5
M2 CB1 PD4
PROG_B CB2 PC4
INIT_B CB3 PD1
DIN - (PD0)
CCLK - (PC2)
JTAG から Config するには、M2 = H , M1 = L としてから、PROG_B = H → L → H とする。INIT_B は、H になっているはずだが、エラーになると L になる。
正確ではないかも知れないが、だいたいこんな感じの操作をする。
DIN/CCLK は、Serial SLAVE モード(M = 111) での Config で使うもので、おまけ -- 後回し。
MachXO2 には、PROGRAMN, INITN という端子があって、よく似た機能になっている。(M1/M2 相当は必要ない)
こういったピンの割り当ては、設定ファイルで 定義できないと困りそうだ。ただ... あまり凝ったことはしたくない。それと、AE-UM232Rピン互換ボードの UM162 では、serjtag を使うが、こういうピンの定義がそもそもない。serjtag 自体拡張しないと。
um232r.type = ft245r
um232r.tms = 7 # D7/RI
um232r.tck = 5 # D5/DSR
um232r.tdi = 6 # D6/DCD
um232r.tdo = 3 # D3/CTS
um232r.init = 11 # CB3
um232r.prog = 10 # CB2
um232r.m2 = 9 # CB1
um232r.m1 = 8 # CB0
とりあえずこんな感じ。ルールは次のようにする。
- um232r は CABLE 名 で定義可能
- ft245r は CABLE ドライバの指定で、決まった名前。
- # から後はコメントで 無視。
- ピンの指定は、CABLE名.ピン名 = [~][0-9][0-9] で、~ は負論理を示す。あと、存在しないものは定義しない。
この程度なら、ちょっとしたコードで解析できるだろう。
ちなみに serjtag の定義はまた違うもの。tms/tck/tdi/tdo の割り当ては決まっている。init/prog/m2/m1 は GPIO 的につかうから似たような設定か。
さて、CABLE ドライバの操作メソッドは、
int setup_port(int tdi, int tms, int tck)
TDI/TMS/TCK の値設定。
注意) tck を 1 に設定すると、クロックの極性が逆になる。
setup_port を呼ばないと 初期値は不定。
int put_tdi_bits(uint8_t *buf, int bit_len, int flags , uint8_t *recv_buf)
TDI にビット列を送り込む。
flags には、受信データを記録する CABLE_RECIEVE と
最後の TMS の状態を H にセットする CABLE_TMS_HIGH がある。
ビットストリームは、1 バイトの中では、LSB first
int put_tms_tdi_bits(uint8_t *buf, int bit_len, int flags , uint8_t *recv_buf)
TDI/TMS の組の データ列を送り込む。
flags には、受信データを記録する CABLE_RECIEVE がある。
ビットストリームは、1 バイトの中では、LSB first 。送信データは、TDI TMS の順。
int get_tdo_bits( int bit_len, int tdi, int tms, unsigned char *rcv_buf)
TDI/TMS の状態を設定して (bit_len 分) TDO を読み取る。
ビットストリームは、1 バイトの中では、LSB first 。
int setup_gpio(int pin, int value)
PROG/M1/M2 の設定。
int get_gpio(int pin)
INIT の読み取り
これだけにする。これを使って JTAG のプリミティブを組んでいく。まずは、ここまでをやってみる。
verilator
ツールは作成中だが、なにかと面倒。FT232R 版の枠組みは出来てきたが、それだけで 1000行近い。
ツール作成に飽きると verilator が気になってくる。verilator は、Verilog のソースを C++ や SystemC に変換してくれるツール(コンパイラ)。Icarus Verilog のようなシミュレータと比べて 2 桁速いそうだ。
Icarus Verilog の入出力をツールにつなげて、なんとか rtavr 自体のデバッグができないか考えていたのだが、これが使えるなら悩む必要もない。
まずは、ちょいとビルド。古い MinGW 環境でも flex/bbison を入れるだけでビルドはできた。
で、50A 用の rtavr を通してみる。
ひとつにまとめた rtavr_50a.v を作り rom_data.mem と同じディレクトリに置いて、
verilator --cc rtavr_50a.v
とやってみると、やたら Waring が出る。
%Warning-IMPLICIT: rtavr_50a.v:1833: Signal definition not found,
ほとんどは、こんな感じのもので、sub module に対する bit 幅 1 のパラメータが定義されていないというものだった。文法上問題ないようだし、他のツールも Warning にならないからわざわざ対応するつもりはない。
%Error: rtavr_50a.v:2739: Unsupported: Can't unroll generate for; condition not <= or <
%Error: rtavr_50a.v:2739: For loop doesn't have genvar index, or is malformed
%Error: rtavr_50a.v:2739: Unsupported: Can't unroll generate for; condition not <= or <
%Error: rtavr_50a.v:2739: For loop doesn't have genvar index, or is malformed
で、エラーはこれ。USART の UBRR のビット数制限で generate しているところ が引っかかるので UBRR_BITS を外す。あと port も generate 使っているから RTAVR_PORT_ESCALATION を定義することで generate しないようにする。
%Error-BLKLOOPINIT: rtavr_50a.v:3853: Unsupported: Delayed assignment to array inside for loops (non-delayed is ok - see docs)
次は、ram の 0 初期化 (initialize での for 文) GPR_INITCLR, SRAM_INITCLR を外すことで対応。
そうしたら... なんか出来た。
-rw-r--r-- 1 suz Administ 200421 Jun 4 12:12 obj_dir/Vrtavr_50a.cpp
-rw-r--r-- 1 suz Administ 19935 Jun 4 12:12 obj_dir/Vrtavr_50a.h
-rw-r--r-- 1 suz Administ 1521 Jun 4 12:12 obj_dir/Vrtavr_50a.mk
-rw-r--r-- 1 suz Administ 617 Jun 4 12:12 obj_dir/Vrtavr_50a__Syms.cpp
-rw-r--r-- 1 suz Administ 1023 Jun 4 12:12 obj_dir/Vrtavr_50a__Syms.h
-rw-r--r-- 1 suz Administ 1133 Jun 4 12:12 obj_dir/Vrtavr_50a_classes.mk
で make してみる。
cd obj_dir
make -f Vrtavr_50a.mk
そうしたら、Vrtavr_50a__ALL.a が生成された。... なんかいけそうな感触。
エミュレータじゃなくて これをツールに統合すれば、プログラムや I/O 周り (SPI_SLAVE) のデバッグができそう。SMP もいけるだろう。ちょっと面白くなってきた。
ただ、こっちは、JTAG 関係は必要ない。こっちに走ると JTAG ツールが後回しになってしまう。しばらくいじるのを我慢しよう。
LCMXO2280C-B-EVN (MachXO 2280 Breakout Board Evaluation Kit)


LCMXO2280C-B-EVN というのが、Digikey で 2700円で売られているのを知った。
デバイスは、MachXO-2280 でひとつ前の世代だが、一応 2280 LUT で MachXO2 Pico Dev kit より多い。
そんなことより、Digikey ですぐ買えて、FT2232 が載っているのが気に入った。
実をいうと FT2232D は持っていない。ツールでは、FT232R と同じ コード(BitBang) で 対応しようと思っているのだが、MachXO2 Pico Dev kit は、すぐには入手できそうにないし困っていた。
ツールを作るには、(ツールのテストのために)確実に動くものが欲しいし、安価だし、願ったりかなったりなので、購入することにした。
ちなみに、秋月の FT2232Dボード 改めて見ると 1450円となんか安くなっている。ただ汎用 JTAG CABLE として使うには、AT93C56 の入手がネック。
... というか、これで rtavr のデバッグまでいける。そうなると artemis ボードを作らなくとも済むようになってしまう。artemis ボードを組むのがますます後回しになるが、まぁ経験を積んだ後でも良いかも知れない。いまさら急いでもという気持ちになっている。
ちなみに、Lattice 純正なのだから書き込みツールは不要。だが、JTAG と内部でつなげて ISP したり、SPI 通信したりするのにツールを使いたい。書き込み機能は不要でもツールの設計の確認のために、おまけで作っておくつもり。
Lattice の合成ツールを入れるためには、空き容量をなんとかしないといけないのだが、実は SSD も新調した。
現在の SSD の erase count は 3000 ぐらいで、まだ 1年〜2年ぐらいは持つのだが、使えなくなったときに入手できないと嫌なので、64GB を買うことにしたのだ。
ところで、『FPGAボードを使う計画』-- ステップ(8) I/O ボードを Spartan-6 で作る。というのがあるのだが、TQG144 では、ピンが足りないことが予想された。かといって BGA など電子工作レベルでは無理。だが、LCMXO2280C-B-EVN は、やたら入出力が多い。
I/O ボードは、これで良いのではないかという気がしてきた。FusionPCB の 10cm x 10cm も安くなったし、これをマウントするマザーボードを作っても良いかもしれない。先の話だが覚えておこう。
... と思ったのだが、320穴もの ピンを ピンヘッダ-ピンソケットで 接続すると 二度と外せなさそう。だいたい 2x40 を 両側に 1つづつ付けるぐらいが精一杯 のような ...
そういうことだとすると、いったいどうやって使うのが良いのだろう?
まずは、コネクタの割り当てを見てみる。
- J5-J6...J10-J9
USB コネクタを下にすると、上下サイドに付くコネクタは、上から J5-J6...J10-J9 になる。
J5 と J10 は信号線がみっちり詰まっていて、GND すらない。一方 J6/J9 は 電源系が多く 信号線はすくない。特に J9は、LED を除くと 信号線は 5 本しかない。(J6 は 12本)
ただその 5本は重要そうな感じで CLK0-3 と SLEEPN 。
- J3-J4..J8-J7
J3,J8 は、作動ペア 2 本づつが GND とともに配置されている。(14ペア)。
J4,J7 は、2,4..22,24 が GND で、25,27 が N.C. 。
ケーブルで引き出すのに向いているかんじ。
... となると、マザーボードに付けるなら 上下サイドにピンソケットを下向きに付けるのが良いのだろうか? J5,J10 をメインにして、J6/J9 は電源供給(他)を目的に 一部だけ使う .. みたいな。
逆に、小基板を載せる.. なら 5cm 四方ぐらいのサイズで 済むから具合が良さそう。ただし、アクセス性が悪いから 何を載せるかは悩ましい。
構想どおりなら、SDRAM と MicroSD スロット x N 。と水晶ぐらい?
... おもいだした。5cm x 5cm なら 40pin 分は無理。19x19 のサイズ(穴は 18x18)まで。-- 片側の 4 列をつなげると 反対側に届かない。それなら、片側だけ使うものとして設計すれば良いか。
中央に J10,J9 を使った SDRAM + クロック ボードを置いて、左右に インターフェイス変換基板 (MicroSD x 4 と ARTEMIS 通信用 2x5コネクタ x 4 + USB みたいなかんじ) を考えてみよう。
... 今そういうものを作りたいわけではなかった。今は、そういう構想のもとに、ピンヘッダ/ソケットをどう付けるかだけ決める。
2x40 低メス (40円) を J5,J6 と J10 に 付けることにして、左右はさわらない ことにしよう。
C 基板を付けるなら、スルーホールにして、中央に縦にマウント。ピンヘッダは、必要な分だけにしておかないと 外すのがやっかいになる。
で、とりあえずやりたいのは、セラミック発振子 とか 水晶発振子 で発振できるかのテストぐらい。
(おまけ)邪な考えだとは思うが、J9 の 上の列 (下から 2 番目の スルーホールの列) で切ってしまうとどうなるのだろう? ひょっとして USB Jtag ケーブルとして使えるのだろうか?
MachXO は、MachXO2 とは違い JTAGENB というピンはなく ユーザI/O として使えないようだ。ユーザ I/O として使えれば、他の I/O ピンに接続するとか ができるのだが...
あと、Config は JTAG のみのようだから、切り離した FPGA の利用は難しそうだ。
当面は FPGA も必要なので、そのようなことは実行しないつもりだが、不要になってしまったら、そういう形で再利用できるかも知れない。
ツールの状況とか
デリミタは、* だが行末にしか来ないようだし、簡易パーザなら簡単に作れそう。
さて、どうやって Config するものなのか ... XP2Write を眺める。
int JtagCableOpen(int num=0);
void JtagQueSIR(PUCHAR tx,unsigned bitadr,unsigned bitlen,int read=0);
void JtagQueSDR(PUCHAR tx,unsigned bitadr,unsigned bitlen,int read=0);
void JtagQueIDLE(unsigned clocks);
int JtagFlushQue(PUCHAR rx=0,unsigned rxbits=0,int check=1);
void JtagCableClose();
jtag.h で定義されている Jtag のプリミティブはこう。-- 実は JTAG の操作をよく知らない。SIR/SDR を基本とすれば良いわけか。なるほど。
で、XP2WriteDlg.cpp にこれを使っているコードがある。コードは長いがなにをやっているかはわかりやすい。
tx[0]=0x16; //IDCODE
tx[0]=0x1C; //Preload
tx[0]=0x15; //Enter programming mode
tx[0]=0xB2; //Read status
tx[0]=0x03; //Erace
tx[0]=0x1E; //Leave programming mode
tx[0]=0x21; //InitAddress
tx[0]=0x67; //ProgramIncrRti
tx[0]=0x52; //Program/Status
tx[0]=0x1A; //program user code
tx[0]=0x21; //Reset addr
tx[0]=0x17; //Read Usercode
tx[0]=0x45; //program sed crc
tx[0]=0x44; //read sed crc
tx[0]=0x2F; //program done bit
tx[0]=0xFF; //Bypass ...to enter usermode?
8bit の IR を登場順に拾っていくとこんなかんじ。-- 随分あるものだ。
TN1086: MachXO JTAG Programming and Configuration User's Guide (pdf)
『DS1002: MachXO ファミリ データシート (日本語 pdf)』には、これを読めと書いてあるのだが、こんな情報は載っていない。
分かるのは、JTAG 1532 を通して Flash に書き込む方法と 直接 Config する方法があり、Flash からの Load指令(Refresh) もできるということぐらい。
... JTAG 1532 では、BSDL ファイル にコンフィグ方法が定義されている ... らしい。
ここからダウンロードして眺めてみることにしよう。
見たのだが... なにかそれらしいことが書いてあることは分かる。IR の定義も分かる。だが、アルゴリズムは直感的にはよくわからない。XP2WriteDlg.cpp と XP2 とを見比べて みるしかないか。それで理解が進んだら、今度は XP2 と MachXO,MachXO2 を見比べる -- って そんな手順以外ないのだろうか?
よくよく見たが、アルゴリズムなんて載っていない。載っているのは、IR に対応した DR の名前と bit 幅。
DR IR XP2_5E XO_2280 XO2_1200
ISC_ADDRESS ISC_ADDRESS_SHIFT 1938 1116 333
ISC_DATA ISC_DATA_SHIFT 638 436 1080
ISC_PDATA ISC_PROGRAM,ISC_READ 638 1080
ISC_PDATA VINCR_RTI,ISC_READ 436
ISC_SECTOR ISC_ERASE 8
ISC_CONFIG ISC_ENABLE,LSC_ENABLE_X 8
ISC_CONFIG ISC_SETUP,READ_SETUP 4
ちょっと比べてみたのだが、定義上は微妙に違う。手順も似ているが微妙に違うのだろうか?
あと、『Lattice XP2のC-SRAM書き込みモードに対応しました』という記事を発見。ただ、そういうことが可能であるということしか分からない。
どうも Lattice の場合 config は、Flash に対してやるものであって 直接 config は、optional みたいな感じがする。MachXO2 の場合、SPI や I2C でも config できるが 直接 config は、JTAG だけだし。
一番の問題は、ドキュメントを見付けられていないこと。
TN1204 MachXO2 Programming and Configuration Usage Guide の Appendix B. MachXO2 Slave SPI Programming Guide に 例が載っている。
この例が、XP2Write のコードに似ている。比較していけば、MachXO2 の Flash への config はできるようになるかも知れない。だが、もっと 直接説明した ドキュメントはないのだろうか?
ちょっと大変そうなかんじだ。もともとは、(後で困らないような) Jtag のメソッドを決めるために 調べてみようと思っただけ。その観点でまとめて次にいこう。
Lattice の場合、IR コードに多数のコマンドが定義されている。これはちょっと想定と違った。DR に流し込むデータにコマンドも含まれているのが普通だと思っていたのだ。
設計にあまり影響はないが、SIR と SDR を頻繁に切り替えて使う場合もあることを想定しておく。
JTAG の扱い方はよく知らないわけだが、デバイスに対して、IR の設定と DR の読み書きができれば良さそうな印象。
JTAG chain は、とりあえず考えない。当面使う予定のものは chain がない。デバイスの選択という概念は、とりあえずなしにして、カレントのデバイスのみを操作するような API だけ作っていこう。
Lattice のコンフィグは、とりあえず必要ない。とりあえず必要なのは、JTAG 使った ISP と通信。これを先にしよう。
... といってもデバイスによって手順が違う。デバイスのドライバは必要だが、部分的にサポートするような構造になる。
FPGA を直接 config するのと (SPI_FLASH とか)FLASH を書き込むのは全然別のものと考えていた。
SPI_FLASH の書き込みは、FPGA 内に作りこんだ回路との通信を想定していた。無駄が多いが、Lattice でも MachXO2 ならそのようなものは作れる。とりあえず、その構想のまま行く。
作りたいのは、ライタソフトではないのだ。あくまで、JTAG を通して通信するのをサポートするツールで その仕組みの応用として FLASH の書き込みができるなら対応を考える。直接 config するのは、これを作るためにも必要だし、基本機能として考える。... ということにしよう。
MachXO は JTAG 以外からの FLASH の書き込みは できないような感じだが、Breakout ボードしかつかう気がないし そうであれば なにも考えずに 純正ツールで書き込めるわけだから、気にしないことにする。
BSDL ファイル のチェック
そういえば、『LatticeXP2のFPGA回路内部へJTAGで通信する』 の記事には、
JTAGEモジュールを有効にするには、JTAGプライベート命令のIPA(0x32)とIPB(0x38)を使います。インストラクションレジスタにIPA命令を入れるとJTAGEモジュールの信号系統1が有効になり、IPB命令を入れると信号系統2が有効になります。
と書いてある。これは BSDL ファイルに記載されているのだろうか?
" IPB (00111000)," &
" IPA (00110010)," &
MachXO の場合はこう書いてある。大丈夫そうだ。
"PRIVATE (00000010, 00111010, 00110010, 10111010, " &
"11011101, 11001010, 00111000, 01100000, " &
だが、MachXO2 の場合、PRIVATE の中で記述してあるだけ。
JTAGF という機能はあるから出来ないわけではないが、enable にする手順が違うかも知れない。ただ、XP2 の場合も 同様だからたぶん大丈夫だろう。(内容訂正)
ここでつまずくと全然面白くない。MachXO2 Pico Dev kit が欲しかったが、とりあえずは、MachXO Breakout で良かったのかも知れない。
FPGA との通信の方法(めも)
一番作りたいものは、これなわけだ。いったいどうするのか整理しておこう。ただし、どれも未確認なので要注意。
MachXO の場合は、『LatticeXP2のFPGA回路内部へJTAGで通信する』 の記事がとても参考になる。
Diamond 1.1 で使った限り違うのは、lscc/diamond/1.1/cae_library/synthesis/verilog/machxo*.v に定義があり、インスタンシエートする必要はないということと、MachXO では、JRSTN ではなく JRST になっているということぐらい。
さて、IPA と IPB を 使って 2 つのチャネルが作れる。 『JCE1は、Capture-DRもしくはShift-DRのときにHになります。』ということだから、JCE1/JCE2 が H のときにそれぞれのチャネルが動作するようにしておけば良いのだろう。
使い方は、チャネル1(IPA) は、SPI として 通信に使う。チャネル2(IPB) は、rtavr の ISP に使うことにした。SPI_FLASH の書き換えは、rtavr の SPI を通して接続する予定(希望)だが、そんなまどろっこしいことをせずに、SPI_FLASH の線と直結するかも知れない(未定)。いずれにしても チャネル1に接続。
これらの通信を、JTAG のフルスピードで行うとまずい場合がある。rtavr の ISP は、rtavr の 周波数 (CLK2X / 2) の X 倍を超えてはいけないとか なにか条件がある。チャネル1(IPA) を rtavr の SPI につなぐ場合は、もっと厳しく 1/2.5 以下とか。しかも連続で送れないとか ファームウェアの都合に起因する条件もある。忘れてはいけないのでメモ。
___ ___ ___ ___
JCK _____| |___| |___| |___| ....
_______________________
JCE1 & JSHIFT _____| |____
IN SFT IN SFT IN SFT
どうもこんなタイミングで動かしてやれば良いらしい。
注意点は、両方とも 論理が逆なので、SPI と接続するときは反転して入力。MSB first か LSB first かは通信規約によるが、普通の SPI なら MSB first 。
あと Shift-DR でしか使えない。いったん Shift-DR に入ったら その状態でずっと使うのが基本。bit 同期を取り直すなら、Shift-DR を抜けて再度 Shift-DR に入り直す。
ISP はいまのところ RESET 状態でしか使えない。( JCE2 & JSHIFT ) を rtavr の RESET に入力することにしよう。
rtavr で、CPU を一時止める機能は、作れないことはないのだが、そうなると ISP に RESET のための レジスタ定義と レジスタへのアクセスメソッドの追加が必要になる。面倒というより論理が増えるし、メリットも感じないので とりあえずパス。
MachXO2 では、IPA/IPB がない。どうするのかは、要調査。 でも たぶん同様。
さて、同じ機能を Spartan-3A で使うには BSCAN_SPARTAN3A を使う。これもチャネルが2つある。チャネルの選択は同様で、IPA/IPB の代わりに USER1(0x02)/USER2(0x03) を使う。
同様の定義にするなら、JCE1/JCE2 , JSHIFT の代わりに SEL1/SEL2 , SHIFT を使う。TCK も同様だと思うのだが、タイミングが違うかも知れず扱いかたが変わるかも知れない。TCK の代わりに DRCK1/DRCK2 を使ったほうが良いかもしれない。こちらは、Shift-DR と連動するので確実かも。(その場合は、SHIFT との AND は不要 -- というかするとまずいかも)
Spartan-6 では、また違うのかも。4 つのチャネルが定義できて module の仕様も変わった。要調査。
Xilinxの config の方法(めも)
FPGA の config をどうしても作らないといけないのは、自作 ARTEMIS ボードの Spartan-3A 。-- CABLE が独自だから代用ができない。
ただ、基本はすごく簡単なような ...
JPROGRAM にして CFG_IN で bitstreame の内容を叩き込んで JSTART 。これだけのような ..
ただ、チェックとかはしないといけない。ステータスを見るには、READ_STATUS のシーケンスを CFG_IN で流して CFG_OUT で読むようだ。
SYNC_TIMEOUT
SEU_ERR
DONE
INIT
MODE
VSEL
GHIGH_B
GWE
GTS_CFG_B
DCM_LOCK
ID_ERROR
CRC_ERROR
『xulaload』のコードを見るとこれだけある。ちゃんと終了したか 。エラーなら理由は何かぐらい見ないと。
INIT_B を接続したが、不要なのか。ちなみに M1/M2/PROG_B は、SPI_FLASH からのロードを強制的に行ったり、スレーブシリアルモードにしたりする場合に使い、普通は不要。
ついでに書いておくと 相手が入力専用の TXD 以外 は抵抗を入れるべきだった。(スペース的に入れられたかどうか分からないが)。
同じようにしていろんな情報が取れるようだが、そこまでしなくて良いだろう。
Lattice のデバイスも このレベルなら簡単なのだろうが ... 今はよくわからない。まぁぼちぼちやろう。
通信機能のプロトコル
SPI をシリアルのように使いたい。どのような通信ルールにするか。
JTAG を使うのだから HOST 側はポーリングしないといけない。これはやむを得ないとして...どういうやり方が良いのだろう?
(案1)ステータスを読む/送信する/受信する/ といったコマンドを作る。
(案2)0xff は、データがない という意味にして、送信データがある場合は、データを送り ポーリングする場合は、0xff を送る。受信も同様で、データがなければ 0xff が読める。
(案1)は、ありがちで悪くなさそうなのだが、コマンドを決めないといけないし、変更すると混乱するから決めたものをずっと使うことになる。コマンドを決めるのに悩みそうだし、拡張が可能だから安易に拡張したくなるという罠もある。
(案2)は、シリアルの代替にしか使えなさそうだが、その分明快だ。こっちにしようかと思う。
ツールでは、terminal-mode というモードにして、このモードに入るとキー入力を送り 、受信データを そのまま表示する。MSYS の rxvt の上で動かすと 端末ソフトで通信しているのとあまり変わらない感じになるはず。モードから抜けるのは、~. とか。
SVF ファイルと ispVM
SVF ファイルとは、どういうものか知らなかったので ググってみたら TEXTファイルだと書いてあった。
MachXO2280 への Implement はできていたので SVF に変換して読んでみたところ ..
なんだか可読性が良いではないか。これなら、なにをやっているか(かなり)理解できる。随分参考になりそうだ。この情報と XP2Write を合わせて見れば、ライタも作れそうだ。
で、MachXO2 のほうも同じようにしようとしたら .. Export Files に JEDEC file の項目が出ていない。
理由がわからないので、新しい ispVM だけ インストールしてみることにした。
で、インストールされるものを眺めていたら なにかソースコードもある。
CPUEmbedded/PCM, CPUEmbedded/SCM, ispSlimVMEmbedded, ispVMEmbedded, SSPIEmbedded ... なんだろう?
JEDEC file の項目が出ない件についてはわからない。Diamond 1.2 の日本語ドキュメントが出ていたから 早々と 1.2 にするのが良いのかも知れない。
update チェックをしたら B1.1.01.50.42.10_xo2_1200JEDEC というそのままズバリな名前のパッチがでていた。 10MB ほどなので、Diamond 1.2(既に出ていた)にせずに パッチで済ませることにした。
XO2 も いずれ 2000/4000/7000 が出てくる。バージョンアップは、そのときでいいや。
(追記) 確かに JEDEC は作れた。しかし ... SVF への変換でエラーになった。Diamond 1.1 付属の ispVM は、17.9 。単独で インストールする ispVM は、18.0 なので試してみたが、これもダメ。待つしかないようだ。
あと ググっていたら、『XAPP058 には、エンべデッド SVF ファイル プレーヤのソース コードが掲載されています。』という情報も見付けた。ちょっと見てみようかと思う。
たぶん JTAG レイヤーの プリミティブは、こういうのと同じレベルにするのが良いのだろう。参考にしたい。
ちょっと 『XAPP058 (日本語 pdf)』 を読んでみた。XSVF というバイナリに変換したものを入力して JTAG を操作するエンジンがあるらしい。
で、フロチャートを見ると XSIR, XSDR に加えて XRUNTEST の 3 つの処理しかない。XRUNTEST は、delay の役目がある。sleep とは違い クロックを出している。MMC/SD カードで クロックを出していることが重要な場合があったが、JTAG はどうなんだろうか? -- 少なくとも ユーザ回路での SPI 通信で クロックだけが欲しいような設計はあり得る。
そういうプリミティブも必要そうだ。あと API を決める上では、SPI通信が悩ましい。rtavr の場合、バイトデータを連続して送ると ファームウェアの処理が間に合わないのが明白。クロックを 100kHz ぐらいまで落とせば良いわけではあるが... せめて SPI をダブルバッファ化すべきかも知れない。あるいは... FIFO の CPI を使うことにして、SPI ブリッジを入れる... とか。
少なくとも クロックだけを動的に変更する API は必要そうだ。
SSPIEmbedded をちょっと見たのだが、『Slave SPI (SSPI) Embedded』が名称。 algorithm file and data file. を入力して SPI 経由の コンフィグをするものらしい。algorithm file は、コンフィグの手順を抽象的に定義したものというより 単なるステートマシンのパラメータみたいな気がする。
API を決める上での 調査は、これぐらいで良いだろう。
JTAG レイヤの API
void jtag_go(CABLE cbl,int state);
void jtag_init(CABLE cbl);
void jtag_IDLE(CABLE cbl, int ms, int count);
void jtag_SIR(CABLE cbl, unsigned char *buf, int bit_len, int flags, unsigned char *rcv_buf);
void jtag_SDR(CABLE cbl, unsigned char *buf, int bit_len, int flags, unsigned char *rcv_buf);
void jtag_SIR32(CABLE cbl, unsigned int code, int bit_len, int flags, unsigned int *rcv_data);
void jtag_SDR32(CABLE cbl, unsigned int code, int bit_len, int flags, unsigned int *rcv_data);
こんな風に決めた。
jtag_init は、RunTestIdle 状態まで持っていく。
jtag_IDLE は、RunTestIdle 状態 にして、count 分 (tms,tdi) = (0,0) を送出。count が 0 なら ms (ミリ秒) を元に count を計算。
jtag_SIR/SDR は、ShiftIR/DR 状態にして、buf を送出。flags が 1 なら rcv_buf に TDO を採る。
状態は ShiftIR/DR のまま。
jtag_SIR32/SDR32 は、32bit までのデータを扱う場合にコードを簡潔に書くための API 。
jtag_go は内部関数。RunTestIdle, ShiftIR, ShiftDR にしか行けない。
XP2Write なんかは、FLush という概念がある。キューに溜め込んでおいて、複数の 処理をまとめてやることでUSBの遅延の影響を少なくするわけだ。
決めた API では、受信データを要求された時に、自動で SYNC するという構想。serjtag のプロトコルでは、送出のみとか all 0 の送出では、送出データを送らないとか、TDO の値は、要求されたときだけ採取して返すようになっているので 送受信データ量も減らせる。ft245r (BitBang) では、データ量は減らないが、自動で SYNCというのは有効。
関数は 全部 void 。どうせ受信データをチェックするから、いちいちチェックしなくて良いだろうという考え。
TARGET レイヤの API
typedef struct target *TARGET;
struct target {
int (* sel_chan)(TARGET tgt, CABLE cbl, int chan);
int (* program)(TARGET tgt, CABLE cbl, unsigned char *buf, int len);
int (* verify)(TARGET tgt, CABLE cbl, unsigned char *buf, int len);
};
int tgtxil_init (TARGET tgt, CABLE cbl, unsigned int device_id);
とりあえず、こんな風にした。SPI_FLASH の program は、もっと上位のレイヤ。
program/verify は、FPGA の直接 config で、RAM だけの 書き込みを想定。program/verify は作れなかったら常に ERROR するようにする。
sel_chan は、簡単だが最も重要。これでお膳立てをして、あとは、jtag_SDR/jtag_SDR32 で通信する。
ちなみに bitclock を変えるのは、CABLE の API 。
こんなわけで、ようやくツールづくりが回り始めた。ちょっとがんばってみよう。
いろいろ問題が出た。
まず、jtag 。
ShiftIR/DR 状態のまま終わるのは、無理。最後の bit は、TMS=1 で送出しないといけない。
これで最後という場合は、flags に 0x2 を付けることにした。... で、ターゲットの コンフィグのコードを書いて見たら、全部 0x2 が付くことになった。むしろ続く場合に 0x2 をつけた方がよさそうだ。
あと、状態が増えた。ちなみに、通信する場合も 1 つのブロックの処理をしたら いったん終わらせた方が良いかもしれない。CS の操作と同じなので bit 同期がとれる。
次にターゲットの API 。verify できるものなのかどうか良くわからない。xilinx の場合すごく大変そうだし、lattice の場合でも いったんプログラムモードから抜けたら読めるものなのかどうか?
program のときに verify なり CRC チェックなりをすることにして、verify プリミティブは削除しても良いかもしれない。lattice で verify だけ出来るのなら削除しないが、無理だったら削除することにしよう。
あと lattice では特にいくつかのパラメータが必要。最初に PRELOAD する bit 幅がまず必要。次に アドレスサイズとデータ幅。
XP2 と MachXO は、手順がかなり似ているが、違う部分もある。MachXO2 も 多少違うはず。
これらの違いへの対応は、IDCODE で判断するつもり。
... だいぶ具体的なことが書けるようになってきた。もうすぐベースは出来るだろう。
まだまだ
なんと、Lattice の IDCODE は、ファミリで 1種類だった。... ということは IDCODE をパラメータとして渡しても コンフィグ できない。で、xx_init のパラメータは、LCMXO2280 とか名前で渡すことにした。
あと、Lattice XP2 と MachXO では、似ているものの やはり違いは大きい。SVF ファイルを見ると違いが良く分かる。
/* XP2 only */
#define ISC_PROGRAM_STATUS 0x52
#define ISC_ERASE_DONE 0x24
#define PROGRAM_SED_CRC 0x45
#define READ_SED_CRC 0x44
/* XO only */
#define ISC_SRAM_ENABLE 0x55
#define DATA_SHIFT 0x02
SIR で これだけ違う 命令を使う。ステータスの読み方なんかも違う。program() 自体別立てにした方がすっきりしそうだ。
一方 Xilinx の方は、IDCODE でデバイスまで分かる。だが、デバイスが違っても コンフィグするコードは FPGA なら 同じ。
さて、jed ファイルの読み込みも いんちきパーザを作ったので読み込めるようになった。デバイス固有のパラメータは、プログラムの中にテーブルを作って対応することにした。MachXO に関する 下位レイヤは揃ったことになる。後は上位レイヤだが、なかなか悩ましい。
MachXO2 の SVF が作成できた。
ispVM には、SVF の作成方法が 2 つある。試してだめだったのは、UFW での 作成で、組み込みの SVF 作成機能は OK だった。それだけでなく、Verify だけする設定とか、SRAM だけ書き換える設定があった。-- ispVM を起動しただけでは UFW しか動かせないので 実際にデバイスが接続されていないとダメなのかと早とちりしてたのだ。
SRAM だけ書き換える設定は、MachXO や XP2 にもあるから SVF を作れば、想定どおりのライタが作れる。
問題は、組み合わせが沢山あるから、どういう API にして 関数をどう作るか。
一応、SRAM への書き込みを default にして、Flash の書き込みは option にしようかと思う。verify も同様。あと ERASE のみというのも、必要なのかも知れない。これは FLASH のみ。
で、MachXO (LCMXO2280) と MachXO2 と XP2 (LFXP2_5E) に対応するつもり。今 LCMXO2280 は持っているからテストできる。MachXO2 は、1200 以上をこれから使っていこうと思っている。LFXP2_5E は、雑誌付録でまだ入手可能。それ以外は対応するつもりはない。
ちなみに、Xilinx は、XC3S50A/XC3S200A と XC6SLX9 のみを予定。-- 要するに自分が使う予定があるもののみ。
Lattice の SVF を整理。
Flash の Erase , Program, Read と SRAM の Program , Read を XP2/XO/XO2 について出力して比べて見た。
見ているとどうもいくつかのプリミティブに分けられそう。
その前に、読み書きする対象について。
XO は最も基本的で コンフィグデータ と USERCODE の 2 つ。XP2 はそれに SED_CRC が付く。で、コンフィグデータの書きかたは、SRAM と FLASH であまり違いはない。-- SRAM に書いて WRITE-BACK しているような印象。
XO2 は、SED_CRC はないが、FEATURE というのがあるようだ。それに加えて、FLASH での WRITE では、ADDRESS を WRITE している。どういう概念なのか良くわかっていない。また XO2 は、SIR の命令も随分違う。XP2/XO とは、大分違う印象だ。
まず、Enter_Programming_Mode と Exit_Programming_Mode , この手続きは デバイスが同じなら同じ。
あと、Program_Done 。更新系では、Exit_Programming_Mode の前に行う。エラーが起きた場合、Program_Done してはいけない(たぶん)。
この間で、読み書きする。たぶん Erase → Program → Verify(Read) に分けることができて 独立したプリミティブに出来そう。 あと、SRAM と FLASH は、それぞれのプリミティブのパラメータに出来そう。( Program_Done も SRAM と FLASH の区別がいるかも )
読み書きする対象はいくつかあるのだが、単一のメモリブロックということにしている。サイズは、決まっているので、コンフィグデータ , (SED_CRC/FEATURE) , USERCODE の順に配置するつもり。
ただ、XO2 がどうなっているか、ちゃんと調べた後でないと確定できない。
LCMXO2_1200 (SRAM):
0 - 359639 (333 * 1080) Config data
359640 - 359671 (32) USERCODE
LCMXO2_1200 (FLASH):
0 - 278399 (128 * 2175) Config data
278400 - 343935 (128 * 512) UFM
343936 - 344015 (80) FEATURE
344016 - 344047 (32) USERCODE
XP2/XO は、SRAM と FLASH に書くデータのサイズが同じで address_size x data_width で計算できた。(データの内容も同じ: 確認済)
XO2 も SRAM に書くデータのサイズは、address_size x data_width で同じ。
だが FLASH に書くデータは別のものであるらしい。そして、jed ファイルに入っているのは、FLASH に書くデータ。-- これは困った。jed ファイル は容易に作れるが SRAM に直接書けるものではない。
SRAM に書くデータ は、ispVM を 起動すれば SVF で 作れるが手順が面倒。
『TN1204: MachXO2 コンフィグレーションガイド (日本語 pdf)』
に書いてあることが少し理解できるようになった。
- 設定は、「SpreadSheet View」の「Global Preferences」で行うが、まず GENERATE_BITSTREAM を ON にして .bit ファイルを生成しないと SRAM 用 SVF は作れない。COMPRESS_CONFIG は、.bit ファイルにだけ影響すると書いてあるが、ON にしないと .jed ファイルが生成されない。
- FLASH のエリアは、CFM と UFM そして、Feature Row と USERCODE 。CFM は、"Configuration Flash" という記述で書かれる場合もある。Flash は、桁 x 行(Row) でアドレスされていて、Feature Row は ひとつの 行(Row) を USERCODE と共に使用する。
CONFIGURATION のデフォルトは、CFG_EBRUFM となっているが、EBR(ブロックRAM) の初期値を UFM に置くとう意味で、ユーザロジックで書き換えが可能になっている。
どうも MachXO2 では、SRAM 用のデータを作るのが面倒なようだ。だが、SRAM 用の SVF ファイルから取り出せば 作れないことはない。
作ってどうするのか?
Flash を読み書きする ロジックを SRAM だけで動かすように作るつもりだったのだが ..
まぁ、すくなくとも、こういう特殊なものは、ツールで使うとか用途も特殊。そうであれば、一回作ったものを使い回すはずで、作成の手間は多少あってもかまわないのかも知れない。
ちなみに 無圧縮 bit ファイルのサイズは、45376 バイトだった。情報量は、359640/8 = 44955 バイトで 差分は、421 バイト。
Lattice Semiconductor Corporation Bitstream
Version: Diamond_1.1_Pro duction (517)
Bitstream Status: Advanced Version 1.62
Design name: rtavr_test_rtavr_test.ncd
Architecture: xo2c00
Part: LCMXO2-1200HC-4TQFP100ES
Date: Wed Jun 15 05:50:25 2011
Rows: 333
Cols: 1080
Bits: 359640
Readback: Off
Security: Off
Bitstream CRC: 0xF760
421 バイトのなかには、こういう情報もヘッダとして入っているし、FEATURE ROW , USERCODE が別にあるはず。必要な情報を取り出すこと自体は容易そうだが、無圧縮の bit ファイルを作るということは、設定を変更して Implement しなおすということで、ispVM を起動して設定するより時間がかかる。
Digilent JTAG SMT1

あ、Digilent が、FTDI 採用している! ... と思ったら iMPACT から直接使えるのか。
そうか。JTAG 界 は FTDI があれば、良いわけか。... そうなると 作っているツールは、LCMXO2280C-B-EVN (MachXO 2280 Breakout Board Evaluation Kit) に対応しておけば、万全といえる。
ただ、EEPROM 設定済みの FT2232 は、Synchronous BitBang Mode が使えないかも。
-- と思ったが ドキュメントを見る限り、大丈夫なようだ。
ちなみに、MPSSE の使い方。ちゃんと対応すれば、30MHz もの bitclock で動作できる。
- AN_135_MPSSE_Basics
これ読むと MPSSE を使う場合でも Open , Close は同じで良いらしい。FT_SetBitMode からが違う。データの詰め方が違うところは、影響が大きいが、1つのソースで対応できるはず。
- AN_108 -- これに MPSSE の詳細が書いてあるらしい。
あと、実効性能は、MPSSE の場合、片道 20〜24Mbps 程度だそうだ。さて、Synchronous BitBang Mode はどれぐらいになるのだろう?
FT232R と同様に設定可能な bitclock より 実効性能がボトルネックになるはず。FT2232HL のデータシートだと Synchronous FIFO Mode は 25MB/sec 以上と書いてある。Synchronous BitBang Mode は、送信データ量と受信データ量が同じだから 片道 12MB/sec ぐらい?
... CLK の ON/OFF に 2 バイト送信するので、そこまで出るなら 6Mbps ぐらいということになる。
MPSSE の 1/4 程度なわけだが、Config する程度ならデータ量は、50A , MachXO 2280 , MachXO2 1200 クラスだと 多くて 0.5 Mbit ぐらい。 バウンダリスキャンをして パラレルの Flash に書きこむような使い方だと いくらでも性能は欲しいが、Config する程度ならば十分すぎるぐらい。FT232R 使っても あまりストレスはないだろうと思える。
ついでにいろいろ見ていたら、Hi-Speed シングルチャネルの FT232H なんてものがある。

FTDI 純正の モジュール UM232H (1801円) なんてのも出ている。(データシート)
MPSSE も使えるし、JTAG 用に便利かも。... あとよく見たら CLK 付きの Fast Serial がある。... これは PDI に使えるかも。
ツールの進捗状況。
基本的なものが動くようになった。ターゲットは、Lattice LCMXO2280C-B-EVN (MachXO 2280 Breakout Board Evaluation Kit) 。FT2232H + MachXO が載ったボードで、MPSSE ではなく Synchronous BitBangMode を使っている。
今は、ft245r CABLE ドライバと jtag 操作が一応動いたという段階。LCMXO2280C-B-EVN を使って、config 関係のコードのテストが可能になったし、SPI terminal モードとか ISP でのプログラムのコードを作ってテストもできる。それらが終わったらいよいよ rtavr のテストを開始できる。
XC3S50A/200A の Artemis ボードの出番がないが、ある程度ツールが動くようになれば、AE-UM232R を使ってテストが出来るようになる。やっぱり最初は、Xilinx の config で、それが出来たら、AE-UM232R 互換ボードで serjtag を使っておなじことができる所まで持っていく。
まぁこんな手順で進めようかと思っている。
ツールの進捗状況2。
ツールをテストするため、LCMXO2280C-B-EVN の HDL を作った。
まずは、内部クロックの確認と LED の ピン割り当てが正しいかのテスト。-- OK。
次に、JTAG の先に、単にエコーバックする spi_echo と メモリを内部に持った ISP をつけた。
IPA/IPB が選択されたら それぞれ LED を点灯させる。-- OK。
エコーバックのテスト :
spi_test
30 fe
31 0c
32 0c
33 cc
34 0c
35 cd
36 0d
37 0f
38 c7
39 ce
ff 0e
ff ff
spi_test done
値は変だが、なにか返って来た。
(続く)