1 设计一个Mealy型的有限状态机
实现一个 mealy 类型的有限状态机,它可以识别输入信号 x 上的序列“101”。当检测到“101”序列时,FSM 应该有一个输出信号 z,这个信号被断言为逻辑 -1。您的 FSM 还应该有一个活动-低异步复位。在状态机中可能只有3个状态。你的 FSM 应该识别重叠序列。
solution:
module top_module (
input clk,
input aresetn, // Asynchronous active-low reset
input x,
output z );
parameter s0=0,s1=1,s2=2;
reg [1:0] state,next;
always @(*) begin
case(state)
s0 : next = x ? s1 : s0;
s1 : next = x ? s1 : s2;
s2 : next = x ? s1 : s0;
endcase
end
always @(posedge clk or negedge aresetn) begin
if (~aresetn)
state <= s0;
else
state <= next;
end
assign z = (state==s2 & x==1);
endmodule
2 Serial 2’s complementer
2.1 Serial 2’s complementer(Moore)
你将要设计一个单输入单输出串行的2进制补码器Moore型状态机。 输入(x)是一系列数字(每个时钟周期一个),从数字的最低有效位开始,而输出(Z)是输入的2进制补码。 状态机将接受任意长度的输入数字。该电路需要异步复位。 转换在reset低电平时开始,并在reset高电平时停止。
根据下一题的提示,可以知道本题输入是默认负数的,除了第一次的出现的1以外,其余每一位都相应取反,因为第一次出现的1是最高位,即符号位。
状态转换图来自这篇文章
三个状态分别表示的是:
- A表示的是等待直到出现第一个1(未出现则一致在状态A),然后跳转至状态B;
- B表示的是输出output是1的情况,由A跳转来之后,下一个输入是0则输出相应取反,output则为1;若下一个输入是1则跳转至状态C;
- C表示的是输出output是0的情况,造成这一情况的原因有两种,一个是B跳转,一个是C状态时的输入是1。若C状态时的输入是0则输出取反,跳转至状态B。
solution;
module top_module (
input clk,
input areset,
input x,
output z
);
parameter A=0,B=1,C=2;
reg [1:0] state,next;
always @(*) begin
case(state)
A: next = x ? B : A;
B: next = x ? C : B;
C: next = x ? C : B;
endcase
end
always @(posedge clk or posedge areset) begin
if(areset)
state <= A;
else
state <= next;
end
assign z = (state==B);
endmodule
2.2 Serial two’s complementer(Mealy FSM)
下图是2进制补码器在Mealy型状态机上的实现。 使用独热码编码实现。
状态转换图:
波形图:
solution:
module top_module (
input clk,
input areset,
input x,
output z
);
parameter A=0,B=1;
reg state,next;
always @(*) begin
case(state)
A: next = x ? B : A;
B: next = B;
endcase
end
always @(posedge clk or posedge areset) begin
if(areset)
state <= A;
else
state <= next;
end
assign z = (state==A) ? x : ~x;
endmodule
3 FSM(Q3)
3.1 FSM(Q3a)
考虑一个输入为s和w的有限状态机。 假定FSM以复位状态A开始,如下所示。
只要s = 0,FSM就会保持状态A,而当s = 1时,FSM会进入状态B。
一旦进入状态B,FSM就会在接下来的三个时钟周期中检查输入w的值。 如果恰好在这些时钟周期中的两个时钟周期中w = 1,则FSM必须在下一个时钟周期中将输出z设置为1。 否则z必须为0。FSM在接下来的三个时钟周期中继续检查w,依此类推。 下面的时序图说明了不同w值所需的z值。
使用尽可能少的状态。
请注意,s输入仅在状态A中使用,因此只需要考虑w输入。
面对需要检测重复周期的脉冲信号时,不妨采用状态机+计数器的方法。这里还需要移位寄存器来存储待检测的信号,但是这里移位寄存器似乎只能这样写(即先描述两个寄存器变量w_reg1和w_reg2,用来存储之前状态的值,w_reg1存储前一状态的值,w_reg2存储w_reg2的值),否则出错。
solution:
module top_module(
input clk,
input reset, // Synchronous reset
input s,
input w,
output z
);
parameter s0=0,s1=1;
reg state,next;
reg [2:0] data;
always @(*) begin
case (state)
s0: next <= s ? s1 : s0;
s1: next <= s1;
endcase
end
reg w_reg1;
reg w_reg2;
always@(posedge clk)begin
if(reset)begin
w_reg1 <= 1'b0;
w_reg2 <= 1'b0;
state <= s0;
end
else if(next == s1)begin
w_reg1 <= w;
w_reg2 <= w_reg1;
state <= next;
end
else begin
w_reg1 <= 1'b0;
w_reg2 <= 1'b0;
state <= next;
end
end
reg [1:0] cnt;
always @(posedge clk) begin
if(reset) begin
cnt <= 0;
end
else if(state==s1) begin
if (cnt == 2'd2)
cnt <= 0;
else
cnt <= cnt + 2'b1;
end
end
always @(posedge clk) begin
if(reset) begin
z <= 0;
end
else if(state==s1 & cnt == 2'd2) begin
if(~w & w_reg1 & w_reg2 | w & ~w_reg1 & w_reg2 | w & w_reg1 & ~w_reg2)
z <= 1;
else
z <= 0;
end
else
z <= 0; //这里不能漏掉
end
endmodule
3.2 FSM(Q3b)
给定如下所示的状态分配表,实现该有限状态机。 重置应将FSM重置为000状态。
module top_module (
input clk,
input reset, // Synchronous reset
input x,
output z
);
parameter s0=0,s1=1,s2=2,s3=3,s4=4;
reg [2:0] state,next;
always @(*) begin
case (state)
s0 : next = x==0 ? s0 : s1;
s1 : next = x==0 ? s1 : s4;
s2 : next = x==0 ? s2 : s1;
s3 : next = x==0 ? s1 : s2;
s4 : next = x==0 ? s3 : s4;
endcase
end
always @(posedge clk) begin
if(reset)
state <= s0;
else
state <= next;
end
assign z = (state==s3)|(state==s4);
endmodule
3.3 FSM(Q3c)
给定如下所示的状态分配表,请实现逻辑功能Y[0]和z。
module top_module (
input clk,
input [2:0] y,
input x,
output Y0,
output z
);
parameter s0=3'd0,s1=3'd1,s2=3'd2,s3=3'd3,s4=3'd4;
always @(*) begin
case ({x,y})
{1'b0,s0} : Y0 = s0[0];
{1'b1,s0} : Y0 = s1[0];
{1'b0,s1} : Y0 = s1[0];
{1'b1,s1} : Y0 = s4[0];
{1'b0,s2} : Y0 = s2[0];
{1'b1,s2} : Y0 = s1[0];
{1'b0,s3} : Y0 = s1[0];
{1'b1,s3} : Y0 = s2[0];
{1'b0,s4} : Y0 = s3[0];
{1'b1,s4} : Y0 = s4[0];
endcase
end
assign z = (y==s3)|(y==s4);
endmodule
4 FSM(Q6)
4.1 FSM next-state logic(Q6b)
考虑下面显示的状态机,它有一个输入w和一个输出z。
假设你希望使用三个触发器和状态码y [3:1] = 000、001,…,101分别用于状态A,B,…,F来实现FSM。 显示此FSM的状态分配表。 推导触发器y[2]的次态表达式。
仅实现y[2]的下一状态逻辑。
module top_module (
input [3:1] y,
input w,
output Y2);
parameter s0=3'd0,s1=3'd1,s2=3'd2,s3=3'd3,
s4=3'd4,s5=3'd5;
always@(*) begin
case ({y,w})
{s0,1'b0}: Y2 = s1[1];
{s0,1'b1}: Y2 = s0[1];
{s1,1'b0}: Y2 = s2[1];
{s1,1'b1}: Y2 = s3[1];
{s2,1'b0}: Y2 = s4[1];
{s2,1'b1}: Y2 = s3[1];
{s3,1'b0}: Y2 = s5[1];
{s3,1'b1}: Y2 = s0[1];
{s4,1'b0}: Y2 = s4[1];
{s4,1'b1}: Y2 = s3[1];
{s5,1'b0}: Y2 = s2[1];
{s5,1'b1}: Y2 = s3[1];
endcase
end
endmodule
4.2 FSM one-hot next-state logic(Q6c)
考虑下面显示的状态机,它有一个输入w和一个输出z。
对于此部分,假设使用独热码分别为状态A,B,…,F编码,状态分配为y [6:1] = 000001、000010、000100、001000、010000、100000。
编写次态信号y2和y4的逻辑表达式。
独热码的问题思路就是看输出信号可能来自于什么情况,然后列出这些情况。
module top_module (
input [6:1] y,
input w,
output Y2,
output Y4);
parameter s1=6'b000001,s2=6'b000010,s3=6'b000100,s4=6'b001000,s5=6'b010000,s6=6'b100000;
reg [5:0] next;
always@(*) begin
case ({y,w})
{s1,1'b0}: begin next = s2; end
{s1,1'b1}: begin next = s1; end
{s2,1'b0}: begin next = s3; end
{s2,1'b1}: begin next = s4; end //
{s3,1'b0}: begin next = s5; end
{s3,1'b1}: begin next = s4; end //
{s4,1'b0}: begin next = s6; end
{s4,1'b1}: begin next = s1; end
{s5,1'b0}: begin next = s5; end
{s5,1'b1}: begin next = s4; end //
{s6,1'b0}: begin next = s3; end
{s6,1'b1}: begin next = s4; end //
endcase
end
assign Y2 = y[1] & ~w; //Y2是1的情况只有s2,即状态B
assign Y4 = (y[2]&w) | (y[3]&w) | (y[5]&w) | (y[6]&w);//Y4是1的情况只有s4,即状态D
endmodule
4.3 FSM(Q6)
考虑下面显示的状态机,它有一个输入w和一个输出z。
module top_module (
input clk,
input reset, // synchronous reset
input w,
output z);
parameter s1=6'b000001,s2=6'b000010,s3=6'b000100,s4=6'b001000,s5=6'b010000,s6=6'b100000;
reg [5:0] state,next;
always@(*) begin
case ({state,w})
{s1,1'b0}: begin next = s2; end
{s1,1'b1}: begin next = s1; end
{s2,1'b0}: begin next = s3; end
{s2,1'b1}: begin next = s4; end //
{s3,1'b0}: begin next = s5; end
{s3,1'b1}: begin next = s4; end //
{s4,1'b0}: begin next = s6; end
{s4,1'b1}: begin next = s1; end
{s5,1'b0}: begin next = s5; end
{s5,1'b1}: begin next = s4; end //
{s6,1'b0}: begin next = s3; end
{s6,1'b1}: begin next = s4; end //
endcase
end
always @(posedge clk) begin
if(reset)
state <= s1;
else
state <= next;
end
assign z = (state==s5)|(state==s6);
endmodule
5 FSM(Q2)
5.1 FSM(Q2a)
考虑下面显示的状态机。
编写代表此FSM的完整Verilog代码。 对状态表和状态触发器使用单独的Always块。 使用连续赋值语句或Always块描述FSM的输出z。 状态编码随你心意。
module top_module (
input clk,
input reset, // Synchronous active-high reset
input w,
output z
);
parameter s1=6'b000001,s2=6'b000010,s3=6'b000100,s4=6'b001000,s5=6'b010000,s6=6'b100000;
reg [5:0] state,next;
always@(*) begin
case ({state,w})
{s1,1'b0}: begin next = s1; end
{s1,1'b1}: begin next = s2; end
{s2,1'b0}: begin next = s4; end
{s2,1'b1}: begin next = s3; end //
{s3,1'b0}: begin next = s4; end
{s3,1'b1}: begin next = s5; end //
{s4,1'b0}: begin next = s1; end
{s4,1'b1}: begin next = s6; end
{s5,1'b0}: begin next = s4; end
{s5,1'b1}: begin next = s5; end //
{s6,1'b0}: begin next = s4; end
{s6,1'b1}: begin next = s3; end //
endcase
end
always @(posedge clk) begin
if(reset)
state <= s1;
else
state <= next;
end
assign z = (state==s5)|(state==s6);
endmodule
5.2 One-hot FSM equations(Q2b)
考虑下面显示的状态机。
假设使用独热码进行状态分配,y [5:0] = 000001(A),000010(B),000100(C),001000(D),010000(E),100000(F)
写出状态触发器y [1]输入Y1的逻辑表达式。
写出状态触发器y [3]输入Y3的逻辑表达式。
module top_module (
input [5:0] y,
input w,
output Y1,
output Y3
);
//Y1为1的情况只有状态B,y3为1的情况只有状态D
assign Y1 = y[0] & w;
assign Y3 = y[1]&~w | y[2]&~w | y[4]&~w | y[5]&~w;
endmodule
5.3 an arbiter circuit(Q2a)
该FSM充当仲裁器电路,该电路控制三个请求设备对某种类型资源的访问。每个设备通过设置信号r [i] = 1来请求资源,其中r [i]为r [1],r [2]或r [3]。
每个r [i]是FSM的输入信号,代表三个设备之一。只要没有请求,FSM就会保持状态A。当发生一个或多个请求时,FSM决定哪个设备接收到使用该资源的授权,并更改为将该设备的g [i]信号设置为1的状态。
每个g [i]是FSM的输出。有一个优先级系统,即设备1的优先级高于设备2的优先级,而设备3的优先级最低。因此,例如,当FSM处于状态A时,如果设备3是唯一发出请求的设备,则设备3将仅接收授权。一旦设备(即,FSM给了设备i)授权,该设备将继续接收授权,只要它的请求r [i] = 1。
编写代表此FSM的完整Verilog代码,对状态表和状态触发器使用单独的Always块。使用连续赋值语句或Always块(自行决定)描述FSM输出g [i]。状态分配随你所意。
module top_module (
input clk,
input resetn, // active-low synchronous reset
input [3:1] r, // request
output [3:1] g // grant
);
parameter s0=0,s1=1,s2=2,s3=3;
reg [1:0] state,next;
always @(*) begin
case (state)
s0 : begin
if(r[1])
next = s1;
else if(r[2])
next = s2;
else if(r[3])
next = s3;
else
next = s0;
end
s1 : begin
if(r[1])
next = s1;
else
next = s0;
end
s2 : begin
if(r[2])
next = s2;
else
next = s0;
end
s3 : begin
if(r[3])
next = s3;
else
next = s0;
end
endcase
end
always @(posedge clk) begin
if(~resetn)
state <= s0;
else
state <= next;
end
assign g = {state==s3,state==s2,state==s1};
endmodule
5.4 an arbiter circuit(Q2b)
考虑用于控制某种类型电动机的有限状态机。FSM具有来自电动机的输入x和y,并产生控制电动机的输出f和g。还有一个时钟输入叫clk和一个复位输入叫resetn。
FSM必须按以下方式工作:
只要复位输入有效,FSM保持初始状态,即状态A。
复位信号无效后,在下一个时钟沿之后,FSM必须在一个时钟周期内将输出f设置为1。然后,FSM必须监视x输入。当x在三个连续的时钟周期中产生值1,0,1时,则应在下一个时钟周期将g设置为1。
在保持g = 1的同时,FSM必须监视y输入。如果y在最多两个时钟周期内具有值1,则FSM应永久保持g = 1(即直到复位)。但是,如果y在两个时钟周期内没有变为1,则FSM应该永久设置g = 0(直到复位)。
(最初的考试问题仅要求提供状态图。但是,在这里实施FSM。)
这道题其实有很多条件没有讲清楚:
- FSM在输出f设置为1后,是否应该保持为1,如果不是那么应该保持多少个周期?根据多次试错,可以知道f在设置为1后维持一个周期即变为了0;
- “然后,FSM必须监视x输入,当x在三个连续的时钟周期中产生值1,0,1时”,这里监视x输入是在f设置为1这一时刻开始,还是f设置为1这一时刻后的一个时钟周期开始。根据多次试错,可以知道应该是后者。
- 监视y输出同上,是在g=1这一时刻的后一个时钟周期开始。
于是这里代码中判断状态变换的情况就都是state,而不是next。
module top_module (
input clk,
input resetn, // active-low synchronous reset
input x,
input y,
output f,
output g
);
parameter s0=0,s1=1,s2=2,s3=3,s4=4,s5=5;
reg [2:0] state,next;
reg [2:0] data_x;
always @(posedge clk) begin
if (~resetn) begin
data_x <= 3'b0;
end
else if(state==s2) begin
data_x <= {data_x[1:0],x};
end
else begin
data_x <= 3'b0;
end
end
reg cnt;
reg y_reg;
always @(posedge clk) begin
if (~resetn) begin
y_reg <= 1'b0;
cnt <= 1'b0;
end
else if(cnt==1'b1)
cnt = 0;
else if(state==s3) begin
cnt <= cnt + 1'b1;
y_reg <= y;
end
end
always @(*) begin
case (state)
s0: next = s1;
s1: next = s2;
s2: next = ({data_x[1:0],x}==3'b101) ? s3 : s2;
s3: next = (cnt==1'b1) ? (({y_reg,y}==2'b00) ? s4 : s5) : s3;
s4: next = s4;
s5: next = s5;
endcase
end
reg k;
always @(posedge clk) begin
if (~resetn)
state <= s0;
else begin
state <= next;
end
end
assign f = (state==s1);
assign g = (state==s5)|(state==s3);
endmodule