计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图

文章目录

  • 二、指令:计算机的语言
    • 章节导图
    • 一、MIPS概述
      • 计算机的组成 MIPS的设计思想
      • MIPS-32中的通用寄存器
    • 二、三类汇编指令
      • 运算指令
        • 算术运算
          • 加add、减sub
          • 加立即数addi
        • 逻辑运算
          • 逻辑按位运算:and or nor指令
          • 逻辑移位运算:sll和srl指令
            • 综合练习1:变量运算与赋值
      • 寄存器-存储器数据传送
        • lw指令
        • 字与sw指令
        • 装载立即数到寄存器
        • 装载32位立即数到寄存器
          • 综合练习2:数组元素运算与赋值
      • 决策指令
        • 条件分支beq和bne
          • 综合练习3:if-else语句(无条件跳转j和条件分支)
        • 小于则置位slt
        • 6种条件判定及其伪指令
          • 综合练习4:while循环
      • MIPS汇编指令小结
      • 三种指令格式
        • R型
        • I型(立即数)
        • I型(偏移量)
        • I型(标签)
        • 机器语言指令格式小结
        • 复习题
    • 三、过程支持
      • 过程(函数)的执行过程
      • 支持过程的三大寄存器
      • jal -- jr指令对 程序计数器
      • 综合练习5:数组清零函数(叶过程)
      • 保存寄存器的压栈和出栈栈指针$sp
          • 综合练习6:运算函数(叶过程)
          • 综合练习6改进:减少指令条数
          • 嵌套过程调用 综合练习7:数组求平方和(嵌套过程)
          • 需要压栈保存的寄存器
      • 进阶内容:复杂MIPS程序示例
      • 过程帧与帧指针$fp
      • 全局指针$gp程序的内存分配
    • 四、寻址方式
      • 32个通用寄存器及其编号
      • R型:寄存器寻址
      • I型:立即数寻址和基址偏移寻址
      • I型:PC相对寻址
      • J型:伪直接寻址
      • 扩大分支与跳转的范围
      • 寻址方式小结
      • MIPS汇编指令小结
    • 五、C程序执行过程
      • C语言的四个翻译层次
      • 字符支持同步指令对II-sc ARM和x86简介
      • 复习题

二、指令:计算机的语言

章节导图

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第1张图片

一、MIPS概述

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第2张图片

计算机的组成 MIPS的设计思想

计算机执行任何程序,本质上都是在执行机器语言指令(instruction)。每条指令都是一条0-1串。

指令首先要指明执行什么操作,通常用0-1串的前几位来表示,称为操作码

指令还要指出需要操作的数据来自哪里,操作后的结果数据放回哪里,通常用0-1串中的剩余位来表示,称为操作数地址码

大部分操作数都是一个地址编号,告诉CPU从哪里取得数据、向哪里放回数据,所以操作数通常也叫做地址码。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

MIPS作为一种RISC指令集,设计力求保证硬件设备的简单性。

在本书的32为MIPS汇编语言(MIPS-32)中,所有指令都是32位长。

MIPS-32中的通用寄存器

MIPS中运算操作的操作数必须来自寄存器(register)或者指令本身。

一种位于CPU、比cache更小更快的存储器,用来暂时存放运算的源数据和结果。

一些寄存器是专用的,如存放执行中指令地址的程序计数器(PC),与此相对应,用于暂时存放运算数据的寄存器称为通用寄存器

MIPS中一共有32个32位的寄存器,共128B(大部分架构都采用16和32个寄存器)

我们约定:

程序中的变量存放在**保存寄存器(store reg)中: s 0   s0~ s0 s7共8个。运算的临时变量、中间变量存放在临时寄存器(temp-reg)**中; t 0   t0~ t0 t7共8个,还有一个零寄存器,永远存放32位的0,写作$zero。

二、三类汇编指令

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第3张图片

运算指令

算术运算
加add、减sub

C赋值语句:c = a + b;

加法指令 add c , a , b; 将a和b中的数据相加,并将结果存放在s中

再次强调:MIPS中运算的操作数必须来自寄存器或者指令本身!

