

`timescale 1ns/10ps

module p2040cpld( //  wd_cfg,				//m2
				 //	wd_in,				//m2
					cpld_clk,
					clkin66,
					cfg_sd_refclk1_s,
					fbank_sel,
					cpu_poreset_n,
					cpu_hrst_n,
					cpu_trst_n,
					rst_flsh_n,
					rst_sgmii_n,
					rst_tsec_n,
					rst_pexconn_n,
					rst_ddr,
					rst_i2c_exp,
			//		cop_srst_n,
					cop_hrst_n,
					cop_trst_n,
					status_led,
					ps_vcore_pg,
					ctl_vcore_en,
					ps_ddr_pg,
					gvdd_pwr_on,
					ctl_vcore_mgn,
					ctl_usb1p0_en,
					ctl_usb3p3_en,
					atx_pwr_sw,
					atx_pwr_on,
					atx_pwr_pg,
					povdd_0_en,
					povdd_1p5_en,
					addr,
					data,
					lwe0_n,
					lgpl0,
					lgpl1,
					lgpl2,
					lgpl3,
			//		lgpl4,
					lgpl5,
					cfg_sdwidth,
					lcs3_n,
					rst_pld_n,
					hrstreq_n,
					pcie_sel,
					aurora_sel,
					mux_en,
					sysclk_clk,
					sysclk_data,
					sysclk_strobe,
					sw_sysclk,
			//		pwr_sw_bypass,
					gen_rst,
					spi_i2c_1588,
					atxpreload_on,
					sw3_7,
					flash_cs_sel
			//		sw6				//m2
					 );

//input	wd_in;			//watchdog timer over flow output  m2
input	cpld_clk;		//clock 32.768KHz input for count and delay	
input	clkin66;		//system clock input for POR hold time count
//input	cop_srst_n;		//SW reset from JTAG
input	cop_hrst_n;		//HW reset from JTAG
input	cop_trst_n;		//test reset from JTAG
input	ps_vcore_pg;	//cpu core voltage power good
input	ps_ddr_pg;		//DDR power good
input	atx_pwr_pg;		//ATX power good
input	atx_pwr_sw;		//ATX power switch input
input	lcs3_n;			//local bus chip select
input	lwe0_n;			//local bus write enable
input	[4:0]addr;		//local bus address
input	rst_pld_n;		//reset triggered by max811 with manual switch
input	hrstreq_n;		//HW reset request from cpu
input	cpu_hrst_n;		//HW reset output from CPU while power on
input	[2:0]sw_sysclk;	//system clock select input 66.666MHz, 100MHz or 83.333MHz
//input	pwr_sw_bypass;
//input	[7:0]sw6;		//m2
input	sw3_7;

//output	[2:0]wd_cfg;			//watchdog timeout period configure  m2
output	cpu_poreset_n;			//cpu power on reset
output	cpu_trst_n;				//cpu JTAG reset
output	rst_pexconn_n;			//pcie connector reset
output	rst_tsec_n;				//RGMII GbE PHY reset
output	rst_sgmii_n;			//SGMII GbE PHY reset
output	rst_flsh_n;				//flash reset
output	rst_ddr;				//DDR reset
output	rst_i2c_exp;			//I2C I/O expender reset

output  [3:0]pcie_sel;			//PCIe or SATA/SGMII/Aurora interface select
output	status_led;				//Status LED for CPLD
output	ctl_vcore_en;			//cpu core voltage enable
output	ctl_vcore_mgn;			//cpu core voltage control
output	gvdd_pwr_on;			//DDR voltage enable		
output	ctl_usb1p0_en;			//CPU USB 1.0V enable
output	ctl_usb3p3_en;			//CPU USB 3.3V enable
output	atx_pwr_on;				//ATX power enable
input	povdd_0_en;				//CPU fuse programming override 0V enable
output	povdd_1p5_en;			//CPU fuse programming override 1.5V enable


output	sysclk_clk;				//programmable clock device IS307M configuration signal
output	sysclk_data;			//programmable clock device IS307M configuration signal
output	sysclk_strobe;			//programmable clock device IS307M configuration signal

output	gen_rst;				//1588 connector reset
output	spi_i2c_1588;			//1588 connector SPI or IIC select

output	atxpreload_on;
output	flash_cs_sel;

inout	lgpl0;					//POR pin
inout	lgpl1;					//POR pin
inout	lgpl3;					//POR pin
inout	lgpl5;					//POR pin



inout	[7:0]data;				//local bus data
inout	lgpl2;					//local bus read enable and POR Pin
inout	[3:0]cfg_sd_refclk1_s;	//SerDes reference clock select
inout	aurora_sel;				//JTAG or Aurora interface select
inout	mux_en;					//1588 or RGMII
inout	cfg_sdwidth;			//SPI or SD/MMC data bus 4~7
inout	fbank_sel;				//NOR flash bank select


// statemachine parameters
parameter	idle = 4'b0001;
parameter	wait_for_pwr_switch = 4'b0010;
parameter	turn_atx_on = 4'b0011;
parameter	poreset_assert = 4'b0100;
parameter	turn_vcore_on = 4'b0101;
parameter	turn_gvdd_on = 4'b0110;
parameter	system_up = 4'b0111;
parameter	override_reset = 4'b1001;			//system reset without initializing CPLD registers
parameter	override_poreset_assert = 4'b1010;	//system reset without initializing CPLD registers




//reg [2:0]wd_cfg;			//default disable the watchdog  m2
reg ctl_vcore_en = 1'b0;			//default cpu core voltage disabled
reg gvdd_pwr_on = 1'b0;				//default DDR voltage disabled
reg [7:0] regd = 8'b11111111;		//read buff register
reg [3:0] cpld_rev = 4'b0100;		//cpld major revision register  m1
reg	[3:0] cpld_rev_sub = 4'b0001;	//cpld minor revision register  m1
reg [3:0] pcba_rev = 4'b0101;		//pcba revision register        m1
reg override_system_rst = 1'b0;		//set this register to reset the system directly without initializing CPLD registers
reg	hreset_req_flag;			//flag of HW reset request from CPU
reg	hreset_req_ff;				//HW reset request from CPU time buffer
reg [11:0] delay = 12'b0;			//time delay register
reg non_reg = 1'b0;
reg [3:0] current_state = idle;		//current statemachine register
reg [3:0] next_state = idle;		//next statemachine register
reg	pwr_hrst_n = 1'b1;				//system reset control from CPLD
reg sync4_ff1;						//POR hold time delay buffer respect to negation of PORESET based on system clock
reg sync4_ff2;						//POR hold time delay buffer respect to negation of PORESET based on system clock
reg sync4_ff3;						//POR hold time delay buffer respect to negation of PORESET based on system clock
reg	sync4_ff4;						//POR hold time delay buffer respect to negation of PORESET based on system clock
reg	[4:0]cfg_rcw_src;	//POR CPLD control register  m3
reg	atx_pwr_on = 1'b1;				//default ATX power disable
reg	ctl_usb1p0_en = 1'b0;			//default CPU USB 1.0V power disable
reg	ctl_usb3p3_en = 1'b0;			//default CPU USB 3.3V power disable
reg	[1:0]sdbank1_clk;		//default SerDes bank1 reference clock 100MHz
reg	[1:0]sdbank2_clk;		//default SerDes bank2 reference clock 125MHz
reg	aurora_jtag_sel =1'b0;			//default JTAG port enabled
reg [3:0]pcie_sel;			//default pice interface enabled
reg	[1:0]switch_strobe;		//default SPI and RGMII interface selected
reg	[7:0]software_on;		//ddfault CPLD control disabled
reg	vbank = 1'b0;					//default upper flash bank for booting
reg [7:0]atx_pwr_sw_cnt = 8'b0;		//ATX power on or off time count
reg atx_pwr_sw_over;			//ATX power on or off count over flow
reg atx_pwr_up = 1'b0;				//ATX power up control
reg ret_reg = 1'b0;					//initializing CPLD registers trigger sigal
reg	global_rst = 1'b0;				//set this register to reset the system directly with initializing CPLD registers


reg	sysclk_data =1'b0;
reg	sysclk_strobe;
reg	[4:0]sysclk_num = 5'b0;			//programmable clock device IS307M configure clock count			
reg	sysclk_num_over =1'b0;			//programmable clock device IS307M configure clock count over flow
reg	sysclk_strobe_num = 1'b0;

reg	flash_cs_sel = 1'b0;
reg	atxpreload_reg = 1'b0;

reg [3:0]rev_inner = 4'b0101;

//programmable clock device IS307M configuration words
reg	[23:0]pro_clk_config0 = 24'b001101110000100000000001;	//66.666MHz
reg	[23:0]pro_clk_config1 = 24'b001100110000011000000001;	//83.333MHz
reg	[23:0]pro_clk_config2 = 24'b001100110000100000000001;	//100MHz



wire	[4:0]addr;
wire	[7:0]data;
wire	por_drive_n;				//POR drive enable 
wire	sysclk_clk;
wire	[23:0]sysclk_24bit;




assign 	sysclk_24bit[23:0] =	(sw_sysclk[2:0] == 3'b001)?	pro_clk_config1[23:0] :
								(sw_sysclk[2:0] == 3'b010)?	pro_clk_config2[23:0] : pro_clk_config0[23:0];



			
assign	sysclk_clk = (sysclk_num_over)? cpld_clk: 1'b0;
	
assign spi_i2c_1588 = 1'b1;



//************************************************
//CPU, DDR, flash, PCIe, RGMII and SGMII PHY reset
assign	cpu_poreset_n 	= (cop_hrst_n && pwr_hrst_n);
assign	cpu_trst_n 		= (pwr_hrst_n && cop_trst_n);
assign	rst_flsh_n 		= cpu_poreset_n;
assign	rst_sgmii_n 	= cpu_hrst_n;
assign	rst_tsec_n 		= cpu_hrst_n;
assign	rst_pexconn_n 	= cpu_hrst_n;
assign	rst_ddr 		= cpu_hrst_n;
assign	rst_i2c_exp 	= cpu_hrst_n;
assign	gen_rst			= cpu_hrst_n;
//************************************************




//************************************************
//CPU core voltage 1.1V
assign ctl_vcore_mgn = 1'b1;
//************************************************									

assign status_led = 1'b0;

//************************************************
//power supply for secure boot fuse programming, now 0V
//assign	povdd_0_en = 1'b0;
assign	povdd_1p5_en = povdd_0_en;
//************************************************


//************************************************
//POR hold time delay respect to negation of CPU PORESET
assign por_drive_n = sync4_ff4;
//************************************************


//programmable clock device IS307M configuration
always @(negedge cpld_clk)
	begin
		if (ret_reg)
			begin
				if (sysclk_num == 5'b11000)
					begin
						sysclk_num_over <= 1'b0;
						if (sysclk_strobe_num)
							begin
								sysclk_strobe <= 1'b0;
							end
						else
							begin
								sysclk_strobe_num <= 1'b1;
								sysclk_strobe <= 1'b1;
							end
					end
				else
					begin
									
						sysclk_num <= sysclk_num + 1;
						sysclk_num_over <= 1'b1;
						sysclk_data <= sysclk_24bit[23-sysclk_num];	
					end
			end
		else
			begin
				sysclk_num <= 5'b0;			
				sysclk_num_over <= 1'b0;
				sysclk_strobe_num <=1'b0;
				sysclk_strobe <= 1'b0;
			end
	end




//provide POR hold time (4 system clks) respect to negation of PORESET
always @(posedge clkin66 or negedge cpu_poreset_n)
     begin
          if (!cpu_poreset_n)
             begin
               sync4_ff1 <= 1'b0;
               sync4_ff2 <= 1'b0;
               sync4_ff3 <= 1'b0;
               sync4_ff4 <= 1'b0;
             end
          else
             begin
               sync4_ff1 <= cpu_poreset_n;
               sync4_ff2 <= sync4_ff1;
               sync4_ff4 <= sync4_ff3;
               sync4_ff3 <= sync4_ff2;
             end
     end


//RCW source location setting
bufif1  b0(lgpl0,	cfg_rcw_src[0],	(~por_drive_n) && software_on[0]);
bufif1  b1(lgpl1,	cfg_rcw_src[1], (~por_drive_n) && software_on[0]);
bufif1  b2(lgpl2,	cfg_rcw_src[2], (~por_drive_n) && software_on[0]);
bufif1  b3(lgpl3,	cfg_rcw_src[3], (~por_drive_n) && software_on[0]);
bufif1  b4(lgpl5,	cfg_rcw_src[4], (~por_drive_n) && software_on[0]);


//software CPLD registers controllable output 
bufif1	b5(cfg_sdwidth,				switch_strobe[0],	software_on[1]);
bufif1	b6(mux_en,					switch_strobe[1],	software_on[2]);
bufif1	b7(aurora_sel,				aurora_jtag_sel,	software_on[3]);
bufif1	b8(cfg_sd_refclk1_s[0],		sdbank1_clk[0],		software_on[4]);
bufif1	b9(cfg_sd_refclk1_s[1],		sdbank1_clk[1],		software_on[4]);
bufif1	b10(cfg_sd_refclk1_s[2],	sdbank2_clk[0],		software_on[5]);
bufif1	b11(cfg_sd_refclk1_s[3],	sdbank2_clk[1],		software_on[5]);
bufif1	b12(fbank_sel,				vbank,				software_on[6]);


assign	atxpreload_on = (software_on[7] == 1'b1)? atxpreload_reg : sw3_7;



always @(posedge clkin66 or negedge cpu_poreset_n)
     begin
		if (!cpu_poreset_n)
			flash_cs_sel = ({lgpl0, lgpl1, lgpl2, lgpl3, lgpl5} == 5'b01001)? 1'b1 : 1'b0;
		else
			flash_cs_sel = flash_cs_sel;
     end




//time delay counter
//set time delay between reset assert and power on 
always@(posedge cpld_clk)
	begin
		if (next_state == system_up || next_state == poreset_assert || next_state == override_poreset_assert)
			begin
				if (delay == 12'b1111_1111_1111)
					begin
						current_state <= next_state;
						delay <= 12'b0;
					end
				else
					delay <= delay +1;
			end
		else
			begin
				current_state <= next_state;
				delay <= 12'b0;
			end
	end






//ATX power on/off control by power switch
always@(posedge cpld_clk)
	begin
		if (current_state == wait_for_pwr_switch || current_state == system_up)
			begin
				if (!atx_pwr_sw)
					begin
						if (atx_pwr_sw_cnt == 8'b1111_1111)
							begin
								atx_pwr_sw_over <= 1'b1;
							end
						else
							begin
								atx_pwr_sw_cnt <= atx_pwr_sw_cnt + 1;
							end
	
					end
				else
					begin
						if (atx_pwr_sw_over)
							begin
								atx_pwr_up <= ~atx_pwr_up;
							end
						atx_pwr_sw_cnt <= 8'b0;
						atx_pwr_sw_over <= 1'b0;
					end
			end

		else
			begin
				atx_pwr_sw_cnt <= 8'b0;
				atx_pwr_sw_over <= 1'b0;
			end

	end



//hrstreg_n: output of HRESET_REQ pin of CPU
always@(posedge cpld_clk or negedge hrstreq_n)
	begin
		if (!hrstreq_n)
			begin
				if (cop_hrst_n)
					begin
						hreset_req_flag <= 1'b0;
						hreset_req_ff <= 1'b0;
					end
				else
					begin
						hreset_req_flag <= 1'b1;
						hreset_req_ff <= 1'b1;						
					end
			end
		else
			begin
				hreset_req_ff <= hrstreq_n;
				hreset_req_flag <= hreset_req_ff;
			end
	end



//state machine
always@(rst_pld_n or current_state or atx_pwr_up or atx_pwr_pg or ps_vcore_pg or ps_ddr_pg or override_system_rst or hreset_req_flag or global_rst)
	begin
		case (current_state)
			idle:
				begin
					if (rst_pld_n)
						begin
							next_state = wait_for_pwr_switch;
						end
					else
						next_state = idle;
				end
			wait_for_pwr_switch:
				begin
					if (atx_pwr_up)
						next_state = turn_atx_on;
					else
						next_state = wait_for_pwr_switch;
				end
			turn_atx_on:
				begin
					next_state = poreset_assert;
				end
			override_reset:
				begin
					next_state = override_poreset_assert;
				end
			poreset_assert:
				begin
					if (atx_pwr_pg)
						next_state = turn_vcore_on;
					else
						next_state = poreset_assert;
				end
			override_poreset_assert:
				begin
					if (atx_pwr_pg)
						next_state = turn_vcore_on;
					else
						next_state = override_poreset_assert;
				end
			turn_vcore_on:
				begin
					if (ps_vcore_pg)
						next_state = turn_gvdd_on;
					else
						next_state = turn_vcore_on;
				end
			turn_gvdd_on:
				begin
					if (ps_ddr_pg)
						next_state = system_up;
					else
						next_state = turn_gvdd_on;
				end
			system_up:
				begin
					if (!atx_pwr_up)
						next_state = idle;
					else if ((!rst_pld_n) || global_rst || (~hreset_req_flag))
						next_state = turn_atx_on;
					else if (override_system_rst)
						next_state = override_reset;
					else
						next_state = system_up;
				end	
//			load_default:
//				begin
//					if (global_rst || (~hreset_req_flag))
//						next_state = turn_atx_on;
//					else
//						next_state = load_default;
//				end
			default:
				begin
					next_state = idle;
				end
		endcase
			
	end


//output per state change
always@(next_state)
	begin
		case (next_state)
			idle:
				begin
					pwr_hrst_n = 1'b1;
					atx_pwr_on = 1'b1;
					ctl_usb1p0_en = 1'b0;
					ctl_usb3p3_en = 1'b0;
					ctl_vcore_en = 1'b0;
					gvdd_pwr_on = 1'b0;
					ret_reg = 1'b0;
				end
			wait_for_pwr_switch:
				begin
					pwr_hrst_n = 1'b1;
					atx_pwr_on = 1'b1;
					ctl_usb1p0_en = 1'b0;
					ctl_usb3p3_en = 1'b0;
					ctl_vcore_en = 1'b0;
					gvdd_pwr_on = 1'b0;
					ret_reg = 1'b0;
				end
			turn_atx_on:
				begin
					pwr_hrst_n = 1'b1;
					atx_pwr_on = 1'b0;
					ctl_usb1p0_en = 1'b0;
					ctl_usb3p3_en = 1'b1;
					ctl_vcore_en = 1'b0;
					gvdd_pwr_on = 1'b0;
					ret_reg = 1'b0;
				end
			override_reset:
				begin
					pwr_hrst_n = 1'b1;
					atx_pwr_on = 1'b0;
					ctl_usb1p0_en = 1'b0;
					ctl_usb3p3_en = 1'b1;
					ctl_vcore_en = 1'b0;
					gvdd_pwr_on = 1'b0;
					ret_reg = 1'b0;
				end
			poreset_assert:
				begin
					pwr_hrst_n = 1'b0;
					atx_pwr_on = 1'b0;
					ctl_usb1p0_en = 1'b0;
					ctl_usb3p3_en = 1'b1;
					ctl_vcore_en = 1'b0;
					gvdd_pwr_on = 1'b0;
					ret_reg = 1'b1;
				end
			override_poreset_assert:
				begin
					pwr_hrst_n = 1'b0;
					atx_pwr_on = 1'b0;
					ctl_usb1p0_en = 1'b0;
					ctl_usb3p3_en = 1'b1;
					ctl_vcore_en = 1'b0;
					gvdd_pwr_on = 1'b0;
					ret_reg = 1'b0;
				end
			turn_vcore_on:
				begin
					pwr_hrst_n = 1'b0;
					atx_pwr_on = 1'b0;
					ctl_usb1p0_en = 1'b1;
					ctl_usb3p3_en = 1'b1;
					ctl_vcore_en = 1'b1;
					gvdd_pwr_on = 1'b0;
					ret_reg = 1'b0;		
				end
			turn_gvdd_on:
				begin
					pwr_hrst_n = 1'b0;
					atx_pwr_on = 1'b0;
					ctl_usb1p0_en = 1'b1;
					ctl_usb3p3_en = 1'b1;
					ctl_vcore_en = 1'b1;
					gvdd_pwr_on = 1'b1;
					ret_reg = 1'b0;
				end
			system_up:
				begin
					pwr_hrst_n = 1'b1;
					atx_pwr_on = 1'b0;
					ctl_usb1p0_en = 1'b1;
					ctl_usb3p3_en = 1'b1;
					ctl_vcore_en = 1'b1;
					gvdd_pwr_on = 1'b1;
					ret_reg = 1'b0;
				end
			default:
				begin
					pwr_hrst_n = 1'b1;
					atx_pwr_on = 1'b1;
					ctl_usb1p0_en = 1'b0;
					ctl_usb3p3_en = 1'b0;
					ctl_vcore_en = 1'b0;
					gvdd_pwr_on = 1'b0;
					ret_reg = 1'b0;					
				end
		endcase
	end



//read registers
always@(negedge lgpl2)        //lgpl2==oe;                 
	begin
		if (lcs3_n==0)
			begin
				case (addr)
					0:	regd[7:0] <= {4'b0, cpld_rev[3:0]};
					1:	regd[7:0] <= {4'b0, cpld_rev_sub[3:0]};
					2:	regd[7:0] <= {4'b0, pcba_rev[3:0]};
					3:	regd[7:0] <= {7'b0, override_system_rst};
					4:	regd[7:0] <= {4'b0, rev_inner[3:0]};
					5:	regd[7:0] <= software_on[7:0];					
					6:	regd[7:0] <= {3'b0, cfg_rcw_src[4:0]};
					7: 	regd[7:0] <= {6'b0, switch_strobe[1:0]};
					8:	regd[7:0] <= {7'b0, aurora_jtag_sel};
					9: 	regd[7:0] <= {6'b0, sdbank1_clk[1:0]};
					10: regd[7:0] <= {6'b0, sdbank2_clk[1:0]};
					11:	regd[7:0] <= {7'b0, vbank};
					12:	regd[7:0] <= {4'b0, pcie_sel[3:0]};
					13:	begin
							regd[0] <= mux_en;
							regd[1] <= fbank_sel;
							regd[3:2] <= cfg_sd_refclk1_s[1:0];
							regd[5:4] <= cfg_sd_refclk1_s[3:2];
							regd[6] <= cfg_sdwidth;
							regd[7] <= aurora_sel;
						end
					14:	regd[7:0] <= {7'b0, global_rst};
					15:	regd[7:0] <= {5'b0, sw_sysclk[2:0]};
					16:	regd[7:0] <= {7'b0, atxpreload_reg};
					17: begin
							regd[5:0] <= 6'b0;
							regd[6] <= (software_on[7] == 1'b1)? atxpreload_reg : sw3_7;
							regd[7] <= 1'b0;
						end
		//			16:	regd[7:0] <= sw6[7:0];					//m2
					default:	regd[7:0] <= 8'bzzzzzzzz;
				endcase	
			end
	end







always@(posedge clkin66 or negedge pwr_hrst_n)                               
begin
	if (!pwr_hrst_n)
		begin
			override_system_rst <= 1'b0;
			if (ret_reg)
				begin
		//			override_system_rst <= 1'b0;
					software_on[7:0] <= 8'b0; 
		//			wd_cfg[2:0] <= 3'b011;			//m2
					cfg_rcw_src[4:0] <= {lgpl5, lgpl3, lgpl2, lgpl1, lgpl0};
					switch_strobe[1:0] <= {mux_en, cfg_sdwidth};																																																																																																																											
					aurora_jtag_sel <= aurora_sel;
					sdbank1_clk[1:0] <= cfg_sd_refclk1_s[1:0];
					sdbank2_clk[1:0] <= cfg_sd_refclk1_s[3:2];
					vbank <= fbank_sel;
					pcie_sel[3:0] <= 4'b1110;
					global_rst <= 1'b0;
					atxpreload_reg <= sw3_7;
				end
		//	else
		//		override_system_rst <= 1'b0;
		end
	else if (lwe0_n== 1'b0 && lcs3_n== 1'b0)
			begin
				case (addr)
					3:	override_system_rst <= data[0];
		//			4:	wd_cfg[2:0] <= data[2:0];		//m2
					5:	software_on[7:0] <= data[7:0];
					6:	cfg_rcw_src[4:0] <= data[4:0];
					7: 	switch_strobe[1:0] <= data[1:0];
					8:	aurora_jtag_sel <= data[0];
					9:	sdbank1_clk[1:0] <= data[1:0];
					10:	sdbank2_clk[1:0] <= data[1:0];
					11:	vbank <= data[0];
					12:	pcie_sel[3:0] <= data[3:0];
					14:	global_rst <= data[0];
					16: atxpreload_reg <= data[0];
					default:	non_reg <= data[0];
				endcase

			end

end




assign data[7:0] = (lcs3_n==0 && lgpl2==0) ? regd[7:0] : 8'bzzzzzzzz;



endmodule

