前言:本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载
示例:序列发生器与序列检测器
目录
Ⅰ. 前置知识
0x00 序列检测器
0x01 序列发生器
Ⅱ. 示例讲解
0x00 序列发生器
0x01 序列检测器
Ⅲ. Verilog实现
0x00 序列检测器
0x01 序列发生器
序列检测器在数据通讯,雷达和遥测等领域中用于检测同步识别标志。
它是一种用来检测一组或多组序列信号的电路。例如检测器收到一组指定的串行码后,输出标志1,否则,输出0。检测器每收到一个符合要求的串行码就需要用一个状态进行记忆。
若要检测的串行码长度为N位,则需要N个状态;另外,还需要增加一个“未收到一个有效位”的初始状态,共N+1个状态;
序列发生器用于产生一个指定序列串,与序列检测器类似,每产生一个符合要求的串行码就需要用一个状态进行记忆。
若要产生的串行码长度为N位,则需要N个状态;另外,还需要增加一个“未产生一个有效位”的初始状态,共N+1个状态
❗注:
进行序列发生器或者序列检测器的设计,首先按要求画出状态转换图(表),然后按照实现方案采用经典设计方法或者Verilog语言完成设计。
设计一个序列发生器,输出序列为110100
a、设计实现方法;
b、基于Verilog语言完成设计;
c、利用VIVADO验证并给出testbench结果(波形图)。
参考方法一:计数器加组合输出网络类型
计数型序列信号发生器的结构框图如图示:
它由计数器和组合输出网络两部分组成,序列信号从组合输出网络输出。
这种类型的序列信号发生器一般分两步来设计,首先根据序列的长度M设计模M计数器,计数器的状态可以自定;然后按计数器的状态转移关系和序列码的要求设计组合输出网络。
由于计数器的状态设置和输出网络没有直接的关系,因此这种结构对于输出序列的更改比较方便,而且还能同时产生多组序列码。
下面描述的为计数器加组合输出网络构成的序列信号发生器,产生001011序列信号,通过内部的3位计数器进行计数,由计数状态和输出序列的对应关系,得到其输出组合逻辑真值表,从表中可以看到,Q2Q1Q0从000开始计数并不断加1,每个状态对应一个输出Z。通过真值表可以得到卡诺图,
Q2 |
Q1 |
Q0 |
Z |
0 |
0 |
0 |
0 |
0 |
0 |
1 |
0 |
0 |
1 |
0 |
1 |
0 |
1 |
1 |
0 |
1 |
0 |
0 |
1 |
1 |
0 |
1 |
1 |
参考代码如下:
module sequence_signal_counter(input clk, input rst_n, output outD);
//实现001011序列信号产生
reg [2:0] counter;
always @(posedge clk) begin
if(rst_n == 1'b0) counter <= 3'b000;
else if(counter == 3'b101) counter <= 3'b000;
else counter <= counter + 1'b1;
end
assign outD = ((~counter[0]) & counter[1]) | counter[2];
endmodule
参考方法二:寄存器方式实现的序列信号产生器。
利用6位移位寄存器方式实现序列信号产生器,在输入端din输入任意序列,通过移位寄存器,使得输入信号的最高位移入最低位,其他各位依次向左移一位,在每个时钟上升沿到来时,将输入信号的最高位通过dout输出,从而循环产生序列信号。
module sequence_signal_shifter(input clk, input rst, input [5:0] din, output outD);
reg dout;
reg [5:0] temp;
assign outD=dout;
always@(posedge clk)
begin
if(rst == 1'b0)
temp <= din;
else
begin
dout <= temp[5];
temp <= {temp[4:0], temp[5]};
end
end
endmodule
参考方法三:利用有限状态机构造序列信号产生器。关于状态图和状态机的构造可以参考下面序列检测器的内容。
module sequence_signal_FSM(input clk, input rst_n, output outD);
//有限状态机方式实现010011序列信号产生器
reg dout;
reg [2:0] pre_state, next_state;
parameter s0 = 3'b000, s1 = 3'b001, s2 = 3'b010,
s3 = 3'b011, s4 = 3'b100, s5 = 3'b101;
assign outD=dout;
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 0) pre_state <= s0; //让初始为输出0的状态,观察与设为s5的区别
else pre_state <= next_state;
end
always @(pre_state)
begin
case(pre_state)
s0:
begin
dout = 1'b0;
next_state <= s1;
end
s1:
begin
dout = 1'b1;
next_state = s2;
end
s2:
begin
dout = 1'b0;
next_state = s3;
end
s3:
begin
dout = 1'b0;
next_state = s4;
end
s4:
begin
dout = 1'b1;
next_state = s5;
end
s5:
begin
dout = 1'b1;
next_state = s0;
end
default: next_state = s0;
endcase
end
endmodule
设计一个序列检测器,检测序列为11010
a、画出状态转换图;
b、基于Verilog语言完成设计,结合序列发生器,编写顶层文件,在vivado中验证并给出整体test bench结果(波形图)
下面讨论状态机的设计方法:
在“11010”序列检测器中,有6个状态,如果加上一个Idle状态,共7个状态,最初的状态分析如下表:
input NS/out PS |
0 |
1 |
IDLE |
0/0 |
1/0 |
0 |
0/0 |
1/0 |
1 |
0/0 |
11/0 |
11 |
110/0 |
11/0 |
110 |
0/0 |
1101/0 |
1101 |
11010/1 |
11/0 |
11010 |
0/0 |
1/0 |
Present State |
Next State/Output |
对应状态图如图:
首先考虑是否可以通过状态化简,简化电路结构,减少Verilog代码量。
可以看到状态“Idle”、状态“0”和“11010”在相同的输入下,它们的次态、输出都完全相同,故此三个状态可以化简为一个状态。化简结果如下表和下图。
input NS/out PS |
0 |
1 |
0 |
0/0 |
1/0 |
1 |
0/0 |
11/0 |
11 |
110/0 |
11/0 |
110 |
0/0 |
1101/0 |
1101 |
0/1 |
11/0 |
Present State |
Next State/Output |
接下来对化简后的状态进行命名、编码。本例将“0”,“1”,“11”,“110”,“1101”状态分别命名为“S0”,“S1”,“S11”,“S110”,“S1101”。
Verilog参考程序如下:
module sequence_detector(input seq, input clk, input rst,output Z); // detector "11010"
reg b;
reg [4:0]state;
assign Z=b;
parameter S0 = 5'b1_0000,
S1 = 5'b0_1000,
S11 = 5'b0_0100,
S110 = 5'b0_0010,
S1101 = 5'b0_0001;
//状态的记录利用one-hot编码
always @(posedge clk or negedge rst) //low active
if (!rst) begin
state <= S0;
b <= 0;
end
else
case(state)
S0: if( seq == 0)
begin
state <= S0;
b <= 0;
end
else
begin
state <= S1;
b <= 0;
end
S1: if( seq == 0)
begin
state <= S0;
b <= 0;
end
else
begin
state <= S11;
b <= 0;
end
S11: if( seq == 0)
begin
state <= S110;
b <= 0;
end
else
begin
state <= S11;
b <= 0;
end
S110: if( seq == 0)
begin
state <= S0;
b <= 0;
end
else
begin
state <= S1101;
b <= 0;
end
S1101: if( seq == 0)
begin
state <= S0;
b <= 1;
end
else
begin
state <= S11;
b <= 0;
end
default state <= 5'bx;
endcase
endmodule
设计代码:
module t_11010(reset,clk,x,z);
input reset,clk,x;
output z;
parameter y0=3'b000,y1=3'b001,y2=3'b010,y3=3'b011,y4=3'b100,y5=3'b101;
reg z;
reg [3:1] now,next;
always@(posedge clk)
if(!reset)now<=y0;
else now<=next;
always@(x or now)
case(now)
y0:if(x) next=y1;
else next=y0;
y1:if(x) next=y2;
else next=y0;
y2:if(!x)next=y3;
else next=y2;
y3:if(x) next=y4;
else next=y0;
y4:if(!x) next=y0;
else next=y2;
default:next=y0;
endcase
always @(posedge clk)
if(!reset)z<=0;
else if((now==y0)&&(x==0))z<=1;
else z<=0;
endmodule
仿真代码:
module sim_pj1();
reg reset,clk,x;
wire z;
reg[10:0]test;
t_11010 uu1(reset,clk,x,z);
initial begin
clk=0;
reset=0;
test=11'd0;
#100 reset=1;
test=11'b0001_1010_000;
end
always #20 clk=~clk;
always #40
begin
x=test[10];
test={test[9:0],test[10]};
end
endmodule
仿真波形:
设计代码:
module sequence_signal_FSM(input clk, input rst_n, output outD);
//有限状态机方式实现010011序列信号产生器
reg dout;
reg [2:0] pre_state, next_state;
parameter s0 = 3'b000, s1 = 3'b001, s2 = 3'b010,
s3 = 3'b011, s4 = 3'b100, s5 = 3'b101;
assign outD=dout;
always @(posedge clk or negedge rst_n)
begin
if(rst_n == 0) pre_state <= s0; //让初始为输出0的状态,观察与设为s5的区别
else pre_state <= next_state;
end
always @(pre_state)
begin
case(pre_state)
s0:
begin
dout = 1'b0;
next_state <= s1;
end
s1:
begin
dout = 1'b1;
next_state = s2;
end
s2:
begin
dout = 1'b0;
next_state = s3;
end
s3:
begin
dout = 1'b0;
next_state = s4;
end
s4:
begin
dout = 1'b1;
next_state = s5;
end
s5:
begin
dout = 1'b1;
next_state = s0;
end
default: next_state = s0;
endcase
end
endmodule
仿真代码:
module sim_sequence_signal_FSM();
reg clk;
reg rst_n;
wire outD;
sequence_signal_FSM uu1(clk,rst_n,outD);
initial begin
clk=0;rst_n=1;
#30;
rst_n=0;#10;
rst_n=1;
end
always #10 clk=~clk;
endmodule
仿真波形图: