参考博文:题解 | #根据状态转移表实现时序电路#_牛客博客 (nowcoder.net)
VL21 根据状态转移表实现时序电路
某同步时序电路转换表如下,请使用D触发器和必要的逻辑门实现此同步时序电路,用Verilog语言描述。其接口 input A ,input clk , input rst_n;output wire Y 。
根据该转换表和题目,可以发现不同的A值,对于受 控制的
、Y取值不同。但是
又不是输入信号,那么它是怎么变换的呢?我们发现表中存在
信号,转换表蕴含了
的时钟变化规律。结合题目要采用D触发器实现,代表一个always块只能控制一个信号变量。因此列出
的真值表。
由于逻辑表达式的化简结果不同,我们采用最小项表示(不需要进行化简,化简会出错):
q1 <= (~A & ~q1 & q0) | (~A & q1 & ~q0) | (A & ~q1 & ~q0) | (A & q1 & q0);
q0 <= (~A & ~q1 & ~q0) | (~A & q1 & ~q0) | (A & ~q1 & ~q0) | (A & q1 & ~q0);
上式的左侧q1、q0代表,而右侧为
。
对于输出Y,其值只受当前的控制,真值表有:
有逻辑表达式Y = q0 & q1;
采用D触发器实现,则有两个always块分别控制和
信号的变化,所有代码如下:
`timescale 1ns/1ns
module seq_circuit(
input A ,
input clk ,
input rst_n,
output wire Y
);
reg q0, q1;
always@(posedge clk or negedge rst_n) begin
if(~rst_n) begin
q1 <= 0;
end
else begin
// q1 <= A ^ q0 ^ q1;
q1 <= (~A & ~q1 & q0) | (~A & q1 & ~q0) | (A & ~q1 & ~q0) | (A & q1 & q0);
end
end
always@(posedge clk or negedge rst_n) begin
if(~rst_n) begin
q0 <= 0;
end
else begin
//q0 <= ~q0;
q0 <= (~A & ~q1 & ~q0) | (~A & q1 & ~q0) | (A & ~q1 & ~q0) | (A & q1 & ~q0);
end
end
assign Y = q0 & q1;
endmodule
这里记录一下自己出现的问题,刚开始自己是采用状态机去实现状态转换,但是回归题目说使用D触发器就懵逼了,也看不懂题目是什么意思。看了其他博客的答案后自己写
逻辑表达式时,对其进行了化简,出现编译无法通过的情况,是由于自己卡诺图画错了。还有自己综合了使用状态机实现状态转换跟D触发器实现状态转换的资源占用率,区别非常大。下面为截图记录。
![](https://i-blog.csdnimg.cn/blog_migrate/54adf92f4f8a884ed1cd8bfc7ba7c5f1.png)
正确状态机描述代码:
`timescale 1ns/1ns
module seq_circuit(
input A ,
input clk ,
input rst_n,
output wire Y
);
reg [1:0] curr_state;
reg [1:0] next_state;
// one step
always @ (posedge clk or negedge rst_n)
begin
if( ~rst_n ) begin
curr_state <= 2'b00;
next_state <= 2'b00;
end
else begin
curr_state <= next_state;
end
end
// two step
always @ (*)
begin
case(curr_state)
2'b00 : next_state = (A == 1'b1) ? 2'b11 : 2'b01;
2'b01 : next_state = (A == 1'b1) ? 2'b00 : 2'b10;
2'b10 : next_state = (A == 1'b1) ? 2'b01 : 2'b11;
2'b11 : next_state = (A == 1'b1) ? 2'b10 : 2'b00;
default : next_state = 2'b00;
endcase
end
assign Y = (curr_state == 2'b11) ? 1 : 0;
endmodule
状态机描述代码(没能够抓住Q1Q0的含义,Q1Q0表示current_state,表示next_state
,以为是随周期递增而已,自己的错误代码跟综合结果):
![](https://i-blog.csdnimg.cn/blog_migrate/08228fa96ef067e14ba3f827468122ed.png)
`timescale 1ns/1ns
module seq_circuit(
input A ,
input clk ,
input rst_n,
output wire Y
);
parameter S1A = 2'b01;
parameter S2A = 2'b10;
parameter S3A = 2'b11;
parameter S4A = 2'b00;
parameter S1B = 2'b11;
parameter S2B = 2'b00;
parameter S3B = 2'b01;
parameter S4B = 2'b10;
reg [1:0]current_state, next_state;
reg [1:0]Q;
reg y_temp;
assign Y = y_temp;
always@(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)
Q = 2'b00;
else
Q = Q + 1'b1;
end
always@(posedge clk or negedge rst_n)begin
if(A == 1'b0)begin
if(rst_n == 1'b0)
current_state <= S1A;
else
current_state <= next_state;
end
else begin
if(rst_n == 1'b0)
current_state <= S1B;
else
current_state <= next_state;
end
end
always@(*)begin
if(A == 1'b0)begin
if(rst_n == 1'b0)
next_state <= S1A;
else begin
case(current_state)
S1A:begin
if(Q == 2'b01)
next_state = S2A;
else
next_state = S1A;
end
S2A:begin
if(Q == 2'b10)
next_state = S3A;
else
next_state = S2A;
end
S3A:begin
if(Q == 2'b11)
next_state = S4A;
else
next_state = S3A;
end
S4A:begin
if(Q == 2'b00)
next_state = S1A;
else
next_state = S4A;
end
default:next_state = S1A;
endcase
end
end
else begin
if(rst_n == 1'b0)
next_state <= S1B;
else begin
case(current_state)
S1B:begin
if(Q == 2'b01)
next_state = S2B;
else
next_state = S1B;
end
S2B:begin
if(Q == 2'b10)
next_state = S3B;
else
next_state = S2B;
end
S3B:begin
if(Q == 2'b11)
next_state = S4B;
else
next_state = S3B;
end
S4B:begin
if(Q == 2'b00)
next_state = S1B;
else
next_state = S4B;
end
default:next_state = S1B;
endcase
end
end
end
always@(posedge clk or negedge rst_n)begin
if(A == 1'b0)begin
if(rst_n == 1'b0)
y_temp <= 1'b0;
else begin
case(next_state)
S4A: y_temp <= 1'b1;
default:y_temp <= 1'b0;
endcase
end
end
else begin
if(rst_n == 1'b0)
y_temp <= 1'b0;
else begin
case(next_state)
S4B: y_temp <= 1'b1;
default:y_temp <= 1'b0;
endcase
end
end
end
endmodule