📄 pcicore.v
字号:
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 + -