hdlbits网站:HDLBits (01xz.net)
有限状态机部分难度比较大,在这一部分我花了比其他另外四个部分都多的时间,几乎占了我刷整个hdlbits一半的时间,死了很多脑细胞,写的我头昏脑胀。一个是很多有些题目作者的表达并不好,项目要求描述的并不清楚,最准确的还是时序图,时序图是不会说谎的。另外一个就是这一部分对初学者难度确实更大,先要弄懂作者题目的需求,然后根据需求要做出正确的状态机设计和输出逻辑的设计,这部分代码长一些,状态机部分也是整个hdlbits的精华内容,所以这部分除了代码,我写的分析的内容也会多一些。
正文:
finite state machines
simple FSM1(asynchronous reset)
Moore状态机,一个输入in,一个输出out,两个状态A和B,异步复位areset
module top_module(
input clk,
input areset, // Asynchronous reset to state B
input in,
output out);//三段式状态机
parameter A=0, B=1;
reg state, next_state;
always @(*) begin //组合逻辑块:状态转换的逻辑判断
case(state)
A:next_state=in?A:B;
B:next_state=in?B:A;
default:next_state=B;//防止进入未设定状态产生latch锁死,设定default后可以自启动
endcase
end
always @(posedge clk, posedge areset) begin // 时序逻辑块:执行状态变换
if(areset)
state<=B;
else
state<=next_state;
end
// Output logic
assign out = (state ==B);
endmodule
simple FSM1(synchronous reset)
Moore状态机,一个输入in,一个输出out,两个状态A和B,同步复位reset
题目给了一段式状态机模板,我就顺着写了,非常不建议写一段式状态机。
// Note the Verilog-1995 module declaration syntax here:
module top_module(clk, reset, in, out);
input clk;
input reset; // Synchronous reset to state B
input in;
output out;//
reg out;
//一段式状态机(不提倡这么写)
reg present_state, next_state;
parameter A=1'b0,B=1'b1;
always @(posedge clk) begin
if (reset) begin
present_state<=B;
out<=1'b1;
end else begin
case (present_state)// state transition logic
A:next_state=in?A:B;
B:next_state=in?B:A;
default:next_state=B;
endcase
// State flip-flops
present_state = next_state;
case (present_state)// output logic
B:out<=1'b1;
A:out<=1'b0;
default:out<=1'b1;
endcase
end
end
endmodule
simple FSM2(asynchronous reset)
Moore状态机,两个输入j和k,一个输出out,两个状态OFF和ON,异步复位areset
module top_module(
input clk,
input areset, // Asynchronous reset to OFF
input j,
input k,
output out); // 三段式
parameter OFF=0, ON=1;
reg state, next_state;
always @(*) begin
case(state)
ON:next_state=k?OFF:ON;
OFF:next_state=j?ON:OFF;
default:next_state=OFF;
endcase
end
always @(posedge clk, posedge areset) begin
if(areset)
state<=OFF;
else
state<=next_state;
end
// Output logic
assign out = (state == ON);
endmodule
simple FSM2(synchronous reset)
Moore状态机,两个输入j和k,一个输出out,两个状态OFF和ON,同步复位reset
module top_module(
input clk,
input reset, // Synchronous reset to OFF
input j,
input k,
output out); //
parameter OFF=0, ON=1;
reg state, next_state;
always @(*) begin
case(state)
OFF:next_state=j?ON:OFF;
ON:next_state=k?OFF:ON;
default:next_state=OFF;
endcase
end
always @(posedge clk) begin
if(reset)
state<=OFF;
else
state<=next_state;
end
// Output logic
assign out = (state == ON);
endmodule
simple state transitions3
要求实现此状态机的状态转换逻辑和输出逻辑(组合逻辑部分)
状态转移图:
Moore状态机,一个输入in,一个输出out,四个状态A,B,C,D。
module top_module(
input in,
input [1:0] state,
output [1:0] next_state,
output out); //
parameter A=2'b00,B=2'b01,C=2'b10,D=2'b11;
// State transition logic: next_state = f(state, in)
always @(*)begin
case(state)
A:next_state=in?B:A;
B:next_state=in?B:C;
C:next_state=in?D:A;
D:next_state=in?B:C;
default:next_state=A;
endcase
end
// Output logic: out = f(state) for a Moore state machine
assign out=(state==D);
endmodule
simple one-hot state transitions3
本题可以设独热码是A=4'b0001,B=4'b0010,C=4'b0100,D=4'b1000,独热码保证每个状态只有一个 state bit 为1,其他都为0。这意味着可以通过检查特定位的值来判别是否处于特定状态。本题中[0]/[1]/[2]/[3]分别是A/B/C/D的状态位(state bit)
要求通过独热编码来检查推导出状态转换逻辑和输出逻辑(组合逻辑部分)。
状态转移图:
本题与上题放在前后可以做对比,正常写状态机的状态转移逻辑,都是根据现态(current_state)和触发条件转移到哪个次态(next_state),这是current_state→next_state的思路,也就是看现态(current_state)指出去的箭头。
这里题目要求通过独热编码来检查状态转换逻辑,这里从次态(next-state)出发,分析什么样的现态(current_state)加什么样的条件会得到该次态,这是next_state→current_state的思路(一种逆向的思路),也就是看指向次态(next_state)的箭头。
更详细的信息可以参考作者的解释:
module top_module(
input in,
input [3:0] state,
output [3:0] next_state,
output out); //
parameter A=0, B=1, C=2, D=3;//A=0,B=1,C=2,D=3是一个[3:0]state位索引
// State transition logic: Derive an equation for each state flip-flop.
assign next_state[A] = (state[A]&~in)|(state[C]&~in);
assign next_state[B] = (state[A]&in)|(state[B]&in)|(state[D]&in);
assign next_state[C] = (state[B]&~in)|(state[D]&~in);
assign next_state[D] = (state[C]&in);
// Output logic:
assign out = (state[D]);
endmodule
因为这里独热码设为了A=4‘b0001,B=4'b0010,C=4'b0100,D=4'b1000,所以上面这段代码A=0,B=1,C=2,D=3其实是一个[3:0]state bit的索引,如果不写parameter,还可以这样写:
module top_module(
input in,
input [3:0] state,
output [3:0] next_state,
output out); //
// State transition logic: Derive an equation for each state flip-flop.
assign next_state[0] = (state[0]&~in)|(state[2]&~in);
assign next_state[1] = (state[0]&in)|(state[1]&in)|(state[3]&in);
assign next_state[2] = (state[1]&~in)|(state[3]&~in);
assign next_state[3] = (state[2]&in);
// Output logic:
assign out = (state[3]);
endmodule
simple FSM3(asynchronous reset)
Moore状态机,一个输入in,一个输出out,四个状态A,B,C,D,异步复位。
module top_module(
input clk,
input in,
input areset,
output out); //
parameter A=2'b00,B=2'b01,C=2'b10,D=2'b11;
reg [1:0]current_state,next_state;
// 主控状态转移逻辑
always @(*)begin
case(current_state)
A:next_state=in?B:A;
B:next_state=in?B:C;
C:next_state=in?D:A;
D:next_state=in?B:C;
default:next_state=A;
endcase
end
// 主控执行逻辑
always @(posedge clk,posedge areset)begin
if(areset)
current_state<=A;
else
current_state<=next_state;
end
// 输出逻辑
assign out=(current_state==D);
endmodule
simple FSM3(synchronous reset)
Moore状态机,一个输入in,一个输出out,四个状态A,B,C,D,同步复位。
module top_module(
input clk,
input in,
input reset,
output out); //三段式
parameter A=2'b00,B=2'b01,C=2'b10,D=2'b11;
reg [1:0]current_state,next_state;
// 主控状态转移逻辑
always @(*)begin
case(current_state)
A:next_state=in?B:A;
B:next_state=in?B:C;
C:next_state=in?D:A;
D:next_state=in?B:C;
default:next_state=A;
endcase
end
// 主控执行逻辑
always @(posedge clk)begin
if(reset)
current_state<=A;
else
current_state<=next_state;
end
// 输出逻辑
assign out=(current_state==D);
endmodule
design a Moore FSM
module top_module (
input clk,
input reset,
input [3:1] s,
output reg fr3,
output reg fr2,
output reg fr1,
output reg dfr
);
parameter H3=4'b1000,B32=4'b0100,B21=4'b0010,L1=4'b0001;//4个状态:high s3,between s3s2,between s2s1, low s1,
reg [3:0]current_state,next_state;
always @(posedge clk)begin//主控执行逻辑
if (reset) begin
current_state<=L1;
end
else begin
current_state<=next_state;
end
end
always @(*)begin//主控状态转移逻辑
case(s)
3'b000:next_state=L1;
3'b001:next_state=B21;
3'b011:next_state=B32;
3'b111:next_state=H3;
default:next_state=L1;
endcase
end
always @(posedge clk)begin//{fr3,fr2,fr1}的输出逻辑
if(reset) begin
{fr3,fr2,fr1}<=3'b111;
end
else begin
case(next_state)
L1:{fr3,fr2,fr1}<=3'b111;
B21:{fr3,fr2,fr1}<=3'b011;
B32:{fr3,fr2,fr1}<=3'b001;
H3:{fr3,fr2,fr1}<=3'b000;
default:{fr3,fr2,fr1}<=3'b111;
endcase
end
end
always @(posedge clk)begin//dfr的输出逻辑
if(reset) begin
dfr<=1'b1;
end
else begin
if(next_state<current_state) begin
dfr<=1'b1;
end
else if(next_state>current_state) begin
dfr<=1'b0;
end
else
dfr<=dfr;
end
end
endmodule
lemmings 1
用摩尔状态机实现,两种状态LEFT和RIGHT,两个输入bump_left和bump_right,两个输出walk_left和walk_right;
状态转移图:
代码:
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 current_state, next_state;
always @(*) begin// State transition logic
case(current_state)
LEFT:next_state=bump_left?RIGHT:LEFT;
RIGHT:next_state=bump_right?LEFT:RIGHT;
default:next_state=LEFT;
endcase
end
always @(posedge clk, posedge areset) begin// State flip-flops with asynchronous reset
if(areset) begin
current_state<=LEFT;
end
else begin
current_state<=next_state;
end
end
// Output logic
assign walk_left = (current_state == LEFT);
assign walk_right = (current_state == RIGHT);
endmodule
lemmings 2![9376ed577e6d4d2bb8f35d17796402ee.png](https://i-blog.csdnimg.cn/direct/9376ed577e6d4d2bb8f35d17796402ee.png)
优先级:下落>碰撞,所以下落时候无视碰撞信号
用摩尔状态机实现,四种状态LEFT、RIGHT、FALL_LEFT和FALL_RIGHT,三个输入bump_left、 bump_right和ground,三个输出walk_left、walk_right和aaah
状态转移图(粗黑色箭头代表areset复位到的状态):
代码:
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 LEFT=4'b0001,RIGHT=4'b0010,FALL_LEFT=4'b0100,FALL_RIGHT=4'b1000;
reg [3:0]current_state,next_state;
always@(*)begin主控状态转移逻辑
case(current_state)
LEFT:begin
if(!ground) begin//地面消失,向左下落
next_state=FALL_LEFT;
end
else begin//在地面上向左走
if(bump_left) begin//碰撞改向右走
next_state=RIGHT;
end
else begin
next_state=LEFT;//没碰撞继续向左走
end
end
end
RIGHT:begin
if(!ground) begin//地面消失,向右下落
next_state=FALL_RIGHT;
end
else begin//在地面上向右走
if(bump_right) begin//碰撞改向左走
next_state=LEFT;
end
else begin
next_state=RIGHT;//没碰撞继续向右走
end
end
end
FALL_LEFT:begin
if(ground) begin
next_state=LEFT;
end
else begin
next_state=FALL_LEFT;
end
end
FALL_RIGHT:begin
if(ground) begin
next_state=RIGHT;
end
else begin
next_state=FALL_RIGHT;
end
end
default:next_state=LEFT;
endcase
end
always @(posedge clk or posedge areset)begin//主控执行逻辑
if(areset) begin
current_state<=LEFT;
end
else begin
current_state<=next_state;
end
end
//输出逻辑
assign walk_left=(current_state==LEFT);
assign walk_right=(current_state==RIGHT);
assign aaah=((current_state==FALL_LEFT)||(current_state==FALL_RIGHT));
endmodule
lemmings 3
用摩尔状态机实现,六种状态LEFT、RIGHT、FALL_LEFT、FALL_RIGHT、DIG_LEFT和DIG_RIGHT,四个输入bump_left、 bump_right、dig和ground,四个输出walk_left、walk_right、aaah和digging
优先级:fall>dig>bump,下落和挖掘时候忽略碰撞输入信号,下落时候忽略挖掘信号
状态转移图(粗黑色箭头代表areset复位到的状态):
代码:
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 LEFT=6'b000001,RIGHT=6'b000010,DIG_LEFT=6'b000100,DIG_RIGHT=6'b001000,FALL_LEFT=6'b010000,FALL_RIGHT=6'b100000;
reg [5:0]current_state,next_state;
always@(*)begin//主控状态转移逻辑
case(current_state)
LEFT:begin
if(!ground) begin
next_state=FALL_LEFT;//地面消失下落
end
else begin//有地面
if(dig) begin//挖掘
next_state=DIG_LEFT;
end
else if(bump_left) begin//不挖掘碰撞了向右走
next_state=RIGHT;
end
else begin//不挖掘不碰撞继续向左走
next_state=LEFT;
end
end
end
RIGHT:begin
if(!ground) begin
next_state=FALL_RIGHT;//地面消失下落
end
else begin//有地面
if(dig) begin//挖掘
next_state=DIG_RIGHT;
end
else if(bump_right) begin//不挖掘碰撞了向左走
next_state=LEFT;
end
else begin//不挖掘不碰撞继续向右走
next_state=RIGHT;
end
end
end
DIG_LEFT:begin
if(!ground) begin
next_state=FALL_LEFT;
end
else begin
next_state=DIG_LEFT;
end
end
DIG_RIGHT:begin
if(!ground) begin
next_state=FALL_RIGHT;
end
else begin
next_state=DIG_RIGHT;
end
end
FALL_LEFT:begin
if(ground) begin
next_state=LEFT;
end
else begin
next_state=FALL_LEFT;
end
end
FALL_RIGHT:begin
if(ground) begin
next_state=RIGHT;
end
else begin
next_state=FALL_RIGHT;
end
end
default:next_state=LEFT;
endcase
end
always@(posedge clk or posedge areset)begin//主控执行逻辑
if(areset) begin
current_state<=LEFT;
end
else begin
current_state<=next_state;
end
end
//输出逻辑
assign walk_left=(current_state==LEFT);
assign walk_right=(current_state==RIGHT);
assign aaah=((current_state==FALL_LEFT)||(current_state==FALL_RIGHT));
assign digging=((current_state==DIG_LEFT)||(current_state==DIG_RIGHT));
endmodule
lemmings 4
优先级:die>fall>dig>bump,死亡状态忽略任何输入信号,fall状态忽略dig和bump信号,dig状态忽略bump信号
用摩尔状态机实现,七种状态LEFT、RIGHT、FALL_LEFT、FALL_RIGHT、DIG_LEFT、DIG_RIGHT和DIE,四个输入bump_left、 bump_right、dig和ground,四个输出walk_left、walk_right、aaah和digging。
本题引入了下落超过20个周期落地会摔死飞溅的设定,所以需要编写一个计数器fallcount实现对下落周期的计数。
状态转移图(粗黑色箭头代表areset复位到的状态):
lemmings4是在lemmings3的基础上完善的版本,这里对比lemmings3题目多了一个DIE状态,只有FALL_LEFT和FALL_RIGHT才可能转移成DIE状态,所以LEFT、RIGHT、DIG_LEFT、DIG_RIGHT这四个状态的转移逻辑没有变,直接copy过来就可以。输出逻辑的assign式子中没有DIE状态,即DIE状态四个assign式子的输出(walk_left、walk_right、aaah和digging)都为0,也满足了题干要求的“飞溅死亡后所有 4 个输出全变为 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 LEFT=7'b0000001,
RIGHT=7'b0000010,
DIG_LEFT=7'b0000100,
DIG_RIGHT=7'b0001000,
FALL_LEFT=7'b0010000,
FALL_RIGHT=7'b0100000,
DIE=7'b1000000;
reg [6:0] current_state,next_state;
reg [100:0]fallcount;
always@(posedge clk or posedge areset)begin//主控状态执行逻辑
if(areset) begin
current_state<=LEFT;
end
else begin
current_state<=next_state;
end
end
always@(*)begin//主控状态转移逻辑
case(current_state)
LEFT:begin
if(!ground) begin
next_state=FALL_LEFT;//地面消失下落
end
else begin//有地面
if(dig) begin//挖掘
next_state=DIG_LEFT;
end
else if(bump_left) begin//不挖掘碰撞了向右走
next_state=RIGHT;
end
else begin//不挖掘不碰撞继续向左走
next_state=LEFT;
end
end
end
RIGHT:begin
if(!ground) begin
next_state=FALL_RIGHT;//地面消失下落
end
else begin//有地面
if(dig) begin//挖掘
next_state=DIG_RIGHT;
end
else if(bump_right) begin//不挖掘碰撞了向左走
next_state=LEFT;
end
else begin//不挖掘不碰撞继续向右走
next_state=RIGHT;
end
end
end
DIG_LEFT:begin
if(!ground) begin
next_state=FALL_LEFT;
end
else begin
next_state=DIG_LEFT;
end
end
DIG_RIGHT:begin
if(!ground) begin
next_state=FALL_RIGHT;
end
else begin
next_state=DIG_RIGHT;
end
end
FALL_LEFT:begin
if(!ground) begin//没有地面则继续下落
next_state=FALL_LEFT;
end
else begin
if(fallcount<='d20) begin//下落20个周期内落地,继续向左走
next_state=LEFT;
end
else begin//下落20个周期以上落地,死
next_state=DIE;
end
end
end
FALL_RIGHT:begin
if(!ground) begin//没有地面则继续下落
next_state=FALL_RIGHT;
end
else begin
if(fallcount<='d20) begin//下落20个周期内落地,继续向左走
next_state=RIGHT;
end
else begin//下落20个周期以上落地,死
next_state=DIE;
end
end
end
DIE:begin
next_state=DIE;//除非异步复位areset,否则永远保持在死亡状态
end
default:next_state=LEFT;
endcase
end
always@(posedge clk or posedge areset)begin//fallount对旅鼠下落周期计数
if(areset) begin
fallcount<='d0;
end
else if((next_state==FALL_LEFT)||(next_state==FALL_RIGHT))begin//下一个状态仍然下落继续计数
fallcount<=fallcount+'d1;
end
else begin//下一个周期不下落则计数归0
fallcount<='d0;
end
end
//输出逻辑
assign walk_left=(current_state==LEFT);
assign walk_right=(current_state==RIGHT);
assign aaah=((current_state==FALL_LEFT)||(current_state==FALL_RIGHT));
assign digging=((current_state==DIG_LEFT)||(current_state==DIG_RIGHT));
endmodule
one-hot FSM
要求通过独热编码来检查推导出状态转换逻辑和输出逻辑(组合逻辑部分)。
可参考:Fsm3onehot - HDLBits (01xz.net)
module top_module(
input in,
input [9:0] state,
output [9:0] next_state,
output out1,
output out2);
assign next_state[0]=(~in&state[0])|(~in&state[1])|(~in&state[2])|(~in&state[3])|(~in&state[4])|(~in&state[7])|(~in&state[8])|(~in&state[9]);
assign next_state[1]=(in&state[0])|(in&state[8])|(in&state[9]);
assign next_state[2]=(in&state[1]);
assign next_state[3]=(in&state[2]);
assign next_state[4]=(in&state[3]);
assign next_state[5]=(in&state[4]);
assign next_state[6]=(in&state[5]);
assign next_state[7]=(in&state[6])|(in&state[7]);
assign next_state[8]=(~in&state[5]);
assign next_state[9]=(~in&state[6]);
assign out1=(state[8]|state[9]);
assign out2=(state[7]|state[9]);
endmodule
PS/2 packet parser
用摩尔状态机实现,四个状态WAIT、BYTE1、BYTE2、BYTE3,一个输入in,一个输出done
状态转移图:
代码:
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output done); //
parameter WAIT=4'b0001,BYTE1=4'b0010,BYTE2=4'b0100,BYTE3=4'b1000;
reg [3:0]current_state,next_state;
always@(posedge clk)begin
if(reset) begin
current_state<=WAIT;
end
else begin
current_state<=next_state;
end
end
always@(*)begin
case(current_state)
WAIT:begin//等待状态
if(in[3])begin//in[3]为1,字节流有效,接收字节流数据
next_state=BYTE1;
end
else begin//否则,字节流无效,丢弃数据继续等待
next_state=WAIT;
end
end
BYTE1:begin
next_state=BYTE2;
end
BYTE2:begin
next_state=BYTE3;
end
BYTE3:begin
if(in[3])beginin[3]为1,字节流有效,接收字节流数据
next_state=BYTE1;
end
else begin//否则,字节流无效,丢弃数据开始等待状态
next_state=WAIT;
end
end
endcase
end
assign done=(current_state==BYTE3);
endmodule
PS/2 packet parser and datapath
这题对比上一题状态机的设计是一样的,所以直接copy过来就好。要求再添加一个24 位(3 字节)的数据路径out_bytes用来传输接收到的3字节数据包。
根据题意,该协议一次发送3字节的数据,这里我有两种理解方法:
一、3字节数据串行传输
如果串行传输,out_bytes可看作一个以字节为单位的左移移位寄存器(因为byte1先被送来),数据流是这样传输的:
题目还要求done信号有效时,out_bytes也需要是有效的,当然也可以在其他时间传输任何内容(即其他时间对out_bytes是否传输不做要求),可以看时序图来理解
module top_module(
input clk,
input [7:0] in,
input reset, // Synchronous reset
output reg[23:0] out_bytes,
output done);
// FSM from fsm_ps2
parameter WAIT=4'b0001,BYTE1=4'b0010,BYTE2=4'b0100,BYTE3=4'b1000;
reg [3:0]current_state,next_state;
always@(posedge clk)begin
if(reset) begin
current_state<=WAIT;
end
else begin
current_state<=next_state;
end
end
always@(*)begin
case(current_state)
WAIT:begin
if(in[3])begin
next_state=BYTE1;
end
else begin
next_state=WAIT;
end
end
BYTE1:begin
next_state=BYTE2;
end
BYTE2:begin
next_state=BYTE3;
end
BYTE3:begin
if(in[3])begin
next_state=BYTE1;
end
else begin
next_state=WAIT;
end
end
endcase
end
// New: Datapath to store incoming bytes.
always @(posedge clk)begin//串行传输
if(reset)begin
out_bytes<=24'b0;
end
else if(next_state==BYTE1) begin//BYTE1/2/3状态下in输入是有效数据会被接收,接收完串行传输给out_bytes
out_bytes<={out_bytes[15:0],in};
end
else if(next_state==BYTE2) begin
out_bytes<={out_bytes[15:0],in};
end
else if(next_state==BYTE3) begin
out_bytes<={out_bytes[15:0],in};
end
else begin//WAIT状态in输入是无效数据会被丢弃,out_bytes不会被更新
out_bytes<=out_bytes;
end
end
assign done=(current_state==BYTE3);
endmodule
BYTE1/2/3状态下in输入是有效数据会被接收,接收完传输给out_bytes;而且因为是非阻塞赋值,
所以数据传输是这样的:
二、3字节数据并行传输
如图,代码一看就懂
always @(posedge clk)begin//并行传输
if(reset)begin
out_bytes<=24'b0;
end
else if(next_state==BYTE1) begin//BYTE1/2/3状态下in输入是有效数据会被接收,并行传输给out_bytes
out_bytes<={in,out_bytes[15:0]};
end
else if(next_state==BYTE2) begin
out_bytes<={out_bytes[23:16],in,out_bytes[7:0]};
end
else if(next_state==BYTE3) begin
out_bytes<={out_bytes[23:8],in};
end
else begin//WAIT状态in输入是无效数据会被丢弃,out_bytes不会被更新
out_bytes<=out_bytes;
end
end
serial receiver
用摩尔状态机实现,五个状态IDLE、START、DATA、STOP和WAIT,一个输入in,一个输出done。
状态转移图:
需要注意的是,START模式传输数据最终有两种可能:
正确传输,跳转到STOP模式;或者错误传输,跳转到WAIT模式。所以STOP和WAIT模式不会在一次8位数据传输中都出现,两者是互斥的关系,所以不会有STOP和WAIT状态之间的转换。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output reg done
);
parameter IDLE=5'b00001,START=5'b00010,DATA=5'b00100,WAIT=5'b01000,STOP=5'b10000;
reg [4:0]current_state,next_state;
reg [3:0]data_count;
always @(posedge clk)begin//主控执行逻辑
if(reset)begin
current_state<=IDLE;
end
else begin
current_state<=next_state;
end
end
always @(*)begin//状态转移逻辑
case(current_state)
IDLE:begin
if(!in)begin
next_state=START;
end
else begin
next_state=IDLE;
end
end
START:begin
next_state=DATA;
end
DATA:begin
if(data_count==8&&in==1)begin
next_state=STOP;
end
else if(data_count==8&&in==0)begin
next_state=WAIT;
end
else begin
next_state=DATA;
end
end
STOP:begin
if(!in)begin
next_state=START;
end
else begin
next_state=IDLE;
end
end
WAIT:begin
if(!in)begin
next_state=WAIT;
end
else begin
next_state=IDLE;
end
end
default:next_state=IDLE;
endcase
end
always @(posedge clk)begin//给DATA状态接收到的数据的位数计数
if(reset)begin
data_count<=4'h0;
end
else if(next_state==DATA)begin
data_count<=data_count+4'h1;
end
else begin
data_count<=4'h0;
end
end
always @(posedge clk)begin//输出逻辑
if(next_state==STOP)
done<=1;
else
done<=0;
end
endmodule
serial receiver and datapath
这题对比上一题状态机的设计是一样的,所以直接copy过来就好。要求再添加一个8位(1字节)的数据路径out_byte用来传输(寄存)接收到的有效数据。
根据题意,out_byte是8位宽的数据传输路径,in输入一次发送的也是8位,所以out_byte恰好可以寄存一次的数据,该协议首先发送最低有效位。这里我有两种理解方法:
一、8位数据串行传输
也就是将out_byte看作一个以位为单位的移位寄存器。因为串行协议首先发送出最低有效位,最先送到out_byte的也是最低有效位,所以数据流传输方向如下(这样8位数据全部装入out_byte后最低有效位在out_byte[0],没有大小端颠倒。如果数据流是左移且最低有效位先传入,8位数据全部装入out_byte后最低有效位在out_byte[7],大小端颠倒,数据传输出现错误):
代码如下:
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output reg done
);
// Use FSM from Fsm_serial
parameter IDLE=5'b00001,START=5'b00010,DATA=5'b00100,WAIT=5'b01000,STOP=5'b10000;
reg [4:0]current_state,next_state;
reg [3:0]data_count;
always @(posedge clk)begin//主控执行逻辑
if(reset)begin
current_state<=IDLE;
end
else begin
current_state<=next_state;
end
end
always @(*)begin//状态转移逻辑
case(current_state)
IDLE:begin
if(!in)begin
next_state=START;
end
else begin
next_state=IDLE;
end
end
START:begin
next_state=DATA;
end
DATA:begin
if(data_count==8&&in==1)begin
next_state=STOP;
end
else if(data_count==8&&in==0)begin
next_state=WAIT;
end
else begin
next_state=DATA;
end
end
STOP:begin
if(!in)begin
next_state=START;
end
else begin
next_state=IDLE;
end
end
WAIT:begin
if(!in)begin
next_state=WAIT;
end
else begin
next_state=IDLE;
end
end
default:next_state=IDLE;
endcase
end
always @(posedge clk)begin
if(reset)begin
data_count<=4'h0;
end
else if(next_state==DATA)begin
data_count<=data_count+4'h1;
end
else begin
data_count<=4'h0;
end
end
always @(posedge clk)begin
if(next_state==STOP)
done<=1;
else
done<=0;
end
// New: Datapath to latch input bits.
always @(posedge clk)begin
if(reset)begin
out_byte<=8'b0;
end
else if(next_state==DATA)begin
out_byte<={in,out_byte[7:1]};//DATA状态输入的数据,串行传输寄存到out_byte中
end
else begin
out_byte<=out_byte;//没有接收有效数据,out_byte不会被更新
end
end
endmodule
一、8位数据并行传输
该协议首先发送最低有效位,DATA状态的第1个clk内,data_count为0,in寄存在out_byte[0]中,第2个clk内,data_count为1,in寄存在out_byte[1]中,后面到第8个clk同理。
out_byte段的代码改为
always @(posedge clk)begin
if(reset)begin
out_byte<=8'b0;
end
else if(next_state==DATA)begin//DATA状态输入的数据,并行传输寄存到out_byte中
out_byte[data_count]<=in;//注意不是out_byte[data_count-1]<=in;
end
else begin
out_byte<=out_byte;//没有接收有效数据,out_byte不会被更新
end
end
其实只是把out_byte段的
out_byte<={in,out_byte[7:1]};
改成了
out_byte[data_count]<=in;
(易错)注意不要写成
out_byte[data_count-1]<=in;
例:现在是START状态,data_count为0,下一clk是DATA状态第一个clk(next_state==DATA),记为DATA1。当上升沿(posedge clk)到来,从START→DATA时刻:
data_count段执行:
data_count<=data_count+4'h1
非阻塞赋值,加1后data_count变为1
同一时刻out_byte段并行执行:
out_byte[data_count]<=in;
但因为上面data_count 是非阻塞赋值,所以这一句中data_count还是旧值0,这样DATA状态第1个clk输入in装入data_count[0]
类推在DATA第8个(最后1个)clk,data_count加1变为8(满足data_count==8,下一状态转变成STOP/WAIT),输入in装入data_count[7],即DATA状态完成了8 bit输入in装入[7:0]data_count。
serial receiver with parity checking
本题在上一题的基础上进行奇偶校验的奇校验,在每个数据字节后添加一个额外的校验位,用于检测正确性(这一位用来检测传输的数据是否正确,不是真正有用的数据,所以传输给out_byte时候要丢弃这一位)
对比上一题, 需要更改的有以下几个
1.声明一个data_in中间的寄存器,存8位数据data_in[7:0]和奇校验位data_in[8],之后把data_in[7:0]传给out_byte,丢弃奇校验位
2.因为中间DATA多了一位,DATA转到WAIT或者STOP模式的判断条件从data_count==8改为data_count==9
3.写data_in数据传输逻辑(这里我写的数据并行传输)和重写out_byte段数据传输逻辑
4.注意odd位是奇校验位,odd为1说明奇校验通过,所以done=1的判断条件要有odd==1,out_byte<=data_in的判断条件要有odd==1。
module top_module(
input clk,
input in,
input reset, // Synchronous reset
output [7:0] out_byte,
output reg done
);
// Modify FSM and datapath from Fsm_serialdata
parameter IDLE=5'b00001,START=5'b00010,DATA=5'b00100,WAIT=5'b01000,STOP=5'b10000;
reg [4:0]current_state,next_state;
reg [3:0]data_count;
reg odd;
reg [8:0]data_in;
always @(posedge clk)begin//主控执行逻辑
if(reset)begin
current_state<=IDLE;
end
else begin
current_state<=next_state;
end
end
always @(*)begin//状态转移逻辑
case(current_state)
IDLE:begin
if(!in)begin
next_state=START;
end
else begin
next_state=IDLE;
end
end
START:begin
next_state=DATA;
end
DATA:begin
if(data_count==9&&in==1)begin
next_state=STOP;
end
else if(data_count==9&&in==0)begin
next_state=WAIT;
end
else begin
next_state=DATA;
end
end
STOP:begin
if(!in)begin
next_state=START;
end
else begin
next_state=IDLE;
end
end
WAIT:begin
if(!in)begin
next_state=WAIT;
end
else begin
next_state=IDLE;
end
end
default:next_state=IDLE;
endcase
end
always @(posedge clk)begin//对接收到的数据位数计数
if(reset)begin
data_count<=4'h0;
end
else if(next_state==DATA)begin
data_count<=data_count+4'h1;
end
else begin
data_count<=4'h0;
end
end
always @(posedge clk)begin
if(next_state==STOP&&odd==1)在STOP状态且校验通过才认为传输的数据正确有效,done为1
done<=1;
else
done<=0;
end
// New: Datapath to latch input bits.
always @(posedge clk)begin//data_in的数据传输逻辑
if(reset)begin
data_in<=8'b0;
end
else if(next_state==DATA)begin//DATA状态接收数据时,data_in进行数据传输
data_in<={in,data_in[8:1]};//数据串行传输
end
else begin
data_in<=data_in;//没有接收有效数据,data_in不会被更新
end
end
always @(posedge clk)begin//out_byte的数据传输逻辑
if(reset)begin
out_byte<=8'd0;
end
else if(next_state==STOP&&odd==1)begin//在STOP状态且校验通过才把data_in[7:0]赋给out_byte
out_byte<=data_in[7:0];
end
else begin
out_byte<=8'd0;
end
end
// New: Add parity checking.
parity parity_1(clk,(next_state==START),in,odd);//奇校验,进入START状态时,即开始新的1byte数据传输,odd状态复位
endmodule
如果想写数据串行传输,只需要把data_in部分的
data_in[data_count]<=in;
改为
data_in<={in,data_in[8:1]};
sequence recognitio
序列识别状态机
用摩尔状态机实现,十个状态(其中ONE到SIX状态代表检测到第几个1),一个输入in,三个输出disc、err、flag
状态转移图:
题目只是要我们识别这三种状态,其他如何丢弃等等更多细节不需要关心,所以代码如下:
module top_module(
input clk,
input reset, // Synchronous reset
input in,
output disc,
output flag,
output err);
parameter IDLE=4'd0,ONE=4'd1,TWO=4'd2,THREE=4'd3,FOUR=4'd4;
parameter FIVE=4'd5,SIX=4'd6,DISC=4'd7,FLAG=4'd8,ERROR=4'd9;
reg [3:0]current_state,next_state;
always@(posedge clk)begin
if(reset)begin
current_state<=IDLE;
end
else begin
current_state<=next_state;
end
end
always @(*)begin
case(current_state)
IDLE:next_state=in?ONE:IDLE;
ONE:next_state=in?TWO:IDLE;
TWO:next_state=in?THREE:IDLE;
THREE:next_state=in?FOUR:IDLE;
FOUR:next_state=in?FIVE:IDLE;
FIVE:next_state=in?SIX:DISC;
SIX:next_state=in?ERROR:FLAG;
DISC:next_state=in?ONE:IDLE;
FLAG:next_state=in?ONE:IDLE;
ERROR:next_state=in?ERROR:IDLE;
default:next_state=IDLE;
endcase
end
assign disc=(current_state==DISC);
assign flag=(current_state==FLAG);
assign err=(current_state==ERROR);
endmodule
Q8:design a Mealy FSM
题目描述:实现一个 Mealy 型有限状态机,该机可识别 输入x 上的序列 “101”。 FSM 有一个输出信号 z,当检测到 “101” 序列时,z被置位为 logic-1。异步低电平复位。要求状态机必须写 3 种状态。FSM 应识别重叠序列,如10101识别出两次“101”
序列识别状态机
根据题意画如下状态转移图:
状态中,S1是输入为???,S2是输入为1??,S3是输入为10?
module top_module (
input clk,
input aresetn, // Asynchronous active-low reset
input x,
output z );
parameter S1=3'b001,S2=3'b010,S3=3'b100;//S1是输入为???,S2是输入为1??,S3是输入为10?.
reg [2:0]current_state,next_state;
always @(posedge clk or negedge aresetn)begin
if(!aresetn)begin
current_state<=S1;
end
else begin
current_state<=next_state;
end
end
always @(*)begin
case(current_state)
S1:next_state=x?S2:S1;
S2:next_state=x?S2:S3;
S3:next_state=x?S2:S1;//识别重叠序列,10101中间的1既是第一个101的后一个1,也是第二个101的前一个1,所以S3状态下x为1,next_state是S2
default:next_state=S1;
endcase
end
assign z=(current_state==S3&&x==1);//代表是101序列
endmodule
Q5b:serial two's complementer(Mealy FSM)
我把Q5a和Q5b顺序反过来了,这样分析更符合逻辑更合适
本题为米利状态机,两个状态,一个输入x,一个输出z,首先是根据状态转移图无脑暴力解法
module top_module (
input clk,
input areset,
input x,
output z
);
parameter A=2'b01,B=2'b10;
reg [1:0]current_state,next_state;
always @(posedge clk or posedge areset)begin
if(areset)begin
current_state<=A;
end
else begin
current_state<=next_state;
end
end
always @(*)begin
case(current_state)
A:next_state=x?B:A;
B:next_state=B;
default:next_state=A;
endcase
end
assign z=(current_state==A&&x==1)|(current_state==B&&x==0);
endmodule
可以更深层次的思考:
正数补码是他本身,负数补码是数值位取反+1,下面我们只看负数的数值位:
原码:00110100,取反为11001011,再+1为11001100,所以负数取反还有另一种理解方式,就是从最低位数出现的第一个1的位往下的位都不变(本题100不变),往上的数值位全取反(本题00110变为11001)
本题米利状态机给的状态转移图,A状态就是低位位不变的部分,所以输出位z与输入位x相同,B状态是高位位取反的部分,所以输出位z与输入位x相反。A状态在x=1时代表从低位开始输入遇到了第一个1,再往上的位要取反了,所以变为B状态。
理解了这个意思后,我们可以有另一种输出逻辑
always@(*)begin
case(current_state)
A:z=x;
B:z=~x;
default:z=x;
endcase
end
Q5a:serial two's complementer(Moore FSM)
题目给的那个时序图是错误的,正确时序图应该是这样子
基于上一题的分析,我们可以设置本题的Moore状态机
A状态(低位位不变且输入为0)、B状态(低位位不变且输入为1)、C状态(高位位取反且输入为0)、D状态(高位位取反且输入为1),例如(该例中的数认为是负数,且只写出了数值位)
原码:00110100,补码:11001100,低3位是位不变(110),高5位是位取反(00110变为11001),这8位对应状态为CCDDCBAA
理解了这些状态的意思,画状态转移图
代码如下:
module top_module (
input clk,
input areset,
input x,
output z
);
parameter A=2'b00,B=2'b01,C=2'b10,D=2'b11;
reg [1:0]current_state,next_state;
always @(posedge clk or posedge areset)begin
if(areset)begin
current_state<=A;
end
else begin
current_state<=next_state;
end
end
always @(*)begin
case(current_state)
A:next_state=x?B:A;
B:next_state=x?D:C;
C:next_state=x?D:C;
D:next_state=x?D:C;
default:next_state=A;
endcase
end
always@(*)begin
case(current_state)
A:z=0;
B:z=1;
C:z=1;
D:z=0;
default:z=0;
endcase
end
endmodule
Q3a:FSM
A是复位状态。当s为1,下一个clk进入状态B,进入状态B就监测输入w,每3个clk输入的w有两个1一个0(101/110/011),下一clk就把z置1,时序图如下
根据题目状态转移图的提示,我稍微修改一下
用mealy状态机实现,两个输入s和w,一个输出z,四个状态(A是复位状态,B1是B状态每轮监测w输入3个clk的第1个clk,B2是B状态每轮监测w输入3个clk的第2个clk,B3是B状态每轮监测w输入3个clk的第3个clk)
状态转移图:
一个错误的写法:
module top_module (
input clk,
input reset, // Synchronous reset
input s,
input w,
output z
);
parameter A=2'b00,B1=2'b01,B2=2'b10,B3=2'b11;
reg [1:0]current_state,next_state;
reg w1,w2,w3;
always @(*)begin//状态转移逻辑
case(current_state)
A:next_state=s?B1:A;
B1:next_state=B2;
B2:next_state=B3;
B3:next_state=B1;
default:next_state=A;
endcase
end
always@(posedge clk)begin
if(reset)begin
current_state<=A;
end
else begin
current_state<=next_state;
end
end
always @(posedge clk)begin
if(reset)begin
{w1,w2,w3}<=3'b000;
end
else if(next_state==B1)begin
w1<=w?1'b1:1'b0;//寄存B1状态w的数据
end
else if(next_state==B2)begin
w2<=w?1'b1:1'b0;//寄存B2状态w的数据
end
else if(next_state==B3)begin
w3<=w?1'b1:1'b0;//寄存B3状态w的数据
end
else begin
w1<=w1;
w2<=w2;
w3<=w3;
end
end
assign z=({w1,w2,w3}==3'b011||{w1,w2,w3}==3'b101||{w1,w2,w3}==3'b110);
endmodule
看仿真时序图是这样的
根据时序图可以知道,这里把w1w2w3复位都置0,刚进入B状态,在第一个B1状态w为1所以把w1置1,第一个B2状态w为1所以把w2置1,这样满足了{w1,w2,w3}为1,下一个clk(第一个B3状态)时候就会输出z为1(监测到了{w1,w2,w3}为110,但是这个w3为0是A状态复位的默认值),这不是我们要的结果,出现错误
我们想要的是监测一轮完整B1B2B3状态(也就是三个clk),如果满足{w1,w2,w3}=110/101/011,在下一个clk(也就是下一轮的B1状态)输出z=1,所以修正assign z的输出条件,代码:
module top_module (
input clk,
input reset, // Synchronous reset
input s,
input w,
output z
);
parameter A=2'b00,B1=2'b01,B2=2'b10,B3=2'b11;
reg [1:0]current_state,next_state;
reg w1,w2,w3;
always @(*)begin//状态转移逻辑
case(current_state)
A:next_state=s?B1:A;
B1:next_state=B2;
B2:next_state=B3;
B3:next_state=B1;
default:next_state=A;
endcase
end
always@(posedge clk)begin
if(reset)begin
current_state<=A;
end
else begin
current_state<=next_state;
end
end
always @(posedge clk)begin
if(reset)begin
{w1,w2,w3}<=3'b000;
end
else if(next_state==B1)begin
w1<=w?1'b1:1'b0;//寄存B1状态w的数据
end
else if(next_state==B2)begin
w2<=w?1'b1:1'b0;//寄存B2状态w的数据
end
else if(next_state==B3)begin
w3<=w?1'b1:1'b0;//寄存B3状态w的数据
end
else begin
w1<=w1;
w2<=w2;
w3<=w3;
end
end
assign z=(current_state==B1)&&({w1,w2,w3}==3'b011||{w1,w2,w3}==3'b101||{w1,w2,w3}==3'b110);
//加了current_state==B1的条件,确保{w1,w2,w3}的值都是上一轮B1B2B3状态新得到的w数据
endmodule
Q3b:FSM
根据状态转移表写状态机(y代表现态,Y代表次态)
module top_module (
input clk,
input reset, // Synchronous reset
input x,
output z
);
parameter Y0=3'b000,Y1=3'b001,Y2=3'b010,Y3=3'b011,Y4=3'b100;
reg [2:0]current_state,next_state;
always @(posedge clk)begin
if(reset)begin
current_state<=Y0;
end
else begin
current_state<=next_state;
end
end
always @(*)begin
case(current_state)
Y0:next_state=x?Y1:Y0;
Y1:next_state=x?Y4:Y1;
Y2:next_state=x?Y1:Y2;
Y3:next_state=x?Y2:Y1;
Y4:next_state=x?Y4:Y3;
default:next_state=Y1;
endcase
end
assign z=(current_state==Y3)|(current_state==Y4);
endmodule
Q3c:FSM logic
这个题虽然给的背景是状态机,也给了clk信号,但是让实现的是组合逻辑函数Y0和z,所以本质就是组合逻辑问题
(y代表现态,Y代表次态)
module top_module (
input clk,
input [2:0] y,
input x,
output Y0,
output z
);
always @(*)begin
case(y)
3'b000:Y0=x?1:0;
3'b001:Y0=x?0:1;
3'b010:Y0=x?1:0;
3'b011:Y0=x?0:1;
3'b100:Y0=x?0:1;
default:Y0=0;
endcase
end
assign z = (y == 3'b011) | (y == 3'b100);
endmodule
第二种写法:parameter定义
module top_module (
input clk,
input [2:0] y,
input x,
output Y0,
output z
);
parameter A=3'b000,B=3'b001,C=3'b010,D=3'b011,E=3'b100;
reg [2:0]Y;
always @(*)begin
case(y)
A:Y=x?B:A;
B:Y=x?E:B;
C:Y=x?B:C;
D:Y=x?C:B;
E:Y=x?E:D;
default:Y=A;
endcase
end
assign Y0=Y[0];
assign z = (y==D)|(y==E);
endmodule
Q6b:FSM next_state logic
本题题目要求用y[3:1]=000,001,010,011,100,101分别代表A,B,C,D,E,F状态,根据状态转移图作状态转移表
代码如下:
module top_module (
input [3:1] y,
input w,
output Y2);
parameter A=3'b000,B=3'b001,C=3'b010,D=3'b011,E=3'b100,F=3'b101;
reg [3:1]Y;
always @(*)begin
case(y)
A:Y=w?A:B;
B:Y=w?D:C;
C:Y=w?D:E;
D:Y=w?A:F;
E:Y=w?D:E;
F:Y=w?D:C;
default:Y=A;
endcase
end
assign Y2=Y[2];
endmodule
Q6c:FSM one-hot next-state logic
可参考题目:Fsm3onehot - HDLBits (01xz.net)
Fsm onehot - HDLBits (01xz.net)
本题状态转移逻辑和上一题相同,状态转移图也相同。题目要求用独热码来编码,用y[6:1]=000001,000010,000100,001000,010000,100000代表A,B,C,D,E,F状态。
状态转移表和上题相同,但编码不同(本题用独热码),要求通过独热编码来检查推导出状态转换逻辑和输出逻辑(组合逻辑部分)。
module top_module (
input [6:1] y,
input w,
output Y2,
output Y4);
parameter A=6'b000001,B=6'b000010,C=6'b000100,D=6'b001000,E=6'b010000,F=6'b100000;
reg [6:1]Y;
always @(*)begin
case(y)
A:Y=w?A:B;
B:Y=w?D:C;
C:Y=w?D:E;
D:Y=w?A:F;
E:Y=w?D:E;
F:Y=w?D:C;
default:Y=A;
endcase
end
assign Y2=(y[1]&~w);
assign Y4=(y[2]&w)|(y[3]&w)|(y[5]&w)|(y[6]&w);
endmodule
Q6:FSM
按照状态转移图写状态机即可
module top_module (
input clk,
input reset, // synchronous reset
input w,
output z);
parameter A=6'b000001,B=6'b000010,C=6'b000100,D=6'b001000,E=6'b010000,F=6'b100000;
reg [5:0]current_state,next_state;
always @(posedge clk)begin
if(reset)begin
current_state<=A;
end
else begin
current_state<=next_state;
end
end
always @(*)begin
case(current_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
assign z=(current_state==E)||(current_state==F);
endmodule
Q2a:FSM
按照状态转移图写状态机即可
module top_module (
input clk,
input reset, // synchronous reset
input w,
output z);
parameter A=6'b000001,B=6'b000010,C=6'b000100,D=6'b001000,E=6'b010000,F=6'b100000;
reg [5:0]current_state,next_state;
always @(posedge clk)begin
if(reset)begin
current_state<=A;
end
else begin
current_state<=next_state;
end
end
always @(*)begin
case(current_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
assign z=(current_state==E)|(current_state==F);
endmodule
Q2b:one-hot FSM equations
可参考:Fsm3onehot - HDLBits (01xz.net)
Fsm onehot - HDLBits (01xz.net)
Exams/m2014 q6c - HDLBits (01xz.net)
本题状态转移图(逻辑)和上一题一样。另外本题其实和上面Q6c是一种题,只是状态转换逻辑不一样,本质思路是一样的,换汤不换药。
要求通过独热编码来检查推导出状态转换逻辑和输出逻辑(组合逻辑部分)。
状态转移表:
代码:
module top_module (
input [5:0] y,
input w,
output Y1,
output Y3
);
parameter A=6'b000001,B=6'b000010,C=6'b000100,D=6'b001000,E=6'b010000,F=6'b100000;
reg [5:0]Y;
always @(*)begin
case(y)
A:Y=w?B:A;
B:Y=w?C:D;
C:Y=w?E:D;
D:Y=w?F:A;
E:Y=w?E:D;
F:Y=w?C:D;
default:Y=A;
endcase
end
assign Y1=(y[0]&w);
assign Y3=(y[1]&~w)|(y[2]&~w)|(y[4]&~w)|(y[5]&~w);
endmodule
Q2a:FSM
FSM 充当仲裁电路,它控制对某种类型资源的访问。每个设备通过设置请求信号r[i] = 1 来请求资源。 设备1、设备2、设备3的r[i] 分别是r[1] 、r[2] 、r[3],对应状态B、C、D。只要没有请求,FSM 就会保持状态A。当一个或多个请求发生,则 FSM 决定哪个设备优先使用资源,并且将该设备的g[i]信号设置为 1 。其中资源分配优先级:设备1>设备2>设备3
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,B=4'b0010,C=4'b0100,D=4'b1000;
reg[3:0]current_state,next_state;
always @(posedge clk)begin
if(!resetn)begin
current_state<=A;
end
else begin
current_state<=next_state;
end
end
always @(*)begin
case(current_state)
A:begin
casez(r) //请求优先级r1>r2>r3
3'bzz1:next_state=B;
3'bz10:next_state=C;
3'b100:next_state=D;
3'b000:next_state=A;
default:next_state=A;
endcase
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:next_state=A;
endcase
end
assign g[1]=(current_state==B);
assign g[2]=(current_state==C);
assign g[3]=(current_state==D);
endmodule
Q2b:another FSM
题目描述:有两个输入x和y,两个输出f和g,resetn是同步低电平复位,复位置在A状态,当复位信号无效时,下一个clk把f置为1保持(保持为1的时间为一个clk),f为1的clk之后监测x值。当监测到连续三个clk 输入x的序列为“101”时,下一个clk把g置为1同时开始监测y,从开始监测算起如果两个clk内出现y=1,就把g永远置1(除非复位resetn),否则把g永远置0(除非复位resetn)
分析:有两个输入x和y,两个输出f和g,设置9个状态,状态转移图如下:
A状态是默认状态(复位到的状态),F是f=1的状态(维持一个clk),之后监测x,S1是x序列为???,S2是x序列为1??,S3是x序列为10?,x序列为101进入SS1状态开始监测y,SS1是监测y的第1个clk,SS2是监测y的第2个clk,FOREVER_1代表g永远为1的状态,FOREVER_0代表g永远为0的状态
module top_module (
input clk,
input resetn, // active-low synchronous reset同步低电平复位
input x,
input y,
output f,
output g
);
parameter A=4'b0000,F=4'b0001,S1=4'b0010,S2=4'b0011,S3=4'b0100;
parameter SS1=4'b0101,SS2=4'b0110,FOREVER_1=4'b0111,FOREVER_0=4'b1000;
reg [3:0]current_state,next_state;
//状态转移逻辑
always @(*)begin
case(current_state)
A:next_state=F;
F:next_state=S1;
S1:next_state=x?S2:S1;
S2:next_state=x?S2:S3;
S3:next_state=x?SS1:S1;
SS1:next_state=y?FOREVER_1:SS2;
SS2:next_state=y?FOREVER_1:FOREVER_0;
FOREVER_1:next_state=FOREVER_1;//除非复位,g永远为1
FOREVER_0:next_state=FOREVER_0;//除非复位,g永远为0
default:next_state=A;
endcase
end
//状态执行逻辑
always @(posedge clk)begin
if(!resetn)begin
current_state<=A;
end
else begin
current_state<=next_state;
end
end
//输出逻辑
assign f=(current_state==F);
always @(*)begin
case(current_state)
SS1:g=1;
SS2:g=1;
FOREVER_1:g=1;
default:g=0;
endcase
end
endmodule
buliding lager circuits
counter with period 1000
module top_module (
input clk,
input reset,
output reg[9:0] q);
always @(posedge clk)begin
if(reset)
q<=10'd0;
else if(q==10'd999)
q<=10'd0;
else
q<=q+10'd1;
end
endmodule
4-bit shift register and down counter
本题是移位寄存器和递减计数器的结合
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)begin
q<={q[2:0],data};
end
else if(count_ena==1)begin//q为4'b0000了还可以继续减1,向下溢出为4'b1111
q<=q-4'b1;
end
else begin
q<=q;
end
end
endmodule
FSM:sequence 1101 recognizer
序列识别状态机
一个输入data,一个输出start_shifting,五个状态(S1代表data序列为????,S2代表data序列为1???,S3代表data序列为11??,S4代表data序列为110?,当识别到序列1101后,进入START_SHIFT_1状态,表示start_shifting为1)
状态转移图
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output start_shifting);
parameter S1=3'b000,S2=3'b001,S3=3'b010,S4=3'b011,START_SHIFT_1=3'b100;
reg [2:0]current_state,next_state;
always @(*)begin
case(current_state)
S1:next_state=data?S2:S1;
S2:next_state=data?S3:S1;
S3:next_state=data?S3:S4;
S4:next_state=data?START_SHIFT_1:S1;
START_SHIFT_1:next_state=START_SHIFT_1;//识别到1101序列后,start_shifting 永远为1
default:next_state=S1;
endcase
end
always @(posedge clk)begin
if(reset)begin
current_state<=S1;
end
else begin
current_state<=next_state;
end
end
assign start_shifting=(current_state==START_SHIFT_1);
endmodule
FSM:enable with register
本题是用reset信号控制shift_ena的状态机。
看时序图,reset为1,下一个clk进入复位到的IDLE状态,把shift_ena置1,当reset为0后,shift_ena保持为1四个clk(第一个clk还在IDLE状态,后面三个clk分别在SHIFT_ENA_2、SHIFT_ENA_3、SHIFT_ENA_4状态),再之后shift_ena永远为0(除非reset复位)
设置状态机,一个输入reset,一个输出shift_ena,五个状态IDLE(复位到的状态)、SHIFT_ENA_2(reset为0后shift_ena保持为1的第2个clk)、SHIFT_ENA_3(reset为0后shift_ena保持为1的第3个clk)、SHIFT_ENA_4(reset为0后shift_ena保持为1的第4个clk)和FOREVER_0(shift_ena永远为0的状态)
状态转移图:
module top_module (
input clk,
input reset, // Synchronous reset
output shift_ena);
parameter IDLE=3'b000,SHIFT_ENA_2=3'b001,SHIFT_ENA_3=3'b010;
parameter SHIFT_ENA_4=3'b011,FOREVER_0=3'b100;
reg [2:0]current_state,next_state;
always@(*)begin
case(current_state)
IDLE:next_state=SHIFT_ENA_2;
SHIFT_ENA_2:next_state=SHIFT_ENA_3;
SHIFT_ENA_3:next_state=SHIFT_ENA_4;
SHIFT_ENA_4:next_state=FOREVER_0;
FOREVER_0:next_state=FOREVER_0;
default:next_state=IDLE;
endcase
end
always@(posedge clk)begin
if(reset)begin
current_state<=IDLE;
end
else begin
current_state<=next_state;
end
end
always@(*)begin
case(current_state)
IDLE:shift_ena=1;
SHIFT_ENA_2:shift_ena=1;
SHIFT_ENA_3:shift_ena=1;
SHIFT_ENA_4:shift_ena=1;
FOREVER_0:shift_ena=0;
default:shift_ena=0;
endcase
end
endmodule
FSM:the complete FSM
题目:要实现一个计时器(结合时序图来看)
1.当接收到data输入的“1101”序列就启动计时器开始工作,之后4个clk将shift_ena置1
2.shift_ena置1保持4个clk后开始计数(counting),等待接收到done_counting为1(通知计时器计时完成)就停止计数
3.停止计时后(done置1表示计时器计时完成)进入等待状态,等待用户确认,当用户确认后返回ack为1,计时器就从done为1的完成工作状态回到最初状态。
但本题只要实现控制计时器的有限状态机。不包括 data path (counters 和一些 comparators)
输入有data、done_counting、ack,输出有shift_ena、counting、done,设置了十个状态。
S状态(data输入序列为“????”)、S1状态(data输入序列为“1???”)、S11状态(data输入序列为“11??”)、S110状态(data输入序列为“110?”)、data输入序列为“1101”进入B0状态(shift_ena为1的第1个clk)、B1状态(shift_ena为1的第2个clk)、B2状态(shift_ena为1的第3个clk)、B3状态(shift_ena为1的第4个clk),COUNT状态(计时状态)、WAIT(完成计时工作等待用户确认状态)
状态转移图:
代码:
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output shift_ena,//移位使能信号
output counting,//为1表示计时器计时状态
input done_counting,//计时器接收到该信号停止计时
output done,//为1表示整个计时工作完成在等待状态
input ack );//表示用户确认的信号
parameter S=4'b0000,S1=4'b0001,S11=4'b0010,S110=4'b0011,B0=4'b0100;
parameter B1=4'b0101,B2=4'b0110,B3=4'b0111,COUNT=4'b1000,WAIT=4'b1001;
reg [3:0]current_state,next_state;
//状态转移逻辑
always@(*)begin
case(current_state)
S:next_state=data?S1:S;
S1:next_state=data?S11:S;
S11:next_state=data?S11:S110;
S110:next_state=data?B0:S;
B0:next_state=B1;
B1:next_state=B2;
B2:next_state=B3;
B3:next_state=COUNT;
COUNT:next_state=done_counting?WAIT:COUNT;
WAIT:next_state=ack?S:WAIT;
default:next_state=S;
endcase
end
//状态执行逻辑
always@(posedge clk)begin
if(reset)begin
current_state<=S;
end
else begin
current_state<=next_state;
end
end
//输出逻辑
always@(*)begin
case(current_state)
B0:shift_ena=1;
B1:shift_ena=1;
B2:shift_ena=1;
B3:shift_ena=1;
default:shift_ena=0;
endcase
end
assign counting=(current_state==COUNT);
assign done=(current_state==WAIT);
endmodule
the complete timer
这个题是对前面五道题的综合,所以难度也很高
题目:要实现一个计时器(要结合时序图来看,另外本题的[3:0]delay和[3:0]count是一个东西,这里作者写的乱糟糟的,在题干描述写的delay变量,时序图和给的module配置输出写的count)
1.当接收到data输入的“1101”序列就启动计时器开始工作,之后4个clk将4位data输入移动到count中(通过移位实现)
2.移位完成后开始计时,根据count的值之后计时(count+1)×1000个clk。
3.计时完成后停止计时(把done置1表示计时器计时完成),进入计时完成等待状态,并等待用户确认,当用户确认后返回ack为1,计时器就从done为1的完成工作状态回到最初状态。
计时器的计时逻辑:计时分为(count+1)个大周期,每个周期里面有1000个clk,我们要输出每个大周期内剩余的clk(题目output没给,要自己设置)。其实要计时的周期数就是{count,remain-time},remain-time可以看作低三位(个十百位),count看作更高的千和万位。
计时器有两个输入:data(输入数据)、ack(用户返回的确认信号)
三个输出:count(表示计时当前处在哪个大周期)、counting(为1表示在计时状态)、done(为1表示计时工作完成在等待状态)
我设置了几个中间变量:shift_ena(移位使能信号,为1表示在移位状态,将data移入count)、done_counting(计时器接收到该信号停止计时)、remain_time(每个大周期中当前剩余的clk,可能的取值从999到0)
状态转移逻辑和上一题相同:
代码:
module top_module (
input clk,
input reset, // Synchronous reset
input data,
output [3:0] count,//表示计时的大周期数
output counting,//为1表示在计时状态
output done,//为1表示计时工作完成在等待状态
input ack );//用户返回的确认信号
//控制计时器计时的状态机
parameter S=4'b0000,S1=4'b0001,S11=4'b0010,S110=4'b0011,B0=4'b0100;
parameter B1=4'b0101,B2=4'b0110,B3=4'b0111,COUNT=4'b1000,WAIT=4'b1001;
reg [3:0]current_state,next_state;
wire shift_ena;//移位使能信号,为1时将“1101”后面4个clk的data移入count中
wire done_counting;//计时器接收到该信号停止计时
reg [9:0]remain_time;//每个大周期中当前剩余的clk,可能的取值从999到0
//状态转移逻辑
always@(*)begin
case(current_state)
S:next_state=data?S1:S;
S1:next_state=data?S11:S;
S11:next_state=data?S11:S110;
S110:next_state=data?B0:S;
B0:next_state=B1;
B1:next_state=B2;
B2:next_state=B3;
B3:next_state=COUNT;
COUNT:next_state=done_counting?WAIT:COUNT;
WAIT:next_state=ack?S:WAIT;
default:next_state=S;
endcase
end
//状态执行逻辑
always@(posedge clk)begin
if(reset)begin
current_state<=S;
end
else begin
current_state<=next_state;
end
end
always@(*)begin//移位使能shift_ena有效的触发条件
case(current_state)
B0:shift_ena=1;
B1:shift_ena=1;
B2:shift_ena=1;
B3:shift_ena=1;
default:shift_ena=0;
endcase
end
always@(posedge clk)begin//remain_time的转换逻辑
if(reset)begin
remain_time<=10'd0;
end
else if(counting==1'b1&&remain_time==10'd0)begin//如果remain_time计到0后面还有计时大周期,remain_time回到999计下一个大周期的剩余clk;如果后面没有大周期remain_time就没有意义了,将remain_time保持在默认值,本题默认值我也设置在999,所以这里不需要区分后面是不是还有大计数周期,只要remain_time到0了下一个clk就会回到999
remain_time<=10'd999;
end
else if(counting==1'b1)begin
remain_time<=remain_time-10'd1;
end
else begin
remain_time<=10'd999;//默认remain_time置在10'd999,保证了刚进入计时状态时remain_time的数值就是正确的
end
end
//输出逻辑
always@ (posedge clk)begin//count的转换逻辑
if(reset)begin
count<=4'd0;
end
else if(shift_ena)begin//移位状态(4个clk)把4位的data赋给[3:0]count
count<={count[2:0],data};
end
else if(counting)begin//计时状态,count递减到0
count<=(remain_time==10'd0)?count-4'd1:count;
end
else begin
count<=count;
end
end
assign done_counting=(remain_time==10'b0&&count==4'd0);
assign counting=(current_state==COUNT);//
assign done=(current_state==WAIT);
endmodule
FSM:one-hot logic equations
给定独热编码:(S, S1, S11, S110, B0, B1, B2, B3, Count, Wait) = (10'b0000000001, 10'b0000000010, 10'b0000000100, ... , 10'b1000000000)
要求通过独热编码来检查推导出状态转换逻辑和输出逻辑(组合逻辑部分)。
这种题目前面遇到很多遍了:Fsm3onehot - HDLBits (01xz.net)
Exams/m2014 q6c - HDLBits (01xz.net)
Exams/2012 q2b - HDLBits (01xz.net)
module top_module(
input d,
input done_counting,
input ack,
input [9:0] state, // 10-bit one-hot current state
output B3_next,
output S_next,
output S1_next,
output Count_next,
output Wait_next,
output done,
output counting,
output shift_ena
); //
// You may use these parameters to access state bits using e.g., state[B2] instead of state[6].
parameter S=0, S1=1, S11=2, S110=3, B0=4, B1=5, B2=6, B3=7, Count=8, Wait=9;
assign B3_next=state[B2];
assign S_next=(state[S]&~d)|(state[S1]&~d)|(state[S110]&~d)|(state[Wait]&ack);
assign S1_next=(state[S]&d);
assign Count_next=(state[B3])|(state[Count]&~done_counting);
assign Wait_next=(state[Count]&done_counting)|(state[Wait]&~ack);
assign done=state[Wait];
assign counting=state[Count];
assign shift_ena=state[B0]|state[B1]|state[B2]|state[B3];
endmodule
到这里状态机的部分就算结束了,从上手做hdlbits状态机题目到后来整理错题纠正错误,然后编写这篇超长的文章,前前后后花了12天的时间,几乎花了我刷整个hdlbits一半的时间(一共花了25天左右),不过这个硬骨头终于是啃下来了,状态机的部分就告一段落了。