Conceitos diferentes:
Um dos elementos fundamentais para que um processador se caracterize como RISC é ter pelo menos um pipeline.
Pipeline corresponde à divisão do processamento de cada instrução por diferentes componentes do processador. Estes componentes denominam-se estágios ou andares de execução.
O conceito de processador RISC baseia-se na premissa de que será menos eficiente executar uma instrução complexa do que executar o conjunto de instruções simples equivalente.
Assim, os processadores RISC têm por objectivo simplificar o conjunto de instruções em diversas dimensões por forma a maximizar esta premissa.
Para isso, um processador RISC caracteriza-se por:
O processamento de uma instrução é composto pelo menos por cinco fases:
O resultado é um pipeline de cinco estágios:
Como o estágio de instruction decode (descodificação) não necessita de aceder à memória (recurso partilhado), pode ser realizado em simultâneo com a fase de operand fetch (que usa a memória). O resutlado é um pipeline com 4 estágios.
Esta corresponde a uma abordagem minimalista e original, mas hoje em dia os pipeline não se limitam a 4 ou cinco estágios, mas podem chegar a 20 ou 30 estágios (Intel Pentium 4).
O princípio operacional dum pipeline é que podem estar em processamento várias instruções em simultâneo, pois cada um dos estágios é logicamente independente dos outros.
O resultado é que em execução óptima, o processador executa até uma instrução por ciclo de relógio, mesmo que cada instrução demore mais do que um ciclo de relógio a ser processada.
Portanto, teoricamente é possível executar uma instrução por cada ciclo de relógio.
No entanto, para que todo o conceito/processo funcione é necessário que determinadas restrições se verifiquem. Nomeadamente, é prioritário que todas as instruções permaneçam em cada estágio o mesmo tempo, para que:
Porque o processamento é diferente de estágio para estágio, para que o processo ocorra num único ciclo de relógio é necessário analisar o problema a resolver e encontrar soluções convenientes.
Problema:
Solução:
Problema:
Solução:
Problema:
Solução:
Problema:
Solução:
Problema:
Solução:
Portanto, é fundamental que sejam observadas as seguintes restrições:
No entanto, este conceito de processamento tem alguns problemas, motivados pelo facto de estarem em processamento várias instruções em simultâneo.
São identificados dois tipos de problemas:
A falta de operandos ocorre quando o resultado de uma instrução é usado na instrução da seguinte. Como o resultado da primeira instrução só se torna efectivo (write back) quando a seguinte já está a executar (execution), então os valores dos operandos da segunda instrução não estão correctos.
Considere-se o código seguinte:
mov ax, var1 mov bx, var2 add ax, bx instr4
que corresponde à seguinte representação de execução:
No estágio de execução da instrução add ax, bx, o valor de bx não é o correcto, pois a instrução anterior (mov bx, var2) ainda não escreveu o valor no registo bx.
Existem duas soluções possíveis:
A solução de “forwarding” corresponde a fazer o valor passar directamente para o andar de execução sem passar pelos registos.
A solução de “interlocking” corresponde a fazer parar a instrução seguinte até que o valor correcto dos operandos esteja disponível. Assim, o exemplo anterior teria a seguinte execução:
A solução por software implica um de dois estratagemas:
Quando uma instrução de salto (branch) está a ser executada, já seguinte também esta a ser executada. Mas a instrução a executar a seguir é dependente do resultado da instrução de branch, pelo que não é possível antes disso determinar qual a instrução seguinte.
Considere o exemplo seguinte:
inicio: mov cx, var1 mov dx, var2 mov ax, var3 mov bx, var4 % calcula o menor de dois valores e coloca em ax cmp ax, bx jle fimteste bxmenor: mov ax, bx fimteste: add cx, ax sub dx, ax
A execução corresponde ao modelo seguinte, considerando que o processador tem o mecanismo de “forwarding”:
Algumas instruções irão portanto ser processadas sem que haja garantias de que devam ser executadas. No caso de não deverem ocorre uma “bubble”. É o caso das instruções mov ax, bx (corresponde a colocar em ax o menor valor entre ax e bx) e add cx, ax (corresponde ao processo a seguir ao cálculo do menor valor). Ambas irão ser iniciadas independentemente do resultado da instrução “jle fimteste”.
Em função do resultado da instrução jle fimteste, duas hipóteses existem:
Os efeitos do processamento duma bubble têm de ser desfeitos, o que causa complicações à gestão do pipeline. Esta não é normalmente uma solução aceitável sob o ponto de vista do micro código, pelo que é evitada.
O ponto de partida da solução é o denominado “branch delay slot”. Um branch delay slot corresponde a um ciclo de relógio (slot) em que não é iniciada uma nova instrução por causa dum branch condicional. No caso dos processadores com pipelines de 4 estágios, sempre que ocorrer um branch condicional, também ocorem 2 branch delay slots.
Existem várias potenciais soluções:
No caso do exemplo anterior, seria possível definir uma instrução de “branch and execute” que executasse as instruções mov cx, var1 e mov dx, var2 nos branch delays slots observados. Estas instruções podem ser usadas pois não provocam dependências nas seguintes (mov ax, var3 e mov bx, var4) pois os seus resultados só vão ser usados em add cx, ax.
Portanto, o “branch and execute” corresponde em muitas situações a uma reordenação de instruções sem a necessidade de termos dois saltos.
Originalmente a arquitectura Alpha é caracterizada por:
Outras características tão ou mais importantes:
Pipeline com muitos estágios.
Quando existe mais do que uma unidade de execução no processador.
Normalmente a existência de mais do que uma unidade de execução está associada a processadores RISC (com pipeline), mas o número de unidades de execução é independente do número de pipelines.
Através do historial de instruções, determinar qual o caminho mais provável que o teste+salto irá tomar.
Ordenar/Executar as instrucões em função do resultado do branch prediction.
mov ax,var1 mov bx,var2 add ax,bx ; as instruções seguintes não dependem das anteriores ; portanto podem ser executadas fora da ordem mov cx,var4 mov dx,var5 add cx,dx mov var6,cx
mov ax,var1 mov bx,var2 add ax,bx mov var3,ax ; as instruções seguintes não dependem das anteriores ; mas estão a usar os mesmos registos se usarmos um mecanismo de “register renaming” então as ; instruções usarão outros registos e já serão executadas “fora da ordem” mov ax,var4 mov bx,var5 add ax,bx mov var6,ax
Local de reserva dos resultados das instruções, antes de serem colocados ordenadamente segundo o programa original nas suas localizações definitivas.
Também denominadas filas de espera de instruções.