假设变量a,b,c分别存放在寄存器 s 0 , s0, s0s1,$s2中,这条指令就应当写为

add $a2 , a 0 , a0, a0a1

加法中两个加数可以对换,但减法不行,,故c = a - b;必须写作

sub $s2 , $s0 , $s1

运算的“原材料”a和b对应的寄存器 s 0 , s0, s0,s1分别称为源操作数1(src1)和源操作数(src2),运算的结果c对应的寄存器$s2称为目的操作数(des)

加减指令的通式:add/sub des ,src1,src2

加立即数addi

在i++即i = i + 1;这条赋值语句中,有个确定的常数 1,与其采用额外的步骤将1装入某个寄存器,不如让指令本身包含这个1

假设变量 i 位于寄存器$s0,我们把加法指令的第二个源操作数改为常数1

add $s0 , $s0 , 1

就成了加**立即数(add immediate)**指令

因为add指令中的立即数可以取负数(对立即数取负后相加),因此,MIPS中没有subi指令

逻辑运算
逻辑按位运算:and or nor指令

当两个源寄存器中,对应的位上同时为1时,与and操作数结果为1

当两个源寄存器中,对应的位上至少有一个为1时,或or操作结果为1

因此,假设

$t0 = 0000 0000 0000 0000 0000 0000 0000 1001

$t1 = 0000 0000 0000 0000 0000 0000 0000 1100

执行下列两条指令后,$t2中的数据分别变为多少?

add $t2 , $t0 , $t1 0000 0000 0000 0000 0000 0000 0000 1000

or $t2 , $t0 , $t1 0000 0000 0000 0000 0000 0000 0000 1101

任何数据与0进行或非nor操作,都会0/1反转

执行下列指令后,$t2中的数据会变为多少?

nor $t2 , $t0 , $zero

逻辑移位运算:sll和srl指令

比较12和120两个十进制数,通过在最低位的右边添加一个0,变为了10倍

比较11和110两个十进制数,通过在最低位的右边添加一个0,变为了多少倍?1100呢?

**逻辑左移(shift left logic)**指令让寄存器中的数据整体往左移动指定的位数,并在右边空出来的位上补上0

假设$s2 = 0000 0000 0000 0000 0000 0000 0000 0101

逻辑左移两位后,放到寄存器$s0中:

sll $s0 $s2 2

这里的2不是addi指令中的立即数,而是告诉计算机移动几位的位移量(shift amount)

通过这样一句指令:我们实际上完成了x4的运算。

x2 ,x8,x128时,位移量分别为多少呢?

(sll指令当然也可以实现/2操作)

综合练习1:变量运算与赋值

翻译以下C语句

假设result ,a,b,c分别存放在$s3 $s0 $s1 $s2

result = a - 10 + (b + c * 5)

sll $t0 , $s2 , 2

add $t1 , $t0 , $s2

add t 2 , t2, t2s1,$t1

addi t 3 , t3, t3s0,-10

add s 0 , s0, s0t3,$t2

寄存器-存储器数据传送

lw指令

运算指令的操作数必须来自寄存器/指令本身,但是通用寄存器一共只有128B,数组元素却可以占据成千上万个字节,只能存放在内存中

这时,我们把数组第一个元素,a[0]的32位地址,称为数组的基址。放在寄存器中,基址加上要找的元素下标,就组成了这个元素的地址

如果源操作数在内存中,是数组a的5号元素(第六个元素),数组a的基址存放在$s1中。

那么,a[5]的地址就表示为5($s1)

计算机会自动计算$s1中的基址和偏移量5的和,找到a[ 5 ]的地址

将a[ 5 ]从内存传送到寄存器$s0,使用取字指令(load word)

lw s 0 , 5 ( s0 , 5( s0,5(s1)

字与sw指令

MIPS的通用寄存器都是32位长

这个长度就是MIPS体系结构的字长,通常代表了参与运算的数据的长度

因此我们约定:整门课程中,1字 = 32bit = 4Byte

a[ 5 ]相对于a[ 0 ],在内存中的距离是5个字,而不是5个字节,又因为内存按字节编址,

即,内存每个字节都有一个特定的编号,所以偏移量应该是5x4 = 20个字节

a[ 5 ]的地址应表示成20($s1)

于是取数指令变为:

lw s 0 , 20 ( s0 , 20( s0,20(s1)

如果,我们要把$t0中的运算结果送回到内存中的a[ 2 ],需要用到存字指令(store word)

sw t 0 , 8 ( t0,8( t08(s1)

装载立即数到寄存器

如果我们需要把数从 t 0 保存到存放某变量的 t0保存到存放某变量的 t0保存到存放某变量的s1中,怎么实现?

MIPS没有专门的寄存器间移动数据的指令,但是通过把源寄存器中的数据加上0再保存到目标寄存器中,可以实现相同的功能。

addi $s1 , $s0 , 0 或 addi $s1 , $s0 , $zero

这个功能可以用move伪指令来代替

move $s1 , $s0

假如我们要把一个常数10装入寄存器$s2,同样可以采用addi指令

addi $s2 , $zero , 10

或者使用取立即数(load immediate)li伪指令

li $s2 , 10

程序设计题是否可以用伪指令根据自己学校情况妥善选择

装载32位立即数到寄存器

我们说可以用addi指令向寄存器装载立即数:addi $s2 , $zero , 10;

但是,addi指令中的立即数10只能占用32位指令中的一部分(16位,后面会介绍指令格式)

16位只能表示216即65536个数,寄存器却能容纳232即40多亿个数

二进制转十六进制规则不再赘述

假设我们要向寄存器$s2装载一个32位的立即数:10A2 7FFF(16)

我们必须先用取高位立即数(load upper immediate)指令:将10A2放入$s2的高16位

再用立即数或(immediate or),将32767放入$s2的低16位

lui $s2 , 4258 //十六进制的10A2等于十进制的4258

ori $s2 $s2 , 32767 //7FFF(16) = 32767(10)

这样就分两步把32位立即数装载到了32位的寄存器中

不能用addi代替ori指令,因为如果低16位的最高位是1,那么addi会把它理解为负数

综合练习2:数组元素运算与赋值

a[ i ] = a[ 0 ] + 100000;

假设数组a的基址位于 s 0 ,变量 i 位于 s0,变量i位于 s0,变量i位于s1

100000(10) = 186A0(16),1(16) = 1(10) , 86A0(16) = 34464

lw t 0 , 0 , 0 ( t0 , 0 , 0( t0,0,0(s0)

lui $t1 , 1

ori $t1 , $t1 , 34464

add $t2 , $t1 , $t0

sll $t3 , $s1 , 2

add $t4 , $s0 , t 3 / / 我们必须算出 a [ i ] 的地址, ∗ ∗ 不能直接写成 t3 //我们必须算出a[ i ]的地址,**不能直接写成 t3//我们必须算出a[i]的地址,不能直接写成t3($t0) ,前面必须是一个数字**

sw t 2 , 0 ( t2 , 0( t2,0(t4)

决策指令

条件分支beq和bne

计算机和一般计算器的区别在于何处?

**在于决策能力!**即,根据一定的条件选择执行何种运算的能力

最基础的判断条件是相等关系

假设 s 0 = 0 , s0 = 0 , s0=0s1 = 0, $s2 = 1

相等则分支(branch if equal)指令在两个源操作数寄存器中的值相同时分支

分支以分支标签表示

beq $s0 , $s1 , Label

与此相对应,不相等则分支(branch if not equal)指令在值不同时分支到标签

bne $s0 , $s1 , Label

如果不发生分支,则继续执行内存中相邻的下一条指令

综合练习3:if-else语句(无条件跳转j和条件分支)

if (i == j) f = g + h;

else f = g - h;

假设f ,g,h,i,j分别存放在 s 0 − s0- s0s4中

bne $s3 , $s4 , Else

add $s0 , $s1 , $s2

j Exit

Else: sub $s0 , $s1 , $s2

Exit:

结论:判定相等 == 使用bne , 判断不等 != 用beq

小于则置位slt

除了相等、不等关系,我们还经常比较两个数的大小,MIPS有一条小于则置位(set on less than)指令slt

置位:将一位设置为1;复位:将一位设置为0;

还是假设$s0 = 0 , $s1 = 0 , $s2 = 1

slt $t0 , $s0 , $s2

源操作数1 < 源操作数2吗?Yes!

此时把目的操作数寄存器$t0置位为1

slt $t0 , $s0 , $s1

源操作数1 < 源操作数2吗?No!

此时把目的操作数寄存器$t0复位为0

6种条件判定及其伪指令

六种比较条件:== < <= > >= !=

通过slt,beq,bne(严格来说还有小于立即数则置位slti指令,不做讨论)指令的各种组合,我们就能够实现全部六种比较条件,即六种值为真或假的布尔表达式

例如综合练习3我们可以有如下写法:

if (i == j) f = g + h;

else f = g - h;

slt t 0 , i , j / / 当 i < j 时,把 t0 , i , j //当it0,i,j//i<j时,把t0置为1,否则为0

beq $t0 , z e r o , E l s e / / 当 zero , Else //当 zero,Else//t0为0时,执行else后的语句

add f , g ,h //否则顺着执行if后的语句

j Exit //加法完成后退出if-else语句

Else: sub f , g , h //else

Exit:

结论:判定大于>或者小于<用slt和beq , 判定大于等于>=或小于等于<=用slt和bne

对于比大小的四种比较条件,可以使用伪指令

小于则分支 blt 大于则分支 bgt

小于等于则分支 ble 大于等于则分支 bge

综合练习4:while循环

while(a[ i ] == k) i++;

假设i, k分别存放在 s 3 和 s3和 s3s5中,a的基址存放在$s6中

Loop : sll $t0 , $s3 , 2

add $t1 , $s6 , $t0

lw t 2 , 0 ( t2 , 0( t2,0(t1) //此时$t2就是a[i]的值

bne $t2 , $s5 , Exit

addi $s3 , $s3 , 1 //i++

j Loop //回到开头

Exit:

MIPS汇编指令小结

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第4张图片

三种指令格式

R型

指令中含三个寄存器的运算指令都属于R型(register type)指令

add/sub des,src1,src2

and/or/nor des,src1,src2

slt des , src1 , src2

32位MIPS指令一共分为6个字段

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

op: operation code 操作码

rs: register source 源操作数寄存器-→ rt: s后面是t,表示第二个源操作数寄存器

rd: register destination 目的寄存器

shamt: shift amount 移位量

funct: function code 功能码

R型指令的操作码op都是6个0,由6位功能码funct 进一步指定执行什么操作
以add指令为例

$t0~ t 7 分别为 8   15 号寄存器 ∗ ∗ ∗ ∗ t7分别为8~15号寄存器** ** t7分别为8 15号寄存器s0~ $s7分别为16~23号寄存器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

根据我们R型指令的格式可知:op :000000 rs: s 1 r t : s1 rt: s1rts1 rd:$t0 shampt:0 funct:32(对应add)

sub指令仅仅是功能码funct字段从32变为了34, sub $s1, $s1, $s0的32位机器码是多少?

000000 10001 10000 10001 00000 100010

需要记忆add、sub指令 的操作码(都是0) 和功能码(分别为32、34)

sll/srl des, src1, shamt
也属于R型指令,因为没有第二个源操作数寄存器, rt被置为0

I型(立即数)

有两条、“目的reg +源reg+立即数”格式的指令

addi des,src1,i

ori des,src1,i

通过把R型指令中的后三个字段拼接成一个16位的立即数字段,让指令本身包含常数这样的指令属于**|型(immediate type)指令**

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第5张图片

addi指令为,其操作码为8

addi $t1 , $t0 , 15

001000 01000 01001 0000000000001111

其操作码为8,由于rd字段被合并了,现在rt就成了目的寄存器

I型(偏移量)

Iw/sw reg, num(reg)
两条数据传送指令也包含两个寄存器和一个常数
同样属于I型指令
此时,16位立即数字段的含义发生了改变,表示数组元素相对于数组基址的地址偏移量

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

无论是**|w还是sw指令都是由rs字段表示的寄存器值与address字段相加**,得到存储器单元地址
rt字段表示与存储器单元交换数据的寄存器

Iw、sw指令操作码分别为35和43
Iw t 0 , 8 ( t0, 8( t0,8(s1)

100011 10001 01000 0000000000001000

I型(标签)

beq/bne src1,,src2, Label(两个寄存器都是源寄存器)
在这两条条件分支指令中,同样使用了两个寄存器
还有一个分支标签的地址,用16位立即数字段表示(也就变成了Address字段)
也属于|型指令

例如,当i ( s 0 ) 和 j ( s0) 和j ( s0)j(s1) 相等时分支到地址为10000的标签EIse
beq $s0, $s1, Else
翻译为机器语言为外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

op 10000 10001 10000(10)

这里的10000实际上并不是EIse标签指向指令的地址,讲寻址方式时再具体说明

机器语言指令格式小结

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第6张图片

lui指令的指令格式不作讨论
五条伪指令本身不是真正的指令,程序运行时会被替换为真正指令,不讨论指令格式
j指令的指令格式稍后讲解

复习题

1、指令通常由哪两个部分组成? MIPS-32指令长度均为多少?

操作码 操作数(地址码) 32位

2、8个临时寄存器、8个保存寄存器分别是什么编号?零寄存器存储什么?

t 0   t0~ t0 t7 8~15 s 0   s0~ s0 s7 16~23 0

3、回顾综合练习1~4,掌握运算、数据传送、决策三类汇编指令,注意字和字节的区别.
4、练习上一页PPT中五条指令(add、 sub、 addi、Iw、 sw)汇编语言和机器语言的转化

三、过程支持

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第7张图片

过程(函数)的执行过程

C语言中的函数(一种典型的过程)是结构化编程的强大工具
函数获取参数、执行运算、返回结果,就好比侦探拿着一份计划书去执行任务,再带来想要的结果

1、主程序(调用者)将参数放在过程(被调用者)可以取用的特定位置**什么位置?**
2、主程序将控制权交给过程

3、过程申请并获得存储资源
4、过程执行

5、过程将结果的值放在主程序可以取用的特定位置**什么位置?**
6、过程把控制权返还给主程序,执行调用过程指令的下一条指令**怎么找到这个位置?**

支持过程的三大寄存器

1、主程序(调用者)将参数放在过程(被调用者)可以取用的特定位置**什么位置?**

4个参数寄存器(argument reg) $a0~ $a3

5、过程将结果的值放在主程序可以取用的特定位置**什么位置?**

2个值寄存器(value reg) v 0   v0~ v0 v1

6、过程把控制权返还给主程序,执行调用过程指令的下一条指令**怎么找到这个位置?**

1个返回地址寄存器(return address reg) $ra

截至目前,学习了保存寄存器、临时寄存器各8个,零寄存器1个,以及这一页的7个
共24个寄存器,占MIPS-32寄存器总数的四分之三

主程序通过什么指令,可以跳转到过程指令,并把下一条指令的地址存入$ra?

j + addi吗?

jal – jr指令对 程序计数器

跳转并链接(jump and link)jal指令可以同时实现两个功能:
①无条件跳转到一个标签
②将下一条指令的地址放入返回地址寄存器$ra

jal Label

jal指令由调用者主程序使用,还是由被调用者过程使用?

主程序

寄存器跳转(jump reg)jr指令可以跳转到某一寄存器存储的32位地址
基本上只和返回地址寄存器搭配
jr $ra
jr指令由调用者主程序使用,还是由被调用者过程使用?

被调用者过程

遇到MIPS翻译C函数的题,这么写,可能有一分:
函数名: jr $ra

综合练习5:数组清零函数(叶过程)

void clear(int a[] . int size)
{
    for(i = 0 ; i < size ; i++) a[i] = 0;
}
clear:add $t0 $zero $zero   // i放在$t0
slt $t1 $t0 $a1
beq $t1 $zero Exit
loop:sll $t2 $t0 2
add $t3 $t2 $a0
sw $zero (0)$t3
addi $t0 $t0 1
slt $t1 $t0 $a1
beq $t1 $zero Exit
j loop
Exit:jr $ra

保存寄存器的压栈和出栈栈指针$sp

在过程调用前,主程序往往已经将自己要用的变量放在了保存寄存器中
如果过程要使用保存寄存器,要把主程序已经使用的保存寄存器入栈

栈在内存中以高地址为栈底,低地址为栈顶
,栈从高地址向低地址“生长’
**栈指针(stack pointer)**永远指向栈顶计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第8张图片

入栈时,先把$sp减去待保存的
保存寄存器个数的4倍为什么是4倍?

再用sw将保存寄存器存入栈中(方向从栈底到栈顶)
过程结束时把这些数据出栈、放回保存寄存器,供主程序继续使用
步骤正好相反

综合练习6:运算函数(叶过程)
int cal(int g , int h , int i , int j)//$a0 $a1 $a2 $a3
{
    int f;
    f = (g + h) - (i + j);
    return f;
}
//假设f存储在$s0中
cal:addi $sp , $sp , -4
sw $s0 0($sp)
add $t0 $a0 $a1
add $t1 $a2 $a3
sub $s0 $t0 $t1
addi $v0 $s0 $zero            //move $v0 $s0
lw $s0 0($sp)
addi $sp $sp 4
jr $ra
综合练习6改进:减少指令条数
int cat(int g , int h , int i , int j)//$a0 $a1 $a2 $a3
{
    int f;
    f = (g + h) - (i + j);
    return f;
}
//假设f存储在$s0中
cal:add $t0 $a0 $a1
add $t1 $a2 $a3
sub $v0 $t0 $t1
jr $ra
嵌套过程调用 综合练习7:数组求平方和(嵌套过程)

侦探搞外包、接着雇其他侦探来完成任务,就是嵌套过程调用

int square(int a)
{
    int square;
    square = a * a;
    return square;
}
int sum_of_squares(int a[] , int size)
{
    int i = 0;
    int sum = 0;
    for(i = 0 ; i < size ; i++)
        sum = sum + square(a[i]);
    return sum;
}
sum_of_squares:addi $sp $sp -4
sw $ra 0($sp)     //压栈操作放在循环外提高效率
add $t0 $zero $zero
add $t1 $zero $zero
slt $t3 $t0 $a1
beq $t3 $zer0 Exit

loop:sll $t2 $t0 2
add $t2 $t2 $a0
lw $a2 0($t2)   //因为后面要调用square所以直接放参数寄存器里面


jal square
add $t1 $t1 $v0
addi $t0 $t0 1
slt $t3 $t0 $a1
beq $t3 $zer0 Exit
j loop
Exit:move $v0 $t1 
lw $ra 0($sp)
addi $sp $sp 4      //弹栈操作放在循环外提高效率
jr $ra      

square:mul $v0 $a2 $a2
jr $ra
需要压栈保存的寄存器

[综合练习6]我们默认保存寄存器$s0~ $s7存放了主程序的变量需要由过程开始时压栈保存,结束时出栈恢复

[综合练习7]如果一个过程(外层函数)嵌套了其他过程(内层函数)外层函数通过jal修改了返回地址寄存器$ra

$ra指向外层函数jal的下一条指令 ,不再是外层函数的返回地址

栈指针寄存器$sp、栈中的内容(即栈指针以上的栈)也需要由过程保留
在addi栈指针、sw入栈、Iw出栈的过程中即可保存

结论:任何过程须显式地压栈保存即将使用的保存寄存器$s0~ s 7 ( 用哪几个存哪几个 ) ∗ ∗ ∗ ∗ 外层嵌套过程须显式地压栈保存返回地址寄存器 s7 (用哪几个存哪几个)** **外层嵌套过程须显式地压栈保存返回地址寄存器 s7(用哪几个存哪几个)外层嵌套过程须显式地压栈保存返回地址寄存器ra

进阶内容:复杂MIPS程序示例

2.8节(68页) 提供了一个递归嵌套调用过程计算阶乘的MIPS程序
2.13节(90页) 提供了一个冒泡排序过程嵌套交换过程的MIPS程序
习题2.27 (114页要素察觉) 考察双层for循环的翻译
习题2.34 (115页) 考察自嵌套调用的多参数过程的翻译

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第9张图片

过程帧与帧指针$fp

为了标记运行中过程建立的栈,除了栈顶的栈指针$sp还可以加一个帧指针(frame pointer) $fp指向栈底即过程帧的第一个字

f p 和 fp和 fpsp之间的空间由正在运行的过程使用称为过程帧,也叫活动记录

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第10张图片

全局指针$gp程序的内存分配

为了便于寻找位置固定的数据
(主程序使用的变量,以及声明为static的变量,统称静态变量)
使用一个固定指向静态数据区某一位置全局指针(global pointer) $gp

程序在内存中包含五段,地址从低到高分别为
1)保留段
2)正文段(代码段),保存指令
3)静态数据段 ,保存静态数据
4)动态数据段(堆),从低往高"生长”
5),从高往低“生长”

栈和堆此消彼长,实现了内存空间的高效利用

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第11张图片

四、寻址方式

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第12张图片

32个通用寄存器及其编号

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第13张图片

R型:寄存器寻址

所有操作数都是寄存器的指令采用寄存器寻址(register addressing)

操作数个数从一个到三个不等
R型指令<=>寄存器寻址

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第14张图片

第二部分已经提到过的R型指令有:
1、运算指令: add, sub, and, or, nor 5条三寄存器操作数指令
2、运算指令: sI|、 srl 2条双寄存器操作数指令(rs不使用置为0,使用shamt)
3、决策指令: slt 1条三寄存器操作数指令
第三部分新增R型指令:
4、决策指令: jr 1条单寄存器操作数指令

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

I型:立即数寻址和基址偏移寻址

第三个操作数(第二个源操作数)是常数的指令采用立即数寻址(immediate addressing)
具体包括addi, ori两条指令
其实还包括lui指令,课本没有着重强调其指令格式

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

两条数据传送指令|w,Sw
将基址寄存器和偏移量相加的内存寻址方式称为基址偏移寻址
可单独称为基址寻址(base addressing)和偏移寻址(displacement addressing)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

I型:PC相对寻址

两条条件分支指令beq, bne
在汇编语言中使用标签来表示分支的目标地址,标签翻译成机器语言其实是个整数
告诉计算机从当前指令的地址出发,到达分支目标地址的距离是多少
程序计数器(program counter, PC)保存了执行中指令的地址
分支指令中的16位分支地址是一个二 进制补码,可正可负
表示以PC+ 4为基准相加的字地址数目,叫做PC相对寻址(PC-relative addressing)

分支32位地址= PC + 4 +字地址偏移量

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第15张图片

J型:伪直接寻址

J型指令只需要操作码和目标地址两个字段,形式上最为简单

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

J型指令<=>伪直接寻址,包含j,jal两条
寄存器跳转jr指令是R型指令
直接寻址指的是指令中直接给出32位内存地址,但J型指令地址字段只有26位
因此,执行J型指令时,先将26位字地址左移两位(右侧补0)形成28位字节地址
再和PC的高四位拼接成32位地址
这就是
伪直接寻址(pseudodirect addressing)*

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第16张图片

扩大分支与跳转的范围

PC相对寻址以PC+4为基准,加上一个可正可负的16位补码字地址,寻址范围为
(PC + 4)- 2^17 ~ (PC + 4) + 2^17 -4大约是分支前后各128KB

伪直接寻址用PC中当前指令地址的高四位拼接指令中的26位字地址,寻址范围为
和PC高四位相同的一切地址 一个256MB的地址块

在相近的内存地址中寻址利用了加速大概率事件这一设计思想
要分支到更远距离,可以将beq/bne取反, 下接一条可能绕过的j指令
要跳转到更远距离,可以先将32位地址装载到某临时寄存器,再用jr指令

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第17张图片

//修改后
bne $s0 , $s1 , Exit
j L1
Exit:

j L

//修改后
lui $t0 高16
ori $t0 低16
jr $t0

寻址方式小结

①R型的寄存器寻址:操作数为1个/2个/3个寄存器的数据
②|型的立即数寻址: addi、 lui、 ori三 条立即数指令,其中-个操作数是指令字段中的常数
③I型的基址偏移寻址: |w、 sw两条访存指令
将rs中的基地址和偏移量直接相加,得到偏移地址以lw t 0 , 12 ( t0, 12( t0,12(s0)为例
④I型的PC相对寻址: beq、 bne两条条件分支指令
分支指令中的PC相对地址(可正可负的字偏移量)
左移两位(x4) 形成字节偏移量
再和PC+4中的字节地址相加,形成分支目标地址
以地址为1000 (十进制)的beq reg1, reg2, 4为例
⑤J型的伪直接寻址:将26位字地址左移两位(x4)形成28位字节地址
再和PC (实际上也是PC+4)的高四位拼接成32位跳转目标地址
以PC高四位为1010的i 0000 0000 0000 0000 0000 0000 01为例

MIPS汇编指令小结

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第18张图片

五、C程序执行过程

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第19张图片

C语言的四个翻译层次

编译器将高级语言文件(.c)翻译成汇编语言文件(.asm)

汇编器首先把伪指令替换为等价的真正指令,再将汇编语言翻译成机器语言目标文件(.obj)

链接器把目标文件和静态链接库(.lib)、动态链接库(.dll)拼接成可执行文件(.exe)

加载器把可执行文件放入内存,装载执行

计算机组成与设计:硬件/软件接口,第二章详细梳理,附思维导图_第20张图片

字符支持同步指令对II-sc ARM和x86简介

为了让计算机能够处理C的8位的ASCII字符,MIPS提供字节传送指令lb, sb
字符通常理解为无符号数,故取字节常使用取无符号字节lbu指令
同理,为了支持Java的16位Unicode字符,MIPS提供半字传送指令lh, sh, Ihu

当两个程序访问同一个内存单元,且其中存在写操作时,两程序操作的顺序就尤为重要
MIPS提供链接取数ll指令条件存数sc指令,让程序员能够指定程序操作数据的顺序

ARM和MIPS同为RISC架构,具有优秀的能耗表现,广泛应用于移动端和嵌入式平台
同MIPS相比,ARM的主要区别是通用寄存器更少(16个) 、寻址方式更多(9种)
Intel和AMD主导的x86是一种CISC 架构,指令集十分庞大(2018年约1400条)
x86是一-种本质非常糟糕的架构,最典型的表现是,指令长度从1B到15B不等
由于问世时间恰逢IBM进军PC领域,x86取得了巨大的商业成功,至今占据很大的份额

Intel将x86移动化的尝试屡屡碰壁,苹果将ARM电脑化的实践却高歌猛进

复习题

1、为了实现过程调用,我们引入了哪三类寄存器和哪个指令对?

a 0   a0~ a0 a3 v 0   v0~ v0 v1 $ra jal - jr

2、三类寄存器分别存放什么?指令对中的两条指令分别由谁使用,完成什么功能?

参数 返回值 返回地址

jal 主程序 跳转到寄存器指向的地址并把当前指令下一条指令地址放到$ra里面

jr 过程 跳转到寄存器指向的地址

3、当过程要使用保存寄存器时,要进行什么操作?

压栈保存

4、为什么过程内部的变量优先使用临时寄存器?

使用保存寄存器可能会和主程序争夺内存,因此要进行压栈保存出栈恢复操作,为了减少对内存的使用,我们优先选择临时寄存器

5、复习综合练习5~7,熟悉for循环、清零、函数调用等常见的C语句翻译
6、R型指令和型指令分别采用什么寻址方式? |型有哪三种寻址方式?

R:寄存器寻址(充要条件)

I:立即数寻址 基址偏移寻址 PC相对寻址

J型:伪直接寻址(充要条件)

7、PC相对寻址和伪直接寻址为了扩大寻址范围,其地址代表什么单位?

8、PC相对寻址和伪直接寻址分别怎样获得标签的真实地址?

PC相对存址的后16位存放的是相对PC + 4的偏移字地址

伪直接寻址是用后26位字地址左移两位的到28位字节地址在与PC高4位相连接得到真实地址

9、复习MIPS汇编指令,对应上每条指令的指令格式和寻址方式

10、运行(程序要经过哪四个步骤?

编译 汇编 链接 装载

你可能感兴趣的:(c语言,java,嵌入式硬件,硬件架构)