1. load/store 存储器访问指令
该指令是RISCV架构专门用来访问存储器的指令,其他任何指令均无法访问存储器。一般load采用I型指令格式,store采用S型指令格式。有效字节地址是通过将寄存器rs1与符号扩展的12位偏移量相加而获得的。Load指令将存储器中的一个值复制到寄存器rd中。 Store指令将寄存器rs2中的值复制到存储器中。load/store指令是让寄存器和存储器进行数据交换,虽然不存在运算,但是都会经过完整的数据通路。
- 举例说明指令执行过程:
例如sw rs2, imm(rs1)
即为将rs2寄存器中存放的值保存到rs1寄存器值加上立即数imm值得到的相加结果的内存地址的内存单元
- 在当前时钟下的PC值建立后,PC值被存入指令存储器和加法单元。加法单元得到PC+4;
- 根据当前PC值从指令存储器中(Icache)取出指令机器码,根据机器码中的寄存器编号直接访问寄存器文件,其中指令中立即数字段送给立即数生成单元,指令的机器码送给控制器;
-
控制器获得机器码后根据指令编码格式进行译码,产生控制信号,其中
PC选择信号PCSel为0,
立即数编码选择信号ImmSel为S(表明为Store指令),控制立即数生成单元生成S型立即数编码,
由于sw指令没有写回寄存器的操作,所以写使能端信号RegWEn为0,
写回选择信号WBSel也为*,表示不影响结果;
sw不涉及操作数的比较,因此对分支比较器的控制信号BrUn和比较结果信号BrLT、BrEq都无作用;
B操作数选择信号Bsel为1,选择立即数生成单元输出的立即数值接入ALU的B操作数端口,
A操作数选择信号Asel为0,选择寄存器文件输出的DataA接入ALU的A操作端口;
ALU的控制信号ALUSel为add,控制ALU输出加法运算结果,作为数据存储器的访问地址值;
数据存储器读写控制信号MemRW=write,表示写使能有效;使接入存储器输入数据段的寄存器文件原寄存器2的内容保存到存储器中。 - 最后下一时钟上升沿到来时,将更新的PC+4值写入到PC寄存器,同时原寄存器2的内容写入到数据存储器中。
2. 多线程“上锁”——原子指令
-
“锁”的概念
假设一个场景如core1,core2共享一片数据区间,但是同一时间只有一个core能够独占此数据区间,为避免两core同时发送请求导致竞争现象,于是二者约定了一个共享的全局变量作为“锁”。该变量在硬件上的本质是在存储器中分配一个地址保存该变量的值(core1和core2均能访问)。“上锁”过程:
1)当某个core独占共享数据区并完成相关操作后,便会释放该数据区,通过向锁中写0将其释放。
2)没有独占数据区的core都会不断的读锁中的值,判断是否空闲。若读到的值为0(空闲),便会向锁中写入1进行上锁 - 解决“上锁”问题的方法
- 原子操作(AMO)
为解决上述竞争问题,可引入原子操作,即第一次读(发现锁空闲)和下一次写操作(写入1)成为一个整体,这样当发送读请求的后即上锁,其他core的请求便无效,即读出-计算-写回。操作过程:
1)使用原子指令将锁中的值读出,并向锁中写入数值1。该过程为一个整体性的原子操作,读和写操作间其他核不会访问到锁
2)其他core读锁值,若为1则继续读值,若为0,由于原子操作已向其写入1则可以独占。
例如amoadd.w rd, rs2, (rs1) 该指令用于从地址为寄存器rs1值的存储器中读出一个值,存放到rd寄存器中,并且将读出的数据与rs2寄存器值进行计算(相加),将结果存放到rd寄存器中 - 互斥操作(LR/SC指令)
虽然原子操作能解决多线程的竞争问题,但由于会将总线锁住,导致其他核无法访问总线,在核数众多且频发抢锁的情况下,会造成总线长期被锁的情况,因此引入一种新的互斥类型的存储器访问指令,即LR/SC指令。
LR指令用于从存储器(地址为rs1寄存器的值指定)中读一个长度为XLEN的数据存放到rd寄存器中。
SC指令用于向存储器(地址为rs1寄存器的值指定)中写入一个长度为XLEN的数据,数据的值来自于rs2寄存器中的值。SC指令需要一定条件才能执行成功:1)LR/SC成对访问相同地址;2)LR/SC间没有任何其他的写操作(来自于任何一个hart)访问过相同的地址;3)LR/SC指令间没有中断核异常发生;4)LR/SC间没有执行MRET指令
如果执行成功则向rd寄存器写回数值0;若失败则向rd寄存器写回一个非零值。
LR/SC访问存储器地址必须32位对齐,否则会产生地址非对齐异常。
3. 存储器屏障指令
fence指令用于屏蔽"数据"存储器执行的顺序。