文章目录
两点说明
个人收获:我们在写状态机的时候,在第三段描述输出,以及第二段状态转移的部分有需要注意的地方。
1、对于输出,我们一般用寄存器输出,尽量少的使用assign语句,因为用寄存器输出可带来更好的时序。
2、对于状态机的条件,我们发生有时候条件是当前状态state,有时候状态是下一状态next_state,但是怎么判断用哪个呢?
当我们采用组合逻辑的时候,用当前状态
当我们使用时序逻辑的时候,会打一拍,因此用下一状态。
Fsm hdlc
解码连续的数据位流,以查找指示帧(数据包)开始和结束的位模式。恰好6个连续的1(即01111110)是指示帧边界的“标志flag”,为了避免数据流意外包含“标志”,发送方每5个连续1后插入一个零,接收方必须检测并丢弃该值。如果有 7 个或更多个连续 1,我们还需要发出错误信号。因此:
0111110:每5个1后插入一个0,检测后进行丢弃——disc。
01111110:出现连续6个1,可标记帧(标志)的开头/结尾——flag。
01111111…:有连续7个或者更多1出现,发出错误信号——err。
解题:
根据题目,我们可以确定出五个状态:
IDLE空闲状态,DATA数据流状态,FLAG标志状态,DISC丢弃状态,ERROR错误状态
module top_module(
input clk,
input reset, // Synchronous reset
input in,
output reg disc,
output reg flag,
output reg err
);
parameter IDLE = 5'b00001;
parameter DATA = 5'b00010;
parameter DISC = 5'b00100;
parameter FLAG = 5'b01000;
parameter ERROR = 5'b10000;
reg [4:0] current_state;
reg [4:0] next_state;
reg [2:0] counter;
always @(*) begin
case(current_state)
IDLE:begin
next_state = in ? DATA : IDLE;
end
DATA:begin
case(counter)
3'd5: next_state = in ? DATA : DISC;
3'd6: next_state = in ? ERROR : FLAG;
default:next_state = in ? DATA : IDLE;
endcase
end
DISC:begin
next_state = in ? DATA : IDLE;
end
FLAG:begin
next_state = in ? DATA : IDLE;
end
ERROR:begin
next_state = in ? ERROR : IDLE;
end
endcase
end
always @(posedge clk) begin
if(reset)begin
current_state <= IDLE;
end
else begin
current_state <= next_state;
end
end
always @(posedge clk) begin
if(reset)begin
disc <= 1'd0;
flag <= 1'd0;
err <= 1'd0;
counter <= 3'd0;
end
else begin
case(next_state)
DATA:begin
disc <= 1'd0;
flag <= 1'd0;
err <= 1'd0;
counter <= counter + 1'd1;
end
DISC:begin
disc <= 1'd1;
flag <= 1'd0;
err <= 1'd0;
counter <= 3'd0;
end
FLAG:begin
disc <= 1'd0;
flag <= 1'd1;
err <= 1'd0;
counter <= 3'd0;
end
ERROR:begin
disc <= 1'd0;
flag <= 1'd0;
err <= 1'd1;
counter <= 3'd0;
end
default:begin
disc <= 1'd0;
flag <= 1'd0;
err <= 1'd0;
counter <= 3'd0;
end
endcase
end
end
endmodule
q8 Mealy 型有限状态机
实现一个 Mealy 型有限状态机,该状态机可识别名为 x 的输入信号上的序列“101”。您的 FSM 应具有输出信号 z,当检测到“101”序列时,该信号被断言为 logic-1(也就是检测到101输出逻辑1,否则为0)。FSM 还应具有低电平有效异步复位。
状态机中可能只有 3 个状态。
可识别重叠的序列,意思是当输入10101的时候可以分别在3和5时刻都输出z = 1。因此可能在第一位的基础上检测第二位的情况。
module top_module (
input clk,
input aresetn, // Asynchronous active-low reset
input x,
output z
);
parameter S0 = 3'b001;
parameter S1 = 3'b010;
parameter S2 = 3'b100;
reg [2:0] state;
reg [2:0] next_state;
//第一段,时序逻辑描述状态寄存器
always @(posedge clk or negedge aresetn)
if(!aresetn)
state <= S0;
else
state <= next_state;
//第二段,组合逻辑描述状态转移
always @ (*)
case(state)
S0: next_state = x ? S1 : S0;
S1: next_state = x ? S1 : S2;
S2: next_state = x ? S1 : S0;
default:next_state = S0;
endcase
//第三段,组合逻辑描述输出
assign z = (state == S2) ? x : 1'b0; //因为该题为米利状态机,那么输出与输入x有关,因此可以这么写
endmodule
q5a 单输入单输出串行 2 的补码摩尔状态机
首先我们要了解2的补码如何计算?
简单来说就是取反后加1。例如 给出一个序列数 100100,其2的补码:011011 + 1 = 011100
下图可看出,输出z的左边是LSB低位,右边是MSB高位。因此若输入是00110100,那么进行2的补码计算为11001100.
该题的重点在于进位的处理,进行+1操作的时候,需要进位,但是我们不知道最终需要进位到哪一位,因此采用状态机来解决。
分析:如果输入的低位都是0,那么取反后为1,同时进行+1操作,就需要进位。另外只要低位是0,那么就会一直进位,直到不断检测到输入为1,此时取反+1后不需要进位操作。此时阶段可用一个状态表示(检测1的过程,若没检测到,继续检测,否则跳转到下一状态),下一状态是对输入进行输出,因为此过程已经不涉及进位了。
该题是摩尔状态机,输出与输入无关,因此这里要用到三个状态。
module top_module (
input clk,
input areset,
input x,
output z
);
parameter S0 = 3'b001;
parameter S1 = 3'b010;
parameter S2 = 3'b100;
reg [2:0] state;
reg [2:0] next_state;
//第一段,时序逻辑描述状态寄存器
always @(posedge clk or posedge areset)
if(areset)
state <= S0;
else
state <= next_state;
//第二段,组合逻辑描述状态转移
always @ (*)
case(state)
S0: next_state = x ? S1 : S0;
S1: next_state = x ? S2 : S1;
S2: next_state = x ? S2 : S1;
default:next_state = S0;
endcase
//第三段,组合逻辑描述输出
assign z = (state == S1) ;//因为该题为摩尔状态机,那么输出与输入x无关,因此不能和上题一样,若符合某条件输出x的值。
endmodule
q5b
可看出共两个状态,题目要求采用独热码编码。
状态A可看出,z的值与x相同,因此当A为真的时候,我们即可通过A&&x来进行z的判断,若x为0,z为0,x为1,z为1.
同理,状态B,z的值与x相反,因此当B为真的时候,我们可通过B&&(~x)来进行z的判断,若x为0,z为1,x为1,z为0.
module top_module (
input clk,
input areset,
input x,
output z
);
parameter S0 = 2'b01;
parameter S1 = 2'b10;
reg [1:0] current_state;
reg [1:0] next_state;
//第一段,状态寄存器
always @(posedge clk or posedge areset) begin
if(areset)begin
current_state <= S0;
end
else begin
current_state <= next_state;
end
end
//第二段,描述状态转移
always @(*) begin
case(current_state)
S0: next_state = x ? S1 : S0;
S1: next_state = S1;
endcase
end
//描述输出
assign z = ((current_state == S0) && x) || ((current_state == S1) && ~x);
endmodule
q3fsm(引入计数器)
当s=1时,进入B状态后,检查w的值,如果在接下来的三个周期中w值恰好有两个周期都为1,则z输出1,否则z输出0。
注意,q8中涉及到重叠序列的情况,但是通过该题的波形图可看到是没有进行重叠序列检测的。
要求:使用尽可能少的状态,因此本题目就仅仅用AB两个状态,然后B状态中对w值的判断用计数器来搞。
首先设计一个计数器,对三个周期的w进行统计,同时定义一个数来记录w值的加法结果,当计数三次的时候,可以统计三次w值相加,同时如果加起来是2,说明有两个w值为1.
```bash
module top_module (
input clk,
input reset, // Synchronous reset
input s,
input w,
output z
);
parameter A = 2'b01;
parameter B = 2'b10;
reg [1:0] state,next_state;
reg [1:0] counter,num;
//第一段,状态寄存器
always @ (posedge clk)begin
if(reset)
state <= A;
else
state <= next_state;
end
//第二段,状态转移,根据s判断
always @ (*)begin
case(state)
A: next_state = s ? B:A;
B: next_state = B;
endcase
end
//对B状态内的w进行判断
//设计计数器
always @ (posedge clk)begin
if(reset)
counter <= 2'b0;
else if(counter == 2'd2)
counter <= 2'b0;
else if(state == B)
counter <= counter + 1'b1;
else
counter <= counter;
end
//对进入状态B后的w值进行判断,同时还要判断是否三个周期内有两个w值为1
always @ (posedge clk)begin
if(reset)
num <= 1'b0;
else if(counter == 2'b0)begin //初值或者计数满 ,就可以进行新的统计
num <= w ? 1'b1 : 1'b0;
end
else if(state == B)
num <= w ? (num + 1'b1) : num;
else
num <= 1'b0;
end
//第三段 结果的输出
assign z = (state == B && counter == 2'd0 && num == 2'd2);
endmodule
q3bfsm 根据状态分配表写状态机
该题给出如下的表达来写状态机,可看到有五种状态。复位的时候是状态000
下一状态与输入x有关,将x作为判断状态转移的条件。根据如下的表即可得到状态转移图。
module top_module (
input clk,
input reset, // Synchronous reset
input x,
output z
);
parameter S0 = 3'b000;
parameter S1 = 3'b001;
parameter S2 = 3'b010;
parameter S3 = 3'b011;
parameter S4 = 3'b100;
reg [2:0] state,next_state;
//第一段 状态寄存器
always @ (posedge clk)
if(reset)
state <= S0;
else
state <= next_state;
//第二段,状态转移
always @ (*)
case(state)
S0: next_state = x ? S1 : S0;
S1: next_state = x ? S4 : S1;
S2: next_state = x ? S1 : S2;
S3: next_state = x ? S2 : S1;
S4: next_state = x ? S4 : S3;
endcase
//第三段,描述输出
always @ (*)
if(state == S3 || state == S4)
z = 1'b1;
else if(state == S0 || state == S1 || state == S2)
z = 1'b0;
else
z = 1'b0;
endmodule
q3c
将Y[0]与z表示出来。
z直接找输出z对应的1的位置,然后找到对应的当前状态进行表示即可。
找Y[0]为1的情况,然后找到对应的当前状态进行表示即可。
module top_module (
input clk,
input [2:0] y,
input x,
output Y0,
output z
);
//输出一般用寄存器输出,能获得较好的时序
always @ (*) begin
Y0 = ((( ~y[2]&y[0]) | (y == 3'b100) ) &~x ) | ((~y[2]&~y[0])&x);
z = (y == 3'b011) | (y == 3'b100);
end
endmodule
q6b 根据状态转换图写状态分配表
下面状态机有一个输入 w 和一个输出 z
我们需要根据上面的状态图来写状态分配表,最终只实现 y[2] 的下一状态逻辑。
注意括号的对应。
module top_module (
input [3:1] y,
input w,
output Y2
);
always @ (*)
Y2 = (~w & (~y[2] & y[1])) | (w & ((~y[2] & y[1]) |( y == 3'b010) | y==3'b100));
endmodule
q6c
与上题类似,共六种状态,根据w的值进行下一状态的跳转,但是状态赋值处采用独热码的方式。
为下一状态信号 Y2 和 Y4 编写逻辑表达式。
module top_module (
input [6:1] y,
input w,
output Y2,
output Y4
);
always @ (*)begin
Y2 = ~w & y[1];
Y4 = (w & (y[2] | y[3] |y[5] |y[6] ));
end
endmodule
q6
实现该状态机
通过上状态转移图,我们也可以画状态分配表,也可以直接写,w为状态转移条件,同时有6个状态ABCDE,另外输出值z在状态EF处为1.
module top_module (
input clk,
input reset, // synchronous reset
input w,
output z
);
parameter A = 6'b000001;
parameter B = 6'b000010;
parameter C = 6'b000100;
parameter D = 6'b001000;
parameter E = 6'b010000;
parameter F = 6'b100000;
reg [5:0] state ;
reg [5:0] next_state ;
//第一段,状态寄存器
always @ (posedge clk)
if(reset)
state <= A;
else
state <= next_state;
//第二段,组合逻辑进行状态转移
always @ (*)begin
case(state)
A: next_state = w ? A : B;
B: next_state = w ? D : C;
C: next_state = w ? D : E;
D: next_state = w ? A : F;
E: next_state = w ? D : E;
F: next_state = w ? D : C;
default: next_state = A;
endcase
end
//第三段,组合逻辑描述输出z
always @ (*)begin
z = (state == 6'b010000 | state == 6'b100000);
end
endmodule
q2fsm
和上题一样,无非是状态转移处变化了。
module top_module (
input clk,
input reset, // synchronous reset
input w,
output z
);
parameter A = 6'b000001;
parameter B = 6'b000010;
parameter C = 6'b000100;
parameter D = 6'b001000;
parameter E = 6'b010000;
parameter F = 6'b100000;
reg [5:0] state ;
reg [5:0] next_state ;
//第一段,状态寄存器
always @ (posedge clk)
if(reset)
state <= A;
else
state <= next_state;
//第二段,组合逻辑进行状态转移
always @ (*)begin
case(state)
A: next_state = w ? B : A;
B: next_state = w ? C : D;
C: next_state = w ? E : D;
D: next_state = w ? F : A;
E: next_state = w ? E : D;
F: next_state = w ? C : D;
default: next_state = A;
endcase
end
//第三段,组合逻辑描述输出z
always @ (*)begin
z = (state == E | state == F);
end
endmodule
q2b 采用独热码编写
题目连个要求:
采用独热码编码。
y[5:0]
输y[1]和y[3]。——为更清楚,还是画状态分配表找下一状态(B和D)
只编写输出逻辑,不写状态机的一二段
module top_module (
input [5:0] y,
input w,
output Y1,
output Y3
);
//第三段,组合逻辑描述输出Y1和Y3
always @ (*)begin
Y1 = w & y[0];
Y3 = ~w & ( y[1] | y[2] | y[4] | y[5] );
end
endmodule
q2afsm 用状态机实现仲裁
此 FSM 充当仲裁器电路,它控制三个请求设备对某种类型资源的访问。
关于状态的转换:
每个设备通过设置信号 r[i] = 1 来请求资源,其中 r[i] 为 r[1]、r[2] 或 r[3]。——输入是三位的
每个 r[i] 都是 FSM 的输入信号,代表三个器件之一。只要没有请求,FSM 就会一直保持在状态 A 中。
当一个或多个请求发生时,从而FSM 将决定哪个设备获得使用资源的授权。
关于输出:
当一个或多个请求发生时,FSM 将决定哪个设备获得使用资源的授权,将该设备的 g[i] 信号设置为 1 的状态。
有一个优先级系统,因为设备 1 的优先级高于设备 2,而设备 3 的优先级最低。因此,例如,仅当设备 3 是 FSM 处于状态 A 时发出请求的唯一设备时,它才会获得授权。一旦设备 i 被 FSM 授予授权,只要其请求 r[i] = 1,该设备就会继续获得授权。
module top_module (
input clk,
input resetn, // active-low synchronous reset
input [3:1] r, // request
output [3:1] g // grant
);
parameter A = 4'b0001;
parameter B = 4'b0010;
parameter C = 4'B0100;
parameter D = 4'b1000;
reg [3:0] state,next_state; //注意位数
//第一段
always@(posedge clk)
if(!resetn)
state <= A;
else
state <= next_state;
//第二段
always @(*)
case(state)
A:begin
if(r[1] == 3'b1)
next_state = B;
else if(r[2] == 3'b1)
next_state = C;
else if(r[3] == 3'b1)
next_state = D;
else
next_state = A;
end
B:begin
next_state = r[1] ? B : A;
end
C:begin
next_state = r[2] ? C : A;
end
D:begin
next_state = r[3] ? D : A;
end
default:begin
next_state = A;
end
endcase
//第三段
always@(*)begin
g[1] = (state == B);
g[2] = (state == C);
g[3] = (state == D);
end
endmodule
q2bfsm 根据题目要求来画状态图
用于控制某种类型电机的有限状态机。FSM具有来自电机的输入x和y,并产生控制电机的输出f和g。还有一个名为 clk 的时钟输入和一个名为 resetn 的同步低电平复位输入。
工作方式:
复位时为状态A
输出 f 是采用时序逻辑进行输出,当复位信号被取消置位时,在下一个时钟边沿之后,FSM必须在一个时钟周期内将输出f设置为1。
当 x 在三个连续的时钟周期中生成值 1、0、1 时(检测101序列),则 g 应在下一个时钟周期中设置为 1。——此阶段状态转移的条件是x
在保持 g = 1 的同时,FSM 进行两个序列输入y的检测 。如果 y 为01,10,11,则 FSM 应永久保持 g = 1(直到重置)。但是,如果y为00,则 FSM 应永久设置 g = 0(直到重置)。
module top_module (
input clk,
input resetn, // active-low synchronous reset
input x,
input y,
output f,
output g
);
//九个状态则不用独热码
parameter IDLE = 4'd0;
parameter OUT_F = 4'd1;
parameter OUT_X1 = 4'd2;
parameter OUT_X2 = 4'd3;
parameter OUT_X3 = 4'd4;
parameter OUT_G1 = 4'd5;
parameter OUT_G2 = 4'd6;
parameter KEEP1 = 4'd7;
parameter ZERO = 4'd8;
reg [3:0] state,next_state;
//状态寄存器
always @ (posedge clk)
if(!resetn)
state <= IDLE;
else
state <= next_state;
//状态转移
always @ (*)
case(state)
IDLE : next_state = OUT_F;
OUT_F : next_state = OUT_X1;
OUT_X1: next_state = x ? OUT_X2 : OUT_X1;
OUT_X2: next_state = x ? OUT_X2 : OUT_X3;
OUT_X3: next_state = x ? OUT_G1 : OUT_X1;
OUT_G1: next_state = y ? KEEP1 : OUT_G2;
OUT_G2: next_state = y ? KEEP1 : ZERO;
KEEP1 : next_state = KEEP1;
ZERO : next_state = ZERO;
default:next_state = IDLE;
endcase
//描述输出
always @ (posedge clk)
if(!resetn)
f <= 1'b0;
else if(next_state == OUT_F)
f <= 1'b1;
else
f <= 1'b0;
always @ (*)begin
g = (state == OUT_G1 | state == OUT_G2 |state == KEEP1 );
end
endmodule