Descrever o funcionamento de um fluxo de dados com pipeline;
Projetar o pipeline para o fluxo de dados estudado até agora.
O MIPS estudado até agora, chamado de single cycle (ciclo único), executa cada uma de suas instruções em um único ciclo de clock.
Porém, nem todas as instruções do MIPS precisam do mesmo tempo para serem executadas.
Por exemplo, a instrução jump utiliza somente os circuitos da etapa inicial do fluxo de dados, como pode ser visto abaixo.
Por outro lado, a instrução lw utiliza todas as etapas do fluxo de dados, como visto abaixo.
As instruções do tipo R, não utilizam o acesso à memória RAM e o seu tempo de execução está no intervalo entre jump e lw.
No MIPS de ciclo único, o período do clock deve ser definido pela instrução que demora mais tempo a ser executada, ou seja, a instrução com a maior latência - no caso, a instrução lw.
Isso provoca um disperdício de tempo de processamento nas instruções com menor latência (jump e tipo R), uma vez que elas terminam a execução em um período menor que lw e ficam esperando o próximo clock.
Vale lembrar que para o funcionamento correto do fluxo de dados, o program counter deve manter o endereço da instrução sendo executada até que a mesma seja concluída. Isso é necessário para que os sinais dentro do fluxo de dados fiquem estáveis, sem causar problemas de temporização, após o tempo de propagação das unidades funcionais e assim permaneçam até a próxima borda de subida do clock.
Em outras palavras, os sinais necessários para a correta execução da instrução, chamado de estado interno do processador, deve ser mantido até que a execução da instrução termine.
Para entender melhor, vamos analisar as etapas que fazem parte do fluxo de dados.
O MIPS de ciclo único pode ter seu fluxo de dados dividido em 5 etapas funcionais:
Instruction Fetch (IF): busca da próxima instrução, na memória de programa, a ser executada;
Instruction Decode (ID): decodifica a instrução (UC) e faz a leitura dos registradores utilizados pela instrução;
Execute (EX): executa a operação definida pela instrução. É sempre feita na ULA;
Memory Acess (MEM): lê a memória ou escreve o resultado da execução na memória RAM;
Write Back (WB): escreve o resultado da execução no banco de registradores.
Essa divisão mostra que o fluxo das instruções segue do program counter para a memória RAM, com somente duas exceções. Elas são o retorno do endereço, calculado pela instrução beq e jump, para atualizar program counter, e o retorno do dado a ser escrito no banco de registradores (a consequência disso será tratada em aulas posteriores).
Para simplificar a análise, consideremos que cada uma etapa dessas etapas possui o mesmo tempo de propagação (tp = 200 ps). Além disso, utilizaremos um diagrama simplificado para o fluxo de dados.
Nesse caso, o período do clock é de 1000 ps. Porém, se puder ser feita a separação da execução em cada etapa, poderíamos ter um período de clock de apenas 200 ps. Mas, para tanto, precisamos respeitar o estado interno para que a execução seja correta.
A solução é armazenar o estado interno de cada instrução em cada uma das etapas, fazendo com que a transferência de informação entre as etapas contenha a instrução e seu estado.
Utilizando essa divisão e isolando as etapas de execução, através de registradores que mantenham o estado necessário para a execução da instrução corrente durante aquela etapa, podemos resolver esse problema. Essa construção é conhecida como pipeline clássico e está no diagrama abaixo.

A grande vantagem é o ganho de desempenho. Para entender como o ganho acontece, podemos fazer a analogia com a execução de instruções em fluxos de dados diferentes e em paralelo.
O diagrama, abaixo, mostra a execução de 3 instruções lw em um fluxo de dados de ciclo único. Note que o indicado no fluxo de dados é o recurso sendo utilizado naquele período de clock.
Para a execução das 3 instruções teremos um tempo total de 15 clocks de 200 ps, ou seja, 3.000 ps.
Se executar-mos essa mesma sequência de instruções em um pipeline de 5 estágios, teremos um total de 1.400 ps, ou seja, 2,14 vezes mais rápido.
Como o pipeline possui 5 estágios e usamos somente 3 instruções, o ganho de desempenho não foi o maior possível. Porém, como o pipeline “cheio” e sendo alimentado continuamente por novas instruções, teremos um ganho maior (por volta de 5 vezes mais rápido). A tabela abaixo mostra essa situação.
| Instrução | ||||||||
|---|---|---|---|---|---|---|---|---|
| 1 | IF | ID | EX | MEM | WB | |||
| 2 | IF | ID | EX | MEM | WB | |||
| 3 | IF | ID | EX | MEM | WB | |||
| 4 | IF | ID | EX | MEM | ||||
| 5 | IF | ID | EX | |||||
| 6 | IF | ID | ||||||
| 7 | IF | |||||||
| clk | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
Para um primeiro rascunho do pipeline, vamos usar como base a divisão em 5 etapas do fluxo de dados do MIPS e adicionar os registradores nas fronteiras das etapas.
Para que o nome de cada registrador indique a sua posição, usaremos uma nomenclatura que indica as duas etapas envolvidas e a sequência de execução. Assim, o registrador entre a etapa de busca (IF) e a de decodificação (ID) será chamado de IF/ID. O próximo registrador, entre a decodificação e a execução (EX) será chamado de ID/EX e assim por diante.
Utilizando o esquema acima, simule a passagem da instrução lw por todas etapas do pipeline. Por exemplo, a primeira etapa da instrução lw seria representada como mostrado na figura abaixo. Nela, os blocos funcionais ativos estão em azul. Para os blocos coloridos pela metade, se o lado colorido for o direito, significa que o componente é lido nessa etapa. Se o lado colorido for o esquerdo, indica que nessa etapa ocorre uma escrita nesse componente.
A primeira etapa é a busca da nova instrução, com o incremento do PC e o acesso à memória de instruções.
A segunda etapa, recebe a instrução e faz a sua decodificação, com o acesso aos registradores necessários.
Solução:
A terceira etapa executa a operação definida pela instrução, nesse caso, uma soma.
Solução:
A quarta etapa faz o acesso de leitura na memória RAM, no endereço definido pela soma ocorrida na etapa anterior.
Solução:
A quinta, e última etapa, escreve o dado lido da memória RAM no banco de registradores (no endereço definido pela instrução).
Solução:
Houve algum problema?
Solução:
Como as duas etapas iniciais são iguais para todas instruções, podemos iniciar a verificação na terceira etapa.
Como a instrução lw, a terceira etapa da instrução sw executa a operação definida pela instrução, nesse caso, uma soma.
Solução:
A quarta etapa, do pipeline da instrução sw, deve fazer a escrita do conteúdo do registrador na posição da memória RAM.
Solução:
Como essa é uma instrução de escrita na memória RAM, a quinta etapa do pipeline não executa nada.
Solução:
Ainda falta verificar jump.
Para conferência, utilize o diagrama abaixo.
Solução:
Responder o quiz de participação, no blackboard, em:
Conteúdos > Participação > Aula_18_Quiz-P1
De posse do circuito verificado através de simulação manual, deve ser feita:
A implementação em VHDL;
O teste de funcionamento: