Macroprogramacao

589 visualizações

Publicada em

0 comentários
0 gostaram
Estatísticas
Notas
  • Seja o primeiro a comentar

  • Seja a primeira pessoa a gostar disto

Sem downloads
Visualizações
Visualizações totais
589
No SlideShare
0
A partir de incorporações
0
Número de incorporações
5
Ações
Compartilhamentos
0
Downloads
5
Comentários
0
Gostaram
0
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Macroprogramacao

  1. 1. Macroprogramação <ul><li>Vimos que existem milhares de possibilidades de microinstruções diferentes </li></ul><ul><li>Surge a necessidade de haver instruções em um nível mais alto, para consequentemente reduzir o conjunto de instruções de forma significativa </li></ul><ul><li>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 </li></ul><ul><li>Repare como diminuímos de mais de 2 mil para menos de 25 instruções </li></ul>
  2. 2.
  3. 3. <ul><li>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 </li></ul><ul><li>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 </li></ul><ul><li>Porém, quando a instrução começa por 1111, é necessário analisar os bits seguintes </li></ul>
  4. 4. <ul><li>Diferentemente das microinstruções, que tinham um número fixo para OPCODE e outro para os operandos, a parte de OPCODE varia nas macro </li></ul><ul><li>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 </li></ul>
  5. 5. <ul><li>Para ilustrar como é feita a identificação das macroinstruções, precisamos primeiro tornar aqueles nossos 16 registradores um pouco mais complexos </li></ul><ul><li>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 </li></ul><ul><li>Mais uma vez, trabalharemos em cima de uma figura do livro Organizações Estruturadas de Computadores , que mostra os registradores adequadamente nomeados </li></ul>
  6. 6. <ul><li>O registrador SP armazena o endereço do topo da pilha </li></ul><ul><li>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 </li></ul><ul><li>Os 3 registradores que seguem contém as constantes 0, +1 e -1 </li></ul><ul><li>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 </li></ul><ul><li>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 </li></ul><ul><li>Os demais registradores permanecem sem funções específicas </li></ul>
  7. 7. <ul><li>É preciso convencionar os nomes de algumas operações feitas em microinstruções </li></ul><ul><li>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 </li></ul><ul><li>Para operações do deslocador: lshift(a) desloca a entrada 1 bit para a esquerda, e rshift(a) faz o oposto </li></ul><ul><li>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 </li></ul><ul><li>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 </li></ul>
  8. 8. <ul><li>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: </li></ul><ul><li>Dito tudo isso, podemos ver um microprograma que interpreta macroinstruções </li></ul>
  9. 9.
  10. 10. <ul><li>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 </li></ul><ul><li>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 </li></ul><ul><li>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 </li></ul>
  11. 11. <ul><li>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 </li></ul>
  12. 12. <ul><li>Tanto na linha 28 quanto na linha 3, repare que o teste do desvio condicional é exatamente o mesmo: tir := lshift(ir + ir); </li></ul><ul><li>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 </li></ul><ul><li>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 </li></ul><ul><li>Porém, lembre-se de que os testes são feitos sempre em função dos bits N e Z liberados pela ULA </li></ul>
  13. 13. <ul><li>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 </li></ul><ul><li>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 </li></ul><ul><li>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 </li></ul>
  14. 14. <ul><li>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 </li></ul><ul><li>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) ) </li></ul><ul><li>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) </li></ul>
  15. 15. <ul><li>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 </li></ul><ul><li>Se o bit testado for 0, o OPCODE é 0000, então basta prosseguir para a linha seguinte, que é onde LODD é executada </li></ul><ul><li>Esse processo teste-desvio-execução é a base do microprograma que interpreta macroinstruções </li></ul><ul><li>Acompanhe a seguir um trecho, bastante simples, de um programa qualquer </li></ul>
  16. 16. <ul><li>se (i ≤ j) faça // ‘i’ e ‘j’ são variáveis quaisquer </li></ul><ul><li>m = a[i*2] // ‘a’ é um vetor e ‘m’ uma variável // qualquer </li></ul><ul><li>fim se </li></ul><ul><li>Vamos expressar este algoritmo em nível de </li></ul><ul><li>macroprogramação, e depois em microinstruções, para enfim nos despedirmos </li></ul><ul><li>da nossa máquina-exemplo </li></ul>
  17. 17. Macroprograma <ul><li>Serão realizadas 4 operações nesse algoritmo: </li></ul><ul><ul><li>i ≤ j? </li></ul></ul><ul><ul><li>i * 2 </li></ul></ul><ul><ul><li>buscar valor em a[i * 2] </li></ul></ul><ul><ul><li>m := a[i * 2] </li></ul></ul><ul><li>Testar se i ≤ j é o mesmo que testar se i - j ≤ 0 </li></ul><ul><li>Atenção: ‘i’ e ‘j’ são variáveis globais </li></ul>
  18. 18. Macroprograma <ul><li>Serão realizadas 4 operações nesse algoritmo: </li></ul><ul><ul><li>i ≤ j? </li></ul></ul><ul><ul><li>i * 2 </li></ul></ul><ul><ul><li>buscar valor em a[i * 2] </li></ul></ul><ul><ul><li>m := a[i * 2] </li></ul></ul><ul><li>Testar se i ≤ j é o mesmo que testar se i - j ≤ 0 </li></ul><ul><li>Atenção: ‘i’ e ‘j’ são variáveis globais </li></ul><ul><li>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 </li></ul>LODD j
  19. 19. Macroprograma <ul><li>Serão realizadas 4 operações nesse algoritmo: </li></ul><ul><ul><li>i ≤ j? </li></ul></ul><ul><ul><li>i * 2 </li></ul></ul><ul><ul><li>buscar valor em a[i * 2] </li></ul></ul><ul><ul><li>m := a[i * 2] </li></ul></ul><ul><li>Testar se i ≤ j é o mesmo que testar se i - j ≤ 0 </li></ul><ul><li>Atenção: ‘i’ e ‘j’ são variáveis globais </li></ul><ul><li>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 </li></ul>LODD j <ul><li>Precisamos agora subtrair do valor de i. Com a instrução SUBD, o resultado já será armazenado em AC </li></ul>SUBD i
  20. 20. Macroprograma <ul><li>Serão realizadas 4 operações nesse algoritmo: </li></ul><ul><ul><li>i ≤ j? </li></ul></ul><ul><ul><li>i * 2 </li></ul></ul><ul><ul><li>buscar valor em a[i * 2] </li></ul></ul><ul><ul><li>m := a[i * 2] </li></ul></ul><ul><li>Testar se i ≤ j é o mesmo que testar se i - j ≤ 0 </li></ul><ul><li>Atenção: ‘i’ e ‘j’ são variáveis globais </li></ul><ul><li>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 </li></ul>LODD j <ul><li>Precisamos agora subtrair do valor de i. Com a instrução SUBD, o resultado já será armazenado em AC </li></ul>SUBD i <ul><li>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” </li></ul>JNEG saida saida (continuação do programa) . . . .
  21. 21. Macroprograma <ul><li>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 </li></ul>LODD j SUBD i JNEG saida saida (continuação do programa) . . . . . . LOCO a
  22. 22. Macroprograma <ul><li>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 </li></ul>LODD j SUBD i JNEG saida saida (continuação do programa) . . . . . . LOCO a <ul><li>Quisemos o endereço de a[0] porque assim podemos encontrar a[i * 2]. Já que i * 2 = i + i, fazemos 0 + i... </li></ul>ADDD i
  23. 23. Macroprograma <ul><li>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 </li></ul>LODD j SUBD i JNEG saida saida (continuação do programa) . . . . . . LOCO a <ul><li>Quisemos o endereço de a[0] porque assim podemos encontrar a[i * 2]. Já que i * 2 = i + i, fazemos 0 + i... </li></ul>ADDD i <ul><li>...+ i, e temos em AC o endereço correto do (i * 2)-ésimo elemento do vetor a </li></ul>ADDD i
  24. 24. Macroprograma <ul><li>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 </li></ul>LODD j SUBD i JNEG saida saida (continuação do programa) . . . . . . LOCO a <ul><li>Quisemos o endereço de a[0] porque assim podemos encontrar a[i * 2]. Já que i * 2 = i + i, fazemos 0 + i... </li></ul>ADDD i <ul><li>...+ i, e temos em AC o endereço correto do (i * 2)-ésimo elemento do vetor a </li></ul>ADDD i <ul><li>Aqui vem o problema: queremos fazer </li></ul><ul><li>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 </li></ul>PSHI
  25. 25. Macroprograma <ul><li>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 </li></ul>LODD j SUBD i JNEG saida saida (continuação do programa) . . . . . . LOCO a <ul><li>Quisemos o endereço de a[0] porque assim podemos encontrar a[i * 2]. Já que i * 2 = i + i, fazemos 0 + i... </li></ul>ADDD i <ul><li>...+ i, e temos em AC o endereço correto do (i * 2)-ésimo elemento do vetor a </li></ul>ADDD i <ul><li>Aqui vem o problema: queremos fazer </li></ul><ul><li>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 </li></ul>PSHI <ul><li>...e depois armazenar este valor em AC ( ac := m[sp] ) </li></ul>POP
  26. 26. Macroprograma <ul><li>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 </li></ul>LODD j SUBD i JNEG saida saida (continuação do programa) . . . . . . LOCO a <ul><li>Quisemos o endereço de a[0] porque assim podemos encontrar a[i * 2]. Já que i * 2 = i + i, fazemos 0 + i... </li></ul>ADDD i <ul><li>...+ i, e temos em AC o endereço correto do (i * 2)-ésimo elemento do vetor a </li></ul>ADDD i <ul><li>Aqui vem o problema: queremos fazer </li></ul><ul><li>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 </li></ul>PSHI <ul><li>...e depois armazenar este valor em AC ( ac := m[sp] ) </li></ul>POP <ul><li>Finalmente, armazenar o valor em AC no endereço da memória onde está a variável m </li></ul>STOD m
  27. 27. <ul><li>Com o macroprograma e com o que vimos até aqui sobre microinstruções, fica fácil entender como é o nosso algoritmo em microprograma </li></ul><ul><li>Antes, precisamos apenas esclarecer como funciona a subtração </li></ul><ul><li>O oposto de um número x é -x, e a codificação do oposto de um número binário é o seu inverso + 1 </li></ul><ul><li>Formalizando: x - y = x + (-y) = x + (y + 1) </li></ul><ul><li>Lembre-se também: usaremos &v quando quisermos o endereço de uma variável v </li></ul>
  28. 28. <ul><li>mar := &i; rd; //MAR recebe o endereço da variável i </li></ul><ul><li>rd; //esperando o valor de i chegar até MBR </li></ul><ul><li>b := mbr; //B é um dos resgistradores sem função definida </li></ul><ul><li>mar := &j; rd; </li></ul><ul><li>ac := b + 1; rd; //armazenando i + 1 em AC. Falta somar com j </li></ul><ul><li>a := inv(mbr); //valor de j chegou ao MBR. A recebe o inverso </li></ul><ul><li>ac := ac + a; if n goto faça; //se i + j + 1 < 0, não saia do algoritmo </li></ul><ul><li>alu := ac; if z goto faça; //se essa soma for igual a 0, também não saia </li></ul><ul><li>goto saida; </li></ul><ul><li>faça b := lshift(b); //multiplicando por 2 o conteúdo de B </li></ul><ul><li>ac := &a; //AC recebe o endereço de a[0] </li></ul><ul><li>ac := ac + b; //AC recebe o endereço de a[i*2] </li></ul><ul><li>mar := ac; rd; //lendo na memória o valor que está em a[i*2] </li></ul><ul><li>rd; </li></ul><ul><li>mar := &m; wr; //escreve na variável m o que acabou de ser lido </li></ul><ul><li>wr; </li></ul><ul><li>saida ... //aqui está o que vem após o ‘fim se’ no programa </li></ul>
  29. 29. <ul><li>Há apenas uma última observação. Analise estas últimas linhas do microprograma anterior: </li></ul><ul><li>mar := ac; rd; </li></ul><ul><li>rd; </li></ul><ul><li>mar := &m; wr; </li></ul><ul><li>wr; </li></ul><ul><li>Implicitamente, o que temos é: </li></ul><ul><li>mar := ac; rd; </li></ul><ul><li>rd; </li></ul><ul><li>ac := mbr; </li></ul><ul><li>mar := &m; wr; </li></ul><ul><li>mbr := ac; wr; </li></ul><ul><li>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 </li></ul>

×