Macroprogramacao

29
Macroprogramação Macroprogramaçã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

Transcript of Macroprogramacao

Page 1: 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

Page 2: Macroprogramacao

2

Page 3: Macroprogramacao

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

Page 4: Macroprogramacao

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

Page 5: Macroprogramacao

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

Page 6: Macroprogramacao

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

Page 7: Macroprogramacao

É 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

Page 8: Macroprogramacao

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

Page 9: Macroprogramacao

9

Page 10: Macroprogramacao

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

Page 11: Macroprogramacao

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

Page 12: Macroprogramacao

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

Page 13: Macroprogramacao

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

Page 14: Macroprogramacao

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

Page 15: Macroprogramacao

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

Page 16: Macroprogramacao

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

Page 17: Macroprogramacao

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

Page 18: Macroprogramacao

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

Page 19: Macroprogramacao

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

Page 20: Macroprogramacao

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)

.

.

.

.

Page 21: Macroprogramacao

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

Page 22: Macroprogramacao

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

Page 23: Macroprogramacao

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

Page 24: Macroprogramacao

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

Page 25: Macroprogramacao

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

Page 26: Macroprogramacao

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

Page 27: Macroprogramacao

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

Page 28: Macroprogramacao

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

Page 29: Macroprogramacao

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