数字电路与verilog结合

数字电路与verilog结合

鄙人能力有限,对数电的理解还远远不够,甚至在基础知识上也有问题。于是写下此篇post,加深对数电的理解,并且结合verilog代码。在代码部分,我和同伴共同创作,会使用ChatGPT进行检测。
注意:若代码有问题,请及时提出自己的疑问或是指出我的错误,相互学习共同进步,十分感谢!

三种基本运算

与门

表达式与真值表

  1. 表达式
    $$ Y=A\cdot B $$
  2. 真值表
A B Y
0 0 0
0 1 0
1 0 0
1 1 1

verilog代码

1
2
3
4
5
6
7
module and_gate (
input a,
input b,
output c
);
assign c = a & b;
endmodule

或门

表达式与真值表

  1. 表达式
    $$ Y=A + B $$
  2. 真值表
A B Y
0 0 0
0 1 1
1 0 1
1 1 1

verilog代码

1
2
3
4
5
6
7
module or_gate (
input a,
input b,
output c
);
assign c = a | b;
endmodule

非门

表达式与真值表

  1. 表达式
    $$ Y=\bar{A} $$
  2. 真值表
A Y
0 1
1 0

verilog代码

1
2
3
4
5
6
7
module not_gate (
input a,
output b
);
assign b = ~a;
#assign b = ! a这样写也可以
endmodule

与非

表达式与真值表

  1. 表达式
    $$ Y=\overline{(A\cdot B) } $$
  2. 真值表
A B Y
0 0 1
0 1 1
1 0 1
1 1 0

verilog代码

1
2
3
4
5
6
7
8
9
10
11
12
module nand_gate (
input wire A,
input wire B,
output wire Y
);

wire and_out;

and (and_out, A, B);
not (Y, and_out);

endmodule

或非

表达式与真值表

  1. 表达式
    $$ Y=\overline{(A + B) } $$
  2. 真值表
A B Y
0 0 1
0 1 0
1 0 0
1 1 0

verilog代码

  1. 结构化结构
1
2
3
4
5
6
7
8
9
10
11
12
module nor_gate (
input wire A,
input wire B,
output wire Y
);

wire or_out;

or (or_out, A, B);
not (Y, or_out);

endmodule
  1. 数据流描述
1
2
3
4
5
6
7
8
9
10
module nor_gate (
input wire A,
input wire B,
output wire Y
);

assign Y = ~(A | B);

endmodule

与或非

表达式与真值表

  1. 表达式
    $$ Y=\overline{(A\cdot B+C\cdot D)} $$
  2. 真值表
A B C D Y
0 0 0 0 1
0 0 0 1 1
0 0 1 0 1
0 0 1 1 0
0 1 0 0 1
0 1 0 1 1
0 1 1 0 1
0 1 1 1 0
1 0 0 0 1
1 0 0 1 1
1 0 1 0 1
1 0 1 1 0
1 1 0 0 0
1 1 0 1 0
1 1 1 0 0
1 1 1 1 0

verilog代码

  1. 结构化结构
1
2
3
4
5
6
7
8
9
10
11
12
module nand_gate (
input wire A,
input wire B,
output wire Y
);

wire and_out;

and (and_out, A, B);
not (Y, and_out);

endmodule
  1. 数据流描述
1
2
3
4
5
6
7
8
9
10
module nand_gate (
input wire A,
input wire B,
output wire Y
);

// 直接用数据流描述与或非门的逻辑功能
assign Y = ~(A & B);

endmodule

异或

表达式与真值表

  1. 表达式
    $$ Y = A\oplus B$$
  2. 真值表
A B Y
0 0 0
0 1 1
1 0 1
1 1 0

verilog代码

  1. 结构化结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module xor_gate (
input wire A,
input wire B,
output wire Y
);

wire and1, and2, notA, notB;

not (notA, A);
not (notB, B);
and (and1, A, notB);
and (and2, notA, B);
or (Y, and1, and2);

endmodule
  1. 数据流描述
1
2
3
4
5
6
7
8
module xor_gate (
input wire A,
input wire B,
output wire Y
);
assign Y = A ^ B;

endmodule

同或

表达式与真值表

  1. 表达式
    $$ Y = A\odot B $$

  2. 真值表

A B Y
0 0 1
0 1 0
1 0 0
1 1 1

verilog代码

  1. 结构化结构
1
2
3
4
5
6
7
8
9
10
11
12
module xnor_gate (
input wire A,
input wire B,
output wire Y
);

wire xor_out;

xor (xor_out, A, B);
not (Y, xor_out);

endmodule
  1. 数据流描述
1
2
3
4
5
6
7
8
9
module xnor_gate (
input wire A,
input wire B,
output wire Y
);

assign Y = ~(A ^ B);

endmodule

组合逻辑电路

编码器

代码

我举一个4-2编码器的代码:

