ALU就是计算机里负责运算的组件,这篇文章就是教你自己做一个ALU 第一个ALU 1970年,第一个封装在单个芯片内的完整ALU——英特尔74181诞生,这在当时是惊人的工程壮举! 其他数学运算 ALU还支持其他数学运算,一般是下面的八种.和加法器一样也是通过逻辑门构成 乘除法 简单的ALU电路没有乘除法,而是把乘法用多次加法来实现。 比如12X5和把12加五次是一样的,要经过五次ALU运算才能得出结果 虽然慢但是能用!哈哈,简单的处理器都是这样搞得,比如电视遥控器,微波炉,恒温器。 别着急下面就会列出来 右边的FLAGS是1位(1Bit)代表的是某种特定状态(下面这三种状态是最常用的,高级的ALU会有更多FLAGS) OVERFLOW溢出标志代表的就是是否溢出。 (算数单元和逻辑单元) ,而文章开篇提到的英特尔74181只能处理四位的ALU,你做出来一个比英特尔还好的ALU!
现在,设计复杂性增加,设计需要针对低功率、高速和最小面积进行优化~ ALU设计 算术逻辑单元(ALU)在大多数处理器中用于执行算术和逻辑运算。处理器根据操作代码(opcode)一次执行一个操作。 对于8位处理器,ALU用于对两个8位操作数(Operand,操作数是需要对其执行操作的数据)执行操作。同样,对于16位处理器,ALU用于对两个16位数字执行操作。 图7.7 ALU顶层图表7.5 8位ALU的信号或引脚说明 信号或引脚名称 大小(位) 描述 a_in 8 8位操作数 b_in 8 8位操作数 cin_in 1 ALU进位输入端 op_code_in 4 4位操作码 result_out 8 来自ALU的8位输出 co_out 1 来自ALU的一位输出进位 表7.6 8位ALU的操作表 操作代码 指示 描述 0000 Transfer a_in 的Verilog RTL 图7.8综合的8位ALU 8位ALU的综合图如图7.8所示。
最近,UT-Austin研究小组利用硅光芯片实现了光电混合的算术逻辑单元,相关文章发表在最新一期的Nature Commuications上, 文章标题为"Electronic-photonic arithmetic logic unit for high-speed computing"。小豆芽将在这篇笔记介绍下相关的进展。
因为ALU需要接受输入而控制单元可以控制素有的寄存器所以需要把ALU连接至控制单元。 通过控制单元打开对应的寄存器输出来让ALU接受输入,来看下面的步骤: 1.让ALU接受输入:控制单元启用寄存器B的允许读取线,作为ALU的第一个输入,控制单元启用寄存器A的允许读取线,作为ALU的第二个输入 2.告知ALU进行哪种运算操作: 控制单元传递ALU中的ADD操作码告知ALU进行加法运算 3.ALU输出结果保存:注意此时的A的允许读取还打开着并且ALU还在继续工作,如果控制单元直接把输出给到寄存器 A,那么ALU就会不断进行运算。 当ALU计算出结果后将结果传送至控制单元,控制单元内部寄存器存储这个结果,然后把ALU关闭,再把内部寄存器存储的值给到寄存器A(这是打开的是寄存器A的允许写入) 时钟速度,时钟周期 刚刚我们是一步一步进行讲解的这个过程
ALU就是计算机里负责运算的组件,这篇文章就是教你自己做一个ALU第一个ALU1970年,第一个封装在单个芯片内的完整ALU——英特尔74181诞生,这在当时是惊人的工程壮举! 其他数学运算ALU还支持其他数学运算,一般是下面的八种.和加法器一样也是通过逻辑门构成图片乘除法简单的ALU电路没有乘除法,而是把乘法用多次加法来实现。 比如12X5和把12加五次是一样的,要经过五次ALU运算才能得出结果虽然慢但是能用!哈哈,简单的处理器都是这样搞得,比如电视遥控器,微波炉,恒温器。 别着急下面就会列出来****右边的FLAGS是1位(1Bit)代表的是某种特定状态(下面这三种状态是最常用的,高级的ALU会有更多FLAGS)OVERFLOW溢出标志代表的就是是否溢出。 (算数单元和逻辑单元) ,而文章开篇提到的英特尔74181只能处理四位的ALU,你做出来一个比英特尔还好的ALU!
alu、paopao是表情的图片文件夹,OwO.min.css是表情按钮用到的样式,同理.js是表情用到的脚本。 /OwO/OwO.min.json' );
define( 'OwO_alu', get_bloginfo('template_directory').' /OwO/alu' );
define( 'OwO_paopao', get_bloginfo('template_directory').' /alu/得意.png" alt="得意" style="vertical-align: middle;">',
'@(愤怒)' => '',
'@(黑线)' => '<img src="'.OwO_<em>alu</em>.'
="/OwO/alu/不高兴.png" alt="不高兴" class="OwO-img">',
'@(不说话)' => '<img src="/OwO/<em>alu</em>/不说话.png" alt="不说话" '
',
'@(大囧)' => '
'
',
'@(尴尬)' => '<img src="/OwO/<em>alu</em>/尴尬.png '@(鼓掌)' => '<img src="/OwO/alu/鼓掌.png" alt="鼓掌" class="OwO-img">',
'@(观察)' => '<img src="/OwO/<em>alu</em>/观察 ,
'@(汗)' => '<img src="/OwO/alu/汗.png" alt="汗" class="OwO-img">',
'@(黑线)' => '<img src="/OwO/<em>alu</em>/
Structural Variation of Alu Element and Human Disease Transposable elements are one of major sources gene and most Alu elements are amplified from the hyperactive master genes. Alu elements are associated with approximately 0.1% of human genetic disorders. Alu elements are pervasively involved in gene regulation Reference. Structural Variation of Alu Element and Human Disease. Ling-Ling Chen and Li Yang.
我们现在讲 ALU 的另一半:逻辑单元。 让我们回到昨天开始时的 ALU,英特尔 74181,和我们刚刚做的 8 位 ALU 不同,74181 只能处理 4 位输入。也就是说你刚做了一个比英特尔 74181 还好的 ALU ! 4 位 ALU 已经要很多逻辑门了,但我们的 8 位 ALU 会需要数百个逻辑门。工程师不想在用 ALU 时去想那些事情,所以想了一个特殊符号来代表它,看起来像一个大 "V"。 又一层抽象! 我们的 8 位 ALU 有两个输入,A和B,都是 8 位 (bits),我们还需要告诉 ALU 执行什么操作,例如加法或减法,所以我们用 4 位的操作代码,我们之后会再细说。 高级 ALU 有更多标志,但这 3 个标志是 ALU 普遍用的,其实,我们之后会用到它们。 现在你知道了计算机是怎样在没有齿轮或杠杆的情况下进行运算。
图中绿色的为ALU(运算逻辑单元,Arithmetic Logic Unit), 可以看出GPU相比CPU,多了很多ALU,而且ALU占据了内部空间的绝大部分,所以可以看出GPU是对运算很强调的芯片。 下图是一个GPU核的结构,图中所有8个ALU共用一个指令单元Fetch/Decode, 而Ctx则是每个ALU独有的存储上下文,所以,只是一种SIMD结构。 ? 分支问题 由于每个ALU的Ctx不同,所以有可能会出现分支,这时候8个ALU的指令可能会出现分叉,即各自走了不同的路,没法共享同一个指令了,这种结构就会失效。 从图中我们可以看到,每个ALU都进行了if/else的判断,有的ALU走了if部分,有的ALU走了else部分,这样8个ALU就可以共用一个Fetch/Decode单元了。 但因为每个ALU都要进行判断,所以做了一部分无用功,牺牲了部分性能,性能最差的时候只有1/8的有用功,即只有1个ALU选择if或选择else,其他7个ALU都做了无用功,性能只有1/8。
-A op B(reg-to-reg操作) ALU输出<- A op Imm(reg-to-imm操作) ALU输出<- PC + Imm(计算分支的目标地址),其中op是指令定义的某个操作。 在此阶段,ALU可用于计算内存操作的有效地址,执行寄存器与寄存器/立即操作数操作,或计算分支的目标地址。分支条件也在这个阶段确定。 MEM MEM阶段可以使用以下公式进行总结: 内存load LMD <- MEM[ALU输出] 内存store MEM[ALU输出]<- B 如果(满足条件)PC <- ALU输出 其他PC <- 如果满足在EX阶段获得的条件,PC将加载EX阶段和程序分支的ALU输出;否则程序按顺序执行,PC将指向下一个指令。 WB WB阶段可以使用以下公式进行总结: Regs|IR[20:16]] <- ALU输出(reg-to-reg操作) Regs|IR|15:11]] <- ALU输出(reg-to-imm操作)
1984' < '1998' } int main() { string name; int a_num, g_num; unordered_map<string, bool> find_alu ; vector<string> all_guest, alu_list; cin >> a_num; for (int i = 0; i < a_num; ++i) { cin >> name i = 0; i < g_num; ++i) { cin >> name; all_guest.push_back(name); if (find_alu[name]) alu_list.push_back (name); // 如果是校友那么就把ID添加到校友名单中 } printf("%d\n", alu_list.size()); if (! alu_list.empty()) { sort(alu_list.begin(), alu_list.end(), cmp); // 用STL的方法来进行排序 printf("%s\n",
所以1000 0100的意思是:将寄存器B的值加到寄存器A中执行过程加法需要利用到上一篇文章讲的ALU逻辑运算单元。因为ALU需要接受输入而控制单元可以控制素有的寄存器所以需要把ALU连接至控制单元。 通过控制单元打开对应的寄存器输出来让ALU接受输入,来看下面的步骤:1.让ALU接受输入:控制单元启用寄存器B的允许读取线,作为ALU的第一个输入,控制单元启用寄存器A的允许读取线,作为ALU的第二个输入 2.告知ALU进行哪种运算操作: 控制单元传递ALU中的ADD操作码告知ALU进行加法运算3.ALU输出结果保存:注意此时的A的允许读取还打开着并且ALU还在继续工作,如果控制单元直接把输出给到寄存器A ,那么ALU就会不断进行运算。 当ALU计算出结果后将结果传送至控制单元,控制单元内部寄存器存储这个结果,然后把ALU关闭,再把内部寄存器存储的值给到寄存器A(这是打开的是寄存器A的允许写入)图片时钟速度,时钟周期刚刚我们是一步一步进行讲解的这个过程
ALU_OP_AND 8'b00100100 `define ALU_OP_OR 8'b00100101 `define ALU_OP_XOR 8'b00100110 `define ALU_OP_NOR ALU_OP_SRL 8'b00000010 `define ALU_OP_SRLV 8'b00000110 `define ALU_OP_SRA 8'b00000011 `define ALU_OP_SRAV ALU_OP_BNE 8'b01010010 `define ALU_OP_LW 8'b11100011 `define ALU_OP_SW 8'b11101011 // ALU SEL `define ALU_NOP 3'b000 `define ALU_LOGIC 3'b001 `define ALU_SEL_LOGIC 3'b001 `define ALU_SEL_SHIFT 3'b010 `define ALU_SEL_NOP 3'b000 `define ALU_SEL_MOVE 3'b011 `define ALU_SEL_ARITH 3'b100 `define ALU_SEL_MUL 3'b101
如图所示,ALU 包含各种输入和输出连接,这使得外部电子设备和 ALU 之间可以投射数字信号。ALU 输入从外部电路获取信号,作为响应,外部电子设备从 ALU 获取输出信号。 这些信号存储在外部寄存器中,使它们可用于未来的 ALU 操作。 输入:当 ALU 执行一次操作时,状态输入允许 ALU 访问更多信息以成功完成操作。 在正常操作中,稳定信号被施加到所有 ALU 输入,当信号通过 ALU 电路传播足够的时间(称为“传播延迟”)时,ALU 操作的结果出现在 ALU 输出。 连接到 ALU 的外部电路负责确保 ALU 输入信号在整个操作过程中的稳定性,并在对 ALU 结果进行采样之前留出足够的时间让信号通过 ALU 传播。 通常,外部电路通过向 ALU 的输入施加信号来控制 ALU。通常,外部电路采用时序逻辑来控制 ALU 操作,该操作由频率足够低的时钟信号来控制,以确保 ALU 输出有足够的时间在最坏情况下稳定下来。
ALU 上节,我们谈了如何用二进制表示数字,比如二进制 00101010 是十进制的 42,表示和存储数字是计算机的重要功能,但真正的目标是计算,有意义的处理数字。 但大家会简称:ALU。 ALU 是计算机的数学大脑,等你理解了 ALU 的设计和功能之后,你就理解了现代计算机的基石。ALU 就是 计算机里负责运算的组件基本其他所有部件都用到了它。 先来看看这个美人,这可能是最著名的 ALU,英特尔 74181,1970 年发布时,它是第一个封装在单个芯片内的完整 ALU,这在当时是惊人的工程壮举。 今天我们用上周学的布尔逻辑门,做一个简单的 ALU 电路,功能和 74181 一样,然后接下来几周,用它从头做出一台电脑,所以会有点复杂,但我觉得你们搞的定。 它更快,做的事情是一样的 - 把二进制数相加,ALU 的算术单元,也能做一些其他数学运算,一般支持这 8 个操作。
如图所示,ALU 包含各种输入和输出连接,这使得外部电子设备和 ALU 之间可以投射数字信号。ALU 输入从外部电路获取信号,作为响应,外部电子设备从 ALU 获取输出信号。 这些信号存储在外部寄存器中,使它们可用于未来的 ALU 操作。 输入:当 ALU 执行一次操作时,状态输入允许 ALU 访问更多信息以成功完成操作。 在正常操作中,稳定信号被施加到所有 ALU 输入,当信号通过 ALU 电路传播足够的时间(称为“传播延迟”)时,ALU 操作的结果出现在 ALU 输出。 连接到 ALU 的外部电路负责确保 ALU 输入信号在整个操作过程中的稳定性,并在对 ALU 结果进行采样之前留出足够的时间让信号通过 ALU 传播。 通常,外部电路通过向 ALU 的输入施加信号来控制 ALU。通常,外部电路采用时序逻辑来控制 ALU 操作,该操作由频率足够低的时钟信号来控制,以确保 ALU 输出有足够的时间在最坏情况下稳定下来。
案例:加法指令(ADD R1, R2) 微操作: R1 内容送 ALU R2 内容送 ALU 并执行加法 结果送 R1 Java 代码示例:执行周期模拟 /** * 模拟执行周期(加法指令) */ public class ExecuteCycle { private int[] register = new int[4]; // 模拟寄存器R0-R3 private ALU alu int op1 = register[dst]; int op2 = register[src]; int result = alu.add(op1, op2); // 调用ALU加法功能 register[dst] = result; System.out.println("执行周期:R" + dst + "(" + op1 + ") =3) public void initRegisters() { register[1] = 5; register[2] = 3; } } // ALU
【从理解天然原子性开始】 ---- 通常我们所说的一个内核是8位、16位还是32位并不是指地址总线的宽度,而是ALU操作数的位宽,习惯上又称之为字长。 对8位机来说,ALU一次可以进行8位运算,当我们针对一个32位的数据进行操作时就要拆成4次。对32位机来说,ALU一次就可以完成32位的运算。 ALU对相同字长数据的处理具有天然原子性。也就是说,16位机对16位数据的处理具有天然原子性;64位机对64位数据的处理具有天然原子性。 实际上,很多处理器的的ALU不光对相同字长数据的访问具有天然原子性,对小于这一字长的数据类型也具有天然原子性。 比如Cortex-M的ALU不光对32位的整型变量的访问具有原子性,对16位甚至是8位变量的访问也具有原子性。事实上,这一特性对很多8位机、16位机和64位机都一样适用。
知识储备: 计算机的位数取决CPU中寄存器的宽度,具体来说就是算术逻辑运算单元(ALU)的宽度,用来表征计算机的计算能力,ALU一次可以计算最大长度整数即计算机的位数。 在32bit的计算机中,ALU一次可以计算的最大整数为4个字节。 在64bit的计算机中。ALU一次可以计算的最大整数为8个字节。