FPGA開発日記

FPGAというより、コンピュータアーキテクチャかもね! カテゴリ別記事インデックス https://sites.google.com/site/fpgadevelopindex/

RocketChip周辺のモジュール接続図を作成した

RocketChipを改造しようにも、どこがどうなっているのか全く分からなかったので、頑張ってエディタで配線を追いかけながら接続構成図を作った。

だいたい3本のバスがRocketChipにつながっている。メインのバスと、L2に接続するためのバス、コヒーレント用のバスだ。

f:id:msyksphinz:20170805014844p:plain

VivadoでZynqのブロックデザインをTCLで生成する(3. FPGAでの動作確認)

前回の続き。bitファイルが完成したので、boot.binをSDカードコピーして動作させてみた。

本当に動作しているかどうかを確認するために、BlockRAMのデザインに少しだけギミックを入れた。

  always @ (posedge s_axi_aclk) begin
    up_rack_s      <= up_rreq_s;
    blockram_rdata <= reg_mem[up_raddr_s[9:0]];
  end

  always @ (posedge s_axi_aclk) begin
    up_raddr_s2 <= up_raddr_s;
  end

  assign up_rdata_s = (up_raddr_s2 == 14'h0) ? 32'hdeadbeef : blockram_rdata;

github.com

つまり、当該ブロックの先頭アドレスにリードアクセスをすると、0xdeadbeefが返されるはずだ。

当該ブロックのアドレスは、design_1_bd.tclで定義している。

ad_cpu_interconnect 0x43c00000 axi_blockram

さて、さっそく実行してみた。

f:id:msyksphinz:20170803012041p:plain

まず、当該ブロックの先頭へのリードを実行する。

devmem2 0x43c00000 word

0xdeadbeefが返ってきた。成功だ。

次に、次のワードに対して書き込みを実行する。書き込む値は0x12345678だ。

devmem2 0x43c00004 word 0x12345678

次に同じアドレスに対してリードをする。ちゃんと0x12345678が返ってきた。成功だ。

devmem2 0x43c00000 word

Vivado でZynqのブロックデザインをTCLで生成する方法の調査(2. ADIのモジュールを利用してブロック部品を作成する)

ZynqのCPU Interconnectに接続するためには、AXI経由でブロックモジュールを作成する必要がある。これらの部品は自分で作っても良いのだが、どうにもエラーが取り切れないところもあるし、きちんと作れているのかいまいち自信が無かったので、ADIのデザインを再利用して作ることにした。

github.com

例えば上記のリポジトリ内にある、 library/axi_clkgen/などを見てみよう。 axi_clkgen.v を開くと、まずはAXI信号を受け取り、up_axiというADIのモジュールを使ってアドレスとデータを同期させていることが分かる。

github.com

f:id:msyksphinz:20170802003836p:plain

これらはAXIを変換したもので、アドレスとデータが同期しているので扱いやすい。信号線も、

  wire            up_wreq_s;
  wire    [13:0]  up_waddr_s;
  wire    [31:0]  up_wdata_s;
  wire            up_wack_s;
  wire            up_rreq_s;
  wire    [13:0]  up_raddr_s;
  wire    [31:0]  up_rdata_s;
  wire            up_rack_s;

と数が少ないので、何のための信号かすぐに分かる。

これらを使ってブロックを構成する。例えば、axi_blockramを作ってみよう。

github.com

こんな感じにしてみた。合っているかはよく分からん。

    .up_wreq  (up_wreq_s),
    .up_waddr (up_waddr_s),
    .up_wdata (up_wdata_s),
    .up_wack  (up_wack_s),
    .up_rreq  (up_rreq_s),
    .up_raddr (up_raddr_s),
    .up_rdata (up_rdata_s),
    .up_rack  (up_rack_s));

  reg [31: 0]     reg_mem [1023: 0];

  assign up_wack_s = 1'b1;

  always @ (posedge clk) begin
    if (up_wreq_s) begin
      reg_mem[up_waddr_s[9:0]] <= up_wdata_s[31: 0];
    end
  end

  always @ (posedge clk) begin
    up_rack_s  <= up_rreq_s;
    up_rdata_s <= reg_mem[up_raddr_s[9:0]];
  end

