quinta-feira, julho 06, 2017

O Microprocessador RCA COSMAC CDP1802

O microprocessador CDP1802 da RCA é um microprocessador de 8 bits dos anos 70 que se distingue em vários pontos de outros da mesma época.



Para começar, semicondutores não é a primeira coisa que vem em mente atualmente quando se fala do seu fabricante. A RCA tem uma história interessante, que começa em 1919, estando principalmente ligada a comunicações.  Ela começou a trabalhar com transistores no início dos anos 50 e anos 60 se aventurou a concorrer com a IBM na fabricação de mainframes. Nos anos 70 a companhia experimentou uma diversificação muito louca de atividades (adquirindo empresas como Hertz e Random House). Nos anos 80 entrou em colapso, voltou a fazer parte da General Eletric e, no final da década, sua divisão de semicondutores foi vendida para a Harris Corporation.

No começo dos anos 70, a RCA definiu uma arquitetura para computadores de 8 bits que chamou de COSMAC. A principal implementação desta arquitetura foi o CDP1802, lançado em 1976. Um dos usos importantes para o 1802 foi na industria espacial, principalmente satélites. No lado hobbista, o 1802 foi usado em vários computadores pessoais denominados COSMAC ELF (ou variações disto) vendidos como kits de baixo custo. O primeiro deles foi descrito em artigos da Popular Electronics em 1976. O CDP 1802 continua sendo fabricado pela Intersis.


Algumas características do 1802:
  • Implementado em CMOS
  • Capaz de manter o estado interno mesmo sem a presença de clock
  • Pode operar com clocks baixo, com baixo consumo de energia
  • Via de dados de 8 bits e via de endereços de 16 bits
  • Possui 16 registradores de uso geral de 16 bits; qualquer um deles pode ser usado como contador de programa (não tem um registrador dedicado para isto)
  • Possui um pino de saída digital (Q) e quatro pinos de entrada digital.
  • Suporte a interrupções e DMA
A figura abaixo (extraída do Manual do Usuário do CDP1802) mostra a estrutura interna do 1802:


Embaixo, à esquerda, temos o bloco com os dezesseis registradores de 16 bits (indicados por R(n).1 e R(n).0) . Ainda em baixo, ao centro, temos o registrador D que funciona como acumulador e é o único que pode receber um resultado da unidade lógica aritmética (ALU). Os registradores de 4 bits N, P e X são usados para selecionar um dos dezesseis registradores de uso geral. N é carregado diretamente a partir do código da instrução para selecionar um operando. P e X são acessíveis por instruções dedicadas e selecionam, respectivamente, o contador de programa e o registrador para endereçamento indireto.

Reparar a ausência de um ponteiro explícito para pilha. O tratamento de interrupções e a implementação de subrotinas precisa levar em conta algumas peculiaridades:
  • Quando ocorre uma interrupção, o registrador T recebe o conteúdo de P e X. P é forçado em 1 (causando um pulo para a instrução apontada por R(1), que passa a ser o contador de programa), X é forçado em 2 e as interrupções são inibidas.
  • A instrução SAV salva o conteúdo atual do registrador T na posição de memória apontada pelo registrador selecionado por X
  • A instrução MARK coloca o conteúdo de P e X em T e na posição de memória apontada por R(2). Em seguida o conteúdo de P é salvo em X e R(2) é decrementado de 1.
  • A instrução RET carrega P e X com o conteúdo da posição de memória apontada por R(X). Em seguida R(X) é incrementado de 1 e a interrupção é habilitada.
Confuso? Felizmente o manual explica como usar tudo isto. No caso de subrotinas, o manual apresenta três opções:
  • Usar contadores de programa separados. Esta é forma mais rápida, menos flexível e mais frágil. Por exemplo, o nosso programa principal usa R(1) como contador de programa. Para chamar uma subrotina ele coloca o endereço dela em R(2) e coloca 2 em P. A subrotina roda usando R(2) como contador; ao final coloca 1 em P para retomar o programa principal. Note que neste esquema a subrotina só é capaz de retornar se quem chamou usava R(1) como contador.
  • Usar uma pilha apontada por R(2) e as instruções MARK e RET. Para chamar a subrotina, executa-se MARK (que salva P e X na pilha), coloca-se o endereço da subrotina em algum registrador e passa-se a usar este registrador como ponteiro de programa. Ao seu final a subrotina coloca 2 em X, incrementa R(2) e executa um RET para restaurar P e X original. No retorno quem chamou precisa incrementar mais uma vez R(2). Este esquema permite que a subrotina retorne independente de qual contador de programa era usado antes, mas cada chamada continua "gastando" um registrador de uso geral para armazenar o endereço de retorno.
  • Chamada padrão, definida pela RCA para as suas bibliotecas. Esta é a forma mais genérica, mas requer mais processamento no início e no fim das subrotinas. Na chamada padrão, R(2) aponta para uma pilha, R(3) é usado como contador de programa no programa principal e nas subrotinas, R(4) e R(5) são contadores de programa dedicados ao código de início e fim de subrotinas e R(6) é usado para apontar para o endereço de retorno (e eventualmente acessar parâmetros). A chamada de subrotina começa com uma instrução "SEP 4" (coloca 4 no registrador P). Esta instrução deve ser seguida pelo endereço da subrotina. Isto executa a rotina de início, que coloca R(6) na pilha, copia R(3) em R(6), coloca em R(3) o endereço da subrotina e faz um "SEP 3" para executá-la. O retorno da subrotina é feito por um "SEP 5", a rotina de fim inverte a rotina de início: copia R(6) em R(3), restaura R(6) a partir da pilha e faz "SEP 6" para retornar o controle.
Felizmente as esquisitices estão restritas à chamada de subrotinas. As demais instruções são mais tradicionais.

No ponto de vista de hardware, podemos destacar a flexibilidade do clock (pode ser usada uma onda quadrada em nível TTL ou ligado diretamente um cristal) e o fato do DMA permitir implementar uma entrada de dados na Ram com um mínimo de componentes (o que foi aproveitado no ELF).

Em breve mostrarei uma montagem do 1802 em protoboard.

Nenhum comentário: