Arquitectura de
Computadores
Curso: LMCC
Exame 2ª Chamada 99/02/13
Duração: 2h
Componente teórica ; Componente prática
I
Sugestões para resolução:
[_|_._._._._._._._|_._._._._._._._._._._._._._._._._._._._._._._] S E F
S = sinal - 1 bit
E = expoente - 8 bits - representado em excesso +127
F = fracção - 23 bits - valor absoluto, considerando a existência do bit escondido
com, Valor = (-1)S * (1.F) * 2E-127
| 17,125 | = 17 + 1/8 |
| = 24 + 20 + 2-3 | |
| = 10001,0012 | |
| = 1,00010012 * 24 | |
| -17,125 | = (-1) * 1,0001001 * 24 |
O número já se encontra na forma pretendida (-1)S * 1.F * 2E-127 com:
S = 1
F = 00010010000000000000
E = 4 (Como o expoente E é representado em excesso 127, o valor a colocar é 4+127
= 131 = 1000 00112
[1|10000011|00010010000000000000000] S E F
Agrupando os dígitos binários da direita para a esquerda em grupos de 4 facilmente se obtém a representação do mesmo número na base hexadecimal.
Em binário: 1100 0001 1000 1001 0000 0000 0000 00002
Em hexadecimal: 0xC1890000
i) Se é muito trabalhador mas não gosta de pensar, refaça todos os cálculos anteriores para o número 17,125.
ii) Se é pouco trabalhador mas mais esperto, troque o bit mais à esquerda passando de 1 a 0. Porquê?
Em binário: 0100 0001 1000 1001 0000 0000 0000 00002
Em hexadecimal: 0x41890000
II
Considere o seguinte programa escrito em assembly do MIPS
li $t1, 0x20080120
lw $t2, 4($t1)
subi $t3, $t2, 1
Sabendo que:
Registo $t1 corresponde a $9
Nas instruções lw e sw o campo que contém o endereço é o Rs
A palavra de 4 bytes, colocada em memória no endereço 0x20080124 tem o valor inicial de 1000.
Sugestões para resolução:
a)
li $t1, 0x20080120 => lui $t1, 0x2008
=> ori $t1, $t1, 0x0120
|
- Pseudo instrução. Substituir por instruções nativas MIPS. Há várias alternativas. Apresente outras. |
lw $t2, 4 ($t1) |
- Instrução nativa MIPS. |
subi $t3, $t2, 1 => addi $t3, $t2, -1 |
- Pseudo instrução. Substituir por instruções nativas MIPS. Há mais alternativas? Quais? |
O código anterior em que foram substituidas as pseudo-instruções por instruções nativas com resultado equivalente:
lui $t1, 0x2008 (I) [0x0f | 0 | 9 | 0x2008] ori $t1, $t1, 0x0120 (I) [0x0d | 9 | 9 | 0x0120] lw $t2, 4($t1) (I) [0x23 | 9 | 10 | 4] addi $t3, $t2, -1 (I) [0x08 | 10 | 11 | -1]
NOTA: Nºs negativos (no campo Imm16) são representados em complemento para 2.
Tendo em conta a dimensão dos campos no formato (I) [opcode (6) | Rs (5) | Rt (5) | Imm (16) ] vem em binário:
001111 00000 01001 0010 0000 0000 1000 = 0x3C092008 001101 00000 01001 0000 0001 0010 0000 = 0x34090120 100011 01001 01010 0000 0000 0000 0100 = 0x8D2A0004 001000 01010 01011 1111 1111 1111 1111 = 0x214BFFFF
b) Para cada instrução vá anotando os valores de cada um dos registos $t1, $t2 e $t3.
III
Considere o seguinte programa escrito em linguagem C. Codifique este mesmo programa em assembly do MIPS respeitando a convenção do MIPS para a utilização de registos. (Este exercício é parecido, mas não é o mesmo que saiu no exame)
struct alunos_t
{ char nome [ 10 ];
int idade;
} turma[3] = { { "João", 22 }, { "Anabela", 21 }, { "Manuel", 22 } };
void Calcula_Idade( struct alunos_t turma [], int dim )
{
int idade, i;
idade = turma[0].idade;
for ( i = 1; i < dim; i ++ )
if ( turma[i].idade < idade ) idade = turma[i].idade;
return idade;
}
void main()
{
int junior = Calcula_Idade( turma, 3 );
}
Análise do enunciado:
Depois da interpretação do enunciado em cima poderá verificar que o objectivo deste exercício é procurar a idade do aluno mais novo de uma qualquer turma (talvez para uma aposta, quem sabe...).
A turma é representada por um array de alunos e cada aluno representado por um record constituído pelo seu nome e idade. O algoritmo base assenta na função Calcula_Idade que vai empreender o "trabalho sujo" de vasculhar o enorme array (de 3 elementos) que é apresentado.
A resolução deste exercício apresenta diversos sub-problemas, como a declaração dos dados, a implementação da função Calcula_Idade e da função main, podendo cada um deles ser ainda mais dividido, como veremos adiante nos comentários do programa.
Sugestões para resolução:
.DATA # declaração dos dados
Os dados são declarados como uma sequência de dados simples (.ASCIIZ corresponde a declarar uma string terminada por zero, ver anexo C), já que o assembly do MIPS não suporta a declaração de estruturas de dados. Todos os elementos do array precisam, no entanto, de ter o mesmo tamanho. Assim, como o nome do aluno varia em tamanho, foi necessário introduzir um factor de alinhamento ao tamanho de record pretendido (com .SPACE).
turma: .asciiz "João" #turma[0]
.space 5
.word 22
.asciiz "Anabela" #turma[1]
.space 2
.word 21
.asciiz "Manuel" #turma[2]
.space 3
.word 22
.TEXT
calcula_idade: # int calcula_idade ( alunos_t turma[] => $a0,
# int dim => $a1 )
# salvaguarda de registos
# neste caso não são utilizados registos
# que seja necessário salvaguardar
# atribuição de variáveis locais
# int idade => $t0
# int i => $s1
lw $t0, 10($a0) # idade = turma[0].idade
li $s1, 1 # i = 1
ciclo: # for (i=1; i<dim; i++)
bge $s1, $a1, fim_ciclo
addi $a0, $a0, 14 # Note-se que aqui se preferiu considerar que
# o valor do apontador para o array é
# incrementado a cada iteração do ciclo,
# aproveitanto o facto de i ser sempre
# incrementado uma unidade (a que corresponde
# avançar registo com 14 bytes).
# Uma alternativa, menos eficiente mas mais
# genérica, seria recalcular a posição do
# elemento actual em cada iteração.
if:
# registo temporário
lw $t2, 10($a0) # turma[n].idade = $t2
bge $t2, $t0, fim_if # if ( turma[i].idade < idade )
move $t0, $t2 # idade = turma[i].idade;
fim_if:
b ciclo
fim_ciclo:
move $v0, $t0 # return idade;
# restaurar os registos
jr $ra
main: # void main()
addi $sp, $sp, -8 # salvaguardar os registos:
sw $s0, 0($sp) # Embora a função main seja iniciada pelo
# sistema, não deixa de ser uma função como
# outra qualquer, sendo, assim, necessário
# salvaguardar os registo seguros que utiliza.
sw $ra, 4($sp) # Como não é um procedimento folha, i.e.,
# invoca outras
# funções, é necessário salvaguardar o registo
# de retorno.
# int junior = $s0 (variáveis locais)
la $a0, turma # definir os parâmetros da função
li $a1, 3
jal calcula_idade # invocar a função
move $s0, $v0 # guardar resultados
addi $sp, $sp, 8 # restaurar os registos
lw $s0, 0($sp)
lw $ra, 4($sp)
jr $ra