2012年03月23日

LPCインターフェイスめも

Lattice のリファレンスデザインのなかに

があるのを見つけた。そういえば、自作FPGA ボード を相互に接続するのに I/O が 7本 + 1(入力専用)しかなく、これで実装できるインターフェイスを探したときに LPC を知ったのだった。

    簡単に説明すると、最低 LRESET, LCLK, LFRAME , LAD[3:0] の 7 本の線で接続できる バス規格。周波数は、33 MHz 。

LPC は Intel が提唱した規格で PC の SUPER I/O 用に実際に使われていた。SUPER I/O というのは、所謂レガシーインターフェイスをまとめたもので、今でもデジキーで入手できるチップがある。

もの自体には興味がないが、データシートは実装を実際にどういう風にするのかという参考になる。

    ちょっと見てみたところ、LDRQ , SERIRQ といった DMA や割り込み要求の線がある。実際には 7 本では済まないわけだが、イベントを通知する線は まぁ必要だろう。

    SUPER I/O のデバイスは、シリアル/パラレル/ゲームポート/MIDI/FDC など。あと ハードウェアモニタ関連で、ファンとか 電圧監視用 ADC とか GPIO とか。

    そういえば、PC の bios の FLASH にも使われていた。LPC を初めて知ったのは、これかも知れない。

    こっちのデータシートは、どういう風にアクセスするのか詳細が書いてある。

LPC の詳細

    さて、RD1049 をひもといて見る。ドキュメントは RD1049 自体のもの以外に LPC の仕様書が入っている。規模は、MachXO2 で HOST 用が 84 LUT , デバイス用が 73 LUT 。

    どうも、アドレス 16bit / データ 8bit の ISA バスのような 仕様で使っているようだ。

    次に 仕様書をちょっと見てみた。

    16bit の I/O アドレス以外に 32bit のメモリアドレスが定義されていて、いろいろな転送モードがある。どうも ISA バスの機能を包含することが(もともとの規格では)重要らしい。

      Host Initlated Memory Read
      Host Initlated Firmware Memory Read
      Host Initlated I/O Read

      Host Initlated Memory Write
      Host Initlated Firmware Memory Write
      Host Initlated I/O Write

      Peripheral Initlated Memory Read
      Peripheral Initlated I/O Read (8bit , 16bit, 32bit)

      Peripheral Initlated Memory Write
      Peripheral Initlated I/O Write (8bit , 16bit, 32bit)

      DMA Read (8bit , 16bit, 32bit)
      DMA Write (8bit , 16bit, 32bit)

    RD1049 がサポートしているのは、Host Initlated I/O Read/Write のみのようだ。どんなアクセスをするのか、DMA も加えて表にしてみた。

      START CYCTYPE+DIR ADDR TAR SYNC DATA TAR total
      Host Initlated I/O Read H1 H1 H4 H2 P1 P2 P2 13
      CHANNEL+SIZE
      DMA Write Cycle (8bit) H1 H1 H2 H2 P1 P2 P2 11
      DMA Write Cycle (16bit) H1 H1 H2 H2 P2 P4 P2 14
      DMA Write Cycle (32bit) H1 H1 H2 H2 P4 P8 P2 20

      START CYCTYPE+DIR ADDR DATA TAR SYNC TAR total
      Host Initlated I/O Write H1 H1 H4 H2 H2 P1 P2 13
      CHANNEL+SIZE
      DMA Read Cycle (8bit) H1 H1 H2 H2 H2 P1 P2 11
      DMA Read Cycle (16bit) H1 H1 H2 H4 H4 P2 P4 18
      DMA Read Cycle (32bit) H1 H1 H2 H8 H8 P4 P8 32

    必ずホストが、転送を開始する DMAも同じで、デバイス側の要求が受け付けられたら HOST が転送をスタートさせる。

    H1 というのは、Host 側が 1 回(4bit の)転送を行うという意味。P2 は デバイス側は 2 回。
    DMA では ADDR の代わりに CHANNEL と SIZE が送られる。あと LFRAME は、START の 1 クロックだけ L になる。

    33 MHz 4bit だから 16.5 MB/sec の帯域だが、転送にはこのシーケンスが必要なので、実際の帯域は随分落ちる。Host Initlated I/O Read/Write では 13 クロックで 1 バイトだから 2.56 MB/sec 。

    ちょっと思ったより帯域が少ないのでがっかりだが ... 仕様など知ったことではないというスタンスでプロトコルを 再定義すれば 512B のバースト転送とかで、16 MB/sec ぐらいにはなるかも知れない。

      よく分かって書いているわけではないが、DMA の TAR を 2 クロックに限定して DMA のサイズを 再定義してやるとか。ついでに書くと DDR も CHANNEL か SIZE で指定できるようにしたりして。

      追記: DMA の TAR のクロック数は、上記の表の通りである必要はない。TAR の後に来るのは、SYNC か START で DATA 待ちみたいな感じ。


    以下 START 等の意味。(関係なさそうなものは省略しているので注意)

    START

      0000 Start
      1111 Stop/Abort

      普通 0000 でスタートする。スタートは LFRAME が L になる。Stop/Abort は、wait のタイムアウト時に使う。

    CYCTYPE + DIR

      000x I/O Read
      001x I/O Write
      100x DMA Read
      101x DMA Write

      x は 0 にせよということだが、読む方はきにしない?

    SIZE

      xx00 (0) 8bit
      xx01 (1) 16bit
      xx11 (3) 32bit

      2 のべき乗ルールなら良かったのだが、N+1 になっているようだ。

    SYNC

      0000 Ready
      0101 Short Wait
      0110 Long Wait
      1001 Ready More
      1010 Error

      Short Wait/Long Wait で 所謂 Wait が挿入できるようだ。Short /Long で Timeout のパラメータを変えるものらしい。Short は 数クロック / Long でも 1 マイクロ秒 (30 クロック)程度。

      Timeout したときに HOST は、LFRAME を L にするのだが、数クロック後に 1111(START:abort) を送出して H に戻す。LFRAME=L と同時に 1111 を送出すると信号がぶつかるからダメ。

    TAR (Turn Around)

      1111 zzzz ...

      LAD も weak pull-up だそうだ。最初だけ 1111 にせよということらしい。

    CHANNEL

      なんでも良いかと思ったらルールがあった。0-3 が 8bit で 5-7 が 16 bit 4 が バスマスタ用って書いてある。あと bit3 は、TC(Terminal Count) で 1 だと 最後の転送であることを指示する。

      そして、LDRQ もルールがあった。LCLK に同期したシリアルで、

      LCLK ____ ____ ____ ____ ____ ____
      _____| |____| |____| |____| |____| |____| |____

      LDRQ __________ _________
      |_________| bit2 | bit1 | bit0 |

      こんな風に送るものらしい。

      書き忘れたが、他のデータも negedge LCLK でデータ送出、posedge LCLK で受け取り。

      ちなみに、SERIRQ (Serialized IRQ) というのも プロトコルがあり、LDRQ より複雑そう。
      ( LPC の仕様書には詳細は記述されてない。PCI の仕様書で定義されているらしい。)

おわりに

    なかなか難しいものようだ。だが完全オリジナルよりは、LPC ベースに検討した方が良さそう。

    やりたいことは、もともと 7bit + 入力 1 での デバイスの拡張なのだ。DMA の使い方を変更・拡張して、自分の目的にあったものを作ってみたい。

    あと、lattice のリファレンスデザインは、 lattice のデバイスにインプリメントする場合に限り自由なのであって、本当に自由にしたければ自分で作らないといけない。あくまで参考として使うようにしないと。

おまけ

    RD1049 レベルのものを書いてみた。

  • lpc_master.v
  • lpc_slave.v

    本当は、Host-Peripheral の関係だが、なんとなく master-slave というネーミングにした。あと用語で LAD とすべきところを LDA にしてしまった。(未修正) 。まぁプロトタイプというか書いてみただけだから ... 。もちろん動く保証もない。

    基本的に posedge で state を変更し 入力処理をして、negedge では、state に応じた出力処理になるよにしている。規模は master が 80 LUT , slave が 65 LUT 。RD1049 と似た様なもの。

    これを元にどう膨らませようか思案中。

    まず slave 側。I/O 空間にレジスタをマッピングして定義したデバイスを動作させるようにして、512B ぐらいのバッファを DMA の手順でバースト転送できるようにしたい。あと、クロックは、LCLK をマスタークロックとして全部同期させる。

    slave 側のデバイスとして SDカードをサポートするのをまず想定している。それ以外に複数の slave で共通のデバイスをもたせたりもしたい。なかなかに難しそうな...

    master 側は、LCLK を マスタークロック にしないで ハンドシェークさせるつもり。master 側が数分の1 のクロックで動作しても問題ないようにしたいが、master 側 の方が速かったりするケースにも対応したいような... これもやっぱり難しそう。

