The design example shows the master control logic required for the pci_mt32 MegaCore® function that is connected to a synchronous memory like altsyncram, and focuses on the master functionality.
The document assumes that the user is familiar with the PCI specifications and the PCI MegaCore function.
The sample master control logic handles the following target terminations:
Target disconnect with data
Target disconnect without data
If the transaction is terminated before the entire data is transmitted, the control logic will start a new PCI transaction and will transfer the remaining data. It also handles the master latency timeout condition.
Download the files used in this example
The use of this design is governed by, and subject to, the terms and conditions of the Altera Hardware Reference Design License Agreement.
Figure 1 shows the simplified block diagram of the master control logic. The transaction length, transaction direction, and the transaction address are provided by the input signals XFR_LENGTH, PCI_CMD[3:0, and PCI_ADDRESS. The following sections describe each of the blocks in more detail.
Figure 1. 32-bit Master Memory Control Logic
Master State Machine
The state machine generates control signals like lm_req32n and lm_rdyn. It also generates the various control signals needed to select the data driven on the l_adi and l_cbeni bus. As shown in Figure 2, the state machine has 7 states. The following section describes the states in the state machine in more detail.
Figure 2. Master State Machine
IDLE: This is the idle state. In this state, the state machine waits for the user to assert START. Upon receiving the START signal, the state machine will latch the PCI command provided by the user input signal PCI_CMD[3:0] and generates the wr_rdn signal. The next state is the REQUEST state.
REQUEST: In this state, the state machine will assert the lm_req32n signal and transition to the ADR_PHASE state.
ADR_PHASE: The state machine will remain in the ADR_PHASE state until it sees that the PCI MegaCore function has started the address phase (indicated by lm_tsr) on the PCI bus. Waiting in this state until it sees that the lm_tsr is asserted ensures that the PCI MegaCore function has assumed ownership of the bus and started the transaction.
DATA_PHASE: This is the data transfer phase. The signal data_sel is active in this state. The state machine remains in this state until it sees a falling edge of lm_tsr or lm_lastn is asserted. The falling edge of lm_tsr is indicated as cycle_end in the state diagram and is generated internally. The state machine will transition to the CHK_STATUS state if cycle_end is asserted. If lm_lastn is asserted before cycle_end is asserted, the state machine will transition to the DP_DONE state.
DP_DONE: This state indicates that the data phase is done on the local side (lm_lastn has been asserted). The state machine will remain in this state until cycle_end is asserted and then transition to the CHK_STATUS state.
CHK_STATUS: In this state, the state machine will check the status of the current transaction. If there was a master abort or target abort (indicated by fatal error), or if all of the data has been transferred (indicated by xfr_done), then the state machine transitions to the IDLE state. The signal fatal_error is generated by stat_reg (master abort) and stat_reg (target_abort). If fatal_error is active in this state, the signal abnormal_term is also generated. If there is a target disconnect, retry, or master latency time (indicated by the signal do_retry), the state machine transitions to the RETRY state. The signal do_retry is generated by looking at the signals lm_tsr (master latency timeout), lm_tsr (target retry), lm_tsr (target disconnect without data) and lm_tsr (target disconnect with data).
RETRY: The state machine transitions to the REQUEST state from this state. The local address counter is rolled back in this state.
PCI Address and Transfer Counters
The transfer counter keeps track of the number of transfers occurring on the PCI bus. The counter is loaded with the XFR_LENGTH at the beginning of a transaction. The counter is decremented whenever there is a successful transfer on the PCI bus (indicated by lm_tsr). The signal xfr_done indicates all the data has been transferred and is generated by decoding the value of the transfer counter.
In order to restart a transaction that was terminated because of a target disconnect or a master latency timeout, a counter is required to keep track of the PCI address. The logic of the counter (load and enable) is similar to the PCI transfer counter. Since the PCI address is a DWORD aligned address, the counter is incremented by four.
lm_lastn is an input to the PCI MegaCore function and indicates the end of the current PCI transaction to the MegaCore function. A PCI master indicates that it wants to end a transaction on the final data phase by deasserting framen and asserting irdyn. When the local side asserts lm_lastn, the MegaCore master interface deasserts framen as soon as possible and asserts irdyn. As a general guideline, lm_lastn should be asserted for a single clock-cycle, when the second last transfer is occurring on the PCI bus.
To detect that the second last transfer is occurring on the PCI side, a down counter is required. This example uses a down counter that keeps track of the number of transfers occurring on the local side. The counter is cleared when abnormal_term is active. The local transfer count is loaded with xfr_cnt when lm_req32n is active. The down counter is enabled by lm_dxfrn.
lm_lastn for PCI Writes
The signal lm_lastn for PCI writes can be generated when the value of the local transfer counter is one and there is a successful data transfer on the local side (lm_dxfrn ).
lm_lastn for PCI Reads
The generation of lm_lastn for master reads is little bit more complicated because:
- The transfer occurs on the PCI bus first, and
- The user logic can detect a successful PCI transfer only a clock cycle after it occurs.
So, lm_lastn logic for the case of PCI reads needs to “look-ahead” for the proper generation of lm_lastn. This can be done by considering three different scenarios of the transfer length:
- Single transfer
- 2 DWORD transfers
- Greater than 2 DWORD transfers
lm_lastn for a Single Transfer and 2 DWORDs PCI Reads
In order to detect that only a single transfer or a 2 DWORD transfer is required, the signal xfr_cnt has to be decoded at the beginning of the transaction. The signals xfr_one_word and xfr_two_words indicate whether a single transfer or a 2 DWORD transfer is required, and are generated by looking at the xfr_length when lm_req32n is asserted.
For a single transfer, lm_lastn is generated by looking at lm_tsr. For a 2 DWORD PCI read, lm_lastn is generated by looking at the rising edge of lm_tsr.
lm_lastn for Greater Than 2 DWORDs PCI Read
lm_lastn generation for the third case is generated when the local transfer counter has a value of three and there is a transfer on the local side (indicated by lm_dxfrn).
Local Address Counter and altsyncram Logic
The local address counter provides the address for the altsyncram memory. The local address is a simple counter that is loaded with the local address provided by the user (LOCAL_ADDRESS). The local address counter will need to have some kind of “undo” logic to roll back the counter when the transfer is terminated by a target termination or master latency timer expiration. The signal pipe indicates how many addresses the local address counter should be rolled back, and is an up/down counter that keeps track of how many DWORDs were read from the memory but not transferred on the PCI bus. When the master control state machine is in the RETRY state, the counter is rolled back. The actual address counter (mem_addr) is an up counter. For PCI writes, the address counter is enabled by lm_dxfrn and for reads, the counter is enabled by lm_ackn.
The memory write enable logic is enabled whenever lm_dxfrn is active. The data input to the altsyncram is connected to the signal l_dato[31:0]. Reading from the memory is a little bit more complicated because the target can insert wait states and the local logic must hold the data in this scenario. The clock enable (clken) signal to altsyncram ensures that the local logic will hold the data when the target inserts wait states.