自定义 Opcode

在 FPGA 中通过扩展指令集来加速计算过程,即将某些函数以CPU指令的方式来执行。然后通过将他们用 C 语言进行封装,从而成为标准C库中的一部分。

这里通过简单的添加 opcode 的方式来说明自定义 opcode 中对 gcc 的扩展过程。

环境准备

  • 设置环境变量
#!/bin/bash

# [1]
# prepare-env: export required environment variables, create folders.
# 在环境变量中设置 RISCV 主工程目录
export RISCV_HOME=~/riscv-home
export RISCV="${RISCV_HOME}/riscv"
export PATH="${PATH}:${RISCV}/bin"
export RISCV_PK="${RISCV}/riscv32-unknown-elf/bin/pk"

# 创建这些目录
mkdir -p "${RISCV_HOME}" "${RISCV}"

echo '[OK] done'
  • 构建 RISCV 工具链
#!/bin/bash

# [2]
# download-repos: clone all repositories to $RISCV_HOME.

if [ -z "${RISCV_HOME}" ]; then
    echo '$RISCV_HOME is undefined; run `source prepare-env`'
    exit 1
fi

dst="${RISCV_HOME}"
echo "destination folder is ${dst}"

# 基础同步代码函数
function riscv-clone {
    repo="${1}"
    revision="${2}"
    shift 2
    git clone -b master $@ "https://github.com/riscv/${repo}" "${dst}/${repo}" &&
        cd "${dst}/${repo}" &&
        git checkout "${revision}" &&
        echo "[OK] ${repo} cloning finished"
}

# 分别同步 riscv-fesvr, riscv-pk, riscv-isa-sim, riscv-opcodes, riscv-tests, riscv-gnu-toolchain 等包
riscv-clone 'riscv-fesvr' '01932a715edd22ee451d86cde38c7c07dc9bfa7e' &&
    riscv-clone 'riscv-pk' '66701f82f88d08d3700d8b0bc5d5306abfd0044f' &&
    riscv-clone 'riscv-isa-sim' '3a4e89322a8c8dac94185812a238f13789ab392f' &&
    riscv-clone 'riscv-opcodes' 'e0abc2255a71afb0236032ae3d92bea26c15716d' && 
    riscv-clone 'riscv-tests' '9e313f30205b8172290831c3af18b0779e9b15f2' &&
    riscv-clone 'riscv-gnu-toolchain' 'f5fae1c27b2365da773816ddcd92f533867f28ec' --recursive && 
    echo '[OK] done'
  • 初始化编译
#!/bin/bash

# [3]
# build-repos: build downloaded repositories.

# 安装依赖包
# Get packages that are required to build the GNU toolchain.
# The list provided by https://github.com/riscv/riscv-gnu-toolchain README.
sudo apt-get install \
    autoconf \
    automake \
    autotools-dev \
    curl \
    libmpc-dev \
    libmpfr-dev \
    libgmp-dev \
    gawk \
    build-essential \
    bison \
    flex \
    texinfo \
    gperf \
    libtool \
    patchutils \
    bc \
    zlib1g-dev \
    device-tree-compiler || exit 1

# 编译工具链
function mk-toolchain {
    cd "${RISCV_HOME}/riscv-gnu-toolchain" &&
        ./configure --prefix="${RISCV}" --with-arch=rv32i &&
        echo 'this can take more than a hour...' &&
        make &&
        echo '[OK] mk-toolchain: done'
}

# 编译 front-end server
function mk-fesvr {
    cd "${RISCV_HOME}/riscv-fesvr" &&
        mkdir -p build &&
        cd build &&
        ../configure --prefix="${RISCV}" &&
        make install &&
        echo '[OK] mk-fesvr: done'
}

# 编译代理 kernel, 及 bootloader
function mk-pk {
    # See issue https://github.com/riscv/riscv-pk/issues/56.
    # Remove '-m32' occurences from Makefile 
    # to fix "error: unrecognized command line option '-m32'".
    cd "${RISCV_HOME}/riscv-pk" &&
        mkdir -p build &&
        cd build &&
        ../configure --prefix="${RISCV}" --host=riscv32-unknown-elf --enable-32bit &&
        sed -i 's/\-m32//g' Makefile &&
        make &&
        make install &&
        echo '[OK] mk-pk: done'
}

# 编译 spike 模拟器
function mk-spike {
    cd "${RISCV_HOME}/riscv-isa-sim" &&
        mkdir -p build &&
        cd build &&
        ../configure --prefix="${RISCV}" --with-fesvr="${RISCV}" &&
        make &&
        sudo make install &&
        echo '[OK] mk-spike: done'
}

