计组习题的那些事(4)

今天起床,感觉十分通透啊,是个不错的日子!!!

这一章的核心在于熟悉指令执行时候的整个流程的硬件变化,注意各种图形,以及各种数据通路。

问题:

图 5-11 给出了执行 Add 指令的五个步骤,但在第 4 步中并没有发生任何处理操作。如果我们想要去除这一步,应该怎样修改图 5-8 中的数据通路?


答案:

将图 5-8 中 ALU 的输出直接发送至寄存器 RY,可以跳过第 4 步。我们可以给多路复用器 MuxY 增加一个输入端,并将该输入端连接到 ALU 的输出端来实现。这样,在 ALU 输出端的计算结果就会在第 3 步结束时装入寄存器 RZ 和 RY 中。对于 Add 指令,或者其他的计算型指令,我们可以在第 4 步中激活寄存器文件控制信号 RFwrite 来将 RY 的内容装入寄存器文件中。


问题:

假设在一个使用 1GHz 时钟的处理器中,所有的存储器访问操作都在一个时钟周期内完成。如果在一个程序中,Load 和 Store 指令占动态指令数的 20%,那么存储器访问操作的频率是多少?(动态指令数是指实际执行的指令数量,包括可能会使得一些指令被执行多次的程序循环。)假定所有的指令都在 5 个时钟周期内执行完成。


答案:

读取每一条指令时都会涉及一次存储器访问。还有 20% 的指令需要对存储器进行第二次访问以便读取或写入存储器操作数。平均而言,在 5 个时钟周期里,每条指令会进行 1.2 次存储器访问。因此,存储器访问的频率是 (1.2 / 5) × 10⁹,即每秒 2.4 亿次。


解释:

  1. 指令存储器访问:每条指令都需要从存储器中读取,这意味着每执行一条指令就会进行一次存储器访问。

  2. Load 和 Store 指令的额外访问:程序中有 20% 的指令是 Load 或 Store,这类指令需要额外的存储器访问来读写数据。因此,这部分指令每条需要进行 2 次存储器访问。

  3. 平均存储器访问次数:假设每条指令在 5 个时钟周期内执行完成。除了每条指令的读取操作外,20% 的指令(即 Load 和 Store 指令)还需要额外的访问,因此每条指令平均会进行:

    $ 1 (1 - 0.2) + 2 = 1.2 $

  4. 存储器访问频率:每个时钟周期为 1 纳秒(由于处理器时钟为 1 GHz,即每秒 10⁹ 个周期)。存储器访问次数为每条指令的 1.2 次存储器访问,结合 5 个时钟周期执行一条指令的情况,存储器的访问频率为:

    $ = ^9 = 2.4 ^8 $

因此,存储器的访问频率是每秒 2.4 亿次。


问题:

请给出RISC风格处理器中从子程序返回(Return-from-subroutine)指令的动作序列。假设存储了子程序返回地址的通用寄存器的地址LINK在与寄存器文件的地址A相连的指令字段中给出(\(IR_{31-27}\))。


解答:

在RISC风格处理器中,从子程序返回的指令(例如,Return-from-subroutine)的执行步骤需要从存储器中获取子程序的返回地址,并将其载入程序计数器(PC)以实现跳转。具体的步骤如下:

1
2
3
4
5
6
1) 存储器地址 ← [PC], 读取存储器, 等待 MFC (Memory Function Complete), IR ← 存储器数据, PC ← [PC] + 4
2) 指令译码, RA ← [LINK]
3) PC ← [RA]
4) 空操作
5) 空操作

  1. 从存储器读取指令
    • 存储器地址 ← [PC],读取存储器中的指令。
    • 等待存储器完成数据传送(MFC: Memory Function Complete)。
    • IR ← 存储器数据,指令(IR)被加载到指令寄存器(IR)中。
    • PC ← [PC] + 4,程序计数器(PC)递增,指向下一条指令。
  2. 指令译码并读取返回地址
    • 根据指令字段,提取存储返回地址的通用寄存器的地址(LINK)。
    • RA ← [LINK],将寄存器LINK中的值读取到寄存器RA中,RA保存的是子程序的返回地址。
  3. 将返回地址加载到PC中
    • PC ← [RA],将寄存器RA的值(即返回地址)加载到PC中,从而实现从子程序返回。
  4. 空操作
    • 第四步为占位步骤,不执行任何操作,只是为了匹配指令周期。
  5. 空操作
    • 同样,第五步也为占位步骤,用于维持统一的指令周期。

解释

  • 第一步:从存储器读取当前指令,并更新PC指向下一条指令。
  • 第二步:根据指令字段提取返回地址(存储在LINK寄存器中),将其装入RA寄存器。
  • 第三步:使用RA寄存器中的返回地址更新PC,实现程序跳转到子程序返回地址。
  • 第四步与第五步:这些步骤是占位的,不执行任何操作,只是为了与其他指令保持一致的处理周期。

通过这些步骤,处理器完成了从子程序返回的操作,恢复执行到子程序调用点之后的指令。


问题:

某处理器的中断结构如下:当收到一个中断时,会将该中断的返回地址保存到通用寄存器IRA中。处理器状态寄存器PS的当前内容,会被保存在一个特殊的寄存器IS中,该寄存器不是通用寄存器。中断服务程序从地址ILOC开始。

假设处理器在每条指令的最后一个执行步中进行中断检测。如果出现中断请求,并且处理器允许中断,则该中断请求被接受。处理器会保存PC和PS并跳转至IOC,而不是去读取下一条指令。请给出执行这些操作的相应步骤序列。为了支持中断处理,还需要在图5-18到图5-20中增加哪些硬件?

image-20241207140603894
image-20241207140708451

解答
指令执行的前两步,取指令和指令译码,在中断的情况下是不需要的。这两步可以被跳过或者为空操作以保持5步序列。我们可以用与子程序调用指令完全相同的方式来保存PC。图5-18中的多路复用器MUXC需要增加一个输人端,并将其与寄存器IRA的地址相连。为了将中断服务程序的起始地址装人PC中,我们需要为图5-20中的MuxPC增加一个输人端与ILOC值相连。寄存器PS与IPS应该直接互连,这样可以使数据在两者之间传输。

执行步骤序列:

1
2
3
4
5
6
1) 取指令(跳过,或为空操作,因处理中断)
2) 指令译码(跳过,或为空操作,因处理中断)
3) PC-Temp ← [PC], PC ← ILOC, IPS ← [PS], 禁止中断
4) RY ← [PC-Temp]
5) IRA ← [RY]

硬件改动:

  • 图5-18: 增加多路复用器MUXC的新输入端,并将其与寄存器IRA的地址连接。
  • 图5-20: 增加多路复用器MuxPC的新输入端,并将其与ILOC值连接。
  • 需要直接连接寄存器PS与IPS,以实现数据在两者之间的传输。

问题:

图5-2中,组合电路的传播延迟为600ps(皮秒:\(10^{-12}\)秒)。寄存器的准备时间需要50ps,从时钟输入端到Q输出端的最大传播延迟为70ps。
(a) 如果该电路正确操作,则其最小时钟周期是多少?
(b) 假设该电路被重新组织为图5-3中的三个阶段,这样该组合电路在每个阶段的延迟是200ps。请问这种情况下最小的时钟周期是多少?

解答:
(a) 最小时钟周期需要考虑所有的传播延迟和寄存器的准备时间。时钟周期应包括从时钟输入端到Q输出端的传播延迟、组合电路的传播延迟以及寄存器的准备时间。
因此,最小时钟周期为:
$ = 70 + 600 + 50 = 720 $

  1. 在重新组织为三个阶段后,每个阶段的传播延迟为200ps。时钟周期需要考虑每个阶段的传播延迟、寄存器的准备时间以及从时钟输入端到Q输出端的传播延迟。
    因此,最小时钟周期为:
    $ = 70 + 200 + 50 = 320 $

问题:

在读取指令 Load R6, 1000(R9) 时,R6 和 R9 中的值分别为 4200 和 85320。存储单元 86320 中的值是 75900。请给出在该指令五个执行步骤的每一步中,图5-8中段间寄存器的内容。

注意寄存器是有滞后效应的。

解答:
图5-8显示了执行该指令的五个步骤。每个步骤中,数据流动通过不同的寄存器,这些寄存器会在时钟周期结束时接收新的值。以下是每个步骤的详细解释:

  1. 步骤 1 (取指令):
    在这一步,程序计数器 (PC) 的内容被送到指令寄存器 (IR) 中,指令被读取进来。然而,由于这一步是取指令阶段,段间寄存器的内容还没有更新。
    RA, RB, RZ, RM, RY 都是由上一条指令的执行结果决定的,因此它们的值为 *,即由上一步的指令决定。

  2. 步骤 2 (指令译码):
    在这一步,指令寄存器中的内容被译码,IR中的寄存器选择字段将R6和R9加载到段间寄存器RA和RB中。

  3. 步骤 3 (计算地址):
    在这一步,计算内存地址并传递给 RM。指令 Load R6, 1000(R9) 要读取存储单元 86320,因此计算地址 1000 + 85320 = 86320

  4. 步骤 4 (内存访问):
    在这一步,从内存中读取数据。地址 86320 的值为 75900,这个值被存储到 RY 寄存器中。

  5. 步骤 5 (写回):
    在这一步,读取的数据(75900)将写回到寄存器 R6 中。因此,R6 将得到 75900。

总结:

步骤 RA RB RZ RM RY
步骤 1 * * * * *
步骤 2 * * * * *
步骤 3 85320 4200 * * *
步骤 4 85320 4200 86320 4200 *
步骤 5 85320 4200 86320 4200 75900

问题:

图 5-12 给出了不同指令组其寄存器地址的位字段分配情况。为什么所有的指令要使用相同的字段位置?

解答:
所有指令使用相同的字段位置是为了优化处理器的设计,确保指令译码的效率。具体原因如下:

  1. 简化硬件设计:
    如果所有指令的寄存器地址字段都使用相同的位置,处理器硬件就可以在指令解码之前直接读取源寄存器的值。这减少了指令解析时的复杂性,使硬件设计更简单。

  2. 提高执行效率:
    在图5.11中,例如,通过使用相同的位置,处理器可以在指令译码的第二步(即指令解码之前)就从寄存器文件中读取源寄存器的内容。这意味着处理器可以同时执行指令解码和寄存器读取两个操作,从而提高执行效率。

因此,所有指令使用相同的寄存器字段位置是为了优化硬件设计和提高处理器执行速度。


问题:

在程序执行的某个时刻,寄存器R4,R6和R7中的值分别为1000,7500和2500。请给出在读取并执行指令
Subtract R6, R4, R7
的第3步至第5步以及读取下一条指令的第1步时,寄存器RA、RB、RZ、RY和R6的内容。

解答:

image-20241207142849851

我们可以根据指令的执行步骤来逐步推导出各寄存器的内容。

  1. 第3步:RA=1000, RB=2500, RZ=*, RY=*, R6=7500
  2. 第4步:RA=1000, RB=2500, RZ=-1500, RY=*, R6=7500
  3. 第5步:RA=1000, RB=2500, RZ=-1500, RY=-1500, R6=7500
  4. 第1步(下一条指令):RA=1000, RB=2500, RZ=-1500, RY=-1500, R6=-1500

问题:

指令 And R4, R4, R8 存放在存储单元 0x37C00 处。在读取该指令时,寄存器 R4 和 R8 的值分别为 0x10000xB2500。请给出图 5-8 和图 5-10 中该指令执行的每个时钟周期以及下一条指令的第一个时钟周期中,寄存器 PC、R4、RA、RM、RZ 和 RY 的值。

解答:

image-20241207144106370

问题:

第2章所描述的子程序调用指令总是使用相同的通用寄存器 LINK 来保存返回地址。因此,指令中不包含返回寄存器的地址。然而,在子程序返回指令中,地址 LINK 却包含在位 IR31−27 中(参见5.4.1节和例5.4)。为什么这两条指令会有这样的区别?

答案: LINK 寄存器需要在返回子程序指令的第2步中被读取,即在指令解码之前。由于处理器在第2步中总是读取由 IR31−27 位指定的寄存器,而不等待指令解码完成,因此 LINK 的地址被放置在 IR31−27 位。这样可以确保在读取寄存器内容时不会受到指令解码延迟的影响,使得处理器能够更高效地处理子程序返回操作。


问题:

对于具有例5.5所示中断结构的处理器,请给出其 Return-from-interrupt 指令的执行步骤序列。假设寄存器 IRA 的地址在指令的位 IR[i-27] 中给出。

答案: Return-from-interrupt 指令与返回子程序指令类似,恢复 PC 和处理器状态寄存器(PS)的内容。不同的是,它使用寄存器 IRA 而不是寄存器 LINK 来恢复 PC,并从寄存器 IPS 恢复 PS。其执行步骤如下:

  1. 存储器地址 ← [PC],读取存储器,等待 MFC,IR ← 存储器数据,PC ← [PC] + 4 (指令的读取并更新 PC)
  2. 解码指令,RA ← [IRA] (从寄存器 IRA 中读取返回地址,并将其存储到寄存器 RA)
  3. PC ← [RA], PS ← [IPS] (将返回地址加载到 PC 中,恢复处理器状态寄存器 PS 的内容)
  4. 无操作 (无进一步操作)
  5. 无操作 (无进一步操作)

解释: 此序列类似于返回子程序指令,只是处理的是中断上下文,恢复的内容包括程序计数器 PC 和处理器状态寄存器 PS。


问题:

考虑一个指令集,其指令的编码方式使得不同指令的寄存器地址并不总在相同的位位置中。请问这会对指令的执行步骤造成什么影响?在这种情况下,应该怎样做才能保持五步的执行序列?假设使用与图5-8相同的硬件结构。

答案: 如果寄存器地址不在所有指令的相同位位置中,处理器需要在读取源寄存器之前,至少部分地解码指令。源寄存器的地址必须通过解码指令来确定,这就意味着在执行步骤中需要调整顺序。具体来说,源寄存器的读取将会推迟到第3步,从而增加一个执行步骤。

为了保持五步的执行序列,通常有两种方法:

  1. 扩展时钟周期: 可以延长时钟周期,在第2步结束后读取源寄存器,这要求在指令解码完成后足够的时间来识别寄存器地址的位置。这种方法可以在解码后尽早读取寄存器,在第3步完成后继续执行,保持五步执行序列。
  2. 推迟寄存器读取: 另一种选择是将源寄存器的读取推迟到第3步,并直接将寄存器内容发送到ALU。这意味着在第3步之前,寄存器RA和RB就不再需要。这种方法要求时钟周期足够长,以容纳一次寄存器访问和ALU操作。

解释: 由于寄存器地址在指令编码中的位置不固定,处理器需要先解码指令以确定寄存器的位置。这会增加额外的延迟,从而影响指令的执行步骤。为了确保五步执行序列,必须调整时钟周期,或者推迟寄存器读取到后续步骤,或延长解码和读取寄存器的时间。这两种方法的优劣取决于硬件设计和相关延迟。


问题:

假设立即操作数占据指令的IR21-6位。该立即值在算术运算指令中被符号扩展为32位,如Add指令;在逻辑运算指令中被用零填充为32位,如AND指令。请为图5-9中的立即数模块设计一种合适的实现方式。

答案:
在这种情况下,立即数的扩展方式由一个控制输入SE决定。若SE = 1,则立即数会进行符号扩展;若SE = 0,则立即数会进行零填充。为此,立即数模块的输出Imm31-0可以按如下方式生成:

  • Imm0 = IR6
  • Imm1 = IR7
  • ...
  • Imm15 = IR21
    (这些是立即数的低16位,直接从指令中的IR6到IR21位获得)

对于高16位的扩展:

  • Imm16 = SE * IR21
  • Imm17 = SE * IR21
  • ...
  • Imm31 = SE * IR21

解释:
这里,IR6IR21提供了16位立即数。在符号扩展的情况下,SE = 1时,IR21的值会被复制到高16位,这样保持符号一致;而在零填充的情况下,SE = 0时,IR21的值会被填充为0,填充至高16位。这样就可以根据SE控制输入,生成正确的立即数并传递到后续模块。


问题:

假设使用图5-4中五步序列的RISC处理器由一个1GHz的时钟驱动。一个大型程序中的指令统计结果如下:

  • Branch: 20%
  • Load: 20%
  • Store: 10%
  • 计算型指令: 50%

请预测在下面每一种情况中指令执行的速率:

  1. 存储器访问始终在1个时钟周期内完成。
  2. 90%的取指令操作在一个时钟周期内完成,另外10%则需要4个时钟周期。而Load或Store指令中的数据操作数访问则平均在3个时钟周期内完成。

答案:

(a) 存储器访问始终在1个时钟周期内完成:
在这种情况下,所有指令的执行时间固定为5个时钟周期(因为每条指令按照五步序列执行)。因此,指令执行速率为:
$ = = 200 $

(b) 90%的取指令操作在一个时钟周期内完成,另外10%则需要4个时钟周期。而Load或Store指令中的数据操作数访问则平均在3个时钟周期内完成:
首先,计算取指令的平均执行时间:

  • 90% 的取指令需要1个时钟周期,10% 的取指令需要4个时钟周期:
    $ = 0.9 + 0.1 = 1.3 $

接下来,计算其他指令的执行时间:

  • 计算型指令和分支指令:这两类指令不涉及内存访问,只需要5个时钟周期。
  • Load和Store指令:需要5个时钟周期,加上数据访问的额外3个时钟周期(平均值),因此总共需要8个时钟周期。

然后,计算指令的平均完成时间: $ = 1.3 + (0.2 + 0.5) + (0.2 + 0.1) = 5.9 $

最后,计算指令执行速率:
$ = = 169.5 $

解释:
(a) 由于每条指令始终在5个时钟周期内执行,因此执行速率是1GHz时钟下的200百万指令每秒。

  1. 当取指令的时钟周期不一致,并且Load/Store指令需要更多的时间来访问数据时,平均每条指令的执行时间增加了,因此指令执行速率下降至169.5百万指令每秒。

问题:

计算型指令的执行按照图5-11中Add指令的模式进行,其中在第4步中没有执行任何操作。考虑一个程序,其指令统计结果在习题5.11中给出。请估测在取消第4步的情况下,指令执行速率的提升效果。假设所有的执行步都在一个时钟周期内完成。

答案: 在取消第4步的情况下,计算型指令将只需要4个时钟周期来完成,而不是原来需要的5个时钟周期。

  • 程序中的指令统计结果如下:
    • 50%的指令是计算型指令(Add指令)
    • 20%的指令是Branch指令
    • 20%的指令是Load指令
    • 10%的指令是Store指令

假设每个指令执行的时钟周期如下:

  • 计算型指令:4个时钟周期(取消第4步后的情况)
  • Branch指令:5个时钟周期(按原执行序列)
  • Load/Store指令:5个时钟周期(按原执行序列)

我们可以计算新的指令执行速率:

平均指令执行时间=\((0.5×4)+(0.2×5)+(0.2×5)+(0.1×5)=2+1+1+0.5=4.5时钟周期\text{平均指令执行时间} = (0.5 \times 4) + (0.2 \times 5) + (0.2 \times 5) + (0.1 \times 5) = 2 + 1 + 1 + 0.5 = 4.5 \text{时钟周期}\)

因此,指令执行速率为:

指令执行速率=\(1×1094.5=222.2百万指令每秒\text{指令执行速率} = \frac{1 \times 10^9}{4.5} = 222.2 \text{百万指令每秒}\)

解释: 通过取消第4步,计算型指令的执行时间减少了1个时钟周期,因此程序的平均指令执行时间从原来的5时钟周期减少到了4.5时钟周期。结果,指令执行速率提升到222.2百万指令每秒,相较于取消第4步前的169.5百万指令每秒,提升了约30%。


问题:

图5-16显示,条件转移指令的第3步可能会使得一个新值被装入PC中。在流水线处理器中我们希望在执行序列中尽早确定条件转移的结果。请问需要对硬件进行什么样的改变才可以把第3步的操作移到第2步中?分析这两步中的每一个操作,并说明哪些操作可以并行执行,哪些操作必须顺序执行。

答案: 为了将条件转移的第3步操作移到第2步,需要对硬件做出一些修改,以使得在第2步中尽早确定条件转移的结果。以下是具体的解决方案和分析:

需要的硬件改变:

  1. 计算新的PC值: 在第2步,除了通常的PC递增操作(即 [PC] + 4)外,硬件需要能够根据指令中的分支偏移量(Branch offset)计算更新后的PC值。这个操作可以在第2步完成。
  2. 条件判断: 在第2步中,硬件还需要将寄存器文件输出的两个操作数直接输入到比较器(Comparator)中进行比较。如果分支条件成立,比较器会输出一个信号,指示是否跳转。
  3. 更新PC: 如果分支条件被满足,可以在第2步时直接将新的目标地址([PC] + Branch offset)装入PC,而不是等待第3步。

需要并行执行的操作:

  • 读取寄存器文件: 读取寄存器文件是第2步中的第一项操作。可以在这一时刻完成,并将数据发送给比较器进行条件判断。
  • 比较操作: 在获取两个寄存器的值之后,可以立刻进行比较操作。比较器根据两个操作数的值决定是否满足分支条件。

必须顺序执行的操作:

  • 更新PC: 更新PC必须在比较操作完成后进行。因此,更新PC的操作必须顺序执行,只有在确定分支条件之后才能更新PC。

总结:

为了将条件转移指令的第3步操作移到第2步中,必须确保硬件能够在第2步同时进行寄存器读取、比较操作和PC更新。这要求时钟周期足够长,能够容纳这三个操作的完成。在这种情况下,第2步的操作将包括:读取寄存器文件、执行比较并根据条件决定是否更新PC。


问题:

我们已经知道 RISC风格的指令可以在图5-8的多阶段硬件中用图5-4所示的步骤来执行。RISC风格的指令集中不包括自动增量和自动减量寻址方式。请解释指令 Load R3, (R5)+ 为什么不能在图5-8的硬件中执行。

答案: Load R3, (R5)+ 是一种使用自动增量寻址方式的指令,意味着在读取存储器操作数之后,寄存器R5的值会被自动增量(通常加4)。该指令的执行涉及两个操作:

  1. 读取内存:指令会使用R5中的地址去内存中读取数据。
  2. 更新寄存器R5:在读取数据后,R5的值应该增加4,表示下次寻址时会使用新的地址。

问题的关键在于,图5-8中的硬件结构不支持在一个时钟周期内同时完成这两个操作

  • 内存操作需要在执行Load指令时访问内存并将数据加载到寄存器R3中。
  • 寄存器更新需要在同一时刻将R5更新为其原始值加上4。

在图5-8的硬件中,指令的执行是逐步进行的。具体地,在执行“加载”指令时,数据从内存读取并传输到寄存器R3。然而,寄存器R5的更新必须在该过程之后完成。但由于这两个操作——内存读取寄存器更新——需要在同一时刻完成,而图5-8的硬件结构无法同时执行这两个操作,因此无法支持自动增量寻址方式。

解释:

  • Load R3, (R5)+的执行过程中,需要完成两个任务:一是读取内存内容,二是更新R5寄存器的值。这两个操作的顺序无法被硬件同时支持,因此需要修改硬件结构或分多步完成这些操作。
  • 图5-8的硬件结构只能处理单一的操作步骤,不支持在同一个时钟周期内同时执行内存读取和寄存器更新。

因此,Load R3, (R5)+指令无法直接在图5-8的硬件结构中执行,需要额外的机制来支持自动增量寻址模式。


