本系列内容来自于知乎专栏,链接如下:https://zhuanlan.zhihu.com/c_1131528588117385216 本系列文章将和读者一起巡礼数字逻辑在线学习网站 HDLBits 的教程与习题,并附上解答和一些作者个人的理解,相信无论是想 7 分钟精通 Verilog,还是对 Verilog 和数电知识查漏补缺的同学,都能从中有所收获。
Problem 140 Serial two's complementer (Mealy FSM)
牛刀小试
本题和上一题 Serial two's complementer (Moore FSM) 一样,使用状态机实现一个二进制补码生成器,不同的是此题使用米里型状态机实现。
在本题与上一题中的米里型和摩尔型状态机最简单的区别在于:两者在输出时,摩尔型 FSM 有一个周期延迟。
米里型的输出由当前状态和输入信号的组合逻辑实现,输出信号与输入信号同步。
而摩尔型状态机的输出仅由当前状态决定,与输入信号异步,往往存在延迟。
图片来自下方链接文章,出处见水印
有关两种状态机的知识,大家可以移步下方的文章。
Power小强:FPGA菜鸟学习笔记——4、有限状态机zhuanlan.zhihu.com
书归正传,本题中给出了状态转移图,我们可以直接看图实现状态机。
存在两个状态,复位状态 A,在输入 x 为 1 后状态转移为 B,并保持在状态 B。
状态 A 中输出 z 与输入 x 相同;状态 B 中输出 z 与输入 x 相反。
简单的状态机,但这是如何实现二进制补码的呢?我们根据例子来看:
输入序列为:001101000,即原码,补码通过将原码取反加 1 实现。
取反: 110010111
加 1 110011000
将原码和补码放在一起观察:
001101 000
110011 000
可以发现前半部两者取反,而后半部分两者相同(均为0),两者的分界即是低位第一个 1 。所以有了上图中的状态转移图。
这里我们没有深究原理,只是从状态机的角度出发来实现该题目。(老实说一开始笔者也没想出来如何用状态机来实现这个电路 `_`)
解答与分析
module top_module (
input clk,
input areset, // Asynchronous active-low reset
input x,
output z );
reg [1:0] state;
reg [1:0] nxt_state;
localparam A = 0;
localparam B = 1;
// State transition logic (combinational)
always @(*) begin
case (state)
A:begin
if(x)
nxt_state = B;
else
nxt_state = A;
end
B:begin
nxt_state = B;
end
default: begin
nxt_state = A;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk or posedge areset) begin
if(areset)
state <= A;
else begin
state <= nxt_state;
end
end
//output logic
assign z = state == A ? x:~x ;
endmodule
使用独热码的方式实现了一个双状态状态机。输出 z 取决于状态以及输入信号 x,z = x 或者 z = ~x
Problem 141 Q3a:FSM
牛刀小试
接下来一系列题目是状态机的练习题,出处应该是原作者任教学校的考试题目,适合初学者巩固状态机的编码能力。对于一定基础的学习者来说适合进行一次快速通过 Fast Through.(也适合国内高校的相关课程学习一下)
本题需要实现一个双状态状态机,状态转移并不复杂,由输入变量 s 决定。
稍显复杂的是输出逻辑,由输入变量 w 决定。当处于状态 B 时,以三个时钟为一个周期,如果三个周期中有两个周期 w 为 1,则 z 输出一个周期高电平。
值得注意的是:需要三个周期中 exactly 两个周期为 1 。
解答与分析
module top_module (
input clk,
input reset, // Synchronous reset
input s,
input w,
output z
);
reg [3:0] state;
reg [3:0] nxt_state;
wire w_shft_ena;
reg[1:0] w_cntr;
localparam A = 0;
localparam B = 1;
localparam B1 = 2;
localparam B2 = 4;
// State transition logic (combinational)
always @(*) begin
case (state)
A:begin
if(s)
nxt_state = B;
else
nxt_state = A;
end
B:begin
nxt_state = B1;
end
B1:begin
nxt_state = B2;
end
B2:begin
nxt_state = B;
end
default: begin
nxt_state = A;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk ) begin
if(reset)
state <= A;
else begin
state <= nxt_state;
end
end
always @(posedge clk ) begin
if(reset)
w_cntr <= 2'b0;
else if(state == B)begin
w_cntr <= w;
end
else if(state == B1 || state == B2)begin
w_cntr <= w_cntr + w;
end
end
assign z = state == B && w_cntr == 2 ? 1'b1 : 1'b0;
endmodule
实现中值的注意的是,为了便于每三个时钟为一个单位检查输入 w 的值。笔者将状态 B 划分为 B1 B2 B3 三个子状态。使用计数器 w_cntr 在子状态中统计 w 为 1 的次数。
输出阶段为 B1 状态,当计数器值为 2 时输出 1,对应于 三个周期中 exactly 两个周期为 1
Problem 142 Q3b:FSM
牛刀小试
这是一道简单的根据状态转移实现状态机的题目,实现完整的三段式状态机
解答与分析
module top_module (
input clk,
input reset, // Asynchronous active-low reset
input x,
output z );
`define STT_W 3
`define STT_W1 `STT_W - 1
reg [`STT_W1:0] state;
reg [`STT_W1:0] nxt_state;
localparam IDLE = `STT_W'd0;
localparam s_1 = `STT_W'd1;
localparam s_10 = `STT_W'd2;
localparam s_11 = `STT_W'd3;
localparam s_100 = `STT_W'd4;
// State transition logic (combinational)
always @(*) begin
case (state)
IDLE:begin
if(x)
nxt_state = s_1;
else
nxt_state = IDLE;
end
s_1:begin
if(x)
nxt_state = s_100;
else
nxt_state = s_1;
end
s_10:begin
if(x)
nxt_state = s_1;
else
nxt_state = s_10;
end
s_11:begin
if(x)
nxt_state = s_10;
else
nxt_state = s_1;
end
s_100:begin
if(x)
nxt_state =s_100;
else
nxt_state = s_11;
end
default: begin
nxt_state = IDLE;
end
endcase
end
// State flip-flops (sequential)
always @(posedge clk ) begin
if(reset)
state <= IDLE;
else begin
state <= nxt_state;
end
end
assign z = state >= s_11;
endmodule
有没有巩固自己的状态机编码能力或者 Fast Through 呢?
Problem 143 Q3c:FSM logic
牛刀小试
本题和前一题的区别在于,本题的当前状态于端口输入,只需要实现三段式中的状态跳转逻辑以及输出逻辑,不需要实现状态触发器。
我看过了,状态转移同上一题相同
解答与分析
module top_module (
input clk,
input [2:0] y,
input x,
output Y0,
output z
);
`define STT_W 3
`define STT_W1 `STT_W - 1
wire [`STT_W1:0] state = y;
reg [`STT_W1:0] nxt_state;
localparam IDLE = `STT_W'd0;
localparam s_1 = `STT_W'd1;
localparam s_10 = `STT_W'd2;
localparam s_11 = `STT_W'd3;
localparam s_100 = `STT_W'd4;
// State transition logic (combinational)
always @(*) begin
case (state)
IDLE:begin
if(x)
nxt_state = s_1;
else
nxt_state = IDLE;
end
s_1:begin
if(x)
nxt_state = s_100;
else
nxt_state = s_1;
end
s_10:begin
if(x)
nxt_state = s_1;
else
nxt_state = s_10;
end
s_11:begin
if(x)
nxt_state = s_10;
else
nxt_state = s_1;
end
s_100:begin
if(x)
nxt_state =s_100;
else
nxt_state = s_11;
end
default: begin
nxt_state = IDLE;
end
endcase
end
assign Y0 = nxt_state[0];
assign z = state >= s_11;
endmodule
输入端口中的 y 输入当前状态,按照题目要求输出次状态最低位 Y0
Problem 144 Q6b:FSM next-state logic
牛刀小试
下图为状态机状态转移图。本题需要根据状态转移图以及输入的当前状态 y[3:1]实现状态跳转逻辑,输出次状态的一部分 Y2.
状态机中共有 6 个状态 A - F 分别用 000,001... 101 表示。使用二进制方式编码状态。
解答与分析
module top_module (
input [3:1] y,
input w,
output Y2);
`define STT_W 3
`define STT_W1 `STT_W - 1
wire [`STT_W1:0] state = y;
reg [`STT_W1:0] nxt_state;
localparam sA = `STT_W'd0;
localparam sB = `STT_W'd1;
localparam sC = `STT_W'd2;
localparam sD = `STT_W'd3;
localparam sE = `STT_W'd4;
localparam sF = `STT_W'd5;
// State transition logic (combinational)
always @(*) begin
case (state)
sA:begin
if(w)
nxt_state = sA;
else
nxt_state = sB;
end
sB:begin
if(w)
nxt_state = sD;
else
nxt_state = sC;
end
sC:begin
if(w)
nxt_state = sD;
else
nxt_state = sE;
end
sD:begin
if(w)
nxt_state = sA;
else
nxt_state = sF;
end
sE:begin
if(w)
nxt_state = sD;
else
nxt_state = sE;
end
sF:begin
if(w)
nxt_state = sD;
else
nxt_state = sC;
end
default: begin
nxt_state = sA;
end
endcase
end
assign Y2 = nxt_state[1];
endmodule
值得注意的是 Y2 输出的是对应 Y[2] 的次态,但 Y 在输入时取的是 Y[3:1] ,所以 Y2 取次态 nxt_state[1] 而不是 nxt_state[2]。