RISC-V汇编学习(三)—— RV指令集
有了前两节对于RISC-V汇编、寄存器、汇编语法等的认识,本节开始介绍RISC-V指令集和伪指令。
前面说了RISC-V的模块化特点,是以RV32I为作为ISA的核心模块,其他都是要基于此为基础,可以这样认为:RISC-V ISA = 基本整数指令集+多个可选扩展指令集
;另外RISC-V的ISA spec上是从指令类型和指令格式开始介绍指令的;但从一个嵌入式软件开发人员的角度来说,不是特别适合学习和记忆,所以我这里简单罗列下,不多讲解,感兴趣可以参考spec。
1 指令类型
1.1 组成格式
所有RISC-V指令都是固定长度的32位,这有助于简化指令解码过程。每个指令都由以下几个关键部分组成:
- opcode:这是7位的操作码,用来标识指令的基本类型。
- funct3:这是一个3位的功能码,与opcode一起使用以进一步细化指令的类别。
- funct7:某些指令使用额外的7位功能码来更精确地定义指令的行为。
- rs1/rs2/rd:这些是5位的寄存器地址,分别代表源寄存器1、源寄存器2和目的寄存器。
- imm:立即数字段,其大小和位置根据指令类型的不同而变化。
1.2 类型
RISC-V定义了几种基本的指令格式,每一种都针对特定类型的运算或操作。这些格式包括:R型、I型、S型、B型、U型、J型。
-
R型(Register)
用于寄存器间的算术/逻辑运算(如ADD x1, x2, x3)
字段:opcode确定操作类型,funct3和funct7进一步指定具体操作(如区分ADD与SUB) -
I型(Immediate)
用于立即数操作(如ADDI x1, x2, 42)或加载指令(如LW x1, 100(x2))
立即数:12位符号扩展,直接嵌入指令中 -
S型(Store)
存储数据到内存(如SW x3, 200(x4))
立即数:12位拆分为imm[11:5]和imm[4:0],组合后作为偏移地址。 -
B型(Branch)
条件分支(如BEQ x1, x2, label)
立即数:13位(符号扩展后左移1位),拆分为imm[12|10:5|4:1|11],支持更大跳转范围 -
U型(Upper Immediate)
加载高20位立即数(如LUI x1, 0x12345)或构造地址(如AUIPC)
立即数:20位直接嵌入高位,低12位由后续指令补充 -
J型(Jump)
长距离无条件跳转(如JAL x1, label)
立即数:20位符号扩展后左移1位,支持±1MB跳转范围
但在实际应用中,我们也很难记住这么汇编指令机器码,一般情况下也不会有错,具体可以参考spec。
2 指令命名
下图是RV32I基础指令集的⼀⻚图形表示,将有下划线的字⺟从左到右连接起来,即可组成完整的RV32I指令集。集合标志{}内列举了指令的所有变体,变体⽤加下划线的字⺟或下划线字符_表示,特别的,下划线字符_表示对于此指令变体不需⽤字符表示
以slt指令为例,如下示意图:大括号{ }内列举了每组指令的所有变体,这些变体通过带下滑线的字母(单独的下划线_表示空字段),从左到右连接带下滑线的字母即可组成完整的指令集,比如slt意思是set less than,相当于是一种缩写,完整语句方便我们快速清晰的理解指令的作用。
上图可以表示:slt、slti、sltu、sltiu 这4条RVI指令。
下面将列举以下RISC-V指令集:
- RVI(包括RV32I与RV64I)
- RVM(包括RV32M与RV64M)
- RVFD(包括RV32FD与RV64FD)
- RVA(包括RV32A与RV64A)
3 RVI指令集
RVI是 RISC-V 指令集架构的基础部分,它定义了32位整数运算的核心指令集。RVI 包括 RV32I(32位整数指令集)和 RV64I(64位整数指令集),它们为处理器提供了执行基本计算任务的能力;包括:内存操作指令、逻辑指令、分支和跳转指令、算术指令等等,下面就一一列举。
3.1 内存操作指令
在RISC-V中,内存操作主要通过加载(Load)和存储(Store)两类指令来实现。这些指令允许程序从内存读取数据到寄存器(Load),或将寄存器中的数据写入内存(Store)
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
LB | lb rd, offset(rs1) | 加载字节(符号扩展) | rd = SignExt(Mem[rs1 + offset][7:0]) | RV32I / RV64I |
LBU | lbu rd, offset(rs1) | 加载字节(无符号扩展) | rd = ZeroExt(Mem[rs1 + offset][7:0]) | RV32I / RV64I |
LH | lh rd, offset(rs1) | 加载半字(符号扩展) | rd = SignExt(Mem[rs1 + offset][15:0]) | RV32I / RV64I |
LHU | lhu rd, offset(rs1) | 加载半字(无符号扩展) | rd = ZeroExt(Mem[rs1 + offset][15:0]) | RV32I / RV64I |
LW | lw rd, offset(rs1) | 加载字(RV32I:32位;RV64I:符号扩展至64位) | RV32I: rd = Mem[rs1 + offset][31:0] RV64I: rd = SignExt(Mem[rs1 + offset][31:0]) | RV32I / RV64I |
LWU | lwu rd, offset(rs1) | 加载字(无符号扩展至64位) | rd = ZeroExt(Mem[rs1 + offset][31:0]) | RV64I |
LD | ld rd, offset(rs1) | 加载双字(64位) | rd = Mem[rs1 + offset][63:0] | RV64I |
SB | sb rs2, offset(rs1) | 存储字节 | Mem[rs1 + offset] = rs2[7:0] | RV32I / RV64I |
SH | sh rs2, offset(rs1) | 存储半字 | Mem[rs1 + offset] = rs2[15:0] | RV32I / RV64I |
SW | sw rs2, offset(rs1) | 存储字 | Mem[rs1 + offset] = rs2[31:0] | RV32I / RV64I |
SD | sd rs2, offset(rs1) | 存储双字 | Mem[rs1 + offset] = rs2[63:0] | RV64I |
3.2 算术指令
算术指令狭义定义:仅包含加法、减法及其直接相关的操作,用于寄存器或寄存器与立即数之间的数值运算。
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
基础加减指令 | ||||
ADD | add rd, rs1, rs2 | 加法(忽略溢出) | rd = rs1 + rs2 | RV32I / RV64I |
SUB | sub rd, rs1, rs2 | 减法(忽略溢出) | rd = rs1 - rs2 | RV32I / RV64I |
ADDI | addi rd, rs1, imm | 立即数加法(符号扩展立即数) | rd = rs1 + SignExt(imm) | RV32I / RV64I |
RV64I 扩展加减指令 | ||||
ADDIW | addiw rd, rs1, imm | 立即数加法(32位,符号扩展至64位) | rd = SignExt((rs1 + SignExt(imm))[31:0]) | RV64I |
ADDW | addw rd, rs1, rs2 | 加法(32位,符号扩展至64位) | rd = SignExt((rs1 + rs2)[31:0]) | RV64I |
SUBW | subw rd, rs1, rs2 | 减法(32位,符号扩展至64位) | rd = SignExt((rs1 - rs2)[31:0]) | RV64I |
高位立即数构建指令 | ||||
LUI | lui rd, imm | 加载高位立即数(imm[31:12]) | rd = imm << 12 | RV32I / RV64I |
AUIPC | auipc rd, imm | 将高位立即数与 PC 相加 | rd = PC + (imm << 12) | RV32I / RV64I |
伪指令表格:
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
寄存器操作 | ||||
MV | mv rd, rs | 寄存器间移动值 | addi rd, rs, 0 | RV32I / RV64I |
NEG | neg rd, rs | 取负值(rd = -rs) | sub rd, x0, rs | RV32I / RV64I |
NEGW | negw rd, rs | 取负值(32位操作,符号扩展) | subw rd, x0, rs | RV64I |
立即数操作 | ||||
LI | li rd, imm | 加载任意立即数到寄存器 | 若 imm 在 12 位有符号范围内:addi rd, x0, imm 否则: lui rd, imm[31:12] + addi rd, rd, imm[11:0] | RV32I / RV64I |
地址加载 | ||||
LA | la rd, symbol | 加载绝对地址(链接时解析) | auipc rd, offset_hi + addi rd, rd, offset_lo 或 lui rd, offset_hi + addi rd, rd, offset_lo | RV32I / RV64I |
LLA | lla rd, symbol | 加载本地地址(PC相对,位置无关) | auipc rd, offset_hi + addi rd, rd, offset_lo | RV32I / RV64I |
符号扩展 | ||||
SEXT.W | sext.w rd, rs | 将低32位符号扩展至64位(RV64I) | addiw rd, rs, 0 | RV64I |
空操作 | ||||
NOP | nop | 空操作(无实际效果) | addi x0, x0, 0 | RV32I / RV64I |
3.3 移位指令
移位指令用于对寄存器中的数据进行位级左移或右移,分为以下两类:
-
- 寄存器移位:移位位数由另一个寄存器的低 5 位(RV32I)或低 6 位(RV64I)指定。
-
- 立即数移位:移位位数由指令中的立即数字段直接指定。
- 立即数移位:移位位数由指令中的立即数字段直接指定。
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
逻辑左移 | ||||
SLL | sll rd, rs1, rs2 | 逻辑左移(低位补零) | rd = rs1 << (rs2[4:0]) (RV32I,取低5位)rd = rs1 << (rs2[5:0]) (RV64I,取低6位) | RV32I / RV64I |
SLLI | slli rd, rs1, shamt | 立即数逻辑左移 | rd = rs1 << shamt (shamt范围:RV32I为 0–31,RV64I为 0–63) | RV32I / RV64I |
SLLW | sllw rd, rs1, rs2 | 32位逻辑左移(RV64I,低32位操作) | rd = SignExt((rs1[31:0] << rs2[4:0])) | RV64I |
SLLIW | slliw rd, rs1, shamt | 32位立即数逻辑左移(RV64I) | rd = SignExt((rs1[31:0] << shamt)[31:0]) (shamt范围:0–31) | RV64I |
逻辑右移 | ||||
SRL | srl rd, rs1, rs2 | 逻辑右移(高位补零) | rd = rs1 >> (rs2[4:0]) (RV32I)rd = rs1 >> (rs2[5:0]) (RV64I) | RV32I / RV64I |
SRLI | srli rd, rs1, shamt | 立即数逻辑右移 | rd = rs1 >> shamt | RV32I / RV64I |
SRLW | srlw rd, rs1, rs2 | 32位逻辑右移(RV64I,低32位操作) | rd = SignExt((rs1[31:0] >> rs2[4:0])) | RV64I |
SRLIW | srliw rd, rs1, shamt | 32位立即数逻辑右移(RV64I) | rd = SignExt((rs1[31:0] >> shamt)[31:0]) (shamt范围:0–31) | RV64I |
算术右移 | ||||
SRA | sra rd, rs1, rs2 | 算术右移(高位补符号位) | rd = rs1 >>> (rs2[4:0]) (RV32I)rd = rs1 >>> (rs2[5:0]) (RV64I) | RV32I / RV64I |
SRAI | srai rd, rs1, shamt | 立即数算术右移 | rd = rs1 >>> shamt | RV32I / RV64I |
SRAW | sraw rd, rs1, rs2 | 32位算术右移(RV64I,低32位操作) | rd = SignExt((rs1[31:0] >>> rs2[4:0])) | RV64I |
SRAIW | sraiw rd, rs1, shamt | 32位立即数算术右移(RV64I) | rd = SignExt((rs1[31:0] >>> shamt)[31:0]) (shamt范围:0–31) | RV64I |
3.4 逻辑指令
逻辑指令用于对寄存器中的数据进行按位操作,分为以下两类:
- 1.寄存器-寄存器操作:两个寄存器之间的按位运算。
- 2.寄存器-立即数操作:寄存器与符号扩展后的立即数进行按位运算。
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
按位与操作 | ||||
AND | and rd, rs1, rs2 | 按位与 | rd = rs1 & rs2 | RV32I / RV64Ity-reference |
ANDI | andi rd, rs1, imm | 立即数按位与(符号扩展立即数) | rd = rs1 & SignExt(imm) | RV32I / RV64Ity-reference |
按位或操作 | ||||
OR | or rd, rs1, rs2 | 按位或 | `rd = rs1 | rs2` |
ORI | ori rd, rs1, imm | 立即数按位或(符号扩展立即数) | `rd = rs1 | SignExt(imm)` |
按位异或操作 | ||||
XOR | xor rd, rs1, rs2 | 按位异或 | rd = rs1 ^ rs2 | RV32I / RV64Ity-reference |
XORI | xori rd, rs1, imm | 立即数按位异或(符号扩展立即数) | rd = rs1 ^ SignExt(imm) | RV32I / RV64Ity-reference |
伪指令:
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
NOT | not rd, rs | 按位取反(rd = ~rs) | xori rd, rs, -1 | RV32I / RV64I |
3.5 比较-置位指令
指令根据两个操作数的比较结果设置目标寄存器的值为 1 或 0,用于条件判断和逻辑控制,支持有符号和无符号比较。
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
有符号比较 | ||||
SLT | slt rd, rs1, rs2 | 有符号比较:若 rs1 < rs2,则 rd = 1,否则 rd = 0 | rd = (rs1 < rs2) ? 1 : 0 (有符号比较) | RV32I / RV64Ity-reference |
SLTI | slti rd, rs1, imm | 有符号立即数比较:若 rs1 < SignExt(imm),则 rd = 1 | rd = (rs1 < SignExt(imm)) ? 1 : 0 | RV32I / RV64Ity-reference |
无符号比较 | ||||
SLTU | sltu rd, rs1, rs2 | 无符号比较:若 rs1 < rs2,则 rd = 1 | rd = (rs1 < rs2) ? 1 : 0 (无符号比较) | RV32I / RV64Ity-reference |
SLTIU | sltiu rd, rs1, imm | 无符号立即数比较(立即数符号扩展后按无符号比较):若 rs1 < SignExt(imm),则 rd = 1 | rd = (rs1 < SignExt(imm)) ? 1 : 0 (无符号比较) | RV32I / RV64Ity-reference |
伪指令:
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
零值判断 | ||||
SEQZ | seqz rd, rs | 若 rs == 0,则 rd = 1,否则 0 | sltiu rd, rs, 1 | RV32I / RV64I |
SNEZ | snez rd, rs | 若 rs ≠ 0,则 rd = 1,否则 0 | sltu rd, x0, rs | RV32I / RV64I |
符号判断 | ||||
SLTZ | sltz rd, rs | 若 rs < 0(有符号),则 rd = 1 | slt rd, rs, x0 | RV32I / RV64I |
SGTZ | sgtz rd, rs | 若 rs > 0(有符号),则 rd = 1 | slt rd, x0, rs | RV32I / RV64I |
非零符号判断 | ||||
SLEZ | slez rd, rs | 若 rs ≤ 0(有符号),则 rd = 1 | slt rd, x0, rs → xori rd, rd, 1 | RV32I / RV64I |
SGEZ | sgez rd, rs | 若 rs ≥ 0(有符号),则 rd = 1 | slt rd, rs, x0 → xori rd, rd, 1 | RV32I / RV64I |
3.6 分支指令
分支指令用于控制程序流程,根据条件或地址跳转执行目标代码,均为 B-Type 或 J-Type 格式。
条件分支指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
BEQ | beq rs1, rs2, offset | 若 rs1 == rs2,跳转到 PC + offset | if (rs1 == rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BNE | bne rs1, rs2, offset | 若 rs1 ≠ rs2,跳转到 PC + offset | if (rs1 != rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BLT | blt rs1, rs2, offset | 若 rs1 < rs2(有符号),跳转 | if (rs1 < rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BGE | bge rs1, rs2, offset | 若 rs1 ≥ rs2(有符号),跳转 | if (rs1 >= rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BLTU | bltu rs1, rs2, offset | 若 rs1 < rs2(无符号),跳转 | if (rs1 < rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
BGEU | bgeu rs1, rs2, offset | 若 rs1 ≥ rs2(无符号),跳转 | if (rs1 >= rs2) PC += SignExt(offset << 1) | RV32I / RV64I |
条件分支伪指令
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
BEQZ | beqz rs, offset | 若 rs == 0,跳转到 offset | beq rs, x0, offset | RV32I / RV64I |
BNEZ | bnez rs, offset | 若 rs ≠ 0,跳转到 offset | bne rs, x0, offset | RV32I / RV64I |
BGT | bgt rs1, rs2, offset | 若 rs1 > rs2(有符号),跳转 | blt rs2, rs1, offset | RV32I / RV64I |
BGTU | bgtu rs1, rs2, offset | 若 rs1 > rs2(无符号),跳转 | bltu rs2, rs1, offset | RV32I / RV64I |
BLE | ble rs1, rs2, offset | 若 rs1 ≤ rs2(有符号),跳转 | bge rs2, rs1, offset | RV32I / RV64I |
BLEU | bleu rs1, rs2, offset | 若 rs1 ≤ rs2(无符号),跳转 | bgeu rs2, rs1, offset | RV32I / RV64I |
3.7 跳转指令
跳转指令用于改变程序的执行流程,使程序能够跳转到代码中的其他位置执行
无条件跳转指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 指令集 |
---|---|---|---|---|
JAL | jal rd, offset | 跳转到 PC + offset,并将返回地址存入 rd | rd = PC + 4; PC += SignExt(offset << 1) | RV32I / RV64I |
JALR | jalr rd, offset(rs1) | 跳转到 rs1 + offset,存入返回地址 | rd = PC + 4; PC = (rs1 + SignExt(offset)) & ~1 | RV32I / RV64I |
无条件跳转伪指令
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
J | j offset | 无条件跳转到 offset | jal x0, offset | RV32I / RV64I |
JR | jr rs | 跳转到 rs 指向的地址 | jalr x0, 0(rs) | RV32I / RV64I |
RET | ret | 从函数返回(跳转到 ra 地址) | jalr x0, 0(ra) | RV32I / RV64I |
3.8 同步指令
同步指令用于处理内存访问顺序控制,确保数据一致性和并发安全。
内存屏障指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
FENCE | fence pred, succ | 内存屏障(控制访存顺序) | 确保 pred 操作在 succ 操作前完成 (pred/succ 可以为 r(读)、w(写)、i(指令流)) | RV32I / RV64I |
FENCE.I | fence.i | 指令流同步屏障 | 确保后续指令看到此前所有指令的修改(用于自修改代码) | RV32I / RV64I) |
3.9 环境指令
环境指令用于系统调用、调试、中断处理等特权级操作,通常需在特定权限模式下执行。
系统调用与异常处理指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
ECALL | ecall | 触发环境调用(系统调用/异常) | 根据当前模式跳转到异常处理程序 | RV32I / RV64I |
EBREAK | ebreak | 触发断点异常(用于调试) | 进入调试模式或触发异常处理 | RV32I / RV64I |
中断返回指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
MRET | mret | 从机器模式异常返回 | PC = MEPC; Privilege = MPP | RV32I / RV64I |
SRET | sret | 从监管者模式异常返回 | PC = SEPC; Privilege = SPP | RV32I / RV64I |
URET | uret | 从用户模式异常返回 | PC = UEPC | RV32I / RV64I |
等待与暂停指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
WFI | wfi | 等待中断(暂停执行直至中断发生) | 暂停 CPU 直至中断或事件唤醒 | RV32I / RV64I ) |
3.10 控制状态寄存器指令
指令用于读写处理器的控制状态寄存器(如中断配置、计数器、特权模式设置等),支持原子操作和位操作,适用于系统编程和特权级管理。
CSR 读写指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
CSRRW | csrrw rd, csr, rs1 | 将 rs1 写入 CSR,原值存入 rd | t = CSR[csr]; CSR[csr] = rs1; rd = t | RV32I / RV64I |
CSRRS | csrrs rd, csr, rs1 | 将 rs1 对应位设为 1,原值存入 rd | `t = CSR[csr]; CSR[csr] | = rs1; rd = t` |
CSRRC | csrrc rd, csr, rs1 | 将 rs1 对应位清 0,原值存入 rd | t = CSR[csr]; CSR[csr] &= ~rs1; rd = t | RV32I / RV64I |
CSRRWI | csrrwi rd, csr, imm | 将 5 位立即数写入 CSR | t = CSR[csr]; CSR[csr] = imm; rd = t | RV32I / RV64I |
CSRRSI | csrrsi rd, csr, imm | 将立即数对应位置 1 | `t = CSR[csr]; CSR[csr] | = imm; rd = t` |
CSRRCI | csrrci rd, csr, imm | 将立即数对应位清 0 | t = CSR[csr]; CSR[csr] &= ~imm; rd = t | RV32I / RV64I |
CSR 伪指令
伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|
CSRR | csrr rd, csr | 读取 CSR 的值到寄存器 | csrrs rd, csr, x0 (读 CSR,不修改) | RV32I / RV64I |
CSRW | csrw csr, rs | 将寄存器的值写入 CSR | csrrw x0, csr, rs (丢弃原值,仅写入) | RV32I / RV64I |
CSRS | csrs csr, rs | 设置 CSR 中由 rs 指定的位 | csrrs x0, csr, rs (按位或,不保存结果) | RV32I / RV64I |
CSRC | csrc csr, rs | 清除 CSR 中由 rs 指定的位 | csrrc x0, csr, rs (按位与取反,不保存结果) | RV32I / RV64I |
CSRWI | csrwi csr, imm | 将 5 位立即数写入 CSR | csrrwi x0, csr, imm | RV32I / RV64I |
CSRSI | csrsi csr, imm | 设置 CSR 中由立即数指定的位 | csrrsi x0, csr, imm | RV32I / RV64I |
CSRCI | csrci csr, imm | 清除 CSR 中由立即数指定的位 | csrrci x0, csr, imm | RV32I / RV64I |
4 RVM指令集
RVM 扩展指令分为 乘法指令 和 除法/取余指令,支持有符号和无符号操作,并区分 RV32 和 RV64 的差异。
乘法指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
MUL | mul rd, rs1, rs2 | 乘法(低32/64位结果) | rd = (rs1 * rs2)[31:0] (RV32)rd = rs1 * rs2 (RV64) | RV32M / RV64M |
MULH | mulh rd, rs1, rs2 | 有符号乘法(高32/64位结果) | rd = (rs1 * rs2)[63:32] (RV32)rd = (rs1 * rs2)[127:64] (RV64) | RV32M / RV64M |
MULHU | mulhu rd, rs1, rs2 | 无符号乘法(高32/64位结果) | 同上,操作数为无符号数 | RV32M / RV64M |
MULHSU | mulhsu rd, rs1, rs2 | 有符号-无符号乘法(高32/64位结果) | rs1 有符号,rs2 无符号 | RV32M / RV64M |
MULW | mulw rd, rs1, rs2 | 32位乘法(结果符号扩展至64位) | rd = SignExt((rs1[31:0] * rs2[31:0])) | RV64M |
除法/取余指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
DIV | div rd, rs1, rs2 | 有符号除法(商) | rd = rs1 / rs2 (向零舍入) | RV32M / RV64M |
DIVU | divu rd, rs1, rs2 | 无符号除法(商) | rd = rs1 / rs2 | RV32M / RV64M |
REM | rem rd, rs1, rs2 | 有符号取余(余数) | rd = rs1 % rs2 (符号与 rs1 相同) | RV32M / RV64M |
REMU | remu rd, rs1, rs2 | 无符号取余(余数) | rd = rs1 % rs2 | RV32M / RV64M |
DIVW | divw rd, rs1, rs2 | 32位有符号除法(符号扩展至64位) | rd = SignExt((rs1[31:0] / rs2[31:0])) | RV64M |
DIVUW | divuw rd, rs1, rs2 | 32位无符号除法(零扩展至64位) | rd = ZeroExt((rs1[31:0] / rs2[31:0])) | RV64M |
REMW | remw rd, rs1, rs2 | 32位有符号取余(符号扩展至64位) | rd = SignExt((rs1[31:0] % rs2[31:0])) | RV64M |
REMUW | remuw rd, rs1, rs2 | 32位无符号取余(零扩展至64位) | rd = ZeroExt((rs1[31:0] % rs2[31:0])) | RV64M |
5 RVFD指令集
5.1 访存指令
指令用于在内存和浮点寄存器(f0-f31)之间传输单精度(F 扩展)或双精度(D 扩展)浮点数据:
浮点加载和存储指令
指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|
FLW | flw fd, offset(rs1) | 从内存加载单精度浮点数到浮点寄存器 | fd = F32(Mem[rs1 + offset]) | RV32F / RV64F |
FSW | fsw fs, offset(rs1) | 将单精度浮点数从浮点寄存器存入内存 | Mem[rs1 + offset] = F32(fs) | RV32F / RV64F |
FLD | fld fd, offset(rs1) | 从内存加载双精度浮点数到浮点寄存器 | fd = F64(Mem[rs1 + offset]) | RV64D |
FSD | fsd fs, offset(rs1) | 将双精度浮点数从浮点寄存器存入内存 | Mem[rs1 + offset] = F64(fs) | RV64D |
5.2 算术指令
算术指令用于执行各种数学运算,如加法、减法、乘法、除法等。当涉及到浮点数时,这些操作变得更为复杂,因为它们需要处理指数和尾数部分
基本算术指令
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
加法 | FADD.S | fadd.s fd, fs1, fs2 | 单精度浮点加法 | fd = fs1 + fs2 | RV32F / RV64F |
FADD.D | fadd.d fd, fs1, fs2 | 双精度浮点加法 | fd = fs1 + fs2 | RV64D | |
减法 | FSUB.S | fsub.s fd, fs1, fs2 | 单精度浮点减法 | fd = fs1 - fs2 | RV32F / RV64F |
FSUB.D | fsub.d fd, fs1, fs2 | 双精度浮点减法 | fd = fs1 - fs2 | RV64D | |
乘法 | FMUL.S | fmul.s fd, fs1, fs2 | 单精度浮点乘法 | fd = fs1 * fs2 | RV32F / RV64F |
FMUL.D | fmul.d fd, fs1, fs2 | 双精度浮点乘法 | fd = fs1 * fs2 | RV64D | |
除法 | FDIV.S | fdiv.s fd, fs1, fs2 | 单精度浮点除法 | fd = fs1 / fs2 | RV32F / RV64F |
FDIV.D | fdiv.d fd, fs1, fs2 | 双精度浮点除法 | fd = fs1 / fs2 | RV64D | |
平方根 | FSQRT.S | fsqrt.s fd, fs1 | 单精度浮点平方根 | fd = sqrt(fs1) | RV32F / RV64F |
FSQRT.D | fsqrt.d fd, fs1 | 双精度浮点平方根 | fd = sqrt(fs1) | RV64D | |
最小值 | FMIN.S | fmin.s fd, fs1, fs2 | 单精度浮点最小值 | fd = min(fs1, fs2) | RV32F / RV64F |
FMIN.D | fmin.d fd, fs1, fs2 | 双精度浮点最小值 | fd = min(fs1, fs2) | RV64D | |
最大值 | FMAX.S | fmax.s fd, fs1, fs2 | 单精度浮点最大值 | fd = max(fs1, fs2) | RV32F / RV64F |
FMAX.D | fmax.d fd, fs1, fs2 | 双精度浮点最大值 | fd = max(fs1, fs2) | RV64D |
5.3 RVFD 乘加指令
指令用于执行 乘加融合运算(Fused Multiply-Add, FMA),即在一个操作中完成乘法和加法,通常具有更高的精度和性能
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
单精度乘加 | FMADD.S | fmadd.s fd, fs1, fs2, fs3 | 单精度浮点乘加 | fd = (fs1 * fs2) + fs3 | RV32F / RV64F |
单精度乘减 | FMSUB.S | fmsub.s fd, fs1, fs2, fs3 | 单精度浮点乘减 | fd = (fs1 * fs2) - fs3 | RV32F / RV64F |
单精度负乘加 | FNMADD.S | fnmadd.s fd, fs1, fs2, fs3 | 单精度浮点负乘加 | fd = -((fs1 * fs2) + fs3) | RV32F / RV64F |
单精度负乘减 | FNMSUB.S | fnmsub.s fd, fs1, fs2, fs3 | 单精度浮点负乘减 | fd = -((fs1 * fs2) - fs3) | RV32F / RV64F |
双精度乘加 | FMADD.D | fmadd.d fd, fs1, fs2, fs3 | 双精度浮点乘加 | fd = (fs1 * fs2) + fs3 | RV64D |
双精度乘减 | FMSUB.D | fmsub.d fd, fs1, fs2, fs3 | 双精度浮点乘减 | fd = (fs1 * fs2) - fs3 | RV64D |
双精度负乘加 | FNMADD.D | fnmadd.d fd, fs1, fs2, fs3 | 双精度浮点负乘加 | fd = -((fs1 * fs2) + fs3) | RV64D |
双精度负乘减 | FNMSUB.D | fnmsub.d fd, fs1, fs2, fs3 | 双精度浮点负乘减 | fd = -((fs1 * fs2) - fs3) | RV64D |
5.4 RVFD传送指令
指令用于在 浮点寄存器 和 整数寄存器 之间传输数据,或在不同浮点寄存器之间复制数据
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
浮点到整数 | FMV.X.S | fmv.x.s rd, fs1 | 将单精度浮点数转为整数表示 | rd = fs1 (按位复制) | RV32F / RV64F |
浮点到整数 | FMV.X.D | fmv.x.d rd, fs1 | 将双精度浮点数转为整数表示 | rd = fs1 (按位复制) | RV64D |
整数到浮点 | FMV.S.X | fmv.s.x fd, rs1 | 将整数表示转为单精度浮点数 | fd = rs1 (按位复制) | RV32F / RV64F |
整数到浮点 | FMV.D.X | fmv.d.x fd, rs1 | 将整数表示转为双精度浮点数 | fd = rs1 (按位复制) | RV64D |
5.5 RVFD 转换指令
分两类归纳:浮点寄存器间传送 和 浮点与整数寄存器间传送,涵盖符号操作、位模式复制及特殊值处理
浮点与整数之间的转换
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
浮点 → 整数 | FCVT.W.S | fcvt.w.s rd, fs1 | 单精度浮点转为 32 位有符号整数 | rd = (int32_t)fs1 | RV32F / RV64F |
FCVT.WU.S | fcvt.wu.s rd, fs1 | 单精度浮点转为 32 位无符号整数 | rd = (uint32_t)fs1 | RV32F / RV64F | |
FCVT.L.S | fcvt.l.s rd, fs1 | 单精度浮点转为 64 位有符号整数 | rd = (int64_t)fs1 | RV64F | |
FCVT.LU.S | fcvt.lu.s rd, fs1 | 单精度浮点转为 64 位无符号整数 | rd = (uint64_t)fs1 | RV64F | |
FCVT.W.D | fcvt.w.d rd, fs1 | 双精度浮点转为 32 位有符号整数 | rd = (int32_t)fs1 | RV64D | |
FCVT.WU.D | fcvt.wu.d rd, fs1 | 双精度浮点转为 32 位无符号整数 | rd = (uint32_t)fs1 | RV64D | |
FCVT.L.D | fcvt.l.d rd, fs1 | 双精度浮点转为 64 位有符号整数 | rd = (int64_t)fs1 | RV64D | |
FCVT.LU.D | fcvt.lu.d rd, fs1 | 双精度浮点转为 64 位无符号整数 | rd = (uint64_t)fs1 | RV64D | |
整数 → 浮点 | FCVT.S.W | fcvt.s.w fd, rs1 | 32 位有符号整数转为单精度浮点 | fd = (float)rs1 | RV32F / RV64F |
FCVT.S.WU | fcvt.s.wu fd, rs1 | 32 位无符号整数转为单精度浮点 | fd = (float)rs1 | RV32F / RV64F | |
FCVT.S.L | fcvt.s.l fd, rs1 | 64 位有符号整数转为单精度浮点 | fd = (float)rs1 | RV64F | |
FCVT.S.LU | fcvt.s.lu fd, rs1 | 64 位无符号整数转为单精度浮点 | fd = (float)rs1 | RV64F | |
FCVT.D.W | fcvt.d.w fd, rs1 | 32 位有符号整数转为双精度浮点 | fd = (double)rs1 | RV64D | |
FCVT.D.WU | fcvt.d.wu fd, rs1 | 32 位无符号整数转为双精度浮点 | fd = (double)rs1 | RV64D | |
FCVT.D.L | fcvt.d.l fd, rs1 | 64 位有符号整数转为双精度浮点 | fd = (double)rs1 | RV64D | |
FCVT.D.LU | fcvt.d.lu fd, rs1 | 64 位无符号整数转为双精度浮点 | fd = (double)rs1 | RV64D |
浮点精度之间的转换
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
单精度 ↔ 双精度 | FCVT.S.D | fcvt.s.d fd, fs1 | 双精度浮点转为单精度浮点 | fd = (float)fs1 | RV64D |
单精度 ↔ 双精度 | FCVT.D.S | fcvt.d.s fd, fs1 | 单精度浮点转为双精度浮点 | fd = (double)fs1 | RV64D |
5.6 RVFD 符号注入指令
指令用于将 整数立即数 或 整数寄存器值 注入到浮点寄存器中,通常用于快速构造浮点常数或特殊值(如 NaN、无穷大)
单精度浮点注入指令
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
符号复制 | FSGNJ.S | fsgnj.s fd, fs1, fs2 | 复制数值,符号位取自 fs2 | fd = {fs2[31], fs1[30:0]} | RV32F / RV64F |
符号取反 | FSGNJN.S | fsgnjn.s fd, fs1, fs2 | 复制数值,符号位取反自 fs2 | fd = {~fs2[31], fs1[30:0]} | RV32F / RV64F |
符号取绝对值 | FSGNJX.S | fsgnjx.s fd, fs1, fs2 | 复制数值,符号位异或(取绝对值) | fd = {fs1[31] ^ fs2[31], fs1[30:0]} | RV32F / RV64F |
双精度浮点注入指令
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
符号复制 | FSGNJ.D | fsgnj.d fd, fs1, fs2 | 复制数值,符号位取自 fs2 | fd = {fs2[63], fs1[62:0]} | RV64D |
符号取反 | FSGNJN.D | fsgnjn.d fd, fs1, fs2 | 复制数值,符号位取反自 fs2 | fd = {~fs2[63], fs1[62:0]} | RV64D |
符号取绝对值 | FSGNJX.D | fsgnjx.d fd, fs1, fs2 | 复制数值,符号位异或(取绝对值) | fd = {fs1[63] ^ fs2[63], fs1[62:0]} | RV64D |
伪指令
指令类型 | 伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|---|
单精度浮点注入 | FABS.S | fabs.s fd, fs | 单精度浮点取绝对值 | fsgnjx.s fd, fs, fs | RV32F / RV64F |
FMV.S | fmv.s fd, fs | 单精度浮点复制 | fsgnj.s fd, fs, fs | RV32F / RV64F | |
FNEG.S | fneg.s fd, fs | 单精度浮点取反 | fsgnjn.s fd, fs, fs | RV32F / RV64F |
指令类型 | 伪指令 | 格式 | 功能描述 | 实际转换(基础指令) | 适用指令集 |
---|---|---|---|---|---|
双精度浮点注入 | FABS.D | fabs.d fd, fs | 双精度浮点取绝对值 | fsgnjx.d fd, fs, fs | RV64D |
FMV.D | fmv.d fd, fs | 双精度浮点复制 | fsgnj.d fd, fs, fs | RV64D | |
FNEG.D | fneg.d fd, fs | 双精度浮点取反 | fsgnjn.d fd, fs, fs | RV64D |
5.7 RVFD 比较指令
指令用于比较两个浮点数的值,并将比较结果写入整数寄存器,支持 相等、小于 和 小于等于 三种比较操作
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
相等比较 | FEQ.S | feq.s rd, fs1, fs2 | 单精度浮点相等比较 | rd = (fs1 == fs2) ? 1 : 0 | RV32F / RV64F |
FEQ.D | feq.d rd, fs1, fs2 | 双精度浮点相等比较 | rd = (fs1 == fs2) ? 1 : 0 | RV64D | |
小于比较 | FLT.S | flt.s rd, fs1, fs2 | 单精度浮点小于比较 | rd = (fs1 < fs2) ? 1 : 0 | RV32F / RV64F |
FLT.D | flt.d rd, fs1, fs2 | 双精度浮点小于比较 | rd = (fs1 < fs2) ? 1 : 0 | RV64D | |
小于等于比较 | FLE.S | fle.s rd, fs1, fs2 | 单精度浮点小于等于比较 | rd = (fs1 <= fs2) ? 1 : 0 | RV32F / RV64F |
FLE.D | fle.d rd, fs1, fs2 | 双精度浮点小于等于比较 | rd = (fs1 <= fs2) ? 1 : 0 | RV64D |
5.8 RVFD 分类指令
指令用于检查浮点数的类别(如正无穷、负零、NaN 等),并将结果写入整数寄存器,适用于浮点数的异常处理和特殊值检测
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
浮点分类 | 单精度分类 | fclass.s rd, fs1 | 单精度浮点分类 | rd = classify(fs1) | RV32F / RV64F |
浮点分类 | 双精度分类 | fclass.d rd, fs1 | 双精度浮点分类 | rd = classify(fs1) | RV64D |
5.9 RVFD 配置指令
指令用于配置和管理浮点单元的状态,包括 舍入模式、异常标志 和 浮点控制状态寄存器(fcsr) 的操作
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
浮点控制状态寄存器(fcsr)操作 | |||||
读取 fcsr | FRCSR | frcsr rd | 读取 fcsr 的值到整数寄存器 | rd = fcsr | RV32F / RV64F |
写入 fcsr | FSCSR | fscsr rd, rs | 将整数寄存器的值写入 fcsr | fcsr = rs | RV32F / RV64F |
交换 fcsr | FSRCS | fscsr rd, rs | 交换 fcsr 和整数寄存器的值 | t = fcsr; fcsr = rs; rd = t | RV32F / RV64F |
舍入模式配置 | |||||
读取舍入模式 | FRRM | frrm rd | 读取舍入模式到整数寄存器 | rd = fcsr[7:5] | RV32F / RV64F |
写入舍入模式 | FSRM | fsrm rd, rs | 将整数寄存器的值写入舍入模式 | fcsr[7:5] = rs[2:0] | RV32F / RV64F |
交换舍入模式 | FSRRM | fsrrm rd, rs | 交换舍入模式和整数寄存器的值 | t = fcsr[7:5]; fcsr[7:5] = rs[2:0]; rd = t | RV32F / RV64F |
异常标志操作 | |||||
读取异常标志 | FFLAGS | fflags rd | 读取异常标志到整数寄存器 | rd = fcsr[4:0] | RV32F / RV64F |
写入异常标志 | FSFLAGS | fsflags rd, rs | 将整数寄存器的值写入异常标志 | fcsr[4:0] = rs[4:0] | RV32F / RV64F |
交换异常标志 | FSRFLAGS | fsrflags rd, rs | 交换异常标志和整数寄存器的值 | t = fcsr[4:0]; fcsr[4:0] = rs[4:0]; rd = t | RV32F / RV64F |
6 RVA指令集
RVA(Atomic Operations)扩展为 RISC-V 提供了硬件支持的原子操作指令,用于在多线程或多核环境中实现 原子内存访问 和 同步操作,确保数据一致性和并发安全。
加载保留与条件存储指令
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
加载保留 | LR.W | lr.w rd, (rs1) | 加载保留(原子加载字,标记内存地址) | rd = Mem[rs1]; Reserve rs1 | RV32A / RV64A |
LR.D | lr.d rd, (rs1) | 加载保留(原子加载双字) | rd = Mem[rs1]; Reserve rs1 | RV64A | |
条件存储 | SC.W | sc.w rd, rs2, (rs1) | 条件存储(若地址未被修改,存储字) | if (Reserve rs1 still valid) { Mem[rs1] = rs2; rd = 0 } else { rd = 1 } | RV32A / RV64A |
SC.D | sc.d rd, rs2, (rs1) | 条件存储(若地址未被修改,存储双字) | if (Reserve rs1 still valid) { Mem[rs1] = rs2; rd = 0 } else { rd = 1 } | RV64A |
原子内存操作指令
指令类型 | 指令 | 格式 | 功能描述 | 操作(伪代码) | 适用指令集 |
---|---|---|---|---|---|
原子加 | AMOADD.W | amoadd.w rd, rs2, (rs1) | 原子加并返回原值 | rd = Mem[rs1]; Mem[rs1] += rs2 | RV32A / RV64A |
AMOADD.D | amoadd.d rd, rs2, (rs1) | 原子加并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] += rs2 | RV64A | |
原子交换 | AMOSWAP.W | amoswap.w rd, rs2, (rs1) | 原子交换并返回原值 | rd = Mem[rs1]; Mem[rs1] = rs2 | RV32A / RV64A |
AMOSWAP.D | amoswap.d rd, rs2, (rs1) | 原子交换并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] = rs2 | RV64A | |
原子按位与 | AMOAND.W | amoand.w rd, rs2, (rs1) | 原子按位与并返回原值 | rd = Mem[rs1]; Mem[rs1] &= rs2 | RV32A / RV64A |
AMOAND.D | amoand.d rd, rs2, (rs1) | 原子按位与并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] &= rs2 | RV64A | |
原子按位或 | AMOOR.W | amoor.w rd, rs2, (rs1) | 原子按位或并返回原值 | `rd = Mem[rs1]; Mem[rs1] | = rs2` |
AMOOR.D | amoor.d rd, rs2, (rs1) | 原子按位或并返回原值(双字) | `rd = Mem[rs1]; Mem[rs1] | = rs2` | |
原子按位异或 | AMOXOR.W | amoxor.w rd, rs2, (rs1) | 原子按位异或并返回原值 | rd = Mem[rs1]; Mem[rs1] ^= rs2 | RV32A / RV64A |
AMOXOR.D | amoxor.d rd, rs2, (rs1) | 原子按位异或并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] ^= rs2 | RV64A | |
原子最大值 | AMOMAX.W | amomax.w rd, rs2, (rs1) | 原子有符号最大值并返回原值 | rd = Mem[rs1]; Mem[rs1] = max(rd, rs2) | RV32A / RV64A |
AMOMAX.D | amomax.d rd, rs2, (rs1) | 原子有符号最大值并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] = max(rd, rs2) | RV64A | |
原子无符号最大值 | AMOMAXU.W | amomaxu.w rd, rs2, (rs1) | 原子无符号最大值并返回原值 | rd = Mem[rs1]; Mem[rs1] = maxu(rd, rs2) | RV32A / RV64A |
AMOMAXU.D | amomaxu.d rd, rs2, (rs1) | 原子无符号最大值并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] = maxu(rd, rs2) | RV64A | |
原子最小值 | AMOMIN.W | amomin.w rd, rs2, (rs1) | 原子有符号最小值并返回原值 | rd = Mem[rs1]; Mem[rs1] = min(rd, rs2) | RV32A / RV64A |
AMOMIN.D | amomin.d rd, rs2, (rs1) | 原子有符号最小值并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] = min(rd, rs2) | RV64A | |
原子无符号最小值 | AMOMINU.W | amominu.w rd, rs2, (rs1) | 原子无符号最小值并返回原值 | rd = Mem[rs1]; Mem[rs1] = minu(rd, rs2) | RV32A / RV64A |
AMOMINU.D | amominu.d rd, rs2, (rs1) | 原子无符号最小值并返回原值(双字) | rd = Mem[rs1]; Mem[rs1] = minu(rd, rs2) | RV64A |
上面列举了RISC-V指令集,但实际上上面列举的指令集我很多也没用过,是按照spec总结了下,如有错误或者遗漏,还请各位大佬评论区指出。
参考
riscv-spec-20240411.pdf
一起学RISC-V汇编第5讲之常用指令及伪指令列表
RISC-V 常用汇编指令
相关文章:

RISC-V汇编学习(三)—— RV指令集
有了前两节对于RISC-V汇编、寄存器、汇编语法等的认识,本节开始介绍RISC-V指令集和伪指令。 前面说了RISC-V的模块化特点,是以RV32I为作为ISA的核心模块,其他都是要基于此为基础,可以这样认为:RISC-V ISA 基本整数指…...

OpenCV连续数字识别—可运行验证
前言 文章开始,瞎说一点其他的东西,真的是很离谱,找了至少两三个小时,就一个简单的需求: 1、利用OpenCV 在Windows进行抓图 2、利用OpenCV 进行连续数字的检测。 3、使用C,Qt 3、将检测的结果显示出来 …...

Python中与字符串操作相关的30个常用函数及其示例
以下是Python中与字符串操作相关的30个常用函数及其示例: 1. str.capitalize() 将字符串的第一个字符大写,其余字符小写。 s "hello world" print(s.capitalize()) # 输出: Hello world2. str.lower() 将字符串中的所有字符转换为小写。…...

007-Property在C++中的实现与应用
Property在C中的实现与应用 以下是在C中实现属性(Property)的完整实现方案,结合模板技术和运算符重载实现类型安全的属性访问,支持独立模块化封装: #include <iostream> #include <functional>template<typename HostType, t…...

【实战篇】【DeepSeek 全攻略:从入门到进阶,再到高级应用】
凌晨三点,某程序员在Stack Overflow上发出灵魂拷问:“为什么我的DeepSeek会把财务报表生成成修仙小说?” 这个魔性的AI工具,今天我们就来场从开机键到改造人类文明的硬核教学。(文末含高危操作集锦,未成年人请在师父陪同下观看) 一、萌新村任务:把你的电脑变成炼丹炉 …...

clickhouse属于国产吗
《ClickHouse:探索其背景与国内的应用实例》 当我们谈论数据库技术时,ClickHouse是一个绕不开的话题。很多人可能会好奇,ClickHouse是否属于国产软件呢?答案是,虽然ClickHouse最初并非在中国开发,但这款列…...

ESP32 UART select解析json数据,上位机控制LED灯实验
前言: 本实验的目的主要是通过上位机通过UART来控制ESP32端的LED的点亮以及熄灭,整个项目逻辑比较简单,整体架构如下: 上位机(PC)主要是跑在PC端的一个软件,主要作用包含: 1)串口相关配置&…...

K8S 集群搭建——cri-dockerd版
目录 一、工作准备 1.配置主机名 2.配置hosts解析 3.配置免密登录(只需要在master上操作) 4.时间同步(每台节点都要做,必做,否则可能会因为时间不同步导致集群初始化失败) 5.关闭系统防火墙 6.配置…...

基于Python的电商销售数据分析与可视化系统实
一、系统架构设计 1.1系统流程图 #mermaid-svg-Pdo9oZWrVHNuOoTT {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Pdo9oZWrVHNuOoTT .error-icon{fill:#552222;}#mermaid-svg-Pdo9oZWrVHNuOoTT .error-text{fill:#5…...

学习笔记:Python网络编程初探之基本概念(一)
一、网络目的 让你设备上的数据和其他设备上进行共享,使用网络能够把多方链接在一起,然后可以进行数据传递。 网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信。 二、IP地址的作用 用来标记唯一一台电脑…...

高效处理 List<T> 集合:更新、查找与优化技巧
引言 在日常开发中,List<T> 是我们最常用的数据结构之一。无论是批量更新数据、查找特定项还是进行复杂的集合操作,掌握 List<T> 的高级用法可以显著提高代码的效率和可读性。本文将详细介绍如何使用 List<T> 进行批量更新、查找匹配项以及优化性能的方法…...

HTML5(Web前端开发笔记第一期)
p.s.这是萌新自己自学总结的笔记,如果想学习得更透彻的话还是请去看大佬的讲解 目录 三件套标签标题标签段落标签文本格式化标签图像标签超链接标签锚点链接默认链接地址 音频标签视频标签 HTML基本骨架综合案例->个人简介列表表格表单input标签单选框radio上传…...

Windows控制台函数:标准输入输出流交互函数GetStdHandle()
目录 什么是 GetStdHandle? 它长什么样? 怎么用它? 它跟 std::cout 有什么不一样? GetStdHandle 是一个 Windows API 函数,用于获取标准输入、标准输出或标准错误设备的句柄。它定义在 Windows 的核心头文件 <…...

Vue3 中 Computed 用法
Computed 又被称作计算属性,用于动态的根据某个值或某些值的变化,来产生对应的变化,computed 具有缓存性,当无关值变化时,不会引起 computed 声明值的变化。 产生一个新的变量并挂载到 vue 实例上去。 vue3 中 的 com…...

常见的三种锁
一、互斥锁 互斥锁 Mutex 保证在任意时刻只有一个线程能够进入被保护的临界区。当一个线程获取到互斥锁后,其他线程若要进入临界区就会被阻塞,直到该线程释放锁。 互斥锁是一种阻塞锁,当线程无法获取到锁时,会进入阻塞状态。 应…...

离线文本转语音库pyttsx3(目前接触到的声音效果最好的,基本上拿来就能用)
在现代应用程序中,文本转语音(Text-to-Speech, TTS)技术越来越受到重视。无论是为视力障碍人士提供帮助,还是为教育和娱乐应用增添趣味,TTS 都能发挥重要作用。今天,我们将介绍一个简单易用的 Python 库——…...

LeetCode Hot100刷题——反转链表(迭代+递归)
206.反转链表 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1]示例 2: 输入:head [1,2] 输出:[2,1]示例 3&#…...

JJJ:linux sysfs相关
文章目录 1.sysfs(属性)文件的创建、读、写1.1 创建流程1.2 open流程1.3 read流程 2.补充2.1 sysfs下常见目录介绍2.2 属性相关2.2.1 简介2.2.2 attribute文件的创建 2.3 sysfs目录如何创建的 1.sysfs(属性)文件的创建、读、写 1…...

Leetcode 刷题记录 06 —— 矩阵
本系列为笔者的 Leetcode 刷题记录,顺序为 Hot 100 题官方顺序,根据标签命名,记录笔者总结的做题思路,附部分代码解释和疑问解答。 目录 01 矩阵置零 方法一:标记数组 方法二:两个标记变量 02 螺旋矩阵…...

什么样的物联网框架适合开展共享自助KTV唱歌项目?
现在物联网的广泛应用,也让更多用户们看到了它的实力,也使得共享经济遍地开花。其中共享自助唱歌设备也备受欢迎,那么适合开展共享自助KTV唱歌项目的物联网框架都应具备哪些特点呢? 智能化与自动化管理 物联网技术在共享KTV中的应…...

【Academy】HTTP Host 标头攻击 ------ HTTP Host header attacks
HTTP Host 标头攻击 ------ HTTP Host header attacks 1. 什么是 HTTP Host 标头?2. 什么是 HTTP Host 标头攻击?3. HTTP Host 标头漏洞是如何产生的?4. 如何测试 HTTP Host 标头漏洞4.1 提供任意 Host 标头4.2 检查有缺陷的验证4.3 发送不明…...

Web基础:HTML快速入门
HTML基础语法 HTML(超文本标记语言) 是用于创建网页内容的 标记语言,通过定义页面的 结构和内容 来告诉浏览器如何呈现网页。 超文本(Hypertext) 是一种通过 链接(Hyperlinks) 将不同文本、图像…...

技术领域,有许多优秀的博客和网站
在技术领域,有许多优秀的博客和网站为开发者、工程师和技术爱好者提供了丰富的学习资源和行业动态。以下是一些常用的技术博客和网站,涵盖了编程、软件开发、数据科学、人工智能、网络安全等多个领域: 1. 综合技术博客 1.1 Medium 网址: ht…...

k8s概念及k8s集群部署(Centos7)
Centos7部署k8s集群 部署之前,先简单说下k8s是个啥: 一、k8s简介: k8s,全称:kubernetes,它可以看作是一个分布式系统支撑平台。k8s的作用: 1、故障自愈: k8s这个玩意可以监控容器…...

