序列发生器
描述
编写一个模块,实现循环输出序列001011。
模块的接口信号图如下:
要求使用Verilog HDL实现,并编写testbench验证模块的功能。
输入描述:
clk:时钟信号
rst_n:复位信号,低电平有效
输出描述:
data:输出数据
解题思路
序列信号发生器设计步骤如下:
①确定寄存器的个数n;
由于M(序列信号的长度)= 6,所以n≥3;接下来
②确定寄存器的六个独立状态;
将序列码001011按照移位规律每三位一组,可划分为六个状态**:001、010、101、011、110、100**;
③列态序表和反馈激励函数表;
态序表
|-----------------------------------------------|-----------------------------------------------------------|
| | |
| 001 | 010 |
| 010 | 101 |
| 101 | 011 |
| 011 | 110 |
| 110 | 100 |
| 100 | 001 |
| 000 | 001 |
| 111 | 110 |
反馈激励函数表
|-----------------------------------|-----------------------------------|-----------------------------------|---------------------------------|
| | | | |
| 0 | 0 | 1 | 0 |
| 0 | 1 | 0 | 1 |
| 1 | 0 | 1 | 1 |
| 0 | 1 | 1 | 0 |
| 1 | 1 | 0 | 0 |
| 1 | 0 | 0 | 1 |
将态序表的每下一状态 所需要的移位(左移)输入作为该状态对应的反馈函数输出;
即:
根据反馈激励函数表,画卡诺图;
当设计最终的序列输出时,我们发现最后的输出序列为状态Q0的值(因为每次从Q0端移出数据) ;因此
④列出三大方程
状态方程 :
特征方程 :(注意:该题的Q0Q1Q2有初始值,若不设置初始值(如错误代码所示),结果错误)
输出方程 :
因此,我们给出了以下两种代码方式;
代码一:例化触发器
cpp
`timescale 1ns/1ns
//输出序列:"001011"
module sequence_generator(
input clk,
input rst_n,
output reg data
);
wire d0, d1, d2;
wire q0, q1, q2;
assign d0 = q1;
assign d1 = q2;
assign d2 = ~q0&~q2 | q0&~q1;
DFF D0(.d({d2,d1,d0}), .clk(clk), .rst_n(rst_n), .q({q2,q1,q0}));
always @(posedge clk or negedge rst_n) begin
if (!rst_n) data <= 1'b0;
else data <= q0;
end
endmodule
//例化D触发器
module DFF (
input [2:0] d,
input clk,
input rst_n,
output reg [2:0] q
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) q[2:0] = 3'b100;
else q[2:0] = d[2:0];
end
endmodule
代码二: 不例化触发器
cpp
`timescale 1ns/1ns
//输出序列:"001011"
module sequence_generator(
input clk,
input rst_n,
output reg data
);
reg q0, q1, q2;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
q0 <= 1'b0;
q1 <= 1'b0;
q2 <= 1'b1;
end
else begin
q0 <= q1;
q1 <= q2;
q2 <= ~q0&~q2 | q0&~q1;
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) data <= 1'b0;
else data <= q0;
end
endmodule
错误代码:(即未考虑Q0、Q1、Q2的初始值)
将Q0、Q1、Q2均使用带复位端的D触发器例化;
cpp
`timescale 1ns/1ns
//输出序列:"001011"
module sequence_generator(
input clk,
input rst_n,
output reg data
);
wire F;
wire d0, d1, d2;
wire q0, q1, q2;
assign d0 = q1;
assign d1 = q2;
assign d2 = ~q0&q1&~q2 | q0&~q1;
DFF D0(.d(d0), .clk(clk), .rst_n(rst_n), .q(q0));
DFF D1(.d(d1), .clk(clk), .rst_n(rst_n), .q(q1));
DFF D2(.d(d2), .clk(clk), .rst_n(rst_n), .q(q2));
always @(posedge clk or negedge rst_n) begin
if (!rst_n) data <= 1'b0;
else data <= q0;
end
endmodule
//例化D触发器
module DFF (
input d,
input clk,
input rst_n,
output reg q
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) q = 1'b0;
else q = d;
end
endmodule
我们再给出一种解法,使用有限状态机;
解法二:有限状态机
注意:此处将IDLE注释掉,结果仍然正确。
cpp
`timescale 1ns/1ns
//输出序列:"001011"
module sequence_generator(
input clk,
input rst_n,
output reg data
);
//代码三
reg [2:0] current_state, next_state;
parameter IDLE = 3'b000;
parameter S1 = 3'b001;
parameter S2 = 3'b010;
parameter S3 = 3'b101;
parameter S4 = 3'b011;
parameter S5 = 3'b110;
parameter S6 = 3'b100;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) current_state <= IDLE;
else current_state <= next_state;
end
always @(*) begin
case (current_state)
IDLE:begin next_state = S1; data <= 1'b0; end
S1: begin next_state = S2; data <= 1'b0; end
S2: begin next_state = S3; data <= 1'b0; end
S3: begin next_state = S4; data <= 1'b1; end
S4: begin next_state = S5; data <= 1'b0; end
S5: begin next_state = S6; data <= 1'b1; end
S6: begin next_state = S1; data <= 1'b1; end
default: begin next_state = S1; data <= 1'b0; end
endcase
end
endmodule