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