Macroprogramacao
-
Upload
marcelle-guine -
Category
Documents
-
view
412 -
download
0
Transcript of Macroprogramacao
MacroprogramaçãoMacroprogramação Vimos que existem milhares de possibilidades de
microinstruções diferentes Surge a necessidade de haver instruções em um
nível mais alto, para consequentemente reduzir o conjunto de instruções de forma significativa
Veremos no slide seguinte uma tabela, mais uma vez do livro Organização Estruturada de Computadores, com todas as macroinstruções da nossa máquina e suas descrições
Repare como diminuímos de mais de 2 mil para menos de 25 instruções 1
2
Antes de entender melhor a tabela, é importante ressaltar que seus bits não devem nunca ser confundidos com os bits das microinstruções! Até porque microinstruções são formadas por 32 bits, enquanto as macro possuem 16 apenas
Dito isto, perceba que da 1ª até a 15ª instrução, nunca se repete uma combinação para os 4 primeiros bits. Isto quer dizer que é possível identificar instruções que não comecem por 1111 apenas pelos 4 primeiros bits
Porém, quando a instrução começa por 1111, é necessário analisar os bits seguintes
3
Diferentemente das microinstruções, que tinham um número fixo para OPCODE e outro para os operandos, a parte de OPCODE varia nas macro
A instrução LODD, por exemplo, possui 4 bits de operação, 0000, enquanto todos os outros representam seu operando. Já as instruções que começam por 1111 precisam de mais bits OPCODE para que possam ser diferenciadas entre si
4
Para ilustrar como é feita a identificação das macroinstruções, precisamos primeiro tornar aqueles nossos 16 registradores um pouco mais complexos
Além de PC, IR e AC, precisamos de mais registradores com funções especiais para que seja possível implementar um microprograma que interprete nossas macroinstruções corretamente
Mais uma vez, trabalharemos em cima de uma figura do livro Organizações Estruturadas de Computadores, que mostra os registradores adequadamente nomeados
5
O registrador SP armazena o endereço do topo da pilha
TIR armazena uma cópia temporária da macroinstrução que está sendo executada, ou seja, uma cópia de IR. É usado para decodificar o OPCODE
Os 3 registradores que seguem contém as constantes 0, +1 e -1
AMASK contém a chamada máscara de endereços e é usado para separar bits OPCODE dos bits de endereço, através da operação AND do seu conteúdo com a macroinstrução da qual se quer separar os bits
SMASK é útil nas instruções INSP e DESP, que contém 8 bits de operandos, pois a operação AND de seu conteúdo com a macroinstrução isolará esses 8 bits
Os demais registradores permanecem sem funções específicas 6
É preciso convencionar os nomes de algumas operações feitas em microinstruções
Para as operações da ULA, utilizaremos a + b para soma, band(a, b) para AND, a para retornar a própria entrada e inv(a) para retornar o inverso do primeiro operando
Para operações do deslocador: lshift(a) desloca a entrada 1 bit para a esquerda, e rshift(a) faz o oposto
Desvios condicionais serão representados por if b then goto addr, que significa: se o bit b for 1, vá para o endereço addr
No nosso microprograma, b será N ou Z, os dois bits da ULA que indicam se o resultado foi menor que 0 ou igual a 0, respectivamente 7
Veja a seguir quais valores cada conjunto de bits assume no MIR para os seguintes exemplos de microinstruções, em uma nova tabela do livro:
Dito tudo isso, podemos ver um microprograma que interpreta macroinstruções 8
9
O microprograma começa com um loop principal, que só termina quando acabar o macroprograma, isto é, quando não mais houver macroinstruções a serem interpretadas
Na linha 0, o MAR recebe o conteúdo de PC, que é o endereço da macroinstrução a ser interpretada. Também nesta linha, RD é ativado, para que a macroinstrução desejada comece a ser lida na memória a partir do endereço do MAR
Na linha 1, o microprograma aproveita para incrementar o conteúdo de PC, já que isso alguma hora teria que acontecer. Se isto não fosse feito, a linha 1 seria desperdiçada, porque a macroinstrução ainda não chegou até o MBR. Pelo mesmo motivo, RD continua ativado, pois ainda estamos lendo a macroinstrução na memória 10
Na linha 2, a macroinstrução em MBR é salva em IR. Aqui ainda há tempo para testar o primeiro bit da instrução, da esquerda para a direita: se este não for 0, já sabemos que a macroinstrução não é nenhuma das 8 primeiras da nossa tabela, então podemos ir para a linha 28 e testar o segundo bit
11
Tanto na linha 28 quanto na linha 3, repare que o teste do desvio condicional é exatamente o mesmo: tir := lshift(ir + ir);
Não é uma percepção trivial à primeira vista, mas o que acontece nesse teste é o deslocamento de dois bits à esquerda do conteúdo de IR
Recordando, deslocar um bit à esquerda em um número binário é o mesmo que multiplicar o seu valor por 2. Fazer ir + ir é equivalente a fazer 2 * ir, ou seja, deslocar um bit à esquerda de ir. Fazer lshift(2 * ir) então é o mesmo que deslocar 2 bits
Porém, lembre-se de que os testes são feitos sempre em função dos bits N e Z liberados pela ULA 12
Vamos voltar a focar nas primeiras linhas do microprograma. Na linha 3 (tir := lshift(ir + ir); if n then goto 19;), a interpretação irá para a linha 19 caso o bit N da saída da ULA seja 1
Isto quer dizer que o teste é feito em cima da instrução vinda de IR deslocada um bit à esquerda, pois o segundo deslocamento à esquerda (feito por lshift) é feito somente no deslocador, e não mais na ULA
Caso N tenha sido 0, passamos à linha 4 (tir := lshift(tir); if n then goto 11;). Aqui, o registrador TIR receberá seu próprio conteúdo deslocado em um bit à esquerda 13
Só que este deslocamento é novamente feito por lshift, e opera em cima do próprio conteúdo de TIR. Isso significa que a ULA receberá tir como um dos operandos e retornará ele mesmo – lembrando que tir já é o conteúdo de IR deslocado 2 bits à esquerda, por causa do que aconteceu na linha 3
Então, se na linha 3 testamos o segundo bit da instrução, na linha 4 testa-se o terceiro, e só depois desse teste o conteúdo de tir é novamente deslocado (lshift(tir))
Na linha 5 (alu := tir; if n then goto 9;), alu é uma pseudovariável que representa que o conteúdo de TIR apenas passará pela ULA para que seja testado seu primeiro bit (4º da instrução original) 14
Na linha 5, se o bit testado for 1, significa que o OPCODE da instrução é 0001, e STOD é a única macroinstrução cujo início é 0001. Por isso desviamos para a linha 9, linha onde STOD é executada em microinstruções
Se o bit testado for 0, o OPCODE é 0000, então basta prosseguir para a linha seguinte, que é onde LODD é executada
Esse processo teste-desvio-execução é a base do microprograma que interpreta macroinstruções
Acompanhe a seguir um trecho, bastante simples, de um programa qualquer
15
se (i ≤ j) faça // ‘i’ e ‘j’ são variáveis quaisquer
m = a[i*2] // ‘a’ é um vetor e ‘m’ uma variável // qualquer
fim se
Vamos expressar este algoritmo em nível demacroprogramação, e depois em microinstruções, para enfim nos despedirmosda nossa máquina-exemplo
16
17
Macroprograma Serão realizadas 4 operações nesse algoritmo: i ≤ j? i * 2 buscar valor em a[i * 2] m := a[i * 2]
Testar se i ≤ j é o mesmo que testar se i - j ≤ 0 Atenção: ‘i’ e ‘j’ são variáveis globais
18
Macroprograma Serão realizadas 4 operações nesse algoritmo: i ≤ j? i * 2 buscar valor em a[i * 2] m := a[i * 2]
Testar se i ≤ j é o mesmo que testar se i - j ≤ 0 Atenção: ‘i’ e ‘j’ são variáveis globais Com a instrução LODD passando j (entenda as variáveis passadas no macroprograma como o endereço onde essas variáveis estão, e não seus respectivos valores), armazenamos no registrador AC o valor contido no endereço passado
LODD j
19
Macroprograma Serão realizadas 4 operações nesse algoritmo: i ≤ j? i * 2 buscar valor em a[i * 2] m := a[i * 2]
Testar se i ≤ j é o mesmo que testar se i - j ≤ 0 Atenção: ‘i’ e ‘j’ são variáveis globais Com a instrução LODD passando j (entenda as variáveis passadas no macroprograma como o endereço onde essas variáveis estão, e não seus respectivos valores), armazenamos no registrador AC o valor contido no endereço passado
LODD j
Precisamos agora subtrair do valor de i. Com a instrução SUBD, o resultado já será armazenado em AC
SUBD i
20
Macroprograma Serão realizadas 4 operações nesse algoritmo: i ≤ j? i * 2 buscar valor em a[i * 2] m := a[i * 2]
Testar se i ≤ j é o mesmo que testar se i - j ≤ 0 Atenção: ‘i’ e ‘j’ são variáveis globais Com a instrução LODD passando j (entenda as variáveis passadas no macroprograma como o endereço onde essas variáveis estão, e não seus respectivos valores), armazenamos no registrador AC o valor contido no endereço passado
LODD j
Precisamos agora subtrair do valor de i. Com a instrução SUBD, o resultado já será armazenado em AC
SUBD i
Hora de implementar o desvio condicional: caso o conteúdo de AC seja negativo (j > i), desviamos para o final do ‘se’ do algoritmo. Para isso, criaremos um label “saida”
JNEG saida
saida(continuaçãodo programa)
.
.
.
.
21
Macroprograma Agora, carregamos o endereço do primeiro elemento do vetor a no registrador AC. Se fizéssemos LODD a, teríamos o valor de a[0] no acumulador, e não é o que queremos
LODD jSUBD iJNEG saida
saida(continuaçãodo programa)
.
.
.
.
.
.
LOCO a
22
Macroprograma Agora, carregamos o endereço do primeiro elemento do vetor a no registrador AC. Se fizéssemos LODD a, teríamos o valor de a[0] no acumulador, e não é o que queremos
LODD jSUBD iJNEG saida
saida(continuaçãodo programa)
.
.
.
.
.
.
LOCO a Quisemos o endereço de a[0] porque assim podemos encontrar a[i * 2]. Já que i * 2 = i + i, fazemos 0 + i...
ADDD i
23
Macroprograma Agora, carregamos o endereço do primeiro elemento do vetor a no registrador AC. Se fizéssemos LODD a, teríamos o valor de a[0] no acumulador, e não é o que queremos
LODD jSUBD iJNEG saida
saida(continuaçãodo programa)
.
.
.
.
.
.
LOCO a Quisemos o endereço de a[0] porque assim podemos encontrar a[i * 2]. Já que i * 2 = i + i, fazemos 0 + i...
ADDD i
...+ i, e temos em AC o endereço correto do (i * 2)-ésimo elemento do vetor a
ADDD i
24
Macroprograma Agora, carregamos o endereço do primeiro elemento do vetor a no registrador AC. Se fizéssemos LODD a, teríamos o valor de a[0] no acumulador, e não é o que queremos
LODD jSUBD iJNEG saida
saida(continuaçãodo programa)
.
.
.
.
.
.
LOCO a Quisemos o endereço de a[0] porque assim podemos encontrar a[i * 2]. Já que i * 2 = i + i, fazemos 0 + i...
ADDD i
...+ i, e temos em AC o endereço correto do (i * 2)-ésimo elemento do vetor a
ADDD i
Aqui vem o problema: queremos fazer ac := m[ac], mas não temos uma instrução que o faça. Temos como fazer, porém, m[sp] := m[ac], isto é, colocar na pilha de execução o valor contido no endereço presente em AC
PSHI
25
Macroprograma Agora, carregamos o endereço do primeiro elemento do vetor a no registrador AC. Se fizéssemos LODD a, teríamos o valor de a[0] no acumulador, e não é o que queremos
LODD jSUBD iJNEG saida
saida(continuaçãodo programa)
.
.
.
.
.
.
LOCO a Quisemos o endereço de a[0] porque assim podemos encontrar a[i * 2]. Já que i * 2 = i + i, fazemos 0 + i...
ADDD i
...+ i, e temos em AC o endereço correto do (i * 2)-ésimo elemento do vetor a
ADDD i
Aqui vem o problema: queremos fazer ac := m[ac], mas não temos uma instrução que o faça. Temos como fazer, porém, m[sp] := m[ac], isto é, colocar na pilha de execução o valor contido no endereço presente em AC
PSHI
...e depois armazenar este valor em AC (ac := m[sp])
POP
26
Macroprograma Agora, carregamos o endereço do primeiro elemento do vetor a no registrador AC. Se fizéssemos LODD a, teríamos o valor de a[0] no acumulador, e não é o que queremos
LODD jSUBD iJNEG saida
saida(continuaçãodo programa)
.
.
.
.
.
.
LOCO a Quisemos o endereço de a[0] porque assim podemos encontrar a[i * 2]. Já que i * 2 = i + i, fazemos 0 + i...
ADDD i
...+ i, e temos em AC o endereço correto do (i * 2)-ésimo elemento do vetor a
ADDD i
Aqui vem o problema: queremos fazer ac := m[ac], mas não temos uma instrução que o faça. Temos como fazer, porém, m[sp] := m[ac], isto é, colocar na pilha de execução o valor contido no endereço presente em AC
PSHI
...e depois armazenar este valor em AC (ac := m[sp])
POP
Finalmente, armazenar o valor em AC no endereço da memória onde está a variável m
STOD m
Com o macroprograma e com o que vimos até aqui sobre microinstruções, fica fácil entender como é o nosso algoritmo em microprograma
Antes, precisamos apenas esclarecer como funciona a subtração
O oposto de um número x é -x, e a codificação do oposto de um número binário é o seu inverso + 1
Formalizando: x - y = x + (-y) = x + (y + 1) Lembre-se também: usaremos &v quando
quisermos o endereço de uma variável v
27
mar := &i; rd; //MAR recebe o endereço da variável ird; //esperando o valor de i chegar até MBRb := mbr; //B é um dos resgistradores sem função definidamar := &j; rd;ac := b + 1; rd; //armazenando i + 1 em AC. Falta somar com j a := inv(mbr); //valor de j chegou ao MBR. A recebe o inversoac := ac + a; if n goto faça; //se i + j + 1 < 0, não saia do algoritmoalu := ac; if z goto faça; //se essa soma for igual a 0, também não saiagoto saida;
faça b := lshift(b); //multiplicando por 2 o conteúdo de Bac := &a; //AC recebe o endereço de a[0]ac := ac + b; //AC recebe o endereço de a[i*2]mar := ac; rd; //lendo na memória o valor que está em a[i*2]rd;mar := &m; wr; //escreve na variável m o que acabou de ser lidowr;
saida ... //aqui está o que vem após o ‘fim se’ no programa
28
Há apenas uma última observação. Analise estas últimas linhas do microprograma anterior:
mar := ac; rd;rd;mar := &m; wr;wr;
Implicitamente, o que temos é:mar := ac; rd;rd;ac := mbr;mar := &m; wr;mbr := ac; wr;
O acumulador recebe o que foi lido da memória (valor em a[i*2]). Em seguida, indicamos que estamos visando o endereço da variável m para escrita, fazemos o MBR receber o valor em AC e escrevemos esse valor no endereço onde está m 29