HIFI 4 简介如下

Cadence® Tensilica® HiFi 4 DSP是一款32位固定点和浮点处理器,专为智能音箱、家庭娱乐和汽车信息娱乐等要求高的DSP应用而设计。它为复杂的多麦克风远场处理、使用神经网络技术的唤醒词检测提供了改进的性能,并支持最新的基于对象的编解码器,适用于机顶盒,音响和电视产品。

主要优势:

  1. 复杂的面向对象编解码器:有效执行复杂的音频编解码器,适用于电视、机顶盒和音响。
  2. 高性能的DSP:在FFT和FIR等计算密集型函数方面,HiFi 4 DSP的性能比HiFi 3z DSP提高了一倍,支持ANC、降噪和声音分析等占用性能的算法。
  3. 基于神经网络的语音助手:结合高性能的DSP和增强的NN性能,可靠地用于电视、机顶盒、音箱和智能音箱的远场语音助手功能。
  4. ISO 26262:具有硬件和软件安全机制,符合ASIL标准。

主要特点:

  • 在特定条件下支持每个周期8个32x16位MAC。
  • 四个VLIW槽体结构,每个周期可发出两个64位加载。
  • 可选向量浮点单元,提供每个周期最多四个单精度IEEE浮点MAC。
  • 软件兼容完整的HiFi DSP产品线,提供超过300种HiFi优化的音频和语音编解码器和音频增强软件包。
  • HiFi NN库提供了经过优化的常用NN处理函数集,可轻松集成到流行的机器学习框架中。

img

在 D1-H T113 A523 系列芯片中可以发现 HIFI4 的踪影

image-20240222205218154

HIFI 4 启动流程

先看时钟初始化流程

void sunxi_hifi4_clock_init(uint32_t addr) {
    uint32_t reg_val = 0;

    // 设置SRAM映射
    sram_remap_set(1);

    // 配置DSP时钟源为PERI2X,时钟倍频因子为2,并打开DSP时钟门控
    reg_val |= CCU_DSP_CLK_SRC_PERI2X;
    reg_val |= CCU_DSP_CLK_FACTOR_M(2);
    reg_val |= (1 << CCU_BIT_DSP_SCLK_GATING);
    writel(reg_val, CCU_BASE + CCU_DSP_CLK_REG);

    // 进行时钟门控设置,使得DSP0配置部分的时钟门控位为1
    reg_val = readl(CCU_BASE + CCU_DSP_BGR_REG);
    reg_val |= (1 << CCU_BIT_DSP0_CFG_GATING);
    writel(reg_val, CCU_BASE + CCU_DSP_BGR_REG);

    // 进行复位操作,首先对DSP0进行配置复位,然后对DSP0进行调试复位
    reg_val = readl(CCU_BASE + CCU_DSP_BGR_REG);
    reg_val |= (1 << CCU_BIT_DSP0_CFG_RST);
    reg_val |= (1 << CCU_BIT_DSP0_DBG_RST);
    writel(reg_val, CCU_BASE + CCU_DSP_BGR_REG);

    // 如果需要设置外部复位向量,则将外部复位向量写入指定寄存器,并设置启动向量选择,设置code地址
    if (addr != DSP_DEFAULT_RST_VEC) {
        writel(addr, DSP0_CFG_BASE + DSP_ALT_RESET_VEC_REG);

        reg_val = readl(DSP0_CFG_BASE + DSP_CTRL_REG0);
        reg_val |= (1 << BIT_START_VEC_SEL);
        writel(reg_val, DSP0_CFG_BASE + DSP_CTRL_REG0);
    }

    // 设置运行暂停标志
    sunxi_hifi4_set_run_stall(1);

    // 打开DSP时钟使能
    reg_val = readl(DSP0_CFG_BASE + DSP_CTRL_REG0);
    reg_val |= (1 << BIT_DSP_CLKEN);
    writel(reg_val, DSP0_CFG_BASE + DSP_CTRL_REG0);

    // 取消对DSP0的复位
    reg_val = readl(CCU_BASE + CCU_DSP_BGR_REG);
    reg_val |= (1 << CCU_BIT_DSP0_RST);
    writel(reg_val, CCU_BASE + CCU_DSP_BGR_REG);

    /* 复原 */
    sram_remap_set(0);
    sunxi_hifi4_set_run_stall(0);
}
  • 通过sram_remap_set(1)函数设置SRAM映射,确保存储器映射正确。

  • 配置DSP的时钟源为PERI2X,并将时钟倍频因子设置为2,同时打开DSP的时钟门控功能,以确保时钟信号正常传输到DSP。

  • 进行时钟门控设置,将DSP0的配置部分时钟门控位置为1,以确保配置部分的时钟信号可用。

  • 进行复位操作,首先对DSP0进行配置复位,然后对DSP0进行调试复位,以确保DSP在初始化过程中处于良好的初始状态。

  • 如果需要设置外部复位向量,将指定的地址写入相应的寄存器,同时设置启动向量选择。我们在这里设置 HIFI4 的程序启动地址。

  • 设置运行暂停标志,以确保DSP在初始化完成后进入正常的工作状态。

  • 打开DSP时钟使能,以确保DSP的时钟信号正常启动。

  • 取消对DSP0的复位,使得DSP可以开始正常的运行。

