状态机不稳定的问题。
时间:10-02
整理:3721RD
点击:
状态机不稳定,跑上几十次就卡在某个状态。
改成三段式后,在RTL viewer看综合后的电路,综合成了状态机(黄色那块)。
这时候程序运行几遍就会卡住。但是将CS赋值给led变量后,编译后用RTLviewer观察,没有综合出状态机,CS总合成了触发器,这时候程序反而能一直运行下去,不会卡住。
这到底是为什么。代码如下(两次编译的区别就在于最下边标红的部分,现在的代码编译没有综合出状态机,将下边那行代替这行,就会编译生成状态机):
module DO_backplane(
//global signals
input clk,
input nRST,
//DO_trigger module interface
//input [7:0] b_feedback,
//input [13:0] working_status,
output reg [13:0] b_trigger,
output reg [13:0] led,
//backplane signals
input [9:0] b_addr,
inout [7:0] b_data,
input b_rd, //active low
input b_wr, //active low
//input retry, //active low
output reg ready, //active low
output reg [3:0] oe,
output reg [3:0] dir
);
//FSM is coded by one-hot
localparam Bus_Idle =5'h00;
localparam Bus_RW =5'h01;
localparam Bus_Ready =5'h02;//set ready signal in read cycle
localparam Bus_Data =5'h04;
localparam Bus_Ready_UN =5'h08;
localparam Bus_Finish =5'h10;
/*
//FSM is coded by Gray Code
localparam Bus_Idle =4'b0000;
localparam Bus_RW =4'b0001;
localparam Bus_Ready =4'b0011;//set ready signal in read cycle
localparam Bus_Data =4'b0010;
localparam Bus_Ready_UN =4'b0110;
localparam Bus_Finish_a =4'b0100;
localparam Bus_Finish_b =4'b0101;
localparam Bus_Finish_c =4'b0111;
localparam Bus_Finish_d =4'b1111;
*/
//DO1A board base address
parameter DO_base_addr =10'h180;
//backplane communication
reg [4:0] CS;
reg [4:0] NS;
reg [7:0] data;
reg read_flag;
reg [13:0] b_trigger_temp;
reg [7:0] data_temp;
reg [25:0] count;
//tri-stated databus
assign b_data = (~read_flag)?data:8'hzz;
//output a variable data to CPU board to verify long-time communication
always@(posedge clk or negedge nRST)
begin
if(~nRST)
begin
count <= 25'h0;
data_temp <= 8'h0;
end
else if(count == 25'h16e3200)
begin
count <= 25'h0;
data_temp <= data_temp + 1'b1;
end
else
count <= count + 1'b1;
end
//backplane communication FSM
//1st always block,synchronously update currentstate with next state
always@(posedge clk or negedge nRST)
begin
if(~nRST)
CS <= Bus_Idle;
else
CS <= NS;
end
//2nd always block,combinational condition judgement
always@(b_addr or CS or b_rd or b_wr)
begin
NS = CS;
case(CS)
Bus_Idle:
begin
if(b_addr == DO_base_addr)
NS = Bus_RW;
end
Bus_RW:
begin
if((b_rd == 1'b1)&&(b_wr == 1'b0))//firstly write to DO,then read data from DO
NS = Bus_Ready;
end
Bus_Ready:
begin
NS = Bus_Data;
end
Bus_Data:
begin
if(b_addr[5:0] == 6'h5)
NS = Bus_Ready_UN;
end
Bus_Ready_UN:
begin
NS = Bus_Finish;
end
Bus_Finish:
begin
NS = Bus_Idle;
end
default:
begin
NS = Bus_Idle;
end
endcase
end
//3rd always block,synchronously output
always@(posedge clk or negedge nRST)
begin
if(~nRST)
begin
ready <= 1'b1;
read_flag <= 1'b1;
data <= 8'h0;
oe <= 4'b0101;
dir <= 4'b1101;
end
else
case(CS)
Bus_Idle:
begin
oe <= 4'b0011;
dir <= 4'b1101;
ready <= 1'b1;
end
Bus_RW:
begin
oe <= 4'b0000;
end
Bus_Ready:
begin
ready <= 1'b0;
end
Bus_Data:
begin
if(b_addr[5:0] == 6'h0)
b_trigger_temp[13:8] <= b_data[5:0];
else if(b_addr[5:0] == 6'h1)
b_trigger_temp[7:0] <= b_data;
else if(b_addr[5:0] == 6'h2)
begin
read_flag <= 1'b0;
dir <= 4'b1100;
b_trigger <= b_trigger_temp;
end
else if(b_addr[5:0] == 6'h3)
data <= data_temp;
else if(b_addr[5:0] == 6'h4)
data <= data_temp;
else
data <= 8'hcc;
end
Bus_Ready_UN:
begin
read_flag <= 1'b1;
ready <= 1'b1;
end
endcase
end
always@(posedge clk or negedge nRST)
begin
if(~nRST)
begin
led <= 14'h2aaa;
end
else
begin
led <={2'h0,CS, b_trigger_temp[7:0]};
// led <= b_trigger_temp;
end
end
endmodule
改成三段式后,在RTL viewer看综合后的电路,综合成了状态机(黄色那块)。
这时候程序运行几遍就会卡住。但是将CS赋值给led变量后,编译后用RTLviewer观察,没有综合出状态机,CS总合成了触发器,这时候程序反而能一直运行下去,不会卡住。
这到底是为什么。代码如下(两次编译的区别就在于最下边标红的部分,现在的代码编译没有综合出状态机,将下边那行代替这行,就会编译生成状态机):
module DO_backplane(
//global signals
input clk,
input nRST,
//DO_trigger module interface
//input [7:0] b_feedback,
//input [13:0] working_status,
output reg [13:0] b_trigger,
output reg [13:0] led,
//backplane signals
input [9:0] b_addr,
inout [7:0] b_data,
input b_rd, //active low
input b_wr, //active low
//input retry, //active low
output reg ready, //active low
output reg [3:0] oe,
output reg [3:0] dir
);
//FSM is coded by one-hot
localparam Bus_Idle =5'h00;
localparam Bus_RW =5'h01;
localparam Bus_Ready =5'h02;//set ready signal in read cycle
localparam Bus_Data =5'h04;
localparam Bus_Ready_UN =5'h08;
localparam Bus_Finish =5'h10;
/*
//FSM is coded by Gray Code
localparam Bus_Idle =4'b0000;
localparam Bus_RW =4'b0001;
localparam Bus_Ready =4'b0011;//set ready signal in read cycle
localparam Bus_Data =4'b0010;
localparam Bus_Ready_UN =4'b0110;
localparam Bus_Finish_a =4'b0100;
localparam Bus_Finish_b =4'b0101;
localparam Bus_Finish_c =4'b0111;
localparam Bus_Finish_d =4'b1111;
*/
//DO1A board base address
parameter DO_base_addr =10'h180;
//backplane communication
reg [4:0] CS;
reg [4:0] NS;
reg [7:0] data;
reg read_flag;
reg [13:0] b_trigger_temp;
reg [7:0] data_temp;
reg [25:0] count;
//tri-stated databus
assign b_data = (~read_flag)?data:8'hzz;
//output a variable data to CPU board to verify long-time communication
always@(posedge clk or negedge nRST)
begin
if(~nRST)
begin
count <= 25'h0;
data_temp <= 8'h0;
end
else if(count == 25'h16e3200)
begin
count <= 25'h0;
data_temp <= data_temp + 1'b1;
end
else
count <= count + 1'b1;
end
//backplane communication FSM
//1st always block,synchronously update currentstate with next state
always@(posedge clk or negedge nRST)
begin
if(~nRST)
CS <= Bus_Idle;
else
CS <= NS;
end
//2nd always block,combinational condition judgement
always@(b_addr or CS or b_rd or b_wr)
begin
NS = CS;
case(CS)
Bus_Idle:
begin
if(b_addr == DO_base_addr)
NS = Bus_RW;
end
Bus_RW:
begin
if((b_rd == 1'b1)&&(b_wr == 1'b0))//firstly write to DO,then read data from DO
NS = Bus_Ready;
end
Bus_Ready:
begin
NS = Bus_Data;
end
Bus_Data:
begin
if(b_addr[5:0] == 6'h5)
NS = Bus_Ready_UN;
end
Bus_Ready_UN:
begin
NS = Bus_Finish;
end
Bus_Finish:
begin
NS = Bus_Idle;
end
default:
begin
NS = Bus_Idle;
end
endcase
end
//3rd always block,synchronously output
always@(posedge clk or negedge nRST)
begin
if(~nRST)
begin
ready <= 1'b1;
read_flag <= 1'b1;
data <= 8'h0;
oe <= 4'b0101;
dir <= 4'b1101;
end
else
case(CS)
Bus_Idle:
begin
oe <= 4'b0011;
dir <= 4'b1101;
ready <= 1'b1;
end
Bus_RW:
begin
oe <= 4'b0000;
end
Bus_Ready:
begin
ready <= 1'b0;
end
Bus_Data:
begin
if(b_addr[5:0] == 6'h0)
b_trigger_temp[13:8] <= b_data[5:0];
else if(b_addr[5:0] == 6'h1)
b_trigger_temp[7:0] <= b_data;
else if(b_addr[5:0] == 6'h2)
begin
read_flag <= 1'b0;
dir <= 4'b1100;
b_trigger <= b_trigger_temp;
end
else if(b_addr[5:0] == 6'h3)
data <= data_temp;
else if(b_addr[5:0] == 6'h4)
data <= data_temp;
else
data <= 8'hcc;
end
Bus_Ready_UN:
begin
read_flag <= 1'b1;
ready <= 1'b1;
end
endcase
end
always@(posedge clk or negedge nRST)
begin
if(~nRST)
begin
led <= 14'h2aaa;
end
else
begin
led <={2'h0,CS, b_trigger_temp[7:0]};
// led <= b_trigger_temp;
end
end
endmodule
综合成状态机
没有综合成状态机
状态机的输入条件时序没有给出,很难去判断为何会状态异常,大多情况都是出现了你没有列出转移条件,从而导致的异常,就你列出的代码而言,个人感觉有两个问题,你可以作为参考:
1、NRST为低时,CS<=IDLE状态,同时 “oe <= 4'b0101”,但在状态输出中,当CS==IDLE 状态,oe <= 4'b0011,这两个输出是矛盾的,即NRST时,CS必然为IDLE ,也就是说在NRST为低时,oe可能有两个赋值。
2、data_temp的值可能溢出,不知道你关心这个不。希望对你有用