Also include an active-high synchronous reset that resets the state machine to a state equivalent to if the water level had been low for a long time (no sensors asserted, and all four outputs asserted).
题目地址:Exams/ece241 2013 q4 - HDLBits
文章目录
一、不用状态机
我觉得不用状态机是比较简单的,只不过要多费点脑子,我是画状态图时想出来的。
module top_module (
input clk,
input reset,
input [3:1] s,
output reg fr3,
output reg fr2,
output reg fr1,
output reg dfr
);
always @(posedge clk) begin
if (reset == 1'b1)
{fr1, fr2, fr3} <= 3'b111;
else begin
fr1 <= (s == 3'b000) | (s == 3'b001) | (s == 3'b011);
fr2 <= (s == 3'b000) | (s == 3'b001);
fr3 <= (s == 3'b000);
end
end
reg [3:1] s_prev; // 记录之前的水位
always @(posedge clk) begin
if (reset == 1'b1)
s_prev <= 3'b000;
else
s_prev <= s;
end
// 水位越高,s越大
// 之前的水位比现在的水位高,则dfr打开
always @(posedge clk) begin
if (reset == 1'b1)
dfr <= 1'b1;
else
dfr <= (s_prev > s) ? 1'b1 :
(s_prev < s) ? 1'b0 : dfr;
end
endmodule
二、官方给的参考答案
module top_module (
input clk,
input reset,
input [3:1] s,
output reg fr3,
output reg fr2,
output reg fr1,
output reg dfr
);
// Give state names and assignments. I'm lazy, so I like to use decimal numbers.
// It doesn't really matter what assignment is used, as long as they're unique.
// We have 6 states here.
parameter A2=0, B1=1, B2=2, C1=3, C2=4, D1=5;
reg [2:0] state, next; // Make sure these are big enough to hold the state encodings.
// Edge-triggered always block (DFFs) for state flip-flops. Synchronous reset.
always @(posedge clk) begin
if (reset) state <= A2;
else state <= next;
end
// Combinational always block for state transition logic. Given the current state and inputs,
// what should be next state be?
// Combinational always block: Use blocking assignments.
always@(*) begin
case (state)
A2: next = s[1] ? B1 : A2;
B1: next = s[2] ? C1 : (s[1] ? B1 : A2);
B2: next = s[2] ? C1 : (s[1] ? B2 : A2);
C1: next = s[3] ? D1 : (s[2] ? C1 : B2);
C2: next = s[3] ? D1 : (s[2] ? C2 : B2);
D1: next = s[3] ? D1 : C2;
default: next = 'x;
endcase
end
// Combinational output logic. In this problem, a procedural block (combinational always block)
// is more convenient. Be careful not to create a latch.
always@(*) begin
case (state)
A2: {fr3, fr2, fr1, dfr} = 4'b1111;
B1: {fr3, fr2, fr1, dfr} = 4'b0110;
B2: {fr3, fr2, fr1, dfr} = 4'b0111;
C1: {fr3, fr2, fr1, dfr} = 4'b0010;
C2: {fr3, fr2, fr1, dfr} = 4'b0011;
D1: {fr3, fr2, fr1, dfr} = 4'b0000;
default: {fr3, fr2, fr1, dfr} = 'x;
endcase
end
endmodule
三、自己写的状态机
对比一下状态图可以发现,其实差不多,的确参考答案更精简一点。
module top_module (
input clk,
input reset,
input [3:1] s,
output reg fr3,
output reg fr2,
output reg fr1,
output reg dfr
);
parameter START = 3'd0, W1 = 3'd1, W2 = 3'd2, W3 = 3'd3, W4 = 3'd4, W5 = 3'd5, W6 = 3'd6, W7 = 3'd7;
reg [2:0] curr_state, next_state;
always @(posedge clk) begin
if (reset == 1'b1)
curr_state <= START;
else
curr_state <= next_state;
end
always @(*) begin
case (curr_state)
START: next_state = (s == 3'b000) ? W1 :
(s == 3'b001) ? W2 :
(s == 3'b011) ? W3 :
(s == 3'b111) ? W4 : START;
W1: next_state = (s == 3'b001) ? W2 : W1;
W2: next_state = (s == 3'b011) ? W3 :
(s == 3'b000) ? W5 : W2;
W3: next_state = (s == 3'b111) ? W4 :
(s == 3'b001) ? W6 : W3;
W4: next_state = (s == 3'b011) ? W7 : W4;
W5: next_state = (s == 3'b001) ? W2 : W5;
W6: next_state = (s == 3'b011) ? W3 :
(s == 3'b000) ? W5 : W6;
W7: next_state = (s == 3'b111) ? W4 :
(s == 3'b001) ? W6 : W7;
endcase
end
always @(*) begin
case (curr_state)
START: {fr3, fr2, fr1, dfr} = 4'b1111;
W1: {fr3, fr2, fr1, dfr} = 4'b1110;
W2: {fr3, fr2, fr1, dfr} = 4'b0110;
W3: {fr3, fr2, fr1, dfr} = 4'b0010;
W4: {fr3, fr2, fr1, dfr} = 4'b0000;
W5: {fr3, fr2, fr1, dfr} = 4'b1111;
W6: {fr3, fr2, fr1, dfr} = 4'b0111;
W7: {fr3, fr2, fr1, dfr} = 4'b0011;
endcase
end
endmodule
三种方法的比较 Vivado
不用状态机
elab电路图(综合的电路图可读性差)
综合出的资源占用情况
参考答案的状态机
自己写的状态机
结论:对比综合后的资源占用,好像都差不多的样子。LUT/FF的数量分别是 5/7, 6/6, 7/3
三种方法的比较 Quartus
不用状态机
参考答案的状态机
Quartus的RTL Viewer把状态机单独识别出来,很贴心了。
自己写的状态机
结论:Quartus综合结果和Vivado的差别蛮大的。我自己的状态机比较糟糕,不用状态机最好。