KV260プラットフォームにRISC-Vを組み込む(AI EDGEコンテスト対応版）

# RISC-VをKV260に組み込む

RISC-Vは、オープンソースのCPUです。
次世代CPUの有力候補で、カスタマイズできるのが大きな特徴になっています。
第６回AIエッジコンテストでの課題で、RISCVを搭載することになりました。
ただ、CPUをFPGAに搭載するのにはハードルも高いです。
今回は、オープンソースのVexRISCVを使って、FPGAボード、KV260に搭載する方法をご紹介します。

https://signate.jp/lp/ai-edge-contest/2022


# FPGAにおけるRISCVの位置づけ。
RISCVはオープンソースのCPUです。命令セットが定義されていて、それに対してのCPUの実装は自由になっています。実質的にフリーライセンスなので、そのため多くの発表例があります。
ハードウェアの実装はIC化すると言うのも一つの例ですが、FPGAに実装している例も多いです。

今回のはRISCVを使えば、どの実装でもいいのですが、評価の高かったVexRISCVを使用して、実装します。

https://github.com/riscv


# 実装の方法
KV260に向けてRISCVの実装をご紹介します。VexRISCVを使った実装です。

1. VexRISCVのGithubからデータを取り込みます。
2. VexRISCVの開発環境を整える。
3. パラメータを設定、コンパイル
4. Vitis向けにヘッダー設計
5. Vitis アクセラレータに組み込む
6. RISC-Vのソフトウェアコンパイル
7. Vitisのアプリケーションを組み込む
8. KV260で実行


今回、ソフトウェアの実機動作を含めて、全部紹介したかったのですが、実装を進める途中のシミュレーションで未解決の問題見つかりまして見つかりまして、一部はご紹介のみになります。
６番までは出来ています。
また、改めて、ブログの方を更新させていただきます。

# 事前準備
予め必要なものがあります。

KV260用のVitis プラットフォーム。
RISC-Vを組み込むために必要になります。
ブログ記事を参照にして、作成することが出来ます。

https://qiita.com/basaro_k/items/7295b214f80226b28e7a


KV260　SDカード
実機動作できる、SDカードイメージが必要です。今回はPetalinux2022.1のバージョンを使っています。

https://qiita.com/basaro_k/items/b164a56e978001b8161e

#　RISC-V の 組み込みの仕方
VexRISCV は次のページに用意されています。VexRISCVはSpinalHDLで作成されています。このまま、KV260の開発環境に持ってくることは出来ません。HDL（Verilog)に変更する必要があります。
基本的には、ここに書いてあるページのとおりに実行すれば、RISCVのVerilogソースが出来上がります。
KV260に組み込むには、インターフェースの都合から、さらに追加のソースコードが必要になります。

https://github.com/SpinalHDL/VexRiscv

###### VexRiscvをダウンロードする。

1.1 Ubutu のターミナルを開けて、ワークスペースに移動します。今回は AIEDGEにしました。

```
cd ~/AIEDGE
```
1.2 Gitコマンドを使って、VexRISCVのソースコードをダウンロードします。

``` git
 git clone --recursive https://github.com/SpinalHDL/VexRiscv.git
```

1.3 ダウンロードしたファイルを確認します。

```
ll VexRiscv
```

###### VexRISCVの開発環境を整える。
JAVA 8を使用しています。他のバージョンのJAVAを使っていても、切り替えが出来ます。またはコンパイラーまでの紹介になります。

2.1 下記をコマンドラインで順番に実行します。JAVAとspinalHDLの開発環境をインストールします。

```
# JAVA JDK 8
sudo add-apt-repository -y ppa:openjdk-r/ppa
sudo apt-get update
sudo apt install openjdk-8-jdk -y
sudo update-alternatives --config java
sudo update-alternatives --config javac

# Install SBT - https://www.scala-sbt.org/
echo "deb https://repo.scala-sbt.org/scalasbt/debian all main" | sudo tee /etc/apt/sources.list.d/sbt.list
echo "deb https://repo.scala-sbt.org/scalasbt/debian /" | sudo tee /etc/apt/sources.list.d/sbt_old.list
curl -sL "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x2EE0EA64E40A89B84B2DF73499E82A75642AC823" | sudo apt-key add
sudo apt update
sudo apt install sbt
```

###### パラメータを設定、コンパイル
ソースファイルはSpinalHDLで書かれています。ただし、XILINXのVitisでは、SpinalHDLは使えません。Verilogか、VHDLに変更する必要があります。幸い、コンパイラーがVerilogを出力しますので、それをもとにして、使用します。ただし、パラメータはSpinalHDL側で変更したほうが望ましいです。


3.1 ソースファイルは、VexRiscv/src/main/scala/vexriscv/demo　の中にあります。
今回は、GenFull.scala を使って、実行します。

3.2 必要に応じてパラメータの設定を行います。今回はリセットベクタを０番地にしたいので、Geditなどで、で、GenFull.scaleを開き、１４行目以降に、ResetVectorを挿入して実行しました。
なお、詳しいパラメータの説明は次のところに、書いてあります。

[パラメータの説明。](https://github.com/SpinalHDL/VexRiscv#plugins "Plugins")

```
      new IBusCachedPlugin(
        resetVector = 0x00000000l,
        prediction = DYNAMIC,
```
3.3 コンパイルをします。今回はGenFullで行います。各種パラメータは出来ますので、好みに合わせて、好きなタイプのコンパイルを行います。VexRiscv.v が出来上がります。

```
sbt "runMain vexriscv.demo.GenFull"
```



###### Vitis向けにヘッダー設計
出来上がった、Verlogファイルがそのまま使用できればいいのですが、KV260に合わせるためには、インターフェースを追加する必要がああります。

4.1　ファイルを作成します。ソースファイルは折りたたんだ先にありますので、開いてからコピーしてください。ファイル名は、riscv_example.svで保存します。

<details><summary>Verilogソースを作成します。</summary>

``` riscv_exampl
// This is a generated file. Use and modify at your own risk.
//////////////////////////////////////////////////////////////////////////////// 
// default_nettype of none prevents implicit wire declaration.
`default_nettype none
module riscv_example #(
  parameter integer C_M00_AXI_ADDR_WIDTH = 64,
  parameter integer C_M00_AXI_DATA_WIDTH = 32,
  parameter integer C_M01_AXI_ADDR_WIDTH = 64,
  parameter integer C_M01_AXI_DATA_WIDTH = 32
)
(
  // System Signals
  input  wire                              ap_clk         ,
  input  wire                              ap_rst_n       ,
  // AXI4 master interface m00_axi
  output wire                              m00_axi_awvalid,
  input  wire                              m00_axi_awready,
  output wire [C_M00_AXI_ADDR_WIDTH-1:0]   m00_axi_awaddr ,
  output wire [8-1:0]                      m00_axi_awlen  ,
  output wire                              m00_axi_wvalid ,
  input  wire                              m00_axi_wready ,
  output wire [C_M00_AXI_DATA_WIDTH-1:0]   m00_axi_wdata  ,
  output wire [C_M00_AXI_DATA_WIDTH/8-1:0] m00_axi_wstrb  ,
  output wire                              m00_axi_wlast  ,
  input  wire                              m00_axi_bvalid ,
  output wire                              m00_axi_bready ,
  output wire                              m00_axi_arvalid,
  input  wire                              m00_axi_arready,
  output wire [C_M00_AXI_ADDR_WIDTH-1:0]   m00_axi_araddr ,
  output wire [8-1:0]                      m00_axi_arlen  ,
  input  wire                              m00_axi_rvalid ,
  output wire                              m00_axi_rready ,
  input  wire [C_M00_AXI_DATA_WIDTH-1:0]   m00_axi_rdata  ,
  input  wire                              m00_axi_rlast  ,
  // AXI4 master interface m01_axi
  output wire                              m01_axi_awvalid,
  input  wire                              m01_axi_awready,
  output wire [C_M01_AXI_ADDR_WIDTH-1:0]   m01_axi_awaddr ,
  output wire [8-1:0]                      m01_axi_awlen  ,
  output wire                              m01_axi_wvalid ,
  input  wire                              m01_axi_wready ,
  output wire [C_M01_AXI_DATA_WIDTH-1:0]   m01_axi_wdata  ,
  output wire [C_M01_AXI_DATA_WIDTH/8-1:0] m01_axi_wstrb  ,
  output wire                              m01_axi_wlast  ,
  input  wire                              m01_axi_bvalid ,
  output wire                              m01_axi_bready ,
  output wire                              m01_axi_arvalid,
  input  wire                              m01_axi_arready,
  output wire [C_M01_AXI_ADDR_WIDTH-1:0]   m01_axi_araddr ,
  output wire [8-1:0]                      m01_axi_arlen  ,
  input  wire                              m01_axi_rvalid ,
  output wire                              m01_axi_rready ,
  input  wire [C_M01_AXI_DATA_WIDTH-1:0]   m01_axi_rdata  ,
  input  wire                              m01_axi_rlast  ,
  // Control Signals
  input  wire                              ap_start       ,
  output wire                              ap_idle        ,
  output wire                              ap_done        ,
  output wire                              ap_ready       ,
  input  wire [32-1:0]                     reset_riscv    ,
  input  wire [32-1:0]                     interrupt_riscv,
  input  wire [32-1:0]                     ABS_ADDRESS    ,
  input  wire [32-1:0]                     SAMPLE         ,
  input  wire [64-1:0]                     dBus           ,
  input  wire [64-1:0]                     iBus           
);


