6,167
社区成员
发帖
与我相关
我的任务
分享
//*******************************************************************************
//AutoNego state machine
//reg [5 :0] state_m_autoNego_rx;
//reg [5: 0] flp_cnt;
//reg [28:0] autoNego_wait_timer;
//reg has_recv_three_LCW_flag;
//*******************************************************************************
reg [9:0] in_link_active_flag_copy;
always@(posedge CLK_10M or negedge n_reset_sync)
begin
if(0 == n_reset_sync)
in_link_active_flag_copy <= 0;
else
in_link_active_flag_copy <= {in_link_active_flag_copy[8:0],in_link_active_flag};
end
parameter STATE_NEGO_SLEEPING = 0;
parameter STATE_NEGO_DETECTING = 1;
parameter STATE_NEGO_TALKING = 2;
parameter STATE_NEGO_ALMOSTDONE = 4;
parameter STATE_NEGO_DONE = 8;
parameter FLP_INTERVAL_MIN_TIME = 5*10000; //8 ms
parameter FLP_INTERVAL_MAX_TIME = 24 * 10000; //24 ms
parameter AUTONEGO_WAIT_TIME = 1000 * 10000; //500 ~ 1000 ms
parameter AUTONEGO_TEST_TIMEOUT = 200 * 10000; //500 ~ 1000 ms
parameter AUTONEGO_ALMOSTDONE_TIMEOUT = 100 * 10000; //100 ~ 120 ms
parameter AUTONEGO_TEST_IDLE_TIMEOUT = 500 * 10000; //500ms
parameter AUTONEGO_LINK_FAIL_TIMEOUT = 100 * 10000; //100 ~ 120 ms
reg [31:0] autoNego_wait_timer;
reg test_idle_is_needed_flag;
always@(posedge CLK_10M or negedge n_reset_sync)
begin
if(0 == n_reset_sync)
begin
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
flp_cnt <= 0;
test_idle_is_needed_flag <= 1;
autoNego_wait_timer <= 0;
end
else
case(state_m_autoNego_rx)
STATE_NEGO_SLEEPING:
begin
autoNego_wait_timer <= autoNego_wait_timer + 1;
if(AUTONEGO_WAIT_TIME <= autoNego_wait_timer) //enough sleep. time to test
begin
autoNego_wait_timer <= 0;
flp_cnt <= 0;
state_m_autoNego_rx <= STATE_NEGO_DETECTING;
end
else
if( 1 == link_code_rx_done_flag) //or FLP detected. begin to work
begin
autoNego_wait_timer <= 0;
flp_cnt <= 1; //has received one LCW
state_m_autoNego_rx <= STATE_NEGO_TALKING;
end
end
STATE_NEGO_DETECTING:
begin
autoNego_wait_timer <= autoNego_wait_timer + 1;
if(AUTONEGO_TEST_TIMEOUT <= autoNego_wait_timer)
begin
autoNego_wait_timer <= 0;
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
end
else
if(1 == link_code_rx_done_flag)
begin
autoNego_wait_timer <= 0;
flp_cnt <= flp_cnt + 1;//has received one LCW, maybe tow
state_m_autoNego_rx <= STATE_NEGO_TALKING;
end
end
STATE_NEGO_TALKING:
begin
autoNego_wait_timer <= autoNego_wait_timer + 1;
if(flp_cnt > 10)
begin
autoNego_wait_timer <= 0;
state_m_autoNego_rx <= STATE_NEGO_ALMOSTDONE;
end
else
begin
if(autoNego_wait_timer < FLP_INTERVAL_MAX_TIME)//not timeout
begin
if(autoNego_wait_timer > FLP_INTERVAL_MIN_TIME)
begin
if(link_code_rx_done_flag)// another link_code_word is received
begin
autoNego_wait_timer <= 0;
flp_cnt <= flp_cnt + 1;
end
end
end
else //timeout, return to sleeping
begin
autoNego_wait_timer <= 0;
flp_cnt <= 0;
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
end
end
end
STATE_NEGO_ALMOSTDONE:
begin
test_idle_is_needed_flag <= 1;// test idle is needed, not yet linkup.
if( autoNego_wait_timer > AUTONEGO_ALMOSTDONE_TIMEOUT)
begin
state_m_autoNego_rx <= STATE_NEGO_DONE;
autoNego_wait_timer <= 0;
end
else
begin
autoNego_wait_timer <= autoNego_wait_timer + 1;
end
end
STATE_NEGO_DONE:
begin
if(0 == (&in_link_active_flag_copy[9:0]) ) //link not ready
begin
// first time coming here, need test idle.. 500ms timeout
// second time or more, needtest fail 100ms timeout
if( test_idle_is_needed_flag)
if(autoNego_wait_timer < AUTONEGO_TEST_IDLE_TIMEOUT)
autoNego_wait_timer <= autoNego_wait_timer + 1;
else
begin
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
flp_cnt <= 0;
autoNego_wait_timer <= 0;
end
else //!test_idle_is_needed_flag
if( autoNego_wait_timer < AUTONEGO_LINK_FAIL_TIMEOUT)
autoNego_wait_timer <= autoNego_wait_timer + 1;
else //timeout restart auto-negotiation
begin
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
flp_cnt <= 0;
autoNego_wait_timer <= 0;
end
end
else //linkup!! do nothing, just clear counter;
begin
autoNego_wait_timer <= 0;
//when linkup, clear the flag
test_idle_is_needed_flag <= 0;
end
end
default:
begin
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
flp_cnt <= 0;
autoNego_wait_timer <= 0;
end
endcase
end
//Gen has_recv_three_LCW_flag
always@(posedge CLK_10M or negedge n_reset_sync)
if(!n_reset_sync)
has_recv_three_LCW_flag <= 0;
else
has_recv_three_LCW_flag <= (state_m_autoNego_rx >= STATE_NEGO_TALKING && flp_cnt >= 3);
//Gen out_autoNego_done
always@(posedge CLK_10M or negedge n_reset_sync)
if(!n_reset_sync)
out_autoNego_done <= 0;
else
out_autoNego_done <= (STATE_NEGO_DONE == state_m_autoNego_rx || !in_autoNego_enable);
// 超时标志
wire wait_timeout = autoNego_wait_timer >= FLP_INTERVAL_MAX_TIME;
// 有效flp脉冲,即在计数区间内到来的link_code_rx_done_flag
wire valid_flp_pulse = (autoNego_wait_timer < FLP_INTERVAL_MAX_TIME) &&
(autoNego_wait_timer > FLP_INTERVAL_MIN_TIME) &&
link_code_rx_done_flag;
// state_m_autoNego_rx -- 状态机:寄存器
always @( posedge clk ) begin
if( flp_cnt > 10 ) begin
state_m_autoNego_rx <= STATE_NEGO_ALMOSTDONE;
end
else if( wait_timeout ) begin
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
end
end
// flp_cnt -- flp事件计数: 带清零和使能的计数器
always @( posedge clk ) begin
if( wait_timeout ) begin
flp_cnt <= 0;
end
else if( valid_flp_pulse ) begin
flp_cnt <= flp_cnt + 1;
end
end
// autoNego_wait_timer -- 计时:带清零的计数器
always @( posedge clk ) beign
if( (flp_cnt > 10) || wait_timeout || valid_flp_pulse ) begin
autoNego_wait_timer <= 0;
end
else begin
autoNego_wait_timer <= autoNego_wait_timer + 1;
end
end
// 每个状态的超时计数值
reg [31:0] wait_timeout_value;
always @* begin
case( state_m_autoNego_rx )
STATE_NEGO_SLEEPING : wait_timeout_value = AUTONEGO_WAIT_TIME;
STATE_NEGO_DETECTING : wait_timeout_value = AUTONEGO_TEST_TIMEOUT;
STATE_NEGO_TALKING : wait_timeout_value = FLP_INTERVAL_MAX_TIME;
STATE_NEGO_ALMOSTDONE: wait_timeout_value = AUTONEGO_ALMOSTDONE_TIMEOUT;
STATE_NEGO_DONE : wait_timeout_value = test_idle_is_needed_flag ? AUTONEGO_TEST_IDLE_TIMEOUT : AUTONEGO_LINK_FAIL_TIMEOUT;
default : wait_timeout_value = 0;
endcase
end
// 有效flp脉冲,即在计数区间内到来的link_code_rx_done_flag
wire valid_flp_pulse = (autoNego_wait_timer < FLP_INTERVAL_MAX_TIME) &&
(autoNego_wait_timer > FLP_INTERVAL_MIN_TIME) &&
link_code_rx_done_flag;
// 状态转移:注重每个状态的转移条件
// 另:代码描述是异步复位,与命名_sync不符
always @(posedge CLK_10M, negedge n_reset_sync) begin
if( !n_reset_sync ) begin
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
end
else begin
case( state_m_autoNego_rx )
STATE_NEGO_SLEEPING: begin
if( autoNego_wait_timer > wait_timeout_value )
state_m_autoNego_rx <= STATE_NEGO_DETECTING;
end
else if( link_code_rx_done_flag ) begin
state_m_autoNego_rx <= STATE_NEGO_TALKING;
end
end
STATE_NEGO_DETECTING: begin
if( autoNego_wait_timer > wait_timeout_value )
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
end
else if( link_code_rx_done_flag ) begin
state_m_autoNego_rx <= STATE_NEGO_TALKING;
end
end
STATE_NEGO_TALKING: begin
if( flp_cnt > 10 ) begin
state_m_autoNego_rx <= STATE_NEGO_ALMOSTDONE;
end
else if( autoNego_wait_timer > wait_timeout_value ) begin
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
end
end
STATE_NEGO_ALMOSTDONE: begin
if( autoNego_wait_timer > wait_timeout_value ) begin
state_m_autoNego_rx <= STATE_NEGO_DONE;
end
end
STATE_NEGO_DONE: begin
if( (!(&in_link_active_flag_copy[9:0])) &&
(autoNego_wait_timer > wait_timeout_value) ) begin
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
end
end
end
default: state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
endcase
end
end
// 超时计数 : 注重每个状态下计数器的计数和清零条件
// 还可以写得更简化,不过这只是一种示意
always @(posedge CLK_10M, negedge n_reset_sync) begin
if( !n_reset_sync ) begin
autoNego_wait_timer <= 0;
end
else begin
case( state_m_autoNego_rx )
STATE_NEGO_SLEEPING: begin
if( autoNego_wait_timer > wait_timeout_value ) autoNego_wait_timer <= 0;
else autoNego_wait_timer <= autoNego_wait_timer + 1;
end
STATE_NEGO_DETECTING: begin
if( autoNego_wait_timer > wait_timeout_value ) autoNego_wait_timer <= 0;
else autoNego_wait_timer <= autoNego_wait_timer + 1;
end
STATE_NEGO_TALKING: begin
if( (flp_cnt > 10) ||
(autoNego_wait_timer > wait_timeout_value) ||
valid_flp_pulse )
autoNego_wait_timer <= 0;
else
autoNego_wait_timer <= autoNego_wait_timer + 1;
end
STATE_NEGO_ALMOSTDONE: begin
if( autoNego_wait_timer > wait_timeout_value ) autoNego_wait_timer <= 0;
else autoNego_wait_timer <= autoNego_wait_timer + 1;
end
STATE_NEGO_DONE: begin
if( (!(&in_link_active_flag_copy[9:0])) &&
(autoNego_wait_timer > wait_timeout_value) )
autoNego_wait_timer <= 0;
else
autoNego_wait_timer <= autoNego_wait_timer + 1;
end
default: autoNego_wait_timer <= 0;
endcase
end
end
//......
begin
autoNego_wait_timer <= autoNego_wait_timer + 1;
if(flp_cnt > 10)
begin
autoNego_wait_timer <= 0;
state_m_autoNego_rx <= STATE_NEGO_ALMOSTDONE;
end
else
begin
if(autoNego_wait_timer < FLP_INTERVAL_MAX_TIME)//not timeout
begin
if(autoNego_wait_timer > FLP_INTERVAL_MIN_TIME)
begin
if(link_code_rx_done_flag)
begin
autoNego_wait_timer <= 0;
flp_cnt <= flp_cnt + 1;
end
end
end
else //timeout, return to sleeping
begin
autoNego_wait_timer <= 0;
flp_cnt <= 0;
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
end
end
always @(posedge clk) begin // 时间点:clk上升沿事件发生时刻
a <= 1; // 事件发生时刻,a_temp = 1
a <= 2; // 事件发生时刻,a_temp = 2
a <= 3; // 事件发生时刻,a_temp = 3
end
// 在事件完成时刻,更新变量a的值 a = a_temp = 3
// 这段代码可以实现计数和清0
// 第2句只在条件满足时才对a_temp赋值为0,其它时候取第1句的赋值
always @(posedge clk) begin
a <= a + 1; // 事件发生时刻,a_temp =【事件发生时刻的a】+ 1
if( a == 10 ) a <= 0; // 事件发生时刻,if(【事件发生时刻的a】== 10 ) a_temp = 0
end
// 这段代码只能实现计数,不能实现清零。
// 第2句任何时候都会再次对a_temp赋值为a+1,相当于第1句任何时候都不起作用
always@(posedge clk) begin
if( a == 10 ) a <= 0; // 事件发生时刻,if(【事件发生时刻的a】== 10 ) a_temp = 0
a <= a + 1; // 事件发生时刻,a_temp =【事件发生时刻的a】+ 1
end
begin
autoNego_wait_timer <= autoNego_wait_timer + 1;
if(flp_cnt > 10)
begin
autoNego_wait_timer <= 0;
state_m_autoNego_rx <= STATE_NEGO_ALMOSTDONE;
end
else
begin
if(autoNego_wait_timer < FLP_INTERVAL_MAX_TIME)//not timeout
begin
if(autoNego_wait_timer > FLP_INTERVAL_MIN_TIME)
begin
if(link_code_rx_done_flag)
begin
autoNego_wait_timer <= 0;
flp_cnt <= flp_cnt + 1;
end
end
end
else //timeout, return to sleeping
begin
autoNego_wait_timer <= 0;
flp_cnt <= 0;
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
end
end
begin
autoNego_wait_timer <= autoNego_wait_timer + 1;
if(flp_cnt > 10)
begin
autoNego_wait_timer <= 0;
state_m_autoNego_rx <= STATE_NEGO_ALMOSTDONE;
end
else
begin
if(autoNego_wait_timer < FLP_INTERVAL_MAX_TIME)//not timeout
begin
if(autoNego_wait_timer > FLP_INTERVAL_MIN_TIME)
begin
if(link_code_rx_done_flag)
begin
autoNego_wait_timer <= 0;
flp_cnt <= flp_cnt + 1;
end
end
end
else //timeout, return to sleeping
begin
autoNego_wait_timer <= 0;
flp_cnt <= 0;
state_m_autoNego_rx <= STATE_NEGO_SLEEPING;
end
end
end
always@(posedge clk) begin
if( a == 10 ) a <= 0;
else a <= a + 1;
end