|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
[这个贴子最后由jackzhang在 2006/05/16 11:41am 第 7 次编辑]
这是斑竹编写的用于cpld的PCI Slave 源代码(包括pci slave和一个8位的测试寄存器),可以装到 Xilinx XC9572XL,XC95144XL .. Altera 的 7128(也有可能装入7064)等cpld之中。可以算得上是最小的pci core了吧。
该pci core只被仿真验证过,但没有做成板卡测试,因此希望大家仅仅作为参考。
(代码版权归亿涛工作室所有,未经同意任何人不得转载!)
[post=30]
/***********************************************************************
Little PCI Core
data: 2000/10/10
***********************************************************************/
`define VID 16'H1234
`define DID 16'HABCD
module pci (
// PCI ports -- do not modify names!
AD,
CBE,
// PAR,
FRAME_N,
TRDY_N,
IRDY_N,
STOP_N,
DEVSEL_N,
IDSEL,
RST_N,
PCLK,
INTR_N, //PCI Interrupt output Low level active
//LOCAL Signals
RD_EN,
WR_EN,
ADDR,
P_L_DA,
L_P_DA,
INT //local Interrupt, high level active
);
inout[31:0]AD;
input [3:0]CBE; //inout [3:0] CBE;
input FRAME_N; //inout FRAME_N;
output TRDY_N;
inputIRDY_N;
output STOP_N;
output DEVSEL_N;
input IDSEL;
input RST_N;
input PCLK;
output INTR_N;
output RD_EN;
output WR_EN;
output [4:0] ADDR;
input [31:0] L_P_DA;
output [31:0] P_L_DA;
input INT;
`define state parameter
`state S_IDLE_S = 2'B00;
`state S_BUSY_S = 2'B01;
`state S_DATA_S = 2'B10;
`state S_STOP_S = 2'B11;
reg [1:0] current_state,next_state;
reg CFG_EN; //CFG_EN = 1 : PCI config read/write, CFG_EN = 0: PCI Mem Read/Write
reg S_DATA_REG;
reg HIT;
reg S_RD,S_WR;
reg [11:0] BAR0_REG; //{BAR0_REG,20'h00}: 1M PCI MEM Space,last 20 bit is hardware as 0
reg [4:0] ADDR;
reg S_DATA;
reg [31:0] AD_D;
wire TRDY,STOP;
//State Machine
always @(posedge PCLK or negedge RST_N)
begin
if (~RST_N) current_state <= 2'b0;
else current_state <= next_state;
end
always @(FRAME_N or IRDY_N or HIT or TRDY or STOP or IRDY_N or current_state )
begin
next_state = current_state;
case (current_state)
S_IDLE_S: if (!FRAME_N & !HIT) next_state = S_BUSY_S;
S_BUSY_S: begin
if (FRAME_N & !HIT) next_state = S_IDLE_S;
else if ((!FRAME_N || !IRDY_N) & HIT) next_state = S_DATA_S;
end
S_DATA_S: if (FRAME_N & !TRDY) next_state = S_IDLE_S;
else if (~STOP) next_state = S_STOP_S;
S_STOP_S: if (FRAME_N) next_state = S_IDLE_S;
default: next_state = S_IDLE_S;
endcase
end
//address compare with BAR0
wire #1 AD_EQ = (AD[31:20] == BAR0_REG); //BAR0 Support 1M MEM Space (but littlr PCI CORE only support
// 5bit (32byte) Mem Space)
always @(posedge PCLK or negedge RST_N)
begin
if (~RST_N) begin
S_WR <= 1'B0;
S_RD <= 1'B0;
CFG_EN <= 1'B0;
HIT <= 1'B0; //BASE HIT, CFG HIT
ADDR <= 5'H0;
end
else if (!FRAME_N && (current_state == S_IDLE_S)) begin
ADDR <= AD[4:0]; //littlr PCI CORE only support 5bit (32byte) Mem Space
casex ({CBE,IDSEL})
5'B0110X: begin
S_WR <= 1'B0;
S_RD <= 1'B1; //PCI MEM Read
CFG_EN <= 1'B0;
if (AD_EQ) begin
HIT <= 1'B1;
end
end
5'B0111X: begin
CFG_EN <= 1'B0;
S_WR <= 1'B1; //PCI MEM Write
S_RD <= 1'B0;
if (AD_EQ) HIT <= 1'B1;
end
5'B10101: begin
CFG_EN <= 1'B1;
S_RD <= 1'B1; //PCI CFG Read
S_WR <= 1'B0;
HIT <= 1'B1;
end
5'B10111: begin
CFG_EN <= 1'B1;
S_RD <= 1'B0; //PCI CFG Write
S_WR <= 1'B1;
HIT <= 1'B1;
end
default: begin
S_WR <= 1'B0;
S_RD <= 1'B0;
HIT <= 1'B0;
end
endcase
end
else if (current_state == S_BUSY_S)
HIT <= 1'B0;
end
//S_DATA: is register output, in order to mach CLK to PAD delay <7.8ns
always @(posedge PCLK or negedge RST_N)
begin
if (~RST_N) S_DATA <= 1'B0;
else S_DATA <= (next_state == S_DATA_S);
end
always @(posedge PCLK or negedge RST_N)
begin
if (~RST_N) S_DATA_REG <= 1'B0;
else S_DATA_REG <= S_DATA;
end
//TAR_DLY: delete 1 clock
wire #1 TAR_DLY = S_DATA_REG;
//Address Decode
wire #1 ad_00 = (ADDR == 5'h00);
wire #1 ad_10 = (ADDR == 5'h10);
wire #1 we_en = S_DATA & S_WR;
wire #1 rd_en = S_DATA & S_RD;
wire S_TERM = 1'B0;
wire S_READY = 1'B1;
wire #1 RD_WR = S_DATA & (S_WR || (S_RD & TAR_DLY));
//assign #1 TRDY = !(RD_WR & (CFG_EN || S_READY));
assign #1 TRDY = ~RD_WR; //a optimize , add at 15/01/2002
//assign #1 STOP = ~(RD_WR & (CFG_EN || S_TERM));//1'B1;
assign #1 STOP = ~(RD_WR & CFG_EN);//a optimize , add at 15/01/2002
wire #1 OE = S_DATA || TAR_DLY;
wire #1 DEVSEL = ~S_DATA;
assign TRDY_N = OE ? TRDY : 1'BZ; //tri gate output: is more slower
assign STOP_N = OE ? STOP : 1'BZ;
assign DEVSEL_N = OE ? DEVSEL : 1'BZ;
//CFG
//CFG Address Decode
wire #1 RD_ID = rd_en & CFG_EN & TAR_DLY & ad_00;//(ADDR == 5'h00);
wire #1 RD_BAR0 = rd_en & CFG_EN & TAR_DLY & ad_10;//(ADDR == 5'h10);
wire #1 WE_BAR0 = we_en & CFG_EN & ad_10;//(ADDR == 5'h10);
//CFG Write : BAR0
always @(posedge PCLK or negedge RST_N)
begin
if (~RST_N) BAR0_REG <= 12'B0;
else if (WE_BAR0) BAR0_REG <= AD[31:20];//ADIO[31:20];
end
wire #1 WR_EN = we_en & ~CFG_EN ;
wire #1 RD_EN = rd_en & ~CFG_EN & TAR_DLY ;
//PCI read data
always @(RD_ID or RD_BAR0 or RD_REG or TEST_REG or BAR0_REG)
begin
case ({RD_ID,RD_BAR0,RD_REG})
3'b001: AD_D = {24'H0,TEST_REG};
3'B010: AD_D = {BAR0_REG,20'h0};
3'B100: AD_D = {`DID,`VID};
default:AD_D = 32'B00;
endcase
end
assign AD = rd_en ? AD_D : 32'BZZ;
assign P_L_DA = AD;
//PCI Interrupt Output
assign INTR_N = INT ? 1'B0 : 1'BZ; //Tri gate output, need outside pullup res
endmodule
[/post]
|
|