X86 CPU Power Sequence控制之FPGA代劳

        本人最近心态异常平静,于是乎--->简单整理下这两年魔幻般的经历(咱从地道的搬砖人又回到了研究僧的灵笼中,装作不开心~)。

        注:转载本文章,请标明其来源。同时,此文章涉及的逻辑块代码仅供学习参考!!!谢谢配合!!!!!!!

        本文以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

        [3] 自己脑袋里的江湖(浆糊)

  • 32
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Legal Lines and Disclaimers Intel technologies’ features and benefits depend on system configuration and may require enabled hardware, software or service activation. Learn more at Intel.com, or from the OEM or retailer. No computer system can be absolutely secure. Intel does not assume any liability for lost or stolen data or systems or any damages resulting from such losses. You may not use or facilitate the use of this document in connection with any infringement or other legal analysis concerning Intel products described herein. You agree to grant Intel a non-exclusive, royalty-free license to any patent claim thereafter drafted which includes subject matter disclosed herein. No license (express or implied, by estoppel or otherwise) to any intellectual property rights is granted by this document. The products described may contain design defects or errors known as errata which may cause the product to deviate from published specifications. Current characterized errata are available on request. This document contains information on products, services and/or processes in development. All information provided here is subject to change without notice. Contact your Intel representative to obtain the latest Intel product specifications and roadmaps. Intel disclaims all express and implied warranties, including without limitation, the implied warranties of merchantability, fitness for a particular purpose, and non-infringement, as well as any warranty arising from course of performance, course of dealing, or usage in trade. Copies of documents which have an order number and are referenced in this document may be obtained by calling 1-800-5484725 or by visiting www.intel.com/design/literature.htm. Intel, Xeon, and the Intel logo are trademarks of Intel Corporation in the U.S. and/or other countries. *Other names and brands may be claimed as the property of others. Copyright © 2018, Intel Corporation. All Rights Reserved.
STM32 Cube是STMicroelectronics(ST)提供的一款嵌入式软件开发平台,用于开发基于STM32微控制器的应用程序。Power Sequence是指在STM32微控制器上电时各种电源信号的启动和关闭顺序。 在设计STM32微控制器的电路板时,需要遵循一定的电源引脚的连接规则,以确保电源信号的正确启动和关闭。Power Sequence是这些电源引脚的启动和关闭顺序。 通常情况下,Power Sequence涉及到的电源信号可以分为几种类型:供电电源、复位信号和引脚电源。供电电源包括VDD、VDDA和VDDCORE等,在上电时必须先启动。复位信号包括NRST和PORRST等,用于重置整个系统。引脚电源通常是外部器件的供电引脚,它们的启动和关闭与供电电源的启动和关闭有关。 在STM32微控制器引脚上电之前,必须先启动供电电源,并确保它们的电压稳定,以避免电源噪声对系统的影响。然后,根据设计要求,可以启动复位信号和引脚电源。在关闭时,应按相反的顺序关闭这些信号,以确保系统正常停机。 通过STM32 Cube,开发人员可以灵活配置Power Sequence,以满足不同应用的需求。使用CubeMX工具,开发人员可以通过简单的图形界面进行配置,选择所需的引脚和电源信号,然后自动生成相应的初始化代码。这大大简化了对Power Sequence的配置工作,提高了开发效率。 综上所述,STM32 Cube Power Sequence是STM32微控制器上电时各种电源信号的启动和关闭顺序。通过STM32 Cube开发平台,我们可以方便地配置Power Sequence,并生成相应的初始化代码,提高开发效率。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值