`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: FOM // Engineer: I.J. de Jong // // Description: burst implemented // // Dependencies: // // Revision: // Revision 1.0 - Final release Januari 2008 // Additional Comments: // This is the final version of the PCI code René de Jong // ////////////////////////////////////////////////////////////////////////////////// module PCI_CONFIG(PCI_CLK, PCI_RSTn, PCI_FRAMEn, PCI_AD, PCI_CBE, PCI_IRDYn, PCI_TRDYn, PCI_DEVSELn, SCOOP_A, SCOOP_B, SCOOP_C, SCOOP_D, SCOOP_E, SCOOP_F, PCI_IDSEL, LED_1, LED_2, LED_3, LED_4, LED_5, LED_6, LED_7, LED_8, S_1, S_2,INTAn, PCI_PAR ); input PCI_CLK, PCI_RSTn, PCI_FRAMEn, PCI_IRDYn, PCI_IDSEL; inout [31:0] PCI_AD; inout PCI_PAR; input [3:0] PCI_CBE; output PCI_TRDYn, PCI_DEVSELn, INTAn; input S_1; input S_2; output SCOOP_A; output SCOOP_B; output SCOOP_C; output SCOOP_D; output SCOOP_E; output SCOOP_F; output LED_1; output LED_2; output LED_3; output LED_4; output LED_5; output LED_6; output LED_7; output LED_8; //Lets start with the real work reg PCI_Transaction; // Is there any transaction starting? wire PCI_TransactionStart = ~PCI_Transaction & ~PCI_FRAMEn; wire PCI_TransactionEnd = PCI_Transaction & PCI_FRAMEn & PCI_IRDYn; reg [31:0] CONFIG_RAM [15:0]; reg [31:0] transactie; reg io_checkpoint; // Remember if there is any transaction always @(posedge PCI_CLK or negedge PCI_RSTn) if(~PCI_RSTn) PCI_Transaction <= 0; else case(PCI_Transaction) 1'b0: PCI_Transaction <= PCI_TransactionStart; 1'b1: PCI_Transaction <= ~PCI_TransactionEnd; endcase // We react on IO MEM MMEM CONF read and write transactions. // For IO and MEM actions (every transaction towards our RAM) wire PCI_Targeted = PCI_TransactionStart & ((PCI_AD[31:21]== (CONFIG_RAM[5][31:21]))&io_checkpoint| (PCI_AD[31:6]==CONFIG_RAM[4][31:6])&io_checkpoint) & (PCI_AD[1:0]==0) & (~PCI_CBE[3]&PCI_CBE[1]|PCI_CBE[3]&PCI_CBE[2]); // For CONF actions (every action towards our CONFIG_RAM {the configuration part}) wire PCI_Targeted_CONF = PCI_TransactionStart & PCI_IDSEL & (PCI_CBE[3]&~PCI_CBE[2]&PCI_CBE[1]) & (PCI_AD[1:0]==0); //If there is an transaction started we get an address. In case of a burst transaction we increase this address. reg [3:0] PCI_TransactionAddr; always @(posedge PCI_CLK) if(PCI_TransactionStart) PCI_TransactionAddr <= PCI_AD[5:2]; else if(~PCI_TransactionEnd&PCI_Transaction&~PCI_IRDYn)PCI_TransactionAddr <= PCI_TransactionAddr +1; //Now a few more registers to be able to claim the transaction and remember if it's a read or a write wire PCI_LastDataTransfer = PCI_FRAMEn & ~PCI_IRDYn & ~PCI_TRDYn; // read or write? reg PCI_Transaction_Read_nWrite; always @(posedge PCI_CLK or negedge PCI_RSTn) if(~PCI_RSTn) PCI_Transaction_Read_nWrite <= 0; else if(~PCI_Transaction & (PCI_Targeted | PCI_Targeted_CONF)) PCI_Transaction_Read_nWrite <= ~PCI_CBE[0]; // Is the transaction towards our device? reg PCI_DevSelOE; always @(posedge PCI_CLK or negedge PCI_RSTn) if(~PCI_RSTn) PCI_DevSelOE <= 0; else case(PCI_Transaction) 1'b0: PCI_DevSelOE <= PCI_Targeted | PCI_Targeted_CONF; 1'b1: if(PCI_TransactionEnd) PCI_DevSelOE <= 1'b0; endcase // DevSel should react on LastDataTransfer reg PCI_DevSel; always @(posedge PCI_CLK or negedge PCI_RSTn) if(~PCI_RSTn) PCI_DevSel <= 0; else case(PCI_Transaction) 1'b0: PCI_DevSel <= PCI_Targeted | PCI_Targeted_CONF; 1'b1: PCI_DevSel <= PCI_DevSel & ~PCI_LastDataTransfer; endcase // If we may send data, now is the time to takeover the bus // PCI_TRDYn is hoog omdat er geen wait momenten nodig zijn van ons uit gezien // For read transaction, delay by one clock to allow for the turnaround-cycle reg PCI_TargetReady; always @(posedge PCI_CLK or negedge PCI_RSTn) if(~PCI_RSTn) PCI_TargetReady <= 0; else case(PCI_Transaction) 1'b0: PCI_TargetReady <= (PCI_Targeted | PCI_Targeted_CONF)& PCI_CBE[0]; // active now on write, next cycle on reads 1'b1: PCI_TargetReady <= PCI_DevSel & ~PCI_LastDataTransfer; endcase // Transaction is ours, time for some action. assign PCI_DEVSELn = PCI_DevSelOE ? ~PCI_DevSel : 1'bZ; assign PCI_TRDYn = PCI_DevSelOE ? ~PCI_TargetReady : 1'bZ; // Is it a read or a write? wire PCI_DataTransferWrite = (PCI_DevSel | PCI_IDSEL) & ~PCI_Transaction_Read_nWrite & ~PCI_IRDYn & ~PCI_TRDYn; wire PCI_DataTransferRead = PCI_DevSel & PCI_Transaction_Read_nWrite & ~PCI_IRDYn; // create the RAM. reg [31:0] RAM [15:0]; reg [31:0] PCI_AD_TEMP; reg read_only; // additional config signal. reg PCI_IDSEL_CBE; always @(posedge PCI_CLK ) case(~PCI_CBE[3]&PCI_CBE[1]|PCI_CBE[3]&PCI_CBE[2]) 1'b0: PCI_IDSEL_CBE <= ~PCI_IDSEL_CBE^PCI_Transaction; 1'b1: PCI_IDSEL_CBE <= 0; endcase always @(posedge PCI_CLK) if( ~CONFIG_RAM[0][30]) begin //config initialisation CONFIG_RAM[0] = 32'h644a494a;// My initials CONFIG_RAM[1] = 32'h00200000;// 66MHz fast DevSel CONFIG_RAM[2] = 32'hFF000001;// device does not fit in any class, revision 1 CONFIG_RAM[3] = 32'h00000000;// No BIST, normal Header CONFIG_RAM[4] = 32'h00000001;// IO address CONFIG_RAM[5] = 32'h00000008;// Mem address CONFIG_RAM[6] = 32'h00000000; CONFIG_RAM[7] = 32'h00000000; CONFIG_RAM[8] = 32'h00000000; CONFIG_RAM[9] = 32'h00000000; CONFIG_RAM[10] = 32'h00000000; CONFIG_RAM[11] = 32'h12345678;// Sub Vendor/Device CONFIG_RAM[12] = 32'h00000000; CONFIG_RAM[13] = 32'h00000000; CONFIG_RAM[14] = 32'h00000000; CONFIG_RAM[15] = 32'h000000FF;//no interrupt read_only = 1'b0;// This signal used to be a extra check, no functionality in this design (then why didn't I delete it :P) io_checkpoint = 1'b0; end else begin if(~io_checkpoint&RAM[4][0]) //Checkpoint! After a reboot this goes wrong if not implemeted. At least, in my situation. begin io_checkpoint = 1'b1; CONFIG_RAM[4] = {RAM[4][31:6], 6'h01 }; end if(PCI_DataTransferWrite) if(PCI_IDSEL) case(PCI_TransactionAddr) //schrijf config 4'h0: read_only = 1'b1; 4'h1: CONFIG_RAM[1][1:0] = PCI_AD[1:0]; 4'h2: read_only = 1'b1; 4'h3: read_only = 1'b1; 4'h4: begin CONFIG_RAM[4] = {PCI_AD[31:6], 6'h01 };//32'hFFFFFFC1 I/O; io_checkpoint = 1'b0; end 4'h5: CONFIG_RAM[5] = {PCI_AD[31:21], 21'h000008 };//32'hFFE00008 MEM 4'h6: read_only = 1'b1; 4'h7: read_only = 1'b1; 4'h8: read_only = 1'b1; 4'h9: read_only = 1'b1; 4'hA: read_only = 1'b1; 4'hB: read_only = 1'b1; 4'hC: read_only = 1'b1; 4'hD: read_only = 1'b1; 4'hE: read_only = 1'b1; 4'hF: read_only = 1'b1; default: read_only = 1'b1; endcase else RAM[PCI_TransactionAddr] <= PCI_AD;//write normal RAM end // only for reads reg PCI_AD_OE; always @(posedge PCI_CLK or negedge PCI_RSTn) if(~PCI_RSTn) PCI_AD_OE <= 0; else PCI_AD_OE <= PCI_DevSel & PCI_Transaction_Read_nWrite & ~PCI_LastDataTransfer; //Is it config or normal read? always @(posedge PCI_CLK) if(PCI_DataTransferRead) if(PCI_IDSEL&PCI_IDSEL_CBE) PCI_AD_TEMP <= CONFIG_RAM[PCI_TransactionAddr]; else PCI_AD_TEMP <= RAM[PCI_TransactionAddr]; else PCI_AD_TEMP <=32'hZZZZZZZZ; //always @(negedge PCI_TRDYn or posedge S_2) //additional counter for tests //if(S_2)transactie <= 32'h00000000; //else //if(PCI_DataTransferWrite) transactie <= transactie + 1; //parity seems to be mandatory with burst read, but tests prove that this is not necessarely the case. Even when I inverted this parity, the output remained stable. //parity is one clockpulse behind data reg parity[1:0]; always @(posedge PCI_CLK) begin if(PCI_DataTransferRead&PCI_DevSel) parity[1] = parity[0]; else parity[1] = 1'bZ; parity[0] = PCI_CBE[3] ^ PCI_CBE[2] ^ PCI_CBE[1] ^ PCI_CBE[0] ^ PCI_AD_TEMP[0] ^ PCI_AD_TEMP[1]^ PCI_AD_TEMP[2]^ PCI_AD_TEMP[3]^ PCI_AD_TEMP[4]^ PCI_AD_TEMP[5]^ PCI_AD_TEMP[6]^ PCI_AD_TEMP[7]^ PCI_AD_TEMP[8]^ PCI_AD_TEMP[9]^ PCI_AD_TEMP[10]^ PCI_AD_TEMP[11]^ PCI_AD_TEMP[12]^ PCI_AD_TEMP[13]^ PCI_AD_TEMP[14]^ PCI_AD_TEMP[15]^ PCI_AD_TEMP[16]^ PCI_AD_TEMP[17]^ PCI_AD_TEMP[18]^ PCI_AD_TEMP[19]^ PCI_AD_TEMP[20]^ PCI_AD_TEMP[21]^ PCI_AD_TEMP[22]^ PCI_AD_TEMP[23]^ PCI_AD_TEMP[24]^ PCI_AD_TEMP[25]^ PCI_AD_TEMP[26]^ PCI_AD_TEMP[27]^ PCI_AD_TEMP[28]^ PCI_AD_TEMP[29]^ PCI_AD_TEMP[30]^ PCI_AD_TEMP[31]; end // assign the output. assign PCI_AD = PCI_AD_TEMP; assign PCI_PAR = parity_oud; //don't use an interrupt (this is for later developments) assign INTAn = 1'b1; // monitor posibilities assign SCOOP_A = PCI_CLK; assign SCOOP_B = PCI_AD[0]; assign SCOOP_C = PCI_CBE[0]; assign SCOOP_D = PCI_CBE[1]; //assign SCOOP_E = PCI_CBE[2]; //assign SCOOP_F = PCI_CBE[3]; assign LED_1 = ~S_1? RAM[0][7]:RAM[0][15]; assign LED_2 = ~S_1? RAM[0][6]:RAM[0][14]; assign LED_3 = ~S_1? RAM[0][5]:RAM[0][13]; assign LED_4 = ~S_1? RAM[0][4]:RAM[0][12]; assign LED_5 = ~S_1? RAM[0][3]:RAM[0][11]; assign LED_6 = ~S_1? RAM[0][2]:RAM[0][10]; assign LED_7 = ~S_1? RAM[0][1]:RAM[0][9]; assign LED_8 = ~S_1? RAM[0][0]:RAM[0][8]; endmodule