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

本篇文章的内容

  • 一、RISC-V汇编语言简介
    • 1.1 RISC-V 汇编语言的基本格式
    • 1.2 RISC-V 汇编指令操作对象
    • 1.3 RISC-V 汇编指令编码格式
    • 1.4 RISC-V 汇编指令分类
  • 二、RISC-V汇编语言详解
    • 2.1 add 加法指令
    • 2.2 sub 减法指令


  本系列是博主参考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_nothingnopnop
.endm.text.global _start_start:li x6, 5 # x6 = 5li x7, 4 # x7 = 4add x5, x6, x7 # x5 = x6 + x7do_nothingstop: 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 = 1li x7, 2			# x7 = 2add x5, x6, x7		# x5 = x6 + x7stop: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 = -1li x7, -2			# x7 = -2sub x5, x6, x7		# x5 = x6 - x7stop:j stop			# Infinite loop to stop execution.end			# End of file

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


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/644659.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux条件判断练习

1.实现自动生成相应的压缩包 1.写一个脚本,完成如下功能 传递一个参数给脚本,此参数为gzip、bzip2或者xz三者之一; (1) 如果参数1的值为gzip,则使用tar和gzip归档压缩/etc目录至/backups目录中,并命名为/backups/etc-…

PPP协议原理介绍+报文分析+配置指导-RFC1661

个人认为,理解报文就理解了协议。通过报文中的字段可以理解协议在交互过程中相关传递的信息,更加便于理解协议。 因此本文将在PPP协议报文的基础上进行介绍。 关于PPP协议基本原理,可参考RFC1661-The Point-to-Point Protocol (PPP)。 关于P…

【JavaEE】文件操作 —— IO

文件操作 —— IO 1. 文件的属性 文件内容文件大小文件路径文件名称 2. 文件的管理 采用树形结构进行管理。 3. 文件路径 分为两种:相对、绝对路径。 相对路径:相对于当前位置的路径,以“./xxx.xxx”为标志绝对路径:以从盘符…

手动导入jar包到Maven的解决方案(简单有效!)

想要导入一个jar包到项目中,这个jar包在Maven中没有可以尝试以下方式。 第一步 先找到你maven的本地仓库,我的仓库就在这里,你可以根据你安装的maven找到你的目录 第二步 根据坐标创建文件夹。 这个依赖modbus4j.jar,Maven远…

PyQt ------ QTextEditor

PyQt ------ QTextEditor 引言正文示例1------进阶示例 引言 这里给大家介绍一下 PyQt6 中的 QTextEditor 组件用法。 正文 QTextEditor 可以进行多行字符串输出的组件。 想要获取 QTextEditor 组件中当前存放的字符串,需要使用: QTextEditor.toPla…

《GreenPlum系列》GreenPlum初级教程-GreenPlum详细入门教程

文章目录 GreenPlum详细入门教程第一章 GreenPlum介绍1.MPP架构介绍2.GreenPlum介绍3.GreenPlum数据库架构4.GreenPlum数据库优缺点 第二章 GreenPlum单节点安装1.Docker创建centos容器1.1 拉取centos7镜像1.2 创建容器1.3 进入容器1.4 容器和服务器免密操作1.4.1 生成密钥1.4.…

idea创建公用依赖包项目

创建parent项目 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/…

服务器管理平台(6)- Utils

Utils 本篇为服务器管理平台的结篇&#xff0c;讲述一些必要的Util&#xff0c;如钉钉告警、安全加密、远程登录等功能的实现 1、钉钉告警 1.1、SQL配置告警规则 逻辑磁盘容量已使用比例超过90% 超过30天未登录 字段名称字段类型解释Idint自增IDTablestring监测表名Metri…

matlab appdesigner系列-常用18-表格

表格&#xff0c;常用来导入外部表格数据 示例&#xff1a; 导入外界excel数据&#xff1a;data.xlsx 姓名年龄城市王一18长沙王二21上海王三56武汉王四47北京王五88成都王六23长春 操作步骤如下&#xff1a; 1&#xff09;将表格拖拽到画布上 2&#xff09;对app1右键进行…

GPSR路由算法的MATLAB实现

