Aula 19: Pipeline Hazards (estruturais e dados)

Resultados de aprendizagem esperados:

Até agora, temos o MIPS com pipeline conforme a figura abaixo. Ou seja, com as etapas divididas, conforme a lista abaixo, e os sinais de controle das instruções acompanhando cada instrução através do pipline.

Etapas funcionais do MIPS com pipeline:

  1. Instruction Fetch (IF): busca da próxima instrução, na memória de programa, a ser executada;

  2. Instruction Decode (ID): decodifica a instrução (UC) e faz a leitura dos registradores utilizados pela instrução;

  3. Execute (EX): executa a operação definida pela instrução. É sempre feita na ULA;

  4. Memory Acess (MEM): lê a memória ou escreve o resultado da execução na memória RAM;

  5. Write Back (WB): escreve o resultado da execução no banco de registradores.

Fluxo de Dados do MIPS DLX com Pipeline
Fluxo de Dados do MIPS DLX com Pipeline


Como temos, potencialmente, 5 instruções executadas ao mesmo tempo, pode ocorrer que alguma dessas instruções não possa ser executada no mesmo clock que as outras.

Esse problema é chamado de pipeline hazard e existem três tipos:

Execução no MIPS DLX com Pipeline
Execução no MIPS DLX com Pipeline


O conjunto de instruções do MIPS foi pensado para executar em um pipeline, como pode ser visto através de algumas de suas características:

O cuidado no projeto do conjunto de instruções permitiu evitar problemas estruturais durante a execução do pipeline. Foram evitadas duas situações:

Banco de Registradores do MIPS DLX
Banco de Registradores do MIPS DLX


Envolve o retorno do endereço, calculado pela instrução beq e jump, para atualizar program counter. Trateremos dele na próxima aula.


As dependências entre os dados, em um fluxo de execução no pipeline, são divididas em quatro tipos:

  1. RAR (Read After Read): Essa dependência não gera problemas pois só ocorrem leituras.
            add  R1, R2, R3
            sub  R5, R2, R4
  1. RAW (Read After Write): Chamada de dependência real. A instrução corrente depende do resultado de uma instrução anterior. Dependendo do tamanho do pipeline e da distância entre os dados, pode gerar problemas.
            add  R1, R2, R3
            sub  R5, R1, R4
  1. WAR (Write After Read): Chamada de anti-dependência. A instrução corrente depende de um valor que será alterado em seguida, ou seja, a ordem de execução não pode ser mudada.
            add  R1, R2, R3
            sub  R2, R5, R4
  1. WAW (Write After Write): Chamada de dependência de saída. O valor final de uma variável depende da ordem das instruções.
            add  R1, R2, R3
            sub  R1, R5, R4

Dependências do Tipo RAW

No caso da dependência do tiplo RAW, a execução de uma instrução depende do resultado de outra instrução que ainda não finalizou sua execução.

Por exemplo, no código abaixo temos a dependência RAW no registrador $s0:

    add $s0, $t0, $t1;

    sub $t2, $s0, $t3;

Que pode ser vista no diagrama de execução do pipeline:

Dependência entre add e sub
Dependência entre add e sub


O valor de $s0 ainda não terá seu valor calculado pelo add quando a instrução sub necessitar dele.

Para que o programa obtenha os valores corretos, teríamos que parar ou atrasar a instrução sub:

Chamamos esse sistema de parar a execução do pipeline, por alguns ciclos, de criar bolhas na execução.

Dependência entre add e sub
Dependência entre add e sub

Como o banco de registradores pode ser escrito e lido no mesmo ciclo de clock, podemos economizar um ciclo de clock.

Dependência entre add e sub considereando o funcionamento do Banco de Registradores
Dependência entre add e sub considereando o funcionamento do Banco de Registradores

Essa solução, chamada de stall, desperdiça tempo de processamento.

Outra opção, seria fazer uma análise durante a compilação do programa:

Caso essa solução não seja possível, o compilador deve adicionar instruções nop (não executam nenhuma operação) para criar as bolhas no pipeline:

    add $s0, $t0, $t1;
    nop;
    nop;
    sub $t2, $s0, $t3;

Soma Acumulativa

No caso de uma soma acumulativa, como a mostrada abaixo, existe algum problema?

    add $1,$1,$2
    add $1,$1,$3
    add $1,$1,$4
Dependência na Sequência de add
Dependência na Sequência de add


Temos um problema entre:

Dependência na Sequência de add
Dependência na Sequência de add


A Instrução load word

O caso da instrução lw, que é a mais longa e ocupa todas as etapas do pipeline, se houver uma carga seguida de uma instrução do tipo R, como mostrado abaixo, em qual clock a instrução sub pode iniciar a sua execução? Por que?

    lw $s0, 20($t1);
    sub $t2, $s0, $t3;
Dependência entre a Carga e o Uso
Dependência entre a Carga e o Uso
Load-Use hazard

Para resolver, é necessário a inserção de duas instruções nop, como mostrado abaixo:

Dependência entre a Carga e o Uso Resolvido com nops
Dependência entre a Carga e o Uso Resolvido com nops


Para todos os casos mostrados, será que não existe solução melhor do que inserir nops?


Essa técnica ajuda a mitigar o desperdício de tempo na execução de instruções dependentes.

Ela se baseia no fato de que, para obter dado desejado, não é necessário esperar a instrução atravessar todo o pipeline.

A partir do momento em que o dado foi computado, ele está na saída da ULA e a sua transferência pode ser feita através do próprio pipeline, como se existisse um atalho.

Em resumo, é a criação de um desvio interno ao pipeline.

Transferência de Dado já Calculado  para Etapas Anteriores do Pipeline
Transferência de Dado já Calculado
para Etapas Anteriores do Pipeline


Porém, como e em quais situações esse desvio deve ser ativado?



Detecção de Problemas com Dados

Para facilitar o entendimento, vamos padronizar a nomenclatura dos sinais. Iremos utilizar a seguinte notação:

        (nome do registrador do pipeline).sinal

Na figura abaixo, está o exemplo dos sinais Rs, Rt e Rd, logo após o registrador de borda entre a etapa ID e a etapa EX.

Identificação dos Sinais no Pipeline
Identificação dos Sinais no Pipeline


Agora, precisamos definir em quais estágios do pipeline podem existir dependências. Sabemos que, no caso do MIPS, a produção de dados é feita através do resultado de alguma operação ou do carregamento de um dado da memória.

Dessa forma, a fonte de novos dados está limitada a duas etapas do pipeline:

Etapas do Pipeline que Geram Dados
Etapas do Pipeline que Geram Dados


Por outro lado, o dado é consumido somente na entrada da ULA.

Etapa do Pipeline que Consome Dados
Etapa do Pipeline que Consome Dados


Como é necessário isolar o consumo da produção, a solução deverá ser parecida com o esquema abaixo:

Solução para o Forwarding no Pipeline
Solução para o Forwarding no Pipeline


Como o dado produzido sempre será armazenado em Rd e os dados consumidos sempre serão provenientes de Rs e Rt, podemos verificar a existência do hazard comparando-se os endereços de Rs e Rt:

Com o endereço de Rd, nas etapas seguintes:

Portanto, no caso de igualdade nos endereços, podemos interligar (usando um MUX) os dados desses pontos:

Forwarding no Pipeline
Forwarding no Pipeline


Como a entrada da ULA pode vir do circuito de extensão de sinal, precisaremos de outro MUX. Ele será controlado pelo sinal ALUSrc.

Forwarding no Pipeline
Forwarding no Pipeline


Os sinais envolvidos no controle do forward são os seguintes:


Usaremos a seguinte padronização para a seleção dos MUXES do forward:

Sinais de Seleção do MUX
Seleção do Mux Fonte Explicação
ForwardA=00 ID/EX Operando A (ULA) ← Banco Registradores.
ForwardA=10 EX/MEM Operando A (ULA) ← ALUresult ciclo anterior.
ForwardA=01 MEM/WB Operando A (ULA) ← Memória ou ALUresult (dois ciclos antes).
ForwardB=00 ID/EX Operando B (ULA) ← Banco Registradores.
ForwardB=10 EX/MEM Operando B (ULA) ← ALUresult ciclo anterior.
ForwardB=01 MEM/WB Operando B (ULA) ← Memória ou ALUresult (dois ciclos antes).

Responder o quiz de participação, no blackboard, em:

Conteúdos > Participação > Aula_19_Quiz-P1


Quais as condições gerais que esses sinais devem ter para que o forward seja ativado?

Solução:

Condições gerais:

  • Ser escrita no registrador Rd:

    • RegWrite = Ativo.
  • Uma das igualdades de endereços ser verdadeira:

    • EX/MEM.RegisterRd = ID/EX.RegisterRs;

    • EX/MEM.RegisterRd = ID/EX.RegisterRt;

    • MEM/WB.RegisterRd = ID/EX.RegisterRs;

    • MEM/WB.RegisterRd = ID/EX.RegisterRt.

  • O endereço de Rd:

    • Não pode ser o registrador ZERO (somente leitura).



Utilizando os sinais de seleção definidos anteriormente, como ficariam as equações de ativação dos pontos do forwardA e forwardB no caso de hazard em EX/MEM?



Como ficariam as equações de ativação dos pontos do forwardA e forwardB no caso de hazard em MEM/WB?



No caso de uma soma acumulativa, como a abaixo, essas equações funcionam?

    add $1,$1,$2
    add $1,$1,$3
    add $1,$1,$4 . . .

Solução:

Como temos um problema entre:

  • O resultado da instrução no estágio WB;

  • O resultado da instrução no estágio MEM;

  • O operando da instrução na no estágio EX.

Deve ser utilizado o valor da etapa MEM, por ser o mais atual.

Se o MEM/WB também estiver em conflito, optamos pelo EX/MEM.



Como ficam os sinais de controle, forwardA e forwardB, no caso da soma acumulativa?



O circuito para resolver os problemas de forwarding.

Solução:

Neste circuito é necessário adicionar o MUX referente à entrada do imediato com sinal estendido, como visto anteriormente.

Pipeline do MIPS DLX com Forward
Pipeline do MIPS DLX com Forward



Solução para o Load-Use Hazard

Considere o trecho de código abaixo, onde todas instruções depois do lw dependem do valor de $2 (resultado do lw).

        lw   $2, 20($1)
        and  $4, $2, $5
        or   $8, $2, $6
        add  $9, $4, $2
        slt  $1, $6, $7

Nesse caso, a carga, da instrução lw $2, 20($1), só estará disponível durante o quinto ciclo de clock, na saída do registrador MEM/WB.

Porém, ela é necessária no terceiro estágio da instrução seguinte, o and $4, $2, $5, que ocorre no quarto ciclo de clock.

Problema com a instrução lw
Problema com a instrução lw


Como não é possível retornar o valor que só estará disponível no quinto clock para o quarto clock, já que ele ainda não foi calculado durante o quarto clock, teremos que adicionar uma parada no pipeline.

Problema com a instrução lw
Problema com a instrução lw



Como só temos essa situação no caso do lw seguido por uma instrução do tipo R, qual seria a condição para fazer a parada o pipeline?

Solução:

A condição seria:

  • Leitura da memória;

  • E o destino da leitura é o mesmo registrador do estágio anterior.



Como seria a equação para essa situação?



E como criar a bolha?

Solução:

Paramos o pipeline da seguinte forma:

  • Congelando o valor no PC:

    • Desabilitando esse registrador.
  • Congelando o valor no Instruction Register (IF/ID):

    • Desabilitando esse registrador.
  • E desativando os pontos de controle:

    • No registrador ID/EX.



O circuito para resolver os problemas de forwarding e stall.

Solução:

Neste circuito é necessário adicionar o MUX referente à entrada do imediato com sinal estendido, como visto anteriormente.

Pipeline do MIPS DLX com Stall e Forward
Pipeline do MIPS DLX com Stall e Forward


De posse das equações, ou circuito, deve ser feita: