Processadores de 8 bits: MOS Tech 6502 e Zilog Z80

O primeiro processador que estudei, e no qual consegui colocar minhas mãos, foi o Zilog Z80. Ele foi concebido para ter compatibilidade binária com o 8080 da Intel, mas sofreu diversos avanços significativos. Um exemplo foi a criação do sinal de “interrupção não mascarável” (que só veio a estar disponível nos processadores de Intel à partir do 8085). Outras modificações foram um instruction set mais rico e a adição de dois registradores de índice de 16 bits cada (IX e IY)… O Z80 também tinha dois conjuntos de registradores de uso geral que podiam ser chaveados (nunca usados “ao mesmo tempo”). Isso era útil em rotinas de tratamento de interrupção, já que o conjunto original podia ser preservado facilmente.

No final dos anos 80 coloquei as mãos num Apple ][+, da Microdigital. Como todo Apple ][, ele tinha o processador 6502 da MOS Technologies. Foi o primeiro processador RISC que vi. Diferente do Z80, ele tinha um conjunto realmente restrito, tanto de registradores de uso geral (somente 3, de 8 bits cada: A, X e Y) quanto de instruções… Enquanto o Z80 tinha instruções estendidas, o 6502 só suportava menos que 256 instruções (cada opcode ocupa apenas um byte, seguido do operando).

Para facilitar minha vida aqui e escrever o mínimo possível, vou falar primeiro sobre o 6502, deixando o Z80 para a segunda parte.

MOS Tech 6502:

O 6502 foi muito usado, à partir do final dos anos 70, nos primeiros vídeo games (notoriamente, o ATARI 2600) e até mesmo em arcades. Alguns microcomputadores ficaram bem famosos, como o Apple ][ e o Commodore 64. O motivo foi sua simplicidade.

Atari 2600 e Commodore 64

Existem apenas 3 registradores de uso geral de 8 bits (A, X e Y), os registradores PC (Program Counter), S (Stack pointer) e P (Processor status register) e também um conjunto pequeno de instruções. Há também alguns “atalhos” que não estão presentes em processadores derivados da arquitetura Intel 8080. Por exemplo, ao carregar um registrador os flags de zero (Z) e sinal (S) são automaticamente afetados. Nos Z80, por exemplo, uma operação lógica ou aritmética tem que ser executada para afetar flags (é assim até hoje na arquitetura x86).

As instruções são bem simples e descritivas e temos menos que 256:

opcodes do 6502 (65C02 tem mais!)

Repare como algumas instruções e/ou modos de endereçamento estão agrupados… Isso também facilitava ao desenvolvedor “decorar” os opcodes! Quando aos modos de endereçamento, instruções que exigem algum operando podem tê-lo expresso de diversas formas:

  • Valor imediato: É o caso de instruções como LDA #0, por exemplo, onde o valor 0 é colocado em A. O símbolo # é usado para denotar “imediato”. Sem esse símbolo, estaremos escrevendo um endereço de memória;
  • Página zero: Um endereço de memória no 6502 tem 16 bits de tamanho. O byte superior deste endereço é chamado de página. Podemos omitir a página de um endereço se essa for zero, como em LDA $3F. Aqui $3F é o endereço, em hexadecimal, $003F, mas a instrução só ocupará 2 bytes. Note, também, o uso de $ para denotar valores em hexadecimal;
  • Absoluto: Trata-se do endereço completo de 16 bits, como em LDA $C010.
  • Indexado: É a mesma coisa que o absoluto ou página zero, mas usa um dos registradores, X ou Y, como índice. Como em LDA $40,X ou LDA $C000,Y;
  • Indireto: O operando é um ponteiro (um endereço) de onde será lido o endereço alvo. Como em LDA ($40). Aqui, em $40 e $41 teremos 2 bytes que formam um endereço de 16 bits. Este endereço é que será usado para obter o byte que será colocado em A;
  • Indireto Indexado: Existem dois tipos, um antes e outro após a indireção. LDA ($40),X obtém o endereço lendo 16 bits à partir de $40 e depois soma a X para, só então, usar esse valor como ponteiro. Já LDA ($40,X) adiciona X à zero page $40 para obter o endereço de onde o byte será lido, como no modo indireto normal.

Existem outros argumentos, como os de saltos e chamadas. Neste caso, dependendo da instrução, o operando pode ser um endereço absoluto (16 bits) ou relativo (8 bits). Da mesma forma como acontece nos processadores da família x86, os endereços relativos são adicionados ao valor de PC.

Olhando de novo para a tabela acima temos instruções de carga e armazenamento (por exemplo, LDA carrega [load] A, STA armazena [store] A); adição e subtração sempre usando o flag carry (ADC e SBC); incrementos e decrementos (INA, INX, INY, DEA, DEX e DEY); comparações (CMP, CPX e CPY); operações lógicas (AND, ORA e EOR [mas não existe NOT, que pode ser feito com EOR #$FF!]); outras operações lógicas binárias (BIT, ASL, LSR, ROL e ROR); manipulação de pilha (PHA, PLA, PHP e PLP); manipulação de flags (CLc e SEc) e saltos (JSR, JMP, Bcc, RTS e RTI). Repare que c deverá ser substituído por um dos flags e cc pela comparação desejada: EQ (equal ou Z=1), NE (not equal ou Z=0) MI (minus ou S=1), PL (plus ou S=0), CS (carry set), CC (carry clear), VC e VS (oVerflow clear e oVerflow set). Ah, e existem também as instruções de transferência entre A, X e Y (TAX, TAY, TXA e TYA) e uma instrução especial, BRK, que gerará uma interrupção de “break” (raramente usada).

A versão mais “nova” do 6502, o 65C02, tem alguns instruções a mais, preenchendo o espaço vago na tabela acima. A maioria dos usuários brasileiros desses processadores em microcomputadores, no final dos anos 80, vai se lembrar do TK-2000, quando se fala em 65C02, mas o micro de grande sucesso da Apple que usava esse processador, na época, foi o Apple ][e.

O Apple ][e
Zilog Z80:

O processador Z80 é o primo rico distante da atual arquitetura 80×86. Ele é derivado do antigo 8080, de 8 bits, com um montão de melhorias. Dentre elas, modos de endereçamento melhorados, novas instruções e mais registradores de uso geral.

No antigo 8080 e 8085 tínhamos os registradores A, B, C, D, E, H e L, de 8 bits cada, bem como SP (Stack Pointer), Flags (F) e PC (Program Counter). O Z80 acrescentou um segundo conjunto de uso geral (A', B', C', D', E', H' e L'), bem como os registradores de índice (de 16 bits cada) IX e IY e seus “espelhos” (IX' e IY'), além do espelho dos flags (F'… No 8080 era possível emparelhar apenas os registradores H e L para formar um pseudo registrador chamado M (de “Memória”), que era usado como ponteiro, mas o Z80 permite o emparelhamento BC, DE e no caso de operações de manipulação de pilha, AF.

Não é difícil perceber que a arquitetura 80×86 aproveitou a nomenclatura usada no 8080 de A até D, embora, exceto pelo registrador A, os demais não tinham finalidades bem definidas. No Z80 isso foge um pouco à regra, já que instruções como LDI e LDD (e suas equivalentes com “repetição”), por exemplo, sugerem usos específicos para DE (DE de DEstination).

A matriz do conjunto de instruções do Z80 é grande o suficiente para que fique impraticável mostrá-la aqui de forma reduzida. Você pode vê-la neste link, se quiser.

Assim como no caso do 6502, as operações aritméticas e lógicas são todas feitas tomando como o primeiro operando o registrador A e, geralmente, essas são as únicas instruções que afetam os flags. Assim como o 6502, não existe uma operação NOT, que pode ser efetuada com o XOR contra o valor imediato 0xFF… Mas, diferente do 6502, existem muitas instruções estendidas. Por exemplo, ADD e ADC coexistem, bem como SUB e SBB (onde borrow é o inverso de carry). A quantidade de instruções relacionadas a shifts e rotações é mais rica e temos até instruções para ajustes de valores BCD (Binary Coded Decimal), assim como acontece na família 80×86, exceto no modo x86-64.

No Z80 também é possível carregar um par de registradores com um valor imediato de 16 bits, como em LD HL,0123h, ou via indireção, como em LD HL,(8000h). E, falando em indireção, já que temos um conjunto de registradores de uso geral maior e que podem ser emparelhados, a indireção é mais simples do que a do 6502. A notação entre parênteses simplesmente significa que o que encontra-se entre eles é o endereço onde um byte ou word serão lidos – o esquema de indireção dupla do 6502 é desnecessário.

Existem também instruções especializadas. DJNZ, por exemplo, realiza um salto se, depois de decrementar o registrador B, este não chegou a zero. É como se fosse:

// Equivalente de 'DJNZ addr', em C:
if (--B) goto addr;

As instruções LDI e LDD são instruções de movimentação de blocos. Elas copiam um byte que está apontado por DE para o endereço apontado por HL. A diferença é que LDI incrementa HL e DE e LDD decrementa-os… Mas, também existem LDIR e LDDR, que fazem a mesma coisa, mas usam BC como contador de repetições. Instruções de manipulação de blocos também estão associadas com CP (de ComParação), IN e OUT, na forma de CPI e CPD (e suas equivalentes terminadas em R), acontecendo o mesmo para as demais.

Exemplos de micros com o Z80, no Brasil

Z80 versus 6502:

Durante o final dos anos 70 e até meados dos anos 80 existiu uma verdadeira guerra entre entusiastas de microcomputadores baseados no 6502 (Commodore 64 e Apple ][) e Z80 (onde o maior falatório vinha da turma do TRS-80)… Do ponto de vista dos processadores, o Z80 deveria ganhar de carroçada, mas… O 6502, por ser RISC, tinha um clock reduzido (1 MHz), mas executava código tão rápido quanto o Z80… O Z80, por sua vez, aceitava clock de 4 MHz e, em teoria, poderia ter hardware associado a ele até 4 vezes mais rápido.

Dos micros que usavam o 6502 surgiram softwares sérios que são usados até hoje, pelo menos ao nível conceitual. Por exemplo, a planilha de cálculo surgiu no Apple ][ e chamava-se Visicalc (surgiu em 1979 e foi totalmente escrita em assembly para o 6502).

Essa era a cara do Visicalc.

Originalmente o Visicalc não foi desenvolvido para o Apple ][, mas para o precursor do UNIX (O Multics, mas sob o processador 6502!). Mas foi no Apple ][ que o mundo conheceu a planilha de cálculo eletrônica… Somente em 1983 surgiu uma versão para o PC: O Lotus 1-2-3.

O primeiro filesystem para microcomputadores que tenho notícia, e que suportava nomes “longos”, foi o Apple DOS. Os TRS-80 adotavam o modelo do CP/M-80, usando nomes de 8.3 caracteres (e os drives A: e B:). A diferença é que no DOS dos TRS-80 o separador entre o nome do arquivo e sua extensão era uma ‘/’ e as extensões executáveis tendiam a ser nomeadas ‘/CMD’. O programinha “Dancing Demon” da Radio Shack, se não me engano, era “DEMON/CMD”:

O padrão usado pelo CP/M-80 seguido pela IBM no PC-DOS e pela Microsoft (“criadora” do PC-DOS, que mais tarde viria a ser chamado de MS-DOS), até a criação do Windows NT e a popularização do Windows 95 (já nas versões beta, chamadas de projeto Chicago).

Outra vantagem dos micros com 6502 é que eles eram COLORIDOS. Os TRS-80 jamais foram e os PCs só vieram a sê-lo quando os monitores coloridos começaram ser popularizados. Mas, os Apple ][ e Commodores não precisavam de monitores, bastava uma TV. Eis uma comparação (Karateka, no Apple ][):

Tela de um diretório (catálogo) do Apple DOS

Não me pergunte o significado desses atributos *A, *B, *I e *T porque não me lembro mesmo!

Anúncios