从零学习开发一个RISC-V操作系统(四)丨RISC-V汇编语言编程


  本系列是博主参考B站课程学习开发一个RISC-V的操作系统的学习笔记,计划从RISC-V的底层汇编指令学起,结合C语言,在Ubuntu 20.04上开发一个简易的操作系统。一个目的是通过实践操作学习和了解什么是操作系统,第二个目的是为之后学习RISC-V的集成电路设计打下一定基础。本系列持续不定期更新,分享出来和大家一同交流进步。
  博主是微电子科学与工程专业的学生,对软件和操作系统难免有理解不到位的地方。如有谬误敬请不吝告知,不胜感激。

  参考课程及文章:
  【Bilibili】[完结] 循序渐进,学习开发一个RISC-V上的操作系统 - 汪辰 - 2021春


一、RISC-V汇编语言简介

  汇编语言(Assembly Language)是一种“低级”语言。不同的架构的汇编语言是不同的,因为底层的寄存器的个数和功能不同。例如x86的机器语言在RISC-V的机器上是无法运行的,但是使用高级语言时完全不需要考虑底层的机器语言。我们使用不同的编译器将高级语言翻译成不同的机器语言,来完成对内存和指令的管理和优化。而正是由于这一点,使用汇编语言时完全不需要考虑不同编译器的影响,这也是汇编语言的灵活性的体现。本课程学习和使用的汇编语言是RISC-V汇编语言,其依赖于RISC-V独有的GNU汇编器,所以将RISC-V的汇编程序移植到其他架构的处理器上也是无法运行的。

  • 汇编语言的缺点:难读、难写、难移植
  • 汇编语言的优点:灵活、强大
  • 汇编语言的应用场景
    • 需要直接访问底层硬件的地方
    • 需要对性能执行极致优化的地方

1.1 RISC-V 汇编语言的基本格式

  一个完整的RISC-V汇编程序有多条语句(statement)组成,汇编文件一般由.s结尾(不包含预处理语句,是纯粹的汇编语句)。一条典型的RISC-V汇编语句由3部分组成,分为标签、操作和注释:

[label:] [operation] [comment] 
  • label(标号): GNU汇编中,任何以冒号结尾的标识符都被认为是一个标号。标号相当于给一个指令所在的地址起的一个名字
  • operation 可以有以下多种类型:
    • instruction(指令): 直接对应二进制机器指令的字符串,例如add
    • pseudo-instruction(伪指令): 一些指令的组合。它并不对应二进制机器指令,只是为了提高编写代码的效率,可以用一条伪指令指示汇编器产生多条实际的指令(instructions),方便程序的使用,例如li。在理解和做法上与自定义的函数类似。
    • directive(指示/伪操作): 通过类似指令的形式(以“.”开头),通知汇编器如何控制代码的产生等,不对应具体的RISC-V指令,由汇编器自身定义,例如.text.global.end.macro.endm等。在理解和应用上类似C语言中的#define语句。
    • macro(宏):采用指示/伪操作 .macro/.endm 自定义的宏,汇编器碰到宏时会自动将宏替换成对应定义的内容。
  • comment(注释): 常用方式,#开始到当前行结束,也有些汇编器定义;//开头的注释格式。

  下面是一个简单的RISC-V的汇编语言程序:

# fitst RISC-V Assemble Sample

.macro do_nothing
    nop
    nop
.endm

    .text
    .global _start

_start:
    li x6, 5 # x6 = 5
    li x7, 4 # x7 = 4

    add x5, x6, x7 # x5 = x6 + x7
    do_nothing

stop: 
    j stop  # jump to stop
    .end

1.2 RISC-V 汇编指令操作对象

  1. 寄存器
  • 32个寄存器,x0~x31(本节课只设计RV32I的通用寄存器组)
  • 在RISC-V中,Hart在执行算数逻辑运算时所操作的数据必须直接来自寄存器(Hart可以认为是处理器执行指令的最小单元,类似传统的CPU概念,但是与CPU不同),如果数据存在内存中,必须首先将要操作的数据转移到寄存器中,Hart才能对数据进行处理,计算之后的结果也只能存在寄存器中,之后根据需要再转移到外部的内存空间中。
    在这里插入图片描述
    上图中,XLEN表示机器的字长,RV32I的ISA对应的XLEN对应的就是32位。x0寄存器很特殊,其中的值恒为0,且不允许写操作,读出的值恒为0。pc即指针计数器寄存器在RISC-V中是禁止被访问的。获取程序当前运行的位置需要用特殊的方法实现。
  1. 内存
  • Hart可以执行在寄存器和内存之间的数据读写操作
  • 读写操作时,使用字节(Byte)为基本单位进行寻址;
  • RV32可以访问最多 2 32 2^{32} 232个字节的内存空间。

1.3 RISC-V 汇编指令编码格式

  做底层开发的时候,经常需要进行逐字节对照查阅指令。可以根据手册(RISC-V非特权指令集)查阅每个指令的含义。
在这里插入图片描述

  • 指令长度:在RISC-V汇编指令的规范中,所有的指令的长度都是固定的(在非压缩的情况下讨论)。RV32I中指令长度ILEN1 = 32bit。

  • 指令对齐:指一条指令开始的地址,IALIGN = 32bit表示指令开始的地址一定是4的倍数,程序加载的时候一定从这样一个指令开始的地方开始加载。

  • 每个32bit构成一个域。

  • funct3/funct7opcode共同决定了最终的指令类型。以add指令为例,它对应的opcode为0110011,通过查阅下标可以发现它是一条OP类型的指令。
    在这里插入图片描述

  • 指令在程序中按小端序(Little-Endian)排列(底字节存入低地址,高字节存入高地址)。不同的CPU规定的主机字节序不同。

  • RISC-V中有六种不同的指令格式(format):

    • R-type:(Register),每条指令中有三个 fields,用于指定 3 个寄存器参数(选择的寄存器编号)
    • I-type: (Immediate),每条指令除了带有两个寄存器参数外,还带有一个立即数参数(宽度为 12 bits)。
    • S-type: (Store),每条指令除了带有两个寄存器参数外,还带有一个立即数参数(宽度为 12 bits,但 fields 的组织方式不同于 I-type)
    • B-type: (Branch),每条指令除了带有两个寄存器参数外,还带有一个立即数参数(宽度为 12bits,但取值为 2 的倍数)。
    • U-type: (Upper),每条指令含有一个寄存器参数再加上一个立即数参数(宽度为 20bits,用于表示一个立即数的高 20 位)
    • J-type: (Jump),每条指令含有一个寄存器参数再加上一个立即数参数(宽度为 20bits)

1.4 RISC-V 汇编指令分类

  RISC-V中常用的汇编指令如下表所示:
在这里插入图片描述
  伪指令很多,一条伪指令具体执行哪些代码可以在 RISC-V非特权指令集手册 中的 RISC-V Assembly Programmer’s Handbook 章节查阅到。

二、RISC-V汇编语言详解

2.1 add 加法指令

在这里插入图片描述

  • 编码格式:R-type
  • opcode: 0110011
  • funct3 = 000, funct7 = 0000000
# Add
# Format:
#	ADD RD, RS1, RS2
# Description:
#	The contents of RS1 is added to the contents of RS2 and the result is 
#	placed in RD.

	.text				# Define beginning of text section
	.global	_start		# Define entry _start

_start:
	li x6, 1			# x6 = 1
	li x7, 2			# x7 = 2
	add x5, x6, x7		# x5 = x6 + x7

stop:
	j stop			# Infinite loop to stop execution

	.end			# End of file

Makefile操作须知
  在仓库代码中的common.mk文件中有如下的一段代码,它的意思是启动虚拟机qemu的系统模式(汇编直接编译出的代码是不能在操作系统的裸机上直接运行的,即不能在用户user模式下运行),参数-nographic表示不启动图形界面,-smp 1表示只启动一个Hart,-machine virt表示启动virt的机器类型。

QEMU = qemu-system-riscv32
QFLAGS = -nographic -smp 1 -machine virt -bios none

  运行指令make debug时实际运行的是如下的代码。-s表示在目标机(模拟机)中启动gdbserver,二者建立网络链接(在这个环境中实际上是内部网络的回环),-S表示启动调试模式后程序暂停运行。-x ${GDBINIT}表示启动一个gdb的调试脚本,自动运行gdb的相关指令,脚本的内容可以在文件gdbinit文件中找到

.PHONY : debug
debug: all
	@echo "Press Ctrl-C and then input 'quit' to exit GDB and QEMU"
	@echo "-------------------------------------------------------"
	@${QEMU} ${QFLAGS} -kernel ${EXEC}.elf -s -S &
	@${GDB} ${EXEC}.elf -q -x ${GDBINIT}

在这里插入图片描述

  编译运行后,发现test.bin文件只有16个字节,对应程序中确实只有四条指令。test.elf文件中除了指令本身之外还有很多调试相关的内容。
在这里插入图片描述
  输入命令make hex可以看到test.bin中的数据,可以根据这些数据将所有指令反汇编出来(也可以使用make code命令自动进行反汇编):
在这里插入图片描述
  使用make debug命令对程序进行调试,在gdb页面中,输入si(step instruction)单步运行程序(makefile中已经将断点设置在.start处了)。可以看到,x6,x7,x5的值会依次变化。

如果要退出qemu中的gdb,一定要先 Ctrl+C,之后再输入quit和确认y进行退出,否则会遇到qemu的后台程序杀不死的问题,导致下次启动错误。

在这里插入图片描述

2.2 sub 减法指令

在这里插入图片描述

  • 编码格式:R-type
  • opcode: 0110011
  • funct3 = 000, funct7 = 0100000
# Substract
# Format:
#	SUB RD, RS1, RS2
# Description:
#	The contents of RS2 is subtracted from the contents of RS1 and the result
#	is placed in RD.

	.text				# Define beginning of text section
	.global	_start		# Define entry _start

_start:
	li x6, -1			# x6 = -1
	li x7, -2			# x7 = -2
	sub x5, x6, x7		# x5 = x6 - x7