通过以上初始化流程的操作,可以确保DSP在初始化后可以正常工作,并准备好接收和处理相应的任务和指令。

编译 HIFI 4 固件

由于 HIFI 4 使用的是 Xtensa Xplorer 套件,这个套件需要购买。但是没钱,所以需要手搓一个,手搓方法参考之前写的 HIFI5 即可。

既然有了编译器,那就适配一个 FreeRTOS,链接:https://github.com/YuzukiHD/FreeRTOS-HIFI4-DSP

搭建环境

用下面的命令克隆代码并搭建环境

git clone https://github.com/YuzukiHD/FreeRTOS-HIFI4-DSP.git
cd FreeRTOS-HIFI4-DSP
wget https://github.com/YuzukiHD/FreeRTOS-HIFI4-DSP/releases/download/Toolchains/xtensa-hifi4-dsp.tar.gz
mkdir -p tools/xtensa-hifi4-gcc
mv xtensa-hifi4-dsp.tar.gz tools/xtensa-hifi4-gcc/
cd tools/xtensa-hifi4-gcc/
tar xvf xtensa-hifi4-dsp.tar.gz
cd -

image-20240222213136340

构建 FreeRTOS

构建固件非常简单,执行 make 即可,生成的固件在 ./build/dsp.elf

image-20240222213255206

使用 SyterKit 启动

SyterKit 是一个纯裸机框架,用于 TinyVision 或者其他 v851se/v851s/v851s3/v853 等芯片的开发板,SyterKit 使用 CMake 作为构建系统构建,支持多种应用与多种外设驱动。同时 SyterKit 也具有启动引导的功能,可以替代 U-Boot 实现快速启动

获取 SyterKit 源码

SyterKit 源码位于GitHub,可以前往下载。

git clone https://github.com/YuzukiHD/SyterKit.git

从零构建 SyterKit

构建 SyterKit 非常简单,只需要在 Linux 操作系统中安装配置环境即可编译。SyterKit 需要的软件包有:

  • gcc-arm-none-eabi
  • CMake

对于常用的 Ubuntu 系统,可以通过如下命令安装

sudo apt-get update
sudo apt-get install gcc-arm-none-eabi cmake build-essential -y

然后新建一个文件夹存放编译的输出文件,并且进入这个文件夹

mkdir build
cd build

然后运行命令编译 SyterKit

cmake ..
make

image-20231216174136154

编译后的可执行文件位于 build/app 中,这里包括 SyterKit 的多种APP可供使用。

image-20231216173846369

进入 load_hifi4

image-20240222214431758

按照需求选择,这里我们使用卡启动,所以使用 load_hifi4_bin_card.bin

image-20240222214515148

使用 genimage 打包固件

编写 genimage.cfg 作为打包的配置

image boot.vfat {
	vfat {
		files = {
			"dsp.elf"
		}
	}
	size = 8M
}

image sdcard.img {
	hdimage {}

	partition boot0 {
		in-partition-table = "no"
		image = "syter_boot_bin_card.bin"
		offset = 8K
	}

	partition boot0-gpt {
		in-partition-table = "no"
		image = "syter_boot_bin_card.bin"
		offset = 128K
	}

	partition kernel {
		partition-type = 0xC
		bootable = "true"
		image = "boot.vfat"
	}
}

由于genimage的脚本比较复杂,所以编写一个 genimage.sh 作为简易使用的工具

#!/usr/bin/env bash

die() {
  cat <<EOF >&2
Error: $@

Usage: ${0} -c GENIMAGE_CONFIG_FILE
EOF
  exit 1
}

# Parse arguments and put into argument list of the script
opts="$(getopt -n "${0##*/}" -o c: -- "$@")" || exit $?
eval set -- "$opts"

GENIMAGE_TMP="${BUILD_DIR}/genimage.tmp"

while true ; do
	case "$1" in
	-c)
	  GENIMAGE_CFG="${2}";
	  shift 2 ;;
	--) # Discard all non-option parameters
	  shift 1;
	  break ;;
	*)
	  die "unknown option '${1}'" ;;
	esac
done

[ -n "${GENIMAGE_CFG}" ] || die "Missing argument"

# Pass an empty rootpath. genimage makes a full copy of the given rootpath to
# ${GENIMAGE_TMP}/root so passing TARGET_DIR would be a waste of time and disk
# space. We don't rely on genimage to build the rootfs image, just to insert a
# pre-built one in the disk image.

trap 'rm -rf "${ROOTPATH_TMP}"' EXIT
ROOTPATH_TMP="$(mktemp -d)"
GENIMAGE_TMP="$(mktemp -d)"
rm -rf "${GENIMAGE_TMP}"

genimage \
	--rootpath "${ROOTPATH_TMP}"     \
	--tmppath "${GENIMAGE_TMP}"    \
	--inputpath "${BINARIES_DIR}"  \
	--outputpath "${BINARIES_DIR}" \
	--config "${GENIMAGE_CFG}"

准备完成,运行打包即可

./genimage.sh -c genimage.cfg

IMG_1366

性能对比

官方 XCC 编译器

2K performance run parameters for coremark.
CoreMark Size    : 666
Total ticks      : 26696
Total time (secs): 26
Iterations/Sec   : 1923.07692
Iterations       : 50000
Compiler version : GCC4.2.0 (Xtensa 14.04 release)
Compiler flags   : -Os
Memory location  : STACK
seedcrc          : 0xe9f5
[0]crclist       : 0xe714
[0]crcmatrix     : 0x1fd7
[0]crcstate      : 0x8e3a
[0]crcfinal      : 0xa14c
Correct operation validated. See README.md for run and reporting rules.
CoreMark 1.0 : 1923.07692 /  GCC4.2.0 (Xtensa 14.04 release) -Os / STACK

GCC

Dhrystone Benchmark, Version 2.1 (Language: C)

Program compiled without 'register' attribute

Execution starts, 10000000 runs through Dhrystone
Execution ends

Final values of the variables used in the benchmark:

Int_Glob:            5
        should be:   5
Bool_Glob:           1
        should be:   1
Ch_1_Glob:           A
        should be:   A
Ch_2_Glob:           B
        should be:   B
Arr_1_Glob[8]:       7
        should be:   7
Arr_2_Glob[8][7]:    10000010
        should be:   Number_Of_Runs + 10
Ptr_Glob->
  Ptr_Comp:          933177280
        should be:   (implementation-dependent)
  Discr:             0
        should be:   0
  Enum_Comp:         2
        should be:   2
  Int_Comp:          17
        should be:   17
  Str_Comp:          DHRYSTONE PROGRAM, SOME STRING
        should be:   DHRYSTONE PROGRAM, SOME STRING
Next_Ptr_Glob->
  Ptr_Comp:          933177280
        should be:   (implementation-dependent), same as above
  Discr:             0
        should be:   0
  Enum_Comp:         1
        should be:   1
  Int_Comp:          18
        should be:   18
  Str_Comp:          DHRYSTONE PROGRAM, SOME STRING
        should be:   DHRYSTONE PROGRAM, SOME STRING
Int_1_Loc:           5
        should be:   5
Int_2_Loc:           13
        should be:   13
Int_3_Loc:           7
        should be:   7
Enum_Loc:            1
        should be:   1
Str_1_Loc:           DHRYSTONE PROGRAM, 1'ST STRING
        should be:   DHRYSTONE PROGRAM, 1'ST STRING
Str_2_Loc:           DHRYSTONE PROGRAM, 2'ND STRING
        should be:   DHRYSTONE PROGRAM, 2'ND STRING

Microseconds for one run through Dhrystone:    0.8
Dhrystones per Second:                      1241310.8
DMIPS:                                      706.49

Rolled Double Precision Linpack Benchmark - PC Version in 'C/C++'

Compiler     xtensa hifi4 dsp xtensa-elf-gcc 10.2
Optimisation -O2

norm resid      resid           machep         x[0]-1          x[n-1]-1
   1.7    7.41628980e-14   2.22044605e-16  -1.49880108e-14  -1.89848137e-14

Times are reported for matrices of order          100
1 pass times for array with leading dimension of  201

      dgefa      dgesl      total     Mflops       unit      ratio
    0.07600    0.00200    0.07800       8.80     0.2272     1.3929

Calculating matgen overhead
       100 times   0.43 seconds
       200 times   0.85 seconds
       400 times   1.70 seconds
       800 times   3.41 seconds
      1600 times   6.81 seconds
Overhead for 1 matgen      0.00426 seconds

Calculating matgen/dgefa passes for 5 seconds
       100 times   8.05 seconds
Passes used         62

Times for array with leading dimension of 201

      dgefa      dgesl      total     Mflops       unit      ratio
    0.07621    0.00231    0.07852       8.75     0.2287     1.4021
    0.07621    0.00231    0.07852       8.75     0.2287     1.4021
    0.07621    0.00231    0.07852       8.75     0.2287     1.4021
    0.07621    0.00231    0.07852       8.75     0.2287     1.4021
    0.07621    0.00231    0.07852       8.75     0.2287     1.4021
Average                                 8.75

Calculating matgen2 overhead
Overhead for 1 matgen      0.00426 seconds

Times for array with leading dimension of 200

      dgefa      dgesl      total     Mflops       unit      ratio
    0.07626    0.00231    0.07857       8.74     0.2288     1.4030
    0.07626    0.00231    0.07857       8.74     0.2288     1.4030
    0.07626    0.00231    0.07857       8.74     0.2288     1.4030
    0.07626    0.00231    0.07857       8.74     0.2288     1.4030
    0.07626    0.00231    0.07857       8.74     0.2288     1.4030
Average                                 8.74

Rolled Double  Precision        8.74 Mflops

2K performance run parameters for coremark.
CoreMark Size    : 666
Total ticks      : 16427
Total time (secs): 16.427000
Iterations/Sec   : 1400.133926
Iterations       : 23000
Compiler version : GCC10.3.0
Compiler flags   : -O2
Memory location  : STACK
seedcrc          : 0xe9f5
[0]crclist       : 0xe714
[0]crcmatrix     : 0x1fd7
[0]crcstate      : 0x8e3a
[0]crcfinal      : 0xd340
Correct operation validated. See README.md for run and reporting rules.
CoreMark 1.0 : 1400.133926 / GCC10.3.0 -O2 / STACK