Capítulo 4: Tutorial de linguagem assembly do microprocessador 6502

Capitulo 4 Tutorial De Linguagem Assembly Do Microprocessador 6502



Capítulo 4: Tutorial de linguagem assembly do microprocessador 6502

4.1 Introdução

O microprocessador 6502 foi lançado em 1975. Foi usado como microprocessador para alguns computadores pessoais da época, como Apple II, Commodore 64 e BBC Micro.







O microprocessador 6502 ainda é produzido em grande número hoje. Não é mais uma unidade central de processamento usada hoje em computadores pessoais (laptops), mas ainda hoje é produzida em grande número e usada em aparelhos eletrônicos e elétricos. Para compreender as arquiteturas de computadores mais modernas, é muito útil examinar um microprocessador mais antigo, mas bastante bem-sucedido, como o 6502.



Por ser simples de entender e programar, é um dos melhores (se não o melhor) microprocessador para ensinar linguagem assembly. A linguagem assembly é uma linguagem de baixo nível que pode ser usada para programar um computador. Observe que a linguagem assembly de um microprocessador é diferente da linguagem assembly de outro microprocessador. A linguagem assembly do microprocessador 6502 é ensinada neste capítulo. Mais precisamente, é o 65C02 que é ensinado, mas é simplesmente referido como 6502.



Um computador famoso no passado era chamado commodore_64. O 6502 é um microprocessador da família 6500. O computador commodore_64 usa o microprocessador 6510. O microprocessador 6510 é do tipo 6500 µP. O conjunto de instruções do 6502 µP é quase todo o conjunto de instruções do 6510 µP. O conhecimento deste capítulo e do próximo é baseado no computador commodore_64. Esse conhecimento é usado como base para explicar as modernas arquiteturas de computadores e sistemas operacionais modernos nesta parte do curso de carreira online.





Arquitetura do computador refere-se aos componentes da placa-mãe do computador e uma explicação de como os dados fluem dentro de cada componente, especialmente o microprocessador, como os dados fluem entre os componentes e também como os dados interagem. O singular para dados é datum. Uma maneira eficaz de estudar a arquitetura de um computador é estudar a linguagem assembly da placa-mãe.

Diz-se que o computador commodore_64 é um computador com palavra de computador de 8 bits. Isto significa que as informações são armazenadas, transferidas e manipuladas na forma de códigos binários de oito bits.



Diagrama de blocos da placa-mãe Commodore 64
O diagrama de blocos da placa-mãe Commodore 64 é:


Fig 4.1 Diagrama de blocos da unidade do sistema Commodore_64

Imagine o microprocessador 6510 como o microprocessador 6502. A memória total é uma série de bytes (8 bits por byte). Existe a memória de acesso aleatório (leitura/gravação) na qual os bytes podem ser gravados ou apagados. Quando o computador é desligado, todas as informações da memória de acesso aleatório (RAM) são apagadas. Há também a memória somente leitura (ROM). Quando o computador é desligado, as informações na ROM permanecem (não são apagadas).

Existe a porta de entrada/saída (circuito), que é referida como dispositivos de entrada/saída no diagrama. Esta porta não deve ser confundida com as portas visíveis nas superfícies verticais esquerda e direita ou frontal e traseira da unidade de sistema do computador. Essas são duas coisas diferentes. As conexões desta porta interna com os periféricos, como disco rígido (ou disquete), teclado e monitor, não são mostradas no diagrama.

Existem três barramentos (grupos de condutores elétricos muito pequenos) no diagrama. Cada fio pode transferir um bit 1 ou um bit 0. O barramento de dados, para a transferência de bytes de oito bits por vez (um pulso de clock) para a RAM e a porta de entrada/saída (dispositivos de entrada/saída) é bidirecional. O barramento de dados tem oito bits de largura.

Todos os componentes estão conectados ao barramento de endereços. O barramento de endereços é unidirecional do microprocessador. Existem dezesseis condutores para o barramento de endereços e cada um carrega um bit (1 ou 0). Dezesseis bits são enviados em um pulso de clock.

Existe o barramento de controle. Alguns dos condutores do barramento de controle transfeririam um bit cada do microprocessador para os outros componentes. Algumas linhas de controle transportam os bits da porta de entrada/saída (IO) para o microprocessador.

Memória do computador
A RAM e a ROM são consideradas um conjunto de memória. Esta montagem é representada diagramaticamente da seguinte forma, onde os números hexadecimais possuem o prefixo “$”:


Fig 4.11 Layout de memória para o computador Commodore 64

A RAM é de 0000 16 para DFFF 16 que é escrito entre $ 0000 e $ DFFF. Com a linguagem assembly 6502 µP, um número hexadecimal é prefixado com “$” e não tem o sufixo (subscrito) com 16 ou H ou hexadecimal. Qualquer informação na RAM desaparece quando o computador é desligado. A ROM começa em $E000 a $FFFF. Possui sub-rotinas que não disparam quando o computador é desligado. Essas sub-rotinas são as rotinas comumente usadas que auxiliam na programação. O programa do usuário os chama (consulte o próximo capítulo).

O espaço (bytes) de $0200 a $D000 é para os programas do usuário. O espaço de $D000 a $DFFF é para informações que estão diretamente relacionadas aos periféricos (dispositivos de entrada/saída). Isso faz parte do sistema operacional. Assim, o sistema operacional do computador Commodore-64 é dividido em duas partes principais: a parte da ROM que nunca desliga e a parte de $D000 a $DFFF que desliga quando a energia é desligada. Esses dados de IO (entrada/saída) devem ser carregados de um disco sempre que o computador é ligado. Hoje, esses dados são chamados de drivers periféricos. Os periféricos começam na porta do dispositivo de entrada/saída, passando pelas conexões na placa-mãe até as portas identificáveis ​​nas superfícies verticais do computador às quais o monitor, teclado, etc. estão conectados e aos próprios periféricos (monitor, teclado, etc. .).

A memória consiste em 2 16 = 65.536 localizações de bytes. Na forma hexadecimal, são 10.000 16 = 10.000 H = 10.000 hexadecimal = locais de US$ 10.000. Na computação, a contagem na base dois, na base dez, na base dezesseis, etc. começa em 0 e não em 1. Portanto, o primeiro local é na verdade o número de local 000000000000000 2 = 0 10 = 0000 16 = $ 0.000. Na linguagem assembly 6502 µP, a identificação de uma localização de endereço é prefixada com $ e não há sufixo ou subscrito. O último local é o número de local 1111111111111111 2 = 65.535 10 =FFFF 16 = $FFFF e não 1000000000000000 2 , ou 65.536 10 ou 10.000 16 ou $ 10.000. Os 1000000000000000 2 , 65.536 10 , 10.000 16 , ou $ 10.000 fornece o número total de locais de bytes.

Aqui, 2 16 = 65.536 = 64 x 1024 = 64 x 2 10 = 64 Kbytes (Kilobytes). O sufixo 64 no nome Commodore-64 significa 64 KB de memória total (RAM e ROM). Um byte tem 8 bits e os 8 bits irão para um local de byte na memória.

Os 64 Kbytes de memória estão divididos em páginas. Cada página tem 0100 16 = 256 10 localizações de bytes. Os primeiros 256 10 = primeiro 0100 16 locais é a página 0. A segunda é a página 1, a terceira é a página 2 e assim por diante.

Para endereçar as 65.536 localidades, são necessários 16 bits para cada localidade (endereço). Assim, o barramento de endereços do microprocessador para a memória consiste em 16 linhas; uma linha por um bit. Um bit é 1 ou 0.

Os registros 6502 µP
Um registro é como as células de bytes para um local de memória de bytes. O 6502 µP possui seis registros: cinco registros de 8 bits e um registro de 16 bits. O registro de 16 bits é chamado de Contador de Programa, abreviado como PC. Ele contém o endereço de memória para a próxima instrução. Um programa em linguagem assembly consiste em instruções colocadas na memória. Dezesseis (16) bits diferentes são necessários para endereçar um determinado local de byte na memória. Em um determinado pulso de clock, esses bits são enviados para as linhas de endereço de 16 bits do barramento de endereços para a leitura de uma instrução. Todos os registros do 6502 µP são representados como segue:


Fig. 4.12 Registros 6502 µP

O contador de programa ou PC pode ser visto como um registro de 16 bits no diagrama. Os oito bits menos significativos são rotulados como PCL para Program Counter Low. Os oito bits mais significativos são rotulados como PCH para Program Counter High. Uma instrução na memória do Commodore-64 pode consistir em um, dois ou três bytes. Os 16 bits do PC apontam para a próxima instrução a ser executada, na memória. Dentre os circuitos do microprocessador, dois deles são denominados Unidade Lógica Aritmética e Decodificador de Instruções. Se a instrução atual que está sendo processada no µP (microprocessador) tiver um byte de comprimento, esses dois circuitos aumentam o PC para a próxima instrução em 1 unidade. Se a instrução atual que está sendo processada no µP tiver dois bytes de comprimento, o que significa que ocupa dois bytes consecutivos na memória, esses dois circuitos aumentam o PC para a próxima instrução em 2 unidades. Se a instrução atual que está sendo processada no µP tiver três bytes de comprimento, o que significa que ocupa três bytes consecutivos na memória, esses dois circuitos aumentam o PC para a próxima instrução em 3 unidades.

O acumulador “A” é um registrador de uso geral de oito bits que armazena o resultado da maioria das operações aritméticas e lógicas.

Os registros “X” e “Y” são usados ​​para contar as etapas do programa. A contagem na programação começa em 0. Portanto, são chamados de registradores de índice. Eles têm alguns outros propósitos.

Embora o registro Stack Pointer, “S” tenha 9 bits, que é considerado um registro de oito bits. Seu conteúdo aponta para uma localização de byte na página 1 da memória de acesso aleatório (RAM). A página 1 começa no byte $0100 (256 10 ) para byte $01FF (511 10 ). Quando um programa está em execução, ele passa de uma instrução para a próxima instrução consecutiva na memória. No entanto, nem sempre é esse o caso. Há momentos em que ele salta de uma área de memória para outra para continuar executando as instruções ali, consecutivamente. A página 1 na RAM é usada como pilha. A pilha é uma grande área de memória RAM que contém os próximos endereços para a continuação do código de onde ocorre o salto. Os códigos com instruções de salto não estão na pilha; eles estão em outro lugar na memória. No entanto, após a execução das instruções de salto, os endereços de continuação (não os segmentos de código) ficam na pilha. Eles foram empurrados para lá como resultado das instruções de salto ou ramificação.

O registro de status do processador de oito bits de P é um tipo especial de registro. Os bits individuais não estão relacionados ou conectados entre si. Cada bit ali é chamado de bandeira e é apreciado independentemente dos demais. Os significados das bandeiras são fornecidos a seguir conforme a necessidade.

O primeiro e o último índice de bits de cada registro são indicados acima de cada registro no diagrama anterior. A contagem do índice de bits (posição) em um registrador começa em 0 à direita.

Páginas de memória em binário, hexadecimal e decimal
A tabela a seguir mostra o início das páginas de memória em binário, hexadecimal e decimal:

Cada página tem 1.0000.0000 2 número de bytes que é igual a 100 H número de bytes que é igual a 256 10 número de bytes. No diagrama de memória anterior, as páginas são indicadas subindo a partir da página 0 e não descendo conforme indicado na tabela.

