[TOC]
1:三段式状态机基本格式:
- 第一个always语句实现同步状态跳转;
- 第二个always语句采用组合逻辑判断状态转移条件,这里每一个状态只保持一个时钟周期,也就是直接跳转到下一个状态,在实际应用中,一般根据输入的条件来判断是否跳转到其它状态或者停留在当前转态;
- 第三个always语句描述状态输出(可以用组合电路输出,也可以时序电路输出。一般推荐使用时序电路输出,因为状态机的设计和其它设计一样,最好使用同步时序方式设计,以提高设计的稳定性,消除毛刺
2:代码部分
通过parameter来定义各个不同状态的参数。每一个状态的位宽为7位,接下来还需要定义两个7位的寄存器,一个用来表示当前状态,另一个用来表示下一个状态,如下所示:
定义部分:
1 2 3 4 5 6 7 8 9 10 11 12 13
| //独热码定义方式 parameter S0 = 7'b0000001; parameter S1 = 7'b0000010; parameter S2 = 7'b0000100; parameter S3 = 7'b0001000; parameter S4 = 7'b0010000; parameter S5 = 7'b0100000; parameter S6 = 7'b1000000;
//reg define reg [6:0] curr_st ; //当前状态 reg [6:0] next_st ; //下一状态
|
实现代码1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| 另有写法: always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) curr_st <= S0; else curr_st <= next_st; end
常用写法: always @(*) begin case (curr_st) S0: next_st = S1; S1: next_st = S2; S2: next_st = S3; S3: next_st = S4; S4: next_st = S5; S5: next_st = S6; S6: next_st = S0; default: next_st = S0; endcase end
对应常用写法: always @(posedge sys_clk or negedge sys_rst_n) begin if (!sys_rst_n) clk_divide_7 <= 1'b0; else if ((curr_st == S0) | (curr_st == S1) | (curr_st == S2) | (curr_st == S3)) clk_divide_7 <= 1'b0; else if ((curr_st == S4) | (curr_st == S5) | (curr_st == S6)) clk_divide_7 <= 1'b1; end
|
实现代码2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| 另有写法: always @(posedge sys_clk or negedge sys_rst_n) if (!sys_rst_n) curr_st <= (1‘b1 << S0); else curr_st <= next_st;
always @(*) begin next_st = curr_st; case (1'b1) curr_st[S0]: next_st = 1'b1 << S1; curr_st[S1]: next_st = 1'b1 << S2; curr_st[S2]: next_st = 1'b1 << S3; curr_st[S3]: next_st = 1'b1 << S4; curr_st[S4]: next_st = 1'b1 << S5; curr_st[S5]: next_st = 1'b1 << S6; curr_st[S6]: next_st = 1'b1 << S0; default: next_st = 1'b1 << S0; endcase end
对应常用写法: always @(posedge sys_clk or negedge sys_rst_n) if (!sys_rst_n) clk_divide_7 <= 1'b0; else if (curr_st[S0] | curr_st[S1]) | curr_st[S2] | curr_st[S3]) clk_divide_7 <= 1'b0; else if (curr_st[S4] | curr_st[S5]) | curr_st[S6]) clk_divide_7 <= 1'b1;
|
Verilog 中的 always @ (*) begin 是一种用于编写时序逻辑的语句。它表示无论在什么时候,如果任意输入变量发生变化,就立即执行 begin 和 end 之间的语句。这种类型的 always语句通常用于实现输入变量与输出变量之间的映射关系。