Verilog实现算术逻辑单元(ALU)

算术逻辑单元

一、基本介绍

算术逻辑单元(英语:Arithmetic logic unit,简称:ALU)是一种可对二进制整数执行算术运算或位运算的组合逻辑数字电路。
ALU 与浮点数运算单元(FPU)不同,后者仅对浮点数进行操作。
ALU 是许多类型的计算电路的基本部件,这些计算电路包括计算机的中央处理单元(CPU)、浮点处理单元(FPU)和图形处理单元(GPU)。单个CPU、FPU 或 GPU 可能包含多个 ALU。

ALU 的输入包括需要运算的数据(也称为运算数)和表明了运算操作类型的指令码。ALU 的输出是其执行运算的结果。在许多的设计中,ALU 还带有状态输入或输出,可将其之前操作或当前操作的信息在 ALU 和外部状态寄存器间传递。

image

			  IC-74181是一款常见的ALU

二、信号与电路

数据输入

一个基本的 ALU 具有三个并行的数据总线,包括两个输入操作数(A、B)和结果输出(Y)。

操作码

操作码通过并行总线输入,它向 ALU 传递选择的操作的信息,该操作选择码是对 ALU 要执行的算术或逻辑运算的枚举。操作码的长度(其总线宽度)决定了 ALU 可以执行的操作的最大数量。例如,一个4位操作码可最多为 ALU 指定不同的 16 个操作(16=24)。通常,ALU 的操作码与机器语言的操作码不同,尽管在某些情况下,它可以直接编码为机器语言操作码内的位字段。

输入状态

ALU 的状态输出是各类单独的信号,补充表示了有关当前 ALU 操作结果的信息。通用 ALU 通常具有以下状态信号:

  • Carry-out,表示由加法运算产生的进位、由减法运算产生的借位或由二进制移位运算产生的溢出位。
  • Zero,表示运算结果的所有位均为逻辑零。
  • Negative,表示算术运算结果为负。
  • Overflow,表示算术运算的结果溢出,超出了 Y 的数值范围。
  • Parity,表示输出数 Y 的奇偶校验结果,说明 Y 中的含有逻辑 1 的数量的奇偶性。
    在 ALU 的操作结束后,状态输出信号通常会被存储在外部寄存器中,以使其可用于之后的 ALU 操作(例如实现多倍精度运算,或用于控制条件分支)。存储了状态输出的集合的位寄存器通常被视为一整个多位寄存器,称为“状态寄存器”或“条件代码寄存器”。

数据输出

状态输入使 ALU 在执行操作时可接收其他信息。通常,这是单个“低位进位”,传递了来自上一级 ALU 操作的进位。

三、功能

ALU 通常支持许多基本算术和按位逻辑函数。基本的通用 ALU 通常支持以下操作

算术运算

  • 加法:将操作数 A、B 相加
  • 带进位加法:将操作数 A、B、进位相加
  • 减法:将操作数 A、B 相减,并在 Y 处得到二者的差。对于此功能,结转实际上是“借入”指示器。此操作也可以用来比较A和B的大小;在这种情况下,处理器可能会忽略Y输出,该处理器仅对操作产生的状态位(尤其是零和负)感兴趣。
  • 二补数(取相反数):得到 A 或 B 的相反数(将 0 与 A 相减或将 0 与 B 相减)
  • 加 1:将 A(或 B)增加 1
  • 减 1:将 A(或 B)减小 1
  • 直通(Pass through):保持 A(或 B)的所有位不变,并在 Y 处得到原输入数;该操作常用于对操作数进行奇偶校验,判断是否为 0,判断是否为负数,或者为了将操作数直接加载到寄存器中。

按位逻辑运算

  • AND:将 A 和 B 按位进行“与”运算
  • OR:将 A 和 B 按位进行“或”运算
  • XOR:将 A 和 B 按位进行“异或”运算
  • 补码:将 A(或 B)的每一位都反转

