Na estrutura PCI original ("Convencional PCI") e no PCI-X, os dispositivos correspondiam a "slots", cada um com seus próprios conectores conectados ao mesmo barramento paralelo. Cada slot tinha um pino de identificação exclusivo que foi declarado durante a enumeração. A enumeração estava essencialmente perguntando (para cada slot): "Ei, há algo presente nesse slot?" O dispositivo respondeu direcionando dados para o barramento em resposta a esse sinal. Falta de resposta não significava nenhum dispositivo.
Um dispositivo também poderia ser uma "ponte", o que significava que ele formava um barramento subordinado. Esse barramento teria um ID separado (atribuído a partir do upstream) e teria seu próprio conjunto de slots que foram enumerados independentemente.
O PCI-Express (PCIe) é totalmente diferente. O PCIe não é realmente um barramento - como em um recurso compartilhado entre dispositivos; em vez disso, cada dispositivo tem sua própria conexão serial ponto a ponto individual com seu dispositivo upstream (e com qualquer dispositivo downstream - e se tiver dispositivos downstream, isso significa que também está funcionando como uma ponte). Pense no PCIe como uma LAN. Cada ponte é análoga a um comutador, que possui várias portas conectadas a outros dispositivos. Os outros dispositivos podem ser terminais ou outros comutadores (por exemplo, pontes PCIe).
O PCIe foi projetado de forma que sua estrutura conceitual e endereçamento (e, portanto, o comportamento fornecido ao software) sejam compatíveis com o PCI e o PCI-X. A implementação é completamente diferente. Na enumeração de dispositivos, por exemplo, como é ponto a ponto, a única pergunta que precisa ser determinada em cada ponto da enumeração é "alguma coisa aí?" Como cada dispositivo tem seu próprio conjunto independente de fios, os IDs do dispositivo são essencialmente todos codificados (portanto, cada ponte, incluindo o "complexo raiz" de nível superior, diz a cada dispositivo qual será o seu ID).
Em todos os casos, a parte "função" do barramento / dispositivo / função é tratada estritamente dentro do periférico. Por exemplo, um controlador NIC de porta dupla geralmente possui duas funções, uma para cada porta. Eles podem ser configurados e operados independentemente, mas o caminho de dados da CPU para a função é o mesmo para ambos.