VHDL で書くソーティングネットワーク(コアパッケージ)







# はじめに


別記事 [「はじめに」] を参照してください。

この記事では、マージソーター内部で使用するソーティングネットワーク(Sorting_Network) のコアパッケージについて説明します。




# ソーティングネットワークとは


ソーティングネットワークとは、数列をソートするネットワークで、ワイヤとコンパレータで構成されています。ワイヤは値を伝えます。コンパレーターは入出力に二本のワイヤをとり、二つの値が入力されると、指定された属性に従って出力をスルーしたりスワップしたりします。

コンパレーターには Up/Down という方向が設定されています。下図では矢印で示しています。

ソーティングネットワークの場合は、昇順と降順があります。昇順は値を小さい方から大きい方にソートするため、コンパレーターは値の小さい方を矢印の方に出力します。


![Fig.1 コンパレーター (昇順)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24981/d23f6d34-216e-58f2-0f0c-f77e24af5635.jpeg "Fig.1 コンパレーター (昇順)")

Fig.1 コンパレーター (昇順)

<br />



逆に降順は値を大きい方から小さい方にソートするため、コンパレーターは値の大きい方を矢印の方に出力します。


![Fig.2 コンパレーター (降順)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24981/c6b9063c-9c07-3f04-7a2d-82ff4bc8cb29.jpeg "Fig.2 コンパレーター (降順)")

Fig.2 コンパレーター (降順)

<br />



以下に、単純な昇順のソーティングネットワークの動作を示します。


![Fig.3 ソーティングネットワークの動作例 (4入力昇順)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24981/50fad253-97b2-6ff2-4488-bed9e0f63901.jpeg "Fig.3 ソーティングネットワークの動作例 (4入力昇順)")

Fig.3 ソーティングネットワークの動作例 (4入力昇順)

<br />




# ソーティングネットワークの VHDL 記述



## ソーティングネットワークのステージ


ソーティングネットワークを VHDL で記述するにあたり、ステージという概念を導入します。ステージとは、ソーティングネットワークを並列処理可能な単位で分割したものです。前述の４入力昇順ソーティングネットワークの場合は、次のように３ステージに分割することが出来ます。


![Fig.4 ソーティングネットワークのステージ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24981/b3b0138e-2a80-e8c5-56df-a1b1640e6d5f.jpeg "Fig.4 ソーティングネットワークのステージ")

Fig.4 ソーティングネットワークのステージ

<br />



ステージを分割することによって、ステージ間にレジスタを挿入することでパイプライン処理が可能になります。




## ソーティングネットワーク構成の VHDL 記述



### Param_Type


ソーティングネットワークを VHDL で記述するにあたり、まずはソーティングネットワークの構成を Sorting_Network.Param_Type という record タイプで定義します。これらの定義は Sorting_Network パッケージで定義しています。



Param_Type は、ネットワークのサイズ(入力ワード数)を保持する Size、ステージのサイズを保持する Stage_Size、ステージごとの各種情報を保持する Stage_Listで構成されています。


```VHDL:src/main/vhdl/core/sorting_network.vhd
library ieee;
use     ieee.std_logic_1164.all;
use     ieee.numeric_std.all;
library Merge_Sorter;
use     Merge_Sorter.Word;
package Sorting_Network is
    constant  Max_Network_Size      :  integer := 128;
    constant  Max_Stage_Size        :  integer := 256;
    -- (中略) --
    type      Param_Type            is record
                  Stage_List        :  Stage_Vector( 1 to Max_Stage_Size);
                  Stage_Size        :  integer range 0 to Max_Stage_Size;
                  Stage_Lo          :  integer range 0 to Max_Stage_Size;
                  Stage_Hi          :  integer range 0 to Max_Stage_Size;
                  Stage_Ctrl_Lo     :  integer range 0 to Max_Stage_Size*Stage_Queue_Ctrl_Bits;
                  Stage_Ctrl_Hi     :  integer range 0 to Max_Stage_Size*Stage_Queue_Ctrl_Bits;
                  Sort_Order        :  integer;
                  Size              :  integer range 0 to Max_Network_Size;
                  Lo                :  integer range 0 to Max_Network_Size-1;
                  Hi                :  integer range 0 to Max_Network_Size-1;
    end record;
    -- (後略) --
end Sorting_Network;
```



### Stage_Type


Stage_Type およびその配列型である Stage_Vector は Sorting_Network パッケージにて次のように定義されています。

Stage_Type は、ネットワーク毎のコンパレーター等のオペレーターの情報を保持する Operator_List と、パイプラインレジスタのキューのサイズを保持する Queue_Sizeで構成されています。


```VHDL:src/main/vhdl/core/sorting_network.vhd
library ieee;
use     ieee.std_logic_1164.all;
use     ieee.numeric_std.all;
library Merge_Sorter;
use     Merge_Sorter.Word;
package Sorting_Network is
     -- (前略) --
    constant  Max_Stage_Queue_Size  :  integer := 2;
    type      Stage_Type            is record
                  Operator_List     :  Operator_Vector(0 to Max_Network_Size-1);
                  Queue_Size        :  integer range 0 to Max_Stage_Queue_Size;
    end record;
    constant  Stage_Null            :  Stage_Type := (
                  Operator_List     => (others => Operator_None),
                  Queue_Size        => 0
              );
    type      Stage_Vector          is array (integer range <>) of Stage_Type;
    -- (後略) --
end Sorting_Network;
```



### Operator_Type


Operator_Type およびその配列型である Operator_Vector は Sorting_Network パッケージにて次のように定義されています。

Operator_Type は、オペレーターの種類(OP_NONE、OP_PASS、OP_COMP_UP 、OP_COMP_DOWN) を保持する OP、およびオペレーターを接続する対となるネットワークの相対位置を示す STEP で構成されています。


```VHDL:src/main/vhdl/core/sorting_network.vhd
library ieee;
use     ieee.std_logic_1164.all;
use     ieee.numeric_std.all;
library Merge_Sorter;
use     Merge_Sorter.Word;
package Sorting_Network is
     -- (前略) --
    type      Operator              is (OP_NONE, OP_PASS, OP_COMP_UP, OP_COMP_DOWN);
    type      Operator_Type         is record
                  STEP              :  integer;
                  OP                :  Operator;
    end record;
    constant  Operator_None         :  Operator_Type := (
                  STEP              => 0,
                  OP                => OP_NONE
              );
    type      Operator_Vector       is array (integer range <>) of Operator_Type;
     -- (後略) --
end Sorting_Network;
```



### 構成例


以下に４入力昇順ソーティングネットワーク(Fig.4参照)の構成を VHDL で記述した例を示します。


![Fig.5 ソーティングネットワーク構成の VHDL 記述例](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24981/fe9df627-a351-a345-77cd-815634a07f3c.jpeg "Fig.5 ソーティングネットワーク構成の VHDL 記述例")

Fig.5 ソーティングネットワーク構成の VHDL 記述例

<br />


![Fig.6 ソーティングネットワーク構成の VHDL 記述例 (Stage 1)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24981/1bf242fa-7646-7f57-6977-5d59f5e56771.jpeg "Fig.6 ソーティングネットワーク構成の VHDL 記述例 (Stage 1)")

Fig.6 ソーティングネットワーク構成の VHDL 記述例 (Stage 1)

<br />


![Fig.7 ソーティングネットワーク構成の VHDL 記述例 (Stage 2)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24981/5246905b-1196-59f2-ac47-4b4658ba03a7.jpeg "Fig.7 ソーティングネットワーク構成の VHDL 記述例 (Stage 2)")

Fig.7 ソーティングネットワーク構成の VHDL 記述例 (Stage 2)

<br />


![Fig.8 ソーティングネットワーク構成の VHDL 記述例 (Stage 3)](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24981/4fa6973b-a3c6-3ba8-7e93-50d9bdeb8c14.jpeg "Fig.8 ソーティングネットワーク構成の VHDL 記述例 (Stage 3)")

Fig.8 ソーティングネットワーク構成の VHDL 記述例 (Stage 3)

<br />


# ソーティングネットワークコアの VHDL 記述


ソーティングネットワークコアは、前節で定義したソーティングネットワーク構成(Sorting_Network.Param_Type) に基づき、ソーティングネットワークを構築した回路です。


## 構造


ソーティングネットワークコアの構造は次のようになっています。


![Fig.9 ソーティングネットワークコアの構成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24981/1f03e334-1afa-6231-d97a-c933bdf453c7.jpeg "Fig.9 ソーティングネットワークコアの構成")

Fig.9 ソーティングネットワークコアの構成

<br />


## Entity 


ジェネリック変数の NETWORK_PARAM でソーティングネットワークの構成を指定します。WORD_PARAM で[「ワードの定義」]を指定します。INFO_BITS はソーティングネットワークを通すその他の情報のビット数を指定します。

I_WORD はソーティングネットワークに入力するネットワーク毎のワードで、O_WORD はソートされたネットワーク毎のワードです。I_WORD および O_WORD はネットワーク毎のワードを一次元のビット配列(std_logic_vector)にしたものです。

I_INFO はその他の情報を入力し、O_INFO から内部のパイプライン分だけ遅延されて出力されます。


```VHDL:src/main/vhdl/core/sorting_network_core.vhd
library ieee;
use     ieee.std_logic_1164.all;
library Merge_Sorter;
use     Merge_Sorter.Word;
use     Merge_Sorter.Sorting_Network;
entity  Sorting_Network_Core is
    generic (
        NETWORK_PARAM   :  Sorting_Network.Param_Type := Sorting_Network.Param_Null;
        WORD_PARAM      :  Word.Param_Type            := Word.Default_Param;
        INFO_BITS       :  integer :=  3
    );
    port (
        CLK             :  in  std_logic;
        RST             :  in  std_logic;
        CLR             :  in  std_logic;
        I_WORD          :  in  std_logic_vector(NETWORK_PARAM.Size*WORD_PARAM.BITS-1 downto 0);
        I_INFO          :  in  std_logic_vector(INFO_BITS-1 downto 0) := (others => '0');
        I_VALID         :  in  std_logic;
        I_READY         :  out std_logic;
        O_WORD          :  out std_logic_vector(NETWORK_PARAM.Size*WORD_PARAM.BITS-1 downto 0);
        O_INFO          :  out std_logic_vector(INFO_BITS-1 downto 0);
        O_VALID         :  out std_logic;
        O_READY         :  in  std_logic;
        BUSY            :  out std_logic
    );
end Sorting_Network_Core;

```



## Architecture



### 定数および信号の定義


まずは Sorting_Network_Core 内部で使用するタイプおよびステージ毎の各種信号を定義します。


```VHDL:src/main/vhdl/core/sorting_network_core.vhd
library ieee;
use     ieee.std_logic_1164.all;
use     ieee.numeric_std.all;
library Merge_Sorter;
use     Merge_Sorter.Word;
use     Merge_Sorter.Sorting_Network;
use     Merge_Sorter.Core_Components.Word_Compare;
use     Merge_Sorter.Core_Components.Word_Pipeline_Register;
architecture RTL of Sorting_Network_Core is
    constant  STAGE_OPENER      :  integer := NETWORK_PARAM.Stage_Lo - 1;
    constant  STAGE_FIRST       :  integer := NETWORK_PARAM.Stage_Lo;
    constant  STAGE_LAST        :  integer := NETWORK_PARAM.Stage_Hi;
    subtype   WORD_TYPE         is std_logic_vector (WORD_PARAM.BITS-1 downto 0);
    type      STAGE_WORD_TYPE   is array (NETWORK_PARAM.Lo to NETWORK_PARAM.Hi) of WORD_TYPE;
    type      STAGE_WORD_VECTOR is array (integer range <>) of STAGE_WORD_TYPE;
    signal    stage_word        :  STAGE_WORD_VECTOR(STAGE_OPENER to STAGE_LAST);
    subtype   STAGE_INFO_TYPE   is std_logic_vector (INFO_BITS-1 downto 0);
    type      STAGE_INFO_VECTOR is array (integer range <>) of STAGE_INFO_TYPE;
    signal    stage_info        :  STAGE_INFO_VECTOR(STAGE_OPENER to STAGE_LAST);
    signal    stage_valid       :  std_logic_vector (STAGE_OPENER to STAGE_LAST);
    signal    stage_ready       :  std_logic_vector (STAGE_OPENER to STAGE_LAST);
    signal    stage_busy        :  std_logic_vector (STAGE_OPENER to STAGE_LAST);
    constant  STAGE_BUSY_ALL0   :  std_logic_vector (STAGE_OPENER to STAGE_LAST) := (others => '0');
begin

```



### OPENER Block


 I_WORD はソーティングネットワークに入力するネットワーク毎のワードで、ネットワーク毎のワードを一次元のビット配列(std_logic_vector)にしたものです。OPENER ブロックでは I_WORD を内部の信号に変換します。


```VHDL:src/main/vhdl/core/sorting_network_core.vhd
    OPENER: block
    begin
        NET: for i in 0 to NETWORK_PARAM.Size-1 generate
            stage_word(STAGE_OPENER)(NETWORK_PARAM.Lo+i) <= I_WORD((i+1)*WORD_PARAM.BITS-1 downto i*WORD_PARAM.BITS);
        end generate;
        stage_info (STAGE_OPENER) <= I_INFO;
        stage_valid(STAGE_OPENER) <= I_VALID;
        stage_busy (STAGE_OPENER) <= '0';
        I_READY <= stage_ready(STAGE_OPENER);
    end block;

```



### MAIN Block


ステージ毎に generate 文を使って記述します。


```VHDL:src/main/vhdl/core/sorting_network_core.vhd
    MAIN: for stage in STAGE_FIRST to STAGE_LAST generate
        constant  Stage_Param   :  Sorting_Network.Stage_Type 
                                := NETWORK_PARAM.Stage_List(stage);
        signal    sorted_word   :  STAGE_WORD_TYPE;
    begin
          
```




ステージ内のさらにネットワーク毎にオペレーターの挙動を記述します。


```VHDL:src/main/vhdl/core/sorting_network_core.vhd
        NET: for i in NETWORK_PARAM.Lo to NETWORK_PARAM.Hi generate
            constant  OP   :  Sorting_Network.Operator_Type := Stage_Param.Operator_List(i);
            constant  STEP :  integer := OP.STEP;
        begin
            
```




オペレーターがコンパレータの場合でSTEPが正の値の時は対となるネットワークが自ネットワーク番号＋STEPに存在します。この場合は対となるネットワークとの間にコンパレーターを接続して、その結果に応じて入力ワードを交換します。

STEP が0の時はコンパレーターを使わずに入力ワードをそのまま出力します。

STEP が負の値の時は、すでに対となるネットワーク(STEPの値が正のネットワーク)にてコンパレーターが接続されているので何もしません。


```VHDL:src/main/vhdl/core/sorting_network_core.vhd
            OP_COMP: if Sorting_Network.Operator_Is_Comp(OP) generate
                constant  UP   :  boolean := Sorting_Network.Operator_Is_Comp_Up(OP);
            begin 
                COMP: if (STEP > 0) generate
                    signal    swap      :  boolean;
                    signal    sel_a     :  std_logic;
                    signal    sel_b     :  std_logic;
                begin
                    U: Word_Compare                                      --
                        generic map(                                     --
                            WORD_PARAM  => WORD_PARAM                  , -- 
                            SORT_ORDER  => NETWORK_PARAM.Sort_Order      -- 
                        )                                                -- 
                        port map (                                       --
                            CLK         => CLK                         , -- In  :
                            RST         => RST                         , -- In  :
                            CLR         => CLR                         , -- In  :
                            A_WORD      => stage_word(stage-1)(i     ) , -- In  :
                            B_WORD      => stage_word(stage-1)(i+STEP) , -- In  :
                            VALID       => '1'                         , -- In  :
                            READY       => open                        , -- Out :
                            SEL_A       => sel_a                       , -- Out :
                            SEL_B       => sel_b                         -- Out :
                        );                                               --
                    swap <= (sel_b = '1' and UP = TRUE ) or
                            (sel_a = '1' and UP = FALSE);
                    sorted_word(i     ) <= stage_word(stage-1)(i+STEP) when (swap) else
                                           stage_word(stage-1)(i     );
                    sorted_word(i+STEP) <= stage_word(stage-1)(i     ) when (swap) else
                                           stage_word(stage-1)(i+STEP);
                end generate;
```




オペレーターが OP_PASS だった場合は、対象となるネットワークが自ネットワーク番号＋STEPに存在するので、そのネットワークを自ネットワークに接続します。


```VHDL:src/main/vhdl/core/sorting_network_core.vhd
　　　　　　OP_PASS: if Sorting_Network.Operator_Is_Pass(OP) generate
                    sorted_word(i     ) <= stage_word(stage-1)(i+STEP);
            end generate;            
```