stop:
	j stop			# Infinite loop to stop execution

	.end			# End of file


  原创笔记,码字不易,欢迎点赞,收藏~ 如有谬误敬请在评论区不吝告知,感激不尽!博主将持续更新有关嵌入式开发、FPGA方面的学习笔记。


  • 18
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
目 录 第1章 ARM微处理器概述 1.1 ARM-Advanced RISC Machines 1.2 ARM微处理器的应用领域及特点 1.2.1 ARM微处理器的应用领域 1.2.2 ARM微处理器的特点 1.3 ARM微处理器系列 1.3.1 ARM7微处理器系列 1.3.2 ARM9微处理器系列 1.3.3 ARM9E微处理器系列 1.3.4 ARM10E微处理器系列 1.3.5 SecurCore微处理器系列 1.3.6 StrongARM微处理器系列 1.3.7 Xscale处理器 1.4 ARM微处理器结构 1.4.1 RISC体系结构 1.4.2 ARM微处理器的寄存器结构 1.4.3 ARM微处理器的指令结构 1.5 ARM微处理器的应用选型 1.6 本章小节 第2章 ARM微处理器的编程模型 2.1 ARM微处理器的工作状态 2.2 ARM体系结构的存储器格式 2.3 指令长度及数据类型 2.4 处理器模式 2.5 寄存器组织 2.5.1 ARM状态下的寄存器组织 2.5.2 Thumb状态下的寄存器组织 2.5.3 程序状态寄存器 2.6 异常(Exceptions) 2.6.1 ARM体系结构所支持的异常类型 2.6.2 对异常的响应 2.6.3 从异常返回 2.6.4 各类异常的具体描述 2.6.5 异常进入/退出小节 2.6.6 异常向量(Exception Vectors) 2.6.7 异常优先级(Exception Priorities) 2.6.8 应用程序中的异常处理 2.7 本章小节 第3章 ARM微处理器的指令系统 3.1 ARM微处理器的指令集概述 3.1.1 ARM微处理器的指令的分类与格式 3.1.2 指令的条件域 3.2 ARM指令的寻址方式 3.2.1 立即寻址 3.2.2 寄存器寻址 3.2.2 寄存器间接寻址 3.2.3 基址变址寻址 3.2.4 多寄存器寻址 3.2.5 相对寻址 3.2.6 堆栈寻址 3.3 ARM指令集 3.3.1 跳转指令 3.3.2 数据处理指令 3.3.3 乘法指令与乘加指令 3.3.4 程序状态寄存器访问指令 3.3.5 加载/存储指令 3.3.6 批量数据加载/存储指令 3.3.7 数据交换指令 3.3.8 移位指令(操作) 3.3.9 协处理器指令 3.3.10 异常产生指令 3.4 Thumb指令及应用 3.5 本章小节 第4章 ARM程序设计基础 4.1 ARM汇编器所支持的伪指令 4.1.1 符号定义(Symbol Definition)伪指令 4.1.2 数据定义(Data Definition)伪指令 4.1.3 汇编控制(Assembly Control)伪指令 4.1.4 其他常用的伪指令 4.2 汇编语言的语句格式 4.2.1 在汇编语言程序中常用的符号 4.2.2 汇编语言程序中的表达式和运算符 4.3 汇编语言的程序结构 4.3.1 汇编语言的程序结构 4.3.2 汇编语言的子程序调用 4.3.3 汇编语言程序示例 4.3.4 汇编语言与C/C++的混合编程 4.4 本章小节 第5章 应用系统设计与调试 5.1 系统设计概述 5.2 S3C4510B概述 5.2.1 S3C4510B及片内外围简介 5.2.2 S3C4510B的引脚分布及信号描述 5.2.3 CPU内核概述及特殊功能寄存器(Special Registers) 5.2.4 S3C4510B的系统管理器(System Manager) 5.3 系统的硬件选型与单元电路设计 5.3.1 S3C4510B芯片及引脚分析 5.3.2 电源电路 5.3.3 晶振电路与复位电路 5.3.4 Flash存储器接口电路 5.3.5 SDRAM接口电路 5.3.6 串行接口电路 5.3.7 IIC接口电路 5.3.8 JTAG接口电路 5.3.9 10M/100M以太网接口电路 5.3.10 通用I/O接口电路 5.4 硬件系统的调试 5.4.1 电源、晶振及复位电路 5.4.2 S3C4510B及JTAG接口电路 5.4.3 SDRAM接口电路的调试 5.4.4 Flash接口电路的调试 5.4.5 10M/100M以太网接口电路 5.5 印刷电路板的设计注意事项 5.5.1 电源质量与分配 5.5.2 同类型信号线的分布 5.6 本章小节 第6章 部件工作原理与编程示例 6.1 嵌入式系统的程序设计方法 6.2 应用程序编程示例 6.2.1 通用I/O口工作原理与编程示例 6.2.2 串行通讯工作原理与编程示例 6.2.3 中断控制器工作原理与编程示例 6.2.4 定时器工作原理与编程示例 6.2.5 GDMA工作原理与编程示例 6.2.5 IIC总线控制器工作原理
### 回答1: 《计算机组成与设计:RISC-V版本,硬件与软件的互动》是一本关于计算机体系结构的教材。它涵盖了计算机硬件和软件之间的相互作用。 首先,这本教材深入介绍了计算机组成的基本概念和原理。它讲解了计算机硬件的各个组成部分,如中央处理器、存储器、输入输出设备等,并详细解释了它们之间的工作原理和互动方式。读者可以通过这些内容全面了解计算机硬件的工作方式。 此外,该教材还重点介绍了RISC-V指令集架构。RISC-V是一种现代的、开放的指令集架构,具有简洁、规范和可定制的特点。本书详细描述了RISC-V指令集的设计和实现,并解释了它与计算机硬件的紧密关系。读者可以通过学习RISC-V指令集,了解指令的执行过程,理解计算机在硬件层面上如何处理指令和数据。 在硬件和软件的交互方面,这本教材强调了它们之间的密切联系。它介绍了硬件和软件之间的界面和通信方式,如总线、中断和输入输出等。通过学习这些内容,读者将了解到计算机硬件和软件是如何相互配合工作的。它还讨论了如何进行硬件和软件的调试和优化,以提高计算机的性能和可靠性。 总的来说,《计算机组成与设计:RISC-V版本,硬件与软件的互动》这本书从计算机硬件和软件的角度全面介绍了计算机的组成和互动方式。通过学习这本教材,读者可以深入了解计算机系统的工作原理,并掌握如何设计和优化计算机系统的能力。 ### 回答2: 《计算机组织与设计:RISC-V版》是一本关于计算机硬件和软件互联的重要教材。这本书的主要内容包括计算机组织与结构、指令级并行、存储系统、互连技术、输入输出系统等。该书以RISC-V指令集架构为基础,详细介绍了计算机的硬件结构和设计原理,并与软件编程环境相结合。这种硬件软件相互补充的设计使得计算机能够高效、稳定地运行。 该书的特点之一是使用清晰的语言和具体的实例解释计算机硬件和软件之间的关系。通过逐步引入不同的主题和概念,读者可以深入了解计算机硬件组成的基本原理,并了解它们与软件编程之间的互动关系。此外,书中提供了大量的实践案例和练习题,使读者能够巩固所学的知识,并自主进行实践和思考。 在讲解硬件设计方面,该书详细讨论了计算机的基本组成部分,如处理器、存储器、输入输出设备以及互连技术等。它深入探讨了各个组件的工作原理和设计方法,包括流水线、缓存、并发控制等。此外,该书还介绍了指令级并行的相关技术,如流水线、超标量、动态调度等,使读者能够了解如何通过优化硬件设计来提高计算机的性能。 在软件编程方面,该书介绍了RISC-V指令集的特点和使用方法。它详细讲解了指令的结构和功能,以及如何使用汇编语言进行编程。此外,该书还介绍了操作系统、编译器和调试工具等软件开发环境的基本原理和使用方法,使读者能够理解软件和硬件之间的交互关系,以及如何进行有效的软件开发。 总之,《计算机组织与设计:RISC-V版》通过深入浅出的讲解和大量实例的引导,将计算机硬件和软件的复杂性简化为易于理解和学习的内容。它为读者提供了全面而深入的知识,使他们能够了解计算机系统的工作原理、优化硬件设计和进行高效软件编程。这本书是学习计算机组成与设计的重要参考资料,对于想要深入了解计算机硬件和软件的读者来说是一本不可或缺的教材。 ### 回答3: 《计算机组织与设计RISC-V版:硬件软件接口》介绍了计算机硬件和软件的互动关系。它涵盖了计算机系统中硬件和软件之间的接口,以及它们是如何相互作用的。 该书首先介绍了计算机体系结构的基本知识,包括指令集架构、计算机组成和设计原则等。接着,它深入探讨了RISC-V架构,该架构是一种现代的指令集架构,被广泛用于教育和学术研究。 书中还详细讨论了硬件和软件之间的接口,包括指令集、寄存器、内存和输入输出等。通过深入的解释和实例演示,读者可以了解硬件和软件之间的通信和协作方式。 此外,该书还介绍了一些高级主题,如流水线和并行处理。这些主题涉及到优化计算机性能的技术和策略,使读者能够更好地理解复杂的计算机系统结构。 《计算机组织与设计RISC-V版:硬件软件接口》适用于计算机科学、计算机工程和相关专业的学生。它是一本全面介绍计算机系统结构和设计原理的权威教材,旨在帮助读者深入理解计算机硬件和软件之间的互动关系。读者可以通过阅读本书,获得一种全面的计算机系统知识,为日后的学习和工作打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Include everything

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值