1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vitis C言語で作成した関数を論理合成して動作させてみる

Posted at

はじめに

Vitis HLSで足し算の関数を作成して論理合成して、動作させてみました。
Vitis 2024.2/Vivado 2024.2を使用しています。
備忘録として残しておきます。

VitisでHLSでIPを作る

VitisでCreate HLS Componentを選択して、ウイザードに従って値を入力
image.png

flow_targetは、Vivado IP Flow Targetを選択
package.output.formatは、Generate Vivado IP and .zip archiveを選択

image.png

add.cpp
#include <ap_int.h>

ap_uint<32> add32(ap_uint<32> *in1, ap_uint<32> *in2) {
#pragma HLS TOP name=add32
#pragma HLS INTERFACE s_axilite port=in1
#pragma HLS INTERFACE s_axilite port=in2
#pragma HLS INTERFACE s_axilite port=return

    return *in1 + *in2;
}

テストするほどでも無いですが、テストベンチを作成してみます。
ChatGPTに作ってもらいました。

add_tb.cpp
#include <iostream>
#include <ap_int.h>

ap_uint<32> add32(ap_uint<32> *in1, ap_uint<32> *in2);

int main() {
    ap_uint<32> in1, in2, out, expected_out;

    in1 = 10;
    in2 = 20;
    expected_out = in1 + in2;

    out = add32(&in1, &in2);

    if (out == expected_out) {
        std::cout << "Test Case 1 Passed: " << out << " == " << expected_out << std::endl;
    } else {
        std::cerr << "Test Case 1 Failed: " << out << " != " << expected_out << std::endl;
    }

    in1 = 0xFFFFFFFF;
    in2 = 1;
    expected_out = in1 + in2;

    out = add32(&in1, &in2);

    // 結果の確認
    if (out == expected_out) {
        std::cout << "Test Case 2 Passed: " << out << " == " << expected_out << std::endl;
    } else {
        std::cerr << "Test Case 2 Failed: " << out << " != " << expected_out << std::endl;
    }

    in1 = 0;
    in2 = 0;
    expected_out = in1 + in2;

    out = add32(&in1, &in2);

    if (out == expected_out) {
        std::cout << "Test Case 3 Passed: " << out << " == " << expected_out << std::endl;
    } else {
        std::cerr << "Test Case 3 Failed: " << out << " != " << expected_out << std::endl;
    }

    return 0;
}

VitisのフローのC SIMULATION SYNTHESIS C/RTL CO-SIMULATION PACKAGEを順に実行します。

次のファイルが作成されました。
hls_add/hls_add/hls_add/hls/impl/ip/xilinx_com_hls_add32_1_0.zip

vivadoでハードウエアを作成する

Vivadoを起動して、新規プロジェクトを作成します。
プロジェクト名は、vivado_hls_addとします。

IP Repositoryに、先ほど作成したIPのプロジェクトフォルダを追加します。hls_add/hls_add

image.png

Create Block Designを選択します。Design nameは、design_hls_addとします。

DiagramでZYNQ7 Processing Systemを追加します。

Diagramで、add ipを実行して、add32を追加します。
Run Connection Automationを実行して、接続します。

image.png

Create HDL Wrapperを選択して、OKを押します。

Generate Bitstre を実行

Export Hardware Platformを実行
Incloud bitstreamをチェックする
ファイル名は、デフォルト値の、design_hls_add_wrapper
して、OKを押します。

Standaloneアプリで動作させてみる

VitisでPlatformを作成します。
作成時に、先ほど作成したXSAファイルを指定します。

image.png

Operating Systemは、Standaloneを選択します。

Platformをビルドしてみます。

ビルドすると、Output/Platform/hw/drivers/add32_v1_0/srcに、xadd32.c, xadd32.hが作成されます。
これを呼び出すことで、作成したIPを動作させることができます。

xadd32.h
// ==============================================================
// Vitis HLS - High-Level Synthesis from C, C++ and OpenCL v2024.2 (64-bit)
// Tool Version Limit: 2024.11
// Copyright 1986-2022 Xilinx, Inc. All Rights Reserved.
// Copyright 2022-2024 Advanced Micro Devices, Inc. All Rights Reserved.
// 
// ==============================================================
#ifndef XADD32_H
#define XADD32_H

