terça-feira, julho 25, 2017

Assembler para o CDP1802 - Parte 1

Embora existam alguns assemblers para o 1802 (como este), resolvi me aventurar a escrever um. Segue abaixo a minha motivação e alguns comentários sobre a linguagem assembly suportada.


Motivação

Tudo começou com a leitura deste manual, que se refere a um sistema de desenvolvimento da RCA que possuía um assembler denominado CRA - COSMAC Resident Assembler. Entre outras coisas, este manual descreve a linguagem e apresenta tanto um exemplo ilustrativo como a listagem de um monitor. Como será visto a seguir, esta linguagem tem algumas esquisitices. Os assemblers que encontrei deram um "modernizada" na linguagem. A primeira motivação, portanto, foi escrever um assembler que aceitasse a sintaxe descrita no manual.

Algumas décadas atrás eu escrevi um assembler como um trabalho para a escola. Foi um assembler para o processador Motorola 6809 e foi escrito em Algol para rodar no B6700 da USP. Na época eu considerei um dos meus melhores programas (passei com dez na matéria). Infelizmente não guardei nenhuma listagem nem o deck de cartões (eu disse, foi décadas atrás). Daí a segunda motivação: reviver um pouco desta emoção.

A Linguagem

Uma coisa que talvez esteja confundindo alguns dos leitores é eu estar falando em mais de uma linguagem assembly para o mesmo processador. Embora a linguagem de máquina seja única, múltiplas linguagens assembly são possíveis (e até comuns). Os motivos são os mais variados, de razões práticas a gostos pessoais. A linguagem que vou tratar é chamada no manual de "COSMAC Level I Assembly Language". Não vou aqui tratar de todos os detalhes (para isto tem o manual, apesar de confuso). Alguns aspectos parecem ser consequência não intencional da implementação; uma vez documentados passam a ser features e não bugs.

Só lembrando, um assembler trabalha com um ponteiro que indica o endereço onde o próximo byte gerado será colocado na memória. Vou chamar aqui este ponteiro de pc.

A primeira coisa não muito usual é permitir mais de um comando (statement) por linha, bastando separá-los com ponto e vírgula. Comentários começam com a sequência '..' (dois pontos consecutivos) e vão até o final da linha. Espaços fora de strings são ignorados.

Um comando pode conter:
  • "Nada": só comentário e/ou espaços
  • Uma definição de constante (equate)
  • Uma sequência de dados (datalist)
  • Uma instrução do processador (opcionalmente seguida por uma datalist) ou uma diretiva do assembler, opcionalmente precedidas por um label
  • Também é possível ter apenas o label no comando.
Vejamos um pouco mais de detalhes sobre isto:

O equate consiste em  nome seguido de um '=' e de uma expressão:

  VALOR = 1234

O equate não gera código, apenas define um símbolo com o valor da expressão. Este símbolo pode ser usado em outras expressões.

Uma datalist é uma sequência de expressões ou strings separados por vírgula. Quando usada isoladamente ou após uma instrução do processador deve ser precedia por uma vírgula. Exemplos:

  ,1,2,3
  ,T'Ola, mundo' 
  NOP ,0,0

Uma datalist gera os valores das expressões. Repare no exemplo acima a sintaxe para strings.

Um label é um nome seguido de ':'. Não gera código, apenas define um símbolo com o valor atual do pc. Uma instrução do processador é composta de um mnemônico seguido eventualmente de um operando. Um tipo de operando é o que escolhe um registrador, e isto pode ser feito de várias formas:

  CONTADOR = 1
  INICIO:        .. isto é um label
    INC  R1      .. vamos incrementar o registrador 1
    INC 1        .. mesma coisa
    INC CONTADOR .. idem
  RA = 1         .. não faça isto !
    INC RA       .. o equate prevalece sobre o nome do registrador!

As diretivas são poucas:
  • ORG expr define um novo valor para o pc
  • PAGE avança o pc para a próxima "página" (endereço do tipo xx00)
  • DC datalist é o mesmo que , datalist
  • END marca o final do programa
Para encerrar, vamos falar um pouco sobre constantes e expressões. 

Uma constante decimal pode ser D'1234' ou simplesmente 1234. Uma constante binária tem a forma B'01011'. Uma constante hexadecimal  pode ser X'1234' ou #1234 ou "simplesmente" A000 se o primeiro caracter for uma letra (de A a F) e não for definido um símbolo com este nome (sugestão: coloque sempre o '#' na frente).

Uma expressão pode ser uma constante, um símbolo, simbolo + constante ou símbolo - constante. Além dos símbolos que você definir, você pode usar * para representar o pc. Para facilitar a manipulação de endereços, existem as formas A(expr), A.0(expr) e A.1(expr). A primeira indica que devem ser usados os 16 bits da expressão, a segunda que deve ser usado apenas o byte menos significativo e a terceira apenas o mais significativo:

POS = #1234
ADDR = A(POS+1)   .. #1235
ADR0 = A.0(POS+1) .. #35
ADR1 = A.1(POS+1) .. #12

Na segunda parte vamos ver como eu escrevi o meu assembler.

Nenhum comentário: