
根据状态转移写状态机-三段式三段式状态机是 FPGA/Verilog 中推荐的状态机写法把“状态寄存器、次态逻辑、输出逻辑”分开描述使结构清晰、便于综合和调试。三段划分段 描述内容 常用逻辑类型第一段 当前状态寄存器current_state next_state 时序逻辑非阻塞赋值第二段 次态逻辑根据 current_state 和输入计算 next_state 组合逻辑阻塞赋值第三段 输出逻辑根据状态/输入产生输出 组合逻辑或时序逻辑工程上更稳妥的写法是第三段输出也寄存一拍即“状态寄存 次态组合 输出寄存”可避免组合输出毛刺。通用三段式模板modulefsm_3seg(input wire clk,input wire rst_n,input wire in,output reg out);// 状态编码localparam S_IDLE2b00,S_S12b01,S_S22b10;reg[1:0]current_state,next_state;// 第一段状态寄存器。时序逻辑描述状态转移always (posedge clk or negedge rst_n)beginif(!rst_n)current_stateS_IDLE;elsecurrent_statenext_state;end// 第二段次态组合逻辑。组合逻辑根据输入和当前状态描述下一个状态--状态转移always (*)begin next_statecurrent_state;// 默认保持防止 latchcase(current_state)S_IDLE:beginif(in)next_stateS_S1;elsenext_stateS_IDLE;end S_S1:beginif(in)next_stateS_S2;elsenext_stateS_IDLE;end S_S2:begin next_stateS_IDLE;enddefault:next_stateS_IDLE;endcase end// 第三段输出逻辑这里用时序寄存输出。组合逻辑或时序逻辑描述各个状态变量的输出。always (posedge clk or negedge rst_n)beginif(!rst_n)out1b0;elsebegincase(next_state)// 注意若希望输出与次态同拍用 next_stateS_S2:out1b1;default:out1b0;endcase end end endmodule如果第三段用组合逻辑输出则写成always (*)begin out1b0;case(current_state)S_S2:out1b1;default:out1b0;endcase end注意第三段什么时候使用现态什么时候使用次态。三段式状态机的优点结构清晰状态转移和输出分离代码可读性好。易于维护增加状态或修改输出时影响范围小。综合结果稳定避免把次态和输出混在一个 always 块中导致综合歧义。便于验证可以单独观察 current_state、next_state 和输出。寄存输出可消毛刺适合驱动使能、握手、中断等信号。常见注意事项第一段必须用非阻塞赋值 。第二段组合逻辑用阻塞赋值 且 case 要有 default否则易生成 latch。状态编码可用 localparam不要用宏或魔法数字。复位建议异步复位、同步释放至少保证状态机有明确初态。对非法状态default 应回到安全状态提高可靠性。Moore 输出只与状态有关Mealy 输出还与输入有关。三段式对两者都适用但 Mealy 输出对输入毛刺更敏感通常建议寄存。若第三段用时序输出注意输出相对状态晚一拍需要同拍输出时可用 next_state 判断但要仔细分析时序。高速设计可考虑独热码面积敏感可用二进制码跨时钟域传递状态需额外同步处理。与两段式、一段式的区别一段式所有逻辑写在一个时序 always 块中简单状态机可用但状态一多就难维护。两段式第一段状态寄存第二段把次态和输出都写成组合逻辑输出可能有毛刺。三段式状态寄存、次态组合、输出逻辑分开若输出寄存则最稳健是工程中常用的推荐写法。一句话总结三段式状态机 状态寄存一段 次态组合一段 输出一段工程上优先采用“状态寄存 次态组合 输出寄存”的形式。题目描述如图所示为两种状态机中的一种请根据状态转移图写出代码状态转移线上的0/0等表示的意思是过程中data/flag的值。要求1、 必须使用对应类型的状态机2、 使用三段式描述方法输出判断要求要用到对现态的判断注意rst为低电平复位信号示意图timescale 1ns/1ns module fsm1( input wire clk , input wire rst , input wire data , output reg flag ); //*************code***********// parameter s0 4b0001; parameter s1 4b0010; parameter s2 4b0100; parameter s3 4b1000; reg[3:0] c_state,n_state; always(posedge clk or negedge rst) begin if(!rst) c_state s0; else c_state n_state; end always(*) begin case(c_state) s0:begin if(data 1b1) n_state s1; else n_state s0; end s1:begin if(data 1b1) n_state s2; else n_state s1; end s2:begin if(data 1b1) n_state s3; else n_state s2; end s3:begin if(data 1b1) n_state s0; else n_state s3; end default:n_state s0; endcase end always(posedge clk or negedge rst) begin if(!rst) flag 1b0; else if(c_state s3 data 1b1) flag 1b1; else flag 1b0; end //*************code***********// endmodule