endmodule

とりあえず、これで一通り論理合成を流して、Vivadoでbitファイルが作れるところまでは確認できた。

f:id:msyksphinz:20170802005258p:plain

Vivado でZynqのブロックデザインをTCLで生成する方法の調査

これまだVivadoのプロジェクトの生成方法や、SDKの処理などについてtcl化する方法について調査してきた。

いろいろ試して、結局以下のQiitaの方法に則るのが一番いいという結論に至った。

qiita.com

この中で、VivadoのブロックデザインはGUIで操作したものをtclに書き出し、それをCUIスクリプト化するときはインポートするという手法を取っている。

ブロックデザインというのはこういうのだ。Zynqとその周辺の接続関係を設計できるツールで、新しいIPを追加するとこのGUIを使用してモジュール間を接続する。

f:id:msyksphinz:20170723195744p:plain

この例では、変数 design_bd_tcl_file にファイル名が設定されていた場合、ファイルセット sources_1 に Block Design を追加して、さらにラッパーファイルも生成します。

一応、ADIのプロジェクトを見るとここもスクリプト化できるようだ。ADIのスクリプトをインポートしても良いので、これもtcl化しておきたい。

ADI Reference Designs HDL User Guide [Analog Devices Wiki]

ADIのブロックデザイン生成スクリプト

まずは、ADIのzed_system_bd.tclを見てみよう。これがZedBoard向けにブロックデザインを生成するスクリプトだ。

github.com

tclを読み解くには、Vivadoの “Vivado Design Suite Tcl Command Reference Guide” を参照しよう。

  • Vivado Design Suite Tcl Command Reference Guide

https://www.xilinx.com/support/documentation/sw_manuals/xilinx2013_3/ug835-vivado-tcl-commands.pdf

create_bd_port

ブロックデザインに対してポートを作成する。外部ポートなど、ZedBoardの外に出すポートを作成する。

create_bd_port -dir O spi0_csn_2_o
create_bd_port -dir O spi0_csn_1_o
create_bd_port -dir O spi0_csn_0_o
create_bd_port -dir I spi0_csn_i
create_bd_port -dir I spi0_clk_i
...

create_bd_cell

ブロックデザインに対してIPをインスタンスする。必要なIPをインスタンスしていく。

set axi_iic_main [create_bd_cell -type ip -vlnv xilinx.com:ip:axi_iic:2.0 axi_iic_main]
...
set axi_hdmi_core [create_bd_cell -type ip -vlnv analog.com:user:axi_hdmi_tx:1.0 axi_hdmi_core]
...

ad_connect

これはADIが用意しているサポート関数のようだ。定義を見てみると、いくつかの指定タイプによって、Vivadoの関数connect_bd_xxxを使うかを決定している。さらにどうもポートのDirectionは関係ないようだ。

ad_connect  sys_cpu_clk sys_ps7/FCLK_CLK0
ad_connect  sys_200m_clk sys_ps7/FCLK_CLK1
ad_connect  sys_cpu_reset sys_rstgen/peripheral_reset
ad_connect  sys_cpu_resetn sys_rstgen/peripheral_aresetn
...
ad_connect  sys_cpu_clk axi_hdmi_core/vdma_clk
...

例えば、ad_connect sys_cpu_clk sys_ps7/FCLK_CLK0 でまずは sys_ps7/FCLK_CLK0 から sys_cpu_clkという仮想のクロック配線へと接続し、次に ad_connect sys_cpu_clk axi_hdmi_core/vdma_clksys_ps7/FCLK_CLK0 から axi_hdmi_core/vdma_clk への接続が完成している。 ブロックデザインでその様子を見ると以下のようになっている。