1
2
3
4
5
6
7
8
9
module bianma42(
input [3:0] i_dec,
output [1:0] o_dec
)
assign o_dec = (i_dec : 4'b0001) ? 2'b00:
(i_dec = 4'b0010) ? 2'b01:
(i_dec = 4'b0100) ? 2'b10:
(i_dec = 4'b1000) ? 2'b11 : 2'bxx;
endmodule

译码器

3-8译码器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module decoder3to8 (
input wire [2:0] in,
input wire enable,
output reg [7:0] out
);

always @(*) begin
if (enable)
out = 8'b00000001 << in;
else
out = 8'b00000000;
end

endmodule

加法器

8位加法器

1
2
3
4
5
6
7
module adder (
input [7:0] a,
input [7:0] b,
output [7:0] sum
);
assign sum = a + b;
endmodule

乘法器

8位乘法器

1
2
3
4
5
6
7
module multiplier (
input [7:0] a,
input [7:0] b,
output [15:0] product
);
assign product = a * b;
endmodule

选择器

4选1

1
2
3
4
5
6
7
8
9
10
11
12
module mux4to1 (
input [7:0] a,
input [7:0] b,
input [7:0] c,
input [7:0] d,
input [1:0] sel,
output [7:0] out
);
assign out = (sel == 2'b00) ? a :
(sel == 2'b01) ? b :
(sel == 2'b10) ? c : d;
endmodule

比较器

1
2
3
4
5
6
7
module comparator (
input [7:0] a,
input [7:0] b,
output equal
);
assign equal = (a == b);
endmodule

移位器

1
2
3
4
5
6
7
module shifter (
input [7:0] in,
input [2:0] shamt,
output [7:0] out
);
assign out = in << shamt;
endmodule

时序逻辑

寄存器

在always结构化过语句后面增加边缘敏感信号(posedge和negedge),就会变成一个简单的寄存器!

简单寄存器

寄存器的作用是让能够存储一组二值(0和1)代码,当边缘敏感信号触发时,就会收集收到的数据。以下是代码:

1
2
3
4
5
6
7
8
module dff(
input i_clk,
input i_din,
output reg o_dout
);
always@(posedge i_clk)
o_dout <= i_din;
endmodule

同步有限状态机

计数器

计数器是一个非常简单的时序逻辑。计数器在系统时钟触发下进行计数,并在达到某一个值的时候输出对应的触发信号给其他的电路模块。

此处用一个4位宽的计数器做例子。一开始的初始值为0(verilog代码中可写作4’b0000),这时候我们启动时钟,每上升(或下降)一次就敲一下计数器,计数器就会记仇并在他的小本子上记录你欺负他的次数。由于是4位宽,所以他的忍耐上线是15次(verilog代码4’b1111)。当你达到他忍耐的上线时,他就会去告状并且发出一个忍无可忍的信号o_full,等他火气消了初始值又回变成0。计数器还包含了一个使能信号,当使能信号无效时,计数器暂停计数。

代码可以这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module counter_4(
input i_clk,
input i_rst,
input i_en,
output reg [3:0] o_cnt,
output o_full
)
always@(posedge i_clk or posedge i_rst)begin
if(i_rst)
o_cnt <= 4'b0000;
else if(i_en)
o_cnt <= o_cnt + 4'b0001;
end

assign o_full = (o_cnt == 4'b1111);
endmodule

时钟分频器

时钟分频器的作用是将高频率的时钟转换为低频率的时钟,如果你看过这个视频”计数器“更能够理解分频。

时钟分频计数器可以分为两类,一类是偶数倍分频,如视频所述的那样用计数器就可以实现,且分频后时钟的占空比可以达到50%;另一类则是奇数倍分频,是不能达到50%的。

如果你硬是要挑战难度,想用奇数倍分频达到50%,则需要同时利用输入时钟的上、下沿进行计数,产生两个奇数分频器,然后做异或运算就可以得到

偶数倍分频器

设计一个偶数倍时钟分频器,该电路将输入时钟进行分频,产生一个相位与源时钟相同、周期为8的信时钟。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module even_freq_div(
input i_clk,
input i_rst_n,
output reg o_clk
);
reg [2:0] cnt; // 3位计数器,能计数到7

always @(posedge i_clk or negedge i_rst_n)
if (!i_rst_n)
cnt <= 3'b000;
else if (cnt == 3'b111)
cnt <= 3'b000;
else
cnt <= cnt + 1;

always @(posedge i_clk or negedge i_rst_n)
if (!i_rst_n)
o_clk <= 1'b0;
else if (cnt == 3'b111)
o_clk <= ~o_clk;
endmodule

奇数倍分频器

设计一个占空比不为50%的奇数倍分频器,该电路的输出时钟周期为输入时钟的7倍,占空比为4/7。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
module odd_divider_7_4(
input clk,
input rst,
output reg clk_out
);

reg [2:0] counter;

always @(posedge clk or posedge rst) begin
if (rst) begin
counter <= 3'd0;
end else begin
if (counter == 3'd6) begin
counter <= 3'd0; // 计数器到达7时复位
end else begin
counter <= counter + 3'd1;
end
end
end

always @(posedge clk or posedge rst) begin
if (rst) begin
clk_out <= 1'b0;
end else begin
if (counter < 3'd4) begin
clk_out <= 1'b1; // 在0到3时输出高电平
end else begin
clk_out <= 1'b0; // 在4到6时输出低电平
end
end
end

endmodule
作者

Hau uhang

发布于

2024-08-08

更新于

2025-05-13

许可协议

评论