在调用函数f前,先做了一步将函数f的两个参数放入寄存器a1,a0中。这是因为寄存器a1,a0是调用者保存寄存器(a调用b的话,由a函数来管理调用者保存寄存器的内容) 调用函数f时,将保存着函数参数的a1,a0寄存器压入栈中。 这时我们可以发现,当一个参数寄存器(形式为ax)保存一个数后必定会先将其压入栈中再执行其他操...
swsp.n:将一个值推入堆栈的特定位置,并指定要使用的内存大小。例如,swsp.n s1, 16(sp) 将寄存器s1的值推入堆栈的第16个位置,并使用小端字节序存储。 这些指令通常用于函数调用、局部变量存储等场景。请注意,这只是RISC-V架构中的一部分压栈指令,具体的指令集和语法可能会因不同的实现而有所不同。©...
以CH32V103 printf函数调用为例,其反汇编代码如下: 000007a4 : 7a4: 7139 addi sp,sp,-64 # 调整堆栈指针sp,分配64字节的栈空间 7a6: da3e sw a5,52(sp) # 压栈,保存a5寄存器的值 7a8: d22e sw a1,36(sp) # 压栈,按需保存相应的寄存器 7aa: d432 sw a2,40(sp) 7ac: d636 sw a3,44(sp...
mscratch,sp”,返回时恢复了线程的堆栈指针“csrrw sp,mscratch,sp”中断堆栈指针初始值是在任务开始时存入mscratch寄存器的,如果采用C形式中断函数,中断堆栈的获取会在压栈操作之后,中断压入的堆栈是当前运行任务的任务堆栈区域,如果想要中断函数压栈时压入的自己的堆栈区域,可以使用汇编入口,进中断...
由RISC-V寄存器的个数是有限的,而函数是非常多的,调用路径可能非常长,这么多函数共用有限的寄存器,怎么样才能安全的访问寄存器呢?最安全的做法是,每次调用其它的函数前把寄存器值保存到栈中,等从子函数返回后,再将寄存器的值出栈,恢复函数调用前的状态,通过这个办法,各个函数就都可以随意使用所有寄存器了。
函数调用时,如果函数参数和局部变量很多,寄存器放不下,需要开辟栈空间存储。 中断发生时,栈空间用于存放当前执行程序的现场数据(下一条指令地址、各种缓存数据),以便中断结束后恢复现场。 3、堆栈大小定义 RISC-V MCU的堆栈大小通常在ld链接脚本中定义,关于ld链接脚本可查看该文:RISC-V MCU ld链接脚本说明。
RISC-V 没有多寄存器的 Load/Store 指令,所以压栈/出栈一个寄存器就是一条指令,而Cortex-M 有多寄存器的 Push/Pop 指令,一般情况下进入函数一条 Push,退出函数一条Pop,虽然在执行速度上没有什么区别,但是指令空间上 RISC-V 比 Cortex-M 占用更多,而 RISC-V 的设计则是简化了执行单元的设计。多寄存器的 Loa...
其实直接在函数进入或者碰到浮点指令时压栈mstatus就行了,问题又来了 1) 如果调用深度过深,会浪费不少线程栈,ret前要判断一次,不太简洁。 2)最主要的是,如果线程处于用户模式,是无法访问 mstatus CSR 寄存器的。 或许基于上面原因,编译器并不会帮你保存恢复mstatus.fs状态,mstatus.fs的改变是纯指令触发的硬件...
函数填充了下一个tick的值。 3.4 开启中断 中断的开启通过sstatus全局的状态寄存器设置。 通过设置SIE位就可以达到使能或者关闭中断的作用。 voidinterrupt_enable(void) { w_sstatus(r_sstatus()|SSTATUS_SIE); } 3.5 中断处理 中断处理需要保存当前的上下文寄存器(寄存器压栈操作),然后跳转到中断处理函数去处理具体...