追記: OpenCores の LPC モジュール

  • wb_lpc -- Wishbone LPC Host and Peripheral Bridge

    というのがあった。Features を見てみると DMA や firmware アクセス , Serialized IRQ など フルスペックのように見える。

    DMA の DIR (Read/Write の方向) をどう設計すべきか、参考になるかと期待したのだが ... よくわからなかった。より上位で決めるような設計のようだ。

    serirq については、少し分かった。

      START FRAME -- IRQ0 FRAME ... IRQN FRAME -- STOP FRAME --

      START FRAME 0 ... 0 1 1 (6 - 12 clocks)
      P/H H
      IRQN FRAME 0/1 1 1 (3 clocks)
      P
      STOP FRAME 1 0 0 1 1 (5 clocks)
      H H
      IRQ : IRQ0 ... IRQ15 IOCHECK ( INTA INTB INTC INTD .. )

    最初は、Peripheral が 0 にする場合もあれば Host が 0 にする場合もある。続く 3-7 clock Host が 0 にする。0 の期間は、4,6,8 clock だそうだ。どちらも出力しなくても 1 になるから オープンドレイン?

    ちなみに、信号は、posedge で出力、negedge で取り込み。

    次に 3 clock (S - R - T)づつの FRAME が続く。 IRQ15 までの 16 個かと思ったが、未定義を含めて 17個 - 32個分ある。(数は設定で決まる。)