オペレーターが OP_NONE だった場合は、何もせずにネットワークを継続します。


```VHDL:src/main/vhdl/core/sorting_network_core.vhd
       　   OP_NONE: if Sorting_Network.Operator_Is_None(OP) generate
                    sorted_word(i     ) <= stage_word(stage-1)(i     );
            end generate;
        end generate;
      
```




ステージ毎にパイプラインレジスタを挿入します。


```VHDL:src/main/vhdl/core/sorting_network_core.vhd
        REGS: block
            signal    d_word    :  std_logic_vector(NETWORK_PARAM.Size*WORD_PARAM.BITS-1 downto 0);
            signal    q_word    :  std_logic_vector(NETWORK_PARAM.Size*WORD_PARAM.BITS-1 downto 0);
        begin
            NET_I: for i in 0 to NETWORK_PARAM.Size-1 generate
                d_word((i+1)*WORD_PARAM.BITS-1 downto i*WORD_PARAM.BITS)
                    <= sorted_word(i+NETWORK_PARAM.Lo);
            end generate;
            Q: Word_Pipeline_Register
                generic map(                                      --
                    WORD_PARAM  => WORD_PARAM                   , --
                    WORDS       => NETWORK_PARAM.Size           , --
                    INFO_BITS   => INFO_BITS                    , --
                    QUEUE_SIZE  => Stage_Param.QUEUE_SIZE         --
                )                                                 -- 
                port map (                                        --
                    CLK         => CLK                          , -- In  :
                    RST         => RST                          , -- In  :
                    CLR         => CLR                          , -- In  :
                    I_WORD      => d_word                       , -- In  :
                    I_INFO      => stage_info (stage-1)         , -- In  :
                    I_VALID     => stage_valid(stage-1)         , -- In  :
                    I_READY     => stage_ready(stage-1)         , -- Out :
                    O_WORD      => q_word                       , -- Out :
                    O_INFO      => stage_info (stage  )         , -- Out :
                    O_VALID     => stage_valid(stage  )         , -- Out :
                    O_READY     => stage_ready(stage  )         , -- In  :
                    BUSY        => stage_busy (stage  )           -- 
                );
            NET_O: for i in 0 to NETWORK_PARAM.Size-1 generate
                stage_word(stage)(i+NETWORK_PARAM.Lo)
                    <= q_word((i+1)*WORD_PARAM.BITS-1 downto i*WORD_PARAM.BITS);
            end generate;
        end block;
    end generate;
  
```



### OUTLET Block


 O_WORD はネットワーク毎のソート済みのワードを一次元のビット配列(std_logic_vector)にしたものです。OUTLET ブロックではソート済みの各ネットワークの出力ワードを O_WORD に変換します。


```VHDL:src/main/vhdl/core/sorting_network_core.vhd
    OUTLET: block
    begin
        NET: for i in 0 to NETWORK_PARAM.Size-1 generate
            O_WORD((i+1)*WORD_PARAM.BITS-1 downto i*WORD_PARAM.BITS)
                <= stage_word (STAGE_LAST)(i+NETWORK_PARAM.Lo);
        end generate;
        O_INFO  <= stage_info (STAGE_LAST);
        O_VALID <= stage_valid(STAGE_LAST);
        stage_ready(STAGE_LAST) <= O_READY;
    end block;
    BUSY <= '1' when (stage_busy /= STAGE_BUSY_ALL0) else '0';
end RTL;
  
```



# 参照


* 目次: [「はじめに」]
* 次回: [「ソーティングネットワーク(バイトニックマージソート)」]
* 前回: [「ワード比較器」]
* ソースコード: https://github.com/ikwzm/Merge_Sorter/blob/1.4.1/src/main/vhdl/core/sorting_network.vhd   
https://github.com/ikwzm/Merge_Sorter/blob/1.4.1/src/main/vhdl/core/sorting_network_core.vhd


[「はじめに」]: https://qiita.com/ikwzm/items/6665b2ef44d878a5b85f "「VHDL で書くマージソーター(はじめに)」@Qiita"
[「ワードの定義」]: https://qiita.com/ikwzm/items/bdcd8876317b908ff492 "「VHDL で書くマージソーター(ワードの定義)」@Qiita"
[「ワード比較器」]: https://qiita.com/ikwzm/items/d5d1dd264b1670f33bd7 "「VHDL で書くマージソーター(ワード比較器)」@Qiita"
[「ソーティングネットワーク(コアパッケージ)」]: https://qiita.com/ikwzm/items/a1d06e47523759c726ae "「VHDL で書くソーティングネットワーク(コアパッケージ)」@Qiita"
[「ソーティングネットワーク(バイトニックマージソート)」]: https://qiita.com/ikwzm/items/366eacbf6a877994c955 "「VHDL で書くソーティングネットワーク(バイトニックマージソート)」@Qiita"
[「ソーティングネットワーク(バッチャー奇偶マージソート)」]: https://qiita.com/ikwzm/items/c21a53f21b87408a7805 "「VHDL で書くソーティングネットワーク(バッチャー奇偶マージソート)」@Qiita"
[「シングルワード マージソート ノード」]: https://qiita.com/ikwzm/items/7fd7ef9ffc4d9b314fee "「VHDL で書くマージソーター(シングルワード マージソート ノード)」@Qiita"
[「マルチワード マージソート ノード」]: https://qiita.com/ikwzm/items/ed96b7a44b83bcee4ba5 "「VHDL で書くマージソーター(マルチワード マージソート ノード)」@Qiita"
[「マージソート ツリー」]: https://qiita.com/ikwzm/items/1f76ae5cda95aaf92501 "「VHDL で書くマージソーター(マージソート ツリー)」@Qiita"
[「端数ワード処理」]: https://qiita.com/ikwzm/items/6b15340f1e05ef03f8d0 "「VHDL で書くマージソーター(端数ワード処理)」@Qiita"
[「ストリーム入力」]: https://qiita.com/ikwzm/items/56e22511021a082a2ccd "「VHDL で書くマージソーター(ストリーム入力)」@Qiita"
[「ストリームフィードバック」]: https://qiita.com/ikwzm/items/e8c59c0ec92956c9355f "「VHDL で書くマージソーター(ストリームフィードバック)」@Qiita"
[「ArgSort IP」]: https://qiita.com/ikwzm/items/89fc9542492fca74c9e3 "「VHDL で書くマージソーター(ArgSort IP)」@Qiita"
[「ArgSort-Ultra96」]: https://qiita.com/ikwzm/items/d58c9b77d038e23ac792 "「VHDL で書くマージソーター(ArgSort-Ultra96)」@Qiita"
[「ArgSort-Kv260」]: https://qiita.com/ikwzm/items/ec0f779534c44b35334a "「VHDL で書くマージソーター(ArgSort-Kv260)」@Qiita"
[ACRi]: https://www.acri.c.titech.ac.jp/wp "アダプティブコンピューティング研究推進体(ACRi)"
[アダプティブコンピューティング研究推進体(ACRi)]: https://www.acri.c.titech.ac.jp/wp "アダプティブコンピューティング研究推進体(ACRi)"
[「FPGAを使って基本的なアルゴリズムのソーティングを劇的に高速化(1)」]: https://www.acri.c.titech.ac.jp/wordpress/archives/132 "「FPGAを使って基本的なアルゴリズムのソーティングを劇的に高速化(1)」"
[「FPGAを使って基本的なアルゴリズムのソーティングを劇的に高速化(2)」]: https://www.acri.c.titech.ac.jp/wordpress/archives/501 "「FPGAを使って基本的なアルゴリズムのソーティングを劇的に高速化(2)」"
[「FPGAを使って基本的なアルゴリズムのソーティングを劇的に高速化(3)」]: https://www.acri.c.titech.ac.jp/wordpress/archives/2393 "「FPGAを使って基本的なアルゴリズムのソーティングを劇的に高速化(3)」"
[「FPGAを使って基本的なアルゴリズムのソーティングを劇的に高速化(4)」]: https://www.acri.c.titech.ac.jp/wordpress/archives/3888 "「FPGAを使って基本的なアルゴリズムのソーティングを劇的に高速化(4)」"
[「FPGAを使って基本的なアルゴリズムのソーティングを劇的に高速化(5)」]: https://www.acri.c.titech.ac.jp/wordpress/archives/4713 "「FPGAを使って基本的なアルゴリズムのソーティングを劇的に高速化(5)」"