rtavr_tools で持っている FPGA の コンフィグが出来るようにしようと思っている。MachXO と LatticeXP2 は、一応書いてみたもの(ただし不動)があるが、MachXO2 は、ほぼこれから。
MachXO2 と MachXO , LatticeXP2 の違い
MachXO , LatticeXP2 は、RAM にコンフィグするデータがそのまま FLASH に格納されている。ちょっと手続きとか コマンドとかが違うものの、RAM へのアクセスと FLASH へのアクセスを統合できる。jed データを元に RAM に書くこともできる。
MachXO2 はというと FLASH のデータは圧縮されている。そのデータを FPGA 内部の伸張エンジンで RAM に展開している。伸張アルゴリズムは不明なので、自作の rtavr_tools では、jed は、FLASH のみが対象。
... と思ったが、実をいうと RAM への アクセスコードは、MachXO/LatticeXP2 とよく似ていて統合可能で、そういう風にコードは作っていた。
ついでに書いておくと Xilinx は、FLASH がなく RAM に書くデータだけがある。このデータは SPI FLASH に書くデータと 同じ(bit のオーダーは違う) で、SPI FLASH に対応したとしても 1 種類の内部データで扱える。
構想では、扱うデータはこんな分類になると思う
internal FLASH RAM SPI FLASH file format
Xilinx FPGA x O O bit,mcs
MachXO,XP2 O O ? jed
MachXO2 O x ? jed
MachXO2(RAM) x O ? ? (サポートしない)
O は作ろうと思っているもの。? は未定だが、やるとしても後回し。
MachXO2 のデータ と FLASH の 読み書き
- CFG データ (128bit x 2175 )
- UFM データ (128bit x 512 )
- USERCODE ( 32bit)
- FEATURE (64bit)
- FEABITS (16bit)
- CFG データ (128bit x 2175 )
XO2_INIT_ADDRESS(0x46)
SDR(0x04);
idle(10ms)
# 1 column 分
XO2_PROG_INCR_NV(0x70) XO2_READ_INCR_NV(0x73)
SDR(128 bit) idle( 1ms)
idle( 0ms) SDR(128 bit)
idle( 1ms)
# check busy (10)
XO2_CHECK_BUSY(0xF0)
for (i=0; i&ft;10; i++)
idle(1ms)
if (SDR (1bit 0) == 0 ) break;
read の場合、最初の row だけ XO2_INIT_ADDRES を発行し、SDR していく。PROGRAM の場合は、row 毎に XO2_INIT_ADDRES し、SDR 後 CHECK_BUSYする。
コマンドは、SIR(8bit) コマンドの値は、MachXO2 独自のものがほとんど。 - UFM データ (128bit x 512 )
XO2_INIT_ADDR_UFM(0x47)
idle(10ms)
UFM の場合、最初の指定のみが変わる。PROG/READ の方法は同じ。 - USERCODE ( 32bit)
XO2_USERCODE(0xC0) XO2_USERCODE(0xC0)
SDR (32bit) SDR (32bit)
XO2_PROGRAM_USERCODE(0xC2)
idle(10ms)
# check status bit
XO2_READ_STATUS(0x3C)
idle(1ms)
SDR (32bit) & 0x00003000 == 0 - FEATURE (64bit)
XO2_INIT_ADDRESS(0x46) XO2_READ_FEATURE (0xE7)
SDR(0x02) idle(1ms)
idle(10ms) SDR (64bit)
XO2_PROG_FEATURE( 0xE4)
SDR (64bit)
# check busy (略) - FEABITS (16bit)
XO2_PROG_FEABITS(0xF8) XO2_READ_FEABITS(0xFB)
SDR (16bit) idle(1ms)
idle(0ms) SDR (16bit)
# check busy (略)
これらを実行する前後で、初期化と後処理が必要。あと erase の手続きがある。
# check IDCODE
XO2_IDCODE(0xE0)
SDR(32bbit) == 0x012B2043 (1200の場合)
# Program Bscan register
PRELAD(0x1C)
SDR(208 bit: all 1 , 1200の場合)
# enable flash
XO2_ISC_ENABLE(0xC6)
SDR(0x08)
idle(10ms)
(ここまで共通)
--- erase ----
# check status bit
--- program/read
(Write のみ , erase で実行しないこと)
# Program DONE bit
XO2_PROGRAM_DONE(0x5E)
idle(0ms)
# check busy (略)
(ここから program/read 共通)
# Exit the programming mode
BYPASS(0xFF)
XO2_ISC_DISABLE(0x26)
idle(1000ms)
BYPASS(0xFF)
idle(0ms)
erase 手続き
XO2_ISC_ENABLE(0xC6)
SDR(0x00)
idle(10ms)
XO2_ISC_ERASE(0x0E)
SDR(0x01)
idle(1000ms)
BYPASS(0xFF)
XO2_ISC_ENABLE(0xC6)
SDR(0x08)
idle(10ms)
XO2_ISC_ERASE(0x0E)
SDR(0x0E)
# check busy (350)
ちなみに、XP2 や MachXO も似ていると言えば似ている。ただ、共通化できるほどは似ていない。FLASH への書き込みでは UFM はないし、RAM と同じ column , row で書き込むのも違う点。
MachXO2 のデータには、以下の種類があり、それぞれ別の手続きになる。( () 内は、1200 のサイズ )
FLASH は、128bit の column と 2688 の row からなっていて、USERCODE , FEATURE , FEBITS は 最後の row に入っている。UFM は、ユーザ回路で使えるが、CFG データがはみ出す場合がある。また、ブロック RAM の初期データも UFM に圧縮されない形で入っている。
rtavr_tools への実装
rtavr_tools の内部データは、ただの配列になっている。なので、次の順で格納するようにした。
CFG 128bit x 2175 = 34800 bytes
UFM 128bit x 512 = 8192 bytes
FEATURE 64bit 8 bytes
FEABITS 16bit 2 bytes
USERCODE 32bit 4 bytes
合計 43006 bytes
デバイスによって CFG,UFM の row が変わるが これは 別にデータベースを持っている。Preload での bit 数も データベースに持つ。
LCMXO2_1200.tgt_type = lscc
LCMXO2_1200.device_type = 0x12B2
LCMXO2_1200.address_size = 333
LCMXO2_1200.data_width = 1080
LCMXO2_1200.boundary_width = 208
LCMXO2_1200.flash_col = 128
LCMXO2_1200.flash_cfm_row = 2175
LCMXO2_1200.flash_ufm_row = 512
こんな形式で config ファイルを作っている。address_size , data_width は RAM の column , row。
address_size, data_width, boundary_width は、BSDL ファイルに記載がある。
flash_col, flash_cfm_row, flash_ufm_row は、SVF ファイルを生成すると分かる。( 他の記載は 信用できない。)
作るべきプリミティブは、erase_flash_xo2 , write_flash_xo2 , read_flash_xo2 。サブルーチンとして xo2_check_busy(ループ数) と xo2_read_status() を作る。
あと、FEABITS の jed ファイル読み込みが未対応。
rtavr_tools-0.8
- rtavr_tools-0.8.tar.gz
とりあえず、最新版。
これは、MachXO2 用の コンフィグのコードを入れた版。デバッグ中のもの。
FLASH への書き込みは、
cmd> fl xxxx.jed
cmd> w flash
FLASH からの読み込みは、
cmd> tl flash
とかで出来ることを期待したのだが、全然ダメ。読み込みすらちゃんと動かない。
RAM への読み書きは、以前に作ったコードが大分対応していたので、作ってみた。
cmd> tl ram
とすることで、なにやら読める。
cmd> w ram
で書き戻す操作になるのだが、ERASE はできるが、書き込みでエラーして ERASE された状態になる。
ただし、電源を入れなおすことで、元に戻る。
cmd> w flash
FLASH についての ERASE も動くようだ。
RAM への コンフィグについてのメモ
うまく動かないのであれこれ調べていたら、直接は関係ないことがいろいろ分かってきたのでメモしておく。
SRAM Fast Program というのがあって、
XO2_BITSTREAM_BURST(0x7A)
というコマンドで書き込んでいる。このコマンドでは、どうも 圧縮 bit ファイル と 非圧縮 bit ファイル のデータの 2 種類を流し込めるようなのだ。たぶん、FLASH からのパスを利用しているのだろう。
実際の bit ファイルとどういう関係にあるか調べてみた。
非圧縮 bit ファイル のデータは、47371 バイトで、 XO2_BITSTREAM_BURST で送りこむデータは、47739 バイト。差分の 368 バイト分の 0xff を先行して 送り 非圧縮 bit ファイル のデータ を送っている。
ついでに SRAMのデータ 44959 バイト(1080x333/8) と 非圧縮 bit ファイル のデータ の関係も調べてみた。
0000: ff ff bd cd ff ff dc 00 00 00 ff ff ff ff ff ff
0010: ff ff 62 00 00 00 41 07 80 b2 00
非圧縮 bit ファイル は、このような 0x1A(26) バイトが先行して格納され、SRAMのデータ が続く。 残り は、2386 バイトだが、
2e ce ff ff ff ff ff ff ff ff 43
こういうデータで始まっている。ブロック RAM に 2KB の初期値を入れたので、2386 バイトのうち 2KB ? (2K x 9bit ?) 分の値もそのなかに含まれているはず。
圧縮 bit ファイル のデータは、10170 バイト だった。XO2_BITSTREAM_BURST で書き込むデータは、84152 bit(10519 バイト) 349 バイトの差があるが、これも同様で、差分は、0xff が頭につく。
0000: ff ff bd cd ff ff dc 00 00 00 47 00 00 00 80 d4
0010: 04 c2 40 00 00 00 50 0a 0c c0 12 14 90 ff 44 00
|
:
2790: fd fb f7 ef df bf 7f ff fe fd fb f7 ef df bf 7f
27a0: ff fe fd fb f7 ef df bf 7f ff 44 00 00 00 02 00
27b0: 00 00 7a 00 00 00 ff ff ff ff
圧縮 bit ファイルはこんな風なデータ。非圧縮同様 0x1A バイトがヘッダなのかも知れない。
さて、jed ファイルと 圧縮 bit ファイルは 同じなのか? というのが気になったので見てみると... 似ている感じだが、厳密には だいぶ違う。
0000: ff ff bd cd ff ff dc 00 00 00 40 00 00 00 50 0a
0010: 0c c0 12 14 90 ff 62 00 00 00 1d 07 80 b2 00 00
:
2790: fb f7 ef df bf 7f ff fe fd fb f7 ef df bf 7f ff
27a0: 44 00 00 00 02 00 00 00 7a 00 00 00 ff ff ff ff
そもそもヘッダーがちょっと違う。だが、最後は 同じっぽい。もっとも 非圧縮 bit ファイルも同様。
最後の部分の最初だが、
jed ファイル:
1e60: 39 39 00 a4 c3 e7 e4 00 00 00 e9 ee
1e70: ff ff ff ff ff ff ff ff 43 01 00 00 4a 2a 0c 8c
1e80: 67 90 44 00 00 00 03 00 00 00 ff ff ff ff 6f 00
圧縮 bit ファイル:
1e50: 39 39 00 a4 c3 e7 e4 00 00 00 c8 cc ff ff ff ff
1e60: ff ff ff ff 43 01 00 00 4a 2a 0c 8c 67 90 44 00
こんな風にずれている。"e9 ee" と "c8 cc" は、たぶん CRC かチェックサム。ずれるルールは分からないが、ff が挿入されている感じ。
ところで、圧縮 bit ファイルを生成するのは、意外にも簡単だった。制約ファイルに
SYSCONFIG GENERATE_BITSTREAM=ENABLE ;
この行を入れておけば良い。
... なんだか、XO2_BITSTREAM_BURST だけが動けば良いような気がしてきた。FPGA を汚さずにコンフィグできるし、ブロックRAM もちゃんと初期化できる(はず) 。しかも 圧縮したデータを一気に書くから高速にできる。SPI-FLASH への書き込みでは、それようの回路をコンフィグしないといけないのだが、実装の目処も立つ。
bit ファイルの生成が面倒だと思っていたが、簡単ということも分かった。
XO2_BITSTREAM_BURST
これが動いた。圧縮 bit ファイル, 非圧縮 bit ファイル ともに OK 。それどころか、jed を読み込んだ内部形式のデータまで OK だった。
重要なのは、最初に十分な数の 0xff を送ること と 正しいデータを続けて送ることのようだ。後にごみがあっても問題ない。verify はできないが、失敗すると初期化状態のままになる。
cmd> fl test_hdl.bit
Lattice Semiconductor Corporation Bitstream
Version: Diamond_1.4_Production (87)
Bitstream Status: Final Version 1.80
Design name: MachXO2_Breakout_test_hdl_xo2.ncd
Architecture: xo2c00
Part: LCMXO2-1200ZE-1TQFP144
Date: Thu Mar 15 23:49:02 2012
Rows: 333
Cols: 1080
Bits: 359640
Readback: Off
Security: Off
Bitstream CRC: 0xA2F6
memory loaded size = 10170
cmd> w ram
Programming :################################################## 1.151 sec
program success
書き込みはわずか 1.151 秒。しかも ERASE の待ちが そのうちの 1 秒。
bit ファイル のフォーマット
ちょっと説明しておく。
0xff 0x00 で始まり ストリング 0x00 がいくつか続く。最後に 0xff が来てここまでがヘッダ。その後は バイナリでデータが続くのだが、バイト内の ビットが反転 している。(bit0 ⇔ bit7)。
もともと、Xilinx 用の bit ファイル の読み込みを作っていたのだが、自動判別して読み込むようにした。内部データは、ビットの反転を元に戻したもので、そのまま XO2_BITSTREAM_BURST(0x7A) にかけられる。
書き込みは格段に早いが、RAM にしか書かないので、使用目的は主にテスト。複数の config を切り替えて動作を確認するとか...。あとは、仮の回路を組み付けるときに使う。ツールでは、SPI ライタのサポートで使うつもり。
FLASH への書き込みは、コードは出来たものの全然だめなまま。目的は達したので、当面寝かせるかも。
rtavr_tools-0.9
- rtavr_tools-0.9
最新版を置いておく。
あと SPI FLASH への書き込みコードを作れば、コードだけは予定していたものをだいたい作ったことになる。自作 Xilinx ボード用のコードは形だけは入っている。
次は、rtavr のデバッグに進もう。
rtavr_tools-0.10
- rtavr_tools-0.10
最新版を置いておく。
rtavr のデバッグを少し始めているのだが、なかなか。1回合成するのに、2 時間ぐらいかかるし。
ちょっと息抜きに、SPI FLASH への書き込みコードを作ってみた。もとは、ATUSB162 で Mass Storage Class を作ったときのコードだが、移植というより書き直しになったので、ちょっとデバッグが必要そう。
あと、SPI 用の HDL も作っておいた。手順的には、これをまず SRAM に書き込んで 仮コンフィグし、mcs ファイルを読み込んでSPI FLASH に書き込む。ただしオフセット 0 から書き込んでいるので、mcs ファイルによっては、アドレスがずれる。
ちょっと MCS ファイルの調査:
UFW で bit ファイルを MCS に 変換できる。0x000000 と 0x010000 という アドレスが表示されている。XO2 や XP2 は、0x010000 から ロードするので、0x010000 に Insert するようだ。
*** dump ***
0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
*
10000: aa 76 96 6e a6 4e ce 86 36 04 62 96 36 a6 04 ea
10010: 4e 96 2e a6 4e 04 6a 4c 74 2c 1c 50 22 86 2e a6
10020: 5c 04 2a 16 ae 04 0c cc f4 4c 4c f4 8c 4c 04 8c
10030: 0c 5c ac 2c 5c ac ec 04 50 ff ff ff ff ff ff ff
10040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff
*
10150: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff bd
10160: cd ff ff dc 00 00 00 47 00 00 00 80 d4 04 c2 40
10170: 00 00 00 50 0a 0c c0 12 14 90 ff 44 00 00 00 02
10180: 00 00 00 ff ff ff ff 62 00 00 00 1d 07 80 b2 00
10190: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
できたファイルを 見てみるとこんな感じ。10150 からお馴染みの パターンが入っている。... jed ファイルと全く同じような ...
その上は何かというと テキストなのだった。bit の MSB/LSB を反転すると ...
Universal File Writer V2.48
Date: Thu 03/22/12 5:54:57
こんなようなデータが入っている。ごみはスキップして、ビットストリームだけ取り込んでくれるようだ。
ところで.... 論理合成する時間が MachXO2 だけ圧倒的に長いことに気がついた。1200 だとぎりぎりなので遅いのかと思っていたのでは、そうではない。XO や XP2 は結構速い。
ここまで MachXO2 でやったが、rtavr のデバッグの最初は、MachXO breakout を試してみようかと思っている。ただ、結構忘れてしまっている。
rtavr_tool -p LCMXO2280
rtavr_tool では、こんな風にチップ名を指定するようにしている。さて、XO の場合は、どこまで出来ていたのだっけか。
まず、基本的な話から思い出す。
XO は、flash と ram の構造が一致する。圧縮もない。さらに flash に書くデータと ram に書くデータは同じ。jed ファイルのデータと flash のデータも一致する。ただし、ram から読み込んだデータは、書き込んだデータとは一致しない。svf ファイルを見ても違うデータでベリファイしている。
で、動作を確認したところ..- flash の erase は大丈夫。
- flash の書き込みも 基本 OK なのだが、USERCODE が何故か一致しない。先頭が 0x00 になっってしまう。そのために config をエラーにしてしまっていた。USERCODE が不一致でも成功扱いにすることで、一応は flash に config できるようだ。
- flash の read も OK 。正しいデータと jedから読み込んだ内部データは一致した。
- ram への書き込みは、正しいかチェックできない。コンフィグした回路が動かないことから失敗しているようだ。
まぁ、こんなところ。flash への操作はひと通り可能にしたので使えないことはない。
これで、少しやるきが出た。まずは、MachXO2 と同じレベルまでもっていこう。 - flash の erase は大丈夫。