《DeepSeek-V3:动态温度调节算法,开启推理新境界!》
在人工智能领域不断探索的征程中,DeepSeek-V3以其卓越的创新技术,尤其是动态温度调节算法,成为了备受瞩目的焦点。这项算法犹如一把神奇的钥匙,巧妙地开启了推理速度与精度动态平衡的大门,为大语言模型的发展开辟了新的…...

Python从入门到精通1:FastAPI
引言 在现代 Web 开发中,API 是前后端分离架构的核心。FastAPI 凭借其高性能、简洁的语法和自动文档生成功能,成为 Python 开发者的首选框架。本文将从零开始,详细讲解 FastAPI 的核心概念、安装配置、路由设计、请求处理以及实际应用案例&a…...

fastapi+angular停车管理系统可跨域
说明: 我计划用fastapiangular做一款停车管理系统,支持跨域 1.设计mysql数据库表, 2.建表,添加测试数据,多表查询, 3.在fastapi写接口查询数据, 4.用postman测试, 5.在angular前端展…...

前端题目类型
HTMLCSS常见面试题 HTML标签有哪些行内元素 img、picture、span、input、textarea、select、label 说说你对元素语义化的理解 元素语义化就是用正确的元素做正确的事情。虽然理论上所有html元素都可通过css样式实现相同效果,但这样会使事情复杂化,所以需…...

openwrt路由系统------lua、uci的关系
1. Luci 的核心组成 (1) Lua 简介:Luci 的界面和逻辑几乎完全使用 Lua 脚本语言编写。Lua 是一种轻量级、高效的嵌入式脚本语言,适合在资源受限的路由器环境中运行。作用: 生成动态 Web 页面(与后端交互渲染 HTML)。处理用户提交的表单数据(如修改 Wi-Fi 密码)。调用系…...

Elastic:AI 会开始取代网络安全工作吗?
作者:来自 Elastic Joe DeFever 不会,但它正在从根本上改变这些工作。 生成式 AI (GenAI) 正迅速成为日常安全工作流程中的一个重要组成部分。那么,它是合作伙伴还是竞争对手? GenAI 技术在安全堆栈几乎每个方面的广泛应用&#…...