As colunas binária, hexadecimal e decimal desta tabela fornecem os endereços de localização dos bytes de memória em suas diferentes bases. Observe que para a página zero, apenas os bits do byte inferior são necessários para digitar durante a codificação. Os bits do byte superior podem ser omitidos, pois são sempre zeros (para página zero). Para o restante das páginas, devem ser usados ​​os bits do byte superior.

O restante deste capítulo explica a linguagem Assembly do 6502 µP usando todas as informações anteriores. Para compreender rapidamente a linguagem, o leitor deve somar e subtrair na base dezesseis em vez da base dez. Na verdade, deveria ser a base dois, mas calcular na base dois é complicado. Lembre-se de que ao somar dois números na base dois, um carry ainda será 1, como na base dez. Mas ao subtrair dois números na base dois, um empréstimo é dois e não dez como na base dez. Ao adicionar dois números na base dezesseis, um carry ainda é 1 como na base dez. Mas ao subtrair dois números na base dezesseis, um empréstimo é dezesseis e não dez como na base dez.

4.2 Instruções para transferência de dados

Considere a seguinte tabela de instruções de transferência de dados em linguagem assembly para o 6502 µP:

Quando um byte (8 bits) é copiado de um local de bytes de memória para o Registro Acumulador, Registro X ou Registro Y, isso está sendo carregado. Quando um byte é copiado de qualquer um desses registradores para um local de bytes de memória, isso está sendo transferido. Quando um byte é copiado de um registrador para outro, isso ainda está sendo transferido. Na segunda coluna da tabela, a seta mostra a direção da cópia de um byte. O restante das quatro colunas mostra diferentes modos de endereçamento.

Uma entrada na coluna do modo de endereçamento é o código de bytes real para a parte mnemônica correspondente da instrução em hexadecimal. AE, por exemplo, é o código de byte real para LDX que carrega um byte da memória para o registrador X no modo de endereçamento absoluto como AE 16 = 10101110 2 . Portanto, os bits para LDX em uma localização de bytes de memória são 10101110.

Observe que para a parte mnemônica LDX da instrução, existem três bytes possíveis que são A2, AE e A6, e cada um é para um modo de endereçamento específico. Quando o byte que carrega no registrador X não deve ser copiado de uma localização de bytes de memória, o valor deve ser digitado com (logo após) o mnemônico LDX na instrução em hexadecimal ou decimal. Neste capítulo, tais valores são digitados em hexadecimal. Este é um endereçamento imediato, então o byte real na memória para representar LDX é A2 16 = 10100010 2 e não EA 16 que é igual a 10101110 2 .

Na tabela, todos os bytes sob os títulos do modo de endereçamento são chamados de Códigos de Operação, que são abreviados como opcodes. Pode haver mais de um opcode para um mnemônico, dependendo do modo de endereçamento.

Observação: A palavra “carregar” na unidade de sistema do computador pode ter dois significados: pode referir-se ao carregamento de um arquivo de um disco para a memória do computador ou pode referir-se à transferência de um byte de um local de byte de memória para um registro de microprocessador. .

Existem mais modos de endereçamento do que os quatro da tabela para o 6502 µP.

Salvo indicação em contrário, todo o código de programação do usuário neste capítulo começa no endereço 0200 16 que é o início da área do usuário na memória.

Memória M e Acumulador A

Memória para acumulador

Endereçamento Imediato
A instrução a seguir armazena o número FF 16 = 255 10 no acumulador:

LDA#$FF

O “$” não é usado apenas para identificar um endereço de memória. Em geral, é usado para indicar que o próximo número a seguir é hexadecimal. Neste caso, $FF não é o endereço de nenhuma localização de bytes de memória. É o número 255 10 em hexadecimal. A base 16 ou qualquer outro subscrito equivalente não deve ser escrito nas instruções da linguagem assembly. O “#” indica que o que vem a seguir é o valor a ser colocado no registrador do acumulador. O valor também pode ser escrito na base dez, mas isso não é feito neste capítulo. O “#” significa endereçamento imediato.

Um mnemônico tem alguma semelhança com sua frase correspondente em inglês. “LDA #$FF” significa carregar o número 255 10 no acumulador A. Como este é o endereçamento imediato da tabela anterior, LDA é A9 e não AD ou A5. A9 em binário é 101010001. Portanto, se A9 para LDA estiver no endereço $0200 na memória, $FF estará no endereço $0301 = 0300 + 1. O #$FF é precisamente o operando do mnemônico LDA.

Endereçamento Absoluto
Se o valor de $FF estiver na localização $0333 da memória, a instrução anterior é:

LDA$0333

Observe a ausência de #. Neste caso, a ausência de # significa que o que se segue é um endereço de memória e não o valor de interesse (não o valor a colocar no acumulador). Portanto, o opcode para LDA, desta vez, é AD e não A9 ou A5. O operando para LDA aqui é o endereço $0333 e não o valor $FF. $FF está em $0333, um local bastante distante. A instrução “LDA $0333” ocupa três posições consecutivas na memória, e não duas, como ocorreu na ilustração anterior. “AD” para LDA está na posição de $ 0200. O byte inferior de 0333, que é 33, está no local $0301. O byte mais alto de $0333, que é 03, está no local $0302. Este é o pequeno endianismo usado pela linguagem assembly 6502. As linguagens assembly de diferentes microprocessadores são diferentes.

Este é um exemplo de endereçamento absoluto. O $0333 é o endereço do local que possui $FF. A instrução consiste em três bytes consecutivos e não inclui o $FF ou sua localização real de bytes.

Endereçamento de página zero

Suponha que o valor $FF esteja no local de memória $0050 na página zero. As localizações de bytes para a página zero começam em $0000 e terminam em $00FF. Estes são 256 10 locais no total. Cada página da memória do Commodore-64 tem 256 10 longo. Observe que o byte mais alto é zero para todos os locais possíveis no espaço de página zero na memória. O modo de endereçamento de página zero é igual ao modo de endereçamento absoluto, mas o byte mais alto de 00 não é digitado na instrução. Portanto, para carregar o $FF do local $0050 no acumulador, a instrução do modo de endereçamento de página zero é:

LDA $50

Sendo LDA A5 e não A9 ou AD, A5 16 = 10100101 2 . Lembre-se que cada byte na memória é de 8 células, e cada célula abriga um bit. A instrução aqui consiste em dois bytes consecutivos. A5 para LDA está no local de memória $0200 e o endereço $50, sem o byte superior 00, está no local $0301. A ausência de 00, que consumiria um byte na memória total de 64K, economiza espaço de memória.

Acumulador para memória

Endereçamento Absoluto
A instrução a seguir copia um valor de byte, seja ele qual for, do acumulador para o local de memória $1444:

SÃO $ 1444

Diz-se que isso está sendo transferido do acumulador para a memória. Não está carregando. Carregar é o oposto. O byte do opcode para STA é 8D 16 = 10001101 2 . Esta instrução consiste em três bytes consecutivos na memória. O 8D 16 está na localização de $ 0200. O 44 16 do endereço $ 1444 está no local $ 0201. E 14 16 está na posição de $ 0202 – pouco endianismo. O byte real copiado não faz parte da instrução. 8D e não 85 para endereçamento de página zero (na tabela) são usados ​​aqui para STA.

Endereçamento de página zero
A instrução a seguir copia um valor de byte, seja ele qual for, do acumulador para o local de memória $0050 na página zero:

STA$0050

O byte do opcode para STA aqui é 85 16 = 10000101 2 . Esta instrução consiste em dois bytes consecutivos na memória. O 85 16 está na localização $ 0200. Os 50 16 do endereço $0050 está no local $0201. A questão do endianismo não surge aqui porque o endereço possui apenas um byte, que é o byte inferior. O byte real copiado não faz parte da instrução. 85 e não 8D para endereçamento de página zero são usados ​​aqui para STA.

Não faz sentido usar o endereçamento imediato para transferir um byte do acumulador para um local na memória. Isso ocorre porque o valor real como $FF deve ser citado na instrução de endereçamento imediato. Portanto, não é possível o endereçamento imediato para a transferência de um valor de byte de um registrador no µP para qualquer local de memória.

Mnemônicos LDX, STX, LDY e STY
LDX e STX são semelhantes a LDA e STA, respectivamente. Mas aqui é usado o registro X e não o registro A (acumulador). LDY e STY são semelhantes a LDA e STA, respectivamente. Mas aqui é usado o registro Y e não o registro A. Consulte a Tabela 4.21 para cada opcode em hexadecimal que corresponde a um determinado mnemônico e a um determinado modo de endereçamento.

Transferências de registro para registro
Os dois conjuntos anteriores de instruções na Tabela 4.21 tratam da cópia (transferência) de memória/registro do microprocessador e da cópia de registro/registro (transferência). As instruções TAX, TXA, TAY, TYA, TSX e TXS fazem a cópia (transferência) do registro do microprocessador para outro registro do mesmo microprocessador.

Para copiar o byte de A para X, a instrução é:

IMPOSTO

Para copiar o byte de X para A, a instrução é:

Texas

Para copiar o byte de A para Y, a instrução é:

MÃO

Para copiar o byte de Y para A, a instrução é:

TYA

Para o computador Commodore 64, a pilha é a página 1 logo após a página 0 na memória. Como qualquer outra página, consiste em 25610 10 localizações de bytes, de $ 0100 a $ 01FF. Normalmente, um programa é executado de uma instrução para a próxima instrução consecutiva na memória. De tempos em tempos, ocorre um salto para outro segmento de código de memória (conjunto de instruções). A área da pilha na memória (RAM) contém os próximos endereços de instruções de onde os saltos (ou ramificações) pararam para a continuação do programa.

O ponteiro de pilha “S” é um registrador de 9 bits no 6502 µP. O primeiro bit (mais à esquerda) é sempre 1. Todos os endereços de localização de bytes na página um começam com 1 seguido por 8 bits diferentes para o 256 10 Localizações. O ponteiro da pilha possui o endereço do local na página 1 que contém o endereço da próxima instrução que o programa deve retornar e continuar após executar o segmento de código atual (para o qual saltou). Como o primeiro bit de todos os endereços da pilha (página um) começa com 1, o registrador de ponteiro da pilha só precisa conter os oito bits restantes. Afinal, seu primeiro bit, que é o bit mais à esquerda (o nono bit contando a partir da direita), é sempre 1.

Para copiar o byte de S para X, a instrução é:

TSX

Para copiar o byte de X para S, a instrução é:

TXT

As instruções registro a registro não aceitam nenhum operando. Eles consistem apenas no mnemônico. Cada mnemônico possui seu opcode em hexadecimal. Isto está no modo de endereçamento implícito porque não há operando (sem endereço de memória, sem valor).

Observação: Não há transferência (cópia) de X para Y ou Y para X.

4.3 Operações Aritméticas

O circuito, Unidade Lógica Aritmética no 6502 µP, só pode adicionar dois números de oito bits por vez. Não subtrai, não multiplica e não divide. A tabela a seguir mostra os opcodes e modos de endereçamento para operações aritméticas:

Observação: Todos os mnemônicos para operações aritméticas e outros tipos de operações (ou seja, todos os mnemônicos 6502) ocupam um byte de código de operação (op). Se houver mais de um modo de endereçamento para o mnemônico, haverá diferentes opcodes para o mesmo mnemônico: um por modo de endereçamento. O C, D e V na tabela são os sinalizadores do registrador de status. Seus significados serão fornecidos posteriormente, conforme a necessidade.

Adição de números não assinados
Com o 6502 µP, os números com sinal são números em complemento de dois. Os números sem sinal são números positivos comuns que começam em zero. Portanto, para um byte de oito bits, o menor número sem sinal é 00000000 2 = 0 10 = 00 16 e o maior número sem sinal é 11111111 2 = 255 10 =FF 16 . Para dois números sem sinal, a adição é:

A+M+C→A

Isso significa que o conteúdo de 8 bits do acumulador é adicionado pela unidade lógica aritmética a um byte (8 bits) da memória. Após a adição de A e M, o carry para o nono bit vai para a célula do sinalizador de carry no registrador de status. Qualquer carry anterior de uma adição anterior que ainda esteja na célula do sinalizador de carry no registrador de status também é adicionado à soma de A e M, perfazendo A+M+C→A. O resultado é colocado de volta no acumulador.

Se o acréscimo de juros for:

A + M

E não há necessidade de adicionar nenhum carry anterior, a flag de carry tem que ser apagada que é feita 0, para que a adição seja:

A+M+0→A igual a A+M→A

Observação: Se M for adicionado a A, e ocorrer um carry de 1 porque o resultado é maior que 255 10 = 11111111 2 =FF 16 , este é um novo transporte. Este novo carry de 1 é enviado automaticamente para a célula flag de carry caso seja necessário para o próximo par de oito bits a ser somado (outro A + M).

Código para adicionar dois oito bits não assinados
00111111 2 +00010101 2 é o mesmo que 3F 16 + 15 16 que é igual a 63 10 +21 10 . O resultado é 010101002 2 que é o mesmo que 54 16 e 84 10 . O resultado não ultrapassa o número máximo para oito bits que é 255 10 = 11111111 2 =FF 16 . Portanto, não há carry resultante de 1. Em outras palavras, o carry resultante é 0. Antes da adição, não há carry anterior de 1. Em outras palavras, o carry anterior é 0. O código para fazer esta adição pode ser:

CLC
LDA#$3F
ADC #$15

Observação: Ao digitar a linguagem assembly, a tecla “Enter” do teclado é pressionada ao final de cada instrução. Existem três instruções neste código. A primeira instrução (CLC) limpa o flag de carry caso uma adição anterior tenha 1. O CLC só pode ser feito no modo de endereçamento implícito. O mnemônico para o modo de endereçamento implícito não utiliza operando. Isso limpa a célula de transporte do registrador de status de P. Limpar significa fornecer o bit 0 à célula do sinalizador de transporte. As próximas duas instruções do código usam o modo de endereçamento imediato. Com o endereçamento imediato, existe apenas um operando para o mnemônico que é um número (e não é um endereço de memória nem de registro). E assim, o número deve ser precedido de “#”. O “$” significa que o número a seguir é hexadecimal.

A segunda instrução carrega o número 3F 16 no acumulador. Para a terceira instrução, o circuito da unidade lógica aritmética do µP pega o carry anterior (limpo) de 0 (forçado a 0) da célula flag de carry, do registrador de status e soma-o a 15 16 bem como ao valor que já está no 3F 16 acumulador e coloca o resultado completo de volta no acumulador. Neste caso, há um carry resultante de 0. A ALU (Unidade Lógica Aritmética) envia (coloca) 0 na célula do flag de carry do registrador de status. O registro de status do processador e o registro de status significam a mesma coisa. Se resultar um carry de 1, a ALU envia 1 para o sinalizador de carry do registrador de status.

As três linhas do código anterior devem estar na memória antes de serem executadas. O opcode 1816 para CLC (endereçamento implícito) está na localização de $ 0200 bytes. O código de operação A9 16 para LDA (endereçamento imediato) está na localização de $ 0201 bytes. O número 3F 10 está na localização de $ 0202 bytes. O código de operação 69 16 para LDA (endereçamento imediato) está na localização de $ 0203 bytes. O número 15 10 está na localização de $ 0204 bytes.

Observação: LDA é uma instrução de transferência (carregamento) e não uma instrução aritmética (mnemônica).

Código para adicionar dois dezesseis bits não assinados
Todos os registros no 6502 µP são essencialmente registros de oito bits, exceto o PC (Program Counter) que tem 16 bits. Até mesmo o registrador de status tem 8 bits de largura, embora seus oito bits não operem juntos. Nesta seção, é considerada a adição de dois 16 bits sem sinal, com um carry do primeiro par de oito bits para o segundo par de oito bits. O transporte de interesse aqui é o transporte da posição do oitavo bit para a posição do nono bit.

Deixe os números serem 0010101010111111 2 = 2ABF16 16 = 10.943 10 e 0010101010010101 2 = 2A95 16 = 10.901 10 . A soma é 0101010101010100 2 = 5554 16 = 21.844 10 .

A adição desses dois números sem sinal na base dois é a seguinte:

A tabela a seguir mostra a mesma adição com o transporte de 1 do oitavo bit para a nona posição do bit, começando pela direita:

Ao codificar isso, os dois bytes inferiores são adicionados primeiro. Então, a ALU (Unidade Lógica Aritmética) envia o carry de 1 da posição do oitavo bit para a posição do nono bit, para a célula do sinalizador de carry no registrador de status. O resultado de 0 1 0 1 0 1 0 0 sem carry vai para o acumulador. Em seguida, o segundo par de bytes é adicionado com o carry. O mnemônico ADC significa adicionar automaticamente o carry anterior. Neste caso, o carry anterior, que é 1, não deve ser alterado antes da segunda adição. Para a primeira adição, como qualquer carry anterior não faz parte desta adição completa, deve ser zerado (feito 0).

Para a adição completa dos dois pares de bytes, a primeira adição é:

UMA + M + 0 -> UMA

A segunda adição é:

UMA + M + 1 -> UMA

Portanto, o sinalizador de transporte deve ser apagado (dado o valor 0) pouco antes da primeira adição. O seguinte programa, cujo leitor deve ler a explicação a seguir, utiliza o modo de endereçamento absoluto para esta soma:

CLC
LDA$0213
CDM $0215
; nenhuma compensação porque o valor do sinalizador de transporte é necessário
STA$0217
LDA$0214
CDM $0216
STA$0218

Observe que com a linguagem assembly 6502, um ponto e vírgula inicia um comentário. Isso significa que na execução do programa o ponto e vírgula e tudo à sua direita são ignorados. O programa que é escrito anteriormente está em um arquivo de texto salvo com o nome de escolha do programador e com a extensão “.asm”. O programa anterior não é exatamente o programa que vai para a memória para execução. O programa correspondente na memória é chamado de programa traduzido, onde os mnemônicos são substituídos pelos opcodes (bytes). Qualquer comentário permanece no arquivo de texto em linguagem assembly e é removido antes que o programa traduzido chegue à memória. Na verdade, existem dois arquivos que são salvos no disco hoje: o arquivo “.asm” e o arquivo “.exe”. O arquivo “.asm” é o da ilustração anterior. O arquivo “.exe” é o arquivo “.asm” com todos os comentários removidos e todos os mnemônicos substituídos por seus códigos de operação. Quando aberto em um editor de texto, o arquivo “.exe” fica irreconhecível. Salvo indicação em contrário, para os fins deste capítulo, o arquivo “.exe” é copiado para a memória a partir do local $0200. Este é o outro significado de carregamento.

Os dois números de 16 bits a serem somados ocupam quatro bytes na memória para endereçamento absoluto: dois bytes por número (a memória é uma sequência de bytes). Com endereçamento absoluto, o operando para o opcode fica na memória. O resultado da soma tem dois bytes de largura e também deve ser colocado na memória. Isso dá um total de 6 10 = 6 16 bytes para entradas e saídas. As entradas não vêm do teclado e a saída não vem do monitor ou da impressora. As entradas ficam na memória (RAM) e a saída (resultado da soma) volta para a memória (RAM) nesta situação.

Antes de um programa ser executado, a versão traduzida deve primeiro estar na memória. Observando o código do programa anterior, pode-se observar que as instruções sem o comentário perfazem 19 10 = 13 16 bytes. Portanto, o programa leva de $ 0200 locais de bytes na memória para $ 0200 + $ 13 – $ 1 = $ 0212 locais de bytes (começando em $ 0200 e não em $ 0201, o que implica – $ 1). Adicionar os 6 bytes para os números de entrada e saída faz com que todo o programa termine em $0212 + $6 = $0218. A duração total do programa é 19 16 = 25 10 .

O byte inferior do auge deve estar no endereço $0213, e o byte superior do mesmo auge deve estar no endereço $0214 – pouco endianness. Da mesma forma, o byte inferior do adendo deve estar no endereço $0215, e o byte superior do mesmo adendo deve estar no endereço $0216 – pouco endianness. O byte inferior do resultado (soma) deve estar no endereço $0217, e o byte superior do mesmo resultado deve estar no endereço $0218 – pouco endianness.

O código de operação 18 16 para CLC (endereçamento implícito) está na localização de bytes de $0200. O opcode para “LDA $0213”, ou seja, AD 16 para LDA (endereçamento absoluto), está na localização de bytes $0201. O byte inferior do auge que é 10111111 está na localização do byte de memória $0213. Lembre-se de que cada opcode ocupa um byte. O endereço “$0213” de “LDA $0213” está nas localizações de bytes de $0202 e $0203. A instrução “LDA $0213” carrega o byte inferior do auge no acumulador.

O opcode para “ADC $0215”, ou seja, 6D 16 para ADC (endereçamento absoluto), está na localização de bytes $0204. O byte inferior da extensão que é 10010101 está na localização do byte $0215. O endereço “$0215” de “ADC $0215” está nas localizações de bytes de $0205 e $0206. A instrução “ADC $0215” adiciona o byte inferior do acréscimo ao byte inferior do acréscimo que já está no acumulador. O resultado é colocado de volta no acumulador. Qualquer carry após o oitavo bit é enviado para o flag de carry do registrador de status. A célula do sinalizador de transporte não deve ser apagada antes da segunda adição dos bytes mais altos. Este carry é adicionado automaticamente à soma dos bytes mais altos. Na verdade, um carry de 0 é adicionado à soma dos bytes inferiores automaticamente no início (equivalente a nenhum carry sendo adicionado) por causa do CLC.

O comentário leva os próximos 48 10 = 30 16 bytes. No entanto, isso permanece apenas no arquivo de texto “.asm”. Não chega à memória. Ele é removido pela tradução feita pelo montador (um programa).

Para a próxima instrução que é “STA $0217”, o opcode do STA que é 8D 16 (endereçamento absoluto) está na localização de bytes $0207. O endereço “$0217” de “STA $0217” está nos locais de memória de $0208 e $0209. A instrução “STA $0217” copia o conteúdo de oito bits do acumulador para o local de memória $0217.

O byte mais alto do acrescento que é 00101010 está na localização de memória de $0214, e o byte mais alto do adendo que é 00101010 está na localização de byte de $02 16 . O opcode para “LDA $0214” que é AD16 para LDA (endereçamento absoluto) está na localização de bytes $020A. O endereço “$0214” de “LDA $0214” está nas localizações de $020B e $020C. A instrução “LDA $0214” carrega o byte superior do auge no acumulador, apagando tudo o que estiver no acumulador.

O opcode para “ADC $0216” que é 6D 16 para ADC (endereçamento absoluto) está na localização de bytes de $ 020D. O endereço “$0216” de “ADC 0216” está nas localizações de bytes de $020E e $020F. A instrução “ADC $0216” adiciona o byte superior do acréscimo ao byte superior do acréscimo que já está no acumulador. O resultado é colocado de volta no acumulador. Se houver um carry de 1, para esta segunda adição, ele é automaticamente colocado na célula de carry do registrador de status. Embora o transporte além do décimo sexto bit (esquerda) não seja necessário para este problema, é bom verificar se ocorreu um transporte de 1, verificando se o sinalizador de transporte se tornou 1.

Para a próxima e última instrução que é “STA $0218”, o opcode de STA que é 8D16 (endereçamento absoluto) está na localização de byte $0210. O endereço “$0218” de “STA $0218” está nos locais de memória de $0211 e $0212. A instrução “STA $0218” copia o conteúdo de oito bits do acumulador para o local de memória $0218. O resultado da adição dos dois números de dezesseis bits é 0101010101010100, com o byte inferior de 01010100 no local de memória de $0217 e o byte superior de 01010101 no local de memória de $0218 – pouco endianness.

Subtração
Com o 6502 µP, os números com sinal são números em complemento de dois. Um número em complemento de dois pode ter oito bits, dezesseis bits ou qualquer múltiplo de oito bits. Com complemento de dois, o primeiro bit da esquerda é o bit de sinal. Para um número positivo, este primeiro bit é 0 para indicar o sinal. O resto dos bits formam o número da maneira normal. Para obter o complemento de dois de um número negativo, inverta todos os bits do número positivo correspondente e adicione 1 ao resultado da extremidade direita.

Para subtrair um número positivo de outro número positivo, o subtraendo é convertido em um número negativo em complemento de dois. Em seguida, o minuendo e o novo número negativo são somados normalmente. Então, a subtração de oito bits fica:

Onde o carry é assumido como 1. O resultado no acumulador é a diferença no complemento de dois. Portanto, para subtrair dois números, o sinalizador de transporte deve ser definido (colocado em 1).

Ao subtrair dois números de dezesseis bits, a subtração é feita duas vezes, como na adição de dois números de dezesseis bits. Como a subtração é uma forma de adição com o 6502 µP, ao subtrair dois números de dezesseis bits, o sinalizador de transporte é definido apenas uma vez para a primeira subtração. Para a segunda subtração, qualquer configuração do sinalizador de transporte é feita automaticamente.

A programação da subtração para números de oito ou dezesseis bits é feita de forma semelhante à programação da adição. No entanto, o sinalizador de transporte deve ser definido logo no início. O mnemônico para fazer isso é:

Subtração com números positivos de dezesseis bits
Considere a subtração com os seguintes números:

Esta subtração não envolve complemento de dois. Como a subtração em 6502 µP é feita em complemento de dois, a subtração na base dois é feita da seguinte forma:

O resultado do complemento de dois é igual ao resultado obtido da subtração ordinária. Entretanto, observe que o 1 que vai para a posição do décimo sétimo bit à direita é ignorado. O minuendo e o subtraendo são divididos em dois bits oito cada. O complemento de dois de 10010110 do byte inferior do subtraendo é determinado independentemente do seu byte superior e de qualquer transporte. O complemento de dois de 11101011 do byte superior do subtraendo é determinado independentemente do seu byte inferior e de qualquer transporte.

Os 16 bits do minuendo já estão em complemento de dois, começando com 0 da esquerda. Portanto, não necessita de nenhum ajuste em bits. Com o 6502 µP, o byte inferior do minuendo sem qualquer modificação é adicionado ao byte inferior do complemento de dois do subtraendo. O byte inferior do minuendo não é convertido em complemento de dois porque os dezesseis bits do minuendo inteiro já devem estar em complemento de dois (com 0 como o primeiro bit à esquerda). Nesta primeira adição, é adicionado um carry obrigatório de 1 devido à instrução 1=0 SEC.

Na subtração efetiva atual, há um transporte de 1 (de adição) do oitavo bit para o nono bit (da direita). Como isso é efetivamente uma subtração, qualquer bit que deveria estar no sinalizador de transporte no registrador de status é complementado (invertido). Portanto, o carry de 1 torna-se 0 na bandeira C. Na segunda operação, o byte mais alto do minuendo é adicionado ao byte de complemento de dois mais alto do subtraendo. O bit do sinalizador de transporte complementado automaticamente do registrador de status (neste caso é 0) também é adicionado (aos bytes mais altos). Qualquer 1 que ultrapasse o décimo sexto bit à direita é ignorado.

O próximo passo é codificar todo esse esquema da seguinte maneira:

SEC
LDA$0213
SBC$0215
; nenhuma compensação porque o valor do sinalizador de transporte invertido é necessário
STA$0217
LDA$0214
SBC$0216
STA$0218

Lembre-se que com a linguagem assembly 6502, um ponto e vírgula inicia um comentário que não está incluído na versão traduzida do programa na memória. Os dois números de 16 bits para subtração ocupam quatro bytes de memória com endereçamento absoluto; dois por número (a memória é uma série de bytes). Essas entradas não são do teclado. O resultado da soma tem dois bytes e também deve ser colocado na memória em um local diferente. Esta saída não vai para o monitor ou impressora; vai para a memória. Isso dá um total de 6 10 = 6 16 bytes para entradas e saídas a serem colocadas na memória (RAM).

Antes de um programa ser executado, ele deve primeiro estar na memória. Olhando o código do programa, percebe-se que as instruções sem o comentário perfazem 19 10 = 13 16 bytes. Como todos os programas neste capítulo começam na localização de memória de $0200, o programa passa da localização de bytes $0200 na memória para a localização de bytes $0200 + $13 – $1 = $0212 (começando em $0200 e não em $0201). Este intervalo não inclui a região dos bytes de entrada e saída. Os dois números de entrada ocupam 4 bytes e o número de saída ocupa 2 bytes. Adicionar os 6 bytes para os números de entrada e saída cria o intervalo do programa que termina em $0212 + $6 = $0218. A duração total do programa é 19 16 = 25 10 .

O byte inferior do minuendo deve estar no endereço $0213, e o byte superior do mesmo minuendo deve estar no endereço $0214 – pouco endianness. Da mesma forma, o byte inferior do subtraendo deve estar no endereço $0215, e o byte superior do mesmo subtraendo deve estar no endereço $0216 – pouco endianness. O byte inferior do resultado (diferença) deve estar no endereço $0217, e o byte superior do mesmo resultado deve estar no endereço $0218 – pouco endianness.

O código de operação de 38 16 para SEC (endereçamento implícito) está no endereço $0200. Supõe-se que todos os programas neste capítulo iniciem no local de memória $0200, anulando qualquer programa que estivesse lá; salvo indicação em contrário. O opcode para “LDA $0213”, ou seja, AD 16 , para LDA (endereçamento absoluto) está na localização de $ 0201 bytes. O byte inferior do minuendo que é 10111111 está na localização do byte de memória $0213. Lembre-se de que cada opcode ocupa um byte. O endereço “$0213” de “LDA $0213” está nas localizações de bytes de $0202 e $0203. A instrução “LDA $0213” carrega o byte inferior do minuendo no acumulador.

O opcode para “SBC $0215”, ou seja, ED 16 , para SBC (endereçamento absoluto) está no local de bytes $ 0204. O byte inferior do subtraendo, que é 01101010, está na localização do byte $ 0215. O endereço “$0215” de “ADC $0215” está nas localizações de bytes de $0205 e $0206. A instrução “SBC $0215” subtrai o byte inferior do subtraendo do byte inferior do minuendo que já está no acumulador. Esta é a subtração em complemento de dois. O resultado é colocado de volta no acumulador. O complemento (inversão) de qualquer carry após o oitavo bit é enviado para o flag de carry do registrador de status. Este sinalizador de transporte não deve ser apagado antes da segunda subtração com os bytes mais altos. Este transporte é adicionado automaticamente à subtração dos bytes mais altos.

O comentário leva os próximos 57 10 = 3916 16 bytes. No entanto, isso permanece apenas no arquivo de texto “.asm”. Não chega à memória. Ele é removido pela tradução feita pelo montador (um programa).

Para a próxima instrução que é “STA $0217”, o opcode do STA, ou seja, 8D 16 (endereçamento absoluto), está na localização de bytes $0207. O endereço “$0217” de “STA $0217” está nos locais de memória de $0208 e $0209. A instrução “STA $0217” copia o conteúdo de oito bits do acumulador para o local de memória $0217.

O byte superior do minuendo, que é 00101010, está na localização de memória $ 0214, e o byte superior do subtraendo, que é 00010101, está na localização de byte $ 0216. O opcode para “LDA $0214”, ou seja, AD 16 para LDA (endereçamento absoluto), está na localização de bytes de $ 020A. O endereço “$0214” de “LDA $0214” está nas localizações de $020B e $020C. A instrução “LDA $0214” carrega o byte mais alto do minuendo no acumulador, apagando tudo o que estiver no acumulador.

O opcode para “SBC $0216”, ou seja, ED 16 para SBC (endereçamento absoluto), está na localização de bytes $ 020D. O endereço “$0216” de “SBC $0216” está nas localizações de bytes de $020E e $020F. A instrução “SBC $0216” subtrai o byte superior do subtraendo do byte superior do minuendo (complemento de dois) que já está no acumulador. O resultado é colocado de volta no acumulador. Se houver um carry de 1 para esta segunda subtração, seu complemento é colocado automaticamente na célula de carry do registrador de status. Embora o transporte além do décimo sexto bit (esquerda) não seja necessário para este problema, é bom verificar se o transporte do complemento ocorre verificando o sinalizador de transporte.

Para a próxima e última instrução que é “STA $0218”, o opcode do STA, ou seja, 8D 16 (endereçamento absoluto), está na localização de bytes $0210. O endereço “$0218” de “STA $0218” está nos locais de memória de $0211 e $0212. A instrução “STA $0218” copia o conteúdo de oito bits do acumulador para o local de memória $0218. O resultado da subtração com os dois números de dezesseis bits é 0001010101010101 com o byte inferior de 01010101 no local de memória de $ 0217 e o byte superior de 00010101 no local de memória de $ 0218 – pouco endianness.

O 6502 µP possui circuito apenas para adição e indiretamente para subtração de complemento de dois. Não possui circuito para multiplicação e divisão. Para fazer a multiplicação e divisão, deve ser escrito um programa em linguagem assembly com detalhes, incluindo o deslocamento de produtos parciais e dividendos parciais.

4.4 Operações Lógicas

No 6502 µP, o mnemônico para OR é ORA e o mnemônico para OR exclusivo é EOR. Observe que as operações lógicas não possuem o endereçamento implícito. O endereçamento implícito não aceita operando. Cada um dos operadores lógicos deve receber dois operandos. O primeiro está no acumulador e o segundo está na memória ou na instrução. O resultado (8 bits) volta ao acumulador. O primeiro no acumulador é colocado lá por uma instrução imediata ou é copiado da memória com endereçamento absoluto. Nesta seção, apenas o endereçamento de página zero é usado para ilustração. Esses operadores lógicos são todos operadores bit a bit.

E
A tabela a seguir ilustra o AND bit a bit em binário, hexadecimal e decimal:

