diff --git a/uis7885/hardware/BUILD.gn b/uis7885/hardware/BUILD.gn index af654c05294e7e4c952eff2b8f65df54ca820d62..72da4382793dfef9a8469cdc378c07179e50deef 100644 --- a/uis7885/hardware/BUILD.gn +++ b/uis7885/hardware/BUILD.gn @@ -21,6 +21,7 @@ group("hardware_group") { "location:location_group", "display:display_buffer_model", "display:display_composer_model", - "camera:camera_group" + "camera:camera_group", + "npu:npu_group" ] } diff --git a/uis7885/hardware/npu/BUILD.gn b/uis7885/hardware/npu/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..a0744d8c2f2150b53a875ab6da7f09b8cc065ccb --- /dev/null +++ b/uis7885/hardware/npu/BUILD.gn @@ -0,0 +1,105 @@ +import("//build/ohos.gni") + +ohos_prebuilt_shared_library("libnnrt_vdi_impl.z.so") { + source = "nnrt_vdi/lib64/libnnrt_vdi_impl.z.so" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +ohos_prebuilt_shared_library("libuniai.so") { + source = "sdk/core/libuniai.so" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +ohos_prebuilt_shared_library("unisoc_NPU_backend.so") { + source = "sdk/core/unisoc_NPU_backend.so" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +ohos_prebuilt_shared_library("libcxx_shared.so") { + source = "sdk/lib64/libc++_shared.so" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +ohos_prebuilt_shared_library("libimgcustom.so") { + source = "sdk/lib64/libimgcustom.so" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +ohos_prebuilt_shared_library("libimgdnn.so") { + source = "sdk/lib64/libimgdnn.so" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +ohos_prebuilt_shared_library("libnnacompiler.so") { + source = "sdk/lib64/libnnacompiler.so" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +ohos_prebuilt_shared_library("libnnaruntime.so") { + source = "sdk/lib64/libnnaruntime.so" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +ohos_prebuilt_etc("npu_img_hwconfig.json") { + source = "sdk/etc/npu_img_hwconfig.json" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +ohos_prebuilt_etc("npu_img_mapconfig.json") { + source = "sdk/etc/npu_img_mapconfig.json" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +ohos_prebuilt_executable("uniai_testbench") { + source = "sdk/tools/uniai_testbench" + + install_images = [ chipset_base_dir ] + part_name = "soc_uis7885" + install_enable = true +} + +group("npu_group") { + deps = [ + ":libnnrt_vdi_impl.z.so", + ":libuniai.so", + ":unisoc_NPU_backend.so", + ":libcxx_shared.so", + ":libimgcustom.so", + ":libimgdnn.so", + ":libnnacompiler.so", + ":libnnaruntime.so", + ":npu_img_hwconfig.json", + ":npu_img_mapconfig.json", + ":uniai_testbench", + ] +} \ No newline at end of file diff --git a/uis7885/hardware/npu/nnrt_vdi/lib64/libnnrt_vdi_impl.z.so b/uis7885/hardware/npu/nnrt_vdi/lib64/libnnrt_vdi_impl.z.so new file mode 100644 index 0000000000000000000000000000000000000000..b7f20ef88922386dde321e3fb4e8e9d6aae24c2a Binary files /dev/null and b/uis7885/hardware/npu/nnrt_vdi/lib64/libnnrt_vdi_impl.z.so differ diff --git a/uis7885/hardware/npu/sdk/core/libuniai.so b/uis7885/hardware/npu/sdk/core/libuniai.so new file mode 100644 index 0000000000000000000000000000000000000000..a65e6adda6803dbd54b3c965ee8257613679a9cd Binary files /dev/null and b/uis7885/hardware/npu/sdk/core/libuniai.so differ diff --git a/uis7885/hardware/npu/sdk/core/unisoc_NPU_backend.so b/uis7885/hardware/npu/sdk/core/unisoc_NPU_backend.so new file mode 100644 index 0000000000000000000000000000000000000000..0222767bf751222fb1c833f12727160ee96101a7 Binary files /dev/null and b/uis7885/hardware/npu/sdk/core/unisoc_NPU_backend.so differ diff --git a/uis7885/hardware/npu/sdk/etc/npu_img_hwconfig.json b/uis7885/hardware/npu/sdk/etc/npu_img_hwconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..2989cd147c0f6f6029e698edc0ac0b8fdaeeccb3 --- /dev/null +++ b/uis7885/hardware/npu/sdk/etc/npu_img_hwconfig.json @@ -0,0 +1,22 @@ +{ + "arch_name" : "AURA", + "bvnc" : + [ + 28, + 3, + 7500, + 1502 + ], + "clock_frequency" : 988000000.0, + "conv_blocks" : 16, + "conv_data_unsign" : 1, + "ext_mem_bus_width" : 256, + "hw_params" : "ed9b80bcf2f4eeb9d0fcf9f2eaf6d28cf7e7ecc1e0e2f4adeab2b6ababaaa1f59fb3e8f0f7e4f4b6ebcff4f8ffc5ec9cf5e4fbffe7f3b9ffb5b0a7bd8193af9ee4f2e1c1fdf7f6baadb0acb1a9dbd8add7b3a5949ab4f9ade1e3b4b1b1ba87f6cd9b8097a5afa2e6bebc9c9882adbdcfa4a7a5949a9facefbfa2a6bd819384c8a6a0b9ab999fc6f38599b4f3fdf4eeddb6aba9949acd91d686a2aebd819384ccba9b8097a4a3abefa39a9f98baafbdcd9c98d4b2999fb9bdf6e4f3e2d4eae88dc9f2f0fdfff3b9ffb5b0a5a3a79084ddf5feecf8f5c9f9aae9f6f3e3d4f8ec91fde2abbea9b6aae9a39a9fb3e8f5e899f0ceebebf5f0feadd0f2efe5eee9afdfacb1b8ada2a6aceda39a9fb3e8f5e899f0ceeff1e1fbfaabadb0acb1b9b687f6b4f2e6f0e5c9f9b3e0f3fde2a9bab7dfa7a7a5949ab4f8b0e1e6c9f5eaeeeca0e3fffaf7f4f8b9ffb5b0a7bd8193af9cf9ffffc1e2aefa80fff5e4cee8f2ec91f8f4e5bcb3acbbeea39a9fb3e8f5e389c9e6e0fae7feb9ffb5b0a7a3b3b687f6b4f4fef1ccf4e9b0eef4f5f0f8eee491f1b3a9a4b3a7b7d586b2f3e9ffc5e09afbceebebe0c9ecb6ebe4feb3aba0adcda3a7a5949ab4f2b1ffe5e2cee9efeb99f3e3d6fcf2f8f080eef4f2e3eee9fe9ae5b3a9a4b3a4aee9a39a9fb3e2f4fd8ae2ceebebf5f0feadd0f2f7ffe0e9afdfacb1baacbf9c92fde6fee6e4ffc5ef8af0f7ececcce1f2bbfbf8b4b1b1babbcbba9b80bcfaf8ef80e2f5fbcee9effea0e1f8edeafbb4bbe5afa2a3a7a79084ddfbf0f1c1f0f9f5a9d0ffe3e5d4f4f892c9e1e5fffdf3e8fdafaab6a5bba3bbd39c98abf3f2eec4bce0fee0cefcf3e39bf9e6d6f6f6fffcb7fbb2b6ababa8b8c9ba9b80bcfef7e380ecfff8e7d4ede491f2fefec1e4ffffabe7b2b6ababa8b8c9ba9b80bcfef7e380e9f9fae5eee8d28cf3e5abbea9b6aaedb7bc9c98a9f7ec87c9f7e0f2e7f3e9acd0e7ffe5e3c5ef96f7e2abbea9b6aeeebdbc9c98a9f7e892c9f3fcece0e2c4bdf6e4f3e2a9bab7dfa7a3b1b2999fb9b2eafdf9e3f2c5e09ef8f8f9ebfff7efb6e0feb4b1b1babcd39c98abf3f6fbf4adf6cffbf0e5f3fd8afaf0fdf7fcf8c4bdfaf6f0f4f9c5ef9ef8fafabcb3acbbecbdbc9c98a9f7e892f9e3f0c1fef7f5b6ffe5faf0fff3e291c9f3fcf8f5f3e980fcf9ecf4a9bab7dfa5a3a5949ab4f6bae2ffe4e8d4f7ec91ffe1fcf2f2e2f2b0e1cfe6f0f9fbe193f3fde0edfec9f7efadb0acb1baaca1f59fb3e4fbfef9e9a6d0fdf7ffe2eaf893f7e5e0f1fdc9ebbefdf1fafdeef6e48cfbcee5afb1b6a1ffbbbc9c98a9f7e491c9e1e6f1ffb4bbe5afa1ba9b82b8e096e4e3e6eccce6fabbebf9f8f6a9bab7dfa7bd8397b1fbf6aad0e6f3e3a9bab7dfa5bd8397b1f8f4ade2cfe3ffe2eefeddb6aba9afbf9c92fde1e5fbcef9ffec9bc9f8edbcb3acbbe9bbbc9c98a9f4f892c9e6fbf7e7f3c4b6ebb2b6ababacb9d39c98abf1faf8c4ace6fef1fdeec5fd93f7ffecc1f4e4fab1fafcf7e3e2eef4ddb6aba9aabf9c92fdfffff9fdd4efe396e2e2abbea9b6aae9a39a9fb3f8f8f899c9f5e8eaf2c9eeb1fcf9f1ffa9bab7dfa7bd8397b1e5f3befdf5f2cee9efeb99f3e3d6fcf2f8f080eef4f2e3eee9fe9ae5b3a9a4b3a4aee9a39a9fb3f8f2ec8df3f5d6fce6f0fdbafdcff4f0e5f1feddb6aba9a6bf9c92fdfcf8f7e3eefed29de3f7effbe1c9ecb6ebe4feb3aba0adcda3a783e3", + "int_mem_bus_width" : 256, + "max_conv_window_height" : 256, + "max_conv_window_width" : 256, + "mem_efficiency" : 0.358, + "onchip_mem_page_size" : 0, + "onchip_mem_size" : 0, + "sbuf_data_unsign" : 1 +} diff --git a/uis7885/hardware/npu/sdk/etc/npu_img_mapconfig.json b/uis7885/hardware/npu/sdk/etc/npu_img_mapconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..6c46328896f69689115738a9f491a36d4535e06e --- /dev/null +++ b/uis7885/hardware/npu/sdk/etc/npu_img_mapconfig.json @@ -0,0 +1,31 @@ +{ + "input": { + "bits":8, + "interleaving":1 + }, + "output":{ + "bits":8 + }, + "fast_optim":100, + "mapping_features":["force_dsc","disable_use_sw_ewo"], + "layer_types": [ + { + "weights": { + "bits": 8 + }, + "bias": { + "bits": 8 + }, + "type": "CONV" + }, + { + "weights": { + "bits": 8 + }, + "bias": { + "bits": 8 + }, + "type": "INNERPRODUCT" + } + ] +} diff --git a/uis7885/hardware/npu/sdk/include/IUniAI.hpp b/uis7885/hardware/npu/sdk/include/IUniAI.hpp new file mode 100644 index 0000000000000000000000000000000000000000..56bae6bf2a5f3a501a542988ea931e659975964d --- /dev/null +++ b/uis7885/hardware/npu/sdk/include/IUniAI.hpp @@ -0,0 +1,409 @@ +/** + * @file UniAIClient.hpp + * @brief UniAI interface declaration file + * @date 2024-01-03 + * @copyright Copyright (c) 2024 UNISOC Technologies Co.,Ltd. All Rights + * Reserved + */ + +#pragma once + +#include +#include +#include +#include +namespace unisoc { + +/** + * @brief Supported Frontend ML FW, Use to load different network + */ +enum class FrontendId { + TFlite = 0, ///< TFlite Framework + Onnx = 1, ///< Onnx Framework + TF = 2, +}; + +/** + * @brief backend device state + */ +enum class BackendState { + DEVICE_AVAILABLE = 0, + DEVICE_UNAVAILABLE = 1, + DEVICE_BUSY = 2, + DEVICE_INVALID = 3 +}; + +/** + * @brief Supported model type for inference + */ + +enum class ModelType { + UniAI_IR = 0, + UniAI_NativeModel = 1, ///< Currently only IR & NativeModel model is supported, +}; + +/** + * @brief TensorShape + * \li m_Dims : Dim data of each Dims + * \li m_NumDims : Dim num + */ +struct TensorShape { + std::array m_Dims; + unsigned int m_NumDims; +}; + +/** + * @brief The priority of Inference + */ +enum class Priority { + UNDEFINED = 0, ///< reserved, not use now + LOW = 1, ///< Inference with low priority + MEDIUM = 2, ///< Inference with medium priority + HIGH = 3 ///< Inference with high priority +}; + +/** + * @brief Supported backends for inference + */ + +enum class UniAIBackends { + CPU = 0, ///< CPU backend + NPU = 1, ///< NPU backend + GPU = 2, ///< GPU backend + XTENSA = 3 ///< VDSP backend +}; + +/** + * @brief Model file data type + */ +enum class DataType { + Float16 = 0, + Float32 = 1, + QuantisedAsymm8 = 2, + QuantisedSymm8 = 3, + QSymmS16 = 4, + Signed32 = 5, + Signed64 = 6, +}; + +/** + * @brief data layout of the picture + */ +enum class DataLayout { + UNDEFINED = 0, ///< reserved, not use now + NCHW = 1, ///< [batch, in_channels, in_height, in_weight] + NHWC = 2 ///< [batch, in_height, in_weight, in_channels] +}; + +/** + * @brief Input / Output info of the network + */ +struct IoInfo{ + TensorShape m_Shape; + DataLayout m_Layout; + DataType m_DataType; + std::vector m_Scales; + int32_t m_Offset; +}; + +/** + * @brief Status + */ +enum class Status { + AI_FAILURE, ///< some errors occur, can see log details, see log details + AI_SUCCESS, ///< all operations work successfully + AI_UNKNOWN_FRONTEND_ID, ///< the given frontend id is invalid + AI_UNKNOWN_BACKEND_ID, ///< the given backend id is invalid + AI_OPTIMIZE_ERROR, ///< occur optimize error when NetworkCompile + AI_SMALL_INPUT_SIZE, ///< the given input buffer is too small + AI_SMALL_OUTPUT_SIZE, ///< the given output buffer is too small + AI_FILE_NOT_FOUND, ///< the given file path is not found + AI_INVALID_NETWORK_ID, ///< the given network id is invalid + AI_INVALID_ARGUMENT, ///< the given argument is invalid, see log details + AI_INVALID_QUANTIZE_DATA_TYPE, ///< the given quantize dtaa type id is invalid + AI_INVALID_DATA_TYPE, ///< the given data type id is invalid + AI_PARSE_ERROR, ///< parse error occur, should check input/output nodename +}; + +/** + * @brief UniAI Tensor for inference + */ +class UniAITensor +{ + public: + /** + * @brief Create UniAITensor + * + * @param inputShape Dimensions of tensor + * @param dataLayout Arrangement of tensor data @see { DataLayout } + * @param dataType Data type of tensor data @see { DataType } + * @param data The address of tensor data + */ + UniAITensor(TensorShape inputShape, DataLayout dataLayout, + DataType dataType, void *data = nullptr); + + /** + * @brief Get the data layout of the current UniAITensor + * + * @return UniAITensor data layout + */ + DataLayout GetLayout() const; + + /** + * @brief Get the data type of the current UniAITensor + * + * @return UniAITensor data type + */ + DataType GetDataType() const; + + /** + * @brief Get the shape of the current UniAITensor + * + * @return std::vector the shape of UniAITensor + */ + TensorShape GetShape() const; + + /** + * @brief Get a pointer to UniAITensor data of the specified type + * + * @return a pointer to data of the specified type + */ + template + T* buffer() const { + T* data = reinterpret_cast(m_Data); + return data; + } + + private: + /** + * @brief UniAITensor data layout + */ + DataLayout m_DataLayout; + + /** + * @brief UniAITensor data type + */ + DataType m_DataType; + + /** + * @brief UniAITensor shape + */ + TensorShape m_Shape; + + /** + * @brief UniAITensor data pointer + */ + void *m_Data; +}; + +/** + * @brief IUniAI class (Pre-declaration for IUniAIPtr) + */ +class IUniAI; + +/** + * @brief using IUniAIPtr as std::unique_ptr + */ +using IUniAIPtr = + std::unique_ptr; + +/** + * @brief using NetworkId as int to record the current network id, it is relate + * to the model file + */ +using NetworkId = int; + +/** + * @brief backend device id, "CPU; NPU" + */ +using BackendId = unisoc::UniAIBackends; + + +/** + * @brief Compilation Parameter struct of NetworkCompile() + */ +struct CompilationParameter +{ + CompilationParameter() + : networkid() + , modelType() + , preferentBackendList({UniAIBackends::CPU}) + , saveCache(false) + , cachePath(nullptr) + , udoLibPath(nullptr) + { + } + NetworkId networkid; + ModelType modelType; + std::vector preferentBackendList; + bool saveCache; + const char *cachePath; + const char *udoLibPath; +}; + +/** + * @brief UniAI class, contains all the public interfaces of UniAI + */ +class IUniAI { +public: + + static IUniAIPtr Create(bool isProfiling = false); + + /** + * @brief Create UniAI init dynamic backend path + * + * @param dynamicBackendPath dynamic backends path + * @return IUniAIPtr the pointer to IUniAI @see { + * IUniAIPtr } + */ + static IUniAIPtr Create(const char *dynamicBackendPath, bool isProfiling = false); + + /** + * @brief Destory UniAI env + * + * @param UniAI the pointer to IUniAI @see { IUniAI } + */ + static void Destroy(IUniAI *UniAI); + + /** + * @brief Destory network + * + * @param networkid : network id, it is relate to the model file @see { + * NetworkId } + */ + virtual void DestroyNetwork(NetworkId networkid) = 0; + + /** + * @brief Get backend id list supported by UniAI + * + * @return std::vector the backend id list supported by UniAI + */ + virtual std::vector GetSupportBackendId() = 0; + + /** + * @brief Get the backend state selected by the user + * + * @param id : backend id supported by UniAI @see { BackendId } + * @return BackendState : backend state @see { BackendState } + */ + virtual BackendState GetBackendState(const BackendId id) = 0; + + /** + * @brief Get Data Type supported by UniAI + * + * @return data type list supported by UniAI + */ + virtual std::vector GetSupportedDataType() = 0; + + /** + * @brief LoadNetwork from binary file + * + * @param modelPath The storage path of the model file + * @param networkid network id, it is relate to the model file + * @see { NetworkId } + * @param modelType modelType, type of the modle + * @see { ModelType } + * @return Status Success will return 1, Failure will return 0 + * @see { Status } + */ + virtual Status LoadNetwork(const char* modelPath, NetworkId &networkid, ModelType& modelType) = 0; + + /** + * @brief compile network + * + * @param networkid network id, it is relate to the model file + * @see { NetworkId } + * @param modelType modelType, type of the modle + * @see { ModelType } + * @param preferentBackendList Compile network with the backend list + * @return Status Success will return 1, Failure will return 0 + * @see { Status } + */ + virtual Status NetworkCompile(NetworkId& networkid, ModelType modelType, + const std::vector &preferentBackendList, bool saveCache = false, const char* cachePath = nullptr) = 0; + + /** + * @brief get network input names + * + * @param networkid network id + * @see { NetworkId } + * @return vector of Network input names + */ + virtual std::vector + GetNetworkInputNames(const NetworkId networkid) = 0; + + /** + * @brief get network output names + * + * @param networkid network id + * @see { NetworkId } + * @return vector of Network output names + */ + virtual std::vector + GetNetworkOutputNames(const NetworkId networkid) = 0; + + /** + * @brief Run Model file + * + * @param networkid network id, it is relate to the model file @see { + * NetworkId } + * @param inputData Input data @see { UniAITensor } + * @param outputData The result of Inference @see { UniAITensor } + * @param priority The priority of Inference @see { priority } + * @return Status Success will return 1, Failure will return 0 @see + * { Status } + */ + virtual Status Inference(const NetworkId networkid, + std::vector &inputTensors, + std::vector &outputTensors) = 0; + + /** + * @brief Get AISDK VERSION + * + * @return AISDK VERSION string + */ + virtual std::string GetUniAISdkVersion() = 0; + + /** + * @brief record avaliable network ids + */ + std::vector m_NetworkIds; + + /** + * @brief Get Inputs info + * + * @return std::vector the inputs info list + */ + virtual std::vector GetInputAttributeInfo(NetworkId id) = 0; + + /** + * @brief Get Outputs info + * + * @return std::vector the outputs info list + */ + virtual std::vector GetOutputAttributeInfo(NetworkId id) = 0; + + /** + * @brief compile network + * + * @param CompilationParameter Compilation Parameter struct to avoid too much input Parameter. + */ + virtual Status NetworkCompile(CompilationParameter& compilationParameter) = 0; + + /** + * @brief LoadNetwork from memory buffer + * + * @param modelBuffer The memory buffer of the model file + * @param bufferSize The size of model memory buffer + * @param networkid network id, it is relate to the model file + * @see { NetworkId } + * @param modelType modelType, type of the modle + * @see { ModelType } + * @return Status Success will return 1, Failure will return 0 + * @see { Status } + */ + virtual Status LoadNetwork(const void* modelBuffer, const size_t bufferSize, NetworkId &networkid, ModelType& modelType) = 0; +}; + +} // namespace unisoc diff --git a/uis7885/hardware/npu/sdk/lib64/libc++_shared.so b/uis7885/hardware/npu/sdk/lib64/libc++_shared.so new file mode 100644 index 0000000000000000000000000000000000000000..ad8c26f4a278155b69d962b501bdb723cd9fa669 Binary files /dev/null and b/uis7885/hardware/npu/sdk/lib64/libc++_shared.so differ diff --git a/uis7885/hardware/npu/sdk/lib64/libimgcustom.so b/uis7885/hardware/npu/sdk/lib64/libimgcustom.so new file mode 100644 index 0000000000000000000000000000000000000000..0784210669e24624f29aa9e090ff78fe43864897 Binary files /dev/null and b/uis7885/hardware/npu/sdk/lib64/libimgcustom.so differ diff --git a/uis7885/hardware/npu/sdk/lib64/libimgdnn.so b/uis7885/hardware/npu/sdk/lib64/libimgdnn.so new file mode 100644 index 0000000000000000000000000000000000000000..c7d03032b7e473c781fcb6824e013d9d516d00b1 Binary files /dev/null and b/uis7885/hardware/npu/sdk/lib64/libimgdnn.so differ diff --git a/uis7885/hardware/npu/sdk/lib64/libnnacompiler.so b/uis7885/hardware/npu/sdk/lib64/libnnacompiler.so new file mode 100644 index 0000000000000000000000000000000000000000..6c70d2c0ab112c7325f342ed0bcfe00939a638a9 Binary files /dev/null and b/uis7885/hardware/npu/sdk/lib64/libnnacompiler.so differ diff --git a/uis7885/hardware/npu/sdk/lib64/libnnaruntime.so b/uis7885/hardware/npu/sdk/lib64/libnnaruntime.so new file mode 100644 index 0000000000000000000000000000000000000000..5edd4bc1d60751d945264da2f4f7983103a114fb Binary files /dev/null and b/uis7885/hardware/npu/sdk/lib64/libnnaruntime.so differ diff --git a/uis7885/hardware/npu/sdk/tools/uniai_testbench b/uis7885/hardware/npu/sdk/tools/uniai_testbench new file mode 100644 index 0000000000000000000000000000000000000000..7b72ef163adbdc9364b6d678c3a48d0128b17879 Binary files /dev/null and b/uis7885/hardware/npu/sdk/tools/uniai_testbench differ