ちょっとコードを書いてみた。

    module serirq_slave (
    input LCLK
    , input LRESET
    , inout SERIRQ

    , input [7:0] irq_req
    );

    reg [3:0] state;
    reg [1:0] sub_state; // S R T
    reg serirq_out;

    assign SERIRQ = serirq_out ? 1'b0 : 1'bz;

    always @(negedge LCLK)
    begin
    if (sub_state == 2'b01)
    begin
    if ((state == 4'h1) & (irq_req[0])) serirq_out <= 1'b1;
    else if ((state == 4'h2) & (irq_req[1])) serirq_out <= 1'b1;
    else if ((state == 4'h3) & (irq_req[2])) serirq_out <= 1'b1;
    else if ((state == 4'h4) & (irq_req[3])) serirq_out <= 1'b1;
    else if ((state == 4'h4) & (irq_req[3])) serirq_out <= 1'b1;
    else if ((state == 4'h5) & (irq_req[4])) serirq_out <= 1'b1;
    else if ((state == 4'h6) & (irq_req[5])) serirq_out <= 1'b1;
    else if ((state == 4'h7) & (irq_req[6])) serirq_out <= 1'b1;
    else if ((state == 4'h8) & (irq_req[7])) serirq_out <= 1'b1;
    else serirq_out <= 1'b0;
    end
    else if (sub_state == 2'b00)
    begin
    serirq_out <= irq_req[0] | irq_req[1] | irq_req[2] | irq_req[3]
    | irq_req[4] | irq_req[5] | irq_req[6] | irq_req[7]
    ;
    end
    else serirq_out <= 1'b0;
    end // always

    always @(posedge LCLK)
    begin
    if (LRESET)
    begin
    state <= 4'h0;
    sub_state <= 2'b00;
    end
    else if ((sub_state == 2'b00) & ~SERIRQ)
    begin
    state <= 4'h0;
    sub_state <= 2'b01;
    end
    else if (sub_state == 2'b00)
    begin
    state <= 4'h0;
    sub_state <= 2'b00;
    end
    else if ( (sub_state == 2'b01) & (state == 4'h0) & SERIRQ)
    begin
    state <= 4'h0;
    sub_state <= 2'b10;
    end
    else if ( (sub_state == 2'b01) & (state == 4'h0))
    begin
    state <= 4'h0;
    sub_state <= 2'b01;
    end
    else if ( (sub_state == 2'b11) & ~SERIRQ )
    begin
    state <= 4'h0;
    sub_state <= 2'b00;
    end
    else
    begin
    sub_state <= sub_state + 2'b01;
    end
    end // always
    endmodule


    簡単に説明すると、posedge LCLK で ステート制御。ステートは 3 の倍数で進むので 2 つに分けている。スタートビット検出をきっかけに進む。( 最初のスタートビットは、slave 側が作っている。)

    ストップビットは、2bit 目の 0 を検出したところで IDLE に戻る。

    sub_state は、0 → 1 → 2 → 3 → 1 → 2 → 3 と進む。0 になるのは IDLE だけ。

    master も状態制御は、同じようなもの。スタートストップビットの送出と irq_req が取り込みに変わる。

    冗長な書き方だが、14 スライス/27 LUT 。

LPC マザー

    LPC HOST をいくつか接続できるものを作ってみたい。

    HOST 毎に制御するデバイスが GPIO , SDIO , シリアル とか。共有するデバイスが LCD とか キーボードとか。

    あと入れたいのが、HOST 間通信。4 つ HOST が付けられるとしたら 12 個の FIFO でも実装可能か。
    共有を考えなければ簡単?

    ただ、そんなものを作るぐらいなら、SDIO という気も。

    ちょっとググってみると Posedge SDIO device controller (pdf) なんてものが見つかった。

    SD bus を AHB Bus に変換する IP。チップだと思ったら違った。

    中華Android / 中華PMP に使われている CPU(SoC) は、超低価格なのだが PCI みたいな バスは持っていない。最も高速なインターフェイスが USB device (640Mbps) で次が SDIO (〜 80Mbps x 4 とか) というパターンも多い。これになにかデバイスを付けようとすれば、SDIO のデバイスコントローラが欲しくなるのだった。

      S-ATA が付いているものもある。(Allwinner A10) 。Ethernet は一般的だが 100Mbps で上記より遅い。

    で、公開されている SDIO Simplifyed Specification を見てみた。

       I/O の方式は、SPI , 4bit-SD 以外に 1bit-SD がある。(これはメモリカードも同じ)

       割り込み(IRQ) は、DAT[1] を使うが 4bit-SD では、特定のタイミングでのみ有効(optional) 。詳細は削られている。

       DAT[2] にも Read Wait という機能が割り当てられている(optional)

       I/O 電圧変更は、SPI でも可能なようだ。

      SDIO は、基本的に CMD52(IO_RW_DIRECT), CMD53(IO_RW_EXTENDED) を使う。CMD52 は、レジスタアクセス+I/O 制御。CMD53 が I/O (サイズは 1-512B)

      レジスタ の仕様で 0-FF は、OCCR(Card Common Control Register) といって、いろいろ決まりごとがある。
      256B 単位で Function 1-7 の FBR(Function Basic information Registers) が続く。

      Function の定義には、USB の標準クラスのようなものがある。UART , BlueTooth Type A, BlueTooth Type B, カメラ, GPS, WLAN , SDIO-ATA など。

      CMD52,CMD53 以外で発行されうるコマンドは、

      CMD0 Pin1=High (CS=Low : SPI)
      CMD8
      CMD5 Arg=0 Get IO OCR
      CMD5 Arg=WV
      ACMD41 Arg=00 Get memory OCR (CMD58 : SPI)
      CMD3 (SD only)

      初期化シーケンスから拾ってきただけなので、詳細は知らない。ACMD41 はエラー(OCR invalid)になる。
posted by すz at 22:33| Comment(1) | TrackBack(0) | MachXO2

2012年03月10日

MachXO2コンフィグめも

MachXO2のコンフィグについてのメモ。

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 の 読み書き

    MachXO2 のデータには、以下の種類があり、それぞれ別の手続きになる。( () 内は、1200 のサイズ )

    • CFG データ (128bit x 2175 )
    • UFM データ (128bit x 512 )
    • USERCODE ( 32bit)
    • FEATURE (64bit)
    • FEABITS (16bit)

    FLASH は、128bit の column と 2688 の row からなっていて、USERCODE , FEATURE , FEBITS は 最後の row に入っている。UFM は、ユーザ回路で使えるが、CFG データがはみ出す場合がある。また、ブロック RAM の初期データも UFM に圧縮されない形で入っている。

  • 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 で書き込むのも違う点。

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 と同じレベルまでもっていこう。
posted by すz at 12:47| Comment(0) | TrackBack(0) | MachXO2

2012年03月09日

MachXO2のJTAG通信

MachXO2 , MachXO ともに JTAG を通して SPI (のような方法)で通信できることになっている。MachXO2 breakout ボードでは、MPSSE で JTAG と接続されているから、理想的には、30Mbps までの速度での通信が可能。シリアルのように 外付けクロックにも依存しないからお手軽でもある。

  • LatticeXP2のFPGA回路内部へJTAGで通信する

    これは、XP2 に付いての記事だが、MachXO2もほぼ同じらしい。XP2 では、JTAGE を使うが、MachXO2 では、JTAGF , MachXO では、JTAGD を使う。

    /c/lscc/diamond/1.4/cae_library/synthesis/verilog/machxo2.v

    このあたりを見ると、インターフェイスがわかる。HOST 側での使い方はまったく同じ。

というわけで、通信しようとしているのだが、なかなか思うようにいっていない。何が間違いなのか分からなかったのだが ...どうも根本的なミスをしていたらしい。

    そもそも SPI は、双方の出力は同じタイミングで切り替わる。JTAG 経由の場合もそれは同じ。だから、8bit 目の SCK の立ち上がりで、入力処理をしたら、SCK が立ち下がるまでに次の出力処理も完了させなければならない。
    (補足: 普通に作ると出力が先行する。8 bit のデータを受け取る前に、出力を確定させないといけないが、そうはしたくないのが前提としてある。)

    だいたいが、そういう処理にしていなかった。だが、次の条件があり、なかなか面倒なのだ。

    上の記事には、SCK と MOSI は同時に変化するから、SCK の立ち上がりをトリガーにする 『@(posedge SCK)』 と MOSIは読み込めない。ようなことが書いてある。

で、困ったわけだが ... もっと高い周波数の CLK で 駆動して SCK MOSI ともにデータとして扱うことにした。(SCK はエッジを検出して処理)。もともと ISP として使いたいので、CLK が別にあるのが前提になるから、こうした方が都合がよい。

SCK と MOSI は同時に変化するので、SCK は、CLK でサンプリングして遅延させるようにする。具体的には、top モジュールで次のようにする。

    always @(posedge CLK)
    begin
    r_jtck_prev <= JTCK_IN;
    if (r_jtck_prev == JTCK_IN)
    r_jtck <= r_jtck_prev;
    end
    wire JTCK1 = r_jtck;
    wire JTDI = JTDI_IN;

JTCK_IN だけ ひとまず CLK で同期する。2 クロック連続で同じ値ならという論理なので、これだけで遅延されている。次に下位モジュールで、半クロックずらして処理をする。

    always @(negedge CLK)
    begin
    r_sck <= SCK;
    if (CS)
    :
    else if (~r_sck & SCK) // posedge SCK : INPUT
    begin
    入力処理
    :
    end
    end

これで、JTDI_IN の値は読めるはず。さて、SCK の立ち上がりですべてを行わないといけない 。これは次のようにした。

    else if (~r_sck & SCK) // posedge SCK : INPUT
    begin
    req_shift <= 1'b1;
    入力処理
    end
    else if (req_shift) // next
    begin
    req_shift <= 1'b0;
    :
    出力処理
    end

CLK を複数クロック使って 処理するわけだ。通信速度は、CLK の 1/10 以下でないとダメそうだが、CLKは普通 10 MHz 以上で、1Mbps 程度ならいける。
 
CLK
___ ___ ___ ___ ___ ___ ___ ___ ___
__| |___| |___| |___| |___| |___| |___| |___| |___| |___|

: : :
SCK : : :
_______________________________ ___
_____| |________________________________|


r_valid : : :
_________________________________________________________________
_________| |
: : :
r_req : : :
_______
_________| |_________________________________________________________
@ SPI_DATA_I input

これは、8bit 目を受け取ったときのタイミング。出力処理を他のモジュールで行うなら、CLK の立下りで 行うのが良さそう。

    always @(negedge CLK)
    begin
    if (SPI_DATA_REQ)
    r_data <= SPI_DATA;
    end
    assign SPI_DATA_I = r_data;

こんな風にして、エコーするだけのものは、動いた。(ラッチは必要なく、入出力をつないでも動く。)

実際の応用回路として、ISP を作ろうとしているのだが、こちらは、うまく動いてくれない。

SCK
___ ___ ___ ___ ___ ___ ___ ___
__| |___| |___| |___| |___| |___| |___| |___| |.....
: :
CS _______
|_____________________________________________________.....
: :
data
<bit7 ><bit6 ><bit5 ><bit4 ><bit3 ><bit2 > .....


随分長い間悩んでいたのだが、CS が L になってから 余計な 1bit があるのが原因だった。エコーするだけのものは ずれても問題ないのだが、通信できていると思い込んでいたのが敗因。


CLK
___ ___ ___ ___ ___ ___ ___ ___
__| |___| |___| |___| |___ .... __| |___| |___| |___| |___|

SPI_DATA_REQ
_______ _______
_________| |______________________ .... ___| |__________

r_req
_______ _______
_____________| |__________________ .... ______| |______

(a) (b) (c) (d)

コマンド データ

ISP のモジュールを設計しているのだが、こんな風に 2 バイト のデータ (コマンド , データ) 組みにしようとしている。処理のタイミングは それぞれ 2 つ作る。

(a) , (c) で 出力をラッチすると SPI_DATA_REQ の立下りで受け取られて 次の フェーズで HOST に出力される。(a), (b) で入力データを受け取ることが出来るが、(a) で解析してすぐに次のデータを決めるのは、タイミング的に厳しい。あらかじめ決めておいたデータを送ることにしよう。

といっても、アドレスが決まるのは、(c) でデータを受け取った後。演算する場合もあるので、(d) になる。

    ここで ISP の仕様を書いておく。

    // SSTPR 0110 100a PR[a] ( PR[0] : low byte of PR )
    // XXXX XXXX XXXX XXXX ( PR[1] : high byte of PR )
    //
    // SLD 0010 0I00 XXXX XXXX ( if I == 1 , PR = PR +1 )
    // XXXX XXXX load_data
    //
    // SST 0110 0I00 store_data ( if I == 1 , PR = PR +1 )
    // XXXX XXXX XXXX XXXX

    まぁたいしたことはない。ポインタをセットする命令と、ロード・ストアがあるのみ。


always @(posedge CLK)
begin
if (CS)
:
else
begin
r_req <= SPI_DATA_REQ;
(a) if (SPI_DATA_REQ & ~SPI_COUNT[0])
begin
r_data_out <= ISP_LOAD_DATA;
end
(b) if (r_req & ~SPI_COUNT[0])
begin
r_pr_inc <= f_pr_inc;
r_sstpr_hi <= f_sstpr_hi;
r_sstpr_lo <= f_sstpr_lo;
r_store <= f_store;
end
(c) if (SPI_DATA_REQ & SPI_COUNT[0])
begin
r_data_out[0] <= r_pr_inc;
r_data_out[1] <= r_load;
r_data_out[2] <= r_store;
r_data_out[3] <= 1'b1;
r_data_out[7:4] <= SPI_DATA[7:4];
end
(d) if (r_req & SPI_COUNT[0])
begin
if (r_pr_inc) r_pr <= r_pr + 1;
else if (r_sstpr_hi) r_pr[15:8] <= ISP_STORE_DATA;
else if (r_sstpr_lo) r_pr[7:0] <= ISP_STORE_DATA;
end
end

コードの一部を紹介するとこんな風になった。

ちなみに、コードで ISP_STORE_DATA となっているのは、SPI からの入力データで、ISP_LOAD_DATAは、メモリからの読み出しデータ。

f_pr_inc などは、デコードの結果。

HOST 側のコード

    HOST 側のコードは、随分前から用意してある。(rtavr_tools-0.x.tar.gz)。ちょっと解説。

    もともとは、Xilinx の自作ボード用として作っていたものだが、MachXO/MachXO2 にも一部対応。ISP を使ってプログラムメモリを書き換えるのと config の 両方の機能を想定している。

    MachXO2 は、FT2232H なので MPSSE が使えるのだが、FT232R でも使えるように Bitbang モードを使っている。

    使い方なのだが、少々くせがある。

    target_load タイプ [サイズ]

    これで、バッファに タイプで指定したものから読み込む。

    fpga_ram fpga_flash spi_flash rtavr_isp

    タイプには、以上のものを指定できるが、コードが出来ているのは、rtavr_isp のみ。

    erase タイプ
    program タイプ
    verify タイプ

    書き戻したり、ベリファイする場合は、こういう風に指定する。

    ファイルから読み込む場合は、次のコマンド。

    file_load [ファイルタイプ] file
    filetype: bit jed mcs mem

    MachXO2 に関係するのは、jed と mem 。isp の場合は、mem を使う。jed をコンフィグするコードも用意してあるが、未テスト。... というか未完成。

    mcs も読み込めはするが、SPI FLASH に書き込むには、先に専用の config を書きこまないとだめで、コードは全然。構想では、RAM のみ config して ... みたいなことを考えていたのだが ... MachXO2 では RAM 用のデータを用意するのが面倒そう。

    ちなみに、Xilinx も JTAG を通して通信することが可能。Xilinx 用のコードも入れてはあるのだが、実際に動かすのは随分先の話になりそう。

    他に テスト用のコードも入れてあって

    spi_test
    isp_test

    のコマンドがある。ついでなので、API に付いてもちょっと紹介。

    isp_test(TARGET tgt, CABLE cbl) {

    uint32_t s,r;

    jtag_reset(cbl);
    (tgt->sel_chan)(tgt, cbl, ISP_CHAN);

    s = (TPI_SETPR_LO << 8);
    jtag_SDR32R(cbl, s, 16, JTAG_RECV|JTAG_CONT, &r);
    :

    こんな感じで使えるようになっている。jtag_SDR32R が MSB first の SPI 通信で 32bit までを指定できる。JTAG_CONT は、最後に TMS を H にしないオプションで SPI 通信では必須。

    JTAG_RECVを指定しないと、戻り値不要。書き方も変わりバッファリングされる。

    tgt, cbl の初期化は、ちょっと面倒なので割愛。

rtavr_tools 最新版

  • rtavr_tools-0.7.tar.gz

    上記の内容に対応するコードを rtavr_tools 最新版として置いておく。


    rtavr_tools-0.7/
    /src -- HOST 側プログラム (MinGW , Linux 用)
    /rtavr_tools.exe -- プログラム 実行形式 (CUI)
    /test_hdl/ -- HDL ソース (tool_test.v , jtag_spi.v , isp.v)
    /out/test_hdl_xo2.jed -- MachXO2 breakout ボード用 (CLK 10 MHz)


    さて、これでようやく、ISP のベースが出来た。これがないと rtavr のデバッグが出来るような気がしなかった。ぼちぼち rtavr も実機でのデバッグを進めていこうと思う。

    あと、この ISP は、内部のメモリ(と アドレス可能なデータ)を読み書きするものでもある。調停がまだ出来ていないが、ロジアナとかフレームバッファの通信に応用できるはず。これをベースにしてなにか作ってみたい。

    fpga flash への 操作も できたほうが便利そうな気も。 開発のフェーズによっては、いちいち Diamond で書くのも面倒だろうし。プログラムとハードウェア(HDL) を入れ替えてデバッグしたりするとき なんかは役に立ちそう。ちなみに、fpga flash への 操作は、SVF を作って解析して作る。根気はいるが難しいことではない。気が向いたときでもやっておこう。

タイミング変更

    せっかく動かせたのだが、JTAG 通信の都合に合わせていったので、タイミングはやはり標準的なものではなくなっている。いずれは、rtavr の SPI モジュールに接続したりもしたいので、これでは困るのだ。それで、大胆な変更をあえて行うことにした。

    変更するのは以下のところ。

    • CS の遅延

      CS と通信開始までの 1 クロック(SCK) の空白は 困るので、CS を遅延させることにした。

    • 入力/出力のタイミング

      ISP 向けのコードを作って 入力 した後に 出力を確定できるという特徴は利用しなかった。タイミングが厳しくなるのが嫌なのが、その理由。そうであれば、出力先行で 普通のタイミングにした方が良い。それに合わせて SCK も反転させる。

    • SPI_DATA_VALID の有効化

      いままで SPI_DATA_REQ だけで制御してきたが、タイミングが全く変わるので SPI_DATA_VALID も 使うようにする。


    変更後 タイミング

    ___ __________________ _____
    SCK |___________________| |_________________|

    SPI_DATA_VALID: ____________________________________
    _______________________| |____

    SPI_DATA_REQ:
    _ _
    ___| |______________________________________________________| |__

    コードも随分変わったが、すんなり動かせた。今後は新方法に全面置き換え。以前のコードについて せっかく説明も書いたのだが、rtavr_tools-0.7 のみのコードになる(予定)。

付録: 外部 SPIデバイスとの通信

    `define TARGET_MachXO2
    //`define TARGET_MachXO
    //`define TARGET_LatticeXP2

    module spi_lattice (
    // JTAG
    input TOP_TDI
    , input TOP_TCK
    , input TOP_TMS
    , output TOP_TDO
    // EXTERNAL SPI PORT
    , output CS
    , output SCK
    , output SI
    , input SO
    );

    `ifdef TARGET_MachXO
    `define JTAG_BSCAN JTAGD
    OSCC osc_internal (.OSC(CLK)); // 18 MHz - 26 MHz
    `elsif TARGET_MachXO2
    `define JTAG_BSCAN JTAGF
    OSCH #(.NOM_FREQ("24.18")) osc_internal
    (.OSC(CLK), .STDBY(1'b0));
    `elsif TARGET_LatticeXP2
    `define JTAG_BSCAN JTAGE
    OSCE #(.NOM_FREQ("20.0")) osc_internal
    (.OSC(CLK));
    `endif

    `JTAG_BSCAN bscan (
    .JSHIFT(BSCAN_SHIFT)
    // .JRSTN(BSCAN_RESET) // H : in TestLogicReset State
    // , .JUPDATE(BSCAN_UPDATE)

    , .TDI(TOP_TDI)
    , .TCK(TOP_TCK)
    , .TMS(TOP_TMS)
    , .TDO(TOP_TDO)

    , .JTDI(JTDI_IN)
    , .JTCK(JTCK_IN) // negedge capt, posedge shift

    // signals for IPA
    , .JRTI1(JRTI1)
    , .JCE1(SEL1)
    , .JTDO1(JTDO1)

    // signals for IPB
    , .JRTI2(JRTI2)
    , .JCE2(SEL2)
    , .JTDO2(JTDO2)
    );

    reg r_jtck;
    reg r_jtck_prev;
    reg r_cs1;
    reg r_cs1_prev;
    reg r_cs2;
    reg r_cs2_prev;

    always @(posedge CLK)
    begin
    r_jtck_prev <= JTCK_IN;
    if (r_jtck_prev == JTCK_IN)
    r_jtck <= ~r_jtck_prev;
    if (r_jtck_prev & r_jtck & (r_jtck_prev == JTCK_IN)) // negedge JTCK
    begin
    r_cs1_prev <= ~(SEL1 & BSCAN_SHIFT);
    r_cs1 <= r_cs1_prev;
    r_cs2_prev <= ~(SEL2 & BSCAN_SHIFT);
    r_cs2 <= r_cs2_prev;
    end
    end
    wire JTCK1 = r_jtck;
    wire JTCK2 = r_jtck;
    wire JTDI = JTDI_IN;
    wire CS1 = r_cs1;
    wire CS2 = r_cs2;

    assign CS = CS1;
    assign SCK = JTCK1;
    assign SI = JTDI;
    assign JTDO1 = SO;

    endmodule

    たぶん、このコードで XO/XO2/XP2 で JTAG を通じて SPI デバイスと通信できる。XO2 で確認済みのコードをベースにしているのでたぶん大丈夫だろう。

    ちなみに、XP2 / XO2 だと SPI FLASH からのブートが可能。接続した SPI FLASH にプログラムするためには、こういったものを 一時的に config する必要がある。(バウンダリスキャンでも良いが遅い)

    XilinX も似た様なことは可能だが、内蔵クロックを使えないので、内蔵クロックを使わない やりかたに変更しないといけない。
posted by すz at 00:24| Comment(0) | TrackBack(0) | MachXO2