Verilog学习笔记简单功能实现(三)...............同步有限状态机
在Verilog中可以采用多种方法来描述有限状态机最常见的方法就是用always和case语句。如下图所示的状态转移图就表示了一个简单的有限状态机:
图中:图表示了一个四状态的状态机,输入为A和Reset,同步时钟为clk,输出信号是K1和K2,状态机只能在信号的上升沿发生。
(A)下面是可综合的Verilog模块设计状态机的典型方法:(格雷码表示状态)
1 module fsm(A,Reset,K2,K1,clk,state); 2 input A,Reset,clk; 3 output K2,K1; 4 output [1:0]state; 5 reg K2,K1; 6 reg [1:0]state; 7 parameter Idel=2'b00, 8 start=2'b01, 9 stop=2'b10, 10 clear=2'b11; 11 always @(posedge clk) 12 if (!Reset) 13 begin 14 state<=Idel; 15 K2<=0; 16 K1<=0; 17 end 18 else 19 case(state) 20 Idel:if (A) 21 begin 22 state<=start; 23 K1<=0; 24 end 25 else 26 begin 27 state<=Idel; 28 K2<=0; 29 K1<=0; 30 end 31 start:if(!A) state<=stop; 32 else state<=start; 33 stop: if(A) 34 begin 35 state<=clear; 36 K2<=1; 37 end 38 else 39 begin 40 state<=stop; 41 K2<=0; 42 K1<=0; 43 end 44 clear:if(!A) 45 begin 46 state<=Idel; 47 K2<=0; 48 K1<=1; 49 end 50 else 51 begin 52 state<=clear; 53 K2<=0; 54 K1<=0; 55 end 56 default:state<=2'bxx; 57 endcase 58 endmodule
(B)用可以综合的Verilog模块设计、用独热码表示状态的状态机
独热码,在英文文献中称做 one-hot code, 直观来说就是有多少个状态就有多少比特,而且只有一个比特为1,其他全为0的一种码制。
1 module fsm(A,Reset,K2,K1,clk,state); 2 input A,Reset,clk; 3 output K2,K1; 4 output [3:0]state; 5 reg K2,K1; 6 reg [3:0]state; 7 parameter Idel=4'b1000, 8 start=4'b0100, 9 stop=4'b0010, 10 clear=4'b0001; 11 always @(posedge clk) 12 if (!Reset) 13 begin 14 state<=Idel; 15 K2<=0; 16 K1<=0; 17 end 18 else 19 case(state) 20 Idel:if (A) 21 begin 22 state<=start; 23 K1<=0; 24 end 25 else 26 begin 27 state<=Idel; 28 K2<=0; 29 K1<=0; 30 end 31 start:if(!A) state<=stop; 32 else state<=start; 33 stop: if(A) 34 begin 35 state<=clear; 36 K2<=1; 37 end 38 else 39 begin 40 state<=stop; 41 K2<=0; 42 K1<=0; 43 end 44 clear:if(!A) 45 begin 46 state<=Idel; 47 K2<=0; 48 K1<=1; 49 end 50 else 51 begin 52 state<=clear; 53 K2<=0; 54 K1<=0; 55 end 56 default:state<=Idel; 57 endcase 58 endmoduleView Code
二进制编码、格雷码编码使用最少的触发器,消耗较多的组合逻辑,而独热码编码反之。独热码编码的最大优势在于状态比较时仅仅需要比较一个位,从而一定程度上简化了译码逻辑。虽然在需要表示同样的状态数时,独热编码占用较多的位,也就是消耗较多的触发器,但这些额外触发器占用的面积可与译码电路(组合电路)省下来的面积相抵消。并且采用独热码可以使电路的速度和可靠性有显著提高,而总的单元数并无增加。
(C)用可以综合的Verilog模块设计,用状态码直接作为输出
1 module fsm(A,Reset,K2,K1,clk,state); 2 input A,Reset,clk; 3 output K2,K1; 4 output [4:0]state; 5 reg [4:0]state; 6 assign K2=state[4]; 7 assign K1=state[0]; 8 parameter Idel = 5'b0_000_0, 9 start = 5'b0_010_0, 10 stop = 5'b0_010_0, 11 stoptoclear=5'b1_100_0, 12 clear = 5'b0_101_0, 13 cleartoIdel=5'b0_011_1; 14 always @(posedge clk) 15 if (!Reset) 16 begin 17 state<=Idel; 18 end 19 else 20 case(state) 21 Idel: if (A) state<=start; 22 else state<=Idel; 23 start:if(!A) state<=stop; 24 else state<=start; 25 stop: if(A) state<=stoptoclear; 26 else state<=stop; 27 stoptoclear: state<=clear; 28 clear:if(!A) state<=cleartoIdel; 29 else state<=clear; 30 cleartoIdel: state<=Idel; 31 default:state<=Idel; 32 endcase 33 endmoduleView Code
利用状态机的状态直接作为输出可以提升信号的开关速度并节省电路器件,但是开关的维持时间必须与状态的维持时间一致,如果要实现上述的例子必须增加状态才能实现。
在这里state[4],state[0]分别表示前面的K2和K1。
(D)用可以综合的Verilog模块设计,设计复杂多输出状态机时常用的方法
1 module fsm(A,Reset,K2,K1,clk,state); 2 input A,Reset,clk; 3 output K2,K1; 4 output [1:0]state; 5 reg K2,K1; 6 reg [1:0]state,nextstate; 7 parameter Idel = 2'b00, 8 start = 2'b01, 9 stop = 2'b10, 10 clear = 2'b11; 11 always @(posedge clk) //没一个时钟沿产生一次可能的变化 12 if (!Reset) 13 state<=Idel; 14 else 15 state<=nextstate; 16 always @(posedge clk or A) //产生下一状态的组合逻辑F 17 case(state) 18 Idel: if (A) nextstate=start; 19 else nextstate=Idel; 20 start:if(!A) nextstate=stop; 21 else nextstate=start; 22 stop: if(A) nextstate=clear; 23 else nextstate=stop; 24 clear:if(!A) nextstate=Idel; 25 else nextstate=clear; 26 default: nextstate=2'bxx; 27 endcase 28 always @(posedge clk or Reset or A) //产生输出K1的组合逻辑 29 if(!Reset) K1=0; 30 else if(state==clear&&!A) K1=1; //由clear转向Idel,因为state为非阻塞赋值,所以此时state的状态还是clear 31 else K1=0; 32 always @(posedge clk or Reset or A) //产生输出K2的组合逻辑 33 if(!Reset) K2=0; 34 else if(state==stop&&A) K2=1; //由stop转向clear,因为state为非阻塞赋值,所以此时state的状态还是stop 35 else K2=0; 36 endmoduleView Code
在比较复杂的状态机设计过程中,往往把状态的变化与输出开关的控制分为两部分,就像前面的Mealy型状态机输出部分的组合逻辑一样。为了调试方便还将每一个输出的开关写成一个个的独立的always块以方便调试。在设计复杂的多输出状态及时建议采用这种方法。