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-1 设计一个3个裁判的表决电路,当两个或两个以上裁判同意时,判决器输出“1”,否则输出“0”。
方法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:逻辑代数方式。 组合电路的另一种表达方法是逻辑代数方式,其主要思想是将真值表用卡诺图来表示,然后化简电路,得出逻辑函数表达式。图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:结构描述方式。结构描述方式是对电路最直接的表示,早期的数字电路设计通常采用的原理图设计实际上就是一种结构描述方式。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:抽象描述方式。除了以上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);initialbeginA=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-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) 利用连续赋值语句实现。
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) 利用行为描述方式实现。
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);initialbeginA=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.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);initialbegina=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-4 4位数值比较器。
用F[2:0]表示比较结果{FA>B,FA=B,FAB,CA=B,CA
代码
//例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
测试
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);initialbeginA=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;endendmodule
结果
例4.2-5 8选1数据选择器。
8选1数据选择器可以由多个2选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) 抽象描述方式。多路选择器的设计可以采用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); initialbegind_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-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
例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 begincasex (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 beginI=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;endendmodule
例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 begindata_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-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 begindata_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
同编码器一样,译码器的级联扩展也可使用同样的方法,其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);initialbeginE=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;endendmodule
例4.2-10 8 bit奇偶校验器。
在Verilog HDL中,可以采用结构描述方式也可以采用抽象描述方式。
书上有误
(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) 抽象描述方式:
//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 beginb=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
触发器是时序逻辑电路的最基本电路单元,主要有D触发器、JK触发器、T触发器和RS触发器等。根据功能要求的不同,触发器还具有置位、复位、使能、选择等功能。
例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;initialbeginclk=0;data_in=0; #20 data_in=1;#20 data_in=0;#20 data_in=1;#15 data_in=0;#15 data_in=1;endendmodule
例4.3-3 带复位端的D触发器。
//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
//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;initialbeginclk=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;endendmodule
例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;initialbeginclk=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;endendmodule
例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;initialbeginclk=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;endendmodule
例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;initialbeginclk=0;reset=0;#10reset=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;initialbeginclk=0;reset=1;#10reset=0;#130 reset=1;#20 reset=0;endendmodule
移位寄存器可以用来实现数据的串并转换,也可以构成移位行计数器,进行计数、分频,还可以构成序列码发生器、序列码检测器等,它也是数字系统中应用非常广泛的时序逻辑部件之一。
例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;initialbeginclk=0;reset=1;#100 reset=0;#20 reset=1;endendmodule
具有置位功能的环形寄存器
//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;initialbeginclk=0;set=0;Q=4'b0000;#10set=1;Q=4'b1100;#10set=0;#100 set=1;Q=4'b0011;#10set=0;endendmodule
序列信号是数字电路系统中常用的功能单元,其种类很多,如按照序列循环长度M与触发器数目n的关系,一般可分为三种:
(1) 最大循环长度序列码,M = 2n。
(2) 最长线性序列码(M序列码),M = 2n -1。
(3) 任意循环长度序列码,M<2n。
序列信号发生器是能够产生一组或多组序列信号的时序电路,它可以由纯时序电路构成,也可以由包含时序逻辑和组合逻辑的混合电路构成。
例4.3-9 用Verilog HDL设计一个产生100111序列的信号发生器。
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:由移位寄存器和组合逻辑电路构成。
反馈移位寄存器型序列信号发生器的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:由计数器构成。
由真值表可画出输出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;initialbeginclk=0;load=0;#10load=1;D=6'b100111;#10load=0;#200 load=1;D=6'b100111;#10load=0;endendmodule
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;initialbeginclk=0;load=0;#10load=1;D=6'b100111;#10load=0;#100 load=1;D=6'b100111;#10load=0;endendmodule
module signal_maker3_tb; parameter M=3; wire out; reg clk,reset;signal_maker3 u3(out,clk,reset); always #5 clk = ~clk;initialbeginclk=0;reset=0;#10reset=1;#100 reset=0;#10reset=1;endendmodule
例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;initialbeginclk=0;load_n=0;D_load=4'b0000;#10load_n=1;#100 load_n=0;D_load=4'b0000;#10load_n=1;endendmodule
有限状态机可以分为同步和异步两种,在本书中我们只讨论有限同步状态机,后文中提到的有限状态机均指有限同步状态机。有限状态机是时序电路的通用模型,任何时序电路都可以表示为有限状态机。在由时序电路表示的有限状态机中,各个状态之间的转移总是在时钟的触发下进行的,状态信息存储在寄存器中。因为状态的个数是有限的,所以称为有限状态机。
图4.4-1 有限状态机的电路结构
图4.4-2 有限状态机的结构
状态机的编码方式很多,由此产生的电路也不相同。
常见的编码方式有三种:二进制编码、格雷编码和一位独热编码。
在Verilog HDL中,有限状态机的描述方法较多,常用的有两段式和三段式两种。
//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)beginif(clr==1)present_state<=s0;else present_state<=next_state ;endalways @(*)begincase (present_state)s0: if(din==1) begin next_state=sl; dout=0; endelse begin next_state=s0; dout=0; endsl: if(din==1) begin next_state=s2; dout=0; endelse begin next_state=s0; dout=0; ends2: if(din==1) begin next_state=s3; dout=1; endelse begin next_state=s0; dout=0; ends3: if(din==1) begin next_state=s3; dout=1; endelse begin next_state=s0; dout=0; enddefault: next_state=s0;endcaseend
endmodule
//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)beginif(clr==1)present_state<=s0;else present_state<=next_state ;endalways @(*)begincase (present_state)s0: if(din==1) begin next_state=sl; endelse begin next_state=s0; endsl: if(din==1) begin next_state=s2; endelse begin next_state=s0; ends2: if(din==1) begin next_state=s3; endelse begin next_state=s0; ends3: if(din==1) begin next_state=s3; endelse begin next_state=s0; enddefault: next_state=s0;endcaseendalways @(*)beginif (present_state==s3) begin dout=1; endelse begin dout=0; end end
endmodule
//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)beginif(clr==1)present_state<=s0;else present_state<=next_state ;endalways @(*)begincase (present_state)s0: if(din==1) begin next_state=sl; dout=0; endelse begin next_state=s0; dout=0; endsl: if(din==1) begin next_state=s2; dout=0; endelse begin next_state=s0; dout=0; ends2: if(din==1) begin next_state=s2; dout=1; endelse begin next_state=s0; dout=0; enddefault: next_state=s0;endcaseend
endmodule
//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)beginif(clr==1)present_state<=s0;else present_state<=next_state ;endalways @(*)begincase (present_state)s0: if(din==1) begin next_state=sl; endelse begin next_state=s0; endsl: if(din==1) begin next_state=s2; endelse begin next_state=s0; ends2: if(din==1) begin next_state=s2; endelse begin next_state=s0; enddefault: next_state=s0;endcaseendalways @(*)begincase (present_state)s0: if(din==1) begin dout=0; endelse begin dout=0; endsl: if(din==1) begin dout=0; endelse begin dout=0; ends2: if(din==1) begin dout=1; endelse begin dout=0; enddefault: dout=0;endcaseendendmodule
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 beginclk = 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 //添加beginSTATE=2'b00;endalways @(STATE) case (STATE)2'b00: begin OUT<=4'b1000; next_STATE<=2'b01; end 2'b01: begin OUT<=4'b0100; next_STATE<=2'b10; end2'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;initialbeginclk=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: beginnext_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 endcase3'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; end3'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 endcase3'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: beginnext_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; endendcase 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: beginnext_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; end3'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; end3'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: beginnext_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; end3'b010: begin next_state<=3'b011; data_out<=1'b0;data_out_return1<=1'b0; data_out_return2<=1'b0; end3'b011: 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'b010; data_out<=1'b0; data_out_return1<=1'b0; data_out_return2<=1'b0; end endcase3'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; end3'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 endcase3'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: beginnext_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; endendcase 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: beginnext_state<=3'b101;data_out<=1'b0;data_out_return1<=1'b0;data_out_return2<=1'b0;end3'b010: beginnext_state<=3'b110;data_out<=1'b0;data_out_return1<=1'b0;data_out_return2<=1'b0;end3'b011: beginnext_state<=3'b000;data_out<=1'b1;data_out_return1<=1'b1;data_out_return2<=1'b0;endendcase3'b101: case (data_in)3'b000: beginnext_state<=3'b101;data_out<=1'b0;data_out_return1<=1'b0;data_out_return2<=1'b0;end3'b001: beginnext_state<=3'b110;data_out<=1'b0;data_out_return1<=1'b0;data_out_return2<=1'b0;end3'b010: beginnext_state<=3'b111;data_out<=1'b0;data_out_return1<=1'b0;data_out_return2<=1'b0;end3'b011: beginnext_state<=3'b000;data_out<=1'b1;data_out_return1<=1'b0;data_out_return2<=1'b1;endendcase3'b110: case (data_in)3'b000: beginnext_state<=3'b110;data_out<=1'b0;data_out_return1<=1'b0;data_out_return2<=1'b0;end3'b001: beginnext_state<=3'b111;data_out<=1'b0;data_out_return1<=1'b0;data_out_return2<=1'b0;end3'b010: beginnext_state<=3'b000;data_out<=1'b1;data_out_return1<=1'b0;data_out_return2<=1'b0;endendcase3'b111: case (data_in)3'b000: beginnext_state<=3'b111;data_out<=1'b0;data_out_return1<=1'b0;data_out_return2<=1'b0;end3'b001: beginnext_state<=3'b000;data_out<=1'b1;data_out_return1<=1'b0;data_out_return2<=1'b0;endendcaseendcasealways@(posedge clk or rst_n)if(!rst_n) current_state<=3'b000;else current_state<=next_state;
endmodule
例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 beginclk = 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
这篇博客能写好的原因是:站在巨人的肩膀上
这篇博客要写好的目的是:做别人的肩膀
开源:为爱发电
学习:为我而行