跳转至

RISC-V

编译工具链

  • 工具链仓库

    # 仓库地址
    https://github.com/riscv-collab/riscv-gnu-toolchain
    
    git clone https://github.com/riscv-collab/riscv-gnu-toolchain.git
    

  • 显式添加默认的平台支持并附加特定的平台

    ./configure --prefix=/opt/riscv \
      --enable-multilib \
      --with-multilib-generator="rv64gc-lp64d--;rv64imac-lp64--;rv32gc-ilp32d--;rv32imac-ilp32--;rv32ima-ilp32--"
    

  • 验证支持的多库组合

    riscv64-unknown-elf-gcc --print-multi-lib
    

RISC-V主要内容

  1. ISA命名规范

    RV[###][abc...xyz]
    

    • RV用于标识RISC-V 。
    • [###]: {32, 64, 128} 用于标识处理器的字宽(寄存器的宽度)。
    • [abc...xyz]: 标识该处理器支持的指令集模块集合。
  2. 模块化的ISA

    • RISC-V ISA = 1个基本整数指令集 + 多个可选的扩展指令集。
  3. 通用寄存器

    • 定义了32个通用寄存器以及一个PC。
    • 寄存器宽度由ISA指定。
    • 每个寄存器具体编程时有特定的用途以及各自的别名。由RISC-V ABI定义。
  4. Hart

    • HARdware Thread(相当于一个基本的CPU单元)
  5. 特权级别

    • 机器模式(M Machine Mode):最高权限,用于启动、配置硬件和异常处理。
    • 监督模式(S Supervisor Mode):运行操作系统内核。
    • 用户模式(U User/Application Mode):运行应用程序,权限受限。 (可选H Mode:支持虚拟化扩展的超监模式。)
  6. Control and Status Registers(CSR)

    • 不同的特权级别下时分别对应各自的一套Register。
    • 高级别的特权级别下可以访问低级别的CSR。
    • RISC-V 定义了专门用于操作CSR的指令。
    • RISC-V 定义了特定的指令可以用于在不同特权级别之间进行切换。
  7. 内存管理和保护(物理内存保护、虚拟内存)

    • 物理内存保护(Physical Memory Protection, PMP)
    • 虚拟内存 RISC-V 的虚拟内存(Virtual Memory)既依赖硬件支持,也依赖软件实现。其 ISA(指令集架构)提供了明确的硬件机制,包括特权模式、控制状态寄存器(CSR)和地址转换机制,而操作系统(如 Linux)则负责页表管理、缺页处理等软件层面的实现。
  8. 异常和中断

    risc-v的大多数异常会中断返回后会再执行一次异常指令。而中断后本身返回后会执行下一条语句。

    • 软件中断(本地中断)
    • 时钟中断(本地中断)
    • 外设中断(全局中断)
    • 涉及中断的CSR(mtvec, mepc,mcause, mtval, mstatus, mscratch, mie, mip, mtime, mtimecmp

主机字节序

  • 二进制码: 左高右底
  • 内存布局: 上高下底
  • 大端序: 高位二进制码存入底地址
  • 小端序: 高位二进制码存入高地址
  • risc-v使用小端序
  • 注意:字节序是否反转以字节为单位,一个字节8位,8位内部不反转

risc-v 的6种指令格式

  • R-Type: 用于寄存器间的算术逻辑运算(如 add x1, x2, x3)。
  • I-Type: 用于立即数操作、加载指令和跳转(如 addi x1, x2, 5lw x1, 4(x2))。
  • S-Type: 专用于存储指令到内存(如 sw x1, 8(x2))。
  • B-Type: 用于条件分支跳转(如 beq x1, x2, label)。
  • U-Type: 用于将长立即数装入寄存器高位(如 lui x1, 0x12345)。
  • J-Type: 用于无条件长跳转(如 jal x1, far_away_label)。

汇编相关命令

  1. 编写汇编 nvim test.s
  2. 编译 [rgcc] -march=[rv32im] -mabi=ilp32 -c test.s -o test.o
  3. 链接 [rld] -m elf32lriscv -o test.elf test.o
  4. 查看段头信息 [rreadelf] -S test.elf
  5. 查看 .text 段原始内容 [rreadelf] -x .text test.elf
  6. 反汇编所有段 [robjdump] -D test.elf
  7. 反汇编代码段 [robjdump] -d test.elf
  8. 展开所有伪指令 [robjdump] -d -M no-aliases test.elf

模拟器运行与调试

  1. 模拟器运行程序。启动时暂停CPU等待GDB连接,默认1234端口。
    • qemu-system-riscv32 -nographic -smp 1 -machine virt -bios none -kernel kernel -S -s
    • -S 启动时暂停CPU,等待GDB的 continue 命令才开始执行
    • -s 是 -gdb tcp:127.0.0.1:1234 的缩写
  2. 运行gdb [rgdb] test.elf
  3. gdb连接远程1234端口 target remote : 1234
  4. monitor quit 让QEMU立即停止运行
  5. gdb运行参数 -q 安静模式,不显示介绍信息, -x <file> 执行指定文件中的 GDB 命令

  6. gdbinit

    # /z 十六进制显示寄存器中的值
    # 每一步都显示
    display/z $x5
    display/z $x6
    display/z $x7
    
    # 自动反汇编,每一步都反汇编
    set disassemble-next-line on
    b _start
    target remote : 1234
    c