J

2004 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 12 |
2008 | 01 | 02 | 04 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 03 | 04 | 05 | 06 | 07 | 08 | 12 |
2013 | 01 | 02 | 03 | 05 | 06 | 07 | 08 | 09 | 10 | 11 |
2014 | 01 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2015 | 02 | 03 | 04 | 05 | 06 | 07 | 10 | 11 | 12 |
2016 | 01 | 02 | 04 | 05 | 06 | 07 |

ホーム

日記内の"morihyphen.hp.infoseek.co.jp"へのリンクは切れてます。必要な場合はお手数ですが int.main.jp へ書き換えをお願いします。

TODO: ファイル名確認を忘れないこと > 自分

twitter

 

2016-07-08

pipe, splice, sendfile, vmsplice, tee 02:28

ファイルから読んだデータを、CPUで加工せずにソケットに送りたいとする。

read(in_fd, buffer, 4096);
write(out_fd, buffer, 4096);

とか、やりたくなるが、これは実際には非常に無駄で、read 時に、ファイルシステムキャッシュからユーザ空間へコピー、ユーザ空間からskbへコピーしている。

まあ1Gb Etherなら全然大したオーバーヘッドにはならないけど(それがなるんだよなぁ…(なんで?))、NVMe Flash から、100Gb イーサに送るとかすると、memcpy が一回増えるだけで無視できないオーバーヘッドになるので、無駄がある。


そこで sendfile というシステムコールがある。

上のread,writeは

sendfile(out_fd, in_fd, NULL, 4096);

とか書くと、カーネル内のページをなんかうまくやってくれる。

例えば、in_fd がregular ファイルで、out_fd がソケットだった場合、ファイルシステムキャッシュに使われてるページメモリが、そのままイーサネットドライバに渡される。


このsendfileの処理をもう少し分割したspliceというシステムコールがある。

キャッシュシステムを自分で持っていて、ファイルシステムキャッシュが必要無いアプリケーションの場合、キャッシュを自分で管理したい場合があるかもしれない。そういう場合、Linux では、POSIX の pipe をカーネル内のページへのポインタとして使うことができる。


splice で、出力先をpipeにすると、そのpipeが、入力fdのカーネル内ページキャッシュのページを保持するようになる。

splice で、入力元をpipeにすると、pipeが保持しているポインタをドライバとかに直接送れる。

vmsplice すると、ユーザ空間に置いてあるメモリを、カーネル内からpipeで参照できるようになる。

tee するとpipeが指してるポインタを別のpipeにコピーできる。


一個のpipeが保持できるバッファサイズは標準だと64KBだけど、fcntl(pipe, F_SETPIPE_SZ, 1024*1024) とかすると変えられる(CAP_SYS_RESOURCE 権限が無いとサイズ制限が付く)


sendfileは実際には、

splice(in_fd, NULL, 
       current->pipe, NULL, 4096, 0); // current->pipe が in_fd のページキャッシュを保持する
splice(current->pipe, NULL,
       out_fd, NULL, 4096, 0); // current->pipe が保持しているページを out_fd へ

みたいな処理になっている。


(あとで計測したい)

トラックバック - http://d.hatena.ne.jp/w_o/20160708

2016-06-19

Cortex-A7 vs Cortex-A9 vs Cortex-A53 vs Silvermont 23:30

http://wlog.flatlib.jp/item/1800 この表を見てて、そういえば、私もRaspberry Pi 3 が家に来たし似たような実験できるなと思ったので私も似たような実験をした。

binutilsのビルド時間です。消費電力はKILL A WATT目視。

raspberry pi 3 (idle 1.8W, load 4.7W, diff=2.9W)
 Performance counter stats for 'sh -c ../configure ; make -j4':

     797005.468900      task-clock (msec)         #    2.953 CPUs utilized
           121,732      context-switches          #    0.153 K/sec
            29,936      cpu-migrations            #    0.038 K/sec
         8,586,527      page-faults               #    0.011 M/sec
   954,251,209,471      cycles                    #    1.197 GHz
   <not supported>      stalled-cycles-frontend
   <not supported>      stalled-cycles-backend
   422,118,328,351      instructions              #    0.44  insns per cycle
    53,087,297,010      branches                  #   66.608 M/sec
     6,646,202,484      branch-misses             #   12.52% of all branches

     269.885547005 seconds time elapsed


raspberry pi 2 (idle 1.6W, load 2.9W, diff=1.3W)
 Performance counter stats for 'sh -c ../configure ; make -j4':

    1477301.886492      task-clock (msec)         #    3.017 CPUs utilized
           138,249      context-switches          #    0.094 K/sec
            31,201      cpu-migrations            #    0.021 K/sec
         8,587,257      page-faults               #    0.006 M/sec
 1,326,853,390,190      cycles                    #    0.898 GHz
   <not supported>      stalled-cycles-frontend
   <not supported>      stalled-cycles-backend
   422,185,890,968      instructions              #    0.32  insns per cycle
    52,974,180,568      branches                  #   35.859 M/sec
    13,626,377,155      branch-misses             #   25.72% of all branches

     489.620091792 seconds time elapsed

parallella (idle 2.8W, load 3.5W, diff=0.7W)
 Performance counter stats for 'sh -c ../configure ; make -j2':

    1477010.321602      task-clock (msec)         #    1.674 CPUs utilized
            138413      context-switches          #    0.094 K/sec
             12771      cpu-migrations            #    0.009 K/sec
           8209396      page-faults               #    0.006 M/sec
      982777694036      cycles                    #    0.665 GHz
       83520783309      stalled-cycles-frontend   #    8.50% frontend cycles idle
      629510158808      stalled-cycles-backend    #   64.05% backend  cycles idle
      553902409016      instructions              #    0.56  insns per cycle
                                                  #    1.14  stalled cycles per insn
       57338355895      branches                  #   38.821 M/sec
       15218097669      branch-misses             #   26.54% of all branches

     882.186437213 seconds time elapsed

liva ecs (idle 3.5W, 7.2W, diff=3.7W) Celeron N2807 2core
 Performance counter stats for 'sh -c ../configure ; make -j2':

     399205.341262      task-clock (msec)         #    1.790 CPUs utilized
            180763      context-switches          #    0.453 K/sec
             24511      cpu-migrations            #    0.061 K/sec
           8537573      page-faults               #    0.021 M/sec
      832800007036      cycles                    #    2.086 GHz                      (51.63%)
   <not supported>      stalled-cycles-frontend
   <not supported>      stalled-cycles-backend
      407625678041      instructions              #    0.49  insns per cycle          (76.75%)
       88939447423      branches                  #  222.791 M/sec                    (76.15%)
        7372201988      branch-misses             #    8.29% of all branches          (76.20%)

     222.991643196 seconds time elapsed
時間[秒]IPC W(load)W(idle)W(load-idle)
rpi3 270 0.444.7 1.8 2.9 Cortex A53 4core
rpi2 490 0.322.9 1.6 1.3 Cortex A7 4core
parallella882 0.563.5 2.8 0.7 Cortex A9 2core
liva ecs 223 0.497.2 3.5 3.7 Silvermont 2core

わかることは、

  • Cortex-A9 と Cortex-A53 だと、A53のほうがIPC良いと思ってたけど、A9のほうがいいんだな。まあA9一応OoOだからとは思うけど、Cortex-A9 → Cortex-A53って5年も時間経ってるしなんとかなってると思ってた
  • 分岐ミスがA9,A7 は同じぐらいだけど、A53は半分くらいに減ってる。

まああんまり良い比較ではない、というのは

  • 今のCPUならidle は周辺IOのほうが効くのでidleの比較に意味あるかは謎
  • load-idle は、省電力機能が強いほうが大きくなる。ので、load-idleで比較すればいいわけでもない
  • ビルドのように並列処理できるものは1コアが小さくてコア数が多いほうが有利
  • コンパイル処理だと、x86とarmで処理内容が変わる
トラックバック - http://d.hatena.ne.jp/w_o/20160619

2016-05-24

肉と値段 19:36

気分が良かった…いや良くなかったな…まあ気分とは関係無く、Walmart で grassfed とか書いてある肉を試してしまった。(grassfed = 草だけで育てた)

Walmart では、下限が $4.8/lb とかで売ってて、grassfed は $11.8/lb とか書いてた気がするので、2.5倍ぐらい値段が違う。


lb ってなんだよ不思議単位系やめろ。lbて書いてpoundって読むのやめろ。

(書いてなかったけど1月からカリフォルニア州Irvineに住んでます。)


やはり、値段が高い肉はおいしい。定期的にステーキ焼いてるが、焼いてる人間は同じなので、確実に肉のほうの問題だ。硬さが全然違うので、ブラインドテストしてもわかると思う。


値段が高いほうが、おいしいというのは、結構納得いかない。

放牧して、草だけ食べさせて苦労して育てたほうがおいしくなる。一方、狭いところで、成長促進薬投与したりすると、固くて食べづらい、というのに、特に合理的な理由なんて無いと思うけど。


真面目に考えると、安くて、かつ、おいしくできる、みたいなテクニックは、全ての牧場、全ての牛に普及するので、最終的には、値段と味のトレードオフが必要な成分だけが残って、うまくて高い肉と、かたくて安い肉が、住みわけられる、というのは理解できる。

が、その結果が、なんか、「広々とした空間で、のびのび牛を育てるとサシが入って柔らかくておいしい肉になる」「狭い空間で牛にストレスを与えながら育てると肉が固くなる」みたいな、なんかヒューマンの想像するイメージと一致してしまうトレードオフ成分が最後に残るのが納得いかない。

トラックバック - http://d.hatena.ne.jp/w_o/20160524

2016-05-20

clflushopt を使ってキャッシュフラッシュを高速にしよう 17:48

キャッシュフラッシュに苦しんでいる人も世の中にはたくさんいる。

そういう人を救うために、Skylake からはclflushopt という命令が新設された。


これまでは、clflush という命令があって、これを使うとキャッシュフラッシュができた。clflushoptは、これよりはやい。どのぐらい違うかというと、手元(i7-6770 + DDR4 2ch) だと、

clflush 4.1[GB/s]
clflushopt 43.6[GB/s]
memset 30.2[GB/s]

このぐらい違う。


#include <stdio.h>
#include <x86intrin.h>
#include <sys/time.h>
#include <string.h>
#include <time.h>

double
sec(void)
{
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);

    return ts.tv_sec + (ts.tv_nsec / 1000000000.0);
}

unsigned char *data;

void __attribute__((noinline,noclone))
clflush(size_t nline)
{
    int li;
    for (li=0; li<nline; li++) {
        _mm_clflush(data + li*64);
    }

    asm volatile ("" ::: "memory");
}

void __attribute__((noinline,noclone))
clflush_opt(size_t nline)
{
    int li;
    for (li=0; li<nline; li++) {
        _mm_clflushopt(data + li*64);
    }

    asm volatile ("" ::: "memory");
}

void __attribute__((noinline,noclone))
run_memset(size_t nline)
{
    int li;
    memset(data, 0, nline * 64);
    asm volatile ("" ::: "memory");
}

int
main(int argc, char **argv)
{
    double t0, t1, total;
    size_t size = 128 * 1024*1024;
    void *p;
    int li;
    int nloop = 32;

    if (argc > 1) {
        size = atoi(argv[1]) * 1024*1024;
    }

    posix_memalign(&p, 4096, size);
    data = p;

    clflush(size/64);
    clflush_opt(size/64);

    t0 = sec();
    for (li=0; li<nloop; li++) {
        clflush(size/64);
    }
    t1 = sec();

    total = size * (double)nloop;
    printf("%20s %f[MiB/s]\n", "clflush", total / ((t1-t0) * 1024*1024));

    t0 = sec();
    for (li=0; li<nloop; li++) {
        clflush_opt(size/64);
    }
    t1 = sec();

    total = size * (double)nloop;
    printf("%20s %f[MiB/s]\n", "clflushopt", total / ((t1-t0) * 1024*1024));


    t0 = sec();
    for (li=0; li<nloop; li++) {
        run_memset(size/64);
    }
    t1 = sec();

    total = size * (double)nloop;
    printf("%20s %f[MiB/s]\n", "memset", total / ((t1-t0) * 1024*1024));
    
}

以下書いてたらクソつまらなくて長い文章になったのでひとことで書いておくと、clflushopt を使うときは、ちゃんと mfence も入れたほうがいいです。

(以下、クソつまらなくて長い文章です)


さて、何故、同じキャッシュフラッシュなのに、clflushopt が、 clflush よりとても速いのか、だが、以下に書いておく。


まず、clflush が memset より遅いのは不思議に思うかもしれない。(思ってほしい)


clflush は、データをキャッシュから追い出す処理で、memset はメモリに書き込む処理だが、キャッシュは数MBしか無いのだから、巨大な領域に大してキャッシュフラッシュするのと、memsetするのを比べると

  • clflush : 8MBのキャッシュ領域をチェックして、あとはなにもしない
  • memset : 8MBのキャッシュ領域をチェックして、溢れたら巨大な領域にデータをストアする

と、なるはず。作業量は、clflushのほうが少ないはずだ。しかし、実際には、clflush のほうが10倍近く遅い。何故?


何故かというと、clflush は、処理の完了を待ってから、次の命令を実行する必要があるからだ。


今のCPUでは、物理的にメモリに書き込まれる値は、プログラムから見える値とは、異なる場合がある。

p0[0] = 0; // (1)
p1[0] = 0;
p0[0] = 1;

とかを考えれば、今のCPUにキャッシュが付いてることをを知ってる人ならば(1)の書き込みが、実際にメモリに書きこまれることなく世界から消えてることはわかるだろう。

store 命令は、実際にはstore なんてしてなくて、単に「次にアドレスp0を読んだときに値が見えるようにする」だけだ。

キャッシュに書き込む処理というのは、

  1. MMU経由して、仮想アドレスを物理アドレスに変換する(これも実際には2階層 TLBを引くので結構処理する)
  2. PAT を見てキャッシュの挙動を探す
  3. キャッシュ可能領域なら L1 のタグを探してあるかどうか見る
  4. L1 に無ければ L2 を探す

と、いうような処理をしないといけない。しかし、「次にp0を読んだときに値が見えるようにする」だけなら、直前に書いた値をいくつか履歴として持っておくだけでよい。(これをストアバッファとかいう)

CPUとしては、とりあえず、ストアバッファに値だけ入れておいて、そこから先は、CPUコアとは独立して動くキャッシュシステムに丸投げ、CPUコアは、キャッシュシステムと並列に動き、全体として効率が上がる、というようになる

そして、上の 1,2,3,4 の処理は、依存しない書き込みならパイプライン化できるので、長い目で見れば、スループットはCPUの速度に追い付けるぐらい十分良くできる(ここらへん説明不足。お前こんだけ長い文章書いてて説明不足なのかよぉ!)


一方、clflush では、そういうインチキは許されない。


例えば、次の処理を考える

memset(mem, 0, sizeof(mem)); // メモリ領域に値をセット
dma_set_address(mem);        // これをdma転送する
clflush(mem);                // DMAできるように領域flush
dma_start();                 // DMA開始

wait_dma();

この処理は、正しく動くだろうか?DMA は実際にメインメモリへ読みに行くので、storeと同じように、clflush が「メインメモリには書かないでclflushしたように見えるだけ」なら、間違った値が読めてしまう可能性がある。

つまり、clflush は、

  1. MMU経由して、仮想アドレスを物理アドレスに変換する
  2. PAT を見てキャッシュの挙動を探す
  3. L1 のタグを探してあるかどうか見る
  4. L1 にあればそれをフラッシュ
  5. L2 のタグを探してあるかどうか見る
  6. L2 にあればそれをフラッシュ

この動作を完全に終えた時点で、命令終了としなければならない。完了まで、次の動作を開始できないので、メモリパイプラインを埋めることができず、効率は非常に悪くなってしまう。


ボールが一個ギリギリ通せる配管をイメージしてもらって、store 命令は、この配管にボールを大量に片方向に流しこんでるイメージ

(A) store

\10回ストアして/            
      ○      ----------------        ○ 
      ↑      コロコロ =OOOOOOOOOO        ↑
      ∧      ----------------        ∧
                              /ボールまだかなー\

一方、clflush は、同じ配管を使って、ボールを交互にやりとりしてる状態をイメージしてもらうのがよいかもしれない。

(B) clflush

\フラッシュして/
      ○      ----------------        ○ 
      ↑      コロコロ =O                 ↑
      ∧      ----------------        ∧
                              /ボールまだかなー\


      ○      ----------------        ○ 
      ↑                     =O       ↑
      ∧      ----------------        ∧
                              /はいフラッシュ\


      ○      ----------------        ○ 
      ↑               O=             ↑
      ∧      ----------------        ∧
                                 /おわったよ\

   \(^o^)/
      ○      ----------------        ○ 
      ↑     O=                       ↑
      ∧      ----------------        ∧

これだと、例え、ボールの数が半分だったとしても片方向に一方的に流すよりもボールを相手に送るのに必要な時間は増えることがわかるだろう。


しかし、これは、実際の使いかたを考えると、安全側に倒しすぎだ。実際の用途なら、キャッシュライン毎に完了を待つのはほぼ確実に無駄で、もっと大きい領域で、完了を待ったほうが効率がいい。

上の配管のイメージでいうと、100個ぐらいボールを投入してから、「今まで入れた100個のボールが届いたら、1個ボールを返してくれ」とするほうが、配管の利用効率は上がる。


(C) clflushopt

\フラッシュしといて/
      ○      ----------------        ○ 
      ↑      コロコロ =XOOOOOO           ↑
      ∧      ----------------        ∧
                              /ボールまだかなー\


      ○      ----------------        ○ 
      ↑                    =XOOOO    ↑
      ∧      ----------------        ∧
                              /フラフラフラ…フラッシュ\

      ○      ----------------        ○ 
      ↑                     =X       ↑
      ∧      ----------------        ∧
                              /これで終わりね\


      ○      ----------------        ○ 
      ↑               O=             ↑
      ∧      ----------------        ∧
                                 /おわったよ\

   \(^o^)/
      ○      ----------------        ○ 
      ↑     O=                       ↑
      ∧      ----------------        ∧

ここで、(B)のように一回一回確認するのが、clflush、(C)のように複数のflushリクエストをまとめて実行するのが、clflushopt、ということになる。


なので、clflushoptのほうがはやくなるのだった。


ただし、上のような事情があって、clflushoptのほうは、命令が終わってもflushの完了が終わるわけではないので、clflushopt のあとは、ちゃんとmfence, sfenceを入れる必要がある。忘れないようにね。


// clflush はsfenceいらない

_mm_clflush(mem+64*0);
_mm_clflush(mem+64*1);
_mm_clflush(mem+64*2);
_mm_clflush(mem+64*3);
// clflushopt はちゃんと完了を待つために、最後にsfenceを入れる

_mm_clflushopt(mem+64*0);
_mm_clflushopt(mem+64*1);
_mm_clflushopt(mem+64*2);
_mm_clflushopt(mem+64*3);

_mm_sfence();


あと昔のマニュアルでは、clflushが今のclflushoptの挙動(完了を待たない)と書いてあったのだけど、ドライバが壊れることを恐れて日和ったIntel は、マニュアルに反してこれまでのCPU全てで clflush の挙動を安全側に倒しており、clflushopt の実装にあわせて、マニュアルのほうを安全側に修正するという対応をとった。過去は書きかわったのだ!(という話がそもそも書きたかったのだけど前フリが長くなりすぎたので没)

トラックバック - http://d.hatena.ne.jp/w_o/20160520

2016-05-19

無からはじめるFPGAプログラミング(2) 20:05

1 : http://d.hatena.ne.jp/w_o/20160518#1463571239


さて、PS7を置いたら、Synthesizeをしよう。Synthesizeは、ボタンをポチーとするとできる。


Synthesizeすると、netlistができる。あんまりXilinx以外は知らないのだけど、Xilinx では、複雑な演算を、FPGA内にあるprimitiveで表現できるように変換した物体のことを、netlistと呼んでる気がする。


f:id:w_o:20160519185427p:image

このへんの画面で、オブジェクトを右クリックして、Schematicを選ぶと、画像でnetlistが見られる。


f:id:w_o:20160519185452p:image

とりあえず今は、「PS7を置け」というHDLを書いたので、そのとおりPS7が置いてあるはず。


これを、Generate Bitstreamすると、何もしないbitfileが完成する(project_dir/なんとか.runs/impl_1/design_1_wrapper.bit とかにある) 。cat bitfile > /dev/xdevcfg とかすると、何も起こらないことが確認できるはずだ(DDR3とかはn/cになってるけど動く。よくわからないが固定ピンなので大丈夫なのかもしれない)。


(ここからしばらくFPGA関係無いです)

さて、Zynq には、GPIO が付いている。これは、ARMと同じように、固定機能として入っていて、FPGAが何もしないように設定されていても使える。GPIOというのは、まあ、ただの1bit入出力なのだけど(何の機能も無い1bitをGeneral Purposeと呼ぶ姿勢を見習っていきたい)、LEDやボタン等は、1bit取れればいいので、このGPIOを使ってアクセスすることが多い。

http://www.xilinx.com/support/documentation/user_guides/ug585-Zynq-7000-TRM.pdf#381

GPIO の使いかたは、このへんにある。が、別にこれを読まなくてもLinux なら以下のようにして使える。

 $ sudo sh -c 'echo 913 > /sys/class/gpio/export'  # 7番目のGPIOを見えるようにする
 $ ls /sys/class/gpio/gpio913/
active_low  device/     direction   edge        power/      subsystem/  uevent      value       
 $ sudo sh -c 'echo out > /sys/class/gpio/gpio913/direction' # out 方向に設定
 $ sudo sh -c 'echo 1 > /sys/class/gpio/gpio913/value'       # Hi 出力
 $ sudo sh -c 'echo 0 > /sys/class/gpio/gpio913/value'       # Lo 出力

これをすると、Parallella ならLチカができるはずだ。Lチカできたので満足した(完)


終わりではない。


913が何かというと、Zynqはカーネルコンフィグで、GPIO1024個と指定されてるけど、実際は118個しかなくて、何故か後ろから番号詰められるので 1024-118 = 906 が GPIO0 番に対応してるらしい。

https://forums.xilinx.com/t5/Embedded-Linux/GPIO-issues-with-Linux-version-3-17-0-xilinx/td-p/560245/page/2

GPIO 7 番が、LEDに接続されているので、906+7 = 913番目が、LEDと対応するGPIOになる。なので、それをHiにしたりLoにしたりすると、Lチカができる。(ZedboardもLEDが7番に繋がってるので同じようにできると思う)

parallella-utils には、これを簡単に使うスクリプトが入っている https://github.com/parallella/parallella-utils/blob/master/gpio (というかこれ見て上の機能知った)

しかし、残念ながら、このピンは固定なので、ARMからLチカできても、FPGAからはLチカはできない。悲しいなぁ…

(ここまでFPGA関係ないです)


で、このGPIOだが、外部I/Oに54本、 FPGA側に64本出ていて、FPGAで出したbitをARMから読んだり、ARMから出したbitをFPGAから読んだりできるようになっている。


module design_1_wrapper
   ()
   ;

   wire [63:0] gpio_out;
   wire [63:0] gpio_in;

   assign gpio_in[0] = gpio_out[1];

   PS7 ps7 (
            .EMIOGPIOO (gpio_out),
            .EMIOGPIOI (gpio_in)
            );
endmodule

昨日書いた、design_1_wrapper.v をこんな感じに変更する。ps7 の EMIOGPIOO と、EMIOGPIOI を引き出して、そのうちの、EMIOGPIOO[1] と、EMIOGPIOI[0] を接続する。これでsynthesize,implementation,Generate Bitstream して、できたbitfileを、/dev/xdevcfgに書く。


EMIOGPIO[0] は、GPIO54 と対応している。EMIOGPIO[0] を in に、EMIOGPIO[1] を out に設定して、EMIOGPIO[1] を 0 にしたり、1にしたりすると、あわせて EMIOGPIO[0] が 0 になったり 1 になったりするのが確認できるはず。

$ # (上のparallella-utils に入ってるgpioスクリプトを使ってます)
$ ./gpio ex 960 961   # EMIOGPIO[0] = GPIO54 = 906+54 = 960
Exporting 960
Exporting 961
$ ./gpio in 960       # EMIOGPIO[0] は in
$ ./gpio out 961      # EMIOGPIO[1] は out
$ ./gpio 0 961        # EMIOGPIO[1] に Lo
$ ./gpio ls 960       # EMIOGPIO[0] が Lo 
gpio960: in 0
$ ./gpio 1 961        # EMIOGPIO[1] に Hi
$ ./gpio ls 960       # EMIOGPIO[0] が Hi
gpio960: in 1

これで、1bitデバッグが可能になったはず。


netlist を見ると、がんばって EMIOGPIOO と EMIOGPIOI を接続しているのがわかるはず。

f:id:w_o:20160519200222p:image


配置後の配線を見ても、すっごいがんばって EMIOGPIOO と EMIOGPIOI を接続しているのがわかるね…

f:id:w_o:20160519200220p:image


(飽きてきたので続かないかも)

書きたかった一覧

  • IBUF, OBUF
  • クロック
  • CLB
  • AXI

なんか、HDLだけじゃなくて、primitiveの使いかたも覚えないといけないよねー的な話を書きたかった。あとTclがクソだ…というのは最初に書いたしいいか…

トラックバック - http://d.hatena.ne.jp/w_o/20160519