GPSR基于节点地理位置路由信息&#xff0c;采用贪婪策略和右手准则的结合在邻居节点中选择下一跳节点进行数据转发。节点在进行路由选择时&#xff0c;只需知道自己、邻居和目标节点的地理位置信息&#xff0c;无需维护全局网络的链路状态&#xff0c;这在很大程度上降低了网络…

高质量简历模板网站,免费、免费、免费

你们在制作简历时&#xff0c;是不是基本只关注两件事&#xff1a;简历模板&#xff0c;还有基本信息的填写。 当你再次坐下来更新你的简历时&#xff0c;可能会发现自己不自觉地选择了那个“看起来最好看的模板”&#xff0c;填写基本信息&#xff0c;却没有深入思考如何使简历…

基于 Docker 部署 Pingvin Share 文件共享平台

一、Pingvin Share 介绍 Pingvin Share 简介 Pingvin Share 是自托管文件共享平台&#xff0c;是 WeTransfer 的替代方案。 Pingvin Share 特点 在 2 分钟内启动您的实例使用可通过链接访问的文件创建共享没有文件大小限制&#xff0c;只有你的磁盘是你的限制设置共享到期时间…

C++11新特性:final/override控制

override关键字 用于显式标识一个成员函数&#xff08;通常是虚函数&#xff09;是在派生类中重写&#xff08;覆盖&#xff09;了基类中的虚函数。这有助于提高代码的可读性&#xff0c;同时在编译时提供了检查&#xff0c;确保派生类中的函数确实是在基类中有对应的虚函数。…

GZ036 区块链技术应用赛项赛题第3套

2023年全国职业院校技能大赛 高职组 “区块链技术应用” 赛项赛卷&#xff08;3卷&#xff09; 任 务 书 参赛队编号&#xff1a; 背景描述 新能源作为新兴领域&#xff0c;产业呈现碎片化与复杂化的特性&#xff0c;逐渐出现管理困难、供应链金融、可信监管与数…

论文阅读_训练大模型用于角色扮演

英文名称: Character-LLM: A Trainable Agent for Role-Playing 中文名称: 角色-LLM&#xff1a;训练Agent用于角色扮演 文章: [https://arxiv.org/abs/2310.10158](https://arxiv.org/abs/2310.10158) 作者: Yunfan Shao, Linyang Li, Junqi Dai, Xipeng Qiu 机构: 复旦大学…

军事智能中的深度强化学习不同于传统的深度强化学习

在军事智能中&#xff0c;“诡”和“诈”是两个最重要的概念。 “诡”变指的是智能体通过采取一些不可预测或复杂的变化策略来获得优势。诡变可能包括逃避对手的观察或引诱对手采取不利的行动。智能体可以使用诡变来欺骗对手&#xff0c;使其做出错误的决策或暴露其策略。 “诈…

【第七在线】智能商品计划:重塑服装行业的供应链管理

在当今快速变化的市场环境中&#xff0c;供应链管理已成为企业成功的关键因素之一。尤其在服装行业&#xff0c;供应链的效率、灵活性和透明度直接影响着企业的竞争力和盈利能力。随着技术的发展&#xff0c;智能商品计划正逐渐成为重塑供应链管理的强大工具。 一、智能商品计划…

什么是JMeter?我们为什么要用JMeter做性能测试

什么是JMeter&#xff1f;我们为什么要用JMeter做性能测试 什么是JMeter&#xff1f;为什么选择JMeterJMeter的优点JMeter是如何工作的 什么是JMeter&#xff1f; Apache JMeter TM是纯Java开源软件&#xff0c;最初由Apache软件基金会的Stefano Mazzocchi开发&#xff0c;旨在…

如何在Linux上部署Docker容器

一、什么是docker&#xff1f; Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的 Linux或Windows 机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不…

方法调用(java)

方法调用的基本内存原理&#xff1a;先进后出 基本数据类型&#xff1a;整数类型、浮点数类型、布尔类型、字符类型&#xff1b;数据类型存储在自己的空间 引用数据类型&#xff1a;除了以上数据类型都是&#xff1b;数据值是存储在其他空间中&#xff0c;变量中存储的是地址…