🏷️ 知识点:汇编代码
对汇编语言程序员来说,以下部件中不透明的是( )。
A. I、II和III B. IV、V和VI C. III和IV D. I、II、V和VI
[tag_link]
正确答案:C
在计算机体系结构中,对汇编语言程序员“不透明”的部件是指程序员需要直接了解或操作的部件,而“透明”的部件则由硬件自动管理,程序员无需关心其具体实现。
对于各个部件的分析如下:
- I. 指令缓冲器:用于缓存指令,由硬件自动管理,程序员不直接控制,因此是透明的。 >
- II. 移位器:执行移位操作,程序员通过移位指令(如SHL、SHR)使用,但移位器内部实现不可见,因此是透明的。 >
- III. 通用寄存器:程序员在指令中直接指定寄存器来存储数据和进行计算,是汇编编程的基础,因此是不透明的。 >
- IV. 中断寄存器:用于处理中断,程序员需要配置中断处理程序、设置中断向量等,在系统编程中直接操作,因此是不透明的。 >
- V. 乘法器:执行乘法运算,程序员通过乘法指令(如MUL)使用,但乘法器本身是硬件单元,内部实现不可见,因此是透明的。 >
- VI. 先行进位链:用于加速加法器,完全是硬件细节,程序员无需关心,因此是透明的。 >
综上所述,不透明的部件是III(通用寄存器)和IV(中断寄存器),对应选项C。 >
流水线计算机中,下列语句发生的数据相关类型是( )。 ADD R1, R2, R3; (R2)+(R3)→R1 ADD R4, R1, R5; (R1)+(R5)→R4
A. 写后写 B. 读后写 C. 写后读 D. 读后读
[tag_link]
正确答案:C
在流水线计算机中,数据相关是指令之间由于共享寄存器或内存位置而导致的依赖关系。 分析给定的两条指令:第一条指令 ADD R1, R2, R3 将 R2 和 R3 的值相加后写入 R1; 第二条指令 ADD R4, R1, R5 需要读取 R1 的值与 R5 相加后写入 R4。 因此,第二条指令读取 R1 的操作依赖于第一条指令写入 R1 的结果。
这种依赖关系是第一条指令“写”R1,第二条指令“读”R1,即写操作之后发生读操作,属于写后读数据相关。 在流水线执行中,如果第二条指令的读阶段在第一条指令的写阶段之前发生,就会读取到旧值,导致数据冲突。 其他选项如写后写、读后写和读后读均不匹配此处依赖,因为指令间没有写入同一寄存器或先读后写的场景。
(12 分)某 16 位机器所使用的指令格式和寻址方式如下所示,该机有四个 20 位基址寄存器,十六个 16 位通用寄存器(可用做变址寄存器)。指令汇编格式中的 S(源)、D(目标)都是通用寄存器,M 是主存的一个单元。三种指令的操作码分别是 MOV(OP)=(A)₁₆、STA(OP)=(B)₁₆、LDA(OP)=(C)₁₆。MOV 是传送指令,STA 为写数据指令,LDA 为读数据指令。
(1)分析三种指令的指令格式和寻址方式特点。
(2)处理机完成哪一种操作所花时间最短?哪一种最长?第二种指令的执行时间有时会等于第三种指令的执行时间吗?
(3)下列情况中,每个十六进制指令字分别代表什么操作?若有指令编码不正确,如何改正才能成为合法指令? ① (F0F1)₁₆ (3CD2)₁₆ ② (2856)₁₆ ③ (6DC6)₁₆ ④ (1C2)₁₆
[tag_link]
【解析】 本题考查指令的格式与编码。
(1)第一种指令是单字长二地址指令, RR 型 ;第二种指令是双字长二地址指令, RS 型 ,其中 S 采用基址寻址或变址寻址,R 由源寄存器决定;第三种也是双字长二地址指令, RS 型 ,其中 R 由目标寄存器决定,S 由 20 位地址(直接寻址)决定。
(2)处理机完成第一种指令所花的时间最短,因为是 RR 型指令,不需要访问存储器。第二种指令所花的时间最长,因为 RS 型指令需要访问存储器,同时要进行寻址方式的变换运算(基址或变址),这也需要时间。第二种指令的执行时间不会等于第三种指令,因为第三种指令虽然也访问存储器,但节省了求有效地址运算的时间开销。
(3)根据已知条件: MOV(OP)=001010 , STA(OP)=011011 , LDA(OP)=111100 ,将指令的十六进制格式转换为二进制代码并比较后可知: ① (F0F1)ₕ (3CD2)ₕ = 1111 00|00| 1111| 0001 0011 1100 1101 0010 ,指令代表 LDA 指令 ,编码正确,其含义是把主存 (13CD2)ₕ 地址单元的内容取至 15 号寄存器。 ② (2856)ₕ = 0010 10|00| 0101| 0110 指令代表 MOV 指令 ,编码正确,含义是把 6 号源寄存器的内容传送至 5 号目标寄存器。 ③ (6DC6)ₕ = 0110 11|01 |1100 |0110 是单字长指令,一定是 MOV 指令,但编码错误,可改正为 (29C6)ₕ 。 ④ (1C2)ₕ = 0000 00|01 |1100| 0010 是单字长指令,代表 MOV 指令,但编码错误,可改正为 (29C2)ₕ 。
(12 分)现有 4 级流水线,分别完成取指、指令译码并取数、运算、回写四步操作。假设完成各部操作的时间依次为 100ns、100ns、80ns、50ns。请问:
(1)流水线的操作周期应设计为多少?
(2)若相邻两条指令如下,发生数据相关,而且在硬件上不采取措施,那么第 2 条指令要推迟多少时间进行?
(3)如果在硬件设计上加以改进,至少需要推迟多少时间?
[tag_link]
【解析】
(1) 流水线操作的时钟周期 t 应按四步操作中的最长时间来考虑,所以 t = 100 ns 。
(2) 两条指令在流水线中执行情况如下表所示: 指令 时钟 1 时钟 2 时钟 3 时钟 4 时钟 5 时钟 6 时钟 7 ADD 取指 指令译码并取数 运算 写回 SUB 取指 指令译码并取数 运算 写回 ADD 指令在时钟 4 时将结果写入寄存器堆 (R1),但 SUB 指令在时钟 3 时读寄存器堆 (R1)。本来 ADD 指令应先写入 R1,SUB 指令后读 R1,结果变成 SUB 指令先读 R1,ADD 指令后写 R1,因而发生两条指令间数据相关。如果硬件上不采取措施,第 2 条指令 SUB 至少应推迟 2 个操作时钟周期( 2 × 100 ns ),即将 SUB 指令中的指令译码并取数阶段推迟到 ADD 指令的写回阶段之后才能保证不会出错。如下表所示: 指令 时钟 1 时钟 2 时钟 3 时钟 4 时钟 5 时钟 6 时钟 7 ADD 取指 指令译码并取数 运算 写回 SUB 取指 指令译码并取数 运算 写回
(3) 如果硬件上加以改进,可只延迟 1 个操作时钟周期(100ns)。因为在 ADD 指令中,运算阶段就已经得到结果了,因此可以通过数据旁路技术在运算结果一得到的时候将结果快速送入寄存器 R1,而不需要等到写回阶段完成。流水线中执行情况如下图所示: 时钟 1 2 3 4 5 6 7 ADD 取指 指令译码并取数 运算(并采用数据旁路技术写入寄存器 R1) 写回 取指 SUB 取指 指令译码并取数 运算 写回
某计算机的主存地址空间大小为 256MB,按字节编址。指令 Cache 和数据 Cache 分离,均有 8 个 Cache 行,每个 Cache 行大小为 64B,数据 Cache 采用直接映射方式。现有两个功能相同的程序 A 和 B,其伪代码如下所示:
// 程序 A
int a[256][256];
.....
int sum_array1()
{
int i, j, sum=0;
for (i=0; i<256; i++)
for (j=0; j<256; j++)
sum += a[i][j];
return sum;
}
// 程序 B
int a[256][256];
.....
int sum_array2()
{
int i, j, sum=0;
for (j=0; j<256; j++)
for (i=0; i<256; i++)
sum += a[i][j];
return sum;
}
假定 int 类型数据用 32 位补码表示,程序编译时 i,j,sum 均分配在寄存器中,数组 a 按行优先方式存放,其首地址为 320(十进制数)。请回答下列问题,要求说明理由或给出计算过程。
(1) 若不考虑用于 cache 一致性维护和替换算法的控制位,则数据 Cache 的总容量为多少?
(2) 数组元素 a[0][31] 和 a[1][1] 各自所在的主存块对应的 Cache 行号分别是多少(Cache 行号从 0 开始)?
(3) 程序 A 和 B 的数据访问命中率各是多少?哪个程序的执行时间更短?
[tag_link]
1)每个 Cache 行对应一个标记项,如下所示:| 有效位 | 脏位 | 替换控制位 | 标记位 |不考虑用于 Cache 一致性维护和替换算法的控制位。地址总长度为 28 位(228=256 M),块内地址 6 位(26=64),Cache 块号 3 位(23=8),故 Tag 的位数为 28-6-3=19 位,还需使用一个有效位,故题中数据 Cache 行的结构如下图所示。
数据 Cache 共有 8 行,因此数据 Cache 的 总容量为8×(64+20/8)B= 532B。
2)数组 a 在主存的存放位置及其 与 Cache 之间的映射关系如下图所示。
数组按行优先方式存放,首地址为 320,数组元素占 4 字节。a[0][31] 所在的主存块对应的 Cache 行号为(320+31×4)/64=6;a[1][1] 所在的主存块对应的 Cache 行号为(320+256×4+1×4)/64%8=5。
3)数组 a 的大小为256×256×4B=218 B, 占用218/64=212个主存块,按行优先存放,程序A逐行访问数组,共需访问的次数为216次,未命中次数为212次(即每个字块的第一个数未命中),因此程序A的命中率为(216−212)/216×100%=93.75%。【另解】数组 a 按行存放,程序 A 按行存取。每个字块中存放 16 个 int 型数据,除访问的第一个不命中,随后的 15 个全都命中,访问全部字块都符合这一规律,且数组大小为字块大小的整数倍,故程序 A 的命中率为 15/16=93.75%。程序 B 逐列访问数组 a,Cache 总容量为 64Bx8=512B,数组 a 一行的大小为 1KB,正好是 Cache 容量的 2 倍,可知不同行的同一列数组元素使用的是同一个 Cache 单元,故逐列访问每个数据时,都会将之前的字块置换出,也即每次访问都不会命中,命中率为 0。由于从 Cache 读数据比从主存读数据快很多,所以程序 A 的执行比程序 B 快得多。注意:本题考查 Cache 容量计算,直接映射方式的地址计算,以及命中率计算(注意:行优先遍历与列优先遍历命中率差别很大)。
(13分)某程序中有如下循环代码段P:“for (int i=0;i<N;i++)su m +=A[i];”。假设编译时变量sum 和i 分别分配在寄存器R1 和R2 中。常量N 在寄存器R6 中,数组A 的首地址在寄存器R3 中。程序段P 起始地址为08048100H, 对应的汇编代码和机器代码如下表所示。
| 编号 | 地址 | 机器代码 | 汇编代码 | 注释 |
|---|---|---|---|---|
| 1 | 08048100H | 00022080H | loop:sll R4,R2,2 | (R2)《2→R4 |
| 2 | 08048104H | 00083020H | add R4,R4,R3 | (R4)+(R3)→R4 |
| 3 | 08048108H | 8C850000H | load R5,0(R4) | ((R4)+0)→R5 |
| 4 | 0804810CH | 00250820H | add R1,R1,R5 | (R1)+(R5)→R1 |
| 5 | 08048110H | 20420001H | add R2,R2,1 | (R2)+1→R2 |
| 6 | 08048114H | 1446 FFFAH | bne R2,R6,loop | if (R2)≠(R6) goto loop |
执行上述代码的计算机 M 采用32位定长指令字,其中分支指令 bne 采用如下格式:
| 31 26 | 25 21 | 20 16 | 15 0 |
|---|---|---|---|
| OP | Rs | Rd | OFFSET |
OP为操作码,Rs 和Rd 为寄存器编号,OFFSET为偏移量,用补码表示。请回答下列问题,并说明理由。
(1)M 的存储器编址单位是什么?
(2)已知sll 指令实现左移功能,数组A 中每个元素占多少位?
(3)表中bne 指令的OFFSET 字段的值是多少?已知bne 指令采用相对寻址方式,当前PC内容为bne 指 令地址,通过分析题44表中指令地址和bne 指令内容,推断出bne指令的转移目标地址计算公式。
(4)若M 采用如下“按序发射、按序完成”的5级指令流水线:IF ( 取指)、ID ( 译码及取数)、EXE ( 执 行 ) 、MEM ( 访存)、 WB ( 写回寄存器),且硬件不采取任何转发措施,分支指令的执行均引起3个时 钟周期阻塞,则P 中那些指令的执行会由于数据相关而发生流水线阻塞?哪条指令的执行会发生控制冒 险?为什么指令1的执行不会因为与指令5的数据相关而发生阻塞?
[tag_link]
(1) 存储器编址单位为字节。因为每条指令占 4B,指令地址差为 4 个地址单位,故一个地址单位代表 1B。
(2) 数组 A 中每个元素占 32 位(4B)。sll 指令左移 2 位相当于乘 4,用于计算数组元素地址偏移,说明每个元素占 4B = 32 位。
(3) bne 指令的机器代码为 1446 FFFAH,后 2B 为 OFFSET 字段,值为 FFFAH(补码),即 -6。bne 指令地址为 08048114H,根据指令格式,转移目标地址计算公式为:(PC) + 4 + OFFSET × 4。执行 bne 时 PC 已自动加 4 变为 08048118H,-6 × 4 = -24,08048118H - 18H = 08048100H(loop 地址)。
(4) 由于数据相关而发生阻塞的指令为第 2、3、4、6 条。第 6 条指令会发生控制冒险。指令 1(sll)与指令 5(add R2,R2,1)之间没有数据相关,因为指令 1 写 R4,指令 5 写 R2,寄存器不同,不会发生阻塞。
对于题 43 中的计算机 M,C 语言程序 P 包含的语句 sum+=a[i];,在 M 中对应的指令序列 S 如下:
slli r4, r2, 2 // R[r4] <- R[r2]<<2
add r4, r3, r4 // R[r4] <- R[r3]+R[r4]
lw r5, 0(r4) // R[r5] <- M[R[r4]+0]
add r1, r1, r5 // R[r1] <- R[r1]+R[r5]
已知变量 i,sum 和数组 a 都为 int 型,通用寄存器 r1 - r5 的编号为 01H-05H。请回答下列问题。
(1)根据指令序列 s 中每条指令的功能,写出存放数组 a 的首地址、变参 i 和 sum 的通用寄存器编号(3 分)
(2)已知 M 为小端方式,计算机采用页式存储管理方式。页大小为 4KB。若执行到指令序列 s 中第 1 条指令时,i=5 且 r1 和 r3 的内容分别为 0000 1332H 和 0013 DFF0H。从地址 0013 DFF0H 开始存储单元内容如题 44 图所示。则执行 sum+=a[i]; 语句后。a[i] 的地址、a[i] 和 sum 的机器数分别是什么(用十六进制表示)?a[i] 所在页的页号是多少?在此次执行中,数据组 a 至少存放在几页中?(5 分)
(3)指令 slli r4, r2, 2 的机器码是什么(用十六进制表示)?若数组 a 改为 short 类型,则指令序列存到 S 中 slli 指令的汇编形式应是什么?
[tag_link]
【答案】
1)a 的首地址存放在 r3;i 存放在 r2;sum 存放在 r1。
2)a[i] 的地址为 0013 E004H;a[i] 的机器数为 FFFF ECDCH;sum 的机器数为 0000 000EH;a[i] 所在页的页号是 0013EH;数组 a 至少存放在 2 页中。
3)指令机器码为 0021 2213H。汇编形式是 slli r4, r2, 1。【解析】
1)add r4,r3,r4:这条指令将寄存器 r3 和 r4 的值相加,结果存储在寄存器 r4 中。这对应于计算数组元素的内存地址(即&a[i])。因此,我们可以推断出寄存器 r3 存储的是数组 a 的首地址,即 a 的寄存器编号为 03H。slli r4,r2,2:这条指令将寄存器 r2 的值左移 2 位,2 结果存储在寄存器 r4 中。在 C 语言中,这对应于数组索引的计算(即 i*4,因为每个 int 类型占 4 字节)。因此,我们可以推断出寄存器 r2 存储的是变量 i 的值,即的寄存器编号位 02H。add r1,rl,r5:这条指令将寄存器 r1 和 r5 的值相加,结果存储在寄存器 r1 中。这对应于累加操作(即 sum+=a[i])。因此,我们可以推断出寄存器 r1 存储的是变量 sum 的值,即 sum 的寄存器编号为 01H。所以,数组 a 的首地址、变量 i 和 sum 的通用寄存器编号分别为 03H、02H 和 01H。
2)执行 sum+=a[i] 语句后,i 保持不变即 i = 5,每个数组元素占用四个字节
i=0时,a[0]占据存储单元 FF FF FF 7Ci=1时,a[1]占据存储单元 70 FE FF FFi=2时,a[2]占据存储单元 00 00 00 00i=3时,a[3]占据存储单元 3C 02 01 FFi=4时,a[4]占据存储单元 FF FF FF 7Ci=5时,a[5]占据存储单元 F0 F1 00 00i=6时,a[6]占据存储单元 DC EC FF FF所以a[i]的地址 = 首地址 + 偏移量 =0013 E000 + 4 * (5-1)= 0013 E004H。a[i]的机器数按照小端编址,所以 DC 作为最低位放在最右边,以此类推可得:a[i] 的机器数 = FFFF ECDCH。sum 的机器数 = 0000 1332H + FFFF ECDCH = (1) 0000 000EH。由于只有 32 位,所以最高位舍掉后答案为 0000 000EH。页大小为 4KB =212 B,所以页内地址占 12 位,去掉后 12 位剩余的则是 20 位页号,a[i] 所在页页号 = 0013EH。我们有 20 位页号,根据题目可知数组跨页号了 0013E 和 0013D,所以数组 a 至少存放在 2 页中。
3)slli r4,r2,2 // R[r4]←R[r2]<<2通用寄存器 r1→r5 的编号位 01H→05H。
- 6~0:由表可得:0010011
- 11~7:rd = r2 = 00010
- 14~12:由表可知为 010
- 19~15:rd = r4 = 00100
- 24~20:shamt = 2,可以为 2420:
- 31~25:由表可知为 000 0000机器码 = 0000 0000 0010 0001 0010 0010 0001 0011B = 0021 2213H。若 a 改为 short 类型,slli 指令的汇编形式应该是
slli r4, r2, 1。
已知f(n)=n!=n×(n−1)×(n−2)×⋯×2×1,计算f(n)的 C 语言函数 f1 的源程序(阴影部分)及其在 32 位计算机 M 上的部分机器级代码如下:
int f1(int n) {
1 00401000 55 push ebp
... ... ...
if(n>1)
11 00401018 83 7D 08 01 cmp dword ptr [ebp+8],1
12 0040101C 7E 17 jle f1+35h (00401035)
return n*f1(n-1);
13 0040101E 8B 45 08 mov eax, dword ptr [ebp+8]
14 00401021 83 E8 01 sub eax, 1
15 00401024 50 push eax
16 00401025 E8 D6 FF FF FF call f1 ( 00401000)
... ... ...
19 00401030 0F AF C1 imul eax, ecx
20 00401033 EB 05 jmp f1+3Ah (0040103a)
else return 1;
}
21 00401035 B8 01 00 00 00 mov eax,1
... ... ...
26 00401040 3B EC cmp ebp, esp
... ... ...
30 0040104A C3 ret
其中,机器级代码行包括行号、虚拟地址、机器指令和汇编指令,计算机 M 按字节编址,int 型数据占 32 位。请回答下列问题:
(1) 计算 f(10) 需要调用函数 f1 多少次?执行哪条指令会递归调用 f1?
(2) 上述代码中,哪条指令是条件转移指令?哪几条指令一定会使程序跳转执行?
(3) 根据第 16 行的 call 指令,第 17 行指令的虚拟地址应是多少?已知第 16 行的 call 指令采用相对寻址方式,该指令中的偏移量应是多少(给出计算过程)?已知第 16 行的 call 指令的后 4 字节为偏移量,M 是采用大端方式还是采用小端方式?
(4) f(13)=6227020800,但 f1(13) 的返回值为 1932053504,为什么两者不相等?要使 f1(13) 能返回正确的结果,应如何修改 f1 的源程序?
(5) 第 19 行的 imul 指令(带符号整数乘)的功能是 R[eax]←R[eax]×R[ecx],当乘法器输出的高、低 32 位乘积之间满足什么条件时,溢出标志 OF=1?要使 CPU 在发生溢出时转异常处理,编译器应在 imul 指令后应加一条什么指令?
[tag_link]
1)计算 f(10) 需要调用函数 f1 共 10 次,执行第 16 行的 call 指令会递归调用 f1。
2)第 12 行的 jle 指令是条件转移指令,其含义为小于等于时转移,本行代码的意义为:当 n≤1 时,跳转至地址 0040 1035H。第 16 行的 call 指令为函数调用指令,第 20 行的 jmp 指令为无条件转移指令,第 30 行的 ret 指令为子程序的返回指令,这三条指令一定会使程序跳转执行。
3)其长度计算机 M 上按字节编址,第 16 行的 call 指令的虚拟地址为 0040 1025H,长度为 5 字节,故第 17 行的指令的虚拟地址为 0040 1025H + 5 = 0040 102AH。第 16 行的 call 指令采用相对寻址方式,即目标地址 = (PC) +偏移量,call 指令的目标地址为 0040 1000H,所以偏移量 = 目标地址 - (PC) = 0040 1000H - 0040 102AH = FFFF FFD6H。根据第 16 行的 call 指令的偏移量字段为 D6 FF FF FF,可以确定 M 采用小端方式。
4)因为 f(13) = 6227020800,其结果超出了 32 位 int 型数据可表示的最大范围,因此 f(13) 的返回值是一个发生了溢出的错误结果。为使 f1(13) 能返回正确结果,可将函数 f1 的返回值类型改为 double(或 long long,或 long double,或 float)类型。
5)若乘积的高 33 位为非全 0 或非全 1,则 OF=1。编译器应在 imul 指令后加一条“溢出自陷指令”,使得 CPU 自动查询溢出标志 OF,当 OF=1 时调出“溢出异常处理程序”。