RISC-V手册 第三、四章 RISC-V汇编语言,乘法和除法指令

第三章 RISC-V汇编语言 3.2 函数调用规范 3.3 汇编器 这类指令在巧妙配置常规指令的基础上实现,称为伪指令。图 3.3和 3.4列出了 RISC-V伪指令。 汇编程序的开头是一些汇编指示符,它们是汇编器的命令。图 3.9是RISC-V的汇编指示符。其中图 3.6中用到的指示符有: .text:进入代码段。 .align 2:后续代码按2^2字节对齐。 .globl main:声明全局符号 “main” .section .rodata:进入只读数据段 .balign 4:数据段按4字节对齐 .string “Hello, %s!\n": 创建空字符结尾的字符串 .string “world": 创建空字符结尾的字符串 3.4 链接器 3.5 静态链接和动态链接 上一节对 静态链接进行了说明,在程序运行前所有的库都进行了链接和加载。如果这样的库很大,链接一个库到多个程序中会十分占用内存。另外,链接时库是绑定的,即使它们后来的更新修复了 bug,强制的静态链接的代码仍然会使用旧的、有bug的版本。 为了解决这两个问题,现在的许多系统使用动态链接,外部的函数在第一次被调用时才会加载和链接。后续所有调用都使用快速链接,因此只会产生一次动态开销。每次程序开始运行,它都会按照需要链接最新版本的库函数。另外,如果多个程序使用了同一个动态链接库,库代码在内存中只会加载一次。 编译器产生的代码和静态链接的代码很相似。其不同之处在于,跳转的目标不是实际的函数,而是一个只有三条指令的存根函数( stub function)。存根函数会从内存中的一个表中加载实际的函数的地址并跳转。不过,在第一次调用时,表中还没有实际的函数的地址,只有一个动态链接的过程的地址。当这个动态链接过程被调用时,动态链接器通过符号表找到实际要调用的函数,复制到内存中,更新记录实际的函数地址的表。后续的每次调用的开销就是存根函数的三条指令的开销。 第四章 乘法和除法指令 RV32M向RV32I中添加了整数乘法和除法指令。图4.1是RV32M扩展指令集的图形表示,图4.2列出了它们的操作码。 RV32M具有有符号和无符号整数的除法指令:divide(div)和divide unsigned(divu),它们将商放入目标寄存器。在少数情况下,程序员需要余数而不是商,因此RV32M提供remainder(rem)和remainder unsigned(remu),它们在目标寄存器写入余数,而不是商。 将两个32位数相乘得到的是64位的乘积。为了正确地得到一个有符号或无符号的64位积,RISC-V中带有四个乘 法指令。要得到整数要得到整数32位乘积( 64位中的低 32位)就用 mul指令。要得到高32位,如果操作数都是有符号数,就用mulh指令;如果操作数都是无符号数,就用mulhu指令。指令;如果一个有符号一个无符号,可以用mulhsu指令。在一条指令中完成把64位积写入两个 32位寄存器的操作会使硬件设计变得复杂,所以RV32M需要两条乘法指令才能得到一个完整的64位积。 对许多微处理器来说,整数除法是相对较慢的操作。如前述,除数为2的幂次的无符号除法可以用右移来代替。事实证明,通过乘以近似倒数再修正积的高32位的方法,可以优化除数为其它数的除法。例如,图 4.3显示了 3为除数的无符号除法的代码。 {% note danger %} lui t0, 0xaaaab 为什么t0=0xaaaaaaab而不是0xaaaab000 {% endnote %}

2023-01-06 · 1 min

RISC-V手册 第二章 RV32I基础整数指令集

1.2 模块化与增量型 ISA ​和几乎所有以往的 ISA不同,RISC-V是模块化的。它的核心是一个名为RV32I的基础 ISA,运行一个完整的软件栈。RV32I是固定的,永远不会改变。模块化来源于可选的标准扩展,根据应用程序的需要,硬件可以包含或不包含这些扩展。可以生成当前硬件条件下的最佳代码。惯例是把代表扩展的字母附加到指令集名称之后作为指示。例如,RV32IMFD将乘法( RV32M),单精度浮点(RV32F)和双精度浮点(RV32D)的扩展添加到了基础指令集 RV32I)中。 2.2 RV32I 指令格式 ​用于寄存器-寄存器操作的R类型指令,用于短立即数和访存load操作的I型指令,用于访存store操作的S型指令,用于条件跳转操作的B类型指令,用于长立即数的U型指令和用于无条件跳转的J型指令。 2.3 RV32I 寄存器 ​RV32I有31寄存器加上一个值恒为0的x0寄存器。 2.4 RV32I 整数计算 ​简单的算术指令(add, sub)、逻辑指令(and, or, xor),以及图2.1中的移位指令(sll, srl, sra)和其他ISA差不多。他们从寄存器读取两个32位的值,并将32位结果写入目标寄存器。 ​程序可以根据比较结果生成布尔值。为应对这种使用场景下,RV32I提供一个当小于时置位的指令(slt)。 ​图2.1剩下的两条整数计算指令主要用于构造大的常量数值和链接。加载立即数到高位(lui)将20位常量加载到寄存器的高20位。接着便可以使用标准的立即指令来创建32位常量。 有什么不同之处? RISC-V中没有字节或半字宽度的整数计算操作。操作始终是以完整的寄存器宽度。 RV32I也不包含乘法和除法,它们包含在可选的RV32M扩展中。 2.5 RV32I 的Load 和 Store ​除了提供32位字(lw,sw)的加载和存储外,图2.1中说明,RV32I 支持加载有符号和无符号字节和半字(lb,lbu,lh,lhu)和存储字节和半字(sb,sh)。有符号字节和半字符号扩展为32位再写入目的寄存器。即使是自然数据类型更窄,低位宽数据也是被扩展后再处理,这使得后续的整数计算指令能正确处理所有的32位。在文本和无符号整数中常用的无符号字节和半字,在写入目标寄存器之前都被无符号扩展到32位。 RV32I 条件分支 ​相等(beq),不相等 (bne),大于等于(bge),或小于(blt)。最后两种比较有符号比较,RV32I也提供相应的无符号版本比较的:bgeu和bltu。分支指令的寻址方式是12位的立即数乘以2,符号扩展它,然后将得到值加到PC上作为分支的跳转地址。{% label danger @这句话没理解 %} {% note info %} 补充说明:获取PC 当前的PC可以通过将auipc的U立即数字段设置为0来获得。 {% endnote %} 2.7 RV32I无条件跳转 ​图2.1中的跳转并链接指令(jal)具有双重功能。若将下一条指令PC + 4的地址保存到目标寄存器中,通常是返回地址寄存器ra(见图2.4),便可以用它来实现过程调用。如果使用零寄存器(x0)替换ra作为目标寄存器,则可以实现无条件跳转,因为x0不能更改。像分支一样,jal将其20位分支地址乘以2,进行符号扩展后再添加到PC上,便得到了跳转地址。 {% note info %} jal x1, X means jump to X, and save the return address which is normally PC+4 to the x1....

2023-01-06 · 1 min

Git 常用指令

GIT Git push # git push [ 远程主机名 ][ 本地分支名 ]:[ 远程分支名 ] $ git push origin HEAD:master # HEAD 是当前指向的分支 , 可以用 git show HEAD 查看 $ git show HEAD $ git branch -a # 需要 code view 时要加 /refs/for $ git push origin HEAD:refs/for/master # 不加远程分支名 $ git push origin dev # 相当于 , 如果远程分支不存在则会自动创建 , 并创建联系 $ git push origin dev:dev $ git branch --set-upstream-to=origin/dev # 删除远程分支,直接推送空分支到远程分支 $ git push origin :dev git diff # 查看 unstaged 的改动 (还没 git add) $ git diff # 查看 staged 的改动 (git add 过的) $ git diff --staged # 显示出 branch1 和 branch2 中差异的部分 $ git diff branch1 branch2 --stat # 显示指定文件的详细差异 $ git diff branch1 branch2 具体文件路径 # 显示出所有有差异的文件的详细差异 $ git diff branch1 branch2 # 显示本地 master 分支与远程 master 分支的区别 $ git diff master origin/master # 比较两个 commit git diff commit id1 commit id2 git log # 查看前两个 commit 的修改 $ git log -p -2 # 查看改动了哪些文件 $ git log --stat # 每个 commit 一行展示 $ git log --pretty=oneline # 展示合并历史 $ git log --graph # 从一定时间开始的 commit $ git log --since=2....

2023-01-04 · 5 min

电源管理

This article is out of date and need to rewrite. http://www.wowotech.net/pm_subsystem/suspend_and_resume.html Linux内核提供了三种Suspend: Freeze、Standby和STR(Suspend to RAM),在用户空间向”/sys/power/state”文件分别写入”freeze”、”standby”和”mem”,即可触发它们。 echo "freeze" > /sys/power/state echo "standby" > /sys/power/state echo "mem" > /sys/power/state 参考文章: https://www.cnblogs.com/arnoldlu/p/6253665.html 系统睡眠模型 On S0 - working Standby S1 - CPU and RAM are powered but not executed Suspend to RAM S3 - RAM is powered and the running content is saved to RAM Suspend to Disk , Hibernation(disk) S4 - All content is saved to Disk and power down 嵌入式系统中一般没有 Runtime电源管理模型...

2022-04-26 · 3 min

程序员的自我修养学习笔记

$ objdump -h # 显示段结构 $ objdump -s # 将所有段以16进制打印出来 $ objdump -d # 反汇编 $ objdump -D # 反汇编更多信息 $ objdump -t # 查看符号 $ objdump -R # 查看目标文件重定位表 $ readelf -S # 显示段结构 $ readelf -h # 查看文件头 $ readelf -s # 查看符号表 $ readelf -l # 查看ELF加载时的Segment $ readelf -d 第二章 编译和链接 2.1.1 预处理 gcc –E hello.c –o hello.i 展开宏定义 处理预编译指令 “#if”、“#ifdef”等等 处理 “#include ”预编译指令 删除注释 添加行号和文件名标识 保留所有的 #pragma 编译器指令 2....

2022-01-27 · 2 min · YC-Xiang

Linux输入输出重定向

&>file 意思是把标准输出 和 标准错误输出 都重定向到文件file中 /dev/null是一个文件,这个文件比较特殊,所有传给它的东西它都丢弃掉 command > filename 把标准输出重定向到一个新文件中 command » filename 把标准输出重定向到一个文件中(追加) command 1 > fielname 把标准输出重定向到一个文件中(和 > 一样的) command > filename 2>&1 把标准输出和标准错误一起重定向到一个文件中 command 2 > filename 把标准错误重定向到一个文件中 command 2 » filename 把标准输出重定向到一个文件中(追加) command » filename 2>&1 把标准输出和标准错误一起重定向到一个文件中(追加) command < filename >filename2 把command命令以filename文件作为标准输入,以filename2文件作为标准输出 command < filename 把command命令以filename文件作为标准输入 command « delimiter 把从标准输入中读入,直至遇到delimiter分界符 command <&m 把文件描述符m作为标准输入 command >&m 把标准输出重定向到文件描述符m中 command <&- 把关闭标准输入 原文链接

2021-12-31 · 1 min · YC-Xiang

mac Homebrew和gem下载源修改

Homebrew下载源修改 https://mirrors.tuna.tsinghua.edu.cn/help/homebrew/ $ export HOMEBREW_INSTALL_FROM_API=1 $ export HOMEBREW_API_DOMAIN="https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles/api" $ export HOMEBREW_BOTTLE_DOMAIN="https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles" $ export HOMEBREW_BREW_GIT_REMOTE="https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git" $ export HOMEBREW_CORE_GIT_REMOTE="https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git" $ export HOMEBREW_PIP_INDEX_URL="https://pypi.tuna.tsinghua.edu.cn/simple" Gem下载源修改 # 移除gem默认源,改成ruby-china源 $ gem sources -r https://rubygems.org/ -a https://gems.ruby-china.com/ # 使用Gemfile和Bundle的项目,可以做下面修改,就不用修改Gemfile的source $ bundle config mirror.https://rubygems.org https://gems.ruby-china.com # 删除Bundle的一个镜像源 $ bundle config --delete 'mirror.https://rubygems.org'

2021-12-24 · 1 min · YC-Xiang

Getting Started First-time Git setup /etc/gitconfig: system-wide configuration file. 影响整个系统的 git 配置. git config --system 选项. ~/.gitconfig 或 ~/.config/git/config: user-specific configuration file. 影响当前用户的 git 配置. git config --global 选项. .git/config: repository-specific configuration file. 影响当前仓库的 git 配置. git config --local 选项. 通过下面这个命令可以查看所有的配置, 以及在上述哪个文件中: $ git config --list --show-origin 配置邮箱和姓名, 默认编辑器: $ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com $ git config --global core.editor vim Git Basics short status git status -s: git status 的简化版....

1 min

https://www.cnblogs.com/Chary/p/11736497.html 观察者模式 struct object { struct observer* observer_list[MAX_BINDING_NUMBER]; int number; void (*notify)(struct object* object); void (*add_observer)(struct observer* observer); void (*del_observer)(struct observer* observer); } struct observer { struct object* object; void (*update)(struct observer* observer); }; void bind_observer_to_object(struct observer* observer, struct object* object) { observer->object = object; object->add_observer(observer); } void unbind_observer_from_object(struct observer* observer, struct object* object) { object->del_observer(observer* observer); memset(observer, 0, sizeof(struct observer)); } void notify(struct object* object) { struct observer* observer; for(int index = 0; index < pObject->number; index++) { observer = object->observerList[index]; observer->update(observer); } } 装饰器模式 struct object { struct object* prev; void (*decorate)(struct object* object); } void decorate(struct object* object) { object->prev->decorate(object->prev); printf("normal decorate!...

1 min

Chapter 1 计算机网络和因特网 1.1 什么是因特网 端系统通过通信链路和分组交换机连接到一起. 通信链路: 同轴电缆, 铜线, 光纤, 无线电频谱. 分组交换机: 路由器, 链路层交换机. ISP: 因特网服务提供商. 因特网标准由 IETF 研发, IETF 标准文档称为 RFC. 1.2 网络边缘 主机 = 端系统. 主机可以划分为 client 和 server. 1.2.1 接入网 接入网是将端系统物理链接到其边缘路由器的网络. 家庭接入: DSL, 电缆, FTTH, 拨号和卫星. 1.2.2 物理媒体 1.3 网络核心 1.3.1 分组(packet)交换 1.存储转发机制 就是收到完整一个 packet 才会往输出链路发送数据。 2.排队时延和分组丢失 分组交换机具有输出缓存。 在输出缓存等待的时间为排队时延。 如果输出缓存满了则会产生分组丢失(丢包) 3.转发表和路由选择协议 每台路由器具有一个转发表。 路由选择协议 1.3.2 电路交换 通过网络链路和交换机移动数据有两种方法:电路交换和分组交换。

1 min