Todos os programas neste capítulo devem começar na localização de bytes de memória $0200. Porém, os programas desta seção estão na página zero, com o objetivo de ilustrar o uso da página zero sem o byte superior 00000000 2 . O AND anterior pode ser codificado da seguinte forma:

LDA#$9A ; não da memória – endereçamento imediato
E #$CD ; não da memória – endereçamento imediato
STA $ 30; armazena $ 88 em $ 0.030 de base zero

OU
A tabela a seguir ilustra o OR bit a bit em binário, hexadecimal e decimal:

LDA#$9A ; não da memória – endereçamento imediato
ORA #$CD ; não da memória – endereçamento imediato
STA $ 30; armazena $CF em $0030 de base zero

LIVRE
A tabela a seguir ilustra o XOR bit a bit em binário, hexadecimal e decimal:

LDA#$9A ; não da memória – endereçamento imediato
EOR #$CD ; não da memória – endereçamento imediato
STA $ 30; armazena $ 57 em $ 0.030 de base zero

4.5 Operações de mudança e rotação

Os mnemônicos e códigos de operação para os operadores de deslocamento e rotação são:

ASL: Desloca um bit para a esquerda do acumulador ou localização da memória, inserindo 0 na célula vaga mais à direita.

LSR: Desloca um bit para a direita do acumulador ou localização da memória, inserindo 0 na célula vaga mais à esquerda.
ROL: Gira um bit para a esquerda do acumulador ou local da memória, inserindo o bit que caiu à esquerda na célula vazia mais à direita.
ROR: Gira um bit à direita do acumulador ou local da memória, inserindo o bit que foi eliminado à direita na célula vazia mais à esquerda.

Para fazer um deslocamento ou rotação com o acumulador, a instrução é mais ou menos assim:

LSR A

Isso usa outro modo de endereçamento denominado modo de endereçamento do acumulador.

Para fazer um deslocamento ou rotação com uma localização de memória de bytes, a instrução é mais ou menos assim:

ROR$ 2BCD

Onde 2BCD é o local da memória.

Observe que não existe modo de endereçamento imediato ou implícito para mudança ou rotação. Não existe modo de endereçamento imediato porque não faz sentido mudar ou girar um número que permanece apenas na instrução. Não há modo de endereçamento implícito porque os projetistas do 6502 µP desejam que apenas o conteúdo do acumulador (registro A) ou a localização de um byte de memória seja deslocado ou girado.

4.6 Modo de Endereçamento Relativo

O microprocessador sempre incrementa (em 1, 2 ou 3 unidades) o Contador de Programa (PC) para apontar para a próxima instrução a ser executada. O 6502 µP possui uma instrução cujo mnemônico é BVS que significa Branch on Overflow Set. O PC consiste em dois bytes. Esta instrução faz com que o PC tenha um endereço de memória diferente para a próxima instrução a ser executada, não resultante de um incremento normal. Isso é feito adicionando ou subtraindo um valor, denominado deslocamento, ao conteúdo do PC. E assim, o PC aponta para um local de memória diferente (ramificado) para o computador continuar a execução a partir daí. O deslocamento é um número inteiro de -128 10 para +127 10 (complemento de dois). Assim, o deslocamento pode fazer com que o salto avance na memória. Se for positivo ou atrasado na memória, ou se for negativo.

A instrução BVS utiliza apenas um operando que é o offset. BVS usa o endereçamento relativo. Considere a seguinte instrução:

BVS $ 7F

Na base dois, 7F H é 01111111 2 = 127 10 . Suponha que o conteúdo no PC para a próxima instrução seja de US$ 0300. A instrução BVS faz com que $7F (um número positivo já em complemento de dois) seja adicionado a $0300 para dar $037F. Portanto, em vez da próxima instrução ser executada no local de memória $0300, ela estará no local de memória $037F (aproximadamente meia página de diferença).

Existem outras instruções de desvio, mas o BVS é muito bom para ilustrar o endereçamento relativo. O endereçamento relativo lida com instruções de desvio.

4.7 Endereçamento Indexado e Endereçamento Indireto Separadamente

Esses modos de endereçamento permitem que o 6502 µP lide com enormes quantidades de dados em curtos períodos de tempo com número reduzido de instruções. Existem locais de 64 KB para toda a memória do Comodore-64. Assim, para acessar qualquer localização de bytes, de 16 bits, são necessários dois bytes. A única exceção à necessidade de dois bytes é para a página zero, onde o byte superior $00 é omitido para economizar o espaço ocupado pela instrução na memória. Com um modo de endereçamento diferente de página zero, os bytes superiores e inferiores do endereço de memória de 16 bits são geralmente indicados de alguma forma.

Endereçamento Indexado Básico

Endereçamento de índice absoluto
Lembre-se de que o registrador X ou Y é chamado de registrador de índice. Considere a seguinte instrução:

LDA $C453,X

Suponha que o valor de 6 H está no registrador X. Observe que 6 não é digitado em nenhum lugar da instrução. Esta instrução adiciona o valor de 6H a C453 H que faz parte da instrução digitada no arquivo de texto que ainda será montado – C453 H + 6 H =C459 H . LDA significa carregar um byte no acumulador. O byte a ser carregado no acumulador vem do endereço $C459. O $C459 que é a soma de $C453 digitado com a instrução e 6 H que é encontrado no registrador X torna-se o endereço efetivo de onde vem o byte a ser carregado no acumulador. Se 6 H estava no registrador Y, Y é digitado no lugar de X na instrução.

Na instrução de instrução digitada, $C453 é conhecido como endereço base e 6 H no registrador X ou Y é conhecido como parte de contagem ou índice do endereço efetivo. O endereço base pode referir-se a qualquer endereço de byte na memória e os próximos 256 10 endereços podem ser acessados, assumindo que o índice inicial (ou contagem) no registro X ou Y seja 0. Lembre-se de que um byte pode fornecer um intervalo contínuo de até 256 10 números (ou seja, 00000000 2 para 11111111 2 ).

Assim, o endereçamento absoluto soma tudo o que já está colocado (foi colocado por outra instrução) no registrador X ou Y aos 16 endereços digitados com a instrução para obter o endereço efetivo. Na instrução digitada, os dois registradores de índice são diferenciados por X ou Y, que são digitados após uma vírgula. X ou Y é digitado; não ambos.

Após todo o programa ser digitado em um editor de texto e salvo com o nome do arquivo de extensão “.asm”, o assembler, que é outro programa, tem que traduzir o programa digitado para o que está (carregado) na memória. A instrução anterior, que é “LDA $C453,X”, ocupa três posições de bytes na memória, e não cinco.

Lembre-se que um mnemônico como o LDA pode ter mais de um opcode (bytes diferentes). O opcode da instrução que usa o registrador X é diferente do opcode que usa o registrador Y. O montador sabe qual código de operação usar com base na instrução digitada. O opcode de um byte para “LDA $C453,X” é diferente do opcode de um byte para “LDA $C453,Y”. Na verdade, o opcode para LDA em “LDA $C453,X” é BD, e o opcode para LDA em “LDA $C453,9” é BD.

Se o opcode para LDA estiver no local de bytes $0200. Então, o endereço de 16 bits de $C453 fica próximo aos locais de bytes na memória que são $0201 e $0202. O byte do código de operação específico indica se é o registro X ou o registro Y que está envolvido. E assim, a instrução de linguagem montada que é “LDA $C453,X” ou “LDA $C453,Y” ocupa três bytes consecutivos na memória, e não quatro ou cinco.

Endereçamento indexado de página zero
O endereçamento do índice de página zero é como o endereçamento do índice absoluto descrito anteriormente, mas o byte de destino deve estar apenas na página zero (de $0000 a $00FF). Agora, ao lidar com a página zero, o byte superior que é sempre 00 H para os locais de memória geralmente é evitado. Portanto, normalmente é mencionado que a página zero começa de $00 a FF. E assim, a instrução anterior de “LDA $C453,X” é:

LDA $53,X

O $C4, um byte superior que se refere a uma página acima do zero da página, não pode ser empregado nesta instrução, pois coloca o byte alvo esperado para ser carregado no byte acumulado fora e acima do zero da página.

Quando o valor digitado na instrução é somado ao valor do registrador de índice, a soma não deve dar resultado acima do zero da página (FF H ). Portanto, está fora de questão ter uma instrução como “LDA $FF, X” e um valor como FF H no registrador de índice porque FF H +FF H = 200 H que é a localização do primeiro byte ($0200) da página 2 (terceira página) na memória, está a uma grande distância da página 0. Portanto, com endereçamento indexado de página zero, o endereço efetivo deve estar na página zero.

Endereçamento Indireto

Saltar Endereçamento Absoluto
Antes de discutir o endereçamento indireto absoluto, é bom primeiro examinar o endereçamento absoluto do JMP. Suponha que o endereço que possui o valor de interesse (byte alvo) seja $8765. São 16 bits que consistem em dois bytes: o byte mais alto que é 87 H e o byte inferior que é 65 H . Assim, os dois bytes de $ 8.765 são colocados no PC (contador de programa) para a próxima instrução. O que é digitado no programa (arquivo) em linguagem assembly é:

JMP$ 8.765

O programa em execução na memória salta de qualquer endereço acessado para $ 8.765. O mnemônico JMP possui três códigos de operação que são 4C, 6C e 7C. O opcode para este endereçamento absoluto é 4C. O opcode para o endereçamento indireto absoluto JMP é 6C (consulte as ilustrações a seguir).

Endereçamento Indireto Absoluto
Isto é usado somente com a instrução de salto (JMP). Suponha que o endereço que contém o byte de interesse (byte de destino) seja $8765. São 16 bits que consistem em dois bytes: o byte mais alto que é 87 H e o byte inferior que é 65 H . Com o endereçamento indireto absoluto, esses dois bytes estão, na verdade, localizados em dois locais de bytes consecutivos em outro lugar da memória.

Suponha que eles estejam localizados nas posições de memória $0210 e $0211. Então, o byte inferior do endereço de interesse que é 65 H está no endereço $0210, e o byte mais alto que é 87 H está no endereço $0211. Isso significa que o byte de interesse de memória mais baixo vai para o endereço consecutivo mais baixo, e o byte de interesse de memória mais alto vai para o endereço consecutivo mais alto – pouco endianness.

O endereço de 16 bits pode referir-se a dois endereços consecutivos na memória. Diante disso, o endereço $0210 refere-se aos endereços de $0210 e $0211. O par de endereços $0210 e $0211 contém o endereço final (16 bits de dois bytes) do byte de destino, com o byte inferior de 65 H em $ 0210 e o byte superior de 87 H em $ 0211. Portanto, a instrução de salto digitada é:

JMP (US$ 0210)

O mnemônico JMP possui três códigos de operação que são 4C, 6C e 7C. O opcode para endereçamento indireto absoluto é 6C. O que está digitado no arquivo de texto é “JMP ($0210)”. Por causa dos parênteses, o montador (tradutor) usa o opcode 6C para JMP, e não 4C ou 7C.