移位操作

  • 算术移位:操作数被视为二补数整数,其高有效位是符号位,在移位时会被保留。
  • 逻辑移位:移位时用逻辑 0 补充操作数,这适合于无符号整数。
  • 循环移位:此时操作数被视为一个循环缓冲区,因此在移位时,其最低和最高位就像是相邻的。
  • 循环移位(带进位):进位输入(C)和操作数被视为整个操作数的循环移位。

四、Verilog实现

ALU Arithmetic and Logic Operations

  • |ALU_Sel| ALU Operation

  • | 0000 | ALU_Out = A + B;

  • | 0001 | ALU_Out = A - B;

  • | 0010 | ALU_Out = A * B;

  • | 0011 | ALU_Out = A / B;

  • | 0100 | ALU_Out = A << 1;

  • | 0101 | ALU_Out = A >> 1;

  • | 0110 | ALU_Out = A rotated left by 1;

  • | 0111 | ALU_Out = A rotated right by 1;

  • | 1000 | ALU_Out = A and B;

  • | 1001 | ALU_Out = A or B;

  • | 1010 | ALU_Out = A xor B;

  • | 1011 | ALU_Out = A nor B;

  • | 1100 | ALU_Out = A nand B;

  • | 1101 | ALU_Out = A xnor B;

  • | 1110 | ALU_Out = 1 if A>B else 0;

  • | 1111 | ALU_Out = 1 if A=B else 0;

8位ALU的Verilog代码

module	alu_8bit
(
	input		[7:0]	a,		
	input		[7:0]	b,				//alu数据输入
	input				cin,			//进位输入
	input		[3:0]	alu_sel,		//功能选择
	output	[7:0]	alu_out,		//数据输出
	output			alu_cout		//进位输出
);
reg	[7:0]	result;				//寄存运算结果
wire	[8:0]	carry_temp;			//最高位为进位
assign	alu_out 	  = result;
assign	carry_temp = {1'b0,a} + {1'b0,b};
assign	alu_cout	  = carry_temp[8];
always@(*)	begin
	case(alu_sel)
		4'b0000:	result <= a + b;
		4'b0001:	result <= a - b;
		4'b0010:	result <= a * b;
		4'b0011:	result <= a / b;

4'b0100: result <= a << 1;
4'b0101: result <= a >> 1;
4'b0110: result <= {a[6:0],a[7]};
4'b0111: result <= {a[0],a[7:1]};

4'b1000: result <= a & b;
4'b1001: result <= a | b;
4'b1010: result <= a ^ b;
4'b1011: result <= ~(a|b);
4'b1100: result <= ~(a&b);
4'b1101: result <= ~(a^b);

4'b1110: result <= (a>b)?8'd1:8'd0;
4'b1111: result <= (a==b)?8'd1:8'd0;
default:	result <= a + b;
	endcase
end
endmodule

仿真测试代码

`timescale 1ns / 1ps

module tb_alu_8bit;
//Inputs
 reg		[7:0] a,b;
 reg 		[3:0] alu_sel;

//Outputs
 wire 	[7:0] alu_out;
 wire 	  alu_cout;
 // Verilog code for ALU
 integer i;
alu_8bit	alu_8bit_unit
(
	a,
	b,				//alu数据输入
	cin,			//进位输入
	alu_sel,		//功能选择

	alu_out,		//数据输出
	alu_cout		//进位输出
);
	initial begin
	// hold reset state for 100 ns.
	  a = 8'h0A;
	  b = 4'h02;
	  alu_sel = 4'h0;

	  for (i=0;i<=15;i=i+1)
	  begin
	   alu_sel = alu_sel + 8'h01;
	   #10;
	  end

	  a = 8'hF6;
	  b = 8'h0A;
	end
endmodule

仿真测试结果
image

posted @ 2022-12-14 19:48  IC小菜叶  阅读(3928)  评论(0编辑  收藏  举报