CSAPP 第四章 HCL语言

CSAPP 第四章 HCL语言

HCL和布尔表达式 多路复用器 集合 存储器和时钟 HCL和布尔表达式 对于看过计算机系统要素的我, 这一部分的很多概念就很熟悉了. GO! HCL类似于用布尔表达式来书写门电路的组合方式, 像这个bool eq = (a && b) || (!a && !b);. 离散数学中提到, 不管多复杂的逻

  1. HCL和布尔表达式
  2. 多路复用器
  3. 集合
  4. 存储器和时钟

HCL和布尔表达式

对于看过计算机系统要素的我, 这一部分的很多概念就很熟悉了. GO! HCL类似于用布尔表达式来书写门电路的组合方式, 像这个bool eq = (a && b) || (!a && !b);. 离散数学中提到, 不管多复杂的逻辑电路, 只要有了and or not三个算子, 就是完备的, 可以拼接出来.

练习 4.9 写出xor的HCL表达式

计算机系统要素里有一张表列出了所有简单的布尔逻辑的表达式: bool_function 这里的+号表示or, ·或者写在一起表示and, 上横线表示not. 根据XOR的表达式, 可以很容易的写出来:
bool xor = (a && !b) || (!a && b)
再注意观察eq的结果, 可以发现, 给eq接一个非门, 也是一样的效果
HCL语言看上去很像C语言表达式, 相比C语言, HCL有一些特点:
  1. HCL的值是持续响应的, 并不是像语句一样遇到才求值
  2. C的判断条件是不是0都是真, 而是0就是假. HCL中的值只有0和1代表高低电压, 不存在其他值.
  3. C表达式有短路作用, 而HCL一直响应输入变化, 不存在求值与否的问题.
  4. 将所有输入都假设为数据类型是int的字来解释, 其实底层是没有数据类型一说的, 这样假设是为了说起来方便.
  5. 允许比较字是否相等, 即 bool eq = (A==B)

练习 4.10 用异或电路来实现相等电路

使用异或电路也比较简单, 如果两个位相等, 则输出是0, 两个位不相等,输出是1. 先把每个字的每两个位接到异或电路上, 然后再把所有的输出接到一个或门上, 这样只要有任意两个位不相等,则输出是1, 然后再接一个非门即可.

多路复用器

多路复用器也很熟悉了, 就是从多个信号中选择一个, 从N个中选几个, 最少需要能表示N的2的几次方对应的输入电路来进行选择. 对于多路复用器, HCL的表达式如下:
[
    select1 : expr1;
    select2 : expr2;
    select3 : expr3;
        .
        .
        .
    selectN : exprN;
]
selectN是选择表达式, 即这个表达式如果为1, 就被选中, 之后的输出结果就是对应的exprN. 注意, 逻辑电路在同一时刻必定有一个输出, 所以MUX2一般会写成:
word out = [
    s: A;
    1: B;
]
这不是写错了, 而是说 s=1 的时候就输出A ,如果 s=0的时候, 就会输出B. 这相当于默认情况, 很多表达式都以1结尾. 如果是4路MUX, 就可以用两路信号的布尔值来表示, 其实就是11, 10, 01, 00 四种情况:
word out4 = [
    !s1 && !s0 : A;  00的情况
    !s1        : B;  01的情况, 由于第一种情况要求!s1和!s0都为真, 既然不满足条件, 说明两个里边至多一个为真, 因此这里无需判断!s0
    !s0        : C;  10的情况, 和上一行一样, 无需判断!s1
    1          : D;  11, 默认情况, 也就是!s1和!s0都是0的情况.
]

练习 4.11 逻辑游戏

比较三个数的大小, 先比较两个数, 再比较第三个数 第一行能确定A最小, 如果A 不是最小, 只需要比较 B和C即可:
word min3 = [
    A <= B && A <= C : A;
    B <= C           : B;
    1                : C;
]

练习 4.12 找中间值

这个类似于比较大小, 返回中间值:
word middle3 = [
    A <= B && B <= C : B;
    C <= B && B <= A : B;
    B <= A && A <= C : A;
    C <= A && A <= B : A;
    1: C;  前两个情况都不满足,就是C了
]

集合

书中的例子, 用了一个信号code来对应高位和低位. code是两位的信号, 有四种变化, 即11 10 01 00, 分别对应code为 3 2 1 0的情况, 取高位为s1, 低位为s0. 可以发现, 当code 为 3 和 2的时候, 高位都是1, 当code为 3 和 1的时候, 低位都是1. 所以可以将s1 和 s2的表达式写作:
bool s1 = code == 2 || code == 3
bool s0 = code == 1 || code == 3
还可以进一步简化成:
bool s1 = code in {2, 3}
bool s0 = code in {1, 3}

存储器和时钟

这里的部分刷新了我的观点. 之前在做计算机系统要素中的题目的时候, 一个存储器是只连读写端的. 时钟寄存器是依靠时钟来控制加载和输入的值. 在Y86-64系统中, 程序计数器PC, 条件码CC和程序状态Stat是用时钟来控制的. 在每个时钟周期的上升沿, 输入信号就加载到寄存器中, 新输出也会变成输入信号. 直到下一个时钟周期上升沿, 再改变. 时钟寄存器实际上是电路中不同部分之间的屏障, 即一块电路的状态改变, 不会立刻将状态改变传播到所有电路中. 寄存器有两个读端口, 给定srcA 和 srcB两个地址输入, 就可以获取valA和valB两个输出. 此外还有一个W端口, 给定目标地址 dstW 和 输入信号 valW, 在下一次时钟周期上升沿, 就可以写入寄存器. 如果同时读端口就在读dstW对应的寄存器, 其数值会变成刚写入的valW. 如果此时不需要写寄存器和读寄存器, 地址线路都会被设置成0xF. 随机访问存储器和寄存器原理相似, 但是结构略微不同. 只有一个输出端口. 然后有地址和数据输入, 此外还有读写信号控制是否读写. 在每个时钟周期上升沿, 根据读写信号控制来控制是否写入, 而不像寄存器默认直接写入. 根据所选择的地址进行输出. 现实中的存储器系统要更复杂, 现在先假设只有寄存器文件和一个简单的随机访问存储器,就是内存. 再包括一个只读的随机访问存储器, 用来存储程序指令, 在运行的过程中只读. 现实中随机访问存储器也是双端的, 一端读, 一端读写.
LICENSED UNDER CC BY-NC-SA 4.0
Comment