Opcodes 说明

简介: 在 rocket-chip 中对 opcodes 进行定制化的过程主要是在 riscv-tools/riscv-opcodes 目录中:.├── encoding.

在 rocket-chip 中对 opcodes 进行定制化的过程主要是在 riscv-tools/riscv-opcodes 目录中:

.
├── encoding.h                 --- 基础编码工具
├── LICENSE
├── Makefile                   --- 编译脚本
├── opcodes                    --- opcodes 定义,下同
├── opcodes-custom
├── opcodes-pseudo
├── opcodes-rvc
├── opcodes-rvc-pseudo
├── parse-opcodes              ---  opcodes 自动化生成工具
└── README.md                  ---  说明文档

接下来解读下 Makefile 文件中的内容:

SHELL := /bin/sh

# 定义目标 encoding.h 目标文件位置
ISASIM_H := ../riscv-isa-sim/riscv/encoding.h
PK_H := ../riscv-pk/machine/encoding.h
FESVR_H := ../riscv-fesvr/fesvr/encoding.h
ENV_H := ../riscv-tests/env/encoding.h
OPENOCD_H := ../riscv-openocd/src/target/riscv/encoding.h

ALL_OPCODES := opcodes-pseudo opcodes opcodes-rvc opcodes-rvc-pseudo opcodes-custom

install: $(ISASIM_H) $(PK_H) $(FESVR_H) $(ENV_H) $(OPENOCD_H) inst.chisel instr-table.tex priv-instr-table.tex

# 安装所有指令码到 c 语言库,并拷贝 encoding.h 文件到目标目录
$(ISASIM_H) $(PK_H) $(FESVR_H) $(ENV_H) $(OPENOCD_H): $(ALL_OPCODES) parse-opcodes encoding.h
    cp encoding.h $@
    cat opcodes opcodes-rvc-pseudo opcodes-rvc opcodes-custom | ./parse-opcodes -c >> $@

# 安装所有的指令码到 Chisel 代码中,通过 parse-opcodes 脚本生成 Instructions 类
inst.chisel: $(ALL_OPCODES) parse-opcodes
    cat opcodes opcodes-custom opcodes-pseudo | ./parse-opcodes -chisel > $@

# 安装所有的指令码到 Go 代码中,通过 parse-opcodes 脚本生成 
inst.go: opcodes opcodes-pseudo parse-opcodes
    cat opcodes opcodes-pseudo | ./parse-opcodes -go > $@

instr-table.tex: $(ALL_OPCODES) parse-opcodes
    cat opcodes opcodes-pseudo | ./parse-opcodes -tex > $@

priv-instr-table.tex: $(ALL_OPCODES) parse-opcodes
    cat opcodes opcodes-pseudo | ./parse-opcodes -privtex > $@

.PHONY : install

执行 make install 之后,在 riscv-fesvr/fesvr/encoding.h 文件中,存在机器码的定义过程,比如:

#ifdef DECLARE_INSN
DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ)
DECLARE_INSN(bne, MATCH_BNE, MASK_BNE)
DECLARE_INSN(blt, MATCH_BLT, MASK_BLT)
DECLARE_INSN(bge, MATCH_BGE, MASK_BGE)
DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU)
DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU)
DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR)
DECLARE_INSN(jal, MATCH_JAL, MASK_JAL)
DECLARE_INSN(lui, MATCH_LUI, MASK_LUI)
DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC)
DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI)
DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI)
DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI)
...省略...
#endif

解析过程

简单分析下 parse-opcodes 文件中生成 encoding.h 文件部分的实现:

...此前省略...
def make_c(match,mask):
  print '/* Automatically generated by parse-opcodes.  */'
  print '#ifndef RISCV_ENCODING_H'
  print '#define RISCV_ENCODING_H'
// 递归指令名称列表,组装 MATCH_*, MASK_*, CSR_*, CAUSE_* 等宏定义
  for name in namelist:
    name2 = name.upper().replace('.','_')
    print '#define MATCH_%s %s' % (name2, hex(match[name]))
    print '#define MASK_%s  %s' % (name2, hex(mask[name]))
  for num, name in csrs+csrs32:
    print '#define CSR_%s %s' % (name.upper(), hex(num))
  for num, name in causes:
    print '#define CAUSE_%s %s' % (name.upper().replace(' ', '_'), hex(num))
  print '#endif'

// 定义 INSN 指令
  print '#ifdef DECLARE_INSN'
  for name in namelist:
    name2 = name.replace('.','_')
    print 'DECLARE_INSN(%s, MATCH_%s, MASK_%s)' % (name2, name2.upper(), name2.upper())
  print '#endif'

