1、输入是什么?
2、现态是什么?
3、次态是什么?
4、转换条件是什么?
5、输出是什么?
在这个问题中,输入是3个传感器,现态和次态是4个水位状态(water level),转换条件是3个传感器的值是什么情况,输出是水阀的开关状态。其中水阀分两类,一类是固定水阀(nominal flow),一类是辅助水阀(supplemental flow)。
module top_module (
input clk,
input reset, //同步复位,高有效
input [3:1] s,
output fr3,
output fr2,
output fr1,
output dfr
);
parameter a=1,b=2,c=3,d=4;
reg [2:0] state,state_n;
//状态转换
always@(posedge clk)begin
if(reset)
state <= a;
else
state <= state_n;
end
//转换条件
always@(*)begin
case(state)
a:state_n = s[1]? b:a;
b:state_n = s[2]? c:(s[1]? b:a);
c:state_n = s[3]? d:(s[2]? c:b);
d:state_n = s[3]? d:c;
endcase
end
//输出结果
always@(*)begin
case(state)
a:{fr3,fr2,fr1} = 3'b111;
b:{fr3,fr2,fr1} = 3'b011;
c:{fr3,fr2,fr1} = 3'b001;
d:{fr3,fr2,fr1} = 3'b000;
endcase
end
always@(posedge clk)begin
if(reset)
dfr <= 1;
else begin
if(state > state_n)
dfr <= 1;
else if(state
其中,辅助水阀的开关取决于当前状态和前一状态的值,所以用时序逻辑+比较器实现。如果现在的状态是a,下一状态是b。那么当下一个时钟来临时,a就变成了上一个状态,b就变成了当前状态,再通过比较得出水是上升还是下降,从而实现dfr的赋值。
答案中给出的程序如下:
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
答案中直接分配了6个状态,包括了上升和下降的信息(b1b2,c1c2),所以结构更为精简。这里给出了状态机的默认值‘x。
碰到左边就往右走,碰到右边就往左走。
所以状态只有两个:向右、向左;输入为碰左边、碰右边。
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
output walk_left,
output walk_right); //
parameter LEFT=0, RIGHT=1;
reg state, next_state;
always @(*) begin
// State transition logic
case(state)
LEFT:next_state = bump_left? RIGHT:LEFT;
RIGHT:next_state = bump_right? LEFT:RIGHT;
default:next_state = 'x;
endcase
end
always @(posedge clk, posedge areset) begin
// State flip-flops with asynchronous reset
if(areset)
state <= LEFT;
else
state <= next_state;
end
// Output logic
assign walk_left = (state == LEFT);
assign walk_right = (state == RIGHT);
endmodule
比上面多了一个“坠落”的效果,并会发出“aaah”,掉落时不再受碰撞影响,地重新出现的时候继续上一方向。
新状态:坠落;转入条件:ground=0;输出:aaah
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
output walk_left,
output walk_right,
output aaah );
parameter WL=0,WR=1,WLF=2,WRF=3;
reg [1:0] state,state_n;
always@(posedge clk or posedge areset)begin
if(areset)
state <= WL;
else
state <= state_n;
end
always@(*)begin
case(state)
WL:state_n = ground? (bump_left? WR:WL):WLF;
WR:state_n = ground? (bump_right? WL:WR):WRF;
WLF:state_n = ground? WL:WLF;
WRF:state_n = ground? WR:WRF;
endcase
end
assign walk_left = (state == WL);
assign walk_right = (state == WR);
assign aaah = (state == WRF)||(state == WLF);
endmodule
新增状态:挖洞
转入条件:ground=1&&dig=1
转出条件:ground=0
优先级:坠落>挖洞>选方向
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
input dig,
output walk_left,
output walk_right,
output aaah,
output digging );
parameter WR=0,WL=1,WLF=2,WRF=3,DIGL=4,DIGR=5;
reg [2:0] state,state_n;
always@(posedge clk or posedge areset)begin
if(areset)
state <= WL;
else
state <= state_n;
end
always@(*)begin
case(state)
WL:state_n = ground? (dig? DIGL:(bump_left? WR:WL)):WLF;
WR:state_n = ground? (dig? DIGR:(bump_right? WL:WR)):WRF;
WLF:state_n = ground? WL:WLF;
WRF:state_n = ground? WR:WRF;
DIGL:state_n = ground? DIGL:WLF;
DIGR:state_n = ground? DIGR:WRF;
endcase
end
assign walk_left = state == WL;
assign walk_right = state == WR;
assign aaah = (state == WLF)||(state == WRF);
assign digging = (state == DIGR)||(state == DIGL);
endmodule
新增状态:飞溅
转入条件:下落时间>20clk && 有地面出现
输出:全部输出为0
通过debug我发现,aaah是在下落过程中一直出现,并不会在splatter的状态下终止。这就意味着在下落过程中,只有t>20且ground=1时,输出才会改变。
module top_module(
input clk,
input areset, // Freshly brainwashed Lemmings walk left.
input bump_left,
input bump_right,
input ground,
input dig,
output walk_left,
output walk_right,
output aaah,
output digging );
parameter WL=0,WR=1,DIGL=2,DIGR=3,WLF=4,WRF=5,SPL=6,OVER=7;
reg [3:0] state,state_n;
reg [4:0] cnt_20;
wire add_cnt_20;
wire end_cnt_20;
wire full_cnt_20;
always@(posedge clk or posedge areset)begin
if(areset)begin
cnt_20 = 5'b0;
full_cnt_20 = 0;
end
else begin
if(add_cnt_20)begin
if(end_cnt_20)begin
cnt_20 = 5'b0;
full_cnt_20 = 1;
end
else begin
cnt_20 = cnt_20 + 1;
full_cnt_20 = full_cnt_20;
end
end
else begin
cnt_20 = 5'b0;//无地计数,有地清零
full_cnt_20 = 0;
end
end
end
assign add_cnt_20 = ~ground;
assign end_cnt_20 = add_cnt_20 && cnt_20 == 20;
always@(posedge clk or posedge areset)begin
if(areset)
state = WL;
else
state = state_n;
end
always@(*)begin
case(state)
WL:state_n = ground?(dig?DIGL:(bump_left?WR:WL)):WLF;
WR:state_n = ground?(dig?DIGR:(bump_right?WL:WR)):WRF;
DIGL:state_n = ground?DIGL:WLF;
DIGR:state_n = ground?DIGR:WRF;
WLF:state_n = ground?(full_cnt_20?OVER:WL):WLF;
WRF:state_n = ground?(full_cnt_20?OVER:WR):WRF;
OVER:state_n = OVER;
endcase
end
assign walk_left = state == WL;
assign walk_right = state == WR;
assign aaah = state == WLF || state == WRF ;
assign digging = state == DIGL || state == DIGR;
endmodule
只写状态转换逻辑和输出
module top_module(
input in,
input [9:0] state,
output [9:0] next_state,
output out1,
output out2);
assign next_state[0] = (state & 10'b1110011111)&&(~in);
assign next_state[1] = (state[0] & in) | (state[8] & in)|(state[9] & in);
assign next_state[2] = (state[1] & in);
assign next_state[3] = (state[2] & in);
assign next_state[4] = (state[3] & in);
assign next_state[5] = (state[4] & in);
assign next_state[6] = (state[5] & in);
assign next_state[7] = (state[7] & in) | state[6] & (in);
assign next_state[8] = state[5] & (~in);
assign next_state[9] = state[6] & (~in);
assign out1 = (state[8] | state[9]) ? 1:0;
assign out2 = (state[9] | state[7]) ? 1:0;
endmodule
我发现除了s5s6,其他状态下当in=0时,都会回到s0。所以将state输入按位与,消去s5s6的影响,再逻辑与上~in,只要其他位有1,则状态回到s0。
其他状态与之前的独热码状态机无差别,独热码的使用让逻辑转换式更加简单,利于消除毛刺。
这里的BYTE1、BYTE2、BYTE3,对应每一组信号的bit[3]、bit[2]、bit[1]
这里in[3]的数据只表示第3位,即标志位。当in[3]=1时,输出3位数据,完成后标志位done=1。这里最下面一行的byte1、byte2、byte3对应的是输出信号,不是done。
这里一组信号输出完成后,下一个in[3]还未来临,所以状态维持在byte1,;当in[3]=1时,下一状态变成byte2.
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output done); //
reg [3:0] state,state_n;
parameter BYTE1=0,BYTE2=1,BYTE3=2,DONE=3;
// State transition logic (combinational)
always@(*)begin
case(state)
BYTE1:state_n = in[3]?BYTE2:BYTE1;
BYTE2:state_n = BYTE3;
BYTE3:state_n = DONE;
DONE: state_n = in[3]?BYTE2:BYTE1;
endcase
end
// State flip-flops (sequential)
always@(posedge clk)begin
if(reset)
state = BYTE1;
else
state = state_n;
end
// Output logic
assign done = (state == DONE)? 1:0;
endmodule
与上一题的主要区别在于提供了数据的存储路径,这里的思路是当下一状态改变时,意味着数据满足要求,在下一个时钟到来的时候,一方面state=state_n;一方面输入数据被存储起来。
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output [23:0] out_bytes,
output done); //
// FSM from fsm_ps2
reg [3:0] state,state_n;
parameter BYTE1=0,BYTE2=1,BYTE3=2,DONE=3;
// State transition logic (combinational)
always@(*)begin
case(state)
BYTE1:state_n = in[3]?BYTE2:BYTE1;
BYTE2:state_n = BYTE3;
BYTE3:state_n = DONE;
DONE: state_n = in[3]?BYTE2:BYTE1;
endcase
end
// State flip-flops (sequential)
always@(posedge clk)begin
if(reset)
state = BYTE1;
else
state = state_n;
end
// Output logic
assign done = (state == DONE);
// New: Datapath to store incoming bytes.
//下一状态为BYTE2时,BYTE1记录完成;
//下一状态为BYTE3时,BYTE2记录完成;
//下一状态为DONE时,BYTE3记录完成;
reg [23:0] out_reg;
always@(posedge clk)begin
if(reset)
out_reg <= 24'b0;
else
case(state_n)
BYTE2:out_reg[23:16] <= in[7:0];
BYTE3:out_reg[15:8] <= in[7:0];
DONE: out_reg[7:0] <= in[7:0];
default:out_reg[23:0]<= 24'b0;
endcase
end
assign out_bytes = (state == DONE)?out_reg[23:0]:24'b0;
endmodule