f:id:msyksphinz:20170731013713p:plain

これらをスクリプトを組み込み、まずはZynqのブロックデザインを構成した。

github.com

$ make impl
vivado -mode batch -source create_project.tcl > adv7511_create_zed_hdf.log 2>&1
vivado -mode batch -source implementation.tcl > adv7511_impl_zed_hdf.log 2>&1

合成結果は、無事にブロックデザインが生成されている。

f:id:msyksphinz:20170731014243p:plain

関連記事

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

msyksphinz.hatenablog.com

FPGAマガジン No.18「RISC-Vづくり」を入手

FPGAマガジンNo.18はRISC-V特集「RISC-Vづくり」ということで、早速入手した。ちなみに、私は本文は何も寄稿してません。

f:id:msyksphinz:20170722001900p:plain

雑誌の上においてあるHiFive1ボード2枚、うち1枚は私のだが壊してしまった。

最初は中森章さんのRISC-Vそのものについての解説。仕様の特徴からRISC-Vがなぜ注目を浴びているのかについての背景まで開設されている。

というところは同意。もう一つ、RISC-Vが脚光を浴びた、という一つの要因に、ARMがソフトバンクに買われたという事実があげられる。ARMがソフトバンクに買われた際に、私のブログのアクセス数も急上昇した。

つまり、

  • 別にARMが安泰ならARMで良いのである(ASIC作っている人は少ないし、ASIC作っている人はARMも買えるお金持ち)。
  • でも、ARMがダメならなるべく楽なやつが良いよね。MIPSとか誰が使ってんのか分かんないし、OpenRISCに戻りたくないし。

で、FPGAマガジン特別設計のRISC-VのVerilog実装は、5段パイプラインと言いつつシーケンシャル実行。これは時間が足らなかったのかな。 CSRレジスタも実装してあるし、割り込みも実装してある。RISC-Vの仕様を身をもって理解したい人はいいんじゃないかしら。

ただし、これ、誰向けに書かれた内容かというとなんだか良く分からない。CPUを作る人向け、っていうのはニッチだし、使う側の人にとってはVerilogの実装とかどうでも良い。

CPUインプリする人だったらRocketChipとか使った方が機能多いし、性能良い。使う人にとって参考になるのはRISC-Vの仕様の解説くらいかしら。

といってもなかなか珍しいRISC-Vの実装なので、「CPUに興味があるけどどうやって作ればよいのか分からない」という方は是非読んでみることをお勧めする。

ついでに宣伝だけど、Vengeneerさんのご厚意で、今年10月のDesign Solution ForumにてRISC-Vトラックの一つとして発表することになり、その宣伝文を掲載させて頂いた。

“オープンアーキテクチャの時代がやってきた!RISC-Vを取り囲む世界のご紹介”

