Sítio do Piropo

B. Piropo

< Coluna em Fórum PCs >
Volte
06/03/2006

< Computadores XXVII: Mnemônicos >


Neste ponto de nossa jornada você já dispõe de todo o necessário para desenvolver qualquer programa que rode em nossa UCP elementar: conhece a estrutura da UCP, sua forma de se comunicar com a MP e sabe de cor (ou não?) todos os dezesseis membros de seu limitado conjunto de instruções examinados detalhadamente nas duas últimas colunas. E já viu um exemplo de um programa completo, funcional, carregado na memória principal. Talvez até tenha “quebrado a cabeça” tentando descobrir o que o tal programeto faz (não é impossível, houve quem conseguisse). Mas, tendo ou não conseguido, certamente há de ter chegado a uma conclusão irretorquível: programar em linguagem de máquina é difícil pracacete abessa ou mais...

Para os que não quiserem se dar ao trabalho de consultar as colunas anteriores aqui vai o programa em linguagem de máquina. Na coluna da esquerda, os endereços de cada posição de memória e na coluna da direita o conteúdo das respectivas posições. Dureza para entender, nénão?

00000000   011100000001

00000001   100100000011

00000010   000100000110

00000011   000000000000

00000100   000000000000

00000101   000000000000

00000110   010100000000

00000111   001000010101

00001000   100100000101

00001001   101100000000

00001010   001000010101

00001011   100100000100

00001100   111000000101

00001101   100100000101

00001110   100000000100

00001111   101100000000

00010000   001000010111

00010001   100100000100

00010010   111000000101

00010011   100100000101

00010100   000100001110

00010101   100000000011

00010110   000100011000

00010111   100000000101

00011000   011000000000

00011001   000000000000

Listagem 1: Programa em linguagem de máquina

Há uma razão para isso. “Linguagem”, segundo o dicionário Houaiss, é “qualquer meio sistemático de comunicar idéias ou sentimentos através de signos convencionais, sonoros, gráficos, gestuais etc.”. Ou seja: uma forma de comunicação.

Máquinas se comunicam com máquinas usando números. Já humanos se comunicam com humanos usando palavras. Para um humano, “entender” a linguagem da máquina é tão difícil quanto para a máquina “entender” a linguagem dos humanos. Seria muito mais fácil se pudéssemos nos comunicar com a máquina usando palavras, cujos significados são muito mais fáceis de memorizar para nós, humanos. Desde que, naturalmente, houvesse uma forma de converter as palavras que nós humanos entendemos nos números que as máquinas “entendem”.

Então cuidemos primeiro do que vem primeiro: substituir números por palavras. Depois veremos como fazer a máquina “entender” essas palavras.

Tomemos uma instrução qualquer como exemplo. Digamos a instrução cujo código é (0001b) (o “b” final indicando que o número está expresso em binário, ou no sistema numérico posicional de base dois). O que ela faz? Examinando a descrição das instruções descobrimos que ela “executa um salto incondicional no fluxo do programa”. Ou seja: SALTA, independentemente do conteúdo do acumulador. Procuremos uma forma de exprimir isso usando uma palavra simples de tal modo que seja fácil lembrar o que faz a instrução apenas examinando a palavra. Que tal “SLTA”?

(Neste ponto cabe um parênteses: é claro que eu poderia usar “SALTA”, ainda mais fácil de entender que “SLTA”, mas acontece que decidi padronizar em quatro o número de caracteres da palavra que representa a instrução apenas para combinar com o número de bits do código da instrução e facilitar minha tarefa de substituir um programa em código de máquina por seu correspondente em Assembly. Esta decisão foi pessoal e arbitrária e nada tem a ver com a verdadeira linguagem Assembly, que usa “palavras” de tamanhos diferentes. Eu somente pude adotá-la porque o número de instruções de nosso conjunto é pequeno, apenas dezesseis.)

Sim, “SLTA” lembra “salta”, portanto fiquemos com ela. E como teremos outras instruções de salto (quando o conteúdo do acumulador for zero, positivo ou negativo, respectivamente), vamos começá-las todas com as letras “SLT” para facilitar a lembrança que se trata de uma instrução de salto. Para a instrução [0010b], salto no caso do conteúdo do acumulador ser zero, acrescentemos um “Z” (de “Zero”) e a “batizaremos” de “SLTZ”. O salto caso positivo (instrução 0011b) será “batizado” de “SLTP” acrescentando um “P” de “Positivo” e o salto caso negativo (instrução 0100b) será “SLTN”, recebendo o acréscimo do “N” de “Negativo”. Falta “batizar” apenas uma das instruções de controle de fluxo, aquela que pára o programa em seu final, interrompendo sua marcha (instrução 0000b). Que batizaremos de “ALTO” (como o comando militar que interrompe a marcha da soldadesca). O resultado é o conjunto de “nomes” abaixo listado: 

Instruções de controle de fluxo:

{[0000] [00000000]} = ALTO

{[0001] [endereço]} = SLTA [endereço]

{[0010] [endereço]} = SLTZ [endereço]

{[0011] [endereço]} = SLTP [endereço]

{[0100] [endereço]} = SLTN [endereço]

Mas, afinal, o que fizemos? Praticamente nada. Apenas substituímos quatro números por quatro letras. Ocorre que, na listagem de um programa, ao encontrar a instrução “SLTZ” fica muito mais fácil lembrar que ela promove um salto caso o acumulador contenha um zero que ao encontrar o número 0010.

Coisas que facilitam a lembrança chamam-se “mnemônicos”. E isso nada tem a ver com informática, tem a ver com português mesmo, aqui está o Houaiss novamente que não me deixa mentir: “mnemônico: relativo à memória; ... que serve para desenvolver a memória e facilitar a memorização;... fácil de ser lembrado; de fácil memorização”. Por isso essas “palavras” usadas para substituir os códigos das instruções são conhecidas por “mnemônicos”. Ou seja: a linguagem Assembly usa mnemônicos em vez dos códigos numéricos da linguagem de máquina.

E não há como negar que isso facilita muito a interpretação das listagens de programas. Vejamos as instruções de entrada e saída. A instrução (0101b), que lê um valor da ENTRADA padrão e o escreve no ACC chamaremos de “ENTR” e a (0110b) que envia o conteúdo do ACC para a SAÍDA padrão batizaremos de “SAID” (para respeitar o critério dos quatro caracteres). Ficaremos então com:  

Instruções de entrada/saída:

{[0101] [00000000]} = ENTR

{[0110] [00000000]} = SAID

Para movimentar dados temos apenas três instruções. A (0111b), que “escreve o número de oito bits no ACC” receberá o mnemônico “ACCM” para lembrar de “acumulador” (algo me diz que tentando com um pouco mais de afinco eu conseguiria um mnemônico melhorzinho para esta). A instrução (1000b), que executa uma LEITURA de memória batizaremos de “LEIA” e a (1000b) que executa uma ESCRITA na memória de “ESCR”. O resultado é a relação abaixo:  

Instruções de movimentação de dados:

{[0111] [valor]} = ACCM [valor]

{[1000] [endereço]} = LEIA [endereço]

{[1001] [endereço]} = ESCR [endereço]

 Agora, ficou fácil “batizar” as instruções matemáticas ou lógicas. Nem vou me dar ao trabalho de explicar o que elas fazem (e, se você não entender todas elas, provavelmente está lendo a série de colunas errada; como não quero perder leitores e o ibope desta série já não está lá essas coisas, por via das dúvidas vou ajudar um pouco: a primeira “incrementa” o acumulador e a segunda o “decrementa”; as demais ficam por sua conta, mas a quem não descobrir o que elas fazem recomendo cuidado para não sujar a testa na próxima vez que tomar sorvete). A lista fica:  

Instruções matemáticas e lógicas:

{[1010] [00000000]} = INCR

{[1011] [00000000]} = DECR

{[1100] [endereço]} = SOMA [endereço]

{[1101] [endereço]} = SUBT [endereço]

{[1110] [endereço]} = MULT [endereço]

{[1111] [endereço]} = DIVI [endereço]

Pronto. Tudo o que fizemos até agora foi substituir quatro bits por quatro caracteres. Mas que diferença! Se eu encontrasse o código (1010b) em uma listagem muito provavelmente teria que recorrer a uma tabela para descobrir o que o programador pretendia com ele, mas se eu me deparar com o mnemônico “INCR” dificilmente deixarei de lembrar que tudo o que ele pretende é incrementar o valor do acumulador. Já facilitou um bocado.

Veja como fica nosso programa substituindo os códigos das instruções por seus mnemônicos:

00000000   ACCM 00000001

00000001   ESCR 00000011

00000010   SLTA 00000110

00000011   0000 00000000

00000100   0000 00000000

00000101   0000 00000000

00000110   ENTR 00000000

00000111   SLTZ 00010101

00001000   ESCR 00000101

00001001   DECR 00000000

00001010   SLTZ 00010101

00001011   ESCR 00000100

00001100   MULT 00000101

00001101   ESCR 00000101

00001110   LEIA 00000100

00001111   DECR 00000000

00010000   SLTZ 00010111

00010001   ESCR 00000100

00010010   MULT 00000101

00010011   ESCR 00000101

00010100   SLTA 00001110

00010101   LEIA 00000011

00010110   SLTA 00011000

00010111   LEIA 00000101

00011000   SAID 00000000

00011001   ALTO 00000000

Listagem 2: substituição de códigos por mnemônicos

Muito mais fácil de entender, pois não? E, repare: ao contrário das linguagens de alto nível, em que um único comando pode ser desdobrado em dezenas, eventualmente centenas ou milhares de instruções em linguagem de máquina, nesta linguagem que estamos “inventando” (e que logo descobriremos que já foi inventada e se chama Assembly) existe uma correspondência biunívoca (ou seja, correspondência “de um para um”) entre os mnemônicos e os códigos de instrução. A cada mnemônico corresponde uma e apenas uma instrução e a cada instrução corresponde um e apenas um mnemônico. O que significa que, basicamente, programar em Assembly corresponde a substituir os códigos das instruções (em linguagem de máquina) por seus correspondentes mnemônicos (em Assembly). Mas apenas isso já é uma melhora e tanto. Basta comparar esta listagem aí de cima com a lá do início da coluna.

Porém, para nosso programa se tornar um pouco mais compreensível ainda falta solucionar um problema cabeludo: batizar e endereçar as variáveis.

Um conceito interessante que fica para a próxima coluna.

B. Piropo