What & How & Why

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录前一修订版
后一修订版
前一修订版
cs:comp_n_arch:courses:fnti_i:week_2 [2025/04/04 14:48] – [实例:Hack ALU] codingharecs:comp_n_arch:courses:fnti_i:week_2 [2025/04/08 14:28] (当前版本) – [其他实现上的一些细节] codinghare
行 125: 行 125:
 本课例子(HACK ALU): 本课例子(HACK ALU):
   * 接收两个 16 bits 的输入   * 接收两个 16 bits 的输入
-  * 得到一个16 bits 的输出和两个 1 bits 的输出。+  * 得到一个 16 bits 的输出和两个 1 bits 的输出。
   * 实现了一系列的(总共18个)**基础**函数   * 实现了一系列的(总共18个)**基础**函数
   * 调用哪个函数通过结构图正上方的 6 个 1 bit 的输入来决定。   * 调用哪个函数通过结构图正上方的 6 个 1 bit 的输入来决定。
行 132: 行 132:
 {{ :cs:comp_n_arch:courses:fnti_i:hack_alu.jpg?300 |}} {{ :cs:comp_n_arch:courses:fnti_i:hack_alu.jpg?300 |}}
 \\  \\ 
 +==控制位与 16bits 输出位的真值表==
 +Hack ALU 常用的 18 种运算的真值表如下:
 +\\ \\ 
 +{{ :cs:comp_n_arch:courses:fnti_i:hackalu_truetable.jpg?400 |}}
 +\\ 
 +上面 6 个控制位均在 0 和 1 时代表了两种不同的运算:
 +\\ \\ 
 +{{ :cs:comp_n_arch:courses:fnti_i:contorl_bits_alu.svg?300 |}}
 +\\ \\ 
 +整个计算过程从左到右进行运算,前面的运算结果会作为下一次的算子参与新的运算。比如下面的例子:
 +
 +<code CIL>
 +// input
 +x = 0010
 +y = 1011
 +
 +// calculation: y - x
 +// control bits sequence from the turth table
 +0 0 0 1 1 1
 +
 +// compute process
 +
 +zx = 0 // do nothing
 +x = 0010
 +y = 1011
 +
 +zy = 0 // do nothing 
 +x = 0010
 +y = 1011
 +
 +zy  = 0 // do nothing
 +x = 0010
 +y = 1011
 +
 +ny = 1 // y = !y
 +x = 0010
 +y = 0100
 +
 +f = 1 // out = x + y
 +x = 0010
 +y = 0100
 +out = 0110
  
 +no  = 1 // out  = !out
 +out = 1001
 +</code>
 +==Add16:串行实现==
 +  * ''0'' bit 使用 half adder 计算
 +  * 之后只需要将前一位计算的 carry 交给下一个Full adder 即可
 +==Add16:Carry-ahead==
 +之前的方法非常慢,必须等到前一个 adder 的结果出来之后才能下一步。我们可以通过 Carry-ahead 的方法进行 carry 位的并行计算。
 +可以观察到的是,当前 adder 中送到下一个 carry 位是可以根据如下的情况来判断的:
 +  * 如果参与计算的 bits ''a'', ''b'' 都是 1,那么无论前一个 adder 传递来的 carry 位是什么,当前 adder 的 carry 位一定是 1,也就是 ''a and b''
 +  * 如果参与计算的 bits 中存在一个 1,且前一位的 carry bit ''ci'' 是 1,那么当前 adder 的 carry 位是 1。判断条件为 ''(a or b) and ci''
 +这里的第一部分(''a and b'')被称为 //Generate// 位(//G//),第二部分(''a or b'')被称为 //Propagate// 位(P)。也就是说当前 carry 位的值实际上取决于以下的表达式:
 +$$C_{i+1} = G_{i}∨(P_{i} ∧C_{i})$$
 +利用这个公式,我们可以对每一位的 $C_i$ 进行展开。也就是说,只要已知所有的 ''a'', ''b'',以及 ''0'' 位的 carry,那么所有的 adder 都可以直接对本位的 carry 进行计算,
 +比如第二位的 carry 公式就可以展开为:
 +$$C_2=G_1​∨(P_1∧G_0)​∨(P_1∧P_0​∧C_0))$$
 +==其他实现上的一些细节==
 +  * ''Mux16'' 是 ''if / else'' 的硬件实现,使用 ''sel'' 位来作为条件输入
 +  * 验证某个输出是否小于 0 只需验证其最高位,比如 ''out[15]'' 为 1 则该数为负
 +  * 验证某个输出是否等于 0 需要使用 ''OrNWay'' 对所有 bits 进行按位 ''Or''。这样计算后:
 +    * 如果有任意 bit 为 1,那么 Or 的结果都为 1。此时输出是不等于 0 的,如果再将其翻转(//Not//)再输出至是否相等的 bit,此时为 0,也就是不相等。
 +    * 反之,按位 Or 全为 0,翻转后结果为 1,说明相等。