timeunit 1ps;
timeprecision 1ps;

///////////////////////////////////////////////////////////////////////////////
// Local Parameters
///////////////////////////////////////////////////////////////////////////////
// Large enough for interesting traffic.
localparam integer  LP_DEFAULT_LENGTH_IN_BYTES = 16384;
localparam integer  LP_NUM_EXAMPLES    = 2;

///////////////////////////////////////////////////////////////////////////////
// Wires and Variables
///////////////////////////////////////////////////////////////////////////////
(* KEEP = "yes" *)
logic                                areset                         = 1'b0;
logic                                ap_start_r                     = 1'b0;
logic                                ap_idle_r                      = 1'b1;
logic                                ap_start_pulse                ;
logic [LP_NUM_EXAMPLES-1:0]          ap_done_i                     ;
logic [LP_NUM_EXAMPLES-1:0]          ap_done_r                      = {LP_NUM_EXAMPLES{1'b0}};
logic [32-1:0]                       ctrl_xfer_size_in_bytes        = LP_DEFAULT_LENGTH_IN_BYTES;
logic [32-1:0]                       ctrl_constant                  = 32'd1;

// RISC V address

logic              dBus_cmd_valid;
logic               dBus_cmd_ready;
logic              dBus_cmd_payload_wr;
logic              dBus_cmd_payload_uncached;
logic     [31:0]   dBus_cmd_payload_address;
logic     [31:0]   dBus_cmd_payload_data;
logic     [3:0]    dBus_cmd_payload_mask;
logic     [2:0]    dBus_cmd_payload_size;
logic              dBus_cmd_payload_last;
logic               dBus_rsp_valid;
logic               dBus_rsp_payload_last;
logic      [31:0]   dBus_rsp_payload_data;
logic               dBus_rsp_payload_error;
logic               timerInterrupt;
logic               externalInterrupt;
logic               softwareInterrupt;
logic               debug_bus_cmd_valid;
logic           debug_bus_cmd_ready;
logic               debug_bus_cmd_payload_wr;
logic      [7:0]    debug_bus_cmd_payload_address;
logic      [31:0]   debug_bus_cmd_payload_data;
logic  [31:0]   debug_bus_rsp_data;
logic              debug_resetOut;
logic              iBus_cmd_valid;
logic               iBus_cmd_ready;
logic  [31:0]   iBus_cmd_payload_address;
logic     [2:0]    iBus_cmd_payload_size;
logic               iBus_rsp_valid;
logic      [31:0]   iBus_rsp_payload_data;
logic               iBus_rsp_payload_error;
logic               clk;
//logic               reset;
logic               debugReset;


// ADDRESS


logic dBus_addflg;
logic iBus_addflg;
logic reset_0;
logic reset_1;



///////////////////////////////////////////////////////////////////////////////
// Begin RTL
///////////////////////////////////////////////////////////////////////////////

// Register and invert reset signal.
always @(posedge ap_clk) begin
  areset <= ~ap_rst_n;
end

// create pulse when ap_start transitions to 1
always @(posedge ap_clk) begin
  begin
    ap_start_r <= ap_start;
  end
end

assign ap_start_pulse = ap_start & ~ap_start_r;

assign reset_0 = ~ap_start | reset_riscv[0];
assign reset_1 = ~ap_start | reset_riscv[1];

// ap_idle is asserted when done is asserted, it is de-asserted when ap_start_pulse
// is asserted
always @(posedge ap_clk) begin
  if (areset) begin
    ap_idle_r <= 1'b1;
  end
  else begin
    ap_idle_r <= ap_done ? 1'b1 :
      ap_start_pulse ? 1'b0 : ap_idle;
  end
end

assign ap_idle = ap_idle_r;

// Done logic
always @(posedge ap_clk) begin
  if (areset) begin
    ap_done_r <= '0;
  end
  else begin
    ap_done_r <= (ap_done) ? '0 : ap_done_r | ap_done_i;
  end
end

assign ap_done = &ap_done_r;

// Ready Logic (non-pipelined case)
assign ap_ready = ap_done;


assign m00_axi_awvalid = (dBus_cmd_valid && dBus_cmd_payload_wr && !dBus_addflg) ? 1:0;


always_ff @(posedge ap_clk or negedge ap_rst_n) begin : proc_dbus_addflg
  if(~ap_rst_n) begin
    dBus_addflg <= 0;
  end  else if(m00_axi_awvalid && m00_axi_awready) begin
    dBus_addflg <= 1;
  end  else if(m00_axi_arvalid && m00_axi_arready) begin
    dBus_addflg <= 1;
  end else if (!dBus_cmd_valid) begin
    dBus_addflg <= 0;
  end
end

assign m00_axi_awaddr = ( dBus_cmd_payload_address > ABS_ADDRESS) ? dBus_cmd_payload_address : dBus_cmd_payload_address + dBus[31:0];

assign m00_axi_awlen = (dBus_cmd_payload_size == 3'd2) ? 8'd1 :
                       (dBus_cmd_payload_size == 3'd3) ? 8'd2 :
                       (dBus_cmd_payload_size == 3'd4) ? 8'd3 :
                       (dBus_cmd_payload_size == 3'd5) ? 8'd4 :
                       (dBus_cmd_payload_size == 3'd6) ? 8'd5 :
                       (dBus_cmd_payload_size == 3'd7) ? 8'd6 : 8'd0;

assign m00_axi_wvalid = dBus_cmd_valid;

assign m00_axi_wdata = dBus_cmd_payload_data;

assign m00_axi_wstrb = dBus_cmd_payload_mask;

assign m00_axi_wlast = dBus_cmd_payload_last;

assign m00_axi_bready = 1'b1;

assign m00_axi_arvalid = (dBus_cmd_valid && !dBus_cmd_payload_wr && !dBus_addflg) ? 1:0;

assign m00_axi_araddr = ( dBus_cmd_payload_address > ABS_ADDRESS) ? dBus_cmd_payload_address : dBus_cmd_payload_address + dBus[31:0];


assign m00_axi_arlen = (dBus_cmd_payload_size == 3'd2) ? 8'd1 :
                       (dBus_cmd_payload_size == 3'd3) ? 8'd2 :
                       (dBus_cmd_payload_size == 3'd4) ? 8'd3 :
                       (dBus_cmd_payload_size == 3'd5) ? 8'd4 :
                       (dBus_cmd_payload_size == 3'd6) ? 8'd5 :
                       (dBus_cmd_payload_size == 3'd7) ? 8'd6 : 8'd0;

assign m00_axi_rready = 1'b1;

assign m01_axi_awvalid = 1'b0;

assign m01_axi_awaddr = 32'b0;

assign m01_axi_awaddr = ( iBus_cmd_payload_address > ABS_ADDRESS) ? iBus_cmd_payload_address : iBus_cmd_payload_address + iBus[31:0];

assign m01_axi_wdata = 32'b0;

assign m01_axi_wstrb = 4'b0;

assign m01_axi_wlast = 1'b0;

assign m01_axi_bready = 1'b1;

assign m01_axi_arvalid = (iBus_cmd_valid  && !iBus_addflg) ? 1:0;

always_ff @(posedge ap_clk or negedge ap_rst_n) begin : proc_ibus_addflg
  if(~ap_rst_n) begin
    iBus_addflg <= 0;
  end  else if(m01_axi_arvalid && m01_axi_arready) begin
    iBus_addflg <= 1;
  end else if (!iBus_cmd_valid) begin
    iBus_addflg <= 0;
  end
end

assign m01_axi_araddr = iBus_cmd_payload_address;

assign m01_axi_arlen = (iBus_cmd_payload_size == 3'd2) ? 8'd1 :
                       (iBus_cmd_payload_size == 3'd3) ? 8'd2 :
                       (iBus_cmd_payload_size == 3'd4) ? 8'd3 :
                       (iBus_cmd_payload_size == 3'd5) ? 8'd4 :
                       (iBus_cmd_payload_size == 3'd6) ? 8'd5 :
                       (iBus_cmd_payload_size == 3'd7) ? 8'd6 : 8'd0;

assign m01_axi_rready = 1'b1;



assign dBus_cmd_ready = m00_axi_wready;

assign dBus_rsp_valid = m00_axi_rvalid | m00_axi_bvalid;

assign dBus_rsp_payload_last = m00_axi_rlast;

assign dBus_rsp_payload_data = m00_axi_rdata;

assign dBus_rsp_payload_error = 0;


assign timerInterrupt = interrupt_riscv[0];
assign externalInterrupt = interrupt_riscv[1];
assign softwareInterrupt = interrupt_riscv[2];

assign  debug_bus_cmd_valid = 0;
assign  debug_bus_cmd_payload_wr = 0;
assign  debug_bus_cmd_payload_address = 0;
assign  debug_bus_cmd_payload_data = 0;

assign iBus_cmd_ready = m01_axi_arready;

assign iBus_rsp_valid = m01_axi_rvalid;

assign iBus_rsp_payload_data = m01_axi_rdata;

assign iBus_rsp_payload_error = 0;

assign clk = ap_clk;

assign ap_done_i = (dBus_cmd_valid && dBus_cmd_payload_wr && (dBus_cmd_payload_address == 32'hFFFFFFF0))? 2'b11:0;

VexRiscv riscv(
  .dBus_cmd_valid(dBus_cmd_valid),
  .dBus_cmd_ready(dBus_cmd_ready),
  .dBus_cmd_payload_wr(dBus_cmd_payload_wr),
  .dBus_cmd_payload_uncached(dBus_cmd_payload_uncached),
  .dBus_cmd_payload_address(dBus_cmd_payload_address),
  .dBus_cmd_payload_data(dBus_cmd_payload_data),
  .dBus_cmd_payload_mask(dBus_cmd_payload_mask),
  .dBus_cmd_payload_size(dBus_cmd_payload_size),
  .dBus_cmd_payload_last(dBus_cmd_payload_last),
  .dBus_rsp_valid(dBus_rsp_valid),
  .dBus_rsp_payload_last(dBus_rsp_payload_last),
  .dBus_rsp_payload_data(dBus_rsp_payload_data),
  .dBus_rsp_payload_error(dBus_rsp_payload_error),
  .timerInterrupt(timerInterrupt),
  .externalInterrupt(externalInterrupt),
  .softwareInterrupt(softwareInterrupt),
  .debug_bus_cmd_valid(debug_bus_cmd_valid),
  .debug_bus_cmd_ready(debug_bus_cmd_ready),
  .debug_bus_cmd_payload_wr(debug_bus_cmd_payload_wr),
  .debug_bus_cmd_payload_address(debug_bus_cmd_payload_address),
  .debug_bus_cmd_payload_data(debug_bus_cmd_payload_data),
  .debug_bus_rsp_data(debug_bus_rsp_data),
  .debug_resetOut(debug_resetOut),
  .iBus_cmd_valid(iBus_cmd_valid),
  .iBus_cmd_ready(iBus_cmd_ready),
  .iBus_cmd_payload_address(iBus_cmd_payload_address),
  .iBus_cmd_payload_size(iBus_cmd_payload_size),
  .iBus_rsp_valid(iBus_rsp_valid),
  .iBus_rsp_payload_data(iBus_rsp_payload_data),
  .iBus_rsp_payload_error(iBus_rsp_payload_error),
  .clk(clk),
  .reset(reset_0),
  .debugReset(reset_1)
);

endmodule : riscv_example
`default_nettype wire

```

</details>

###### Vitis アクセラレータに組み込む
作成したファイルをVitisプラットフォームに組み込みます。ここでは、新しいアプリケーションプロジェクトを作って、VexRiscV.vを組み込む方法をご紹介します。

5.1 アプリケーションプロジェクトを作成します。。Vitisのメニューから　File → New → Application Projectを実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/03d48aec-39d2-43a8-681a-d4017560abdc.png)

5.2 アプリケーションプロジェクトを作成する画面が出てきます。　そのままNextを押します。

5.3 kv260_pfmを選択します。Nextを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/b90eab74-c15c-8097-7f3d-16895ca45036.png)

5.4 プロジェクト名をきめます。今回は riscv にしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/72dc463d-cad5-c751-7d79-d12b0700017b.png)

5.5 sysrootを設定します。ここは、共通イメージから解凍したものを使います。次の位置をして、入力してください。
`
/home/*****/AIEDGE/xilinx-zynqmp-common-v2022.1/sysroots/cortexa72-cortexa53-xilinx-linux`

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/e7fbbfe4-d2c6-73af-82b2-4ef966cc94bc.png)

5.6 アプリケーションのタイプを入力します。今回はEmpty Applicationを選びます。
終わったらFinishをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/615833c6-fea6-ffa8-4ceb-c427a39ff8ac.png)

5.7 Vexriscv は、Verilogで提供されています。このソースコードをVitisに合うように変更する必要があります。Vitisには、RTL WizartdというツールででVerilogの雛形を作ってくれます。、Verilog等が接続できるようになっています。メニューから XILINX→Launch RTL Kernel Wizard　で、riscv_kernels を選択します。（出てこないときもあります）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/e72e1fc2-5dbc-f36b-db81-8d326fa4dfa8.png)

5.8 作成するための画面が出てきます。そのままNextを押します。

5.9 作成するRTLカーネルと名前等を決めます。今回はriscvにしました。Nextをクリックします。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/225a1dfb-6d55-a30c-c5a5-0d9db41cfe4b.png)



5.10　レジスタポートの設定を行います。。今回は4ポート作成しました。reset_riscv interrupt_riscv ABS_ADDRESS SAMPLE です。それぞれ名前を入力したください。
ここでの名前は次のソースコードに反映されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/c23325ab-9cd3-293a-3773-6289775ba5db.png)

5.11 AXIポートの設定を行います。RISCVからメモリーにアクセスするために使用できます。
Widthは３２ビットを使うので、４バイトになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/ecc467b5-639e-9e24-4604-1347dbc848de.png)

5.12 AXISの設定画面が出てきます。今回は使わないので、そのままOKになります。

5.13 確認の画面が出てきます。OKボタンをクリックします。
ある程度時間が立って、Vivadoが立ち上がります。ここで、追加のソースコードを実行します。

5.14 VexRisc.vのソースコードを追加します。　ソースコードの上の＋ボタンをおして、Add Sourceを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/63460d7b-74bc-d24a-6bfc-f03315f708f8.png)

5.15 ソースファイルを選択することが出来ます。
今回は、Add or Create Design Sourcesを選びます


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/e2b12519-638e-4082-4ab6-bd12da58027f.png)

5.16 ソースファイルを追加しますので、Add Filesを追加します。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/b0fb4dd0-8d20-b2f3-6d03-5c0f8ac93a08.png)

5.17 VexRiscv.vを探して入力します。3.3で作成しました。VrexRiscvのフォルダーの下にあります。/home/****/AIEDGE/VexRiscv です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/128ece0e-25c8-fa59-95be-27fa50085be8.png)

5.18 riscv_example.svを4.1で作ったものと置き換えます。VexRiscv.vとの接続を行うためです。ファイルをダブルクリックして、その部分を全選択して、置き換えます。保存を忘れないようにしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/78dfc143-645b-9aea-649d-a42637a9ac7c.png)

5.19 全部終わりましたら、RTLカーネルを作成します。Generate RTL Kernelをクリックします。これはVitisで使える用のまとめる役目があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/3f3d35f2-5333-16d6-f18a-12660cde6bb2.png)

5.20 どのような形で渡すかを書いています。ここではソースコードのみを渡します。Sorce-olny Kernelを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/875e752e-d595-7933-5862-7889b9aeb900.png)

5.21 開いているVivadoを閉じるかを聞いてきます。このまま閉じてください。Vitisに戻ります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/8d6dc9a5-2efc-b87a-7e2f-9f04802ffb2b.png)

5.22　今のままでは、まだ、VitisでハードウェアIPの認識がありません。IPの認識をさせるために、riscv_kernels の設定を行います。IPの追加を行います。右上のActive build Configration は Hardwareに設定の選択してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/005bf20b-143c-fc46-58b7-7a99fe6a8b4f.png)

5.23 どのファイルをトップファイルにして、IP化するかを聞かれます。今回はriscvを選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/62867347-6399-d083-a476-fb041b722d84.png)

5.24　コンパイルをします。　riscv_system をクリックして、ハンマーアイコンをクリックします。
これで、kv260で動く、ハードウェア構成が出来上がります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/299213/77846250-15b2-7dca-be81-0d5f849a98fc.png)

AIエッジコンテスト参加者は、ここまでIPを作りまして、AIの方と組み合わせれば、ハードウェアの構成は週作成できます。
この使い方は、Vitis AIの作り方の方で、ご紹介させていただきます。

###### RISC-Vのクロスコンパイラー環境、コンパイル
RISCVはコンパイルは、CPUなので、コンパイラーが必要になります。知名度が高いため、検索すれば、かなり使い方は探し出さます。
今回はGNUのツールチェンを使いました。

詳しくは整理して、追加します。

https://github.com/riscv-collab/riscv-gnu-toolchain

##### Vitisのアプリケーションを組み込む
KV260では、何かしらの方法で、RISCVが動くプログラムを用意しないといけません。
今回は、Vitisで作成できる、アプリケーションでRISCVの動作を管理します。
クロスコンパイラーでSRECという形式でファイルが作成できます。それを取り込んでメモリーを介して、RISCVにデータをお渡しします。

ブログ発表までに間に合わせたかったのですが、デバッグがうまくいかず、
後日詳細を掲載させていただきます。




###### KV260で実行
　作成した、ファイルをKV260で動かします。
　必要なファイルはriscv.xclbin と、Vitisプラットフォーム作りでで作成した、pl.dtbo,shell.json です。ここも整理して、後日詳細を掲載させていただきます。


＃　お詫び

AIエッジコンテストのため、まだ途中でしたが、ブログ公開をさせていただきました。
一部、動作に不具合点があって、中途半端になってしまいました。
後日、追加しますので、ご了承ください。