本人最近心态异常平静,于是乎--->简单整理下这两年魔幻般的经历(咱从地道的搬砖人又回到了研究僧的灵笼中,装作不开心~)。
注:转载本文章,请标明其来源。同时,此文章涉及的逻辑块代码仅供学习参考!!!谢谢配合!!!!!!!
本文以intel Birch Stream平台为例,参考的Birch Stream PDG为Rev 0.7 版本,如若新版PDG在时序上有所变动,请以最新的PDG或EDG为准,谢谢配合。
第一节:服务器CPU时序的要求
X86架构的服务器CPU含有多路电源轨,如常见的P3V3、P1V05、P0V9等。如整机方案使用的是Eagle Steam或之前的CPU,整个系统的电源时序会增加若干组关于PCH的电源轨。电源部分的常见分类有CPU核心电源、IO电源、总线电源、DIMM电源等,其上电时序和掉电时序必须满足平台的PDG或EDG的时序要求,如若不然,某些BUG可能就脱颖而出(狗头。毕竟咱自己给自己挖过坑,调试时出现各种奇葩问题,这台机器AC cycle跑不起来、那台产品触发保护机制……回忆当年,不争气的眼睛又进了沙子)。关于电源轨简称或命名的详细含义,请自学~
话不多说,先贴图为证。
1. Power Up Sequence 简略图(G3->S5->S0)
2. Power Down Sequence简略图(S0->S5)
3. 详细时序图
第二节:FPGA控制CPU的时序
1.三段式状态机FSM
整个核心的时序控制逻辑分为三部分,第一部分为状态转移逻辑;第二部分描述状态转移条件和规律;第三部分为输出控制逻辑。详细介绍如下:
1.1 状态转移逻辑(时序逻辑)
//1 Sequential state transition
always@( posedge i_sys_clk or negedge i_sys_rst_n)begin
if(!i_sys_rst_n)
r_current_state <= FSM_IDLE;
else
r_current_state <= r_next_state ;
end
1.2 状态转移条件和规律(组合逻辑)
//2 Combinational condition judgment
always@(*) begin
if(!i_sys_rst_n) begin
w_delay_start = 1'b1;
w_delay_ms_cnt = 8'd49;
w_timeout_cnt = 8'd49;
end
else begin
case(r_current_state)
FSM_IDLE : begin
if(i_config_error || w_pwr_fault_flg)
r_next_state = FSM_IDLE;
else if(w_delay_ms_done) begin
w_delay_start = 1'b0;
w_delay_ms_cnt = AUX_DELAY_G0;
w_timeout_cnt = TIMEOUT_COUNT;
r_next_state = FSM_AUX_G0_PWR_ON;
end
else
r_next_state = FSM_IDLE;
end
FSM_AUX_G0_PWR_ON : begin
w_delay_start = 1'b1;
// (power on timeout | power run down) & (~forced power on)
if(w_pwr_fault_flg)
r_next_state = FSM_PWR_FAIL;
else if((&i_aux_g0_pwr_pgd | i_forced_pwron) && w_delay_ms_done)begin
w_delay_start = 1'b0;
w_delay_ms_cnt = AUX_DELAY_G1;
w_timeout_cnt = TIMEOUT_COUNT;
r_next_state = FSM_AUX_G1_PWR_ON;
end
else
r_next_state = FSM_AUX_G0_PWR_ON;
end
FSM_AUX_G1_PWR_ON : begin
w_delay_start = 1'b1;
if(w_pwr_fault_flg)
r_next_state = FSM_PWR_FAIL;
else if((&i_aux_g1_pwr_pgd | i_forced_pwron) && w_delay_ms_done) begin
w_delay_start = 1'b0;
w_timeout_cnt = TIMEOUT_COUNT;
w_delay_ms_cnt = (AUX_PWR_GROUP > 2) ? AUX_DELAY_G2 : RSMRST_DELAY;
r_next_state = (AUX_PWR_GROUP > 2) ? FSM_AUX_G2_PWR_ON : FSM_AUX_PWR_OK;
end
else
r_next_state = FSM_AUX_G1_PWR_ON;
end
......
FSM_AUX_G4_PWR_ON : begin
w_delay_start = 1'b1;
if(w_pwr_fault_flg)
r_next_state = FSM_PWR_FAIL;
else if((&i_aux_g4_pwr_pgd | i_forced_pwron) && w_delay_ms_done) begin
w_delay_start = 1'b0;
w_timeout_cnt = TIMEOUT_COUNT;
w_delay_ms_cnt = RSMRST_DELAY;
r_next_state = FSM_AUX_PWR_OK;
end
else
r_next_state = FSM_AUX_G4_PWR_ON;
end
// power stby ok
FSM_AUX_PWR_OK : begin
w_delay_start = 1'b1;
if(w_pwr_fault_flg)
r_next_state = FSM_PWR_FAIL;
else if(w_delay_ms_done) begin
w_delay_start = 1'b0;
w_timeout_cnt = TIMEOUT_COUNT;
r_next_state = FSM_SYS_PWR_ON;
end
else
r_next_state = FSM_AUX_PWR_OK;
end
FSM_SYS_PWR_ON : begin
if(w_pwr_fault_flg)
r_next_state = FSM_PWR_FAIL;
else if(r_system_pwron | i_forced_pwron) begin
w_delay_ms_cnt = MAIN_DELAY_G0;
w_timeout_cnt = TIMEOUT_COUNT;
r_next_state = FSM_MAIN_G0_PWR_ON;
end
else
r_next_state = FSM_SYS_PWR_ON;
end
FSM_MAIN_G0_PWR_ON : begin
w_delay_start = 1'b1;
if(w_pwr_fault_flg)
r_next_state = FSM_PWR_FAIL;
else if((&i_main_g0_pwr_pgd | i_forced_pwron) && w_delay_ms_done) begin
w_delay_start = 1'b0;
w_delay_ms_cnt = MAIN_DELAY_G1;
w_timeout_cnt = TIMEOUT_COUNT;
r_next_state = FSM_MAIN_G1_PWR_ON;
end
else
r_next_state = FSM_MAIN_G0_PWR_ON;
end
......
FSM_MAIN_G9_PWR_ON : begin
w_delay_start = 1'b1;
if(w_pwr_fault_flg)
r_next_state = FSM_PWR_FAIL;
else if((&i_main_g9_pwr_pgd | i_forced_pwron) && w_delay_ms_done) begin
w_delay_start = 1'b0;
w_timeout_cnt = TIMEOUT_COUNT;
r_next_state = FSM_CPUDONE;
end
else
r_next_state = FSM_MAIN_G9_PWR_ON;
end
FSM_CPUDONE : begin
if(w_pwr_fault_flg)
r_next_state = FSM_PWR_FAIL;
else if(!r_system_pwron)
r_next_state = FSM_PWR_DOWN;
else
r_next_state = FSM_CPUDONE;
end
FSM_PWR_FAIL : begin
r_next_state = FSM_PWR_DOWN;
end
FSM_PWR_DOWN : begin
case(MAIN_PWR_GROUP)
8'd10 : begin
w_delay_start = 1'b0;
w_delay_ms_cnt = PWR_OFF_DELAY;
r_next_state = FSM_MAIN_G9_PWR_OFF;
end
......
8'd4 : begin
w_delay_start = 1'b0;
w_delay_ms_cnt = PWR_OFF_DELAY;
r_next_state = FSM_MAIN_G3_PWR_OFF;
end
default : begin
w_delay_start = 1'b0;
w_delay_ms_cnt = PWR_OFF_DELAY;
r_next_state = FSM_MAIN_G9_PWR_OFF;
end
endcase
end
FSM_MAIN_G9_PWR_OFF : begin
w_delay_start = ~(|i_main_g9_pwr_pgd);
if(w_delay_ms_done)begin
w_delay_start = 1'b0;
w_delay_ms_cnt = PWR_OFF_DELAY;
r_next_state = FSM_MAIN_G8_PWR_OFF;
end
else
r_next_state = FSM_MAIN_G9_PWR_OFF;
end
......
FSM_MAIN_G0_PWR_OFF : begin
w_delay_start = ~(|i_main_g0_pwr_pgd);
if(w_delay_ms_done)begin
w_delay_start = 1'b0;
w_delay_ms_cnt = PWR_OFF_DELAY;
if(w_pwr_fault_flg)
r_next_state = FSM_CLEAR_FAULT;
else
r_next_state = FSM_SYS_PWR_ON;
end
else
r_next_state = FSM_MAIN_G0_PWR_OFF;
end
FSM_CLEAR_FAULT : begin
if(~(w_aux_timeout_flg | w_aux_rundown_flg) && i_clear_fault)
r_next_state = FSM_SYS_PWR_ON;
else if(w_aux_timeout_flg | w_aux_rundown_flg)
r_next_state = FSM_AUX_PWR_FAULT;
else
r_next_state = FSM_CLEAR_FAULT;
end
FSM_AUX_PWR_FAULT : begin
case(AUX_PWR_GROUP)
4'd5 : begin
w_delay_start = 1'b0;
w_delay_ms_cnt = PWR_OFF_DELAY;
r_next_state = FSM_AUX_G4_PWR_OFF;
end
4'd3 : begin
w_delay_start = 1'b0;
w_delay_ms_cnt = PWR_OFF_DELAY;
r_next_state = FSM_AUX_G2_PWR_OFF;
end
default :
begin w_delay_start = 1'b0;
w_delay_ms_cnt = PWR_OFF_DELAY;
r_next_state = FSM_AUX_G4_PWR_OFF;
end
endcase
end
FSM_AUX_G4_PWR_OFF : begin
w_delay_start = ~(|i_aux_g4_pwr_pgd);
if(w_delay_ms_done)begin
w_delay_start = 1'b0;
w_delay_ms_cnt = PWR_OFF_DELAY;
r_next_state = FSM_AUX_G3_PWR_OFF;
end
else
r_next_state = FSM_AUX_G4_PWR_OFF;
end
......
FSM_AUX_G0_PWR_OFF : begin
w_delay_start = ~(|i_aux_g0_pwr_pgd);
if(w_delay_ms_done)begin
w_delay_start = 1'b0;
w_delay_ms_cnt = PWR_OFF_DELAY;
r_next_state = FSM_IDLE;
end
else
r_next_state = FSM_AUX_G0_PWR_OFF;
end
default : begin
r_next_state = FSM_IDLE;
end
endcase
end
end
1.3 输出控制逻辑(时序逻辑)
// 3 the sequential FSM output
always@(posedge i_sys_clk or negedge i_sys_rst_n)begin
if(!i_sys_rst_n)begin
o_aux_g0_pwr_en <= {AUX_NUM_G0 {1'b0}};
......
o_aux_g4_pwr_en <= {AUX_NUM_G4 {1'b0}};
o_main_g0_pwr_en <= {MAIN_NUM_G0{1'b0}};
......
o_main_g9_pwr_en <= {MAIN_NUM_G9{1'b0}};
o_sys_power_good <= 1'b0;
o_cpu_rsmrst_n <= 1'b0;
end
else if((r_next_state == FSM_IDLE))begin
o_aux_g0_pwr_en <= {AUX_NUM_G0 {1'b0}};
......
o_aux_g4_pwr_en <= {AUX_NUM_G4 {1'b0}};
o_main_g0_pwr_en <= {MAIN_NUM_G0{1'b0}};
......
o_main_g9_pwr_en <= {MAIN_NUM_G9{1'b0}};
o_sys_power_good <= 1'b0;
o_cpu_rsmrst_n <= 1'b0;
end
else begin
o_aux_g0_pwr_en <= (r_next_state == FSM_AUX_G0_PWR_ON ) ? {AUX_NUM_G0 {1'b1}} : ((r_next_state == FSM_AUX_G0_PWR_OFF ) ? {AUX_NUM_G0 {1'b0}} : o_aux_g0_pwr_en );
......
o_aux_g4_pwr_en <= (r_next_state == FSM_AUX_G4_PWR_ON ) ? {AUX_NUM_G4 {1'b1}} : ((r_next_state == FSM_AUX_G4_PWR_OFF ) ? {AUX_NUM_G4 {1'b0}} : o_aux_g4_pwr_en );
o_main_g0_pwr_en <= (r_next_state == FSM_MAIN_G0_PWR_ON) ? {MAIN_NUM_G0{1'b1}} : ((r_next_state == FSM_MAIN_G0_PWR_OFF) ? {MAIN_NUM_G0{1'b0}} : o_main_g0_pwr_en);
......
o_main_g9_pwr_en <= (r_next_state == FSM_MAIN_G9_PWR_ON) ? {MAIN_NUM_G9{1'b1}} : ((r_next_state == FSM_MAIN_G9_PWR_OFF) ? {MAIN_NUM_G9{1'b0}} : o_main_g9_pwr_en);
o_sys_power_good <= (r_next_state == FSM_CPUDONE ) ? 1'b1 : ((r_next_state == FSM_PWR_DOWN ) ? 1'b0 : o_sys_power_good );
o_cpu_rsmrst_n <= (r_next_state == FSM_AUX_PWR_OK ) ? 1'b1 : ((r_next_state == FSM_CLEAR_FAULT) ? 1'b0 : o_cpu_rsmrst_n );
end
end
2.上电超时和异常掉电逻辑
2.1 上电超时
always@(posedge isys_clk or negedge isys_rst_n)begin
if(!isys_rst_n) begin
rPWR_RUNTIME <= 1'b0;
end
else begin
if((rPWR_RISE_TIME_COUNT == POWER_RUNTIME_NUM) && (rPWR_RUNDOWN == 1'b0))begin
rPWR_RUNTIME <= 1'b1;
end
else begin
rPWR_RUNTIME <= rPWR_RUNTIME;
end
end
end
always@(posedge i10ms_clk or negedge isys_rst_n)begin
if((!isys_rst_n) || (!iEN_POWER))begin
rPWR_RISE_TIME_COUNT <= 16'h0000;
end
else if((rPWR_RISE_TIME_COUNT == POWER_RUNTIME_NUM)||(iPGD_POWER == 1'b1)) begin
rPWR_RISE_TIME_COUNT <= rPWR_RISE_TIME_COUNT ;
end
else begin
rPWR_RISE_TIME_COUNT <= rPWR_RISE_TIME_COUNT + 1'b1;
end
end
2.2 异常掉电
always@(posedge isys_clk or negedge isys_rst_n)begin
if(!isys_rst_n) begin
rPWR_RUNTIME_Q1 <= 1'b0;
rPWR_RUNTIME_Q2 <= 1'b0;
rPWR_RUNTIME_Q3 <= 1'b0;
end
else begin
rPWR_RUNTIME_Q1 <= iPGD_POWER;
rPWR_RUNTIME_Q2 <= rPWR_RUNTIME_Q1;
rPWR_RUNTIME_Q3 <= rPWR_RUNTIME_Q2;
end
end
assign wPWR_FAILURE_FLG = (~rPWR_RUNTIME_Q1) && (rPWR_RUNTIME_Q3);
always@(posedge isys_clk or negedge isys_rst_n)begin
if(!isys_rst_n || !iPREVIOUS_PGD) begin
rPWR_RUNDOWN <= 1'b0;
end
else if(wPWR_FAILURE_FLG) begin
rPWR_RUNDOWN <= 1'b1;
end
else begin
rPWR_RUNDOWN <= rPWR_RUNDOWN;
end
end
3.计数器计时逻辑
always @(posedge i_sys_clk or negedge i_sys_rst_n or negedge i_start)begin
if (!i_sys_rst_n | !i_start) begin
r_done <= 1'b0;
r_count <= 8'h00;
end
else if(i_sample_clk)begin
if(i_delay_cnt == (r_count + 1'b1))begin
r_done <= 1'b1;
r_count <= 8'h00;
end
else begin
r_done <= 1'b0;
r_count <= r_count + 1'b1;
end
end
end
assign o_done = r_done;
第三节:逻辑解析
1. 模块输入信号
2. 模块输出信号
3. 模块传递参数
4. 边沿检测
小举栗子(上升沿检测)
4.1 Verilog源码
always@(posedge i_sys_clk or negedge i_sys_rst_n)begin
if(!i_sys_rst_n) begin
r_siganl_d1_q <= 1'b0;
r_siganl_d2_q <= 1'b0;
end
else begin
r_siganl_d1_q <= signal_in;
r_siganl_d2_q <= r_siganl_d1_q;
end
end
assign w_rising_edge = r_siganl_d1_q & (~r_siganl_d2_q);
assign w_falling_edge = r_siganl_d2_q & (~r_siganl_d1_q);
4.2 Visio波形图
4.3 数字逻辑图
5. 延时计数器
5.1 Verilog源码
always @(posedge i_sys_clk or negedge i_sys_rst_n or negedge i_start)begin
if (!i_sys_rst_n | !i_start) begin
r_done <= 1'b0;
r_count <= 8'h00;
end
else if(i_sample_clk)begin
if(i_delay_cnt == (r_count + 1'b1))begin
r_done <= 1'b1;
r_count <= 8'h00;
end
else begin
r_done <= 1'b0;
r_count <= r_count + 1'b1;
end
end
end
assign o_done = r_done;
5.2 Visio波形图
5.3 数字逻辑图
6. 采样时钟
6.1 Verilog 源码
parameter DIV_NUM = 6;
always@(posedge i_sys_clk or negedge i_sys_rst_n)begin
if(!i_sys_rst_n)
r_div_cnt <= 8'h00;
else if(r_div_cnt == DIV_NUM)
r_div_cnt <= 8'h00;
else
r_div_cnt <= r_div_cnt + 1'b1;
end
always@(posedge i_sys_clk or negedge i_sys_rst_n)begin
if(!i_sys_rst_n)
r_div_clk <= 1'b0;
else if(i_div_en)
r_div_clk <= (r_div_cnt == DIV_NUM) ? 1'b1 : 1'b0;
else
r_div_clk <= r_div_clk;
end
assign o_div_clk = r_div_clk;
6.2 Visio波形图
6.3 数字逻辑图
7. 状态转移逻辑
7.1 Verilog源码
FSM_GROUP1_PWR_ON : begin
w_delay_start = 1'b1;
if(w_pwr_fault_flg) // (power on timeout | power run down) & (~forced power on)
r_next_state = FSM_PWR_FAIL;
else if((&i_main_g5_pwr_pgd | i_forced_pwron) && w_delay_ms_done) begin
w_delay_start = 1'b0;
w_timeout_cnt = TIMEOUT_COUNT;
w_delay_ms_cnt = (MAIN_PWR_GROUP > 2) ? MAIN_DELAY_G6 : w_delay_ms_cnt;
r_next_state = (MAIN_PWR_GROUP > 2) ? FSM_GROUP2_PWR_ON : FSM_CPUDONE;
end
else
r_next_state = FSM_GROUP1_PWR_ON;
end
7.2 数字逻辑图
第四节:时序仿真结果
哈哈哈哈哈,Testbench.v测试激励文件想要不,哈哈哈哈哈!!!
先不说了,直接放结果,信息量有点大(包含上电超时和异常掉电的仿真波形),慢慢品哦^_^
第五节:优化逻辑资源
咋滴,这部分你也想CV,不可能,绝不可能!开个玩笑!!
此优化部分需要结合自己的实际项目平台(因为不同平台的电源轨数目有所差异,状态机的状态数目也应有相应的变化)。因此,如何优化power sequence Verilog模块并运用在自己的项目上,待续……
第六节:参考资料
[1] 633502 Birch Stream-SP Platform Design Guide Rev0.7 2022
[2] 772467_BHS_Intel_PFR_FPGA_Source_Code_Rev0_5.7Z文章来源:https://www.toymoban.com/news/detail-853174.html
[3] 自己脑袋里的江湖(浆糊)文章来源地址https://www.toymoban.com/news/detail-853174.html
到了这里,关于X86 CPU Power Sequence控制之FPGA代劳的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!