QEMU
一种计算机系统模拟软件,在GNU/Linux平台上使用广泛。
支持多种体系结构,例如RISC-V 32 64等
QEMU有两种主要运作模式:
- User mode:直接运行应用程序。
- System mode:模拟整个计算机系统,包括中央处理器及其它周边设备。
使用riscv gcc编译代码
-march:编译生成的程序可以运行在RISC-V 32位系统上并且支持整数乘法原子性指令集。
-mabi=ilp:一个长整数支持多少位
riscv64-unknown-elf-gcc -march=rv32ima -mabi=ilp32 hello.c
生成出来的可执行文件
不能在linux上直接执行
应该把此软件加载到RISCV板子上去运行
或者使用模拟器运行
qemu-riscv32 ./a.out
上述是在user mode下运行,只模拟到了Application层。开发操作系统时应该是system mode。
项目构造工具
- make:一种自动化管理工具
- makefile,配合make,用于描述构建工程过程中所管理的对象以及如何构造工程的过程。
- 隐式查找:当前目录下按顺序找寻文件名为:GNUmakefile、makefile、Makefile的文件。
- 显示查找:-f。
- makefile:由一条或多条规则组成。
每条规则的组成
- target:目标,可以是obj文件也可以是可执行文件。
- -prerequisites:生成target所需要的依赖。
- command:为了生成target需要执行的命令,可以有多条。
例如:
hello:hello.c
gcc hello.c -o hello
make的运行
汇编语言
汇编语言(Assembly language)是一种低级语言。
缺点:
- 难读
- 难写
- 难移植
优点: - 灵活
- 强大
汇编语言的应用场景: - 需要直接访问底层硬件的地方
- 需要对性能执行极致优化的地方
汇编语言语法介绍(GNU版本)
一个完整的RISC-V汇编程序(也就是一个.s文件,大写的S包含一些预处理指令,例如#include #define等,小写的s就是纯汇编指令构成的文件)由多条语句(statement)组成。
一条典型的RISC-V汇编语句由3部分组成。
[label:][operation][comment]
- label(标号):GNU汇编中,任何以冒号结尾的标识符都会被认为是一个标号。相当于为一个地址取了一个名字(每条机器指令加载到CPU中都是有一个地址的)。
- operation:可以有多种类型。(1)instruction(指令):直接对应二进制机器指令的字符串。(2)pseudo-instruction(伪指令):为了提高代码编写的效率,可以用一条伪指令指示汇编器产生多条实际的指令。(3)directive(指示/伪操作):通过类似指令的形式(以.开头),通知汇编器如何控制代码的产生等,不对应具体的指令。(4)macro:采用.macro/.endm自定义的宏。
- comment(注释):常用方式以#开始到当前行结束。
RISC-V汇编指令操作对象
- 寄存器:32个通用寄存器,x0~x31。在RISC-V中,Hart(处理器执行的最小单元)在执行算术逻辑运算时所操作的数据必须直接来自寄存器。
- 内存:Hart可以执行在寄存器和内存之间的数据读写操作。读写操作使用字节(Byte)为基本单位进行寻址。RV32可以访问最多232个字节的内存空间。
- 最右边是低地址位,最左侧是高地址位。
- x0寄存器不能对它进行写操作,进行读操作时永远读出来为零。
- pc寄存器不能对它进行直接的访问。
RISC-V汇编指令编码格式
- 指令长度:ILEN1 = 32bits (RV32I)
- 指令对齐:IALIGN = 32bits(RV32I)
- 32个bit划分为不同的域(field)
- funct3(占3个bit)/funct7(占7个bit) 和 opcode 一起决定最终的指令类型
- 指令在内存中按照小端序排列。
opcode一共有7位,第0位和第1位永远是11。
例如ADD指令的opcode
最低两位——第零位和第一位都是11,
接下来2-4位为一组,
再接着5-6位为一组。
对应高位就是01100——OP
主机字节序(HBO Host Byte Order)
- 一个多字节整数在计算机内存中存储的字节顺序称为主机字节序,或者称为本地字节序。
- 不同类型CPU的HBO不同,分为大端序(Big-Endian)和小端序(Little-Endian)。
小端序:数据的低位字节存放在内存的低地址。
六种指令格式
- R-type(Register):每条指令中有3个fields,用于指定3个寄存器的参数——rs2、rs1(source:源)和rd(destination 存放最终结果的寄存器)。各个寄存器占5个bit,最多能表达32个寄存器。
- I-type(Immediate):每条指令除了带有两个寄存器参数外,还带有一个立即数参数(宽度为12bits)imm[11:0]。
- S-type(Store):每条指令除了带有两个寄存器参数外,还带有一个立即数参数(宽度为12bits,但field的组织方式与I-type不同)。用来访问内存的一种指令。
- B-type(Branch):每条指令除了带有两个寄存器参数外,还带有一个立即数参数(宽度为12bits,但取值为2的倍数)。与分支跳转有关系。
- U-type(Upper):每条指令含有一个寄存器参数再加上一个立即数参数(宽度为20bits,用于表示一个立即数的高20位)。
- J-type(Jump):每条指令含有一个寄存器参数再加上一个立即数参数(宽度为20bits)。
要学习的汇编指令分类:
常用的一些伪指令与基本指令的对应关系