第二章 指令

第二章 指令:计算机的语言

2.1 引言

  • 计算机语言
    • 指令:基本单词
    • 指令集 Instruction Set:全部指令
    • 存储程序概念

2.2 计算机硬件的操作

  • 算术运算

    add a, b, c  # a = b + c
    sub d, a, e  # d = a - e
    
  • 硬件设计第一条原则简单源于规整。操作个数可变将给硬件设计带来更大的复杂性。

    例题 \color{White}\colorbox{Fuchsia}{例题} f = (g + h) - (i + j)

    add t0, g, h
    add t1, i, j
    sub f, t0, t1
    

2.3 计算机硬件的操作数

  • 寄存器:由硬件构成,数量有限

    • 计算机硬件设计的基本元素
    • MIPS体系结构中:32个大小为32位(字 word,32位一组)的寄存器。MIPS指令的三个操作数必须从32个寄存器中选取。
    • 变量对应的寄存器:$s0, $s1,...
    • 临时寄存器:$t0, $t1,...
  • 硬件设计第二条原则越小越快。操作个数可变将给硬件设计带来更大的复杂性。

2.3.1 存储器操作数

  • 数据传送指令:存储器和寄存器之间移动数据的命令。访问存储器(下标从0开始的一维数组)地址。

    大量数据结构(数组和结构)无法存放在寄存器中,只能存放在存储器中。于是MIPS指令需要在存储器和寄存器之间传送数据。

  • 取数指令lw (load word)——将数据从存储器复制到寄存器

    • 格式:操作码 + 目标寄存器 + 常数和寄存器(访问存储器)

      其中,常数+第二个寄存器=存储器地址

      常数:偏移量(offset),基址(base address)寄存器(base register)

      例题 \color{White}\colorbox{Fuchsia}{例题} :数组A的起始地址为$s3g:$s1,h:$s2,表示 g = h + A[8]

      lw $t0, 32($s3)  #将A数组存储器中操作数传送到寄存器,每个内存单元占4位,8*4=32
      add $s1, $s2, $t0
      

      字节寻址:一个字的地址必和其包括的4字节中某个地址相匹配,所以连续字的地址相差4。

      对齐限制 alignment restriction:数据地址与存储器的自然边界对齐的要求

  • 存数指令sw (store word)——将数据从寄存器复制到存储器

    例题 \color{White}\colorbox{Fuchsia}{例题} :数组A的起始地址为$s3h:$s2,表示 A[12] = h + A[8]

    lw $t0, 32($s3)
    add $t0, $s2, $t0
    sw $t0, 48($s3)
    
  • 寄存器溢出 spilling:将不常使用的变量存回到存储器中的过程。寄存器的访问时间,吞吐率都比存储器高优秀许多。

2.3.2 常数或立即数操作数

  • 加立即数addi (add immediate) —— 一个操作数是常数的算术运算指令

    代替从存储器中取常数: lw $t0, const4($s1) #$t0 = const 4

    • 立即数:常数操作数。

      addi $s3, $s3, 4  #$s3 = $s3 + 4
      
    • 由于MIPS支持负常数,故不需要设置减立即数指令

2.4 有符号数和无符号数

  • 二进制数位 binary digit / 位 bit:信息的基本组成单元。

  • 最低/高有效位 least/most significant bit:在MIPS字中最右/左边的一位

  • 溢出 overflow:操作结果不能被最右端的硬件位表示

  • 二进制补码 two’s complement:表示 − 2 n − 1 ∼ 2 n − 1 − 1 -2^{n-1}\sim 2^{n-1}-1 2n12n11 2 n 2^n 2n 个数。

    • 补码取反:基于 x + x ˉ = − 1 x+\bar{x}=-1 x+xˉ=1.
.
  • 无符号数

  • 符号扩展 sign extension:16位的数转成数值相等的32位数。

    • 步骤:将最高有效位(最左边——符号位)重复16次放到32位的左半部分,右半部分照抄。

      例题 \color{White}\colorbox{Fuchsia}{例题} :将 − 2 10 -2_{10} 210 16 16 16 位二进制数转为 32 32 32 位二进制数
      2 10 的 16 位 二 进 制 : 0000 0000 0000 0010 2 − 2 10 的 16 位 二 进 制 : 1111 1111 1111 1110 2 − 2 10 的 32 位 二 进 制 : 1111 1111 1111 1111 1111 1111 1111 1110 2 \begin{aligned} 2_{10}的16位二进制&:\text{0000 0000 0000 0010}_2\\ -2_{10}的16位二进制&:\text{1111 1111 1111 1110}_2\\ -2_{10}的32位二进制&:\text{1111 1111 1111 1111 1111 1111 1111 1110}_2 \end{aligned} 210162101621032:0000 0000 0000 00102:1111 1111 1111 11102:1111 1111 1111 1111 1111 1111 1111 11102

2.5 计算机中的指令表示

  • MIPS中通用寄存器 General-Purpose registers 位置

    寄存器映射编号名称用途
    0$zero地址、内容都是0,不能被改写
    1$at给汇编提供的寄存器(不是很懂)
    2~3$v0, $v1函数(子程序)出口参数(返回值)
    4~7$a0 ~ $a3函数(子程序)入口参数
    8~15, 24~25$t0 ~ $t7,$t8,$t9临时寄存器,不受保护(使用后不必恢复原样)
    16~23$s0 ~ $s7受保护,调用的子程序结束后,必须恢复原样
    26~27$k0, $k1操作系统专用寄存器
    28$gp保存全局变量的地址
    29$sp栈顶指针
    30$fp帧指针
    31$ra子程序返回地址 return address(返回的指令的地址)
  • 指令格式 instruction format:二进制数字段组成的指令表示形式 <op><rs><rt><rd><shamt><funct>

    • R R R指令: 6 6 6 位(表示操作) + 5 5 5 位(源地址一) + 5 5 5 位(源地址二) + 5 5 5 位(目标寄存器) + 5 5 5 位(位移量) + 6 6 6 位(功能码) = 32 32 32
    • MIPS指令占 32 32 32
    • 机器语言:指令的数字形式,指令序列称为机器码
  • MIPS字段 field

    • R型指令:用于寄存器
      在这里插入图片描述

      • op (opcode):操作码。指令中用来表示操作和格式的字段
      • rs (rigister source):第一个源操作数寄存器
      • rt (rigister target):第二个源操作数寄存器
      • rd (rigister destination):存放操作结果的目的寄存器
      • shamt (shift amount):位移量。
      • funct (function code):功能码。用于指明 o p op op 字段中操作的特定变式
    • I型指令:用于立即数或数据传送
      在这里插入图片描述

      • 取字指令中:rt ——接受结果的目的寄存器
    • J型指令:跳转地址 target address

    • 对应机器码在这里插入图片描述

      例题 \color{White}\colorbox{Fuchsia}{例题} :将汇编语言翻译成机器语言,数组 A A A 的起始地址为$t1h:$s2,表示 A[300] = h + A[300]

      lw $t0, 1200($t1)  #35 9 8 1200 #op = 0x23
      add $t0, $s2, $t0  #8 18 8 8 0 32
      sw $t0, 1200($t1)  #43 9 8 1200 #op = 0x2b
      
  • 硬件设计第三条原则优秀的设计需要适宜的折中方案。既希望所有指令长度相同,又希望具有统一指令格式,于是分出三种指令格式 R, I, J

2.6 逻辑指令等 Logic Instructions

伪指令 pseudo instruction

  • 逻辑位移 shift:(R-型

    sll $t1, $s0, 4  #$t1 = $s0 << 4 bits = $s0 * 16  #0 0 16 9 4 0 #op = 0,funct = 0
    srl $t1, $s0, 4  #$t1 = $s0 >> 4 bits #op = 0,funct = 3
    
    • sll:中 o p op op 字段和 f u n c t funct funct 字段都是 0 0 0 s h a m t shamt shamt 代表位移量
    • 算数位移(扩展指令):sal 算数左移,sra 算术右移(intel指令集)
      • 逻辑右移和算术右移的区别在于,算术右移高位补充符号位,逻辑右移高位补 0 0 0.
    • 伪指令:ror 循环右移,rol 循环左移;rcl 加进位的循环左移,rcr 加进位的循环右移。
  • 按位与 AND:(R-型

    and $t0, $t1, $t2 #op = 0,funct = 0x24
    andi  #立即数与 #op = 0xc
    
    • 掩码 mask:某一位,第二操作数上为 0,按位与可将第一操作数置为 0,“隐藏”某一位。
  • 按位或 OR:(R-型

    or $t0, $t1, $t2 #op = 0,funct = 0x25
    ori  #立即数或  #op = 0xd
    
    • andiori I I I 类型指令,会首先用零扩展补充立即数的高16位
  • 或非 NOR:(R-型

    nor $t0, $t1, $t2  #$t0 = ~ ($t1 | $t2) #op = 0,funct = 0x27
    
    • 按位取反 NOTa NOR 0 = NOT(a)

      非指令 NOT 不属于经典指令集,利用或非的一个操作数为 0 0 0 表示

2.7 决策指令

2.7.1 分支

  • 条件分支指令 Conditional Branch

    • beq (branch if equal):(I-型)如果相等则分支

      • beq reg1, reg2, L1 #op = 4 :若 r e g 1 reg1 reg1 r e g 2 reg2 reg2 数值相等则转到 L1​ 语句
    • bne (branch if not equal):(I-型)如果不相等则分支

      • bne reg1, reg2, L1 #op = 5 :若 r e g 1 reg1 reg1 r e g 2 reg2 reg2 数值不相等则转到 L1 语句

      以上属于 I​ 类型指令,其中 L1​ 会被转换成立即数:算出和当前指令的下一条指令个数,并乘以4.

      目标地址 = PC + 4 + sign-extend(16-bit immediate << 2)

    例题 \color{White}\colorbox{Fuchsia}{例题} f , g , h , i , j f,g,h,i,j f,g,h,i,j 变量依次对应 $s0 - $s4 的寄存器,用MIPS编码表示 if(i == j) f = g + h; else f = g - h

    bne $s3, $s4, Else
    add $s0, $s1, $s2
    j Exit
    Else: sub $s0, $s1, $s2
    Exit:
    
  • 无条件分支指令

    • j (unconditional branch):(J-型)jump
    • j L1 #op = 2:必须分支

2.7.2 循环指令

  • 循环

    • 直接用标签 Loop 代表循环体

      例题 \color{White}\colorbox{Fuchsia}{例题} :变量 i:$s3,k:$s5,数组 s a v e save save 的基址在 $s6,用MIPS编码表示 while(save[i] == k) i += 1;

      Loop: sll $t1, $s3, 2  # $t1 = i * 4
      add $t1, $s6, $t1  # $t1 = save[i]的地址
      lw $t0, 0($t1)  # $t0 = save[i]
      bne $t0, $s5, Exit
      addi $s3, $s3, 1
      j Loop
      Exit:
      
    • 基本块 basic block:没有分支和分支目标/分支标签的指令序列。

    • slt (set on less than):(R-型)(有符号数)小于则置位 slt $t0, $s3, $s4 # $t0 = $s3 < $s4 ? 1 : 0 #op = 0,funct = 0x2a

      由于过于复杂,会延长时钟周期时间,没有小于则分支指令

    • slti (set on less than immediate):(I-型)(有符号数)立即数版本 slti $t0, $s2, 10 # $t0 = $s2 < 10 ? 1 : 0

    • sltu/sltiu (set on less than (immediate) unsigned):无符号整数版本

      例题 \color{White}\colorbox{Fuchsia}{例题} $s0:0xffff ffff, $s1:0x0000 0001,则执行 slt $t0, $s0, $s1sltu $t1, $s0, $s1$t0, $t1 的值

      解:$t0=1, $t1=0

2.7.3 case/switch 语句

  • case/switch语句
    • 转移地址表 jump table:又称转移表,指包含不同指令序列地址的表
    • jr (jump register):寄存器跳转指令

2.8 计算机硬件对过程的支持

  • 过程:根据提供的参数执行一定任务的存储的子程序

  • 子程序调用 Procedure call and return

    • jal (jump-and-link instruction) 跳转和链接指令:(J-型)跳转到某个地址的同时将下一条指令的地址保存在寄存器 $$ra$ 中 jal ProcedureAddress #op = 3

      • 链接部分:指向调用点的地址或链接

      • 返回地址 return address:存储在寄存器 $$ra$ 中的链接部分

      • 程序计数器 PC(program counter):一个保存当前运行的指令地址的寄存器,即指令地址寄存器。

        jal 一般将 P C + 4 PC+4 PC+4 保存在寄存器 $$ra$ 中,即 jal $ra

2.8.1 堆栈

目的:由于寄存器在调用后需恢复到过程调用前所存储的值,所以需要位置保存寄存器旧值,以便于恢复。

  • :后进先出的数据结构,用于寄存器换出

    • 栈指针 stack pointer:指示栈中最近分配的地址的值,指示寄存器被换出的位置,或寄存器旧值的存放位置
      • 以字为单位进行调整
      • MIPS中是第 29 29 29 号寄存器 $$sp$。
      • 入栈时栈指针减小( − 4 -4 4):因为栈“增长”是按照地址从高到底的顺序。

    例题 \color{White}\colorbox{Fuchsia}{例题} :将C语言编译为MIPS汇编语言,参数变量 g , h , i , j , f g,h,i,j,f g,h,i,j,f 分别对应 $$a0,$a1,$a2,$a3,$s0$

    int leaf_example(int g, int h, int i, int j){
    	int f;
        f = (g + h) - (i + j);
        return f;
    }
    

    解:

    leaf_example:
        #保存过程中使用的寄存器
        addi $sp, $sp, -12  #建立三个字的空间
        sw $t1, 8($sp)  #存入数据
        sw $t0, 4($sp)
        sw $s0, 0($sp)
        #过程实体
        add $t0, $a0, $a1
        add $t1, $a2, $a3
        sub $s0, $t0, $t1
        #将f的值复制到返回值寄存器v0
        add $v0, $s0, $zero
        #弹出数据,恢复是寄存器旧值
        lw $s0, 0($sp)
        lw $t0, 4($sp)
        lw $t1, 8($sp)
        addi $sp, $sp, 12
        #返回地址跳转
        jr $ra
    

2.8.2 嵌套过程

  • 叶过程 leaf procedure:不调用其他过程的过程

  • 调用非叶过程:寄存器在嵌套保存的地址或内容上会导致冲突。

    • 解决方法:将所有必须保留的寄存器都压栈。

      例题 \color{White}\colorbox{Fuchsia}{例题} :将C语言编译为MIPS汇编语言,参数变量 n n n 分别对应 $a0

      int fact(int n){
          if(n < 1) return 1;
          else return (n * fact(n - 1));
      }
      

      解:

      fact:
          #保存返回地址寄存器和变量 n 寄存器
          addi $sp, $sp, -8
          sw $ra, 4($sp)
          sw $a0, 0($sp)
          #判断是否跳转
          slti $t0, $a0, 1
          beq $t0, $zero, L1
          # n < 1时
          addi $v0, $zero, 1
          #由于旧值未改变,直接改变栈指针即可
          addi $sp, $sp, 8
          #返回地址跳转
          jr $ra
          L1:  # n >= 1时
              addi $a0, $a0, -1
              jal fact
          #弹出数据,恢复栈指针,旧寄存器返回地址和旧参数
          lw $a0, 0($sp)
          lw $ra, 4($sp)
          addi $sp, $sp, 8
          #值寄存器v0 = 旧参数a0 * 当前值寄存器v0
          mul $v0, $a0, $v0
          #返回地址跳转
          jr $ra
      

2.10 MIPS中32位立即数和寻址

2.10.1 32位立即数

伪指令为 li $s0 0x3f3f2f2f

  • lui (load upper immediate):(I-型)读取立即数高位指令 lui $t0(reg), 255(const) #op = 0xf

    • 将立即数 c o n s t const const 存入寄存器常数的高 16 16 16 位,低位用 0 0 0 补充
  • 32 32 32 位的立即数装入寄存器中

    MIPS实现:

    1. 先用 lui (load upper immediate) 装入高16位,且低位用0补充 lui $s0 0x3f3f.
    2. 在用 ori 填补低16位 ori $s0 $s0 0x2f2f.

    例题 \color{White}\colorbox{Fuchsia}{例题} :加载 32 32 32 位常量 0000 0000 0011 1101 0000 1001 0000 0000 \text{0000 0000 0011 1101 0000 1001 0000 0000} 0000 0000 0011 1101 0000 1001 0000 0000 到寄存器 $$s0$ 的MIPS代码

    lui $s0, 16   # 0000 0000 0011 1101 = 16
    ori $s0, 2304 # 0000 1001 0000 0000 = 2304
    

2.10.2 分支和跳转中的寻址

32 32 32 位的地址装入寄存器中:伪指令为 la $t0 0x10010008(比如将内存地址装载到寄存器中)

diate)** 装入高16位,且低位用0补充 lui $s0 0x3f3f.
2. 在用 ori 填补低16位 ori $s0 $s0 0x2f2f.

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值