addm 指令必须在写入寄存器之前将内存读取的结果与寄存器的值相加。
从根本上说,加法器必须放在数据存储器之后(以处理其输出)。加法器的一个输入是内存读取的结果,另一个是另一个寄存器的值。
在addm $t0, 8($s1) 中,(如lw)寄存器$s1 向主ALU 提供一个值,而符号扩展向主ALU 提供另一个值8;主 ALU 在计算寻址时进行加法运算,并将该地址发送到数据存储器以供读取。但是,第一个区别是addm 还需要源$t0,而lw 不需要(lw 只针对$t0,而addm 既源又目标$t0)。
需要将来自$t0 的源输入addm 的新(上述)加法器作为其输入之一,该新加法器的另一个输入是数据存储器读取值。
加法器的结果需要写入$t0寄存器。
您可以看到,对于主 ALU 的第二个操作数,控制信号 ALUSrc 在 Read Data 2 和 Sign Extended immediate 之间进行选择。对于addm 和lw,控制信号都应为1,以选择符号扩展立即数。
让我们进一步注意Read Data 2 被转发到Data Memory 的情况下sw 指令b/c 因为Read Data 2 是要写入内存的值(即在sw $t0, 8($s1) 中,而@ 987654345@ 用于地址计算,$t0 不是,而是作为Write Data 转发给Data Memory。
该行已经有一个拆分(fork,即一个输出馈送到多个输入),因此,将进一步拆分它并扩展同一行的新分支(来自Read Data 2)以到达addm 的新加法器放在Data Memory之后。
然后,addm 的新加法器的输出需要拼接到Register File 的Write Data 行。
每当对程序框图进行拼接更改时,我们都希望现有功能能够按原样继续,并拼接新功能,仅在遇到新指令时才会触发。这种拼接的想法是剪断一条线并插入另一个输入,在新 MUX 的控制下将新功能加入(如新加法器),这意味着新的控制信号进入新的 MUX 以在新行为和现有行为之间切换.这里的开关是在现有行为和addm 的新加法器的输出之间进行选择。
作为一个例子,我们已经可以看到Register File 的Write Data 来自两种可能性之一,在MemToReg 的控制下,要么是ALU 输出,要么是来自数据的Read Data记忆。 addm 不是选择两个,而是添加了第三个选择,通常这可以通过简单地拥有两个常规 MUX 来完成(例如,简单地添加一个 MUX),但也可以使用在 ALU 中进行选择的三选择器 MUX 来完成输出、数据存储器读取值或新的addm 加法器输出,用于返回寄存器文件的那条线。
以上为单循环,如图所示;几乎没有办法在单个周期内将主 ALU 用作新的加法器,因为主 ALU 已经在执行每条指令。
在多周期处理器中,我们可以通过为addm添加一个新周期来重用主ALU而不是添加一个新的加法器,这样单周期中的新加法器的功能就会被使用主ALU代替ALU,但在额外的循环之后。
在流水线处理器中,您将再次难以使用主 ALU,因为指令的重叠执行意味着 ALU 在每个周期都很忙,因此我们可以为新的加法器添加流水线阶段,尽管这会减慢所有速度现有指令以适应addm。