system: [SYSTEM]

user: 4. 基本整数指令 4.1. 单字节指令 该类指令没有操作数，只有操作码，因此只有一个字节，如表1所示。其中全0的操作码用于检查非法指令，这在错误使用数据区作为指令区时就容易出现。WFI指令为休眠指令，此时处理器主动休眠，等待外部中断唤醒，这便于降低功耗。NOP指令为无操作状态，相当于暂停，不进行任何操作，可用于等待，此时功耗较休眠状态高，好处是可立即恢复到工作状态。ECALL指令和ERET指令用于系统中断的调用和返回，所需的参数由系统的一些特殊寄存器给出。EBRK指令用于程序调试，便于主动产生一个调试异常。在正常的指令执行序列下，用中断和异常管理外部突发的事件。中断可用4位定义中断级别，4位定义中断类型，合成1个字节。异常也可称为软中断，也可用1个字节来管理级别和类型。 Table 1 Single byte instruction 编号 名称 格式 长 说明 0 错误 ERR 1 为非法指令，便于检查 1 休眠 WFI 1 主动休眠，等待中断唤醒 2 空闲状态 NOP 1 无操作，暂停状态 3 系统调用 ECALL 1 发起系统中断或异常调用 4 系统返回 ERET 1 系统中断和异常调用返回 5 产生断点异常 EBRK 1 发起断点异常调用，进入调试模式 6 获得寄存器窗口 NXTW 1 获得一个新的寄存器窗口 7 回退寄存器窗口 BCKW 1 放弃当前寄存器窗口，回退到上一窗口 表1. 单字节指令 NXTW指令和BCKW指令用于寄存器窗口调度，窗口的范围用当前位置和末尾位置来标识。如果当前位置增加后与末尾位置相同，则发生上溢，而当前位置减少后与末尾位置相同，则发生下溢，之间的部分即为空闲窗口。通常情况下，NXTW指令将当前寄存器窗口的指针移动到下一个位置即可，如果产生上溢，则需要将已被占用的窗口内的寄存器值保存到内存后，才得到可用的寄存器窗口。BCKW指令将窗口的当前位置回退一个位置，如果发生下溢，则需要将内存中的寄存器值读回，才是正确的当前窗口。由于有内存作为后备，因此寄存器窗口并不需太多，用4位来表示即可，即最多实现16个寄存器窗口。每个窗口实现8个输入寄存器，8个输出寄存器，16个局部寄存器，相邻窗口的输入寄存器和输出寄存器重叠，因此实际每个窗口只占用24个寄存器。在特殊情况下，即只有一个寄存器窗口时，NXTW指令和BCKW指令相当于“保存现场”和“恢复现场”的操作，使用该指令可以简化子程序调用，当然也可自行实现寄存器值的保存和恢复操作，便于更灵活控制需要保存的寄存器数量。局部寄存器窗口的调度方法可同样用于全局寄存器，使得通用寄存器的地址编码虽只有1个字节，但能突破范围限制，这对于一些应用来说也许是必要的。 4.2. 双字节指令 该部分指令只需要两个字节，用来读取一些重要的系统状态，如表2所示。在处理器内部设置一个主频节拍计数器，用于高精度计时，处理器一个频率周期计数一次。用一个40位特殊寄存器来保存节拍计数，在计数一定间隔时产生一个中断，这时可以检查系统中的等待任务，RDCYC指令可读取该计数。另外为准确计时的需要，设置时钟计数器，频率比主频低，用一个40位寄存器来保存计数，每隔一定计数产生一次中断，可处理一些低优先级的中断或异常，RDTIME指令读取该时钟计数。为节省硬件成本，特殊情况下可由主频计数器中断来设置时钟计数器。另外设置程序执行指令计数器，为40位特殊寄存器，可以用RDPC读取当前的指令计数器值。 Table 2 Double byte instruction 编号 名称 格式 长 说明 8 读取主频计数 RDCYC:rd 2 读取频率计数器值，放置到rd中 9 读取时钟计数 RDTIME:rd 2 读取时钟计数器值，放置到rd中 10 读取指令计数 RDPC:rd 2 读取当前指令的程序计数器值到rd中 11 读取堆栈栈顶 RDSTK:rd 2 读取堆栈栈顶指针到rd中 12 设置堆栈栈顶 WRSTK:rs 2 将寄存器rs中内容设置为栈顶指针 13 增减堆栈栈顶 INCSTK:imm 2 将堆栈的栈顶指针增加立即数imm 14 计数加1 INC:rd 2 计算[rd]+=1 15 计数减1 DEC:rd 2 计算[rd]-=1 表2. 双字节指令 设置40位的堆栈栈顶指针特殊寄存器，该指针指向内存地址，读取时用指令RDSTK，设置时用指令WRSTK，便于切换不同的堆栈空间。移动栈顶指针用指令INCSTK，一次移动的量为1个字节，为有符号立即数，因此分配或释放的最大值为127字节。使用时可以灵活采用向下堆栈或向上堆栈，分配空间后，采用内存读写指令在内存堆栈和寄存器之间移动数据。 由于递增和递减操作经常使用，故定义了加1指令INC和减1指令DEC。 4.3. 载入存储指令 载入存储指令负责寄存器与内存之间的数据交换，有单字(五字节)、双字(十字节)和多字节的读写指令，如表3所示。要求对某个处理核心，读写顺序严格按照指令的先后顺序执行，即使用按序一致性模型，这样无需使用存储器屏障指令。多核心的并行调度采用特定的存储器读写原子指令来完成。 Table 3 Load-Save instruction 编号 名称 格式 长 说明 80 载入五字节 LF: rd， rs1，imm[15:0] 5 以[rs1]+imm为地址，载入五个字节到rd寄存器中 81 载入十字节 LT: rd， rs1，imm[15:0] 5 以[rs1]+imm为地址，将十个字节载入rd中，若rd寄存器已满，则按顺序移到下一位置 24 载入多字节 LB: rd， rs1， len 4 以[rs1]为初始地址，连续载入len个字节到rd寄存器中，若rd寄存器已满，则按顺序移到下一位置 82 存储五字节 SF: rs2， rs1，imm[15:0] 5 以[rs1]+imm为地址，将rs2中五个字节存入存储器 83 存储十字节 ST: rs2， rs1，imm[15:0] 5 以[rs1]+imm为地址，将rs2中十个字节存入存储器 25 存储多字节 SB: rs2， rs1， len 4 以[rs1]为初始地址，连续将rs2中len个字节存入存储器，若rs2已读完，则按顺序移到下一位置 表3. 载入存储指令 4.4. 整数加减指令 基本整数指令包含40位整数的加减和复制操作，如表4所示。对40位无符号数，表示范围为0~2 40 −1，即0~1099511627775，对40位有符号数，最高位为符号位，表示范围为−549755813887~549755813887。实现时，根据整数的最高位来判断正负，负整数用补码的形式表示，因此无符号整数和有符号整数的加法形式一样，不需要区分。结合填充立即数指令LUI和立即数加法指令ADDI，可以对40位的整数立即数进行处理。对于程序中循环变量一次增减大于1的情况，用自加操作INCB处理，立即数imm为8位，可正可负，范围为−127~127。利用补码，立即数减法可转化为加法进行。 Table 4 Integer addition and subtraction instruction 编号 名称 格式 长 说明 26 加法 ADD: rd， rs1， rs2 4 计算[rd]=[rs1]+[rs2] 27 减法 SUB: rd， rs1， rs2 4 计算[rd]=[rs1]-[rs2] 84 立即数加法 ADDI: rd， rs1， imm[15:0] 5 计算[rd]=[rs1]+imm，imm为16位立即数 85 填充立即数 LUI: rd， imm[23:0] 5 将24位立即数imm左移16位(低位补0)，放置到rd寄存器中 16 自加操作 INCB: rd， imm 3 计算[rd]+=imm，imm为8位立即数 17 复制内容 MOV: rd， rs1 3 将rs1寄存器内容复制到rd寄存器中 表4. 整数加减指令 4.5. 整数乘除指令 整数的乘除运算指令包含了相乘、相除、求余数等功能，如表5所示。如果希望得到两个40位整数相乘的完整80位结果，可以融合两条指令连续执行“MUL:rd， rs1， rs2；MULH[U]: rd+1， rs1， rs2”，此处将80位结果的小端部分放在前，大端部分放在后，便于40位整数和80位整数的相互转换，无需特别的转换指令。40位整数转换为80位整数时，将后续的40位扩充为大端部分，无符号数和有符号数的正数填充全零，有符号数的负数填充全1 (补码表示)。80位整数转换为40位整数时，必须满足相反条件，抛弃大端部分即可。 Table 5 Integer multiplication and division instruction 编号 名称 格式 长 说明 28 整数相乘低位 MUL: rd， rs1， rs2 4 rd保存[rs1]*[rs2]的低40位 29 整数相乘高位 MULH: rd， rs1， rs2 4 rd保存rs1]*[rs2]的高40位 30 无符号整数相乘高位 MULHU: rd， rs1， rs2 4 rd保存40位无符号整数相乘[rs1]*[rs2]的高40位 31 整数相除 DIV: rd， rs1， rs2 4 整数相除[rd]=[rs1]/[rs2] 32 无符号整数相除 DIVU: rd， rs1， rs2 4 无符号整数相除[rd]=[rs1]/[rs2] 33 整数求余数 REM: rd， rs1， rs2 4 整数求余[rd]=[rs1]%[rs2] 34 无符号整数求余数 REMU: rd， rs1， rs2 4 无符号整数求余[rd]=[rs1]%[rs2] 表5. 整数乘除指令 4.6. 逻辑操作指令 逻辑操作指令包含了与、或、异或操作，如表6所示，可以是寄存器与寄存器操作，也可以是寄存器和立即数操作，立即数为2个字节长度。 Table 6 Logic operation instruction 编号 名称 格式 长 说明 35 异或 XOR: rd， rs1， rs2 4 [rs1]与[rs2]进行异或，结果放置到rd 86 立即数异或 XORI: rd， rs1， imm[15:0] 5 [rs1]与imm进行异或，结果放置到rd 36 或 OR: rd， rs1， rs2 4 [rs1]与[rs2]进行或操作，结果放置到rd 87 立即数或 ORI: rd， rs1， imm[15:0] 5 [rs1]与imm进行或操作，结果放置到rd 37 与 AND: rd， rs1， rs2 4 [rs1]与[rs2]进行与操作，结果放置到rd 88 立即数与 ANDI: rd， rs1， imm[15:0] 5 [rs1]与imm进行与操作，结果放置到rd 表6. 逻辑操作指令 4.7. 移位操作指令 移位操作指令包含了左移、右移、算术右移操作，如表7所示，可以是寄存器与寄存器操作，也可以是寄存器和立即数操作，立即数为1个字节长度。 Table 7 Shift operation instruction 编号 名称 格式 长 说明 38 左移 SLL: rd， rs1， rs2 4 [rd]=[rs1]<<[rs2]，低位补入0 39 立即数左移 SLLI: rd， rs1， imm 4 [rd]=[rs1]<< imm，低位补入0 40 右移 SRL: rd， rs1， rs2 4 [rd]=[rs1]>>[rs2]，高位补入0 41 立即数右移 SRLI: rd， rs1， imm 4 [rd]=[rs1]>> imm，高位补入0 42 算术右移 SRA: rd， rs1， rs2 4 [rd]=[rs1]>>[rs2]，最高位保持符号位 43 立即数算术右移 SRAI: rd， rs1， imm 4 [rd]=[rs1]>> imm，最高位保持符号位 表7. 移位操作指令 4.8. 比较操作指令 比较操作指令包含小于、小于等于、等于比较操作，如表8所示，可以是寄存器与寄存器比较，也可以是寄存器与立即数比较，立即数为2个字节长度。 Table 8 Comparison operation instruction 编号 名称 格式 长 说明 44 小于 SLT: rd， rs1， rs2 4 如果[rs1]<[rs2]，[rd]=1，否则为0 89 立即数小于 SLTI: rd， rs1， imm[15:0] 5 如果[rs1]< imm，[rd]=1，否则为0 45 小于等于 SLE: rd， rs1， rs2 4 如果[rs1]<=[rs2]，[rd]=1，否则为0 90 立即数小于等于 SLEI: rd， rs1， imm[15:0] 5 如果[rs1]<= imm，[rd]=1，否则为0 46 等于 SEQ: rd， rs1， rs2 4 如果[rs1]==[rs2]，[rd]=1，否则为0 91 立即数等于 SEQI: rd， rs1， imm[15:0] 5 如果[rs1]==imm，[rd]=1，否则为0 表8. 比较操作指令 4.9. 控制转移指令 控制转移指令用于程序的跳转操作，如表9所示。JAL指令用于近跳转，跳转到与当前位置偏移24位立即数地址，该立即数为有符号整数，因此能跳转到前后8M的地址区间。更远的跳转，可使用JALR指令，跳转偏移为寄存器与立即数的和。在近跳转和远跳转时，将当前指令地址保存到寄存器，这样在返回时，跳转到该地址递增5的位置，即下一指令地址，就结束子程序调用，继续执行原来的指令流。 在程序的内部跳转可以使用BLT、BLE、BEQ、BNE指令，在进行比较操作后进行跳转，通常无需返回，故不用保存当前指令地址，跳转偏移立即数为16位有符号数，因此偏移量范围为±32 KB。 Table 9 Control transfer instruction 编号 名称 格式 长 说明 92 近跳转 JAL: rd， imm[23:0] 5 跳转到当前指令偏移imm的地址，rd保存当前指令位置 93 远跳转 JALR: rd， rs1， imm[15:0] 5 跳转到偏移[rs1]+imm的指令地址，rd保存当前指令位置 94 小于 BLT: rs1， rs2，imm[15:0] 5 如果[rs1]<[rs2]，跳转到偏移imm地址 95 小于等于 BLE: rs1， rs2，imm[15:0] 5 如果[rs1]<=[rs2]，跳转到偏移imm地址 96 等于 BEQ: rs1， rs2，imm[15:0] 5 如果[rs1]==[rs2]，跳转到偏移imm地址 97 不等于 BNE: rs1， rs2，imm[15:0] 5 如果[rs1]!=[rs2]，跳转到偏移imm地址 表9. 控制转移指令 4.10. 控制状态设置指令 在处理器架构中，需要定义一些控制和状态寄存器，用于配置或记录一些运行的状态，称之为CSR寄存器，使用专有的地址编码空间，便于统一管理。如架构的版本信息、寄存器窗口的控制信息、整数和浮点数的运算状态、中断的控制状态等。CSR寄存器的访问采用CSR指令统一管理，如表10所示，对于一些常用的操作指令还可用伪指令来简化使用。CSR寄存器的编码仍然采用8位，即一个字节，它们与通用寄存器的编码空间互相独立，互不干扰。每个CSR寄存器编码对应1个字节宽度，因此最大管理空间是256个字节，并不充裕，需要节省使用。用其它指令能读取的内容，如前述的时钟计数等可不必纳入编码空间，以保留足够的扩充能力。CSR寄存器可以统一设置(CSRRW指令)，也可以按位设置(CSRRS指令)或者按位清除(CSRRC)。该三条指令允许从初始地址开始，进行完整的40位值读取和设置。 Table 1 0 Control state setting instruction 编号 名称 格式 长 说明 47 全部设置 CSRRW: rd， csr， rs1 4 读取csr内容到rd中，然后将rs1内容写入csr中 48 比特位设置 CSRRS: rd， csr， rs1 4 读取csr内容到rd中，以rs1中的值逐位作为参考，若某比特位为1，则将csr中对应的比特位置1 49 比特位清除 CSRRC: rd， csr， rs1 4 读取csr内容到rd中，以rs1中的值逐位作为参考，若某比特位为1，则将csr中对应的比特位置0 50 立即数设置 CSRRWI: rd， csr， imm 4 读取csr内容到rd中，然后将8位立即数写入csr中 51 立即数比特位设置 CSRRSI: rd， csr， imm 4 读取csr内容到rd中，以8位立即数中的值逐位参考，若某比特位为1，则将csr中对应的比特位置1 52 立即数比特位清除 CSRRCI: rd， csr， imm 4 读取csr内容到rd中，以8位立即数中的值逐位参考，若某比特位为1，则将csr中对应的比特位置0 表10. 控制状态设置指令 CSR寄存器的设置还可以直接利用立即数来处理，立即数为8位，一个字节，可以统一设置(CSRRWI指令)，也可以按位设置(CSRRSI指令)或者按位清除(CSRRCI)。此时只使用通用寄存器的低8位和CSR寄存器进行数据交换，高位默认扩展补0。如果立即数的值为0，则不会进行写操作，只进行读取操作。如果结果寄存器的索引值为0，则不会进行读操作。 4.11. 原子存储操作指令 处理器对速度的追求是无止境的，超线程技术能尽量挖掘处理器内部执行部件的能力，也就是用同一套执行机构，不同的寄存器来达到程序快速切换的能力，避免了保存现场和恢复现场的费时操作，这与采用寄存器窗口的思路是一致的。在单个处理器核心充分挖掘达到速度瓶颈后，一般通过多个核心来提高处理能力。但核心之间的并行性必须要协调，由于多个核心一般围绕同一份数据进行处理，因此只要保证数据的一致性，就容易达成多核心的并行性，故多核心的并行性一般通过内存变量的同步来处理。在核心数少时，某个核心读写时可以通知其他核心暂停存储器操作，保证读写共享变量的唯一性。在核心数多时，通过总线来控制更简单一些。此时某个核心锁定总线，只有当前核心能进行读写，其它核心则不能操作存储器，保证了共享变量的正确读写。 原子性存储操作指令为多核心执行读–算–写操作时对共享变量进行同步，即在对存储器执行操作时，不被其它核心干扰。在读出和写回的间隙，存储器的该地址不能被其它的进程或线程访问，这保证了共享变量的操作唯一性，然后借此达成多个核心的同步和并行。这些原子计算存储指令原子性地从rs1地址读取数据值、将这个值写入寄存器rd、在这个值和rs2的原始值上施加一个二进制操作、然后把结果保存到rs1地址的存储器中。支持的操作包括原子比较交换、交换、整数加、逻辑操作等，如表11所示。 这些指令在执行时先尝试获取存储总线，获取后进行读取并计算，存储结果后释放存储总线。如果不能获取总线，一般需要等待，这阻塞了指令执行，对计算速度有所影响。其中原子比较交换指令AMCMPS无需等待，可用来实现加锁，一般用1表示加锁状态，用0表示解锁状态。如果发现为0的解锁状态，则进行加锁，否则退出，可等待片刻后再尝试加锁。解锁时更为简单，只需将解锁信号传递即可，无需比较，可采用原子交换指令AMSWAP。为并行计算的简单性，无需加锁解锁的繁琐过程，可采用原子加、与、或、异或、取最小值指令，这些指令能保证核心操作时的唯一性。 Table 1 1 Atomic storage operation instruction 编号 名称 格式 长 说明 53 原子比较交换 AMCMPS: rd， rs2， rs1 4 以[rs1]为地址，读出五字节内容，与rd寄存器中内容比较，相等则将[rs2]存储到[rs1]位置，不相等则将rd设为读出值，但并不存储[rs2]到[rs1]位置 54 原子交换 AMSWAP: rd， rs2， rs1 4 以[rs1]为地址，读出五字节存放到rd寄存器中，将[rs2]存储到[rs1]为地址的位置，然后[rs2]=[rd] 55 原子加 AMADD: rd， rs2， rs1 4 以[rs1]为地址，读出五字节存放到rd寄存器中，[rs2]+=[rd]，将[rs2]存储到[rs1]位置 56 原子与 AMAND: rd， rs2， rs1 4 从[rs1]读出五字节存放到rd寄存器中，[rs2]&=[rd]，将[rs2]存储到[rs1]位置 57 原子或 AMOR: rd， rs2， rs1 4 从[rs1]读出五字节存放到rd寄存器中，[rs2]|=[rd]，将[rs2]存储到[rs1]位置 58 原子异或 AMXOR: rd， rs2， rs1 4 从[rs1]读出五字节存放到rd寄存器中，[rs2]|^=[rd]，将[rs2]存储到[rs1]位置 59 原子最小 AMMIN: rd， rs2， rs1 4 从[rs1]读出五字节整数存放到rd寄存器中，[rs2]|=min([rd]，[rs2])，将[rs2]存储到[rs1]位置 60 原子无符号数最小 AMMINU: rd， rs2， rs1 4 从[rs1]读出五字节无符号整数存放到rd寄存器中，[rs2]|=min([rd]，[rs2])，将[rs2]存储到[rs1]位置 表11. 原子存储操作指令