これまで、ソフトウェアの世界だけの話であったオープンソースという概念は、ついにハードウェアの世界にまで広がろうとしています。RISC-Vはこれまでこれまでに限られた会社によって開発されていたマイクロプロセッサアーキテ> クチャを、誰でも触れる、仕様や実装について議論できる、広くオープンなものにしました。 この新しいオープンアーキテクチャのプロセッサについて、「FPGA開発日記(http://msyksphinz.hatenablog.com) 」というブログにまとめる活動をしています。 この新しいアーキテクチャについて、その特徴やこれを取り囲むエコシステム、またRISC-V自作プロセッサの開発実績についてまで、幅広くご紹介する予定です。

あー恥ずかし。まだ内容ほとんど出来てないんだけど、何しゃべるのかしら。

ThinkPadのトラックポインタが交換できることは意外と知られていなかった

わずか10~20年前、パーソナルコンピュータといえば日本の大手家電メーカがこぞって手を出していた分野であり、また国内家電量販店に並べてあるPCはほとんどが国産だった。 名立たる国内家電メーカは独自のPCを短いスパンでリリースし、国内のシェアも相当高かったものと思う。

そんな中、ThinkPadユーザといえば非常にコアな人間か、PCに熱い思いを持っている人たちの集まりであるという印象だった。 しかし、それは昔の話、国内PCは衰退し、今や格安海外メーカのPCか、ビジネス用にはThinkPad、くらいの選択肢くらいしかなくなってしまったと思う。 (私はLenovoIBMからThinkPadを買ってからのユーザなのでそういう意味ではニワカである。が、それ以降メーカPCは全部ThinkPad。)

というわけなので、別に今の時代ThinkPadを使っていてもPCヘビーユーザとは限らず、キーボードの真ん中に何か赤いの付いてる、ナニコレ指に当たって邪魔なんだけど、くらいの人がいても不思議はない、っていうかそんな人ばかりである。

しかしThinkPadヘビーユーザにとって、赤ポチ(トラックポインタ)の摩耗は死活問題だ。トラックポインタが削れてくると指が滑るようになり、作業効率が落ちる。 従って、定期的にトラックポインタを交換するのは大事な作業だ。

しかし、長らくThinkPadを使っているユーザでも、トラックポインタのキャップが交換できることを知っている人が少なくて驚いた(サンプル数は数人だけど…)。

下記のような感じである。

ThinkPad X250のトラックポイントキャップを底上げして交換 | ThinkPad X240sを使い倒す シンクパッドのレビュー・カスタマイズ

ちなみに、私はトラックポインタの種類は2種類(古いタイプのものとロープロファイルのもの)しか知らなかったのだが、どうやら2016年モデルからさらにロープロファイルになったようだ。

f:id:msyksphinz:20170721235658p:plain

私の持ってるやつ。左が古いもの、右がロープロファイル。さらに2016年モデルからはさらにロープロファイルになってるっぽい。もうどんどん互換性がなくなっていく!

というわけでロープロファイルのものが無くなったので秋葉原に買いに行った。秋葉原にある唯一のThinkPad専門店、ThinkFactoryで取り扱っている。

ThinkFactory IBM Lenovo秋葉原 持込修理 販売 保守パーツ

ただし、

f:id:msyksphinz:20170722000603p:plain

って感じのため、ThinkPadユーザはもうちょっと足繁く通ってあげよう。

VivadoでIPを生成する方法の調査(VivadoのIPインテグレーションの仕組み調査3. RAMの実装)

f:id:msyksphinz:20170723195744p:plain

AXIインタフェースに対して、RAMを実装していく。

github.com

  • blockram_test_v1_0_S00_AXI.v
  // Add user logic here
  reg [C_S_AXI_DATA_WIDTH-1:0]               mem_ram[1024-1: 0];
  wire                                       mem_wren, mem_rdenn;
  assign mem_wren = axi_wready && S_AXI_WVALID ;
  assign mem_rden = axi_arv_arr_flag ; //& ~axi_rvalid
  always @ (posedge S_AXI_ACLK) begin
    mem_ram [axi_awaddr[11: 2]] <= S_AXI_WDATA[31: 0];
  end

  always @ (posedge S_AXI_ACLK) begin
    if (!S_AXI_RESETN) begin
      axi_rdata <= 32'h0;

      axi_rvalid <= 0;
      axi_rresp  <= 0;
    end else begin
      if (axi_arv_arr_flag && ~axi_rvalid) begin
        axi_rvalid <= 1'b1;
        axi_rresp  <= 2'b0;
        // 'OKAY' response

        axi_rdata <= mem_ram [axi_araddr[11: 2]];
      end else if (axi_rvalid && S_AXI_RREADY) begin
        axi_rvalid <= 1'b0;
      end
    end // else: !if(!S_AXI_RESETN)
  end // always @ (posedge S_AXI_ACLK)

   // User logic ends

まあ簡単な実装なので、すぐにできると思うのだが、少し改造するとビルドスクリプトが動かなくなってしまった。。。調査中。。。

github.com