转载自:知乎
作者:ljgibbs
首先附上传送门:
https://hdlbits.01xz.net/wiki/Exams/2013\_q2bfsmhdlbits.01xz.net
Problem 150 Q2b Another FSM (Exams/2013 q2bfsm)
牛刀小试
想象你这会儿需要开发一个控制电机的状态机。FSM 有两个来自电机的输入信号 x 和 y,产生两个输出信号 f 和 g 控制电机,此外还有时钟信号 clk 以及低电平的复位信号 resetn。
开发电机的同事给了你状态机的需求,并告诉你今晚必须搞定(原文中并没有,由译者脑补^\_^)。状态机电路的工作原理如下:
- 在复位信号有效的情况下,FSM 处于初始状态。
- 在复位信号移除后,FSM 在下一个时钟沿输出 f = 1,持续一个时钟周期。
- 接下来的,FSM 监视输入信号 x,当 x 在连续 3 个时钟周期内输出 3'b101 时,在下一周期将信号 g 置 1。
- 在信号 g 置 1 期间,FSM 监视输入信号 y ,如果
- 在接下来 2 个周期内,输入信号 y 跳变为 1'b1,那么 FSM 保持信号 g = 1 (直到复位信号到来)
- 输入信号 y 在 2 个时钟周期内未跳变为 1'b1,那么 FSM 保持信号 g = 0 (直到复位信号到来)
解答与分析
作为一道状态机题目,我们首先分析需要设置哪些状态:
首先,设置初始状态 IDLE。对于复位信号移除后的事件和操作,设置状态 AFT\_RST,该周期中输出一个周期的高电平 f 信号,注意:此时还未触发任何其他功能。
接下来是对信号 x 的监控,需求可化简为序列检测电路,待检测的序列是 3'b101,设置相应的状态:STRT\_X\_MNT, X\_0, X\_1, X\_10, X\_101。
接下来是对信号 y 的监控,需求可化简为接下来 2 个周期中,y 是否均为低电平。同样可转换为一个检测 2'b00 的序列检测电路。为其设计一个中间状态 Y\_S0 ,表示第一周期 y 为低电平。
最后设计 2 个保持 g 输出的状态:G\_O0,G\_O1。
看起来不困难,根据需求,我们写完代码,跑完 tb,下班(希望如此)!
module top_module (
input clk,
input resetn, // active-low synchronous reset
input x,
input y,
output f,
output g
);
localparam FSM_W = 10;
localparam FSM_W1 = FSM_W - 1'b1;
reg [FSM_W1:0] state;
reg [FSM_W1:0] nxt_state;
localparam IDLE = 0;
localparam AFT_RST = 1;
localparam STRT_X_MNT= 2;
localparam X_1 = 3;
localparam X_0 = 4;
localparam X_10 = 5;
localparam X_101 = 6;
localparam Y_S0 = 7;
localparam G_O0 = 8;
localparam G_O1 = 9;
// State transition logic (combinational)
always @(*) begin
nxt_state[IDLE ] = 1'b0; // never reach for nxt_state
nxt_state[AFT_RST] = (state[IDLE ]);
nxt_state[STRT_X_MNT] = (state[AFT_RST]);
nxt_state[X_1 ] = (state[STRT_X_MNT] && x) || (state[X_1 ] && x) || (state[X_0 ] && x);
nxt_state[X_0 ] = (state[STRT_X_MNT] && ~x) || (state[X_10 ] && ~x) || (state[X_0 ] && ~x);
nxt_state[X_10 ] = (state[X_1 ] && ~x);
nxt_state[X_101 ] = (state[X_10 ] && x);
nxt_state[Y_S0 ] = (state[X_101 ] && ~y);
nxt_state[G_O0 ] = (state[Y_S0 ] && ~y) || state[G_O0 ];
nxt_state[G_O1 ] = (state[Y_S0 ] && y) || (state[X_101 ] && y) || state[G_O1 ];
end
// State flip-flops (sequential)
always @(posedge clk) begin
if(~resetn)
state <= 'b1; //IDLE
else begin
state <= nxt_state;
end
end
//output logic
assign f = state[AFT_RST];
assign g = (state[X_101] || state[G_O1] || state[Y_S0]) ? 1'b1 : 1'b0;
endmodule
提示:题目中说
then after the next clock edge the FSM has to set the output f to 1 for one clock cycle. Then, the FSM has to monitor the x input.
对于这里的 THEN ,我们可以理解为,在输出一个周期的高电平 f 信号后,在下个周期才开始监测 X 的值,输出高电平的周期不进行监控。
实不相瞒,笔者做此题时在 X 序列检测上也卡了一会,但当我在纸上画下状态转移图时,神奇的事情发生了:我一下子就发现了自己状态跳转中的错误。所以建议读者们画出状态转移图,即使是并不复杂。
到这里我们就完成了状态机的单元,撒花~
接下来 Building Larger Circuits 这一节中,我们将综合运用此前在计数器、状态机章节中掌握的技能,尝试构建一些规模稍大的数字电路。
Problem 151 Counter with period 1000
牛刀小试
本题需要我们构建一个周期为 1000 的计数器,从 0 计数至 999。设计一个同步复位信号 reset ,复位置起时,计数值清 0.
解答与分析
module top_module (
input clk,
input reset,
output reg [9:0] q);
always @(posedge clk ) begin
if(reset | q == 10'd999)
q <= 10'd0;
else begin
q <= q + 10'd1;
end
end
endmodule
Problem 152 4-bit shift register and down counter
牛刀小试
接下来的五道题目,每题构建一个小型的电路,最终组装成为一个复杂的计数器电路。
本题设计一个 4bit 位宽的移位寄存器,并具有计数器功能,可向下计数(即计数值递减)。
当移位使能 shift\_ena 信号有效时,数据 data 移入移位寄存器,向高位移动(most-significant-bit),即左移。
当计数使能 count\_ena 信号有效时,寄存器中现有的数值递减,向下计数。
由于系统不会同时使用移位以及计数功能,因此不需要考虑两者使能信号皆有效的情况。
解答与分析
module top_module (
input clk,
input shift_ena,
input count_ena,
input data,
output reg [3:0] q);
always @(posedge clk ) begin
if(shift_ena)
q <= {q[2:0],data};
else if(count_ena) begin
q <= q - 10'd1;
end
end
endmodule
Problem 153 FSM:1101 序列检测器
牛刀小试
本题实现复杂计数器的第二个组件,构建一个能从输入数据流中,识别 1101 序列的有限状态机电路。当检测到相应序列后,将信号 start\_shifting 置 1 ,保持该状态直到被复位为止。
最终状态机会进入一个不会跳转的状态(stuck),这是为了模拟后续状态机的其他状态。其他状态我们将在后面的几项练习中陆续构建,最终构成一个贼大的状态机。
解答与分析
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output start_shifting);
localparam FSM_W = 6;
localparam FSM_W1 = FSM_W - 1'b1;
reg [FSM_W1:0] state;
reg [FSM_W1:0] nxt_state;
localparam IDLE = 0;
localparam S_0 = 1;
localparam S_1 = 2;
localparam S_11 = 3;
localparam S_110 = 4;
localparam S_1101 = 5;
// State transition logic (combinational)
always @(*) begin
nxt_state[IDLE ] = 1'b0; // never reach for nxt_state
nxt_state[S_0 ] = (state[IDLE ] && ~data) || (state[S_1 ] && ~data) || (state[S_0 ] && ~data) || (state[S_110 ] && ~data);
nxt_state[S_1 ] = (state[IDLE ] && data) || (state[S_0 ] && data);
nxt_state[S_11 ] = (state[S_1 ] && data) || (state[S_11 ] && data);
nxt_state[S_110 ] = (state[S_11 ] && ~data);
nxt_state[S_1101 ] = (state[S_110 ] && data) || state[S_1101 ];
end
// State flip-flops (sequential)
always @(posedge clk) begin
if(reset)
state <= 'b1; //IDLE
else begin
state <= nxt_state;
end
end
//output logic
assign start_shifting = state[S_1101];
endmodule
检查一个序列检测状态机是否完备,一个简单的方法是观察所有状态,是否均包括输入分别为 0/1 的情况下的跳转,比如 state[IDLE ] && ~data 和 state[IDLE ] && data 是否均存在于状态跳转条件中。
Problem 154 FSM:Enable shift register
牛刀小试
本题实现复杂计数器的第三个组件,用于控制我们我们先前构建的移位寄存器模块。整个控制电路在检测到某个序列后,使能移位寄存器 4 个周期。前一题中我们已经完成了序列检测的部分,本题中的状态机则来提供 4 个周期的使能信号。
电路复位信号移除后,将 shift\_ena 信号置 1 ,持续 4 个周期后置 0,直至电路被复位。
解答与分析
module top_module (
input clk,
input reset, // Synchronous reset
output shift_ena);
localparam FSM_W = 3;
localparam FSM_W1 = FSM_W - 1'b1;
reg [FSM_W1:0] state;
reg [FSM_W1:0] nxt_state;
localparam IDLE = 0;
localparam S_1 = 1;
localparam S_0 = 2;
reg [1:0] asrt_cntr;
wire asrt_cntr_add;
wire asrt_cntr_clr;
//assert signal cntr
always @(posedge clk) begin
if(reset) begin
asrt_cntr <= 'b0;
end else if(asrt_cntr_add)begin
asrt_cntr <= asrt_cntr + 1'b1;
end else if(asrt_cntr_clr)begin
asrt_cntr <= 'b0;
end
end
assign asrt_cntr_add = state[S_1 ];
assign asrt_cntr_clr = 1'b0; // cntr clear itself
// State transition logic (combinational)
always @(*) begin
nxt_state[IDLE ] = 1'b0; // never reach for nxt_state
nxt_state[S_1 ] = state[IDLE ] || (state[S_1] && ~(asrt_cntr == 2'd3));
nxt_state[S_0 ] = (state[S_1] && asrt_cntr == 2'd3) || state[S_0 ];
end
// State flip-flops (sequential)
always @(posedge clk) begin
if(reset)
state <= 'b1; //IDLE
else begin
state <= nxt_state;
end
end
//output logic
assign shift_ena = nxt_state[S_1];
endmodule
注意:题目要求 reset 信号移除后,立即 输出使能信号,因此需要组合逻辑输出。
结语
久违的 HDLBits 中文导学专栏终于更新啦!在接下来一段时间,我们将尽快完成所有题目的解析文章,并将读者们留在评论区中的优秀解法添加到正文中!
推荐阅读
- HDLBits:在线学习 Verilog (三十 · Problem 145-149)
- HDLBits:在线学习 Verilog (二十九 · Problem 140-144)
- HDLBits:在线学习 Verilog (二十八 · Problem 135-139)
- HDLBits:在线学习 Verilog (二十七 · Problem 130-134)
- HDLBits: 在线学习Verilog(Problem 127-130)
关注此系列,请关注专栏FPGA的逻辑