求教一下状态机的状态跳转问题
时间:10-02
整理:3721RD
点击:
先说明一下常见的状态机写法:
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模块,它里面用的是非阻塞赋值方式来进行状态的跳转以及判断的,有哪个大虾给解释一下这样做有什么优缺点么?虽然自己也这样写过,但对这个用法还是很迷糊。希望能得到大家的指点。
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模块,它里面用的是非阻塞赋值方式来进行状态的跳转以及判断的,有哪个大虾给解释一下这样做有什么优缺点么?虽然自己也这样写过,但对这个用法还是很迷糊。希望能得到大家的指点。
我看你第二个always是阻塞方式描述的呀?难道<=是非阻塞?
我觉得 这段always语句用 阻塞 和非阻塞的效果应该差不多...
阻塞我感觉类似于顺序执行,而非阻塞则类似于并行,现在整个always语句中间下面的if语句只有一个短句
所以阻塞和非阻塞时一个效果....
第二段always用阻塞和非阻塞是一样的,不过一般编码风格是推荐用非阻塞赋值的
现在是一个语句这样赋值,效果是一样的,但如果有多个语句的话,那<=和=的赋值效果还一样么?求教了。
现在是一个语句这样赋值,效果是一样的。但如果有多个语句这样赋值的话,那<=和=的赋值效果还一样么?求教了。
状态机无所谓怎么写,只要判断转移条件合理就行了,=和=〉在verilog中的用法和状态机没什么关系,关键是你可能还没仔细看过verilog方面的教程之类的书,你只要搞清楚组合逻辑和时序逻辑怎样书写就不会有这样的疑问了
恩,是这么说的,这一次我想把这个问题搞懂,以免在以后的过程中又出现问题,
阻塞、非阻塞赋值是没错,但如果理解错了,就真的错了,这个影响到对结果的引用。希望你能多指点些。非常感谢!
看看啥!
建议将每一个verilog的写法都能对应到具体的物理电路上。
如果实现的是一个组合逻辑,用什么能表示呢?
路过 围观!
理论上应该是有区别的,至于在仿真的时候会不会出现问题就不知道了,
我的理解是应该会出现差异
恩,我觉得也是,应该是有差异的。这个是描述语言而不是设计语言。
不同的赋值,对结果的引用也是不一样的。
