⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcicore.v

📁 PIC 的ip 有用的着的拿去看看吧 对于开发pci总线会有很大帮助的
💻 V
📖 第 1 页 / 共 2 页
字号:
						if ((HitBaseAddress0) || (HitBaseAddress1))
							begin
							    //if our device is accessed,output devsel,trdy and stop signal
								PciDevselTrdyStopOutEnable = 1'B1;
								//8051 P2 output current local high 8bit address
								P2LatchStrobe = 1'b1;
								//P0 output address and P0 output enable
								E8051P0DataAddressSelect = 1'B1;    
								E8051P0OutEnable = 1'B1;
								//if PCI IO adderss is high 8 byte,we interpret it as inner io access
								if 	(IoMemReadInnerIo)	PciAdOutSelect = `PCI_READ_INNER_IO;
								//else if PCI IO address is low 8 byte,we interpret is as expand 8051 IO access
								else					PciAdOutSelect = `PCI_READ_E8051;

								PciStateMachine = `IO_MEMORY_ACCESS2;
							end
						//else this PCI cycle is not aim at our device
						else
								PciStateMachine = `IDLE;
					end
				`IO_MEMORY_ACCESS2:
					begin
					    //devsel is active
						PciDevsel_ 	= 1'B0;	
						//if master is not accessing our inner io,ALE will produce a falling edge to latch low 8bit address 
						//if ((~IoMemReadInnerIo) && (~IoMemWriteInnerIo))    E8051Ale = 1'B0;        
						//PciStateMachine = `IO_MEMORY_ACCESS3;						
						PciStateMachine = `IO_MEMORY_WAIT1;						
					end
				`IO_MEMORY_WAIT1:
				    begin
						//if master is not accessing our inner io,ALE will produce a falling edge to latch low 8bit address 
						if ((~IoMemReadInnerIo) && (~IoMemWriteInnerIo))    E8051Ale = 1'B0; 
						PciStateMachine = `IO_MEMORY_WAIT2;    			    
				    end
				`IO_MEMORY_WAIT2:
				    begin
						PciStateMachine = `IO_MEMORY_WAIT3;    			    
				    end	
				`IO_MEMORY_WAIT3:
				    begin
                        //if it is a memory write or expanded io write,P0 should output data	
                        if (IoMenWriteMemory || IoMemWriteExternalIo)   E8051P0DataAddressSelect = 1'B0;    
                        //else,P0 should be high impedance state
                        else    E8051P0OutEnable = 1'B0;            //else P0 output will be disabled			    
						PciStateMachine = `IO_MEMORY_ACCESS3;    			    
				    end			    			    
				`IO_MEMORY_ACCESS3:		
					begin
					    //if irdy is active,PCI master is ready for data phase,and we should produce wr or rd signal for data exchange
						if (!PciIrdy_)
							begin
                                E8051IoRd_ = ~IoMemReadExternalIo;
                                E8051Rd_ = ~IoMenReadMemory;
                                E8051IoWr_ = ~IoMemWriteExternalIo;
                                E8051Wr_ = ~IoMenWriteMemory;
                                InnerIoWriteStrobe = ~IoMemWriteInnerIo;	
                                //if it is a memory write or expanded io write,P0 should output data	
                                //if (IoMenWriteMemory || IoMemWriteExternalIo)   E8051P0DataAddressSelect = 1'B0;    
                                //else,P0 should be high impedance state
                                //else    E8051P0OutEnable = 1'B0;            //else P0 output will be disabled
                                PciStateMachine = `IO_MEMORY_ACCESS4;
                            end
                        //wait irdy be active
                        else
                            PciStateMachine = `IO_MEMORY_ACCESS3;
					end

				`IO_MEMORY_ACCESS4:
				//for this design,we want enough width of wr or rd for safty access external memory or io access timing
				//so here a wait state is inseted
					begin
					    //PciStateMachine = `IO_MEMORY_ACCESS5;
					    PciStateMachine = `IO_MEMORY_WAIT4;
					end
				`IO_MEMORY_WAIT4:
				//for this design,we want enough width of wr or rd for safty access external memory or io access timing
				//so here a wait state is inseted
					begin
					    PciStateMachine = `IO_MEMORY_ACCESS5;
					end					
				`IO_MEMORY_ACCESS5:
				    begin
				        //we activate trdy signal and will complete this pci bus cycle
						if (!PciIrdy_)
							begin
								PciTrdy_ 	= 1'B0;
								//if this is a read cycle,we should return data to master
                                if (IoMemReadExternalIo || IoMenReadMemory || IoMemReadInnerIo)   PciAdOutEnable = 1'B1;
								PciStateMachine = `IO_MEMORY_ACCESS6;
								//if master want a burst access,stop it
								if (!PciFrame_)	PciStop_ 	= 1'B0;
							end
						else	PciStateMachine = `IO_MEMORY_ACCESS5;
				    end
				`IO_MEMORY_ACCESS6:				    
				    begin
				        //local write or read is complete,all relative control signal should be inactive
                        E8051IoRd_ = 1'B1;
                        E8051Rd_ = 1'B1;
                        E8051IoWr_ = 1'B1;
                        E8051Wr_ = 1'B1;
                        InnerIoWriteStrobe = 1'B1;	
                        PciTrdy_ 	= 1'B1;
                        PciAdOutEnable = 1'B0;
                        //if it is a pci read cycle,output parity signal
                        if (IoMemReadInnerIo || IoMemReadExternalIo || IoMenReadMemory)     PciParOutEnable = 1'B1;
                        //if master want a burst access,we stop it and wait master release frame signal to flag
                        //a burst is stoped
						if (!PciFrame_)
							begin
								PciStateMachine = `IO_MEMORY_ACCESS6;		
							end 
						else
							begin
								PciStateMachine = `ACCESS_FINISH;
								PciDevsel_ 	= 1'B1;	
								PciStop_ 	= 1'B1;
							end
				    end
				`ACCESS_FINISH:
				//this PCI bus cycle is complete
					begin
						PciStateMachine = `IDLE;
						PciParOutEnable = 1'B0;
						E8051P0OutEnable = 1'B0;
						PciDevselTrdyStopOutEnable = 1'B0;
						P2LatchStrobe = 1'b0;
						E8051Ale = 1'B1;        
					end
				
			endcase
			
		end
end

////////////////////////////////////////////////////////////////////
//following block is for judge whether a PCI cycle is start or not:
//a falling edge of frame flags a PCI bus cycle will start
always @(posedge PciClk or negedge PciReset_)    
begin
    if (!PciReset_)
        PciCycleBeginClear_ = 1'B1;
    else
        PciCycleBeginClear_ = ~PciCycleBegin;
end

wire PciCycleBeginRst_;
assign PciCycleBeginRst_ = PciReset_ & PciCycleBeginClear_;
always @(negedge PciFrame_ or negedge PciCycleBeginRst_)    
begin
    if (!PciCycleBeginRst_)
        PciCycleBegin = 1'B0;
    else
        PciCycleBegin = 1'B1;
end
////////////////////////////////////////////////////////////////////			
//when a PCI cycle is start, at PCI command phase, PCI_AD and PCI_CBE
//will be latched
always @ (PciFrame_ or PciStateMachine)
begin 
   	if ((PciStateMachine == `IDLE) && (!PciFrame_)) 
		begin 
     		PciAdLatchEnable = 1'B1;
     	end
	else 
		begin 
			PciAdLatchEnable = 1'B0;
      end
end

always @ (posedge PciClk or negedge PciReset_)
begin 
   	if (PciReset_ == 1'b0) 				
   	    begin
   	        PciAdressReg = 32'H00000000; 
   			PciCbeReg	= 4'H0;
   	    end
    else
        begin
            if (PciAdLatchEnable == 1'b1) 	
                begin
                    PciAdressReg = PciAdIn; 
                    PciCbeReg = PciCbe_;
                end
   			else 	
   				begin
   					PciAdressReg = PciAdressReg;
   					PciCbeReg = PciCbeReg;
   				end
                
        end
end
 
////////////////////////////////////////////////////////////////////			
//judge whether current PCI cycle will access our device or not:
assign HitBaseAddress0 = (PciAdressReg[31:`BASE_ADDRESS0_SIZE]== BaseAddress0)? 1'b1 : 1'b0;
assign HitBaseAddress1 = (PciAdressReg[31:`BASE_ADDRESS1_SIZE]== BaseAddress1)? 1'b1 : 1'b0;

////////////////////////////////////////////////////////////////////			
//when master read our device,we should return appropriate data to master,
//the data may be config space register,memory ,expand io or inner io
always @(PciAdOutSelect or ConfigDataOut or InnerIoReg or E8051P0In )
begin
	if (PciAdOutSelect == `PCI_READ_CONFIG)			        PciAdOut = ConfigDataOut;	
	else
		begin
			PciAdOut[31:8] = 24'H000000;
			if 	(PciAdOutSelect == `PCI_READ_INNER_IO)  	PciAdOut[7:0] = {BUTTON_INT_,InnerIoReg};
			else if (PciAdOutSelect ==`PCI_READ_E8051)		PciAdOut[7:0] = E8051P0In;
			else                            				PciAdOut[7:0] = 8'H00;
		end
end

////////////////////////////////////////////////////////////////////			
//PCI config space:
//when read PCI config space:
always @ (ConfigDataChange or PciReset_)
begin 
	if (!PciReset_) 
		begin 
			ConfigDataOut = 32'H0000000; // zero at reset
     	end
	else
		begin 
			case (PciAdressReg[7:2])	
				6'b0000_00:	ConfigDataOut = {`DEVICE_ID,`VENDOR_ID};				        //config space 00
				6'b0000_01: ConfigDataOut = {5'B0,`DEVSEL_TIMING,9'B0,14'B0,Com};	        //config space 04
				6'b0000_10: ConfigDataOut = {`CLASS_CODE,`REVISION_ID};				        //config space 08
    			6'b0001_00: ConfigDataOut = {BaseAddress0,`BASE_ADDRESS0_SIZE'b0 | 1'b1};	//config space 10
				6'b0001_01: ConfigDataOut = {BaseAddress1,`BASE_ADDRESS1_SIZE'b0};	        //config space 14
				6'b0011_11: ConfigDataOut = {16'B0,`INTERRUPT_PIN,InterruptLine};	        //config space 3C
				default:  	ConfigDataOut = 32'B0; 									        //all other config space
			endcase
		end
end			
//when write to PCI config space:
always @ (posedge PciClk or negedge PciReset_)
begin 
	if (!PciReset_) 
		begin 
			Com = 2'b00;
			BaseAddress0 = ~(`BASE_ADDRESS0_LENGTH'B0);
			BaseAddress1 = ~(`BASE_ADDRESS1_LENGTH'B0);
			InterruptLine = 8'HFF;					
     	end
	else if (ConfigWriteEnable == 1'b1)
		begin 
			case (PciAdressReg[7:2])	
				6'b0000_01: 	Com = PciAdIn[1:0];	                            //config space 04
				6'b0001_00: 	BaseAddress0 = PciAdIn[31:`BASE_ADDRESS0_SIZE]; //config space 10
				6'b0001_01: 	BaseAddress1 = PciAdIn[31:`BASE_ADDRESS1_SIZE]; //config space 14
				6'b0011_11:     InterruptLine = PciAdIn[7:0];					//config space 3C
				default:  	
					begin
						Com = Com;
						BaseAddress0 = BaseAddress0;
						BaseAddress1 = BaseAddress1;
					end
			endcase
		end
end			

////////////////////////////////////////////////////////////////////			
//write inner IO space:
//inner io occupy  bytes,but only one byte is implemented physically:
//InnerIoReg.0: PCI interrupt enable,1:enable,0:disable
//InnerIoReg.1: local reset, 1:release,0:reset active
//InnerIoReg.2~6: no function is defined,user can use it as themselves prupose
//InnerIoReg.7: it is special.when read,it shows BUTTON_INT_ state,
//              when write,write 1 will clear BUTTON_INT_,write 0 has no effect
always @(negedge PciReset_ or posedge InnerIoWriteStrobe)
begin
	if (!PciReset_)
		InnerIoReg = 7'B0000000;
	else
		InnerIoReg = PciAdIn[6:0];
end		

assign	LocalReset_ = InnerIoReg[1] & PciReset_;
assign	PciIntA_  = (InnerIoReg[0] == 1'B1) ? ~BUTTON_INT_ : 1'B1;
////////////////////////////////////////////////////////////////////			
//par output when master read our device
assign Par0 = ^PciAdOut[7:0];
assign Par1 = ^PciAdOut[15:8];
assign Par2 = ^PciAdOut[23:16];
assign Par3 = ^PciAdOut[31:24];
assign ParCbe = ^PciCbe_;
assign ParReg = Par0 ^ Par1 ^ Par2 ^ Par3 ^ ParCbe;
always @(posedge PciClk)
begin
	PciPar = ParReg;
end

///////////////////////////////////////////////////////
//button interrupt produce:
`define	BUTTON_INT_SCAN_TIME		19  //PCI clock is 33MHz,this value is for a 16ms timer
//`define	BUTTON_INT_SCAN_TIME		4	//when simulation,a little counter is convenient
 
reg	[`BUTTON_INT_SCAN_TIME-1:0]	INT_SCAN_COUNTER;
wire INT_SCAN_CLK;

always @(negedge PciReset_ or posedge PciClk)
begin
	if (!PciReset_)
		INT_SCAN_COUNTER = `BUTTON_INT_SCAN_TIME'H0;
	else
		INT_SCAN_COUNTER = INT_SCAN_COUNTER+1;
end		

//PCI clock divided by 2^19, 30ns->16ms as scan clock of button
assign INT_SCAN_CLK = INT_SCAN_COUNTER[`BUTTON_INT_SCAN_TIME-1];

reg	BUTTON_INT_REG;
always @(negedge PciReset_ or posedge INT_SCAN_CLK)
begin
	if (!PciReset_)
		BUTTON_INT_REG = 1'B1;
	else
		BUTTON_INT_REG = LocalInt_;	//latch int_ input,if button is pressed and released,a posedge of BUTTON_INT will be produced
end		


wire BUTTON_INT_CLEAR;

//when button is ever pressed,a button interrupt status bit BUTTON_INT_ will flags a pending button event,
//it will be valid and can not accept next button interrupt, unless master write 1 to inner io register 
//bit7 to clear button interrupt status register bit,

assign BUTTON_INT_CLEAR = PciReset_ &  (InnerIoWriteStrobe | ~PciAdIn[7]);
always @(negedge BUTTON_INT_CLEAR or posedge BUTTON_INT_REG)
begin
	if (!BUTTON_INT_CLEAR)
		BUTTON_INT_ = 1'B0;
	else
		BUTTON_INT_ = 1'B1;
end	
/////////////////////////////////////////////////////////////////////////////////////
//8051 P2 and P0,AL deal with:
always @(posedge P2LatchStrobe or negedge PciReset_)
begin
    if (!PciReset_)
        E8051P2 = 8'H00;
    else
        E8051P2 = PciAdressReg[17:10];
end
assign E8051P0Out = (E8051P0DataAddressSelect == 1'B1)? PciAdressReg[9:2] : PciAdIn[7:0];
//assign E8051Al = PciAdressReg[9:2];
always @(negedge E8051Ale or negedge PciReset_)
begin
    if (!PciReset_)
        E8051Al = 8'H00;
    else
        E8051Al = PciAdressReg[9:2];


end

endmodule

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -