Instrução SLT no MIPS - Set on Less Than - Embarcados
{"vars":{{"visitorLoginState":"logged-out","visitorType":"visitor-logged-out","pageTitle":"Instrução SLT no MIPS - Set on Less Than - Embarcados","pagePostType":"post","pagePostType2":"single-post","pageCategory":["software"],"pageAttributes":["firmware","iniciante"],"pagePostAuthor":"Elaine Cecília Gatto","pagePostDate":"02\/06\/2017","pagePostDateYear":"2017","pagePostDateMonth":"06","pagePostDateDay":"02"}} }
Oi pessoal! Tudo bem com todos? Conseguiram resolver os exercícios que eu deixei no último artigo? Bom, quem conseguiu, parabéns! Quem não conseguiu, hoje vou explicar uma instrução nova que irá ajudar na resolução desses exercícios. Não se esqueçam de verificar os artigos anteriores para conseguir acompanhar o artigo de hoje, beleza? Bora então?
A Instrução SLT
SLT significa Set on less Than, ao pé da letra seria algo como comparar menor que, então essa instrução será muito utilizada em comparações entre registradores, para identificar quem tem o maior ou menor valor. A função desta instrução é comparar dois valores de dois registradores diferentes e atribuir o valor 1 a um terceiro registrador se o valor do primeiro registrador for menor que o valor do segundo registrador. Caso contrário, atribuir zero. A sintaxe é:
SLT registrador_temporário, registrador1, registrador2
O formato da instrução é:
Código da Operação Registrador Temporário Registrador a ser comparado 2 Registrador a ser comparado 1 não usado código da operação aritmética
Vamos supor a seguinte instrução MIPS:
SLT $t0, $s1, $s2
$st0 = $s1 < $s2
O registrador temporário $t1 armazena o resultado da avaliação da expressão $s1 < $s2. Se for verdade que $s1 é menor que $s2, então, é atribuído ao registrador temporário o valor 1. Agora se o resultado da comparação entre os dois registradores for FALSO, ou seja, $s1 NÃO é menor que $s2, então, é atribuído ao registrador temporário o valor 0. O registrador temporário será utilizado por outra instrução, para realizar outra tarefa.
Considere o seguinte código em C:
if ( i < j ) a = b + c; else a = b – c;
Vamos fazer a compilação desse trecho de código em C para MIPS, seguindo o nosso roteiro padrão:
Linguagem de Montagem;
Linguagem de Máquina;
Representação e;
Código de Máquina.
Considere a = $s0, b = $s1, c = $s2, i = $s3, j = $s4.
a) Linguagem de Montagem
linha código
1 slt $t0, $s3, $s4
2 bne $t0, $zero, ELSE
3 add $s0, $s1, $s2 #a = b + c; (se $t0 <> 0)
4 j Exit #desvia para exit
5 ELSE: sub $s0, $s3, $s4 #a = b – c; (se $t0 = 0)
6 Exit:
Vamos entender o que acontece aqui. A Figura 1 apresenta o Fluxograma da instrução SLT. Para codificar em assembly mips if(i<j), primeiro é feita a comparação entre os registradores $s3 e $s4. Se a resposta for verdadeira, registrador $t0 receberá o valor 1. Se a resposta for falsa, então o registrador $t0 receberá o valor 0. A partir daí, o fluxograma segue para uma próxima avaliação, que será a instrução BEQ (branch if equal – desvie se igual).
Figura 1: Fluxograma de SLT.
A Figura 2 mostra o que acontece depois de se realizar esta comparação com SLT, isto é, o que a instrução BEQ deve fazer. Quando entra no ELSE? Quando o valor de i for menor que o valor de j. Portanto, para entrar no ELSE o valor de $t0 deve ser zero. Assim, quando $t0 = 0 entra no ELSE, caso contrário, executa o que está no IF. Por isso usamos a instrução BEQ pois ela vai desvia se os valores forem iguais, então, desviará quando $t0 = 0.
Figura : BEQ após execução da SLT
b) Linguagem de Máquina
slt $8, $19, $20
bne $8, $zero, ELSE
add $17, $18, $16
ELSE: sub $19, $20, $16
c) Representação
Agora vamos entender algo importante sobre os valores que devem ser inseridos no lugar dos labeLs ELSE e EXIT. Sabemos que o endereço 80004 pula para o endereço 80016, que é a nossa quinta linha de código, ou seja, o ELSE.
Precisamos lembrar que as instruções MIPS possuem endereços em bytes, de modo que os endereços das palavras sequenciais diferem em 4 bytes. Começamos esse bloco de comando no endereço 80000 e terminamos no endereço 80020 (exit).
Cada instrução está inserida no seu endereço correspondente que difere em quatro bytes. O cálculo que devemos fazer deve considerar o endereço SEGUINTE e NÃO o endereço atual da instrução.
Assim, a instrução BEQ, na segunda linha, acrescenta duas palavras, ou oito bytes, ao endereço da instrução SEGUINTE, especificando o destino do desvio em relação à instrução seguinte, e não em relação à instrução de desvio.
O endereço da instrução seguinte é 80008. Agora, veja que curioso, se você fizer 80016 – 80008, tem-se como resultado o número 8, isto é, oito bytes, o que significa que devemos "pular" duas posições na memória, portanto, o número 2 é quem deve ir no campo endereço da instrução BEQ. Se você fizer 80008 + 8, o resultado será 80016, que é exatamente o endereço para onde queremos ir.
Ainda está difícil de entender? Vou tentar simplificar, veja como a tabela deve ficar:
O número 2 é o número de instruções de distância para se desviar até ELSE. O número 1 é o número de instruções de distância para se desviar até EXIT. Abstraindo, podemos resumir o cálculo MANUAL em duas fases:
a) Número de Instruções de Distância do Desvio
Qtde de bytes = endereço de memória de desvio – endereço de memória seguinte
Qtde de bytes = 80016 – 80008 = 8 bytes => 2 instruções de distância
Qtde de byte = 80020 – 80016 = 4 bytes => 1 instrução de distância
b) Cálculo do endereço de desvio
endereço desejado = endereço seguinte ao atual + quantidade de bytes
endereço desejado = 80008 + 8 = 80016
endereço desejado = 80016 + 4 = 80020
É claro que os compiladores fazem esse cálculo de forma automática, aqui estou mostrando pra vocês algo bem manual, no sentido de aprendizagem didática. Mas, no geral, o cálculo automático é feito usando o PC (Contador de Programa), que contém o valor da instrução corrente. O endereço relativo ao PC é o endereço relativo à instrução seguinte, isto é:
PC = PC + 4.
(PC = Endereço Atual + 4 bytes)
Assim, EXIT seria calculado como o conteúdo do registrador mais o campo do endereço, o qual é calculado pela própria instrução de desvio condicional. Portanto, a instrução de desvio poderia calcular algo como:
Contador de Programa = Contador de Programa + Endereço de Desvio.
Vale ressaltar aqui que os desvios condicionais tendem a desviar para a instrução mais próxima e quase metade de todos os desvios condicionais é para endereços situados a menos de 16 instruções (de "distância") da origem do desvio. Se você ainda não conseguiu entender, não se preocupe! Voltarei a falar sobre endereçamento, especificamente sobre eles, então não se preocupe tanto por hora.
d) Código de Máquina
‭10 011‬
10 100‬
‭101 010‬
‭0000 0000 0000 0010
‭10 001‬
‭10 010‬
10 000‬
‭100 000‬
0000 0000 0000 0000 0000 0000 01
10 011‬
‭10 000‬
‭100 010‬
Agora que vocês já conhecem essa instrução, que tal refazer alguns dos exercícios apresentados nos artigos anteriores e verificar o resultado? Para concluir, saliento que a arquitetura MIPS não inclui uma instrução "desvie se menor que".
Uma instrução como esta fugiria do princípio de simplicidade de equipamento proposta por Von Neuman, além de que, ela também poderia esticar o tempo do ciclo de clock, ou ainda exigiria mais ciclos de clock.
Assim, duas instruções rápidas são mais úteis do que várias instruções mais complexas. Compiladores MIPS utilizam as instruções SLT, SLTI, BEQ, BNE e o valor fixo ZERO (registrador $zero) para criar todas as condições de operações relacionais: igual, diferente, menor que, maior que, menor ou igual, maior que e maior ou igual.
Fiquem atentos, nos próximos artigos falarei sobre como implementar operações lógicas, o uso de valores imediatos, números com e sem sinal, e outras operações matemáticas básicas.