|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
先说明一下常见的状态机写法:
2段式:一个时序逻辑,一个组合逻辑(状态跳转和决定输出)。
3段式:2个时序逻辑,一个组合逻辑控制状态跳转。
最近在看到他人的代码的时候,对有些状态机的写法还不是很明了,上来求教一下大家.
always @(posedge clk or negedge rst_n)
begin : TX_STAT_UPDATE
if (~rst_n) begin
rStatTxCur <= TX_IDLE;
rPlsStatChanged <= 1'b0;
end
else begin
rStatTxCur <= rStatTxNext; // 更新当前发送器的状态机状态
rPlsStatChanged <= (rStatTxCur != rStatTxNext);
end
end
/*********************************************************************************************************
** 根据多个信号和当前状态机的状态, 判断发送器状态机的下一个状态
**
** [特别注意]:
** 状态值使用OneHot编码, 而这种编码一般会优为移位寄存器, 为了防止状态出现00000的情况(如时钟质量差),
** 在综合器中要设置'safe stat mechine = on'(安全状态机)
********************************************************************************************************/
always @(
rPlsBaudTick or
wFlgTxStart or
rStatTxCur or
rTxClkCnt or
rTxBitCnt or
wDatWid or
wFlgParEn or
wFlgParMod or
clk_en or
wStopBits or
enable
)
begin : TX_NEXT_STAT_JUDGE
case (rStatTxCur) // 根据当前状态机的状态, 判断输入信号, 得
// 到发送器状态机的下一个状态
TX_IDLE: begin
if (wFlgTxStart && enable) // 当模块端口的发送数据标志有效, 则启动发送事件
rStatTxNext <= TX_READY;
else
rStatTxNext <= TX_IDLE;
end
TX_READY: begin
if (clk_en) begin // 同步UART时钟
rStatTxNext <= TX_START; // 进入发送器状态机的发送起始位状态
end
else begin
rStatTxNext <= TX_READY;
end
end
TX_START: begin
if (rPlsBaudTick) // 持续一个波特位, 进入帧的数据位状态
rStatTxNext <= TX_DATA;
else
rStatTxNext <= TX_START;
end
TX_DATA:
begin
if ( (rTxBitCnt == wDatWid) && (rPlsBaudTick) ) begin // 当逐位发送完帧格式设置的位数后, 进入下一状态
if (wFlgParEn)
rStatTxNext <= TX_PARITY; // 如果使能校验位, 则进入校验状态
else
rStatTxNext <= TX_STOP1; // 否则进入停止位状态
end
else begin
rStatTxNext <= TX_DATA;
end
end
TX_PARITY: begin
if (rPlsBaudTick)
rStatTxNext <= TX_STOP1; // 持续一个波特位后, 进入停止位状态
else
rStatTxNext <= TX_PARITY;
end
TX_STOP1: begin
if (rPlsBaudTick) begin
if (wStopBits) // 如果设置了2个停止位, 则再进入停止位
rStatTxNext <= TX_STOP2;
else
rStatTxNext <= TX_DONE;
end
else begin
rStatTxNext <= TX_STOP1;
end
end
TX_STOP2: begin
if (rPlsBaudTick)
rStatTxNext <= TX_DONE;
else
rStatTxNext <= TX_STOP2;
end
TX_DONE: begin
rStatTxNext <= TX_IDLE; // 再次进入空闲状态
end
default: begin
rStatTxNext <= TX_IDLE;
end
endcase
end
还有一个always块代码没列出,这个是时序逻辑,问题就出在上面的第二个always模块,它里面用的是非阻塞赋值方式来进行状态的跳转以及判断的,有哪个大虾给解释一下这样做有什么优缺点么?虽然自己也这样写过,但对这个用法还是很迷糊。希望能得到大家的指点。 |
|