# The order matters.
mk-toolchain &&
    mk-fesvr &&
    mk-pk &&
    mk-spike &&
    echo '[OK] done'
  • 测试
#!/bin/bash

# [4]
# check-install: try to find out it installation was successful.

cc='riscv32-unknown-elf-gcc'
cxx='riscv32-unknown-elf-g++'

# 测试 command 命令
function check-cmd {
    name="${1}"
    command -v "${name}" >/dev/null 2>&1 ||
        (echo "${name}: command not found" && exit 1)
    echo "[OK] located ${name}"
}

# 通过spike 模拟器测试执行环境
function check-spike {
    mkdir -p build &&
        ${cc} data/hello.c -O1 -march=rv32im -o build/cc_hello &&
        echo '[OK] C compiler works' &&
        ${cxx} data/hello.cpp -O1 -march=rv32im -o build/cxx_hello &&
        echo '[OK] C++ compiler works' &&
        spike --isa=RV32IM "${RISCV_PK}" build/cc_hello &&
        spike --isa=RV32IM "${RISCV_PK}" build/cxx_hello &&
        echo '[OK] spike works'
}

check-cmd "${cc}" &&
    check-cmd "${cxx}" &&
    check-cmd 'spike' &&
    check-spike &&
    echo '[OK] done'

添加 Opcode

定义新指令

mac(a, b, c)  =>  c := c + (a * b)
  • 创建 riscv/insns/mac.h 文件
    用来描述 mac 指令的功能
// 'M' extension means we require integer mul/div standard extension.
require_extension('M');
// RD = RD + RS1 * RS2
reg_t tmp = sext_xlen(RS1 * RS2);
WRITE_RD(sext_xlen(READ_REG(insn.rd()) + tmp));
  • 添加Opcode
cd "${RISCV_HOME}/riscv-opcodes"
echo -e "mac rd rs1 rs2 31..25=1 14..12=0 6..2=0x1A 1..0=3\n" >> opcodes
make install

# 将 mac 指令追加到 riscv_insn_list 中去
sed -i 's/riscv_insn_list = \\/riscv_insn_list = mac\\/g' \
    "${RISCV_HOME}/riscv-isa-sim/riscv/riscv.mk.in"
  • 重新编译spike模拟器
cd "${RISCV}/riscv-isa-sim/build"
sudo make install
  • 测试程序编写
#include <stdio.h>
// Needed to verify results.
int mac_c(int a, int b, int c) {
    a += b * c; // Semantically, it is "mac"
    return a;
}

// Should not be inlined, because we expect arguments
// in particular registers.
__attribute__((noinline))
int mac_asm(int a, int b, int c) {
    // 0x02C5856B 为 mac 的 16进制 执行编码
    asm __volatile__ (".word 0x02C5856B\n");
    return a;
}
int main(int argc, char** argv) {
    int a = 2, b = 3, c = 4;
    printf("%d =?= %d\n", mac_c(a, b, c), mac_asm(a, b, c));
}
  • 编译执行
riscv32-unknown-elf-gcc test_mac.c -O1 -march=rv32im -o test_mac
spike --isa=RV32IM "${RISCV_PK}" test_mac

输出: 14 =?= 14

执行格式说明

  • mac & mul
# file "riscv-opcodes/opcodes"
#                                differs
#                                |
#                                v
mac rd rs1 rs2 31..25=1 14..12=0 6..2=0x1A 1..0=3
mul rd rs1 rs2 31..25=1 14..12=0 6..2=0x0C 1..0=3
#   ^  ^   ^   ^        ^        ^         ^
#   |  |   |   |        |        |         |
#   |  |   |   |        |        |         |
#   |  |   |   |        |        |         also opcode 3 bits
#   |  |   |   |        |        opcode 5 bits
#   |  |   |   |        funct3 3 bits
#   |  |   |   funct7 7 bits
#   |  |   rs2 (src2) 5 bits
#   |  rs1 (src1) 5 bits
#   dest 5 bits
  • 实际执行
# Encoding used for "mac a0, a1, a2"
0x02C5856B [base 16]
== 
10110001011000010101101011 [base 2]
== 对齐后
00000010110001011000010101101011 [base 2]
# Group by related bit chunks:
0000001 01100 01011 000 01010 1101011
^       ^     ^     ^   ^     ^
|       |     |     |   |     |
|       |     |     |   |     opcode (6..2=0x0C 1..0=3)
|       |     |     |   dest (10 : a0)
|       |     |     funct3 (14..12=0)
|       |     src1 (11 : a1)
|       src2 (12 : a2)
funct7 (31..25=1)

参考

RISC-V: custom instruction and its simulation
gnu-riscv32_ext
Adding the custom instruction to spike ISA simulator

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341

推荐阅读更多精彩内容