// 声明 CSR 
  print '#ifdef DECLARE_CSR'
  for num, name in csrs+csrs32:
    print 'DECLARE_CSR(%s, CSR_%s)' % (name, name.upper())
  print '#endif'

// 声明 CAUSE 
  print '#ifdef DECLARE_CAUSE'
  for num, name in causes:
    print 'DECLARE_CAUSE("%s", CAUSE_%s)' % (name, name.upper().replace(' ', '_'))
  print '#endif'
...此后省略...

Opcodes 定义文件

opcodes-rvc-pseudo 文件为例,其中包含了一些特定的指令:

# these aren't really pseudo-ops, but they overlay other encodings,
# so they are here to prevent parse-opcodes from barfing

@c.nop      1..0=1 15..13=0 12=0      11..7=0      6..2=0
@c.addi16sp 1..0=1 15..13=3 12=ignore 11..7=2      6..2=ignore
@c.jr       1..0=2 15..13=4 12=0      11..7=ignore 6..2=0
@c.jalr     1..0=2 15..13=4 12=1      11..7=ignore 6..2=0
@c.ebreak   1..0=2 15..13=4 12=1      11..7=0      6..2=0

# RV64C
@c.ld      1..0=0 15..13=3 12=ignore 11..2=ignore # c.flw for RV32
@c.sd      1..0=0 15..13=7 12=ignore 11..2=ignore # c.fsw for RV32
@c.addiw   1..0=1 15..13=1 12=ignore 11..2=ignore # c.jal for RV32
@c.ldsp    1..0=2 15..13=3 12=ignore 11..2=ignore # c.flwsp for RV32
@c.sdsp    1..0=2 15..13=7 12=ignore 11..2=ignore # c.fswsp for RV32
目录
相关文章
|
6月前
|
网络协议 Unix Linux
OpenOCD(五):调试适配器配置
OpenOCD(五):调试适配器配置
386 0
|
6月前
|
NoSQL 网络协议 Linux
OpenOCD(二):Jim-Tcl&运行&OpenOCD项目设置
OpenOCD(二):Jim-Tcl&运行&OpenOCD项目设置
181 1
|
移动开发 NoSQL 网络协议
掌握GDB调试工具,轻松排除bug(下)
掌握GDB调试工具,轻松排除bug
|
数据可视化 编译器 开发工具
RISC-V MCU开发 (一):MounRiver Studio集成开发环境
近年来,RISC-V生态获得了空前的繁荣发展,国内外众多科技公司纷纷下场布局、行业应用层出不穷,搭载RISC-V内核的MCU也逐渐走入了工程师的日常开发工作中。 工欲善其事必先利其器,要想实现基于RISC-V MCU的项目开发,与之配套的集成开发环境必不可少。目前市场上可供选择的RISC-V MCU开发工具已初具规模,由MounRiver团队打造的MounRiver® Studio(MRS)便是其中一种。
RISC-V MCU开发 (一):MounRiver Studio集成开发环境
|
算法 Java 关系型数据库
|
6月前
|
算法 NoSQL 网络协议
嵌入式软件开发应该掌握哪些知识?
本文介绍了嵌入式软件及其在汽车、医疗设备等领域的应用。嵌入式软件是运行在嵌入式系统中的程序,负责控制硬件并提供特定功能。要成为嵌入式软件开发者,需掌握C/C++编程语言、数据结构与算法、Linux基础知识,如文件系统管理、命令操作。进阶知识包括文件I/O、线程进程、IPC和网络编程。高阶知识涉及ARM架构、系统移植、Bootloader、内核移植及Linux驱动开发,包括设备驱动编程和调试优化技术。
138 0
|
6月前
|
NoSQL 芯片 网络架构
OpenOCD(七):TAP声明
OpenOCD(七):TAP声明
241 1
|
6月前
|
NoSQL Linux Android开发
OPENJTAG调试学习(四):OpenJTAG 来烧写、调试 cortex M3
OPENJTAG调试学习(四):OpenJTAG 来烧写、调试 cortex M3
131 0
|
6月前
|
NoSQL 安全 芯片
OpenOCD(三):学习OpenJTAG Config文件配置
OpenOCD(三):学习OpenJTAG Config文件配置
371 0
|
6月前
|
存储 NoSQL Linux
OpenOCD(一):什么是OpenOCD&调试适配器硬件
OpenOCD(一):什么是OpenOCD&调试适配器硬件
614 0