第四章 数字逻辑电路设计方法【Verilog】
- 前言
- 推荐
- 第四章 数字逻辑电路设计方法
- 概览
- 4.2 组合逻辑设计
- 裁判表决电路
- 方法1:真值表方式
- 方法2:逻辑代数方式
- 方法3:结构描述方式
- 方法4:抽象描述方式
- 测试
- 结果
- 4.2.1数字加法器
- 2输入1 bit信号全加器
- (1) 利用连续赋值语句实现
- (2) 利用行为描述方式实现
- 测试
- 结果
- 4位超前进位加法器
- 代码
- 测试
- 结果
- 4.2.2 数据比较器
- 4位数值比较器
- 代码
- 测试
- 结果
- 4.2.3 数据选择器
- 8选1数据选择器
- (1) 多个2选1数据选择器的结构级描述
- (2) 抽象描述方式 -
- 测试
- 结果
- 4.2.4数字编码器
- 3位二进制8线—3线编码器
- 8线—3线优先编码器
- 测试
- 结果
- 二进制转化十进制8421BCD编码器
- 代码
- 测试
- 结果
- 8421BCD十进制余3编码器 -
- 代码
- 测试
- 结果 -
- 4.2.5数字译码器
- 2线—4线译码器
- 代码
- 测试
- 结果
- 4.2.6奇偶校验
- 8 bit奇偶校验器
- (a) 结构描述方式
- (b) 抽象描述方式
- 测试
- 结果
- 4.3 时序逻辑设计
- 4.3.1 触发器
- 最简D触发器
- 测试
- 结果
- 带复位端的D触发器
- 同步清0
- 异步清0
- 测试
- 结果
- 复杂功能的D触发器
- 代码
- 测试
- 结果
- T触发器
- 代码
- 测试
- 结果
- 4.3.2 计数器
- 二进制计数器
- 代码
- 测试
- 结果
- 任意进制计数器
- 代码
- 测试
- 结果
- 4.3.3 移位寄存器
- 环形移位寄存器
- 代码
- 测试
- 结果
- 代码改进
- 测试
- 结果
- 4.3.4 序列信号发生器
- 产生100111序列的信号发生器
- 方法1:由移位寄存器构成。
- 方法2:由移位寄存器和组合逻辑电路构成。
- 方法3:由计数器构成
- 测试
- 结果
- 伪随机码发生器
- 代码
- 测试
- 结果
- 4.4 有限同步状态机
- 111序列检测器
- moore型状态转移图
- moore型 2段式
- moore型 3段式
- mealy型状态转移图
- mealy型 2段式
- mealy型 2段式
- 测试
- 结果
- 顺序脉冲发生器
- 代码
- 测试
- 结果
- 自动售报机
- 代码
- 测试
- 结果
- “11010”序列检测器
- 代码
- 测试
- 结果
- 最后
前言
2022/11/28 10:20
以下内容源自Verilog
仅供学习交流使用
推荐
在线文本字符串批量替换工具
如何设置Tab键缩进数量
第四章 数字逻辑电路设计方法
概览
design Verilog 4.2 组合逻辑设计 裁判表决电路
one_bit_fulladder Verilog 4.2.1 数字加法器 2输入1 bit信号全加器
four_bits_fast_addder Verilog 4.2.1 数字加法器 4位超前进位加法器
four_bits_comp Verilog 4.2.2 数据比较器 4位数值比较器
mux8to1 Verilog 4.2.3 数据选择器 8选1
code_8to3 Verilog 4.2.4 数据编码器 3位二进制8线—3线编码器 8线—3线优先编码器
BCD8421 Verilog 4.2.4 数据编码器 二进制转化十进制8421BCD编码器 8421BCD十进制余3编码器
decode_2to4 Verilog 4.2.5 数据译码器 2线—4线译码器
checker Verilog 4.2.6 奇偶校验器 8 bit奇偶校验器
Verilog 4.3 时序逻辑设计
dff Verilog 4.3.1 触发器 最简D触发器 带复位端的D触发器 复杂功能的D触发器
tff Verilog 4.3.1 触发器 T触发器
comp Verilog 4.3.2 计数器 二进制计数器 11进制计数器
shiftregist Verilog 4.3.3 移位寄存器 环形移位寄存器
signal_maker Verilog 4.3.4 序列信号发生器 100111序列产生器
signal Verilog 4.3.4 序列信号发生器 伪随机码发生器
seqdata Verilog 4.4 有限状态转移机 111序列检测器
state Verilog 顺序脉冲发生器 4位顺序脉冲发生器
auto_sellor Verilog 自动售报机
seqdet Verilog “11010”序列检测器
4.2 组合逻辑设计
裁判表决电路
例4.2-1 设计一个3个裁判的表决电路,当两个或两个以上裁判同意时,判决器输出“1”,否则输出“0”。
方法1:真值表方式
方法1:真值表方式。真值表是对电路功能最直接和简单的描述方式。根据电路的功能,可以通过真值表直接建立起输出与输入之间的逻辑关系。例4.2-1有三个输入端A、B、C和一个输出端OUT,其真值表如表4.2-1所示。
module design1(OUT,A,B,C);
output OUT;
input A,B,C;
reg OUT;
always @(A or B or C)
case ({A,B,C})
3'b000 : OUT<=0;
3'b001 : OUT<=0;
3'b010 : OUT<=0;
3'b100 : OUT<=0;
3'b011 : OUT<=1;
3'b101 : OUT<=1;
3'b110 : OUT<=1;
3'b111 : OUT<=1;
endcase
endmodule
方法2:逻辑代数方式
方法2:逻辑代数方式。 组合电路的另一种表达方法是逻辑代数方式,其主要思想是将真值表用卡诺图来表示,然后化简电路,得出逻辑函数表达式。图4.2-2是例4.2-1的卡诺图。 通过对卡诺图的化简,可以得到组合电路逻辑输出与输入之间的逻辑函数表达式: OUT = AB + BC + AC (4.2-1) 根据逻辑函数表达式可以很方便地写出采用逻辑代数方式的Verilog HDL程序:
module design2(OUT,A,B,C);
output OUT;
input A,B,C;
assign OUT=(A&B)|(B&C)|(A&C);
endmodule
方法3:结构描述方式
方法3:结构描述方式。结构描述方式是对电路最直接的表示,早期的数字电路设计通常采用的原理图设计实际上就是一种结构描述方式。Verilog HDL同样可以采用结构描述方式对数字电路进行设计。图4.2-3是公式(4.2-1)表示的基本电路单元构成的电路结构。
module design3(OUT,A,B,C);
output OUT;
input A,B,C;
and U1 (w1,A,B);
and U2 (w2,B,C);
and U3 (w3,A,C);
or U4 (OUT,w1,w2,w3);
endmodule
方法4:抽象描述方式
方法4:抽象描述方式。除了以上3种方法,Verilog HDL还提供了以抽象描述方式进行电路设计的方法,可以直接从电路功能出发,编写代码。例如判决器设计,将三个输入的判决相加,当判决成功时相加器之和大于1,即表示投票成功。采用这种描述方式的Verilog HDL程序代码如下:
module design4(OUT,A,B,C);
output OUT;
input A,B,C;
wire [1:0] sum;
reg OUT;
assign sum=A+B+C;
always @(sum)
if (sum>1) OUT=1;
else OUT=0;
endmodule
测试
module design_tb;
wire OUT;
reg A,B,C;
//design1 u1(OUT,A,B,C);
//design2 u2(OUT,A,B,C);
//design3 u3(OUT,A,B,C);
design4 u4(OUT,A,B,C);
initial
begin
A=0;B=0;C=0;
#10 A=0;B=0;C=1;
#10 A=0;B=1;C=0;
#10 A=0;B=1;C=1;
#10 A=1;B=0;C=0;
#10 A=1;B=0;C=1;
#10 A=1;B=1;C=0;
#10 A=1;B=1;C=1;
end
endmodule
结果
4.2.1数字加法器
2输入1 bit信号全加器
例4.2-2 2输入1 bit信号全加器。如果运算考虑了来自低位的进位,那么该运算就为全加运算。实现全加运算的电路称为全加器。2输入1 bit信号全加器的真值表如表4.2-2所示。
代数逻辑表示为
SUM = A⊕B⊕C_IN (4.2-2)
C_OUT = AB + (A⊕B)C_IN (4.2-3)
对应的电路如图4.2-5所示。
(1) 利用连续赋值语句实现
(1) 利用连续赋值语句实现。
module one_bit_fulladder1(SUM, C_OUT, A, B, C_IN);
input A, B, C_IN;
output SUM, C_OUT;
assign SUM=(A^ B)^C_IN;
assign C_OUT=(A&B)|((A^B)&C_IN); //全加器的输出
endmodule
(2) 利用行为描述方式实现
(2) 利用行为描述方式实现。
module one_bit_fulladder2(SUM, C_OUT, A, B, C_IN);
output SUM, C_OUT;
input A, B, C_IN;
assign {C_OUT,SUM}=A+B+C_IN;
endmodule
测试
module one_bit_fulladder_tb;
reg A, B, C_IN;
wire SUM, C_OUT;
//one_bit_fulladder1 u1(SUM, C_OUT, A, B, C_IN);
one_bit_fulladder2 u2(SUM, C_OUT, A, B, C_IN);
initial
begin
A=0;B=0;C_IN=0;
#10 A=0;B=0;C_IN=1;
#10 A=0;B=1;C_IN=0;
#10 A=0;B=1;C_IN=1;
#10 A=1;B=0;C_IN=0;
#10 A=1;B=0;C_IN=1;
#10 A=1;B=1;C_IN=0;
#10 A=1;B=1;C_IN=1;
end
endmodule
结果
例如一个2输入8 bit加法器,可以采用下面的Verilog HDL程序代码实现。
module eight_bits_fulladder(SUM, C_OUT, A, B, C_IN);
output[7:0] SUM;
output C_OUT;
input [7:0] A, B;
input C_IN;
assign {C_OUT,SUM}=A+B+C_IN;
endmodule
4位超前进位加法器
例4.2-3 4位超前进位加法器。
C1 = G0 + P0C0
C2 = G1 + P1G0 + P1P0C0
C3 = G2 + P2G1 + P2P1G0 + P2P1P0C0
C4 = G3 + P3G2 + P3P2G1 + P3P2P1G0 + P3P2P1P0C0
代码
4位超前进位加法器对应的Verilog HDL代码如下:
书上有误
//例4.2-3 4位超前进位加法器。
module four_bits_fast_addder (sum_out,c_out,a,b,c_in);
input [3:0] a,b; //加数,被加数
input c_in; //来自前级的进位
output [3:0] sum_out; //和
output c_out; //进位输出
wire [3:0] g,p; //产生函数、传输函数
wire [4:0] c; //内部进位
assign c[0]=c_in;
assign p=a^b;
assign g=a&b;
assign c[1]=g[0]|(p[0]&c[0]);
assign c[2]=g[1]|(p[1]&(g[0]|(p[0]&c[0])));
assign c[3]=g[2]|(p[2]&(g[1]|(p[1]&(g[0]|(p[0]&c[0])))));
assign c[4]=g[3]|(p[3]&(g[2]|(p[2]&(g[1]|(p[1]&(g[0]|(p[0]&c[0])))))));
assign sum_out=p^c[3:0];
assign c_out=c[4];
endmodule
module four_bits_fast_addder_tb ;
reg [3:0] a,b; //加数,被加数
reg c_in; //来自前级的进位
wire [3:0] sum_out; //和
wire c_out; //进位输出
four_bits_fast_addder u(sum_out,c_out,a,b,c_in);
initial
begin
a=4'b0000;b=4'b0000;c_in=0;
#10 a=4'b0001;b=4'b0001;c_in=0;
#10 a=4'b0011;b=4'b0011;c_in=0;
#10 a=4'b0111;b=4'b0111;c_in=0;
#10 a=4'b1111;b=4'b1111;c_in=0;
#10 a=4'b0000;b=4'b0000;c_in=1;
#10 a=4'b0001;b=4'b0001;c_in=1;
#10 a=4'b0011;b=4'b0011;c_in=1;
#10 a=4'b0111;b=4'b0111;c_in=1;
#10 a=4'b1111;b=4'b1111;c_in=1;
end
endmodule
测试
结果
4.2.2 数据比较器
4位数值比较器
例4.2-4 4位数值比较器。
用F[2:0]表示比较结果{FA>B,FA=B,FA<B},C[2:0]表示前一级比较结果{CA>B,CA=B,CA<B},采用描述方式的Verilog HDL程序如下:
代码
//例4.2-4 4位数值比较器。
module four_bits_comp1(F, A, B, C);
parameter comp_width=4;
output [2:0] F;
input [2:0] C;
input [comp_width-1:0] A;
input [comp_width-1:0] B;
reg [2:0] F; always @(A or B or C)
if (A>B) F=3'b100;
else if (A<B) F=3'b001;
else F=C;
endmodule
测试
module four_bits_comp1_tb;
parameter comp_width=4;
wire [2:0] F;
reg [2:0] C;
reg [comp_width-1:0] A;
reg [comp_width-1:0] B;
four_bits_comp1 u1(F, A, B, C);
initial
begin
A=4'b0000;B=4'b1111;C=3'b000;
#10 A=4'b1111;B=4'b0000;C=3'b000;
#10 A=4'b0011;B=4'b0011;C=3'b100;
#10 A=4'b0011;B=4'b0011;C=3'b010;
#10 A=4'b0011;B=4'b0011;C=3'b001;
end
endmodule
结果
4.2.3 数据选择器
8选1数据选择器
例4.2-5 8选1数据选择器。
8选1数据选择器可以由多个2选1数据选择器构成,也可以采用抽象描述方式进行设计;
可以采用2选1数据选择器串行连接,也可以用树形连接分成三级实现。
(1) 多个2选1数据选择器的结构级描述
(1) 多个2选1数据选择器的结构级描述(见图4.2-8)。
// 8选1数据选择器
// (1) 多个2选1数据选择器的结构级描述
module mux8to1_2(d_out, d_in, sel);
output d_out;
input [7:0] d_in;
input [2:0] sel;
wire[3:0] w1;
wire[1:0] w2;
assign w1=sel[0]? {d_in[7],d_in[5],d_in[3],d_in[1]} :{d_in[6],d_in[4], d_in[2],d_in[0]};
assign w2=sel[1]? {w1[3],w1[1]} :{w1[2],w1[0]};
assign d_out=sel[2]?w2[1]:w2[0];
endmodule
(2) 抽象描述方式 -
(2) 抽象描述方式。多路选择器的设计可以采用case语句直接进行设计。在这种设计方式中,只需考虑选择信号列表就可以实现功能更为复杂的数据选择器。
// 8选1数据选择器
// (2) 抽象描述方式
module mux8to1_1(out,sel,data_in);
output out;
input [7:0] data_in;
input [3:0] sel;
reg out;
always @ (data_in or sel)
case (sel)
3'b000 : out<=data_in[0];
3'b001 : out<=data_in[1];
3'b010 : out<=data_in[2];
3'b011 : out<=data_in[3];
3'b100 : out<=data_in[4];
3'b101 : out<=data_in[5];
3'b110 : out<=data_in[6];
3'b111 : out<=data_in[7];
endcase
endmodule
测试
module mux8to1_tb;
wire d_out;
reg [7:0] d_in;
reg [2:0] sel;
//mux8to1_2 u2(d_out, d_in, sel);
mux8to1_1 u1(d_out, d_in, sel);
initial
begin
d_in=8'b01010101;
#10 sel=3'b000;
#10 sel=3'b001;
#10 sel=3'b010;
#10 sel=3'b011;
#10 sel=3'b100;
#10 sel=3'b101;
#10 sel=3'b110;
#10 sel=3'b111;
end
endmodule
结果
4.2.4数字编码器
3位二进制8线—3线编码器
例4.2-6 3位二进制8线—3线编码器。
采用抽象描述方式的Verilog HDL程序代码如下:
// 4.2.4数字编码器
// 3位二进制8线
module code_8to3(F,I);
output [2:0] F;
input [7:0] I;
reg [2:0] F;
always @ (I)
case (I)
8'b00000001: F=3'b000;
8'b00000010: F=3'b001;
8'b00000100: F=3'b010;
8'b00001000: F=3'b011;
8'b00010000: F=3'b100;
8'b00100000: F=3'b101;
8'b01000000: F=3'b110;
8'b10000000: F=3'b111;
default : F=3'bx;
endcase
endmodule
8线—3线优先编码器
例4.2-7 8线—3线优先编码器。
8线—3线优先编码器的Verilog HDL程序代码如下:
//4.2.4数字编码器
//8线—3线优先编码器
module mux8to3_p(data_out, Ys, Yex, sel, data_in);
output [2:0] data_out; output Ys, Yex;
input [7:0] data_in; input sel; reg [2:0]
data_out;
reg Ys,Yex;
always @ (data_in or sel)
if (sel) {data_out, Ys, Yex} ={3'b111,1'b1,1'b1};
else
begin
casex (data_in)
8'b0??????? : {data_out, Ys, Yex} ={3'b000,1'b1,1'b0};
8'b10?????? : {data_out, Ys, Yex} ={3'b001,1'b1,1'b0};
8'b110????? : {data_out, Ys, Yex} ={3'b010,1'b1,1'b0};
8'b1110???? : {data_out, Ys, Yex}={3'b011,1'b1,1'b0};
8'b11110??? : {data_out, Ys, Yex}={3'b100,1'b1,1'b0};
8'b111110?? : {data_out, Ys, Yex}={3'b101,1'b1,1'b0};
8'b1111110? : {data_out, Ys, Yex}={3'b110,1'b1,1'b0};
8'b11111110 : {data_out, Ys, Yex}={3'b111,1'b1,1'b0};
8'b11111111 : {data_out, Ys, Yex}={3'b111,1'b0,1'b1};
endcase
end
endmodule
测试
module code_8to3_tb;
wire [2:0] F;
reg [7:0] I;
code_8to3 u1(F,I);
initial
begin
I=8'b0000_0001;
#10 I=8'b0000_0010;
#10 I=8'b0000_0100;
#10 I=8'b0000_1000;
#10 I=8'b0001_0000;
#10 I=8'b0010_0000;
#10 I=8'b0100_0000;
#10 I=8'b1000_0000;
end
endmodule
结果
二进制转化十进制8421BCD编码器
例4.2-8 二进制转化十进制8421BCD编码器。
代码
//4.2.4数字编码器
//二进制转化十进制8421BCD编码器
module BCD8421(data_out, data_in);
output [3:0] data_out;
input [8:0] data_in;
reg [3:0] data_out;
always @ (data_in)
case (data_in)
9'b000000000 : data_out=4'b0000;
9'b000000001 : data_out=4'b0001;
9'b000000010 : data_out=4'b0010;
9'b000000100 : data_out=4'b0011;
9'b000001000 : data_out=4'b0100;
9'b000010000 : data_out=4'b0101;
9'b000100000 : data_out=4'b0110;
9'b001000000 : data_out=4'b0111;
9'b010000000 : data_out=4'b1000;
9'b100000000 : data_out=4'b1001;
default : data_out=4'b0000;
endcase
endmodule
测试
module BCD8421_tb;
wire [3:0] data_out;
reg [8:0] data_in;
BCD8421 u1 (data_out, data_in);
initial
begin
data_in=9'b000000000;
#10 data_in=9'b000000001;
#10 data_in=9'b000000010;
#10 data_in=9'b000000100;
#10 data_in=9'b000001000;
#10 data_in=9'b000010000;
#10 data_in=9'b000100000;
#10 data_in=9'b001000000;
#10 data_in=9'b010000000;
#10 data_in=9'b100000000;
end
endmodule
结果
8421BCD十进制余3编码器 -
例4.2-9 8421BCD十进制余3编码器。
和8421BCD编码器一样,余3码编码器也可以通过查找表的方式进行描述,仅需改变表4.2-6中真值表的内容即可。
另外,也可以通过8421BCD码加“3”的方式得到,Verilog HDL 程序代码如下:
代码
module code_change(B_out,B_in);
output [3:0] B_out;
input [3:0] B_in;
assign B_out=B_in+2'b11;
endmodule
//4.2.4数字编码器
//8421BCD十进制余3编码器
module top_change(B_out,data_in);
output[3:0] B_out;
input [9:0] data_in;
wire [3:0] change;
BCD8421 u1(change,data_in);
code_change u2(B_out,change);
endmodule
测试
module top_change_tb;
wire [3:0] B_out;
reg [3:0] data_in;
top_change ut (B_out,data_in);
initial
begin
data_in=9'b000000000;
#10 data_in=9'b000000001;
#10 data_in=9'b000000010;
#10 data_in=9'b000000100;
#10 data_in=9'b000001000;
#10 data_in=9'b000010000;
#10 data_in=9'b000100000;
#10 data_in=9'b001000000;
#10 data_in=9'b010000000;
#10 data_in=9'b100000000;
end
endmodule
结果 -
4.2.5数字译码器
2线—4线译码器
代码
同编码器一样,译码器的级联扩展也可使用同样的方法,其Verilog HDL程序代码如下:
//4.2.5数字译码器
// 2线—4线译码器
module decode_2to4_1(Y, E, A);
output [3:0] Y;
input [1:0] A;
input E;
assign Y[0]=~(~E&~A[1]&~A[0]);
assign Y[1]=~(~E&~A[1]&A[0]);
assign Y[2]=~(~E&A[1]&~A[0]);
assign Y[3]=~(~E&A[1]&A[0]);
endmodule
也可以采用抽象描述方式进行设计,其Verilog HDL程序代码如下:
//4.2.5数字译码器
// 2线—4线译码器
// 抽象描述方式 低有效
module decode_2to4_2(Y, E, A);
output [3:0] Y;
input [1:0] A;
input E;
reg [3:0] Y;
always @(E or A)
case ({E,A})
3'b1?? : Y=4'b0000;
3'b000 : Y=4'b0001;
3'b001 : Y=4'b0010;
3'b010 : Y=4'b0100;
3'b011 : Y=4'b1000;
default : Y=4'b0000;
endcase
endmodule
测试
module decode_2to4_tb;
wire[3:0] Y;
reg [1:0] A;
reg E;
decode_2to4_1 u1(Y, E, A);
//decode_2to4_2 u2(Y, E, A);
initial
begin
E=1;A=2'b00;
#10 E=1;A=2'b01;
#10 E=1;A=2'b10;
#10 E=1;A=2'b11;
#10 E=0;A=2'b00;
#10 E=0;A=2'b01;
#10 E=0;A=2'b10;
#10 E=0;A=2'b11;
end
endmodule
结果
4.2.6奇偶校验
8 bit奇偶校验器
例4.2-10 8 bit奇偶校验器。
在Verilog HDL中,可以采用结构描述方式也可以采用抽象描述方式。
书上有误
(a) 结构描述方式
(a) 结构描述方式:
//4.2.6奇偶校验
// 8 bit奇偶校验器
//(a) 结构描述方式
module checker1 (Fod,Fev,b);
output Fod,Fev;
input [7:0] b;
wire w1,w2,w3,w4,w5,w6;
xor U1 (w1,b[0],b[1]);
xor U2 (w2,b[2],b[3]);
xor U3 (w3,b[4],b[5]);
xor U4 (w4,b[6],b[7]);
xor U5 (w5,w1,w2);
xor U6 (w6,w3,w4);
xor U7 (Fev,w5,w6);
not U8 (Fod,Fev);
endmodule
(b) 抽象描述方式
(b) 抽象描述方式:
//4.2.6奇偶校验
// 8 bit奇偶校验器
//(b) 抽象描述方式
module checker2 (Fod,Fev,b);
output Fod,Fev;
input [7:0] b;
assign Fev=^b;
assign Fod=~Fev;
endmodule
测试
module checker_tb;
wire Fod,Fev;
reg [7:0] b;
//checker1 u1(Fod,Fev,b);
checker2 u2(Fod,Fev,b);
initial
begin
b=8'b00000000;
#10 b=8'b00000001;
#10 b=8'b00000011;
#10 b=8'b00000111;
#10 b=8'b00001111;
#10 b=8'b00011111;
#10 b=8'b00111111;
#10 b=8'b01111111;
#10 b=8'b11111111;
end
endmodule
结果
4.3 时序逻辑设计
4.3.1 触发器
触发器是时序逻辑电路的最基本电路单元,主要有D触发器、JK触发器、T触发器和RS触发器等。根据功能要求的不同,触发器还具有置位、复位、使能、选择等功能。
最简D触发器
例4.3-2 最简D触发器。
//4.3.1 触发器
//最简D触发器
module DFF(q, clk, data_in);
output q;
input clk, data_in;
reg q;
always @(posedge clk)
q<=data_in;
endmodule
测试
module DFF_tb;
wire q;
reg clk, data_in;
DFF ud(q, clk, data_in);
always
#5 clk = ~clk;
initial
begin
clk=0;
data_in=0;
#20 data_in=1;
#20 data_in=0;
#20 data_in=1;
#15 data_in=0;
#15 data_in=1;
end
endmodule
结果
带复位端的D触发器
例4.3-3 带复位端的D触发器。
同步清0
//4.3.1 触发器
//带复位端的D触发器
//同步清0
module DFF_rst_sync (q, clk, reset, data_in);
output q;
input clk, reset, data_in;
reg q;
always @(posedge clk)
if (!reset) q<=0;
else q<=data_in;
endmodule
异步清0
//4.3.1 触发器
//带复位端的D触发器
//异步清0
module DFF_rst_nsync (q, clk, reset, data_in);
output q;
input clk, reset,data_in;
reg q;
always @(posedge clk or reset)
if (!reset) q<=0;
else q<=data_in;
endmodule
测试
module DFF_rst_tb;
wire q;
reg clk, reset,data_in;
//DFF_rst_sync us(q, clk, reset, data_in);
DFF_rst_nsync uns(q, clk, reset, data_in);
always
#5 clk = ~clk;
initial
begin
clk=0;
data_in=0;
reset=1;
#20 data_in=1;
#20 data_in=0;
#20 data_in=1;
#20 reset=0;
data_in=1;
#15 reset=1;
data_in=1;
#15 data_in=1;
end
endmodule
结果
复杂功能的D触发器
例4.3-4 复杂功能的D触发器。
代码
前面介绍了最简单的D触发器和带有同步清0、异步清0的D触发器。这里给出同步清0、置1和异步清0、置1共同在一个触发器上的复杂D触发器例子。其Verilog HDL程序代码如下:
module DFF_1(q, clk, reset1, reset2, data_in);
output q;
input clk, reset1,reset2, data_in;
reg q;
always @(posedge clk)
if (!reset1) q<=0;
else q<=data_in;
always @(posedge clk or reset2)
if (!reset2) q<=0;
else q<=data_in;
endmodule
测试
module DFF_1_tb;
wire q;
reg clk, reset1,reset2, data_in;
DFF_1 u1(q, clk, reset1, reset2, data_in);
always
#5 clk = ~clk;
initial
begin
clk=0;
data_in=0;
reset1=1;
reset2=1;
#20 data_in=1;
#20 data_in=0;
#20 data_in=1;
#20 reset1=0;
data_in=1;
#15 reset1=1;
data_in=1;
#15 data_in=1;
#20 reset2=0;
data_in=1;
#15 reset2=1;
data_in=1;
#15 data_in=1;
end
endmodule
结果
T触发器
例4.3-5 T触发器。
T触发器的逻辑符号如图4.3-10所示,其逻辑功能为:当时钟的有效边沿到来时,如果T=1,则触发器翻转;如果T = 0,则触发器的状态保持不变。reset为复位端,异步复位,低电平有效。
T触发器的Verilog HDL程序代码如下:
代码
module TFF(data_out, T, clk, reset);
output data_out;
input T,clk, reset;
reg data_out;
always @(posedge clk or reset)
if (!reset) data_out<=1'b0;
else if (T) data_out<=~data_out;
endmodule
测试
module TFF_tb;
wire data_out;
reg T,clk, reset;
TFF u1(data_out, T, clk, reset);
always
#5 clk = ~clk;
initial
begin
clk=0;
reset=0;
T=0;
#20
reset=1;
T=1;
#20 T=0;
#20 T=1;
#20 reset=0;
T=0;
#15 T=0;
#15 T=0;
#15 reset=1;
T=1;
end
endmodule
结果
4.3.2 计数器
二进制计数器
例4.3-6 二进制计数器。
图4.3-11是采用D触发器设计二进制计数器的逻辑电路图。
由D触发器实现的二进制计数器的Verilog HDL程序代码如下:
代码
//4.3.2 计数器
//十一进制计数器
module comp_11(count, clk, reset);
output [3:0] count; input clk,reset;
reg [3:0] count;
always @ (posedge clk)
if (reset) count<=4'b0000;
else if (count==4'b1010) count<=1'b0;
else count<=count+1;
endmodule
测试
module comp2bit_tb;
wire Q;
reg clk, reset;
comp2bit u1(Q, clk, reset);
always
#5 clk = ~clk;
initial
begin
clk=0;
reset=0;
#10
reset=1;
#50 reset=0;
#20 reset=1;
end
endmodule
结果
任意进制计数器
例4.3-7 任意进制计数器。 在数字电路系统中,经常会使用任意进制计数器,Verilog HDL可以很好地支持对不同进制计数器的设计。 对于M进制的计数器,第一步需要确定计数器所需要触发器的个数。N个触发器对应了2N个状态,应有2N>M。任意进制计数器选取满足条件的最小N,N为计数器中触发器的个数。计数器的状态跳转有两种实现方法:反馈清零法和反馈置数法。
以十一进制计数器为例,最少需要4个触发器。采用反馈清零法设计的十一进制计数器的Verilog HDL程序代码如下:
代码
module comp_11(count, clk, reset);
output [3:0] count; input clk,reset;
reg [3:0] count;
always @ (posedge clk)
if (reset) count<=4'b0000;
else if (count==4'b1010) count<=1'b0;
else count<=count+1;
endmodule
测试
module comp_11_tb;
wire [3:0] count;
reg clk,reset;
comp_11 u1(count, clk, reset);
always
#5 clk = ~clk;
initial
begin
clk=0;
reset=1;
#10
reset=0;
#130 reset=1;
#20 reset=0;
end
endmodule
结果
4.3.3 移位寄存器
移位寄存器可以用来实现数据的串并转换,也可以构成移位行计数器,进行计数、分频,还可以构成序列码发生器、序列码检测器等,它也是数字系统中应用非常广泛的时序逻辑部件之一。
环形移位寄存器
例4.3-8 环形移位寄存器。
N位环型寄存器由N个移位寄存器组成,它可以实现环型移位,如图4.3-12所示。
该例中,将每个寄存器的输出作为下一位寄存器的输入,并将高位寄存器的输出作为循环的输入。
Verilog HDL程序代码如下:
代码
//4.3.3 移位寄存器
//环形移位寄存器
module shiftregist1 (D,clk,reset);
parameter shiftregist_width=4;
output [shiftregist_width-1:0] D;
input clk,reset;
reg [shiftregist_width-1:0] D;
always @(posedge clk)
if (!reset) D<=4'b0000;
else D<={D[shiftregist_width-2:0],D[shiftregist_width-1]};
endmodule
测试
module shiftregist1_tb;
parameter shiftregist_width=4;
wire [shiftregist_width-1:0] D;
reg clk,reset;
shiftregist1 s1(D,clk,reset);
always
#5 clk = ~clk;
initial
begin
clk=0;
reset=1;
#100 reset=0;
#20 reset=1;
end
endmodule
结果
代码改进
具有置位功能的环形寄存器
//4.3.3 移位寄存器
//环形移位寄存器
module shiftregist2 (D,clk,set,Q);
parameter shiftregist_width=4;
output [shiftregist_width-1:0] D;
input clk,set;
input wire[shiftregist_width-1:0] Q;
reg [shiftregist_width-1:0] D;
initial D=4'b1100;
always @(posedge clk)
if (set) D<=Q;
else D<={D[shiftregist_width-2:0],D[shiftregist_width-1]};
endmodule
测试
module shiftregist2_tb;
parameter shiftregist_width=4;
wire [shiftregist_width-1:0] D;
reg clk,set;
reg [shiftregist_width-1:0] Q;
shiftregist2 s2(D,clk,set,Q);
always
#5 clk = ~clk;
initial
begin
clk=0;
set=0;
Q=4'b0000;
#10
set=1;
Q=4'b1100;
#10
set=0;
#100
set=1;
Q=4'b0011;
#10
set=0;
end
endmodule
结果
4.3.4 序列信号发生器
序列信号是数字电路系统中常用的功能单元,其种类很多,如按照序列循环长度M与触发器数目n的关系,一般可分为三种:
(1) 最大循环长度序列码,M = 2n。
(2) 最长线性序列码(M序列码),M = 2n -1。
(3) 任意循环长度序列码,M<2n。
序列信号发生器是能够产生一组或多组序列信号的时序电路,它可以由纯时序电路构成,也可以由包含时序逻辑和组合逻辑的混合电路构成。
产生100111序列的信号发生器
例4.3-9 用Verilog HDL设计一个产生100111序列的信号发生器。
方法1:由移位寄存器构成。
Verilog HDL程序代码如下:
//4.3.4 序列信号发生器
//方法1:由移位寄存器构成
module signal_maker1(out,clk,load,D);
parameter M=6;
output out;
input clk,load;
input [M-1:0] D;
reg [M-1:0] Q;
initial Q=6'b10011;
always @( posedge clk)
if (load) Q<=D;
else Q<={Q[M-2:0],Q[M-1]};
assign out=Q[M];
endmodule
方法2:由移位寄存器和组合逻辑电路构成。
方法2:由移位寄存器和组合逻辑电路构成。
反馈移位寄存器型序列信号发生器的Verilog HDL程序代码如下:
//4.3.4 序列信号发生器
//方法2:由移位寄存器和组合逻辑电路构成
module signal_maker2(out,clk,load,D);
parameter M=4;
output out;
input clk,load;
input [M-1:0] D;
reg [M-1:0] Q;
wire w1;
always @(posedge clk) //时序电路部分,移位寄存器
if (load) Q<=D;
else Q<={Q[M-2:0],w1};
assign w1=(~Q[3])|(~Q[1]&(~Q[0]))|(Q[3]&(~Q[2])); //组合逻辑电路,反馈 //网络
assign out=Q[M-1];
endmodule
方法3:由计数器构成
方法3:由计数器构成。
由真值表可画出输出out的卡诺图,得到输出函数。Verilog HDL程序代码如下:
//4.3.4 序列信号发生器
//方法3:由计数器构成
module signal_maker3(out, clk,reset);
parameter M=3;
output out;
input clk,reset;
reg [M-1:0] counter;
always @(posedge clk)
if (!reset) counter<=3'b000;
else counter<=counter+1;
assign out=counter[2]|((~counter[1])&(~counter[0]))|(counter[1]&counter[0]);
endmodule
测试
module signal_maker_tb;
parameter M=6;
wire out;
reg clk,load;
reg [M-1:0] D;
signal_maker1 u1(out,clk,load,D);
always
#5 clk = ~clk;
initial
begin
clk=0;
load=0;
#10
load=1;
D=6'b100111;
#10
load=0;
#200
load=1;
D=6'b100111;
#10
load=0;
end
endmodule
module signal_maker2_tb;
parameter M=6;
wire out;
reg clk,load;
reg [M-1:0] D;
signal_maker2 u2(out,clk,load,D);
always
#5 clk = ~clk;
initial
begin
clk=0;
load=0;
#10
load=1;
D=6'b100111;
#10
load=0;
#100
load=1;
D=6'b100111;
#10
load=0;
end
endmodule
module signal_maker3_tb;
parameter M=3;
wire out;
reg clk,reset;
signal_maker3 u3(out,clk,reset);
always
#5 clk = ~clk;
initial
begin
clk=0;
reset=0;
#10
reset=1;
#100
reset=0;
#10
reset=1;
end
endmodule
结果
伪随机码发生器
例4.3-10 用Verilog HDL设计伪随机码发生器。 伪随机码是一种变化规律与随机码类似的二进制代码,可以作为数字通信中的一个信号源,通过信道发送到接收机,用于检测数字通信系统错码的概率,即误码率。
表4.3-4 M序列反馈函数表
下面以N = 4为例。在15位最长线性序列移位寄存器型计数器中,有一个由“0000”构成的死循环,为了打破死循环,可以修改式为 F=Q1^Q0+!Q3!Q2!Q1!Q0
(4.3-11)
当Q3~Q0 = 0000时,反馈函数F = 1,打破了原反馈函数F = 0出现的死循环。
根据N = 4的最长线性序列移位寄存器型计数器的功能,实现的伪随机码发生器的Verilog HDL程序代码如下:
代码
//4.3.4 序列信号发生器
//伪随机码发生器
module signal15(out, clk, load_n, D_load);
output out;
input load_n,clk;
input [3:0] D_load;
reg [3:0] Q; wire F;
always @(posedge clk)
if (~load_n) Q<=D_load;
else Q<={Q[2:0],F};
assign F=(Q[1]^Q[0])|(~Q[3]&~Q[2]&~Q[1]&~Q[0]);
assign out=Q[3];
endmodule
测试
module signal15_tb;
wire out;
reg load_n,clk;
reg [3:0] D_load;
signal15 u15(out, clk, load_n, D_load);
always
#5 clk = ~clk;
initial
begin
clk=0;
load_n=0;
D_load=4'b0000;
#10
load_n=1;
#100
load_n=0;
D_load=4'b0000;
#10
load_n=1;
end
endmodule
结果
4.4 有限同步状态机
有限状态机可以分为同步和异步两种,在本书中我们只讨论有限同步状态机,后文中提到的有限状态机均指有限同步状态机。有限状态机是时序电路的通用模型,任何时序电路都可以表示为有限状态机。在由时序电路表示的有限状态机中,各个状态之间的转移总是在时钟的触发下进行的,状态信息存储在寄存器中。因为状态的个数是有限的,所以称为有限状态机。
图4.4-1 有限状态机的电路结构
图4.4-2 有限状态机的结构
状态机的编码方式很多,由此产生的电路也不相同。
常见的编码方式有三种:二进制编码、格雷编码和一位独热编码。
在Verilog HDL中,有限状态机的描述方法较多,常用的有两段式和三段式两种。
111序列检测器
moore型状态转移图
moore型 2段式
//moore型 2段式
//输出只由当前状态决定
//4个状态用格雷码表示
//s0 : 已收到0个1 输出0
//s1 : 已收到1个1 输出0
//s2 : 已收到2个1 输出0
//s3 : 已收到3个1 输出1
module seqdata_moore (
input wire clk,
input wire clr,
input wire din,
output reg dout
) ;
reg [1:0] present_state , next_state ;
parameter s0=2'b00,sl=2'b01,s2=2'b11,s3=2'b10;
always @(posedge clk or posedge clr)
begin
if(clr==1)present_state<=s0;
else present_state<=next_state ;
end
always @(*)
begin
case (present_state)
s0: if(din==1) begin next_state=sl; dout=0; end
else begin next_state=s0; dout=0; end
sl: if(din==1) begin next_state=s2; dout=0; end
else begin next_state=s0; dout=0; end
s2: if(din==1) begin next_state=s3; dout=1; end
else begin next_state=s0; dout=0; end
s3: if(din==1) begin next_state=s3; dout=1; end
else begin next_state=s0; dout=0; end
default: next_state=s0;
endcase
end
endmodule
moore型 3段式
//moore型 3段式
//输出只由当前状态决定
//4个状态用格雷码表示
//s0 : 已收到0个1 输出0
//s1 : 已收到1个1 输出0
//s2 : 已收到2个1 输出0
//s3 : 已收到3个1 输出1
module seqdata_moore3 (
input wire clk,
input wire clr,
input wire din,
output reg dout
) ;
reg [1:0] present_state , next_state ;
parameter s0=2'b00,sl=2'b01,s2=2'b11,s3=2'b10;
always @(posedge clk or posedge clr)
begin
if(clr==1)present_state<=s0;
else present_state<=next_state ;
end
always @(*)
begin
case (present_state)
s0: if(din==1) begin next_state=sl; end
else begin next_state=s0; end
sl: if(din==1) begin next_state=s2; end
else begin next_state=s0; end
s2: if(din==1) begin next_state=s3; end
else begin next_state=s0; end
s3: if(din==1) begin next_state=s3; end
else begin next_state=s0; end
default: next_state=s0;
endcase
end
always @(*)
begin
if (present_state==s3)
begin dout=1; end
else begin dout=0; end
end
endmodule
mealy型状态转移图
mealy型 2段式
//mealy型 2段式
//输出由当前状态和输入共同决定
//s0 : 已收到0个1
//s1 : 已收到1个1
//s2 : 已收到2个1 再输入1 即可输出1
module seqdata_mealy (
input wire clk,
input wire clr,
input wire din,
output reg dout
) ;
reg [1:0] present_state , next_state ;
parameter s0=2'b00, sl=2'b01,s2=2'b11;
always @(posedge clk or posedge clr)
begin
if(clr==1)present_state<=s0;
else present_state<=next_state ;
end
always @(*)
begin
case (present_state)
s0: if(din==1) begin next_state=sl; dout=0; end
else begin next_state=s0; dout=0; end
sl: if(din==1) begin next_state=s2; dout=0; end
else begin next_state=s0; dout=0; end
s2: if(din==1) begin next_state=s2; dout=1; end
else begin next_state=s0; dout=0; end
default: next_state=s0;
endcase
end
endmodule
mealy型 2段式
//mealy型 3段式
//输出由当前状态和输入共同决定
//3个状态用格雷码表示
//s0 : 已收到0个1
//s1 : 已收到1个1
//s2 : 已收到2个1 再输入1 即可输出1
module seqdata_mealy3 (
input wire clk,
input wire clr,
input wire din,
output reg dout
) ;
reg [1:0] present_state , next_state ;
parameter s0=2'b00, sl=2'b01,s2=2'b11;
always @(posedge clk or posedge clr)
begin
if(clr==1)present_state<=s0;
else present_state<=next_state ;
end
always @(*)
begin
case (present_state)
s0: if(din==1) begin next_state=sl; end
else begin next_state=s0; end
sl: if(din==1) begin next_state=s2; end
else begin next_state=s0; end
s2: if(din==1) begin next_state=s2; end
else begin next_state=s0; end
default: next_state=s0;
endcase
end
always @(*)
begin
case (present_state)
s0: if(din==1) begin dout=0; end
else begin dout=0; end
sl: if(din==1) begin dout=0; end
else begin dout=0; end
s2: if(din==1) begin dout=1; end
else begin dout=0; end
default: dout=0;
endcase
end
endmodule
测试
module seqdata_tb;
reg clk;
reg clr;
reg din;
wire dout;
seqdata_moore uut (.clk(clk),.clr(clr),.din (din),.dout (dout) ) ;
//seqdata_moore3 uut (.clk(clk),.clr(clr),.din (din),.dout (dout) ) ;
//seqdata_mealy uut (.clk(clk),.clr(clr),.din (din),.dout (dout) ) ;
//seqdata_mealy3 uut (.clk(clk),.clr(clr),.din (din),.dout (dout) ) ;
always #100 clk=~clk ;
initial begin
clk = 0;
clr = 1;
din = 0;
#500 clr=0;
#200 din=1;
#200 din=0;
#200 din=1;
#400 din=0;
#200 din=1;
#600 din=0;
#200 din=1;
end
endmodule
结果
顺序脉冲发生器
例4.4-1 用Verilog HDL设计顺序脉冲发生器。 顺序脉冲发生器又称脉冲分配器,它将高电平脉冲依次分配到不同的输出上,保证在每个时钟周期内只有一路输出高电平,不同时钟上的高电平脉冲依次出现在所有输出端。
以4位顺序脉冲发生器为例,它有4路输出W0 W1 W2 W3,每路输出上高电平脉冲依次出现,输出在1000、0100、0010、0001之间循环。4位顺序脉冲发生器的状态转移图如图4.4-3所示,它由4个状态构成,每个状态中“1”的个数都是1个,表示每个时钟周期内只有一路输出端为高电平,而且是轮流出现,因此生成了顺序脉冲信号。
代码
对四状态的状态机编码只需要两位二进制编码即可,Verilog HDL程序设计代码如下:
//4.4 有限状态转移机
//顺序脉冲发生器
//4位顺序脉冲发生器
module state4(OUT, clk);
output [3:0] OUT;
input clk;
reg [3:0] OUT;
reg [1:0] STATE, next_STATE;
initial //添加
begin
STATE=2'b00;
end
always @(STATE)
case (STATE)
2'b00: begin OUT<=4'b1000; next_STATE<=2'b01; end
2'b01: begin OUT<=4'b0100; next_STATE<=2'b10; end
2'b10: begin OUT<=4'b0010; next_STATE<=2'b11; end
2'b11: begin OUT<=4'b0001; next_STATE<=2'b00; end
endcase
always @(posedge clk)
STATE<=next_STATE;
endmodule
测试
module state4_tb;
wire [3:0] OUT;
reg clk;
state4 s4(OUT, clk);
always
#5 clk = ~clk;
initial
begin
clk=0;
end
endmodule
结果
自动售报机
例4.4-2 设计一个自动售报机,报纸价钱为八角,纸币有1角、2角、5角、一元。该自动售报机不考虑投币为大额面值等特殊情况。
图4.4-4是自动售报机的状态转移图。图中,S0~S7为状态机的8个状态,角标代表已投币的总和,如S0代表没有投币,S1代表已投入1角,依此类推。M代表输入,M1表示投入1角硬币,M2代表投入2角硬币,M5代表投入5角硬币,M10代表投入一元。
data_out=1表示给出报纸,data_out_return1=1表示找回1角硬币,data_out_return2=1表示找回2角硬币。自动售报机的Verilog HDL程序代码如下:
代码
//4.4 有限同步状态机
//自动售报机
module auto_sellor(current_state,data_out,data_out_return1,data_out_return2, clk,rst_n,data_in);
parameter state_width=3,data_in_width=3;
output [state_width-1:0] current_state;
output data_out, data_out_return1, data_out_return2;
input [data_in_width-1:0] data_in;
input clk, rst_n;
reg [state_width-1:0] current_state, next_state;
reg data_out, data_out_return1, data_out_return2;
always @(current_state or rst_n)
if (!rst_n) next_state<=0;
else
case (current_state)
3'b000: case (data_in)
3'b000: begin
next_state<=3'b000;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b001;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b010;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b101;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b100: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b0;
data_out_return2<=1'b1;
end
endcase
3'b001: case (data_in)
3'b000: begin
next_state<=3'b001;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b010;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b011;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b110;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
endcase
3'b010: case (data_in)
3'b000: begin
next_state<=3'b010;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b011;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b100;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b111;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
endcase
3'b011: case (data_in)
3'b000: begin
next_state<=3'b011;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b100;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b101;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
endcase
3'b100: case (data_in)
3'b000: begin
next_state<=3'b000;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b101;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b110;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b1;
data_out_return2<=1'b0;
end
endcase
3'b101: case (data_in)
3'b000: begin
next_state<=3'b101;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b110;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b111;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b0;
data_out_return2<=1'b1;
end
endcase
3'b110: case (data_in)
3'b000: begin
next_state<=3'b110;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b111;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
endcase
3'b111: case (data_in)
3'b000: begin
next_state<=3'b111;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
endcase
endcase
always @(posedge clk or rst_n)
if (!rst_n) current_state<=3'b000;
else current_state<=next_state;
endmodule
//4.4 有限同步状态机
//自动售报机
module auto_sellor(current_state,data_out,data_out_return1,data_out_return2, clk,rst_n,data_in);
parameter state_width=3,data_in_width=3;
output [state_width-1:0] current_state;
output data_out, data_out_return1, data_out_return2;
input [data_in_width-1:0] data_in;
input clk, rst_n;
reg [state_width-1:0] current_state, next_state;
reg data_out, data_out_return1, data_out_return2;
always @(current_state or rst_n)
if (!rst_n) next_state<=0;
else
case (current_state)
3'b000: case (data_in)
3'b000: begin
next_state<=3'b000;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b001;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b010;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b101;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b100: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b0;
data_out_return2<=1'b1;
end
endcase
3'b001: case (data_in)
3'b000: begin
next_state<=3'b001;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b010;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b011;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b110;
data_out<=1'b0; d
ata_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b010;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
endcase
3'b010: case (data_in)
3'b000: begin
next_state<=3'b010;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b011;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b100;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b111;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
endcase
3'b011: case (data_in)
3'b000: begin
next_state<=3'b011;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b100;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b101;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
endcase
3'b100: case (data_in)
3'b000: begin
next_state<=3'b000;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b101;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b110;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b1;
data_out_return2<=1'b0;
end
endcase
3'b101: case (data_in)
3'b000: begin
next_state<=3'b101;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b110;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b111;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b011: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b0;
data_out_return2<=1'b1;
end
endcase
3'b110: case (data_in)
3'b000: begin
next_state<=3'b110;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b111;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b010: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
endcase
3'b111: case (data_in)
3'b000: begin
next_state<=3'b111;
data_out<=1'b0;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
3'b001: begin
next_state<=3'b000;
data_out<=1'b1;
data_out_return1<=1'b0;
data_out_return2<=1'b0;
end
endcase
endcase
always@(posedge clk or rst_n)
if(!rst_n) current_state<=3'b000;
else current_state<=next_state;
endmodule
测试
结果
“11010”序列检测器
例4.4-3 “11010”序列检测器。 序列检测器就是将一个指定的序列从数字码流中检测出来。当输入端出现序列11010时,输出为1,否则输出为0。在此不考虑重复序列,即出现指定序列后就重新开始序列检测,不再考虑以前的数据。规定数据从右端输入,即按照1—1—0—1—0的顺序输入。该序列检测器的状态转移图如图4.4-5所示。
代码
Verilog HDL程序代码如下:
“11010”序列检测器
module seqdet (D_out,D_in,rst_n,clk);
parameter IDLE=3'd0,A=3'd1,B=3'd2,C=3'd3,D=3'd4,E=3'd5;
output D_out;
input D_in, rst_n,clk;
reg [2:0] state,next_state;
wire D_out;
assign D_out=(state= =E)?1:0;
always @(posedge clk or negedge rst_n)
if (!rst_n) state=IDLE;
else
case (state)
IDLE : if (D_in) next_state=A;
else next_state=IDLE;
A : if (D_in) next_state=B;
else next_state=IDLE;
B : if (D_in) next_state=B;
else next_state=C;
C : if (D_in) next_state=D;
else next_state=IDLE;
D : if (D_in) next_state=B;
else next_state=E;
E : if (D_in) next_state=IDLE;
else next_state=A;
default : next_state=IDLE;
endcase
always @(posedge clk)
state<=next_state;
endmodule
测试
module seqdet_tb;
parameter IDLE=3'd0,A=3'd1,B=3'd2,C=3'd3,D=3'd4,E=3'd5;
wire D_out;
reg D_in, rst_n,clk;
seqdet u1(D_out,D_in,rst_n,clk);
always #5 clk=~clk ;
initial begin
clk = 0;
rst_n=0;
D_in=0;
#10 rst_n=1;
#10 D_in=1;
#10 D_in=1;
#10 D_in=0;
#10 D_in=1;
#10 D_in=0;
#10 D_in=1;
#10 D_in=1;
#10 D_in=0;
#10 D_in=1;
#10 D_in=0;
#10 D_in=1;
#10 D_in=1;
#10 D_in=0;
#10 D_in=1;
#10 D_in=0;
end
endmodule
结果
最后
2022/11/28 23:50
这篇博客能写好的原因是:站在巨人的肩膀上
这篇博客要写好的目的是:做别人的肩膀
开源:为爱发电
学习:为我而行