PCI Target Memory Example for PCI MegaCore Functions
This design example shows how to interface Altera’s PCI target MegaCore® functions to a synchronous memory similar to altsyncram, and assumes that the user is familiar with the PCI specifications and the functionality of the PCI MegaCore functions.
Download the files used in this example:
The following describes implementation for a 64-bit target interface. The implementation for 64-bit and 32-bit is almost identical except for the data path width. The 64-bit design example instantiates two 32-bit wide altsyncrams. For a 32-bit implementation only one instance of the 32-bit altsyncram is required. Figure 1 shows the implementation used in this design example.
Figure 1. 64-bit Target Memory Interface

View full image in new window
The following sections describe the various blocks in more detail.
Address Counter
During burst transfers (more than 1 transfer), the user logic must keep track of the address for the current transfer since only the starting address is supplied by the PCI bus and the PCI MegaCore. For the 32-bit implementation, the PCI addresses are always DWORD-aligned, and the lower 2 bits of the address are always ‘0’ and hence can be omitted. For the 64-bit implementation, the PCI address are always QWORD-aligned and the lower 3 bits of the address are always ‘0’ and hence can be ignored.
The address counter is loaded with the starting address (l_adro) at the start of a PCI transfer. The signal cycle_start is generated by the user logic and logic to indicate the start of a target transaction. This signal can be generated by detecting a falling edge of the signal lt_framen.
For writes the counter is enabled by lt_dxfrn and for reads the signal lt_ackn is used. The signal targ_wr_rdn indicates the direction of the transfer and is generated from the signal l_cmdo[0].
wire mem_wr_inc = (!lt_dxfrn & targ_wr_rdn );
wire mem_rd_inc = (!lt_ackn &!targ_wr_rdn );
wire mem_inc = (mem_wr_inc | mem_rd_inc) & !l_hdat_ackn
The signal l_hdat_ackn indicates that the high-DWORD is currently being transferred on the local side and is not required for a 32-bit only implementation.
The data steering logic is not required for a 32-bit only implementation. Special considerations are required for 32-bit PCI request to a 64-bit local side. During a 32-bit PCI target write to a 64-bit PCI MegaCore, the transfer width on the local side is 32-bits only and only the lower DWORD (l_dato[31:0]) is active. So the local side must add appropriate logic to steer this data when the high DWORD is being addressed. The signals l_hdat_ackn and l_ldat_ackn indicate whether the upper DWORD or lower DWORD is currently being transferred on the local side. The signal lt_tsr[7] indicates if a 64-bit transfer is in progress.
The following example shows the data steering logic and is the multiplexer in Figure 1.
wire [31:0] h_dword; // high DWORD write data
assign h_dword = (!lt_tsr[7] & !l_hdat_ackn) ? l_dato[31:0] : l_dato[63:32];
During a 32-bit PCI target read to a 64-bit local side, the transfer width is always 64-bits and both the DWORDs of the bus l_adi[63:0] are active
The signal lt_dxfrn indicates a successful transfer on the local bus. For writes this signal indicates that valid data is available on the l_dato bus. So the memory write enable signal is simply a logical and of the signals lt_dxfrn, targ_wr_rdn.
wire mem_wr_enable = !lt_dxfrn & targ_wr_rdn;
The data port of the memory can be now be mapped to the signal l_dato[31:0] and h_dword.
Special consideration is required for the case when the master inserts a wait state by de-asserting irdyn. The clock enable is required during PCI reads and will hold the data on the output of the memory when the master inserts a wait state.
wire clken = (mem_wr_enable | mem_rd_inc);
For more information about using this example in your project, visit the related links.
|