Verilog实现RS232_TX模块移位与计数功能异常问题咨询
Verilog RS232 TX模块问题排查结果
核心问题根因
- 寄存器更新逻辑错误放置在组合逻辑块:你将
count_tx递减、temp_tx左移、输出端口赋值等需要时钟沿触发的操作,全部写在了always@(*)的组合逻辑块中,这是所有异常的核心来源。组合逻辑为电平敏感,只要输入变化就会反复执行,且未在所有case分支赋值的变量会生成锁存器,锁存器输出无新赋值时会保持原值,最终表现为count_tx仅减1、temp_tx仅移位1次就不再变化。 count_tx无复位、无初始值加载逻辑:你仅在寄存器定义时给count_tx赋了初始值,该写法仅仿真可用,综合不生效,且进入S_SENDING状态前没有重新加载计数初始值,计数逻辑无法循环执行。- Testbench端口连接错误:DUT的复位端口名为
r_tx,但你在testbench中错误连接为.rst(c_r),复位信号未生效;输入待发送端口data_tx未与testbench的发送数据连接,待发送数据悬空。 - 状态跳转逻辑异常:由于
count_tx被锁存在11,|count_tx始终为1,next_tx一直为S_SENDING,状态机卡死在发送状态。
修复方案
1. 拆分组合逻辑与时序逻辑
组合逻辑块仅负责计算下一状态,所有寄存器更新放在时钟沿触发的时序逻辑块中,示例如下:
// 仅做状态跳转的组合逻辑 always@(*) begin case(state_tx) S_IDLE: next_tx = dsr_tx ? S_START : S_IDLE; S_START: next_tx = cts_tx ? S_SENDING : S_START; S_SENDING: next_tx = (count_tx == 0) ? S_DONE : S_SENDING; S_DONE: next_tx = S_IDLE; default: next_tx = S_IDLE; endcase end // 时序逻辑做寄存器更新 always@(posedge clk_tx, negedge r_tx) begin if(~r_tx) begin count_tx <= 4'd12; temp_tx <= 13'd0; dtr_tx <= 1'b0; rts_tx <= 1'b0; dataframe_tx <= 1'b1; done_tx <= 1'b0; end else begin case(state_tx) S_IDLE: begin done_tx <= 1'b0; dtr_tx <= 1'b1; count_tx <= frame_size; end S_START: begin rts_tx <= 1'b1; // 在这里完成temp_tx的组帧赋值,示例为1bit起始位+9bit数据+3bit停止位的13bit帧结构 temp_tx <= {1'b0, data_tx, 3'b111}; end S_SENDING: begin dataframe_tx <= temp_tx[12]; temp_tx <= temp_tx << 1; count_tx <= count_tx - 1'd1; end S_DONE: begin done_tx <= 1'b1; rts_tx <= 1'b0; end endcase end end
2. 修正Testbench端口连接
// 修正后的DUT连接示例 rs232_tx dut( .clk_tx(c_Clock), .r_tx(c_r), .dsr_tx(t_dsr), .cts_tx(t_cts), .data_tx(t_send_data), // testbench定义的9bit待发送数据 .dataframe_tx(t_serial_out), // 单独的wire接串行输出 .dtr_tx(), .rts_tx() );
内容的提问来源于stack exchange,提问作者SWETHA CHILVERI
相关产品推荐
相关产品推荐