#ifdef __cplusplus
extern "C" {
#endif

/***************************** Include Files *********************************/
#ifndef __linux__
#include "xil_types.h"
#include "xil_assert.h"
#include "xstatus.h"
#include "xil_io.h"
#else
#include <stdint.h>
#include <assert.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>
#endif
#include "xadd32_hw.h"

/**************************** Type Definitions ******************************/
#ifdef __linux__
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#else
typedef struct {
#ifdef SDT
    char *Name;
#else
    u16 DeviceId;
#endif
    u64 Control_BaseAddress;
} XAdd32_Config;
#endif

typedef struct {
    u64 Control_BaseAddress;
    u32 IsReady;
} XAdd32;

typedef u32 word_type;

/***************** Macros (Inline Functions) Definitions *********************/
#ifndef __linux__
#define XAdd32_WriteReg(BaseAddress, RegOffset, Data) \
    Xil_Out32((BaseAddress) + (RegOffset), (u32)(Data))
#define XAdd32_ReadReg(BaseAddress, RegOffset) \
    Xil_In32((BaseAddress) + (RegOffset))
#else
#define XAdd32_WriteReg(BaseAddress, RegOffset, Data) \
    *(volatile u32*)((BaseAddress) + (RegOffset)) = (u32)(Data)
#define XAdd32_ReadReg(BaseAddress, RegOffset) \
    *(volatile u32*)((BaseAddress) + (RegOffset))

#define Xil_AssertVoid(expr)    assert(expr)
#define Xil_AssertNonvoid(expr) assert(expr)

#define XST_SUCCESS             0
#define XST_DEVICE_NOT_FOUND    2
#define XST_OPEN_DEVICE_FAILED  3
#define XIL_COMPONENT_IS_READY  1
#endif

/************************** Function Prototypes *****************************/
#ifndef __linux__
#ifdef SDT
int XAdd32_Initialize(XAdd32 *InstancePtr, UINTPTR BaseAddress);
XAdd32_Config* XAdd32_LookupConfig(UINTPTR BaseAddress);
#else
int XAdd32_Initialize(XAdd32 *InstancePtr, u16 DeviceId);
XAdd32_Config* XAdd32_LookupConfig(u16 DeviceId);
#endif
int XAdd32_CfgInitialize(XAdd32 *InstancePtr, XAdd32_Config *ConfigPtr);
#else
int XAdd32_Initialize(XAdd32 *InstancePtr, const char* InstanceName);
int XAdd32_Release(XAdd32 *InstancePtr);
#endif

void XAdd32_Start(XAdd32 *InstancePtr);
u32 XAdd32_IsDone(XAdd32 *InstancePtr);
u32 XAdd32_IsIdle(XAdd32 *InstancePtr);
u32 XAdd32_IsReady(XAdd32 *InstancePtr);
void XAdd32_EnableAutoRestart(XAdd32 *InstancePtr);
void XAdd32_DisableAutoRestart(XAdd32 *InstancePtr);
u32 XAdd32_Get_return(XAdd32 *InstancePtr);

void XAdd32_Set_in1(XAdd32 *InstancePtr, u32 Data);
u32 XAdd32_Get_in1(XAdd32 *InstancePtr);
void XAdd32_Set_in2(XAdd32 *InstancePtr, u32 Data);
u32 XAdd32_Get_in2(XAdd32 *InstancePtr);

void XAdd32_InterruptGlobalEnable(XAdd32 *InstancePtr);
void XAdd32_InterruptGlobalDisable(XAdd32 *InstancePtr);
void XAdd32_InterruptEnable(XAdd32 *InstancePtr, u32 Mask);
void XAdd32_InterruptDisable(XAdd32 *InstancePtr, u32 Mask);
void XAdd32_InterruptClear(XAdd32 *InstancePtr, u32 Mask);
u32 XAdd32_InterruptGetEnabled(XAdd32 *InstancePtr);
u32 XAdd32_InterruptGetStatus(XAdd32 *InstancePtr);

#ifdef __cplusplus
}
#endif

#endif

applicationを作成します。Platformは、上で作成したものを指定します。

アプリケーションのSettingsのlaunch.jsonのBoard InitializationをFSBLに変更します。
これを行わないと、エラーが発生して動作しませんでした。
TCLでないと動かな場合もあったりして、よくわかっていません。

アプリケーションのSources/srcにmain.cを新規作成します。

関数の呼び出しは、次の手順にします。

  • パラメータの設定
  • XAdd32_Startを実行
  • XAdd32_IsDoneが真になるまで待つ
  • XAdd32_Get_returnで結果を取得する
main.c
#include <stdio.h>
#include "xadd32.h"

int init_xadd32(XAdd32 *add32, XAdd32_Config *config) {
    return XAdd32_CfgInitialize(add32, config);
}

int main() {
    u32 ret;
    XAdd32 add32;
    XAdd32_Config config = {
        .Control_BaseAddress = 0x40000000  // VivadoのIPアドレスMAPに合わせる
    };

    if (init_xadd32(&add32, &config) != XST_SUCCESS) {
        printf("XAdd32 の初期化に失敗しました\n");
        return -1;
    }

    u32 a = 10;
    u32 b = 20;

    XAdd32_Set_in1(&add32, a);
    XAdd32_Set_in2(&add32, b);

    u32 result, tmp;

    tmp = XAdd32_Get_in1(&add32);
    tmp = XAdd32_Get_in2(&add32);
    XAdd32_Start(&add32);
    while (1) {
        ret = XAdd32_IsDone(&add32);
        if (ret) {
            break;
        }
    }
    result = XAdd32_Get_return(&add32);
    printf("結果: %u + %u = %u\n", a, b, result);

    return 0;
}

ビルドして、デバッカーで実行します。

ステップ実行してみると、resultに1e=(十進数で30)が入っていることが確認できました。

まとめ

  • VitisでHLSでIPを作成して、Vivadoでハードウエアを作成し、Standaloneアプリで動作させるまでの手順を紹介しました。
  • 作成されたDriversの関数を呼び出す事で、ハードウエアを動作させ、演算結果を得る事ができました。
  • 今回は、簡単な加算の例を紹介しましたが、他の演算も同様に作成できるとおもいます。

今回は、Standaloneアプリで作成しましたが、Linuxアプリで作成することもできます。
原理的には、NIFを使う事で、Elixirからも呼び出す事ができると思います。今後試して見たいと思います。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?