在调试串口时遇到一个很诡异的问题。我打算用串口循环发送一个频率值,间隔为1s,然而下载到板子后只能发一次。我反复地检查我的时序设计图,然后用testbench仿真观察波形,都没有错!第一次遇到仿真正确然而下板验证时却出错的情况,值得纪念一下。不过难受的是我为这件事卡了一个星期,这一个星期里我反复地修改串口模块、发送频率模块和顶层模块,然而都无济于事,甚至还出现很多莫名其妙的情况,比如发送间隔为1s时只发了一次,改为10ms时就发送了两次,再改为1us时就什么也收不到了,完全不知道里面发生了什么……
转机出现在今晚,我想起了以前看过的fpga开发分享贴,里面提到调试fpga时如果实在找不出bug所在,就看看warning。这一看不得了了!当我把下面这条10240警告改掉之后,程序就跑通了!!!
10240 Verilog HDL Always Construct warning at send_freq.v(38): inferring latch(es) for variable "r_next_state", which holds its previous value in one or more paths through the always construct
这一条警告出现的原因是写了if没写else,或者写了case没写default,产生了锁存器。我在send_freq.v里面是这样写的:
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_cur_state <= S_IDLE;
else
r_cur_state <= r_next_state;
end
always @(*) begin
case(r_cur_state)
S_IDLE:
if(i_freq_send_req)
r_next_state <= S_SEND_TENTH;
S_SEND_TENTH:
...
default: r_next_state <= S_IDLE;
endcase
end
我没有给r_next_state赋初值,复位后r_cur_state为S_IDLE,如果在紧接着的时钟沿到来前i_freq_send_req没有出现,那么r_cur_state就被赋值为r_next_state,一个未初始化的值。然后再次进入case判断时,因为有default的存在,r_next_state第一次被赋值为S_IDLE。接着r_cur_state又被赋值为S_IDLE,这个时候程序才走上正轨,该赋值的变量都赋值了。按理说不应该出现我遇到的问题,所以这个玄学我暂时没法解释。先记录在此,以后回过头来看也许就能一目了然。如果各位看官知道其中道理的,还望不吝赐教。
以后要是要重视编程规范呀。
这部分是可以运行的代码,分别是串口发送模块,频率发送控制模块和顶层模块。
module uart_tx(
input i_clk,
input i_rst_n,
input i_uart_send_req,
input[7:0] i_uart_send_byte,
output o_uart_send_ack,
output o_uart_tx_pin
);
localparam C_CYCLE = 50 * 1000000 / 115200;
localparam S_IDLE = 5'b00001;
localparam S_START = 5'b00010;
localparam S_DATA = 5'b00100;
localparam S_STOP = 5'b01000;
localparam S_ACK = 5'b10000;
reg[4:0] r_cur_state;
reg[4:0] r_next_state;
reg[31:0]r_cycle_cnt;
reg[2:0] r_bit_cnt;
reg[7:0] r_uart_send_byte;
reg r_uart_send_ack;
reg r_uart_tx_pin;
assign o_uart_tx_pin = r_uart_tx_pin;
assign o_uart_send_ack = r_uart_send_ack;
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_cur_state <= S_IDLE;
else
r_cur_state <= r_next_state;
end
always @(*) begin
case(r_cur_state)
S_IDLE:
if(i_uart_send_req)
r_next_state <= S_START;
else
r_next_state <= S_IDLE;
S_START:
if(r_cycle_cnt == C_CYCLE - 1)
r_next_state <= S_DATA;
else
r_next_state <= S_START;
S_DATA:
if((r_cycle_cnt == C_CYCLE - 1) && r_bit_cnt == 3'd7)
r_next_state <= S_STOP;
else
r_next_state <= S_DATA;
S_STOP:
if(r_cycle_cnt == C_CYCLE - 1)
r_next_state <= S_ACK;
else
r_next_state <= S_STOP;
S_ACK: r_next_state <= S_IDLE;
default: r_next_state <= S_IDLE;
endcase
end
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_uart_tx_pin <= 1'b1;
else
case(r_next_state)
S_IDLE: r_uart_tx_pin <= 1'b1;
S_START: r_uart_tx_pin <= 1'b0;
S_DATA: r_uart_tx_pin <= r_uart_send_byte[r_bit_cnt];
S_STOP, S_ACK: r_uart_tx_pin <= 1'b1;
default: r_uart_tx_pin <= 1'b1;
endcase
end
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_cycle_cnt <= 32'd0;
else if(r_cur_state != r_next_state || (r_next_state == S_DATA && r_cycle_cnt == C_CYCLE - 1))
r_cycle_cnt <= 32'd0;
else
r_cycle_cnt <= r_cycle_cnt + 32'd1;
end
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_bit_cnt <= 3'd0;
else if(r_cur_state == S_DATA)
if(r_cycle_cnt == C_CYCLE - 1)
r_bit_cnt <= r_bit_cnt + 3'd1;
else
r_bit_cnt <= r_bit_cnt;
else
r_bit_cnt <= 3'd0;
end
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_uart_send_byte <= 8'd0;
else if(i_uart_send_req)
r_uart_send_byte <= i_uart_send_byte;
else
r_uart_send_byte <= r_uart_send_byte;
end
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_uart_send_ack <= 1'b0;
else if(r_next_state == S_ACK)
r_uart_send_ack <= 1'b1;
else
r_uart_send_ack <= 1'b0;
end
endmodule
module send_freq(
input i_clk,
input i_rst_n,
input i_freq_send_req,
input[9:0] i_freq,
output o_freq_send_ack,
output o_uart_tx_pin
);
localparam S_IDLE = 6'b000001;
localparam S_SEND_TENTH = 6'b000010;
localparam S_SEND_DOT = 6'b000100;
localparam S_SEND_INT = 6'b001000;
localparam S_WAIT = 6'b010000;
localparam S_ACK = 6'b100000;
reg[5:0] r_cur_state;
reg[5:0] r_next_state;
reg[5:0] r_last_state;
reg[9:0] r_freq;
reg[7:0] r_uart_send_byte;
reg r_freq_send_ack;
reg r_uart_send_req;
wire r_uart_send_ack;
assign o_freq_send_ack = r_freq_send_ack;
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_cur_state <= S_IDLE;
else
r_cur_state <= r_next_state;
end
always @(*) begin
case(r_cur_state)
S_IDLE:
if(i_freq_send_req)
r_next_state <= S_SEND_TENTH;
else // important!!
r_next_state <= S_IDLE;
S_SEND_TENTH,S_SEND_DOT,S_SEND_INT: r_next_state <= S_WAIT;
S_WAIT:
if(r_uart_send_ack) begin
if(r_last_state == S_SEND_TENTH)
r_next_state <= S_SEND_DOT;
else if(r_last_state == S_SEND_DOT)
r_next_state <= S_SEND_INT;
else if(r_last_state == S_SEND_INT && (|r_freq))
r_next_state <= S_SEND_INT;
else
r_next_state <= S_ACK;
end
else
r_next_state <= S_WAIT;
S_ACK: r_next_state <= S_IDLE;
default: r_next_state <= S_IDLE;
endcase
end
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_freq_send_ack <= 1'b0;
else if(r_next_state == S_ACK)
r_freq_send_ack <= 1'b1;
else
r_freq_send_ack <= 1'b0;
end
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_last_state <= S_IDLE;
else if(r_next_state == S_SEND_TENTH || r_next_state == S_SEND_DOT || r_next_state == S_SEND_INT)
r_last_state <= r_next_state;
else
r_last_state <= r_last_state;
end
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_uart_send_req <= 1'b0;
else if(r_next_state == S_SEND_TENTH)
r_uart_send_req <= 1'b1;
else if(r_next_state == S_ACK)
r_uart_send_req <= 1'b0;
else
r_uart_send_req <= r_uart_send_req;
end
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_freq <= 10'd0;
else if(r_next_state == S_SEND_TENTH)
r_freq <= i_freq / 10'd10;
else if(r_next_state == S_SEND_INT && (|r_freq))
r_freq <= r_freq / 10'd10;
else
r_freq <= r_freq;
end
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n)
r_uart_send_byte <= 8'hff;
else if(r_next_state == S_SEND_TENTH)
r_uart_send_byte <= i_freq % 10'd10 + "0";
else if(r_next_state == S_SEND_DOT)
r_uart_send_byte <= ".";
else if(r_next_state == S_SEND_INT && (|r_freq))
r_uart_send_byte <= r_freq % 10'd10 + "0";
else
r_uart_send_byte <= r_uart_send_byte;
end
uart_tx uart_tx_inst(
.i_clk (i_clk),
.i_rst_n (i_rst_n),
.i_uart_send_req (r_uart_send_req),
.i_uart_send_byte (r_uart_send_byte),
.o_uart_send_ack (r_uart_send_ack),
.o_uart_tx_pin (o_uart_tx_pin)
);
endmodule
module send_freq_top(
input i_clk,
input i_rst_n,
output o_uart_tx_pin
);
localparam S_IDLE = 4'b0001;
localparam S_SEND = 4'b0010;
localparam S_WAIT = 4'b0100;
localparam S_SEND2= 4'b1000;
reg[3:0] r_next_state;
reg[31:0] r_clk_cnt;
reg[9:0] r_freq;
reg r_freq_send_req;
wire r_freq_send_ack;
always @(posedge i_clk or negedge i_rst_n) begin
if(!i_rst_n) begin
r_next_state <= S_IDLE;
r_freq <= 10'd1021;
r_freq_send_req <= 1'b0;
r_clk_cnt <= 32'd0;
end
else
case(r_next_state)
S_IDLE: r_next_state <= S_SEND;
S_SEND: begin
r_clk_cnt <= 32'd0;
if(r_freq_send_req && r_freq_send_ack) begin
r_freq_send_req <= 1'b0;
r_next_state <= S_WAIT;
end
else if(!r_freq_send_req)
r_freq_send_req <= 1'b1;
end
S_WAIT: begin
r_clk_cnt <= r_clk_cnt + 32'd1;
if(r_clk_cnt >= 32'd50000000)
r_next_state <= S_SEND;
end
default: r_next_state <= S_IDLE;
endcase
end
send_freq send_freq_inst(
.i_clk (i_clk),
.i_rst_n (i_rst_n),
.i_freq_send_req (r_freq_send_req),
.i_freq (r_freq),
.o_freq_send_ack (r_freq_send_ack),
.o_uart_tx_pin (o_uart_tx_pin)
);
endmodule