问题:

2.9节描述了如何使用 OrOrHigh 两条指令来将一个 32位的值装入寄存器中。请问为了实现 OrHigh 指令,还需要在处理器的数据通路中新增哪些功能?请给出读取及执行该指令的动作序列。

答案: 为了实现 OrHigh 指令,需要在处理器的数据通路中新增一个功能,即能够将指令中的立即数数据(IR21-6)左移16位,并将其填充到目标寄存器的高16位,低16位设置为0。具体而言,这要求在立即数模块(Immediate Block)中实现一个左移操作,将立即数移动到目标位置。

新增的功能:

  • 立即数左移: 在数据通路中需要实现一个左移模块,将立即数的高16位(IR21-6)左移16位,并将低16位填充为0。这将把32位的立即数装入寄存器的高16位,而低16位则填充为0。

读取及执行 OrHigh 指令的动作序列:

  1. 取指阶段: PC ← [PC] + 4,取指令并加载到IR。
  2. 译码阶段: Decode instruction, RA ← Ri 在这一步,指令被译码,源寄存器 Ri 的地址被加载到寄存器 RA
  3. 执行阶段: RZ ← [RA] OR Imm 从寄存器 RA 中读取数据,并将其与立即数(Imm)进行按位“或”运算。此时,立即数 Imm 已经被左移并填充到高16位,低16位为0。
  4. 写回阶段: RY ← [RZ] 将按位“或”运算的结果 RZ 传送到寄存器 RY
  5. 写回寄存器: Ri ← [RY] 将结果 RY 写回目标寄存器 Ri

解释:

  • OrHigh 指令通过操作寄存器中的数据与立即数,并将结果写回寄存器。不同于普通的 Or 指令,OrHigh 需要将立即数的高16位与寄存器中的值进行“或”运算,而低16位置为0。这一处理方式通过左移立即数并按位“或”实现。

问题:

在指令处理的第1步中,启动一个存储器读操作以读取在存储单元 0x46000 处的指令。然而由于在高速缓存中没有找到该指令,所以该读操作被延迟,MFC信号直到第四个时钟周期才被激活。假设该延迟按5.6.2节中所述的方式进行处理。请分别给出在第1步的四个时钟周期中以及第2步中PC的内容。

答案:

image-20241207151256014

问题:

请给出读取并执行例5.6中所使用的两条特殊指令:

  1. MoveControl Ri, IPS
  2. MoveControl IPS, Ri

答案:

对于MoveControl Ri, IPS指令,执行步骤如下:

  1. 第3步: 无操作(No action)。
  2. 第4步:IPS的值加载到RY中,即 RY ← [IPS]
  3. 第5步:RY的值写入寄存器Ri中,即 Ri ← [RY]

对于MoveControl IPS, Ri指令,执行步骤如下:

  1. 第2步: 将寄存器Ri的值加载到寄存器RA中,即 RA ← [Ri]
  2. 第3步: 将寄存器RA的值写入IPS中,即 IPS ← [RA]
  3. 第4步: 无操作(No action)。
  4. 第5步: 无操作(No action)。

解释:

  • MoveControl Ri, IPS指令的功能是将IPS寄存器的内容移动到寄存器Ri中,因此在执行过程中,首先需要在第4步将IPS的值加载到中间寄存器RY中,然后在第5步将RY的值存回寄存器Ri
  • MoveControl IPS, Ri指令的功能是将寄存器Ri的内容存储到IPS寄存器中。在执行过程中,首先将寄存器Ri的值加载到中间寄存器RA,然后在第3步将RA的值存储到IPS寄存器。

这些指令的操作是对寄存器的内容进行控制和交换,用于保存或恢复控制寄存器的数据。


问题:

图 5-8和图 5-22的硬件结构之间的本质区别是什么?通过确定在图5-8所示的硬件中执行指令Subtract LOC, R5时可能会遇到的困难来说明你的答案。该指令执行以下操作: LOC ← [LOC] - [R5],其中LOC是一个存储单元,其地址由一条双字指令的第二个字给出。

image-20241207152749107

答案:

图 5-8 和图 5-22 的本质区别:

  • 图 5-8实现的是一种具有固定执行步骤(五步)的硬件结构,其中每个指令按照预定的五个步骤执行,每个步骤执行一个操作。每个步骤被分配到不同的硬件阶段,并且这些阶段通过硬件连接进行顺序执行。由于这种固定的五步执行模式,硬件的操作限制了指令执行的灵活性,无法根据指令需求灵活调整数据流动。
  • 图 5-22提供了一个更灵活的硬件结构,其中可以根据指令的需求在不同的硬件单元之间随时传输数据。硬件模块之间没有严格的步骤限制,允许执行过程中动态地选择需要的数据路径,步骤数也可以根据需要变化。这种灵活性使得指令执行更加高效和灵活。

在图 5-8 中执行Subtract LOC, R5指令时遇到的困难:

指令Subtract LOC, R5的执行涉及以下几个步骤:

  1. 从指令的第二个字获取LOC地址。
  2. 读取内存位置LOC中的值。
  3. 执行减法操作:[LOC] - [R5]
  4. 将结果存回LOC。

在图 5-8 中,由于硬件的五步固定顺序,以下操作无法在一个固定的时间内完成:

  • 步骤1:LOC的地址是从指令的第二个字中提取的,但在图 5-8 中,所有指令的获取、解码等操作必须按照预定的顺序进行。因此,无法在步骤1和步骤2之间灵活地操作数据。
  • 步骤2:内存访问需要特定的步骤完成,在图 5-8 中,内存访问通常是在第四步或之后进行的,这与指令的需求(需要在较早的步骤中访问LOC)相冲突。
  • 步骤3和步骤4:减法操作和存储回内存LOC的过程不能在固定的五步框架中灵活执行,导致需要延迟执行某些操作,影响执行效率。

相比之下,图 5-22的硬件架构允许数据在执行过程中自由流动,可以在任何时刻从任何硬件单元读取或写入数据,使得像Subtract LOC, R5这样需要灵活数据流动的指令可以更加高效和灵活地执行。

解释: 图 5-8 中的五步固定序列使得每个操作都必须按严格的顺序执行,这限制了指令执行的灵活性和效率。而图 5-22的硬件结构通过允许动态的数据流动和更灵活的执行步骤,使得执行复杂指令时不需要遵循固定的步骤顺序,能够更高效地满足指令的执行需求。


问题:

考虑执行5.4.1节给出的指令所需的动作。对于这些指令,请推导出生成图5-18和图5-19中Cselect、MA select和Y select信号的逻辑表达式。

答案:

符号说明:

  • Rgr:表示“寄存器到寄存器”的指令类型(例如加法、减法等寄存器间的操作)。
  • Imd:表示“使用立即数”的指令(例如加法指令中有立即数操作数)。
  • Mem:表示“内存操作指令”,如加载(Load)和存储(Store)指令。
  • Sbr:表示“子程序调用”指令(例如调用子程序的跳转指令)。
  • Cselect0 和 Cselect1:选择目标寄存器的控制信号。Cselect信号决定了在执行指令时,目标寄存器应选择哪个。
  • MA select:选择内存地址的控制信号。MA select决定了用来访问内存的地址源。
  • Y select:选择Y寄存器输入的控制信号。Y select决定了Y寄存器应该接收来自哪里(可能是内存或寄存器)。

任务:

我们需要根据指令的类型,推导出控制信号 CselectMA selectY select 的逻辑表达式。根据题目,指令解码器会产生一个控制信号,这些信号决定了指令的执行方式。

步骤一:推导 Cselect 的逻辑表达式:

image-20241207153350820

如果是三指令,也就是寄存器到寄存器,就是01,如果是子程序调用指令,就是10。

Cselect 信号用于选择目标寄存器,包含两个比特:Cselect0Cselect1。根据题目中给出的条件,Cselect的取值会根据指令类型有所不同:

  • Rgr:如果是寄存器到寄存器的操作(如加法、减法等),则Cselect = 01
  • Sbr:如果是子程序调用指令(如调用某个函数),则Cselect = 10
  • 对于其他类型的指令(如加载、存储等),则Cselect = 00

因此,Cselect 的控制信号需要根据指令类型来选择寄存器:

  • Cselect0 = Rgr
    如果是寄存器到寄存器的指令(Rgr指令),则Cselect0设置为1,否则为0。

  • Cselect1 = Sbr
    如果是子程序调用指令(Sbr指令),则Cselect1设置为1,否则为0。

逻辑表达式:

  • Cselect0 = Rgr
  • Cselect1 = Sbr

步骤二:推导 MA select 的逻辑表达式:

MA只会是PC和RZ,而RZ的存储在第四周期。

image-20241207153516876

MA select 信号用于选择内存地址的来源。在执行指令的过程中,内存地址可以来自不同的地方:

  • 步骤4(T4)时,MA select选择寄存器Z作为内存地址源。
  • 在其他步骤时,MA select选择程序计数器(PC)作为内存地址源。

因此,MA select 信号只与时间步骤(T4)有关。

逻辑表达式:

  • MA select = T4

步骤三:推导 Y select 的逻辑表达式:

image-20241207153634045

Y select 信号决定了Y寄存器的输入来源。Y select信号会根据指令类型选择Y寄存器的输入:

  • 对于Mem指令(加载或存储指令),Y select = 1
  • 对于Sbr指令(子程序调用指令),Y select = 2
  • 对于其他指令,Y select = 0

