全加器

考虑进位的加法称为全加,能够完成全加运算的电路称为全加器,一个基本全加器能够完成两个一位二进制数的全加运算,因此它具有三个输入端和两个输出端,其中 Xi,YiX_i, Y_i 为加数,Ci1C_{i - 1} 相邻低位进来的进位数, SiS_i 为输出和,CiC_i 为向高位邻位进位数

和位

我们称 s 是和位输出,计算方法是对于 x_i, y_i c_i-1 的异或结果

s=xycs = x\oplus y\oplus c

那么在实际电路中我们只有二元输入的异或门,那么我们就可以用两个异或门进行组合完成

1
2
xor g1(a,x,y);
xor g2(s,a,c);

进位位

在三个变量中有两个变量是1的时候发生进位

c=(xy)+(xc)+(yc)c = (x\cdot y) + (x\cdot c) + (y\cdot c)

考虑到我们需要使用尽量少的逻辑门,那么我们需要对这个逻辑表达式进行化简

c=xy+xc+yc=xy+c(x+y)c = x\cdot y + x\cdot c + y\cdot c = x\cdot y + c\cdot(x + y)

那么我们在verilog中可以实现这个代码, 我们需要用到与门和或门处理
1
2
3
and g4(d,a,c);
and g5(b,y,x);
or g6(c_out,d,b);

半加器 half adder

用于将两个单个位二进制数相加,并生成一个和位(sum)和一个进位位(carry)。与全加器不同的是,半加器不处理输入的进位位,只处理两个输入位。

  • 半加器 用于简单的单个位加法,没有进位输入,适用于最低位加法和基础构建模块。
  • 全加器 用于处理多位二进制加法的所有位运算,能够处理来自低位的进位输入,适用于复杂加法电路和带进位输入的场景。

减法器

半减器(Half Subtractor)

半减器 用于减去两个单个位并生成差值(difference)和借位(borrow)。它有两个输入和两个输出。

  • 输入: 两个二进制位 x 和 y。
  • 输出: 一个差值位 d 和一个借位位 b

差值位

两个输入位的差值,用于表示 x - y。

d=xyd = x \oplus y

借位位

用于表示 x - y 的借位,当 x < y 时,需要借位。

b=xyb = \overline{x} \cdot y

其中 xˉ\bar x 表示对x逻辑取反

全减器(Full Subtractor)

差值位

d=xybd = x \oplus y \oplus b

借位位

b=(xy)+((xy)b)b = (\overline{x} \cdot y) + ((\overline{x\oplus y}) \cdot b)

乘法器 multiplier

通过逐位乘法和移位操作来实现二进制数的乘积

  • 逐位乘法:将被乘数与乘数的每一位相乘。
  • 移位和累加:将逐位乘法的结果进行移位,并将所有部分积累加起来,得到最终的乘积。

基本二进制乘法器

基本二进制乘法器是最简单的一种乘法器,它基于逐位乘法和移位操作。以下是其基本实现方法:
假设我们有两个4位二进制数 A 和 B: A=A3A2A1A0A=A_3A_2A_1A_0​, B=B3B2B1B0B=B_3B_2B_1B_0

基本二进制乘法器的步骤

  1. 逐位乘法
    • 计算 A 与 B 每一位的乘积,得到部分积(Partial Products)。
  2. 移位和累加
    • 对每一个部分积进行移位操作,使其对齐。
    • 将所有部分积累加起来,得到最终乘积。

P=A×B=i=0n1(Bi×A<<i)P = A\times B = \sum_{i = 0}^{n-1}(B_i \times A << i)

类似于列竖式的乘法算法

移位操作 Shifter
1
assign B = {A[2:0], 1'b0}; // 将输入 A 左移 1 位

{} 是连接操作符
这里的 1'b0 表示 1 位的二进制数 0
A[2:0] 表示 3 位数据信号 A
assign 表示连续赋值

实现乘法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module multiplier_4bit (
input [3:0] A,
input [3:0] B,
output [7:0] P // 4 bit * 4 bit <= 8 bit
);
wire [3:0] P0, P1, P2, P3;
wire [7:0] Sum1, Sum2, Sum3;

// Generate partial products
assign P0 = A & {4{B[0]}}; // P0 = A * B0, 表示将B[0] 扩展为4位信号
assign P1 = A & {4{B[1]}}; // P1 = A * B1
assign P2 = A & {4{B[2]}}; // P2 = A * B2
assign P3 = A & {4{B[3]}}; // P3 = A * B3

// Shift partial products
assign Sum1 = {4'b0, P0} + {3'b0, P1, 1'b0}; // Sum1 = P0 + (P1 << 1)
assign Sum2 = Sum1 + {2'b0, P2, 2'b0}; // Sum2 = Sum1 + (P2 << 2)
assign Sum3 = Sum2 + {1'b0, P3, 3'b0}; // Sum3 = Sum2 + (P3 << 3)

assign P = Sum3; // P = Final product

endmodule

负数与补码

对于1字节数据,如果我们要表示负数,那么我们就要将一位数据转变成符号位,在工程上我们会将最高位1认为是 负数
那么,从 单纯二进制数转换为 10 进制度数的时候,我们可以理解为 128 -> -128

补码

从上面的定义我们可以感受到,如果要表示 -1, 我们要用等式 1=128+64+32+16+8+4+2+1-1 = -128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 来表示, 二进制表示为 1111111111111111 而其相反数 1 的二进制表示为 0000000100000001
那么,怎么用正数来转换为 负数(相反数)呢
我们先尝试找找规律看看

二进制数 补码 十进制数 全反
00000001 11111111 -1 11111110
00000010 11111110 -2 11111101
00000011 11111101 -3 11111100

那么我们会发现,求二进制的补码,就是对其求全反加一
有了这个算法,我们后面就会非常简单了