A microarquitetura do exemplo é comandada por um microprograma para
implementar as instruções do nível convencional de MAC-1.
Chamamos tal microprograma de MIC-1. Cada microinstrução de
MIC-1 tem 32 bits. A não ser que o microprogramador (quem escreve o
microprograma) seja um masoquista, o seu trabalho pode ser facilitada
pelo uso de um micro-montador ou micro-assembler. O micro-assembler
converte cada instrução da linguagem do micro-assembler a uma
microinstrução. Assim o microprogramado final, resultado da
micro-montagem, é guardado no ``control store'' da
microarquitetura.
Uma instrução em micro-assembler, por exemplo, para somar AC e A e guardar o resultado em AC, poderia ser definida como abaixo, o que, entretanto, não é ainda muito agradável para o microprogramador.
Vamos usar uma linguagem de micro-assembler mais parecida com
linguagem de alto nível. Cada instrução, entretanto, ainda
corresponde a uma microinstrução. Assim, a instrução
exemplificada antes seria
ac:=ac+a
O registrador desejado pode aparecer no lado esquerdo do sinal de
atribuição ``:=''. A função soma () é indicada
pelo sinal ``+''. As demais funções da ALU (AND, A, NOT A),
correspondentes a =1, 2 e 3, são indicadas por
... := band (... , ...)
... := a
... := inv(a)
Para especificar os bits SH que controlam o ``shifter'', usamos as
funções lshift e rshift, como
tir:=lshift(tir+tir)
Essa instrução coloca tir no e , realiza a adição, desloca o resultado de 1 bit para esquerda, e finalmente guarda o resultado de volta a tir.
Desvio incondicional usa o comando goto; desvios condicionais podem
testar n ou z, correspondentes aos sinais de controle e gerados
pela ALU. Assim, podemos ter
if n then goto 27
Atribuição e desvio podem ocupar a mesma instrução, como
por exemplo,
ac:=ac+a; if z then goto 45
Temos uma pequena dificuldade, porém, se queremos testar um
registrador sem desejando fazer nenhuma atribuição. Por
exemplo, testar tir e desviar para 27 se negativo. Como vamos
especificar qual registrador queremos testar. Para isso, introduz-se
a pseudo-variável alu à qual pode-se atribuir um valor apenas para
indicar o conteúdo da ALU. A instrução
alu:=tir; if n then goto 27
significa passar tir pela ALU, o que vai gerar os sinais de e . O
resultado da ALU não é armazenado de volta à memória rascunho.
Assim é sempre 0 se alu é usado.
A Figura ilustra alguns exemplos de instruções de micro-assembler e suas microinstruções correspondentes.
Podemos agora colocar todos os pedaços juntos. As Figuras
e
mostram o microprograma MIC-1. Ele surpreendentemente tem apenas 79
linhas. O microprograma ocupa portanto 79 palavras do ``control
store'' da nossa microarquitetura.
Os nomes dos registradores da memória rascunho agora ficam
óbvios. PC, AC, SP são usados para guardar os 3 registradores de
MAC-1. IR é o registrador de instrução
(``macroinstrução'' do nível convencional) em
execução. TIR é uma cópia de IR, usada para decodificar o
código de operação da instrução. AMASK (address mask)
é uma máscara de endereço, 007777 (octal), usada para separar
os bits do endereço. SMASK (stack mask) é a máscara de pilha,
000377 (octal), usada para isolar um offset de 8 bits, usado para
acessar pilhas. Os outros 6 registradores, A, B, ..., até F, não
têm funções específicas e podem ser usados pelo
microprogromador como ele bem entender.
O microprograma tem um ``loop'' principal que busca, decodifica, e
executa instuções (macroinstruções, do nível
convencional) da memória principal. O loop principal começa na
linha 0, onde é buscada a macroinstrução de endereço
apontado por PC. Enquanto aguarda a chegada da instrução lida,
o microprograma incrementa PC de 1 e continua validando a linha .
Na linha 2, a instrução lida chega e é guardada em IR;
simultaneamente, os bit de ordem superior (bit 15) é testado. Se
tal bit é 1, o processo de decodificação prossegue na linha
28; caso contrário, continua a linha 3.
Suponhamos que a macroinstrução é LODD, na linha 3 é
testado o bit 14 e TIR é carregado com a instrução original
IR deslocada de 2 bits para esquerda. Tal deslocamento de 2 bits é
produzido pela soma de TIR+TIR e pelo ``shifter''. A linha 3 testa o
bit 14 da instrução pois os sinais e referem-se a
saída da ALU (IR+IR ou IR deslocada de 1 bit) e não do
``shifter''.
Todas as instruções que começam com 00 (bits 15 e 14)
chegam a linha 4 para ter seu bit 13 testado. As que começam com
000 continuam para linha 5 e as com 001 vão a linha 11. A linha 5
testa tir (bit 12 da instrução) mas não armazena nenhum
resultado de volta à memória rascunho (uso de alu e ENC=0).
Dependendo deste teste, temos LODD (linha 6) ou STOD (linha 9). Para
LODD, os 12 bits inferiores de IR especificam o endereço da
palavra a ser carregada no acumulador. Como o código de
operação LODD é 0000, não há necessidade de separar os 12
bits de endereço, todo o registrador IR é enviado para ,
para iniciar uma leitura. A palavra lida é guardada no AC na
linha 8 e volta-se a linha 0. Uma maneira mais geral para separar os
12 bits inferiores contendo o endereço numa instrução é
realizar o AND lógico da instrução com a máscara de
endereço (0000111111111111 ou 0777 octal), isto é,
band(ir, amask).
As outras instruções STOD, ADDD e SUBD são tratadas de
maneira análoga. O único ponto que merece algum destaque é como
realizar a subração. Com complemento de dois, temos o seguinte
fato:
x - y = x + (-y) = x + ( y' + 1) = x + 1 + not(y)