因此,Y select0Y select1 的逻辑表达式如下:

  • Y select0 = Mem
    只有当指令是内存操作(如加载)时,Y select0才为1。

  • Y select1 = Sbr
    只有当指令是子程序调用指令时,Y select1才为1。

逻辑表达式:

  • Y select0 = Mem
  • Y select1 = Sbr

总结:

根据上面的推导,三种控制信号的逻辑表达式为:

  1. Cselect0 = Rgr
    Cselect1 = Sbr

  2. MA select = T4

  3. Y select0 = Mem
    Y select1 = Sbr

这些逻辑表达式决定了在不同类型的指令执行时,如何选择寄存器和内存操作数,并且如何控制寄存器Y的输入。


问题:

为什么在5.6.2节所给出的 Counterenable 的逻辑表达式中需要同时包含 WMFCMFC 两个信号?

答案与解释:

WMFC信号标识了一个步骤,在该步骤中会发出读存储器或写存储器命令。 在这些步骤中,计数器的递增必须延迟,直至MFC信号被置为有效状态。


问题:

请说明如果将5.6.2节所给出的PC enable表达式中的 MFC变量省略掉,会发生什么情况?

在步骤1中,当从存储器中取指令时,程序计数器(PC)被使能。如果指令未在高速缓存中找到,而必须从主存储器中读取,那么该步骤将涉及若干个时钟周期。 若没有MFC信号,程序计数器(PC)会在每个周期中被错误地递增。


问题:

请推导出生成图5-20所示的 PC selectINC select 信号的逻辑表达式,考虑执行以下指令所需的操作:

  • Branch:所有转移指令,其中每条指令都包括一个16位的转移偏移量
  • Call register:子程序调用指令,其子程序的地址在一个通用寄存器中给出
  • Other:所有不包含转移的其他指令

答案与解释:

在调用寄存器指令的第3步(T3阶段),多路复用器MuxPC选择寄存器A(RA)。而在其他所有时候,它会选择加法器的输出。 多路复用器MuxINC在第3步选择立即数,该立即数将用于分支指令当中。

image-20241207154343773
image-20241207154254251

问题:

5.25 请给出在图5-24所示的处理器中读取并执行指令 Load R3, (R5)+ 的步骤序列。假设操作数是32位。

5.26 一个CISC风格的处理器将子程序的返回地址保存在处理器堆栈中,而不是在预先定义的寄存器 LINK 中。请给出在图5-24所示的处理器中执行 Call register 指令的动作序列。


答案与解释:

5.25 指令:Load R3, (R5)+

这条指令的含义是:从由 R5 指定的内存地址中加载数据,并将加载的数据存储到 R3 中。然后,将 R5 寄存器的值增加4(模拟字节地址的递增)。

在图5-24所示的处理器中,执行此指令的步骤序列如下:

  1. 读取内存地址 Memory address ← [R5] 计算内存地址,该地址由 R5 寄存器给出。
  2. 读取内存数据 Read memory, Wait for MFC, Temp1 ← Memory data 读取内存中的数据,等待 MFC(Memory Function Complete)信号确认内存读取操作完成,并将读取到的数据存储到临时寄存器 Temp1 中。
  3. 更新 R5 寄存器的值 R5 ← [R5] + 4R5 寄存器的值增加4,模拟加载指令的自增寻址模式,即 R5 的值增加一个字节的大小(假设32位操作数,4字节)。
  4. 将读取的数据存入 R3 R3 ← [Temp1] 将从内存中读取到的数据(存储在 Temp1 寄存器中)存入 R3 寄存器。

5.26 指令:Call Register R5, R7

这条指令的含义是:从 R5 寄存器中获取子程序地址,并将当前的程序计数器(PC)值保存到由 R7 指向的堆栈中。接着,更新 PC 为新的子程序地址,完成子程序调用。

在图5-24所示的处理器中,执行此指令的步骤序列如下:

  1. 计算当前 PC 的值 Temp1 ← [PC] + 0 将当前的 PC 值存储到临时寄存器 Temp1 中。
  2. 更新 PC 为子程序地址 PC ← [R5] + 0PC 寄存器更新为 R5 寄存器中的地址,即跳转到子程序。
  3. 更新 R7 寄存器 R7 ← [R7] - 4R7 寄存器的值减少4,模拟将堆栈指针指向下一个可用的堆栈位置。
  4. 将返回地址保存到堆栈 Memory address ← [R7], Memory data ← [Temp1], Write memory, Wait for MFC 将临时寄存器 Temp1 中保存的当前 PC 值(即返回地址)写入内存地址 R7 所指向的位置,保存返回地址到堆栈中,并等待 MFC 信号完成写内存操作。

总结:

  • 5.25 中,指令 Load R3, (R5)+ 主要涉及内存读取、寄存器自增和数据转移的操作。
  • 5.26 中,Call Register 指令涉及将返回地址保存到堆栈中,并将 PC 更新为子程序的地址以执行子程序调用。