URL
https://opencores.org/ocsvn/pci_mini/pci_mini/trunk
Subversion Repositories pci_mini
Compare Revisions
- This comparison shows the changes necessary to convert path
/pci_mini/trunk
- from Rev 4 to Rev 7
- ↔ Reverse comparison
Rev 4 → Rev 7
/pci_mini-34.v
0,0 → 1,739
// *************************************************************** // |
// // |
// PCI_TARGET-Wishbone_MASTER INTERFACE MODULE (PCI-mini) // |
// v3.4 // |
// // |
// The original PCI module is from: Ben Jackson // |
// http://www.ben.com/minipci/verilog.php // |
// // |
// Redesigned for wishbone : Istvan Nagy, buenos@freemail.hu // |
// // |
// // |
// DOWNLOADED FROM OPENCORES. (License = GPL) // |
// // |
// *************************************************************** // |
|
// The core implements a 16MB relocable memory image. Relocable on the |
// wb bus. the wb address = 4M*wb_baseaddr_reg + PCI_addr[23:2] |
// Only Dword aligned Dword accesses allowed on the PCI. This way |
// we can access to the 4GB wb-space through a 16MB PCI-window. |
// The addressing on the wb-bus, is Dword addressing, while on the |
// PCI bus, the addressing is byte addressing. A(pci)=A(wb)*4 |
// The PCI address is increasing by 4, and we get 4 bytes. The wb |
// address is increasing by 1, and we get 1 Dword (= 4 bytes also). |
// The wb_baseaddr_reg is the wb image relocation register, can be |
// accessed at 50h address in the PCI configuration space. |
// Other bridge status and command is at the 54h and 58h addresses. |
// if access fails with timeout, then the address will be in the |
// wb address will be stored in the failed_addr_reg at 5Ch address. |
// |
// Wishbone compatibility: |
// Wishbone signals: wb_address, wb_dat_o, wb_dat_i, wb_sel_o, wb_cyc_o, |
// wb_stb_o, wb_wr_o, wb_reset_o, wb_clk_o, wb_ack_i. |
// Not implemented wb signals: error, lock, retry, tag-signals. |
// The peripheral has to response with ack in 16 clk cycles. |
// The core has wishbone clk and reset outputs, just like a Syscon module. |
// The core generates single reads/writes. These are made of 4 phases, so |
// dont write new data, until internal data movement finishes: about 300...500ns |
// |
// PCI compatibility: |
// Only single DWORD reads/writes are supported. between them, the software has |
// to wait 300...500nsec, to prevent data corrupting. STOP signaling is not |
// implemented, so target terminations also not. |
// Single Byte access is NOT supported! It may cause corrupt data. |
// The core uses INTA interrupt signal. There are some special PCI config |
// registers, from 50h...60h config-space addresses. |
// PCI-parity: it generates parity, but doesnt check incoming parity. |
// Because of the PC chipset, if you read a value and write it back, |
// the chipset will not write anything, because it can see the data is not |
// changed. This is important at some peripherals, where you write, to control. |
// Device specific PCI config header registers: |
// name: addr: function: |
// wb_baseaddr_reg; 50h A(wb)=(A(pci)-BAR0)/4 + wb_baseaddr_reg. RESET TO 0 |
// user_status_reg; 54h not used yet |
// user_command_reg; 58h not used yet |
// failed_addr_reg; 5Ch address, when timeout occurs on the wb bus. |
// |
// Local bus arbitration: |
// This is not really wishbone compatible, but needed for the PCI. |
// The method is: "brute force". it means if the PCI interface wants to |
// be mastering on the local (wishbone) bus, then it will be mastering, |
// so, the other master(s) must stop anything immediately. The req signal |
// goes high when there is an Address hit on teh PCI bus. so the other |
// master has few clk cycles to finish. |
// Restrictions: the peripherals have to be fast: If the other master |
// starts a transaction before req goes high, the ack has to arrive before |
// the PCI interface starts its own transaction. (max 4clk ACK delay) |
// The other master or the bus unit must sense the req, and give bus |
// mastering to the PCI-IF immediatelly, not just when the other master |
// finished everything, like at normal arbitration schemes. |
// |
// Buffering: |
// There is a single Dword buffering only. |
// |
// The led_out interface: |
// only for system-debug: we can write to the LEDs, at any address. |
// (in the same time there is a wishbone write also) |
// |
// Changes since original version: wishbone interface, |
// bigger memory-image, parity-generation, |
// interrupt handling. Code size is 3x bigger. New registers, |
// |
// Device Compatibility: |
// Until v3.3 the code was tested on Xilinx FPGAs (sp2, sp3) with ISE 4.7-9.1 and VIA/AMD chipsets. |
// Version 3.4 has modifications to work on Actel/Microsemi ProASIC3 with Sinplify and Intel Atom chipset. |
// (v3.4 was not tested on Xilinx FPGAs) To make sure that it runs on the Actel FPGA, we have to use the |
// timing constraint SDC file, AND ALSO set the P&R to Timing optimized and "effort"=high. |
// |
// *************************************************************** // |
|
|
|
module pci(reset, pciclk, frame, irdy, trdy, devsel, idsel, ad, cbe, par, stop, inta, serr, perr, led_out, wb_address, wb_dat_o, wb_dat_i, wb_sel_o, wb_cyc_o, wb_stb_o, wb_wr_o, wb_reset_o, wb_clk_o, wb_ack_i, wb_irq, wb_req, wb_gnt, wb_req_other, contr_o); |
input reset; |
input pciclk; |
input frame; |
input irdy; |
output trdy; |
output devsel; |
input idsel; |
inout [31:0] ad; |
input [3:0] cbe; |
inout par; |
output stop; |
output inta; |
output serr; |
output perr; |
output [3:0] led_out; |
output [31:0] wb_address; |
output [31:0] wb_dat_o; |
input [31:0] wb_dat_i; |
output [3:0] wb_sel_o; |
output wb_cyc_o; |
output wb_stb_o; |
output wb_wr_o; |
output wb_reset_o; |
output wb_clk_o; |
input wb_ack_i; |
input wb_irq; |
output wb_req; |
input wb_gnt; |
input wb_req_other; |
output [7:0] contr_o; |
|
|
|
parameter DEVICE_ID = 16'h9500; |
parameter VENDOR_ID = 16'h11AA; // 16'h11AA = actel, |
parameter DEVICE_CLASS = 24'h118000; // some examples: 068000=bridge/other, 078000=simple_comm_contr/other, 118000=data_acquisition/other |
parameter DEVICE_REV = 8'h01; |
parameter SUBSYSTEM_ID = 16'h0001; // Card identifier |
parameter SUBSYSTEM_VENDOR_ID = 16'h13C7; // 13C7 = bluechip technology |
parameter DEVSEL_TIMING = 2'b00; // Fast! |
|
reg [2:0] state; |
reg [31:0] data; |
|
reg [1:0] enable; |
parameter EN_NONE = 2'b00; |
parameter EN_RD = 2'b01; |
parameter EN_WR = 2'b10; |
parameter EN_TR = 2'b11; |
|
reg memen; // respond to baseaddr? |
reg [7:0] baseaddr; |
reg [5:0] address; |
|
reg [9:0] wb_baseaddr_reg; //remap the image on the wishbone bus |
reg [31:0] wb_address_1; |
reg [31:0] user_status_reg; |
reg [31:0] user_command_reg; |
reg [31:0] failed_addr_reg; |
reg [31:0] dummy_reg; |
reg [31:0] pci_read_reg; |
reg [31:0] pci_write_reg; |
reg [31:0] wb_read_reg; |
reg [31:0] wb_write_reg; |
reg [3:0] pci_read_sel_reg; |
reg [3:0] pci_write_sel_reg; |
reg [3:0] wb_read_sel_reg; |
reg [3:0] wb_write_sel_reg; |
|
assign contr_o = user_command_reg [7:0]; |
|
parameter ST_IDLE = 3'b000; |
parameter ST_BUSY = 3'b010; |
parameter ST_MEMREAD = 3'b100; |
parameter ST_MEMWRITE = 3'b101; |
parameter ST_CFGREAD = 3'b110; |
parameter ST_CFGWRITE = 3'b111; |
|
parameter MEMREAD = 4'b0110; |
parameter MEMWRITE = 4'b0111; |
parameter CFGREAD = 4'b1010; |
parameter CFGWRITE = 4'b1011; |
|
`define LED |
`ifdef LED |
reg [3:0] led; |
`endif |
|
`undef STATE_DEBUG_LED |
`ifdef STATE_DEBUG_LED |
assign led_out = ~state; |
`else |
`ifdef LED |
assign led_out = ~led; |
`endif |
`endif |
|
assign ad = (enable == EN_RD) ? data : 32'bZ; |
|
reg [1:0] enable_delayed; |
always @(posedge pciclk) |
begin enable_delayed <= enable; end |
|
|
// TRDY# Generation -------------------------------------------------- |
reg [31:0] wb_address_previous; |
reg [31:0] wb_address_readonly; |
reg trdy; |
//assign trdy = (enable_delayed == EN_NONE) ? 'bZ : (enable == EN_TR ? 1 : 0); |
always @(posedge pciclk) //delaying of trdy |
if (enable_delayed == EN_NONE) |
trdy <= 'bZ; |
else if (enable == EN_TR) |
trdy <= 'b1; |
else if ((wb_address_previous != wb_address_readonly) && (state == ST_MEMREAD)) |
trdy <= 'b1; |
else |
trdy <= 'b0; |
|
//assign trdylocal = (enable_delayed == EN_NONE) ? 'b1 : (enable == EN_TR ? 1 : 0); |
reg trdylocal; |
always @(posedge pciclk) //delaying of trdy |
if (enable_delayed == EN_NONE) |
trdylocal <= 'b1; |
else if (enable == EN_TR) |
trdylocal <= 'b1; |
else if ((wb_address_previous != wb_address_readonly) && (state == ST_MEMREAD)) |
trdylocal <= 'b1; |
else |
trdylocal <= 'b0; |
|
|
// STOP# Generation -------------------------------------------------- |
//auto-generate Retry for read completion transactions, by using STOP# and target-abort: |
reg stop; |
always @(posedge pciclk) //delaying of trdy |
if (enable_delayed == EN_NONE) |
stop <= 'bZ; |
else if (enable == EN_TR) |
stop <= 'b1; |
else if ((wb_address_previous != wb_address_readonly) && (state == ST_MEMREAD)) |
stop <= 'b0; |
else |
stop <= 'bZ; |
reg stoplocal; |
always @(posedge pciclk) //delaying of trdy |
if (enable_delayed == EN_NONE) |
stoplocal <= 'b1; |
else if (enable == EN_TR) |
stoplocal <= 'b1; |
else if ((wb_address_previous != wb_address_readonly) && (state == ST_MEMREAD)) |
stoplocal <= 'b0; |
else |
stoplocal <= 'b1; |
//assign stop = 1'bZ; //if not used |
|
|
|
|
reg devsel; |
|
assign serr = 1'bZ; |
assign perr = 1'bZ; |
|
|
wire cfg_hit = ((cbe == CFGREAD || cbe == CFGWRITE) && idsel && ad[10:8] == 3'b000 && ad[1:0] == 2'b00); |
wire addr_hit = ((cbe == MEMREAD || cbe == MEMWRITE) && memen && ad[31:24] == {baseaddr}); |
wire hit = cfg_hit | addr_hit; |
|
//count hit for debug purposes. also trigger on it in the logic analyzer: |
reg [7:0] hitcounter; |
always @(posedge pciclk) |
if (~reset) begin |
hitcounter <= 4'b00000000; |
end |
else begin |
if ((hit=='b1) & (frame == 'b0)) hitcounter <= hitcounter +1; |
end |
|
|
|
|
|
// Wishbone SYSCON: output signals------------------------------------ |
assign wb_reset_o = ~reset; |
assign wb_clk_o = pciclk; |
//reg wb_clk_o; |
//always @(posedge clk) |
//wb_clk_o = wb_clk_o+ 1; |
|
|
// PCI parity generation:--------------------------------------------- |
// during read, the parity on AD, and delayen by one clk. |
reg par_en; |
reg par_latched; |
reg EN_RDd; |
reg addr_increment; |
wire data_par = (data[31] ^ data[30] ^ data[29] ^ data[28]) ^ |
(data[27] ^ data[26] ^ data[25] ^ data[24]) ^ |
(data[23] ^ data[22] ^ data[21] ^ data[20]) ^ |
(data[19] ^ data[18] ^ data[17] ^ data[16]) ^ |
(data[15] ^ data[14] ^ data[13] ^ data[12]) ^ |
(data[11] ^ data[10] ^ data[9] ^ data[8]) ^ |
(data[7] ^ data[6] ^ data[5] ^ data[4]) ^ |
(cbe[3] ^ cbe[2] ^ cbe[1] ^ cbe[0]) ^ |
(data[3] ^ data[2] ^ data[1] ^ data[0]) ; |
|
always @(posedge pciclk) //delaying of parity |
if ((enable == EN_RD)|(enable == EN_TR)) begin |
par_latched = data_par; end |
else |
begin par_latched = 0; end |
|
always @(posedge pciclk) //delaying of EN_RD |
EN_RDd = EN_RD; |
|
//assign par = (enable == EN_RD) ? 0 : 'bZ; |
assign par = ((enable == EN_RD)|(enable == EN_RDd)) ? par_latched : 'bZ; //output control |
|
|
|
// Interrupt handling:-------------------------------------------------------------------- |
reg int_dis; |
wire int_stat; |
reg [7:0] int_line; |
assign inta = ((wb_irq == 1) && (int_dis == 0)) ? 1'b0 : 1'bZ; |
assign int_stat = wb_irq; |
|
|
|
// WB bus arbitration:-------------------------------------------------------------------- |
//assign wb_req = mastering; |
reg arb_start; |
reg arb_stop; |
reg wb_req; |
|
parameter arb_state1 = 2'b00; |
parameter arb_state2 = 2'b01; |
reg arb_state = arb_state1; |
always@(posedge pciclk) begin |
if (wb_reset_o) begin |
arb_state <= arb_state1; |
wb_req <= 0; |
end |
else |
case (arb_state) |
arb_state1 : begin //arbitration is not needed: IDLE |
wb_req <= 0; |
if (arb_start == 1) |
arb_state <= arb_state2; |
end |
arb_state2 : begin //arbitration is needed |
wb_req <= 1; |
if (arb_stop == 1) |
arb_state <= arb_state1; |
end |
default : begin // Fault Recovery |
arb_state <= arb_state1; |
wb_req <= 0; |
end |
endcase |
end |
|
|
|
// -------------- wishbone state machine -------------------------------------------------- |
//write FIFO buffer: |
reg [31:0] wb_wr_buf [5:0]; //64 Dwords wb write buffer: wb_wr_buf[index] <= value; |
reg [3:0] wb_wr_sel_buf [5:0]; //select lines, write buffer: wb_wr_buf[index] <= value; |
reg [31:0] fifo_start_wb_addr; |
reg [31:0] fifo_act_wb_addr; |
reg [5:0] fifo_max_count; |
reg [5:0] fifo_wb_counter; |
reg [5:0] fifo_wb_counter_o; |
reg fifo_flush; //wb output mux control |
reg fifo_flush_start; //start pulse |
reg fifo_fill; //disable wb during filling fifo |
reg [3:0] wbw_timeout_count_new; |
reg [1:0] wbw_phase; |
//read FIFO buffer: |
reg [31:0] wb_rd_buf [5:0]; //64 Dwords wb read buffer: wb_rd_buf[index] <= value; |
reg [3:0] wb_rd_sel_buf [5:0]; //select lines, write buffer: wb_wr_buf[index] <= value; |
reg [31:0] fifo_start_wb_addr_rd; |
reg [31:0] fifo_act_wb_addr_rd; |
reg [5:0] fifo_max_count_rd; |
reg [5:0] fifo_wb_counter_rd; |
reg [5:0] fifo_wb_counter_o_rd; |
reg fifo_flush_rd; //wb output mux control |
reg fifo_fill_start_rd; //start pulse |
reg fifo_fill_rd; //disable wb during filling fifo |
reg [3:0] wbr_timeout_count_new; |
reg [1:0] wbr_phase; |
// |
reg wb_cyc_o; |
reg wb_stb_o; |
reg wb_wr_o; |
reg [31:0] wb_address; |
reg [3:0] wb_sel_o; |
reg [31:0] wb_dat_o; |
reg machinereset; |
reg mastering; |
//assign wb_req = mastering; |
|
|
parameter machine_waiting = 2'b00; |
parameter machine_flushing = 2'b01; |
parameter machine_read_filling = 2'b11; |
reg [1:0] wbwf_state = machine_waiting; |
|
always@(posedge wb_clk_o) |
if (wb_reset_o) begin |
wbwf_state <= machine_waiting; |
wbw_phase <= 0; |
wbw_timeout_count_new <= 0; |
fifo_wb_counter_o<=0; |
fifo_flush <= 0; |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wbr_phase <= 0; |
wbr_timeout_count_new <= 0; |
fifo_wb_counter_o_rd<=0; |
fifo_fill_rd <= 0; |
wb_address[31:0] = 32'b0; |
wb_sel_o = 4'b0; |
wb_dat_o = 32'b0; |
pci_read_reg <= 0; |
mastering <= 0; |
arb_stop <= 0; |
failed_addr_reg <= 0; |
end |
else |
case (wbwf_state) |
|
machine_waiting : begin //no operation on Wishbone bus ************** |
wbw_phase <= 0; |
wbw_timeout_count_new <= 0; |
wbr_phase <= 0; |
wbr_timeout_count_new <= 0; |
wb_address[31:0] = 32'b0; |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wb_sel_o = 4'b0; |
wb_dat_o = 32'b0; |
arb_stop <= 0; |
if (fifo_flush_start == 1) |
begin fifo_flush <= 1; wbwf_state <= machine_flushing; fifo_wb_counter_o<=0; mastering <= 1; end |
else if (fifo_fill_start_rd == 1) |
begin fifo_fill_rd <= 1; wbwf_state <= machine_read_filling; fifo_wb_counter_o_rd<=0; mastering <= 1; end |
end |
|
machine_flushing : begin //wr-FIFO flushing: wb write*********************** |
wb_sel_o = pci_write_sel_reg; |
wb_dat_o = pci_write_reg; //wb_wr_buf[fifo_wb_counter_o]; |
wb_address[31:0] = fifo_start_wb_addr; //[31:0]+fifo_wb_counter_o ; |
if ( wbw_phase== 0 ) begin //phase 0: setup |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wbw_phase <= wbw_phase + 1; |
//address and data also changes now, from FIFO |
end |
else if ( wbw_phase== 1 ) begin //phase 1: access |
wb_cyc_o <= 1; |
wb_stb_o <= 1; |
wb_wr_o <= 1; |
wbw_phase <= wbw_phase + 1; |
end |
else if ( wbw_phase== 2 ) begin //phase 2: wait for ack |
wbw_timeout_count_new <= wbw_timeout_count_new +1; |
if ((wb_ack_i==1) | (wbw_timeout_count_new==15)) begin |
wbw_phase <= wbw_phase + 1; |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
if (wbw_timeout_count_new==15) begin failed_addr_reg <= wb_address; end |
end |
else begin wb_cyc_o <= 1; wb_stb_o <= 1; wb_wr_o <= 1; end |
end |
else if ( wbw_phase== 3 ) begin //phase 3: hold (finish) |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wbw_phase <= wbw_phase + 1; |
wbw_timeout_count_new <=0; |
fifo_wb_counter_o <= fifo_wb_counter_o + 1; //for next word |
//if ((fifo_wb_counter_o == fifo_max_count-1)|(machinereset == 1)) begin |
fifo_flush <= 0; |
wbwf_state <= machine_waiting; |
fifo_wb_counter_o<=0; |
mastering <= 0; |
arb_stop <= 1; |
//end |
end |
end |
|
machine_read_filling : begin //rd-FIFO filling: wb read******************** |
wb_sel_o = pci_read_sel_reg; |
wb_dat_o = 32'b0; |
wb_address[31:0] = fifo_start_wb_addr_rd; //[31:0]+fifo_wb_counter_o_rd ; |
if ( wbr_phase== 0 ) begin //phase 0: setup |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wbr_phase <= wbr_phase + 1; |
//address and data also changes now, from FIFO |
end |
else if ( wbr_phase== 1 ) begin //phase 1: access |
wb_cyc_o <= 1; |
wb_stb_o <= 1; |
wb_wr_o <= 0; |
wbr_phase <= wbr_phase + 1; |
end |
else if ( wbr_phase== 2 ) begin //phase 2: wait for ack |
wbr_timeout_count_new <= wbr_timeout_count_new +1; |
if ((wb_ack_i==1) | (wbr_timeout_count_new==15)) begin |
//wb_rd_buf[fifo_wb_counter_o_rd] <= wb_dat_i; //sampling |
pci_read_reg <= wb_dat_i; //sampling |
wbr_phase <= wbr_phase + 1; |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
if (wbw_timeout_count_new==15) begin failed_addr_reg <= wb_address; end |
end |
else begin wb_cyc_o <= 1; wb_stb_o <= 1; wb_wr_o <= 0; end |
end |
else if ( wbr_phase== 3 ) begin //phase 3: hold (finish) |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wbr_phase <= wbw_phase + 1; |
wbr_timeout_count_new <=0; |
fifo_wb_counter_o_rd <= fifo_wb_counter_o_rd + 1; //for next word |
//if ((fifo_wb_counter_o_rd == fifo_max_count_rd-1)|(machinereset == 1)) begin |
fifo_fill_rd <= 0; |
wbwf_state <= machine_waiting; |
fifo_wb_counter_o_rd<=0; |
mastering <= 0; |
arb_stop <= 1; |
//end |
end |
end |
|
default : begin // Fault Recovery |
wbwf_state <= machine_waiting; |
end |
|
|
endcase |
|
|
|
|
|
|
|
// main PCI state machine: --------------------------------------------------------------- |
always @(posedge pciclk) |
begin |
if (~reset) begin |
state <= ST_IDLE; |
enable <= EN_NONE; |
baseaddr <= 0; |
devsel <= 'bZ; |
memen <= 0; |
int_line <= 8'b0; |
int_dis <= 0; |
wb_baseaddr_reg <= 0; |
wb_address_1[31:0] <= 0; |
user_status_reg <= 0; |
user_command_reg <= 0; |
fifo_flush_start <= 0; |
fifo_fill_start_rd <= 0; |
fifo_wb_counter <= 0; |
fifo_wb_counter_rd <= 0; |
dummy_reg <= 0; |
pci_write_reg <= 0; |
machinereset <= 0; |
led <= 0; |
arb_start <= 0; |
addr_increment <= 0; |
wb_address_readonly <= 0; |
wb_address_previous <= 5; |
|
end |
else begin |
|
case (state) |
ST_IDLE: begin |
//enable <= EN_NONE; |
//devsel <= 'bZ; |
fifo_flush_start <= 0; |
fifo_fill_start_rd <= 0; |
fifo_wb_counter <= 0; |
fifo_wb_counter_rd <= 0; |
machinereset <= 0; |
addr_increment <= 0; |
if (~frame) begin |
address <= ad[7:2]; |
if (hit) begin |
devsel <= 0; |
state <= {1'b1, cbe[3], cbe[0]}; |
if (addr_hit) begin arb_start <= 1; end |
//devsel <= 0; |
wb_address_1[31:0] <= {wb_baseaddr_reg, ad[23:2]}; |
//if (wbwf_state == machine_waiting) begin //sample address, if FIFO is not busy |
fifo_start_wb_addr <= {wb_baseaddr_reg, ad[23:2]}; |
fifo_start_wb_addr_rd <= {wb_baseaddr_reg, ad[23:2]}; |
//end |
// pipeline the write enable |
if (cbe[0]) begin //its one? |
enable <= EN_WR; |
end |
else begin |
enable <= EN_RD; |
end |
if (cbe==4'b0110) begin //latch previous address if its going to be a memory read |
wb_address_previous[31:0] <= wb_address_readonly[31:0]; |
wb_address_readonly[31:0] <= {wb_baseaddr_reg, ad[23:2]}; |
end |
end |
else begin |
devsel <= 'bZ; |
state <= ST_BUSY; |
enable <= EN_NONE; |
end |
end |
end |
|
ST_BUSY: begin |
devsel <= 'bZ; |
enable <= EN_NONE; |
arb_start <= 0; |
if (frame) |
state <= ST_IDLE; |
end |
|
ST_CFGREAD: begin |
//enable <= EN_RD; |
if (~irdy || trdylocal) begin |
case (address) |
0: data <= { DEVICE_ID, VENDOR_ID }; |
1: data <= { 5'b0, DEVSEL_TIMING, 5'b0, int_stat, 8'b0, int_dis, 8'b0, memen, 1'b0}; |
2: data <= { DEVICE_CLASS, DEVICE_REV }; |
4: data <= { baseaddr, 12'b0, 8'b0, 4'b0000 }; // baseaddr + request mem < 1Mbyte |
11: data <= {SUBSYSTEM_ID, SUBSYSTEM_VENDOR_ID }; |
15: data <= {16'b0, 7'b0, 1'b1, int_line}; //irq pin and line |
16: data <= { 24'b0, baseaddr }; |
20: data <= { wb_baseaddr_reg, 22'b0}; //wb base address: for wb-local relocation |
21: data <= user_status_reg; |
22: data <= user_command_reg; |
23: data <= failed_addr_reg; //actual addr, at a timeout |
default: data <= 'h00000000; |
endcase |
//address <= address + 1; |
arb_start <= 0; |
addr_increment <= 1; |
if (addr_increment) begin address <= address + 1; end |
end |
if (frame && ~irdy && ~trdylocal) begin |
devsel <= 1; |
state <= ST_IDLE; |
enable <= EN_TR; |
end |
else begin |
enable <= EN_RD; |
end |
end |
|
ST_CFGWRITE: begin |
//enable <= EN_WR; |
if (~irdy) begin |
case (address) |
4: baseaddr <= ad[31:24]; // XXX examine cbe |
1: begin memen <= ad[1]; int_dis <= ad[10]; end |
15: int_line <= ad[7:0]; |
20: wb_baseaddr_reg <= ad[31:22]; |
22: user_command_reg <= ad[31:0]; |
24: machinereset <= 1; //resetting the wb state machine (60h) |
default: ; |
endcase |
//address <= address + 1; |
arb_start <= 0; |
addr_increment <= 1; |
if (addr_increment) begin address <= address + 1; end |
if (frame && ~trdylocal) begin |
devsel <= 1; |
state <= ST_IDLE; |
enable <= EN_TR; |
end |
else begin |
enable <= EN_WR; |
end |
end |
end |
|
ST_MEMREAD: begin |
//enable <= EN_RD; |
arb_start <= 0; |
if (~irdy || trdylocal) begin |
//address <= address + 1; |
data <= pci_read_reg; |
pci_read_sel_reg <= ~cbe; |
end |
if (frame && ~irdy && (~trdylocal || ~stoplocal)) begin |
devsel <= 1; |
state <= ST_IDLE; |
enable <= EN_TR; |
//fifo_fill_rd<=0; |
//if (wbwf_state == machine_waiting) begin |
fifo_fill_start_rd <= 1; |
//end |
end |
else begin |
enable <= EN_RD; |
end |
end |
|
ST_MEMWRITE: begin |
//enable <= EN_WR; |
arb_start <= 0; |
if (~irdy) begin |
led <= ad[3:0]; |
pci_write_reg <= ad[31:0]; |
pci_write_sel_reg <= ~cbe; |
//address <= address + 1; |
if (frame & ~trdylocal) begin |
devsel <= 1; |
state <= ST_IDLE; |
enable <= EN_TR; |
fifo_fill<=0; |
//if (wbwf_state == machine_waiting) begin |
fifo_flush_start <= 1; |
//end |
end |
else begin |
enable <= EN_WR; |
end |
end |
|
end |
|
endcase |
end |
end |
endmodule |
/pci-32.v
0,0 → 1,626
// *************************************************************** // |
// // |
// PCI_TARGET-Wishbone_MASTER INTERFACE MODULE (PCI-mini) // |
// v2.0 // |
// // |
// The original PCI module is from: Ben Jackson // |
// http://www.ben.com/minipci/verilog.php // |
// // |
// Redesigned for wishbone : Istvan Nagy, buenos@freemail.hu // |
// PEC Products, Industrial Technologies // |
// // |
// *************************************************************** // |
|
// The core implements a 16MB relocable memory image. Relocable on the |
// wb bus. the wb address = 4M*wb_baseaddr_reg + PCI_addr[23:2] |
// Only Dword aligned Dword accesses allowed on the PCI. This way |
// we can access to the 4GB wb-space through a 16MB PCI-window. |
// The addressing on the wb-bus, is Dword addressing, while on the |
// PCI bus, the addressing is byte addressing. A(pci)=A(wb)*4 |
// The PCI address is increasing by 4, and we get 4 bytes. The wb |
// address is increasing by 1, and we get 1 Dword (= 4 bytes also). |
// The wb_baseaddr_reg is the wb image relocation register, can be |
// accessed at 50h address in the PCI configuration space. |
// Other bridge status and command is at the 54h and 58h addresses. |
// if access fails with timeout, then the address will be in the |
// wb address will be stored in the failed_addr_reg at 5Ch address. |
// |
// Wishbone compatibility: |
// Wishbone signals: wb_address, wb_dat_o, wb_dat_i, wb_sel_o, wb_cyc_o, |
// wb_stb_o, wb_wr_o, wb_reset_o, wb_clk_o, wb_ack_i. |
// Not implemented wb signals: error, lock, retry, tag-signals. |
// The peripheral has to response with ack in 16 clk cycles. |
// The core has wishbone clk and reset outputs, just like a Syscon module. |
// The core generates single reads/writes. These are made of 4 phases, so |
// dont write new data, until internal data movement finishes: about 300...500ns |
// |
// PCI compatibility: |
// Only single DWORD reads/writes are supported. between them, the software has |
// to wait 300...500nsec, to prevent data corrupting. STOP signaling is not |
// implemented, so target terminations also not. |
// Single Byte access is NOT supported! It may cause corrupt data. |
// The core uses INTA interrupt signal. There are some special PCI config |
// registers, from 50h...60h config-space addresses. |
// PCI-parity: it generates parity, but doesnt check incoming parity. |
// Because of the PC chipset, if you read a value and write it back, |
// the chipset will not write anything, because it can see the data is not |
// changed. This is important at some peripherals, where you write, to control. |
// Device specific PCI config header registers: |
// name: addr: function: |
// wb_baseaddr_reg; 50h A(wb)=(A(pci)-BAR0)/4 + wb_baseaddr_reg |
// user_status_reg; 54h not used yet |
// user_command_reg; 58h not used yet |
// failed_addr_reg; 5Ch address, when timeout occurs on the wb bus. |
// |
// Local bus arbitration: |
// This is not really wishbone compatible, but needed for the PCI. |
// The method is: "brute force". it means if the PCI interface wants to |
// be mastering on the local (wishbone) bus, then it will be mastering, |
// so, the other master(s) must stop anything immediately. The req signal |
// goes high when there is an Address hit on teh PCI bus. so the other |
// master has few clk cycles to finish. |
// Restrictions: the peripherals have to be fast: If the other master |
// starts a transaction before req goes high, the ack has to arrive before |
// the PCI interface starts its own transaction. (max 4clk ACK delay) |
// The other master or the bus unit must sense the req, and give bus |
// mastering to the PCI-IF immediatelly, not just when the other master |
// finished everything, like at normal arbitration schemes. |
// |
// Buffering: |
// There is a single Dword buffering only. |
// |
// The led_out interface: |
// only for system-debug: we can write to the LEDs, at any address. |
// (in the same time there is a wishbone write also) |
// |
// Changes since original version: wishbone interface, |
// bigger memory-image, parity-generation, |
// interrupt handling. Code size is 3x bigger. New registers, |
// |
// *************************************************************** // |
|
|
|
module pci(reset,clk,frame,irdy,trdy,devsel,idsel,ad,cbe,par,stop,inta,serr,perr,led_out, wb_address, wb_dat_o, wb_dat_i, wb_sel_o, wb_cyc_o, wb_stb_o, wb_wr_o, wb_reset_o, wb_clk_o, wb_ack_i, wb_irq, wb_req, wb_gnt, wb_req_other); |
input reset; |
input clk; |
input frame; |
input irdy; |
output trdy; |
output devsel; |
input idsel; |
inout [31:0] ad; |
input [3:0] cbe; |
inout par; |
output stop; |
output inta; |
output serr; |
output perr; |
output [3:0] led_out; |
output [31:0] wb_address; |
output [31:0] wb_dat_o; |
input [31:0] wb_dat_i; |
output [3:0] wb_sel_o; |
output wb_cyc_o; |
output wb_stb_o; |
output wb_wr_o; |
output wb_reset_o; |
output wb_clk_o; |
input wb_ack_i; |
input wb_irq; |
output wb_req; |
input wb_gnt; |
input wb_req_other; |
|
|
|
parameter DEVICE_ID = 16'h9500; |
parameter VENDOR_ID = 16'h10EE; // 16'h10EE=xilinx, 16'h106d; // Sequent! |
parameter DEVICE_CLASS = 24'h068000; // Bridge device - other_bridge_type (original:FF0000 Misc) |
parameter DEVICE_REV = 8'h01; |
parameter SUBSYSTEM_ID = 16'h0001; // Card identifier |
parameter SUBSYSTEM_VENDOR_ID = 16'hBEBE; // Card identifier |
parameter DEVSEL_TIMING = 2'b00; // Fast! |
|
reg [2:0] state; |
reg [31:0] data; |
|
reg [1:0] enable; |
parameter EN_NONE = 0; |
parameter EN_RD = 1; |
parameter EN_WR = 2; |
parameter EN_TR = 3; |
|
reg memen; // respond to baseaddr? |
reg [7:0] baseaddr; |
reg [5:0] address; |
|
reg [9:0] wb_baseaddr_reg; //remap the image on the wishbone bus |
reg [31:0] wb_address_1; |
reg [31:0] user_status_reg; |
reg [31:0] user_command_reg; |
reg [31:0] failed_addr_reg; |
reg [31:0] dummy_reg; |
reg [31:0] pci_read_reg; |
reg [31:0] pci_write_reg; |
reg [31:0] wb_read_reg; |
reg [31:0] wb_write_reg; |
reg [3:0] pci_read_sel_reg; |
reg [3:0] pci_write_sel_reg; |
reg [3:0] wb_read_sel_reg; |
reg [3:0] wb_write_sel_reg; |
|
parameter ST_IDLE = 3'b000; |
parameter ST_BUSY = 3'b010; |
parameter ST_MEMREAD = 3'b100; |
parameter ST_MEMWRITE = 3'b101; |
parameter ST_CFGREAD = 3'b110; |
parameter ST_CFGWRITE = 3'b111; |
|
parameter MEMREAD = 4'b0110; |
parameter MEMWRITE = 4'b0111; |
parameter CFGREAD = 4'b1010; |
parameter CFGWRITE = 4'b1011; |
|
`define LED |
`ifdef LED |
reg [3:0] led; |
`endif |
|
`undef STATE_DEBUG_LED |
`ifdef STATE_DEBUG_LED |
assign led_out = ~state; |
`else |
`ifdef LED |
assign led_out = ~led; |
`endif |
`endif |
|
assign ad = (enable == EN_RD) ? data : 32'bZ; |
assign trdy = (enable == EN_NONE) ? 'bZ : (enable == EN_TR ? 1 : 0); |
//assign par = (enable == EN_RD) ? 0 : 'bZ; |
reg devsel; |
|
assign stop = 1'bZ; |
//assign inta = 1'bZ; |
assign serr = 1'bZ; |
assign perr = 1'bZ; |
|
|
wire cfg_hit = ((cbe == CFGREAD || cbe == CFGWRITE) && idsel && ad[1:0] == 2'b00); |
wire addr_hit = ((cbe == MEMREAD || cbe == MEMWRITE) && memen && ad[31:24] == {baseaddr}); |
wire hit = cfg_hit | addr_hit; |
|
// Wishbone SYSCON: output signals------------------------------------ |
assign wb_reset_o = ~reset; |
assign wb_clk_o = clk; |
//reg wb_clk_o; |
//always @(posedge clk) |
//wb_clk_o = wb_clk_o+ 1; |
|
|
// PCI parity generation:--------------------------------------------- |
// during read, the parity on AD, and delayen by one clk. |
reg par_en; |
reg par_latched; |
reg EN_RDd; |
wire data_par = (data[31] ^ data[30] ^ data[29] ^ data[28]) ^ |
(data[27] ^ data[26] ^ data[25] ^ data[24]) ^ |
(data[23] ^ data[22] ^ data[21] ^ data[20]) ^ |
(data[19] ^ data[18] ^ data[17] ^ data[16]) ^ |
(data[15] ^ data[14] ^ data[13] ^ data[12]) ^ |
(data[11] ^ data[10] ^ data[9] ^ data[8]) ^ |
(data[7] ^ data[6] ^ data[5] ^ data[4]) ^ |
(cbe[3] ^ cbe[2] ^ cbe[1] ^ cbe[0]) ^ |
(data[3] ^ data[2] ^ data[1] ^ data[0]) ; |
|
always @(posedge clk) //delaying of parity |
if ((enable == EN_RD)|(enable == EN_TR)) begin |
par_latched = data_par; end |
else |
begin par_latched = 0; end |
|
always @(posedge clk) //delaying of EN_RD |
EN_RDd = EN_RD; |
|
//assign par = (enable == EN_RD) ? 0 : 'bZ; |
assign par = ((enable == EN_RD)|(enable == EN_RDd)) ? par_latched : 'bZ; //output control |
|
|
|
// Interrupt handling:-------------------------------------------------------------------- |
reg int_dis; |
wire int_stat; |
reg [7:0] int_line; |
assign inta = ((wb_irq == 1) && (int_dis == 0)) ? 1'b0 : 1'bZ; |
assign int_stat = wb_irq; |
|
|
|
// WB bus arbitration:-------------------------------------------------------------------- |
//assign wb_req = mastering; |
reg arb_start; |
reg arb_stop; |
reg wb_req; |
|
parameter arb_state1 = 2'b00; |
parameter arb_state2 = 2'b01; |
reg arb_state = arb_state1; |
always@(posedge clk) begin |
if (wb_reset_o) begin |
arb_state <= arb_state1; |
wb_req <= 0; |
end |
else |
case (arb_state) |
arb_state1 : begin //arbitration is not needed: IDLE |
wb_req <= 0; |
if (arb_start == 1) |
arb_state <= arb_state2; |
end |
arb_state2 : begin //arbitration is needed |
wb_req <= 1; |
if (arb_stop == 1) |
arb_state <= arb_state1; |
end |
default : begin // Fault Recovery |
arb_state <= arb_state1; |
wb_req <= 0; |
end |
endcase |
end |
|
|
|
// -------------- wishbone state machine -------------------------------------------------- |
//write FIFO buffer: |
reg [31:0] wb_wr_buf [5:0]; //64 Dwords wb write buffer: wb_wr_buf[index] <= value; |
reg [3:0] wb_wr_sel_buf [5:0]; //select lines, write buffer: wb_wr_buf[index] <= value; |
reg [31:0] fifo_start_wb_addr; |
reg [31:0] fifo_act_wb_addr; |
reg [5:0] fifo_max_count; |
reg [5:0] fifo_wb_counter; |
reg [5:0] fifo_wb_counter_o; |
reg fifo_flush; //wb output mux control |
reg fifo_flush_start; //start pulse |
reg fifo_fill; //disable wb during filling fifo |
reg [3:0] wbw_timeout_count_new; |
reg [1:0] wbw_phase; |
//read FIFO buffer: |
reg [31:0] wb_rd_buf [5:0]; //64 Dwords wb read buffer: wb_rd_buf[index] <= value; |
reg [3:0] wb_rd_sel_buf [5:0]; //select lines, write buffer: wb_wr_buf[index] <= value; |
reg [31:0] fifo_start_wb_addr_rd; |
reg [31:0] fifo_act_wb_addr_rd; |
reg [5:0] fifo_max_count_rd; |
reg [5:0] fifo_wb_counter_rd; |
reg [5:0] fifo_wb_counter_o_rd; |
reg fifo_flush_rd; //wb output mux control |
reg fifo_fill_start_rd; //start pulse |
reg fifo_fill_rd; //disable wb during filling fifo |
reg [3:0] wbr_timeout_count_new; |
reg [1:0] wbr_phase; |
// |
reg wb_cyc_o; |
reg wb_stb_o; |
reg wb_wr_o; |
reg [31:0] wb_address; |
reg [3:0] wb_sel_o; |
reg [31:0] wb_dat_o; |
reg machinereset; |
reg mastering; |
//assign wb_req = mastering; |
|
|
parameter machine_waiting = 2'b00; |
parameter machine_flushing = 2'b01; |
parameter machine_read_filling = 2'b11; |
reg [1:0] wbwf_state = machine_waiting; |
|
always@(posedge wb_clk_o) |
if (wb_reset_o) begin |
wbwf_state <= machine_waiting; |
wbw_phase <= 0; |
wbw_timeout_count_new <= 0; |
fifo_wb_counter_o<=0; |
fifo_flush <= 0; |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wbr_phase <= 0; |
wbr_timeout_count_new <= 0; |
fifo_wb_counter_o_rd<=0; |
fifo_fill_rd <= 0; |
wb_address[31:0] = 32'b0; |
wb_sel_o = 4'b0; |
wb_dat_o = 32'b0; |
pci_read_reg <= 0; |
mastering <= 0; |
arb_stop <= 0; |
failed_addr_reg <= 0; |
end |
else |
case (wbwf_state) |
|
machine_waiting : begin //no operation on Wishbone bus ************** |
wbw_phase <= 0; |
wbw_timeout_count_new <= 0; |
wbr_phase <= 0; |
wbr_timeout_count_new <= 0; |
wb_address[31:0] = 32'b0; |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wb_sel_o = 4'b0; |
wb_dat_o = 32'b0; |
arb_stop <= 0; |
if (fifo_flush_start == 1) |
begin fifo_flush <= 1; wbwf_state <= machine_flushing; fifo_wb_counter_o<=0; mastering <= 1; end |
else if (fifo_fill_start_rd == 1) |
begin fifo_fill_rd <= 1; wbwf_state <= machine_read_filling; fifo_wb_counter_o_rd<=0; mastering <= 1; end |
end |
|
machine_flushing : begin //wr-FIFO flushing: wb write*********************** |
wb_sel_o = pci_write_sel_reg; |
wb_dat_o = pci_write_reg; //wb_wr_buf[fifo_wb_counter_o]; |
wb_address[31:0] = fifo_start_wb_addr; //[31:0]+fifo_wb_counter_o ; |
if ( wbw_phase== 0 ) begin //phase 0: setup |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wbw_phase <= wbw_phase + 1; |
//address and data also changes now, from FIFO |
end |
else if ( wbw_phase== 1 ) begin //phase 1: access |
wb_cyc_o <= 1; |
wb_stb_o <= 1; |
wb_wr_o <= 1; |
wbw_phase <= wbw_phase + 1; |
end |
else if ( wbw_phase== 2 ) begin //phase 2: wait for ack |
wbw_timeout_count_new <= wbw_timeout_count_new +1; |
if ((wb_ack_i==1) | (wbw_timeout_count_new==15)) begin |
wbw_phase <= wbw_phase + 1; |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
if (wbw_timeout_count_new==15) begin failed_addr_reg <= wb_address; end |
end |
else begin wb_cyc_o <= 1; wb_stb_o <= 1; wb_wr_o <= 1; end |
end |
else if ( wbw_phase== 3 ) begin //phase 3: hold (finish) |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wbw_phase <= wbw_phase + 1; |
wbw_timeout_count_new <=0; |
fifo_wb_counter_o <= fifo_wb_counter_o + 1; //for next word |
//if ((fifo_wb_counter_o == fifo_max_count-1)|(machinereset == 1)) begin |
fifo_flush <= 0; |
wbwf_state <= machine_waiting; |
fifo_wb_counter_o<=0; |
mastering <= 0; |
arb_stop <= 1; |
//end |
end |
end |
|
machine_read_filling : begin //rd-FIFO filling: wb read******************** |
wb_sel_o = pci_read_sel_reg; |
wb_dat_o = 32'b0; |
wb_address[31:0] = fifo_start_wb_addr_rd; //[31:0]+fifo_wb_counter_o_rd ; |
if ( wbr_phase== 0 ) begin //phase 0: setup |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wbr_phase <= wbr_phase + 1; |
//address and data also changes now, from FIFO |
end |
else if ( wbr_phase== 1 ) begin //phase 1: access |
wb_cyc_o <= 1; |
wb_stb_o <= 1; |
wb_wr_o <= 0; |
wbr_phase <= wbr_phase + 1; |
end |
else if ( wbr_phase== 2 ) begin //phase 2: wait for ack |
wbr_timeout_count_new <= wbr_timeout_count_new +1; |
if ((wb_ack_i==1) | (wbr_timeout_count_new==15)) begin |
//wb_rd_buf[fifo_wb_counter_o_rd] <= wb_dat_i; //sampling |
pci_read_reg <= wb_dat_i; //sampling |
wbr_phase <= wbr_phase + 1; |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
if (wbw_timeout_count_new==15) begin failed_addr_reg <= wb_address; end |
end |
else begin wb_cyc_o <= 1; wb_stb_o <= 1; wb_wr_o <= 0; end |
end |
else if ( wbr_phase== 3 ) begin //phase 3: hold (finish) |
wb_cyc_o <= 0; |
wb_stb_o <= 0; |
wb_wr_o <= 0; |
wbr_phase <= wbw_phase + 1; |
wbr_timeout_count_new <=0; |
fifo_wb_counter_o_rd <= fifo_wb_counter_o_rd + 1; //for next word |
//if ((fifo_wb_counter_o_rd == fifo_max_count_rd-1)|(machinereset == 1)) begin |
fifo_fill_rd <= 0; |
wbwf_state <= machine_waiting; |
fifo_wb_counter_o_rd<=0; |
mastering <= 0; |
arb_stop <= 1; |
//end |
end |
end |
|
default : begin // Fault Recovery |
wbwf_state <= machine_waiting; |
end |
|
|
endcase |
|
|
|
|
|
|
|
// main PCI state machine: --------------------------------------------------------------- |
always @(posedge clk) |
begin |
if (~reset) begin |
state <= ST_IDLE; |
enable <= EN_NONE; |
baseaddr <= 0; |
devsel <= 'bZ; |
memen <= 0; |
int_line <= 8'b0; |
int_dis <= 0; |
wb_baseaddr_reg <= 0; |
wb_address_1[31:0] <= 0; |
user_status_reg <= 0; |
user_command_reg <= 0; |
fifo_flush_start <= 0; |
fifo_fill_start_rd <= 0; |
fifo_wb_counter <= 0; |
fifo_wb_counter_rd <= 0; |
dummy_reg <= 0; |
pci_write_reg <= 0; |
machinereset <= 0; |
led <= 0; |
arb_start <= 0; |
|
end |
else begin |
|
case (state) |
ST_IDLE: begin |
enable <= EN_NONE; |
devsel <= 'bZ; |
fifo_flush_start <= 0; |
fifo_fill_start_rd <= 0; |
fifo_wb_counter <= 0; |
fifo_wb_counter_rd <= 0; |
machinereset <= 0; |
if (~frame) begin |
address <= ad[7:2]; |
if (hit) begin |
state <= {1'b1, cbe[3], cbe[0]}; |
if (addr_hit) begin arb_start <= 1; end |
devsel <= 0; |
wb_address_1[31:0] <= {wb_baseaddr_reg, ad[23:2]}; |
//if (wbwf_state == machine_waiting) begin //sample address, if FIFO is not busy |
fifo_start_wb_addr <= {wb_baseaddr_reg, ad[23:2]}; |
fifo_start_wb_addr_rd <= {wb_baseaddr_reg, ad[23:2]}; |
//end |
// pipeline the write enable |
if (cbe[0]) |
enable <= EN_WR; |
end |
else begin |
state <= ST_BUSY; |
enable <= EN_NONE; |
end |
end |
end |
|
ST_BUSY: begin |
devsel <= 'bZ; |
enable <= EN_NONE; |
arb_start <= 0; |
if (frame) |
state <= ST_IDLE; |
end |
|
ST_CFGREAD: begin |
enable <= EN_RD; |
if (~irdy || trdy) begin |
case (address) |
0: data <= { DEVICE_ID, VENDOR_ID }; |
1: data <= { 5'b0, DEVSEL_TIMING, 5'b0, int_stat, 8'b0, int_dis, 8'b0, memen, 1'b0}; |
2: data <= { DEVICE_CLASS, DEVICE_REV }; |
4: data <= { baseaddr, 12'b0, 8'b0, 4'b0000 }; // baseaddr + request mem < 1Mbyte |
11: data <= {SUBSYSTEM_ID, SUBSYSTEM_VENDOR_ID }; |
15: data <= {16'b0, 7'b0, 1'b1, int_line}; //irq pin and line |
16: data <= { 24'b0, baseaddr }; |
20: data <= { wb_baseaddr_reg, 22'b0}; //wb base address: for wb-local relocation |
21: data <= user_status_reg; |
22: data <= user_command_reg; |
23: data <= failed_addr_reg; //actual addr, at a timeout |
default: data <= 'h00000000; |
endcase |
address <= address + 1; |
arb_start <= 0; |
end |
if (frame && ~irdy && ~trdy) begin |
devsel <= 1; |
state <= ST_IDLE; |
enable <= EN_TR; |
end |
end |
|
ST_CFGWRITE: begin |
enable <= EN_WR; |
if (~irdy) begin |
case (address) |
4: baseaddr <= ad[31:24]; // XXX examine cbe |
1: begin memen <= ad[1]; int_dis <= ad[10]; end |
15: int_line <= ad[7:0]; |
20: wb_baseaddr_reg <= ad[31:22]; |
22: user_command_reg <= ad[31:0]; |
24: machinereset <= 1; //resetting the wb state machine (60h) |
default: ; |
endcase |
address <= address + 1; |
arb_start <= 0; |
if (frame) begin |
devsel <= 1; |
state <= ST_IDLE; |
enable <= EN_TR; |
end |
end |
end |
|
ST_MEMREAD: begin |
enable <= EN_RD; |
arb_start <= 0; |
if (~irdy || trdy) begin |
address <= address + 1; |
data <= pci_read_reg; |
pci_read_sel_reg <= ~cbe; |
end |
if (frame && ~irdy && ~trdy) begin |
devsel <= 1; |
state <= ST_IDLE; |
enable <= EN_TR; |
fifo_fill_rd<=0; |
//if (wbwf_state == machine_waiting) begin |
fifo_fill_start_rd <= 1; |
//end |
end |
end |
|
ST_MEMWRITE: begin |
enable <= EN_WR; |
arb_start <= 0; |
if (~irdy) begin |
led <= ad[3:0]; |
pci_write_reg <= ad[31:0]; |
pci_write_sel_reg <= ~cbe; |
address <= address + 1; |
if (frame) begin |
devsel <= 1; |
state <= ST_IDLE; |
enable <= EN_TR; |
fifo_fill<=0; |
//if (wbwf_state == machine_waiting) begin |
fifo_flush_start <= 1; |
//end |
end |
end |
|
end |
|
endcase |
end |
end |
endmodule |
/pci_mini-34_timing_constraints.sdc
0,0 → 1,68
# Synopsys, Inc. constraint file |
# Written on Wed Apr 13 17:34:51 2011 |
# by Synplify Pro, D-2009.12A Scope Editor |
|
# |
# Collections |
# |
|
# |
# Clocks |
# |
|
define_clock {pciclk} -name {pciclk} -freq 33 -clockgroup default_clkgroup_2 |
|
|
# |
# Clock to Clock |
# |
|
|
# |
# Inputs/Outputs |
# |
define_input_delay {serr} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_input_delay {perr} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_input_delay {idsel} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_input_delay {stop} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_input_delay {devsel} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_input_delay {trdy} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_input_delay {irdy} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_input_delay {frame} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_input_delay {par} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_input_delay {cbe[3:0]} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_input_delay {AD[31:0]} 7.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
|
define_output_delay {serr} 22.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_output_delay {perr} 22.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_output_delay {stop} 22.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_output_delay {devsel} 22.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_output_delay {trdy} 22.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_output_delay {par} 22.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
define_output_delay {AD[31:0]} 22.00 -improve 0.00 -route 0.00 -ref {pciclk:r} |
|
|
# |
# Registers |
# |
|
# |
# Delay Paths |
# |
|
# |
# Attributes |
# |
|
# |
# I/O Standards |
# |
|
|
# |
# Compile Points |
# |
|
# |
# Other |
# |
/PCI_Mini_IP_core_Datasheet2.0_oc.pdf
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
PCI_Mini_IP_core_Datasheet2.0_oc.pdf
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: pci-33.v
===================================================================
--- pci-33.v (nonexistent)
+++ pci-33.v (revision 7)
@@ -0,0 +1,629 @@
+// *************************************************************** //
+// //
+// PCI_TARGET-Wishbone_MASTER INTERFACE MODULE (PCI-mini) //
+// v2.0 //
+// //
+// The original PCI module is from: Ben Jackson //
+// http://www.ben.com/minipci/verilog.php //
+// //
+// Redesigned for wishbone : Istvan Nagy, buenos@freemail.hu //
+// PEC Products, Industrial Technologies //
+// //
+// *************************************************************** //
+
+// The core implements a 16MB relocable memory image. Relocable on the
+// wb bus. the wb address = 4M*wb_baseaddr_reg + PCI_addr[23:2]
+// Only Dword aligned Dword accesses allowed on the PCI. This way
+// we can access to the 4GB wb-space through a 16MB PCI-window.
+// The addressing on the wb-bus, is Dword addressing, while on the
+// PCI bus, the addressing is byte addressing. A(pci)=A(wb)*4
+// The PCI address is increasing by 4, and we get 4 bytes. The wb
+// address is increasing by 1, and we get 1 Dword (= 4 bytes also).
+// The wb_baseaddr_reg is the wb image relocation register, can be
+// accessed at 50h address in the PCI configuration space.
+// Other bridge status and command is at the 54h and 58h addresses.
+// if access fails with timeout, then the address will be in the
+// wb address will be stored in the failed_addr_reg at 5Ch address.
+//
+// Wishbone compatibility:
+// Wishbone signals: wb_address, wb_dat_o, wb_dat_i, wb_sel_o, wb_cyc_o,
+// wb_stb_o, wb_wr_o, wb_reset_o, wb_clk_o, wb_ack_i.
+// Not implemented wb signals: error, lock, retry, tag-signals.
+// The peripheral has to response with ack in 16 clk cycles.
+// The core has wishbone clk and reset outputs, just like a Syscon module.
+// The core generates single reads/writes. These are made of 4 phases, so
+// dont write new data, until internal data movement finishes: about 300...500ns
+//
+// PCI compatibility:
+// Only single DWORD reads/writes are supported. between them, the software has
+// to wait 300...500nsec, to prevent data corrupting. STOP signaling is not
+// implemented, so target terminations also not.
+// Single Byte access is NOT supported! It may cause corrupt data.
+// The core uses INTA interrupt signal. There are some special PCI config
+// registers, from 50h...60h config-space addresses.
+// PCI-parity: it generates parity, but doesnt check incoming parity.
+// Because of the PC chipset, if you read a value and write it back,
+// the chipset will not write anything, because it can see the data is not
+// changed. This is important at some peripherals, where you write, to control.
+// Device specific PCI config header registers:
+// name: addr: function:
+// wb_baseaddr_reg; 50h A(wb)=(A(pci)-BAR0)/4 + wb_baseaddr_reg
+// user_status_reg; 54h not used yet
+// user_command_reg; 58h not used yet
+// failed_addr_reg; 5Ch address, when timeout occurs on the wb bus.
+//
+// Local bus arbitration:
+// This is not really wishbone compatible, but needed for the PCI.
+// The method is: "brute force". it means if the PCI interface wants to
+// be mastering on the local (wishbone) bus, then it will be mastering,
+// so, the other master(s) must stop anything immediately. The req signal
+// goes high when there is an Address hit on teh PCI bus. so the other
+// master has few clk cycles to finish.
+// Restrictions: the peripherals have to be fast: If the other master
+// starts a transaction before req goes high, the ack has to arrive before
+// the PCI interface starts its own transaction. (max 4clk ACK delay)
+// The other master or the bus unit must sense the req, and give bus
+// mastering to the PCI-IF immediatelly, not just when the other master
+// finished everything, like at normal arbitration schemes.
+//
+// Buffering:
+// There is a single Dword buffering only.
+//
+// The led_out interface:
+// only for system-debug: we can write to the LEDs, at any address.
+// (in the same time there is a wishbone write also)
+//
+// Changes since original version: wishbone interface,
+// bigger memory-image, parity-generation,
+// interrupt handling. Code size is 3x bigger. New registers,
+//
+// *************************************************************** //
+
+
+
+module pci(reset,clk,frame,irdy,trdy,devsel,idsel,ad,cbe,par,stop,inta,serr,perr,led_out, wb_address, wb_dat_o, wb_dat_i, wb_sel_o, wb_cyc_o, wb_stb_o, wb_wr_o, wb_reset_o, wb_clk_o, wb_ack_i, wb_irq, wb_req, wb_gnt, wb_req_other, contr_o);
+ input reset;
+ input clk;
+ input frame;
+ input irdy;
+ output trdy;
+ output devsel;
+ input idsel;
+ inout [31:0] ad;
+ input [3:0] cbe;
+ inout par;
+ output stop;
+ output inta;
+ output serr;
+ output perr;
+ output [3:0] led_out;
+ output [31:0] wb_address;
+ output [31:0] wb_dat_o;
+ input [31:0] wb_dat_i;
+ output [3:0] wb_sel_o;
+ output wb_cyc_o;
+ output wb_stb_o;
+ output wb_wr_o;
+ output wb_reset_o;
+ output wb_clk_o;
+ input wb_ack_i;
+ input wb_irq;
+ output wb_req;
+ input wb_gnt;
+ input wb_req_other;
+ output [7:0] contr_o;
+
+
+
+parameter DEVICE_ID = 16'h9500;
+parameter VENDOR_ID = 16'h10EE; // 16'h10EE=xilinx, 16'h106d; // Sequent!
+parameter DEVICE_CLASS = 24'h068000; // Bridge device - other_bridge_type (original:FF0000 Misc)
+parameter DEVICE_REV = 8'h01;
+parameter SUBSYSTEM_ID = 16'h0001; // Card identifier
+parameter SUBSYSTEM_VENDOR_ID = 16'hBEBE; // Card identifier
+parameter DEVSEL_TIMING = 2'b00; // Fast!
+
+reg [2:0] state;
+reg [31:0] data;
+
+reg [1:0] enable;
+parameter EN_NONE = 0;
+parameter EN_RD = 1;
+parameter EN_WR = 2;
+parameter EN_TR = 3;
+
+reg memen; // respond to baseaddr?
+reg [7:0] baseaddr;
+reg [5:0] address;
+
+reg [9:0] wb_baseaddr_reg; //remap the image on the wishbone bus
+reg [31:0] wb_address_1;
+reg [31:0] user_status_reg;
+reg [31:0] user_command_reg;
+reg [31:0] failed_addr_reg;
+reg [31:0] dummy_reg;
+reg [31:0] pci_read_reg;
+reg [31:0] pci_write_reg;
+reg [31:0] wb_read_reg;
+reg [31:0] wb_write_reg;
+reg [3:0] pci_read_sel_reg;
+reg [3:0] pci_write_sel_reg;
+reg [3:0] wb_read_sel_reg;
+reg [3:0] wb_write_sel_reg;
+
+assign contr_o = user_command_reg [7:0];
+
+parameter ST_IDLE = 3'b000;
+parameter ST_BUSY = 3'b010;
+parameter ST_MEMREAD = 3'b100;
+parameter ST_MEMWRITE = 3'b101;
+parameter ST_CFGREAD = 3'b110;
+parameter ST_CFGWRITE = 3'b111;
+
+parameter MEMREAD = 4'b0110;
+parameter MEMWRITE = 4'b0111;
+parameter CFGREAD = 4'b1010;
+parameter CFGWRITE = 4'b1011;
+
+`define LED
+`ifdef LED
+reg [3:0] led;
+`endif
+
+`undef STATE_DEBUG_LED
+`ifdef STATE_DEBUG_LED
+assign led_out = ~state;
+`else
+`ifdef LED
+assign led_out = ~led;
+`endif
+`endif
+
+assign ad = (enable == EN_RD) ? data : 32'bZ;
+assign trdy = (enable == EN_NONE) ? 'bZ : (enable == EN_TR ? 1 : 0);
+//assign par = (enable == EN_RD) ? 0 : 'bZ;
+reg devsel;
+
+assign stop = 1'bZ;
+//assign inta = 1'bZ;
+assign serr = 1'bZ;
+assign perr = 1'bZ;
+
+
+wire cfg_hit = ((cbe == CFGREAD || cbe == CFGWRITE) && idsel && ad[1:0] == 2'b00);
+wire addr_hit = ((cbe == MEMREAD || cbe == MEMWRITE) && memen && ad[31:24] == {baseaddr});
+wire hit = cfg_hit | addr_hit;
+
+// Wishbone SYSCON: output signals------------------------------------
+assign wb_reset_o = ~reset;
+assign wb_clk_o = clk;
+//reg wb_clk_o;
+ //always @(posedge clk)
+ //wb_clk_o = wb_clk_o+ 1;
+
+
+// PCI parity generation:---------------------------------------------
+// during read, the parity on AD, and delayen by one clk.
+reg par_en;
+reg par_latched;
+reg EN_RDd;
+wire data_par = (data[31] ^ data[30] ^ data[29] ^ data[28]) ^
+ (data[27] ^ data[26] ^ data[25] ^ data[24]) ^
+ (data[23] ^ data[22] ^ data[21] ^ data[20]) ^
+ (data[19] ^ data[18] ^ data[17] ^ data[16]) ^
+ (data[15] ^ data[14] ^ data[13] ^ data[12]) ^
+ (data[11] ^ data[10] ^ data[9] ^ data[8]) ^
+ (data[7] ^ data[6] ^ data[5] ^ data[4]) ^
+ (cbe[3] ^ cbe[2] ^ cbe[1] ^ cbe[0]) ^
+ (data[3] ^ data[2] ^ data[1] ^ data[0]) ;
+
+ always @(posedge clk) //delaying of parity
+ if ((enable == EN_RD)|(enable == EN_TR)) begin
+ par_latched = data_par; end
+ else
+ begin par_latched = 0; end
+
+ always @(posedge clk) //delaying of EN_RD
+ EN_RDd = EN_RD;
+
+ //assign par = (enable == EN_RD) ? 0 : 'bZ;
+ assign par = ((enable == EN_RD)|(enable == EN_RDd)) ? par_latched : 'bZ; //output control
+
+
+
+// Interrupt handling:--------------------------------------------------------------------
+reg int_dis;
+wire int_stat;
+reg [7:0] int_line;
+assign inta = ((wb_irq == 1) && (int_dis == 0)) ? 1'b0 : 1'bZ;
+assign int_stat = wb_irq;
+
+
+
+// WB bus arbitration:--------------------------------------------------------------------
+//assign wb_req = mastering;
+reg arb_start;
+reg arb_stop;
+reg wb_req;
+
+ parameter arb_state1 = 2'b00;
+ parameter arb_state2 = 2'b01;
+ reg arb_state = arb_state1;
+ always@(posedge clk) begin
+ if (wb_reset_o) begin
+ arb_state <= arb_state1;
+ wb_req <= 0;
+ end
+ else
+ case (arb_state)
+ arb_state1 : begin //arbitration is not needed: IDLE
+ wb_req <= 0;
+ if (arb_start == 1)
+ arb_state <= arb_state2;
+ end
+ arb_state2 : begin //arbitration is needed
+ wb_req <= 1;
+ if (arb_stop == 1)
+ arb_state <= arb_state1;
+ end
+ default : begin // Fault Recovery
+ arb_state <= arb_state1;
+ wb_req <= 0;
+ end
+ endcase
+ end
+
+
+
+// -------------- wishbone state machine --------------------------------------------------
+//write FIFO buffer:
+reg [31:0] wb_wr_buf [5:0]; //64 Dwords wb write buffer: wb_wr_buf[index] <= value;
+reg [3:0] wb_wr_sel_buf [5:0]; //select lines, write buffer: wb_wr_buf[index] <= value;
+reg [31:0] fifo_start_wb_addr;
+reg [31:0] fifo_act_wb_addr;
+reg [5:0] fifo_max_count;
+reg [5:0] fifo_wb_counter;
+reg [5:0] fifo_wb_counter_o;
+reg fifo_flush; //wb output mux control
+reg fifo_flush_start; //start pulse
+reg fifo_fill; //disable wb during filling fifo
+reg [3:0] wbw_timeout_count_new;
+reg [1:0] wbw_phase;
+//read FIFO buffer:
+reg [31:0] wb_rd_buf [5:0]; //64 Dwords wb read buffer: wb_rd_buf[index] <= value;
+reg [3:0] wb_rd_sel_buf [5:0]; //select lines, write buffer: wb_wr_buf[index] <= value;
+reg [31:0] fifo_start_wb_addr_rd;
+reg [31:0] fifo_act_wb_addr_rd;
+reg [5:0] fifo_max_count_rd;
+reg [5:0] fifo_wb_counter_rd;
+reg [5:0] fifo_wb_counter_o_rd;
+reg fifo_flush_rd; //wb output mux control
+reg fifo_fill_start_rd; //start pulse
+reg fifo_fill_rd; //disable wb during filling fifo
+reg [3:0] wbr_timeout_count_new;
+reg [1:0] wbr_phase;
+//
+reg wb_cyc_o;
+reg wb_stb_o;
+reg wb_wr_o;
+reg [31:0] wb_address;
+reg [3:0] wb_sel_o;
+reg [31:0] wb_dat_o;
+reg machinereset;
+reg mastering;
+//assign wb_req = mastering;
+
+
+ parameter machine_waiting = 2'b00;
+ parameter machine_flushing = 2'b01;
+ parameter machine_read_filling = 2'b11;
+ reg [1:0] wbwf_state = machine_waiting;
+
+ always@(posedge wb_clk_o)
+ if (wb_reset_o) begin
+ wbwf_state <= machine_waiting;
+ wbw_phase <= 0;
+ wbw_timeout_count_new <= 0;
+ fifo_wb_counter_o<=0;
+ fifo_flush <= 0;
+ wb_cyc_o <= 0;
+ wb_stb_o <= 0;
+ wb_wr_o <= 0;
+ wbr_phase <= 0;
+ wbr_timeout_count_new <= 0;
+ fifo_wb_counter_o_rd<=0;
+ fifo_fill_rd <= 0;
+ wb_address[31:0] = 32'b0;
+ wb_sel_o = 4'b0;
+ wb_dat_o = 32'b0;
+ pci_read_reg <= 0;
+ mastering <= 0;
+ arb_stop <= 0;
+ failed_addr_reg <= 0;
+ end
+ else
+ case (wbwf_state)
+
+ machine_waiting : begin //no operation on Wishbone bus **************
+ wbw_phase <= 0;
+ wbw_timeout_count_new <= 0;
+ wbr_phase <= 0;
+ wbr_timeout_count_new <= 0;
+ wb_address[31:0] = 32'b0;
+ wb_cyc_o <= 0;
+ wb_stb_o <= 0;
+ wb_wr_o <= 0;
+ wb_sel_o = 4'b0;
+ wb_dat_o = 32'b0;
+ arb_stop <= 0;
+ if (fifo_flush_start == 1)
+ begin fifo_flush <= 1; wbwf_state <= machine_flushing; fifo_wb_counter_o<=0; mastering <= 1; end
+ else if (fifo_fill_start_rd == 1)
+ begin fifo_fill_rd <= 1; wbwf_state <= machine_read_filling; fifo_wb_counter_o_rd<=0; mastering <= 1; end
+ end
+
+ machine_flushing : begin //wr-FIFO flushing: wb write***********************
+ wb_sel_o = pci_write_sel_reg;
+ wb_dat_o = pci_write_reg; //wb_wr_buf[fifo_wb_counter_o];
+ wb_address[31:0] = fifo_start_wb_addr; //[31:0]+fifo_wb_counter_o ;
+ if ( wbw_phase== 0 ) begin //phase 0: setup
+ wb_cyc_o <= 0;
+ wb_stb_o <= 0;
+ wb_wr_o <= 0;
+ wbw_phase <= wbw_phase + 1;
+ //address and data also changes now, from FIFO
+ end
+ else if ( wbw_phase== 1 ) begin //phase 1: access
+ wb_cyc_o <= 1;
+ wb_stb_o <= 1;
+ wb_wr_o <= 1;
+ wbw_phase <= wbw_phase + 1;
+ end
+ else if ( wbw_phase== 2 ) begin //phase 2: wait for ack
+ wbw_timeout_count_new <= wbw_timeout_count_new +1;
+ if ((wb_ack_i==1) | (wbw_timeout_count_new==15)) begin
+ wbw_phase <= wbw_phase + 1;
+ wb_cyc_o <= 0;
+ wb_stb_o <= 0;
+ wb_wr_o <= 0;
+ if (wbw_timeout_count_new==15) begin failed_addr_reg <= wb_address; end
+ end
+ else begin wb_cyc_o <= 1; wb_stb_o <= 1; wb_wr_o <= 1; end
+ end
+ else if ( wbw_phase== 3 ) begin //phase 3: hold (finish)
+ wb_cyc_o <= 0;
+ wb_stb_o <= 0;
+ wb_wr_o <= 0;
+ wbw_phase <= wbw_phase + 1;
+ wbw_timeout_count_new <=0;
+ fifo_wb_counter_o <= fifo_wb_counter_o + 1; //for next word
+ //if ((fifo_wb_counter_o == fifo_max_count-1)|(machinereset == 1)) begin
+ fifo_flush <= 0;
+ wbwf_state <= machine_waiting;
+ fifo_wb_counter_o<=0;
+ mastering <= 0;
+ arb_stop <= 1;
+ //end
+ end
+ end
+
+ machine_read_filling : begin //rd-FIFO filling: wb read********************
+ wb_sel_o = pci_read_sel_reg;
+ wb_dat_o = 32'b0;
+ wb_address[31:0] = fifo_start_wb_addr_rd; //[31:0]+fifo_wb_counter_o_rd ;
+ if ( wbr_phase== 0 ) begin //phase 0: setup
+ wb_cyc_o <= 0;
+ wb_stb_o <= 0;
+ wb_wr_o <= 0;
+ wbr_phase <= wbr_phase + 1;
+ //address and data also changes now, from FIFO
+ end
+ else if ( wbr_phase== 1 ) begin //phase 1: access
+ wb_cyc_o <= 1;
+ wb_stb_o <= 1;
+ wb_wr_o <= 0;
+ wbr_phase <= wbr_phase + 1;
+ end
+ else if ( wbr_phase== 2 ) begin //phase 2: wait for ack
+ wbr_timeout_count_new <= wbr_timeout_count_new +1;
+ if ((wb_ack_i==1) | (wbr_timeout_count_new==15)) begin
+ //wb_rd_buf[fifo_wb_counter_o_rd] <= wb_dat_i; //sampling
+ pci_read_reg <= wb_dat_i; //sampling
+ wbr_phase <= wbr_phase + 1;
+ wb_cyc_o <= 0;
+ wb_stb_o <= 0;
+ wb_wr_o <= 0;
+ if (wbw_timeout_count_new==15) begin failed_addr_reg <= wb_address; end
+ end
+ else begin wb_cyc_o <= 1; wb_stb_o <= 1; wb_wr_o <= 0; end
+ end
+ else if ( wbr_phase== 3 ) begin //phase 3: hold (finish)
+ wb_cyc_o <= 0;
+ wb_stb_o <= 0;
+ wb_wr_o <= 0;
+ wbr_phase <= wbw_phase + 1;
+ wbr_timeout_count_new <=0;
+ fifo_wb_counter_o_rd <= fifo_wb_counter_o_rd + 1; //for next word
+ //if ((fifo_wb_counter_o_rd == fifo_max_count_rd-1)|(machinereset == 1)) begin
+ fifo_fill_rd <= 0;
+ wbwf_state <= machine_waiting;
+ fifo_wb_counter_o_rd<=0;
+ mastering <= 0;
+ arb_stop <= 1;
+ //end
+ end
+ end
+
+ default : begin // Fault Recovery
+ wbwf_state <= machine_waiting;
+ end
+
+
+ endcase
+
+
+
+
+
+
+
+// main PCI state machine: ---------------------------------------------------------------
+always @(posedge clk)
+begin
+ if (~reset) begin
+ state <= ST_IDLE;
+ enable <= EN_NONE;
+ baseaddr <= 0;
+ devsel <= 'bZ;
+ memen <= 0;
+ int_line <= 8'b0;
+ int_dis <= 0;
+ wb_baseaddr_reg <= 0;
+ wb_address_1[31:0] <= 0;
+ user_status_reg <= 0;
+ user_command_reg <= 0;
+ fifo_flush_start <= 0;
+ fifo_fill_start_rd <= 0;
+ fifo_wb_counter <= 0;
+ fifo_wb_counter_rd <= 0;
+ dummy_reg <= 0;
+ pci_write_reg <= 0;
+ machinereset <= 0;
+ led <= 0;
+ arb_start <= 0;
+
+ end
+ else begin
+
+ case (state)
+ ST_IDLE: begin
+ enable <= EN_NONE;
+ devsel <= 'bZ;
+ fifo_flush_start <= 0;
+ fifo_fill_start_rd <= 0;
+ fifo_wb_counter <= 0;
+ fifo_wb_counter_rd <= 0;
+ machinereset <= 0;
+ if (~frame) begin
+ address <= ad[7:2];
+ if (hit) begin
+ state <= {1'b1, cbe[3], cbe[0]};
+ if (addr_hit) begin arb_start <= 1; end
+ devsel <= 0;
+ wb_address_1[31:0] <= {wb_baseaddr_reg, ad[23:2]};
+ //if (wbwf_state == machine_waiting) begin //sample address, if FIFO is not busy
+ fifo_start_wb_addr <= {wb_baseaddr_reg, ad[23:2]};
+ fifo_start_wb_addr_rd <= {wb_baseaddr_reg, ad[23:2]};
+ //end
+ // pipeline the write enable
+ if (cbe[0])
+ enable <= EN_WR;
+ end
+ else begin
+ state <= ST_BUSY;
+ enable <= EN_NONE;
+ end
+ end
+ end
+
+ ST_BUSY: begin
+ devsel <= 'bZ;
+ enable <= EN_NONE;
+ arb_start <= 0;
+ if (frame)
+ state <= ST_IDLE;
+ end
+
+ ST_CFGREAD: begin
+ enable <= EN_RD;
+ if (~irdy || trdy) begin
+ case (address)
+ 0: data <= { DEVICE_ID, VENDOR_ID };
+ 1: data <= { 5'b0, DEVSEL_TIMING, 5'b0, int_stat, 8'b0, int_dis, 8'b0, memen, 1'b0};
+ 2: data <= { DEVICE_CLASS, DEVICE_REV };
+ 4: data <= { baseaddr, 12'b0, 8'b0, 4'b0000 }; // baseaddr + request mem < 1Mbyte
+ 11: data <= {SUBSYSTEM_ID, SUBSYSTEM_VENDOR_ID };
+ 15: data <= {16'b0, 7'b0, 1'b1, int_line}; //irq pin and line
+ 16: data <= { 24'b0, baseaddr };
+ 20: data <= { wb_baseaddr_reg, 22'b0}; //wb base address: for wb-local relocation
+ 21: data <= user_status_reg;
+ 22: data <= user_command_reg;
+ 23: data <= failed_addr_reg; //actual addr, at a timeout
+ default: data <= 'h00000000;
+ endcase
+ address <= address + 1;
+ arb_start <= 0;
+ end
+ if (frame && ~irdy && ~trdy) begin
+ devsel <= 1;
+ state <= ST_IDLE;
+ enable <= EN_TR;
+ end
+ end
+
+ ST_CFGWRITE: begin
+ enable <= EN_WR;
+ if (~irdy) begin
+ case (address)
+ 4: baseaddr <= ad[31:24]; // XXX examine cbe
+ 1: begin memen <= ad[1]; int_dis <= ad[10]; end
+ 15: int_line <= ad[7:0];
+ 20: wb_baseaddr_reg <= ad[31:22];
+ 22: user_command_reg <= ad[31:0];
+ 24: machinereset <= 1; //resetting the wb state machine (60h)
+ default: ;
+ endcase
+ address <= address + 1;
+ arb_start <= 0;
+ if (frame) begin
+ devsel <= 1;
+ state <= ST_IDLE;
+ enable <= EN_TR;
+ end
+ end
+ end
+
+ ST_MEMREAD: begin
+ enable <= EN_RD;
+ arb_start <= 0;
+ if (~irdy || trdy) begin
+ address <= address + 1;
+ data <= pci_read_reg;
+ pci_read_sel_reg <= ~cbe;
+ end
+ if (frame && ~irdy && ~trdy) begin
+ devsel <= 1;
+ state <= ST_IDLE;
+ enable <= EN_TR;
+ fifo_fill_rd<=0;
+ //if (wbwf_state == machine_waiting) begin
+ fifo_fill_start_rd <= 1;
+ //end
+ end
+ end
+
+ ST_MEMWRITE: begin
+ enable <= EN_WR;
+ arb_start <= 0;
+ if (~irdy) begin
+ led <= ad[3:0];
+ pci_write_reg <= ad[31:0];
+ pci_write_sel_reg <= ~cbe;
+ address <= address + 1;
+ if (frame) begin
+ devsel <= 1;
+ state <= ST_IDLE;
+ enable <= EN_TR;
+ fifo_fill<=0;
+ //if (wbwf_state == machine_waiting) begin
+ fifo_flush_start <= 1;
+ //end
+ end
+ end
+
+ end
+
+ endcase
+ end
+end
+endmodule
Index: sample_testbench.GIF
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: sample_testbench.GIF
===================================================================
--- sample_testbench.GIF (nonexistent)
+++ sample_testbench.GIF (revision 7)
sample_testbench.GIF
Property changes :
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: sample_timing_constraints.ucf.txt
===================================================================
--- sample_timing_constraints.ucf.txt (nonexistent)
+++ sample_timing_constraints.ucf.txt (revision 7)
@@ -0,0 +1,80 @@
+# --------------------------------------------------------------
+#
+# Sample Constraints file for pci-mini project
+#
+# Istvan Nagy, PEC Products, Industrial Technologies, 2007
+#
+#
+# The signal names are coming from a used project's top-level
+# signals. These will be different in your project. So, rename
+# them. and copy them into your ucf file, if you use xilinx-ISE.
+# --------------------------------------------------------------
+
+
+#--------------User_Timing ------------------------------------
+NET "extPCICLK" PERIOD = 30 ns HIGH 50 %;
+OFFSET = OUT 23 ns AFTER "extPCICLK" ;
+TIMESPEC "TS_P2P" = FROM "PADS" TO "PADS" 23 ns;
+#TIMESPEC TS_extPCICLK=PERIOD extPCICLK 30 HIGH 15
+# from the pci-opencores.
+NET "extPCI_devsel" OFFSET = IN 7 ns BEFORE "extPCICLK" ;
+NET "extPCI_devsel" OFFSET = OUT 11 ns AFTER "extPCICLK" ;
+NET "extPCI_frame" OFFSET = IN 7 ns BEFORE "extPCICLK" ;
+NET "extPCI_frame" OFFSET = OUT 11 ns AFTER "extPCICLK" ;
+#INST "FRAME.PAD" TNM = "PCI_CTRL"
+#INST "GNT.PAD" TNM = "PCI_GNT"
+NET "extPCI_irdy" OFFSET = IN 7 ns BEFORE "extPCICLK" ;
+NET "extPCI_irdy" OFFSET = OUT 11 ns AFTER "extPCICLK" ;
+#INST "IRDY.PAD" TNM="PCI_CTRL"
+NET "extPCI_par" OFFSET = IN 7 ns BEFORE "extPCICLK" ;
+NET "extPCI_par" OFFSET = OUT 11 ns AFTER "extPCICLK" ;
+#INST "PAR.PAD" TNM = "PCI_CTRL"
+##NET "extPCI_perr" OFFSET = IN 7 ns BEFORE "extPCICLK" ;
+##NET "extPCI_perr" OFFSET = OUT 11 ns AFTER "extPCICLK" ;
+#INST "PERR.PAD" TNM = "PCI_CTRL"
+#INST "REQ.PAD" TNM = "PCI_REQ"
+##NET "extPCI_serr" OFFSET = OUT 11 ns AFTER "extPCICLK" ;
+#INST "SERR.PAD" TNM = "PCI_CTRL"
+#INST "STOP.PAD" TNM = "PCI_CTRL"
+NET "extPCI_stop" OFFSET = IN 7 ns BEFORE "extPCICLK" ;
+NET "extPCI_stop" OFFSET = OUT 11 ns AFTER "extPCICLK" ;
+#INST "TRDY.PAD" TNM = "PCI_CTRL"
+#NET "extPCI_idsel" OFFSET = IN 7 ns BEFORE "extPCICLK" ;
+NET "extPCICLK" TNM_NET = "extPCICLK";
+
+INST "extPCI_AD<6>" TNM = "extPCI_AD";
+INST "extPCI_AD<7>" TNM = "extPCI_AD";
+INST "extPCI_AD<8>" TNM = "extPCI_AD";
+INST "extPCI_AD<9>" TNM = "extPCI_AD";
+INST "extPCI_AD<10>" TNM = "extPCI_AD";
+INST "extPCI_AD<11>" TNM = "extPCI_AD";
+INST "extPCI_AD<12>" TNM = "extPCI_AD";
+INST "extPCI_AD<13>" TNM = "extPCI_AD";
+INST "extPCI_AD<14>" TNM = "extPCI_AD";
+INST "extPCI_AD<15>" TNM = "extPCI_AD";
+INST "extPCI_AD<20>" TNM = "extPCI_AD";
+INST "extPCI_AD<16>" TNM = "extPCI_AD";
+INST "extPCI_AD<21>" TNM = "extPCI_AD";
+INST "extPCI_AD<17>" TNM = "extPCI_AD";
+INST "extPCI_AD<22>" TNM = "extPCI_AD";
+INST "extPCI_AD<18>" TNM = "extPCI_AD";
+INST "extPCI_AD<23>" TNM = "extPCI_AD";
+INST "extPCI_AD<19>" TNM = "extPCI_AD";
+INST "extPCI_AD<24>" TNM = "extPCI_AD";
+INST "extPCI_AD<25>" TNM = "extPCI_AD";
+INST "extPCI_AD<30>" TNM = "extPCI_AD";
+INST "extPCI_AD<26>" TNM = "extPCI_AD";
+INST "extPCI_AD<31>" TNM = "extPCI_AD";
+INST "extPCI_AD<27>" TNM = "extPCI_AD";
+INST "extPCI_AD<28>" TNM = "extPCI_AD";
+INST "extPCI_AD<29>" TNM = "extPCI_AD";
+INST "extPCI_AD<0>" TNM = "extPCI_AD";
+INST "extPCI_AD<1>" TNM = "extPCI_AD";
+INST "extPCI_AD<2>" TNM = "extPCI_AD";
+INST "extPCI_AD<3>" TNM = "extPCI_AD";
+INST "extPCI_AD<4>" TNM = "extPCI_AD";
+INST "extPCI_AD<5>" TNM = "extPCI_AD";
+
+TIMEGRP "extPCI_AD" OFFSET = IN 7 ns BEFORE "extPCICLK";
+TIMEGRP "extPCI_AD" OFFSET = OUT 11 ns AFTER "extPCICLK";
+