Com o endereçamento indireto absoluto, existem na verdade três regiões de memória. A primeira região pode consistir nas localizações de bytes de $0200, $0201 e $0202. Contém os três bytes para a instrução “JMP ($0210)”. A segunda região, que não é necessariamente próxima à primeira, consiste em duas localizações de bytes consecutivas de $0210 e $0211. É o byte inferior aqui ($0210) que é digitado na instrução do programa em linguagem assembly. Se o endereço de interesse for $8765, o byte inferior de 65 H está na localização de bytes $ 0210 e o byte superior de 87 H está no local de bytes $ 0211. A terceira região consiste em apenas um local de byte. É o endereço $ 8.765 para o byte alvo (byte final de interesse). O par de endereços consecutivos, $0210 e $0211, contém o ponteiro $8765 que é o endereço de interesse. Após a interpretação computacional, são $ 8.765 que vão para o PC (Program Counter) para acessar o byte alvo.

Endereçamento indireto de página zero
Este endereçamento é igual ao endereçamento indireto absoluto, mas o ponteiro deve estar na página zero. O endereço de byte inferior da região do ponteiro é o que está na instrução digitada a seguir:

MPJ (US$ 50)

O byte mais alto do ponteiro está na localização de $51 bytes. O endereço efetivo (apontado) não precisa estar na página zero.

Assim, com o endereçamento de índice, o valor em um registrador de índice é adicionado ao endereço base fornecido na instrução para obter o endereço efetivo. O endereçamento indireto usa um ponteiro.

4.8 Endereçamento Indireto Indexado

Endereçamento indireto indexado absoluto
Este modo de endereçamento é usado somente com a instrução JMP.
No endereçamento indireto absoluto, existe o valor apontado (byte) com seus próprios dois endereços de bytes consecutivos. Esses dois endereços consecutivos formam o ponteiro para estar na região do ponteiro de dois bytes consecutivos na memória. O byte inferior da região do ponteiro é o digitado na instrução entre parênteses. O ponteiro é o endereço do valor apontado. Na situação anterior, $8.765 é o endereço do valor apontado. O $0210 (seguido de $0211) é o endereço cujo conteúdo é $8765 que é o ponteiro. No modo de endereçamento indireto absoluto é ($0210) que se digita no programa (arquivo texto), inclusive os parênteses.

Por outro lado, com o Modo de Endereçamento Indireto Indexado Absoluto, o byte de endereço inferior para a região do ponteiro é formado pela adição do valor no registro X ao endereço digitado. Por exemplo, se o ponteiro estiver no endereço $0210, a instrução digitada pode ser algo assim:

JMP (US$ 020A,X)

Onde o registrador X tem o valor 6 H . 020A H + 6 H = 0210 H . O registro Y não é usado neste modo de endereçamento.

Endereçamento indireto indexado de página zero
Este modo de endereçamento utiliza o registro X e não o registro Y. Com este modo de endereçamento, ainda existe o valor apontado e o ponteiro em sua região de ponteiro de endereço de dois bytes. Deve haver dois bytes consecutivos na página zero para o ponteiro. O endereço digitado na instrução é um endereço de um byte. Este valor é adicionado ao valor no registrador X e qualquer transporte é descartado. O resultado aponta para a região do ponteiro na página 0. Por exemplo, se o endereço de interesse (apontado) for $8765 e estiver nas localizações de bytes $50 e $51 da página 0, e o valor no registrador X for $30, o instrução digitada é algo assim:

LDA ($20,X)

Porque $ 20 + $ 30 = $ 50.

Endereçamento Indexado Indireto
Este modo de endereçamento utiliza o registro Y e não o registro X. Com este modo de endereçamento, ainda existe o valor apontado e a região do ponteiro, mas o conteúdo da região do ponteiro opera de forma diferente. Deve haver dois bytes consecutivos na página zero para a região do ponteiro. O endereço inferior da região do ponteiro é digitado na instrução. Este número (par de bytes) que está contido na região do ponteiro é adicionado ao valor no registrador Y para obter o ponteiro real. Por exemplo, deixe o endereço de interesse (apontado) ser $ 8765, o valor de 6H estar no registrador Y e o número (dois bytes) estar no endereço 50 H e 51 H . Os dois bytes juntos custam $ 875F, já que $ 875F + $ 6 = $ 8.765. A instrução digitada é mais ou menos assim:

LDA (US$ 50), Y

4.9 Instruções de incremento, decremento e testes de BITs

A tabela a seguir mostra as operações das instruções de incremento e decremento:

O INA e o DEA aumentam e diminuem o acumulador, respectivamente. Isso é chamado de endereçamento de acumulador. INX, DEX, INY e DEY são para os registradores X e Y, respectivamente. Eles não aceitam nenhum operando. Então, eles usam o modo de endereçamento implícito. Incremento significa adicionar 1 ao registrador ou byte de memória. Decrementar significa subtrair 1 do registrador ou byte de memória.

O INC e o DEC incrementam e decrementam um byte de memória, respectivamente (e não um registrador). Usar o endereçamento de página zero em vez do endereçamento absoluto é economizar memória para a instrução. O endereçamento de página zero é um byte a menos que o endereçamento absoluto da instrução na memória. No entanto, o modo de endereçamento de página zero afeta apenas a página zero.

A instrução BIT testa os bits de um byte na memória com os 8 bits no acumulador, mas não altera nenhum deles. Apenas alguns flags do Registrador de Status do Processador “P” são definidos. Os bits do local de memória especificado são logicamente AND com os do acumulador. Então, os seguintes bits de status são definidos:

  • N, que é o bit 7 e o último bit (esquerdo) do registrador de status, recebe o bit 7 da localização da memória antes do AND.
  • V, que é o bit 6 do registrador de status, recebe o bit 6 da localização da memória antes do AND.
  • O flag Z do registrador de status é definido (tornado 1) se o resultado do AND for zero (00000000 2 ). Caso contrário, é zerado (tornado 0).

4.10 Comparar instruções

Os mnemônicos de instrução de comparação para o 6502 µP são CMP, CPX e CPY. Após cada comparação, os flags N, Z e C do registrador de status do processador “P” são afetados. O sinalizador N é definido (tornado 1) quando o resultado é um número negativo. O sinalizador Z é definido (tornado 1) quando o resultado é zero (000000002). O flag C é definido (feito 1) quando há um carry do oito para o nono bit. A tabela a seguir fornece uma ilustração detalhada

O significa “maior que”. Com isso, a tabela de comparação deve ser autoexplicativa.

4.11 Instruções de Salto e Ramificação

A tabela a seguir resume as instruções de salto e ramificação:

A instrução JMP utiliza o endereçamento absoluto e indireto. O restante das instruções na tabela são instruções de ramificação. Eles usam apenas o endereçamento relativo com o 6502 µP. Com isso, a tabela torna-se autoexplicativa se for lida da esquerda para a direita e de cima para baixo.

Observe que as ramificações só podem ser aplicadas a endereços entre -128 e +127 bytes do endereço fornecido. Este é um endereçamento relativo. Tanto para as instruções JMP quanto para as instruções de desvio, o Contador de Programa (PC) é diretamente afetado. O 6502 µP não permite ramificações para um endereço absoluto, embora o salto possa fazer o endereçamento absoluto. A instrução JMP não é uma instrução de desvio.

Observação: O endereçamento relativo é usado apenas com instruções de desvio.

4.12 A área da pilha

Uma sub-rotina é como um dos programas curtos anteriores para adicionar ou subtrair dois números. A área de pilha na memória começa de $0100 a $01FF inclusive. Esta área é simplesmente chamada de pilha. Quando o microprocessador executa um salto para a instrução de sub-rotina (JSR – consulte a discussão a seguir), ele precisa saber para onde retornar quando terminar. O 6502 µP mantém esta informação (endereço de retorno) em memória baixa de $0100 a $01FF (a área da pilha) e usa o conteúdo do registrador de ponteiro de pilha que é “S” no microprocessador como um ponteiro (9 bits) para o último endereço retornado. que está armazenado na página 1 ($0100 a $01FF) da memória. A pilha diminui de $ 01FF e torna possível aninhar as sub-rotinas em até 128 níveis de profundidade.

Outro uso do ponteiro de pilha é lidar com interrupções. O 6502 µP possui os pinos rotulados como IRQ e NMI. É possível que alguns pequenos sinais elétricos sejam aplicados a esses pinos e façam com que o 6502 µP pare de executar um programa e comece a executar outro. Neste caso, o primeiro programa é interrompido. Assim como as sub-rotinas, os segmentos do código de interrupção podem ser aninhados. O processamento de interrupções será discutido no próximo capítulo.

Observação : O ponteiro da pilha possui 8 bits para o endereço de byte inferior no endereçamento dos locais de $ 0100 a $ 01FF. O byte mais alto de 00000001 2 é assumido.

A tabela a seguir fornece instruções que relacionam o ponteiro de pilha “S” com os registradores A, X, Y e P à área de pilha na memória:

4.13 Chamada e Retorno de Subrotina

Uma sub-rotina é um conjunto de instruções que atingem um objetivo específico. O programa anterior de adição ou subtração é uma sub-rotina muito curta. Às vezes, as sub-rotinas são chamadas apenas de rotinas. A instrução para chamar uma sub-rotina é:

JSR: Ir para a sub-rotina

A instrução para retornar de uma sub-rotina é:

RTS: Retorno da sub-rotina

O microprocessador tem a tendência de executar continuamente as instruções na memória, uma após a outra. Suponha que o microprocessador esteja atualmente executando um segmento de código e encontre uma instrução de salto (JMP) para executar um segmento de código que está codificado por trás do qual já pode ser executado. Ele executa aquele segmento de código atrás e continua a executar todos os segmentos de código (instruções) seguindo o segmento de código atrás, até executar novamente o segmento de código atual e continuar abaixo. O JMP não envia a próxima instrução para a pilha.

Ao contrário do JMP, o JSR envia o endereço da próxima instrução do PC (contador de programa) para a pilha. A posição da pilha deste endereço é colocada no ponteiro de pilha “S”. Quando uma instrução RTS é encontrada (executada) na sub-rotina, o endereço colocado na pilha é retirado da pilha e o programa continua naquele endereço extraído, que é o próximo endereço da instrução imediatamente antes da chamada da sub-rotina. O último endereço removido da pilha é enviado para o contador do programa. A tabela a seguir fornece os detalhes técnicos das instruções JSR e RTS:

Consulte a ilustração a seguir para os usos de JSR e RTS:

4.14 Um exemplo de loop de contagem regressiva

A seguinte sub-rotina faz a contagem regressiva de $FF até $00 (total de 256 10 conta):

iniciar LDX #$FF ; carregue X com $FF = 255
ciclo DEX; X = X – 1
circuito BNE; se X não for zero, então vá para o loop
RTS; retornar

Cada linha tem um comentário. Os comentários nunca vão para a memória para execução. O montador (tradutor) que converte um programa para o que ele está na memória para execução (running) sempre retira os comentários. Um comentário começa com “;” . O “início” e o “loop” neste programa são chamados de rótulos. Uma etiqueta identifica (o nome) o endereço da instrução. Se a instrução for uma instrução de byte único (endereçamento implícito), o rótulo será o endereço dessa instrução. Se a instrução for multibyte, o rótulo identificará o primeiro byte da instrução multibyte. A primeira instrução deste programa consiste em dois bytes. Supondo que comece no endereço $0300, o endereço $0300 pode ser substituído por “start” no programa. A segunda instrução (DEX) é uma instrução de byte único e deve estar no endereço $0302. Isto significa que o endereço $0302 pode ser substituído por “loop”, no programa, o que na verdade ocorre em “loop BNE”.

“Loop BNE” significa o desvio para o endereço fornecido quando o sinalizador Z do registrador de status é 0. Quando o valor no registrador A ou X ou Y é 00000000 2 , devido à última operação, o sinalizador Z é 1 (definido). Portanto, embora seja 0 (não 1), a segunda e a terceira instruções do programa são repetidas nessa ordem. Em cada sequência repetida, o valor (número inteiro) no registro X é diminuído em 1. DEX significa X = X – 1. Quando o valor no registro X é $00 = 00000000 2 , Z passa a ser 1. Nesse ponto, não há mais repetição das duas instruções. A última instrução RTS do programa, que é uma instrução de byte único (endereçamento implícito), retorna da sub-rotina. O efeito desta instrução é endereçar o contador de programa na pilha para o código que será executado antes da chamada da sub-rotina e retornar ao contador de programa (PC). Este endereço é o endereço da instrução que deve ser executada antes da sub-rotina ser chamada.

Observação: Ao escrever um programa em linguagem assembly para o 6502 µP, apenas um rótulo deve começar no início de uma linha; qualquer outro código de linha deve ser deslocado pelo menos um espaço para a direita.

Chamando uma sub-rotina
Ignorando o espaço de memória ocupado pelos rótulos anteriores, o programa ocupa 6 bytes de localizações consecutivas na memória (RAM) de $0300 a $0305. Neste caso, o programa é:

LDX #$FF ; carregue X com $FF = 255
DES; X = X – 1
BNE$0302; se X não for zero, então vá para o loop
RTS; retornar

A partir do endereço $0200 na memória pode ser feita a chamada da sub-rotina. A instrução de chamada é:

Início JSR; start é o endereço $0300, ou seja, JSR $0300

A sub-rotina e sua chamada que estão devidamente escritas no arquivo do editor de texto são:

iniciar LDX #$FF; carregue X com $FF = 255
ciclo DEX; X = X – 1

circuito BNE; se X não for zero, então vá para o loop
RTS; retornar

Início JSR: pule para a rotina começando em $0300

Agora, pode haver muitas sub-rotinas em um programa longo. Todos eles não podem ter o nome “start”. Eles deveriam ter nomes diferentes. Na verdade, nenhum deles pode ter o nome “start”. “Iniciar” é usado aqui por motivos de ensino.

4.15 Traduzindo um Programa

Traduzir um programa ou montá-lo significa a mesma coisa. Considere o seguinte programa:

iniciar LDX #$FF : carregar X com $FF = 255
ciclo DEX: X = X – 1
Loop BNE: se X não for zero, então vá para o loop
RTS: retorno
Início JSR: pule para a rotina começando em $0300

Este é o programa que foi escrito anteriormente. Consiste na sub-rotina, início e na chamada da sub-rotina. O programa faz uma contagem regressiva de 255 10 para 0 10 . O programa começa no endereço inicial do usuário $0200 (RAM). O programa é digitado em um editor de texto e salvo no disco. Tem um nome como “sample.asm” onde “sample” é o nome de escolha do programador, mas a extensão “.asm” para a linguagem assembly deve estar associada ao nome do arquivo.

O programa montado é produzido por outro programa chamado assembler. O montador é fornecido pelo fabricante do 6502 µP ou por terceiros. O montador reproduz o programa de forma que ele fique na memória (RAM) enquanto ele é executado (run).

Suponha que a instrução JSR comece no endereço $0200 e a sub-rotina comece no endereço $0300. O montador remove todos os comentários e espaços em branco. Os comentários e espaços em branco desperdiçam a memória que é sempre escassa. Uma possível linha em branco entre o segmento de código da sub-rotina anterior e a chamada da sub-rotina é um exemplo de espaço em branco. O arquivo montado ainda está salvo no disco e tem um nome como “sample.exe”. A “amostra” é o nome de escolha do programador, mas a extensão “.exe” deve estar lá para indicar que se trata de um arquivo executável.

O programa montado pode ser documentado da seguinte forma:

Diz-se que produzir um documento como este é uma montagem manual. Observe que os comentários deste documento não aparecem na memória (para execução). A coluna de endereço da tabela indica os endereços iniciais das instruções na memória. Observe que “JSR start” que é “JSR $0300”, que se espera ser codificado como “20 03 00”, é na verdade codificado como “20 00 03” com o endereço de byte de memória inferior ocupando o byte inferior na memória e o endereço de byte de memória mais alto ocupando o byte mais alto na memória – pouco endianness. O código de operação para JSR é 20 16 .

Observe que o deslocamento para uma instrução de desvio como BNE é um número em complemento de dois no intervalo de 128 10 para + 127 10 . Portanto, “loop BNE” significa “BNE -1 10 ”que na verdade é “D0 FF” na forma de código de FF 16 é -1 em complemento de dois, que é escrito como = 11111111 na base dois. O programa assembler substitui os rótulos e campos por números hexadecimais reais (números hexadecimais são números binários agrupados em quatro bits). Os endereços reais onde cada instrução começa são incluídos.

Observação: A instrução “JSR start” é substituída por instruções mais curtas que enviam o conteúdo atual (bytes altos e baixos) do contador do programa para a pilha com o ponteiro da pilha que é decrementado duas vezes (uma para byte alto e outra para byte baixo) e em seguida, recarrega o PC com o endereço $0300. O ponteiro da pilha agora aponta para $00FD, assumindo que foi inicializado como $01FF.

Além disso, a instrução RTS é substituída por uma série de instruções mais curtas que incrementam o ponteiro de pilha “S” duas vezes (uma vez para o byte baixo e uma vez para o byte alto) e extraem os dois bytes de endereço correspondentes do ponteiro da pilha para o PC para a próxima instrução.

Observação: O texto da etiqueta não deve ter mais de 8 caracteres.

“Loop BNE” usa o endereçamento relativo. Significa adicionar -3 10 para o próximo contador de programa com conteúdo de $0305. Os bytes para “loop BNE” são “D0 FD” onde FD é o complemento de dois de -3 10 .

Nota: Este capítulo não apresenta todas as instruções para o 6502 µP. Todas as instruções e seus detalhes podem ser encontrados no documento intitulado “Família de microprocessadores SY6500 de 8 bits”. Existe um arquivo PDF com o nome “6502.pdf” para este documento que está disponível gratuitamente na Internet. O 6502 µP descrito neste documento é 65C02.

4.16 Interrupções

Os sinais de qualquer dispositivo conectado às portas externas (superfície vertical) do Commodore 64 devem passar pelos circuitos (ICs) CIA 1 ou CIA 2 antes de chegar ao microprocessador 6502. Os sinais do barramento de dados do 6502 µP devem passar pelo chip CIA 1 ou CIA 2 antes de chegarem a qualquer dispositivo externo. CIA significa Adaptador de interface complexo. Na Fig 4.1 “Diagrama de blocos da placa-mãe Commodore_64”, os dispositivos de entrada/saída do bloco representam o CIA 1 e o CIA 2. Quando um programa está em execução, ele pode ser interrompido para executar algum outro trecho de código antes de continuar. Há interrupção de hardware e interrupção de software. Para interrupção de hardware, existem dois pinos de sinal de entrada no 6502 µP. Os nomes desses pinos são IRQ e MNI . Estas não são linhas de dados µP. As linhas de dados para o µP são D7, D6, D5, D4, D3, D2, D1 e D0; com D0 para o bit menos significativo e D7 para o bit mais significativo.

IRQ significa Interrupt ReQuest “ativo” baixo. Esta linha de entrada para o µP é normalmente alta, aproximadamente 5 volts. Quando cai para aproximadamente 0 volt, é uma solicitação de interrupção que sinaliza o µP. Assim que o pedido for atendido, a linha volta a subir. Conceder a solicitação de interrupção significa que o µP desvia para o código (sub-rotina) que trata a interrupção.

MNI significa Interrupção Não Mascarável “ativa” baixa. Enquanto o código para IRQ está sendo executado MNI pode ir baixo. Nesse caso, MNI é tratado (seu próprio código é executado). Depois disso, o código para IRQ continuou. Depois do código para IRQ termina, o código do programa principal continua. Aquilo é, MNI interrompe o IRQ manipulador. O sinal para MNI ainda pode ser fornecido ao µP mesmo quando o µP está ocioso e não está manipulando nada ou não está executando um programa principal.

Observação: Na verdade, é a transição do alto para o baixo, de MNI , esse é o MNI sinal – mais sobre isso mais tarde. IRQ normalmente vem da CIA 1 e MNI normalmente vem da CIA 2. MNI , que significa Non-Maskable Interrupt, pode ser considerada uma interrupção ininterrupta.

Tratamento de interrupções
Se a solicitação é de IRQ ou MNI , a instrução atual deve ser concluída. O 6502 possui apenas os registros A, X e Y. Enquanto uma sub-rotina está operando, ela pode usar esses três registros juntos. Um manipulador de interrupção ainda é uma sub-rotina, embora não seja visto como tal. Após a conclusão da instrução atual, o conteúdo dos registradores A, X e Y do 65C02 µP é salvo na pilha. O endereço da próxima instrução do Contador de Programa também é enviado para a pilha. O µP então ramifica para o código da interrupção. Depois disso, o conteúdo dos registradores A, X e Y é restaurado da pilha na ordem inversa para a qual foram enviados.

Exemplo de codificação para uma interrupção
Para simplificar, suponha que a rotina para o µP IRQ interrupção é apenas somar os números $01 e $02 e salvar o resultado de $03 no endereço de memória $0400. O código é:

ISR PHA
PHX
FÍSICA
;
LDA#$01
ADC#$02
CUSTAM $ 0400
;
DOBRA
PLX
PLA
RTI

ISR é um rótulo e identifica o endereço de memória onde está a instrução PHA. ISR significa Rotina de Serviço de Interrupção. PHA, PHX e PHY enviam o conteúdo dos registradores A, X e Y para a pilha com a esperança de que sejam necessários para qualquer código (programa) que esteja sendo executado imediatamente antes da interrupção. As próximas três instruções formam o núcleo do manipulador de interrupções. As instruções PLY, PLX e PLA devem estar nessa ordem e trazem de volta o conteúdo dos registradores Y, X e A. A última instrução, que é RTI, (sem operando) retorna a continuação da execução para qualquer código (programa) que esteja sendo executado antes da interrupção. O RTI puxa o endereço da próxima instrução do código que está sendo executado da pilha de volta para o contador do programa. RTI significa ReTurn da interrupção. Com isso, termina o tratamento de interrupções (sub-rotina).

Interrupção de software
A principal maneira de interromper o software para o 6502 µP é com o uso da instrução de endereço implícito BRK. Suponha que o programa principal esteja em execução e encontre a instrução BRK. A partir desse ponto, o endereço da próxima instrução no PC deverá ser enviado para a pilha à medida que a instrução atual for concluída. Uma sub-rotina para lidar com as instruções do software deve ser chamada de “próxima”. Esta sub-rotina de interrupção deve enviar o conteúdo dos registradores A, X e Y para a pilha. Após a execução do núcleo da sub-rotina, o conteúdo dos registradores A, X e Y deve ser puxado de volta da pilha para seus registradores pela sub-rotina de conclusão. A última instrução da rotina é RTI. O conteúdo do PC também é retirado da pilha para o PC automaticamente devido ao RTI.

Comparação e contraste de sub-rotina e rotina de serviço de interrupção
A tabela a seguir compara e contrasta a sub-rotina e a rotina de serviço de interrupção:

4.17 Resumo dos principais modos de endereçamento do 6502

Cada instrução para o 6502 tem um byte, seguido por zero ou mais operandos.

Modo de endereçamento imediato
No modo de endereçamento imediato, após o operando, está o valor e não um endereço de memória. O valor deve ser precedido por #. Se o valor estiver em hexadecimal o “#” deverá ser seguido de “$”. As instruções de endereçamento imediato para o 65C02 são: ADC, AND, BIT, CMP, CPX, CPY, EOR, LDA, LDX, LDY, ORA, SBC. O leitor deve consultar a documentação do 65C02 µP para saber como utilizar as instruções aqui listadas que não são explicadas neste capítulo. Um exemplo de instrução é:

LDA #$77

Modo de endereçamento absoluto
No modo de endereçamento absoluto, existe um operando. Este operando é o endereço do valor na memória (geralmente em hexadecimal ou rótulo). Existem 64 mil 10 = 65.536 10 endereços de memória para o 6502 µP. Normalmente, o valor de um byte está em um desses endereços. As instruções de endereçamento absoluto para o 65C02 são: ADC, AND, ASL, BIT, CMP, CPX, CPY, DEC, EOR, INC, JMP, JSR, LDA, LDX, LDY, LSR, ORA, ROL, ROR, SBC, STA , STX, STY, STZ, TRB, TSB. O leitor deve consultar a documentação do 65C02 µP para saber como utilizar as instruções aqui listadas, bem como para os demais modos de endereçamento que não são explicados neste capítulo. Um exemplo de instrução é:

SÃO $ 1234

Modo de endereçamento implícito
No modo de endereçamento implícito, não há operando. Qualquer registro µP envolvido está implícito na instrução. As instruções de endereçamento implícitas para o 65C02 são: BRK, CLC, CLD, CLI, CLV, DEX, DEY, INX, INY, NOP, PHA, PHP, PHX, PHY, PLA, PLP, PLX, PLY, RTI, RTS, SEC , SED, SEI, IMPOSTO, TAY, TSX, TXA, TXS, TYA. Um exemplo de instrução é:

DEX: Diminui o registro X em uma unidade.

Modo de endereçamento relativo
O modo de endereçamento relativo lida apenas com instruções de desvio. No modo de endereçamento relativo, existe apenas um operando. É um valor de -128 10 para +127 10 . Este valor é chamado de deslocamento. Com base no sinal, este valor é adicionado ou subtraído da próxima instrução do Contador de Programa para resultar no endereço da próxima instrução pretendida. As instruções do modo de endereço relativo são: BCC, BCS, BEQ, BMI, BNE, BPL, BRA, BVC, BVS. Os exemplos de instruções são:

BNE $7F: (ramificação se Z = 0 no registro de status, P)

O que adiciona 127 ao contador do programa atual (endereço a ser executado) e inicia a execução da instrução nesse endereço. De forma similar:

BEQ $F9 : (ramificação se Z = : no registro de status, P)

O que adiciona -7 ao contador do programa atual e inicia a execução no novo endereço do contador do programa. O operando é um número em complemento de dois.

Endereçamento Indexado Absoluto
No endereçamento de índice absoluto, o conteúdo do registrador X ou Y é adicionado ao endereço absoluto fornecido (em qualquer lugar entre $0000 e $FFFF, ou seja, de 0 10 para 65536 10 ) para ter o endereço real. Este endereço absoluto fornecido é chamado de endereço base. Se o registrador X for usado, a instrução assembly será mais ou menos assim:

LDA $C453,X

Se o registrador Y for usado, será algo como:

LDA $C453,Y

O valor do registro X ou Y é chamado de valor de contagem ou índice e pode estar em qualquer lugar entre $ 00 (0 10 ) para $FF (250 10 ). Não é chamado de deslocamento.

As instruções de endereçamento de índice absoluto são: ADC, AND, ASL (somente X), BIT (com acumulador e memória, somente com X), CMP, DEC (somente memória e X), EOR, INC (memória e somente X), LDA , LDX, LDY, LSR (apenas X), ORA, ROL (apenas X), ROR (apenas X), SBC, STA, STZ (apenas X).

Endereçamento Indireto Absoluto
Isto é usado somente com a instrução de salto. Com isso, o endereço absoluto fornecido possui um endereço de ponteiro. O endereço do ponteiro consiste em dois bytes. O ponteiro de dois bytes aponta para (é o endereço) do valor do byte de destino na memória. Portanto, a instrução em linguagem assembly é:

JMP (US$ 3.456)

Com os parênteses, e $ 13 está no endereço $ 3.456, enquanto $ EB está no endereço $ 3.457 (= $ 3.456 + 1). Então, o endereço de destino é $13EB e $13EB é o ponteiro. O valor absoluto $3456 está entre parênteses na instrução onde 34 é o byte inferior e 56 é o byte superior.

4.18 Criando uma String com a Linguagem Assembly 6502 µP

Conforme demonstrado no próximo capítulo, após criar um arquivo na memória, o arquivo pode ser salvo no disco. O arquivo precisa receber um nome. O nome é um exemplo de string. Existem muitos outros exemplos de strings na programação.

Existem duas maneiras principais de criar uma sequência de códigos ASCII. Em ambos os sentidos, todos os códigos ASCII (caracteres) ocupam localizações de bytes consecutivos na memória. De uma das formas, esta sequência de bytes é precedida por um byte inteiro que é o comprimento (número de caracteres) da sequência (string). Por outro lado, a sequência de caracteres é sucedida (imediatamente seguida) pelo byte Nulo que é 00 16 , ou seja, $ 00. O comprimento da string (número de caracteres) não é indicado desta outra forma. O caractere Nulo não é usado da primeira maneira.

Por exemplo, considere o “Eu te amo!” string sem as aspas. O comprimento aqui é 11; um espaço conta como um byte ASCII (caractere). Suponha que a string deva ser colocada na memória com o primeiro caractere no endereço $0300.

A tabela a seguir mostra a configuração da memória de string quando o primeiro byte é 11 10 = 0B 16 :

A tabela a seguir mostra a configuração da memória de string quando o primeiro byte é “I” e o último byte é Nulo ($00):

A seguinte instrução pode ser usada para começar a criar a string:

CUSTAM $ 0300

Suponha que o primeiro byte esteja no acumulador que será enviado para o endereço $0300. Esta instrução é verdadeira para ambos os casos (ambos os tipos de strings).

Após encaixar todos os caracteres nas células da memória, um por um, a string pode ser lida por meio de um loop. Para o primeiro caso, o número de caracteres após o comprimento é lido. Para o segundo caso, os caracteres são lidos de “I” até que o caractere Nulo que é “Nulo” seja encontrado.

4.19 Criando um Array com a Linguagem Assembly 6502 µP

Uma matriz de inteiros de byte único consiste em localizações consecutivas de bytes de memória com os inteiros. Então, há um ponteiro que aponta para a localização do primeiro inteiro. Portanto, um array de inteiros consiste em duas partes: o ponteiro e a série de localizações.

Para uma matriz de strings, cada string pode estar em um local diferente na memória. Então, existem locais de memória consecutivos com ponteiros onde cada ponteiro aponta para o primeiro local de cada string. Um ponteiro, neste caso, consiste em dois bytes. Se uma string começa com seu comprimento, o ponteiro correspondente aponta para a localização desse comprimento. Se uma string não começar com seu comprimento, mas terminar com um caractere nulo, o ponteiro correspondente apontará para a localização do primeiro caractere da string. E há um ponteiro que aponta para o endereço de byte inferior do primeiro ponteiro de ponteiros consecutivos. Portanto, um array de strings consiste em três partes: as strings em diferentes locais da memória, os ponteiros consecutivos correspondentes e o ponteiro para o primeiro ponteiro dos ponteiros consecutivos.

4.20 Problemas

O leitor é aconselhado a resolver todos os problemas de um capítulo antes de passar para o próximo capítulo.

  1. Escreva um programa em linguagem assembly que comece em $ 0200 para 6502 µP e adicione os números sem sinal de 2A94 H (adicionar) a 2ABF H (aumento). Deixe as entradas e saídas estarem na memória. Além disso, produza manualmente o documento do programa montado.
  2. Escreva um programa em linguagem assembly que comece em $ 0200 para 6502 µP e subtraia os números sem sinal de 1569 H (subtraendo) de 2ABF H (minuendo). Deixe as entradas e saídas estarem na memória. Além disso, produza manualmente o documento do programa montado.
  3. Escreva um programa em linguagem assembly para o 6502 µP que conte de $ 00 a $ 09 usando um loop. O programa deve começar em $ 0200. Além disso, produza manualmente o documento do programa montado.
  4. Escreva um programa em linguagem assembly que comece em US$ 0.200 para 6.502 µP. O programa possui duas sub-rotinas. A primeira sub-rotina adiciona os números sem sinal de 0203 H (aumentar) e 0102H (acrescentar). A segunda sub-rotina adiciona a soma da primeira sub-rotina que é 0305H a 0006 H (aumento). O resultado final é armazenado na memória. Chame a primeira sub-rotina que é FSTSUB e a segunda sub-rotina que é SECSUB. Deixe as entradas e saídas estarem na memória. Além disso, produza manualmente o documento do programa montado para todo o programa.
  5. Dado que um IRQ manipulador adiciona $ 02 a $ 01 no acumulador como manipulação principal enquanto MNI é emitido e o tratamento principal para MNI adiciona $ 05 a $ 04 no acumulador, escreva uma linguagem assembly para ambos os manipuladores, incluindo suas chamadas. A chamada para o IRQ o manipulador deve estar no endereço $0200. O IRQ manipulador deve começar no endereço $0300. O MNI manipulador deve começar no endereço $0400. O resultado do IRQ manipulador deve ser colocado no endereço $0500, e o resultado do MNI manipulador deve ser colocado no endereço $0501.
  6. Explique resumidamente como a instrução BRK é usada para produzir a interrupção de software em um computador 65C02.
  7. Produza uma tabela que compare e contraste uma sub-rotina normal com uma rotina de serviço de interrupção.
  8. Explique resumidamente os principais modos de endereçamento do 65C02 µP, dados os exemplos de instruções em linguagem assembly.
  9. a) Escreva um programa em linguagem de máquina 6502 para colocar a mensagem “Eu te amo!” sequência de códigos ASCII na memória, começando no endereço $0300 com o comprimento da sequência. O programa deve começar no endereço $0200. Obtenha cada caractere do acumulador um por um, supondo que sejam enviados para lá, por alguma sub-rotina. Além disso, monte o programa manualmente. (Se você precisa saber os códigos ASCII para “Eu te amo!”. Aqui estão eles: ‘I’:49 16 , espaço: 20 16 , 'eu': 6C 16 , ‘o’:6F 16 , 'em': 76 16 , 'e':65, 'y':79 16 , 'em':75 16 , e ‘!’:21 16 (Nota: cada código ocupa 1 byte).
    b) Escreva um programa em linguagem de máquina 6502 para colocar a mensagem “Eu te amo!” sequência de códigos ASCII na memória, começando no endereço $0300 sem o comprimento da sequência, mas terminando em 00 16 . O programa deve começar no endereço $0200. Obtenha cada caractere do acumulador, supondo que eles sejam enviados para lá, um por um, por alguma sub-rotina. Além disso, monte o programa manualmente.