Thiago Cantero

Tecnologia e Entretenimento

Arquitetura de HardwareAssemblyHistórialinguagem de programaçãoMSXRetrocomputaçãoSistemas OperacionaisZ80

Como as Linguagens de Programação se comportam? Parte I

Olá, mundo!
Tudo bem?

Estou de volta, após mudanças, trabalho, uma série de variáveis que tomaram muito tempo e, me impossibilitou de trazer boas novas, mas o bom filho volta à casa! ; )

Hoje trago um assunto que sempre me fascinou, a programação de baixo nível. Lembro-me de quando garoto, nos livros da Editora Aleph sobre MSX, tratar sobre Assembly do Z-80 (processador que compunha aquela maravilhosa arquitetura). Em que era possível tirar o máximo de possibilidades do MSX, levando a imaginar o que era tão mágico que pudesse nos ofertar!
Naquela época não imaginava, pois tudo que eu sabia eram apenas algumas palavras reservadas de BASIC, em extensas listas de rotinas. Não conseguia abstrair como era possível ter muitas sonoridades, figuras, em uma mesma plataforma. Achava realmente que aquilo tudo era mágica!

E claro!Como diz Isaac Asimov: “A história é cheia de Charlatões e falsos messias!”. Mas não aqui, meu caro leitor! Aqui colocaremos os feitos devidos, em hipótese alguma, não iremos deixar os devidos créditos.

Os processadores, como conhecemos hoje, são baseados na Arquitetura de Von Neumann, logo as explanações ao longo deste artigo deve a este genial matemático.

Por trás desta “magia” havia uma estrutura complexa que possibilita obter recursos mais profundos do processador, placa de vídeo/som, etc, para isso se valiam de compiladores, bibliotecas otimizadas que contribuem para este feito.

Introdução

E após este breve e apaixonado relato, aqui me coloco para explanar a arquitetura do nosso querido Z-80, dentre desta breve introdução e, consequentemente desenvolvimento desta primeira Parte desta série, iremos ver o funcionamento do Assembly para esta arquitetura que não só foi o Coração do MSX, mas sim de muitas outras plataformas, como: Master System, Game Boy, Game Boy Color e outras fascinantes máquinas do entretenimento.
O intuito aqui é expor de maneira bem sútil como é a arquitetura de um processador, o Z-80 foi a escolha pelo fato de ser minimamente mais fácil de compreender do que um processador atual, no entanto os conceito aplicam-se a qualquer arquitetura (RISC ou CISC), tentarei ser o mais breve, pois há muita complexidade envolvida, tentarei abstrair e resumir o máximo. Caso se interesse, recomendo Sistemas Operacionais Modernos, de Andrew S. Tanembaum.

undefined
Diagrama do Z80, obtida no Wikipedia. Disponível em: https://en.wikipedia.org/wiki/Zilog_Z80#/media/File:Z80_arch.svg

Na figura acima, podemos ver o coração pulsante de nossa máquina, comentários à parte vamos ao que interessa!

Basicamente o processador se divide em:

  • Unidade de Controle: responsável para a busca e definição de cada instrução;
  • Unidade Aritmética Lógica: responsável para realizar as operações da execução das instruções, através do conceito Booleano, do modelo do Matemático George Boole;
  • Registradores: Memórias de alta velocidade, que armazenam as informações (bits), no caso de nosso modesto e poderoso z-80, haverá dois tipos (principal e alternativo), estes terão a premissa de armazenar o endereço para a próxima instrução, a instrução que está sendo executada, etc.

Esta arquitetura explanada, é apenas a parte interna do processador, para se comunicar com outros co-processadores, como por exemplo, de Som, Vídeo, utilizamos os barramentos.

Os barramentos são vias em que se comunica com os demais dispositivos de entrada e saída, como teclado, vídeo, impressora. Na arquitetura do MSX temos os três circuitos que auxiliam o processador principal nesta demanda o: 8255A (controla os periféricos como teclado e gravador de cassete), TMS9128A (A nossa “placa de vídeo”) e, o AY8910 (a nossa “placa de som”).

Um fator importante este processador roda a 3,58Mhz, o que corresponde ao que fosse realizar, em apenas um segundo, quase um milhão de operações elementares, o que para época em que fora lançado, 1976, era um grande avanço para os microcomputadores.
Toda informação, em se tratando de informática se dá pelo bit, que nada mais é do que um pulso elétrico, logo o nosso processador consegue atuar com 8 bits, ou seja 1 Byte, no entanto para endereçamento de Memória ele consegue atuar em 16bits, conseguindo alocar 64Kbytes, o que para época era bem interessante, levando em consideração que se tinha lá pelos fins de 1970, quando a Intel também tinha já lançado o seu 8080.

Bom, aqui de maneira bem, mas bem sintetizada, explanei sobre a arquitetura de um processador.

Assembly

Assembly ou linguagem de montagem é uma notação legível por humanos para o código de máquina que uma arquitetura de computador específica usa, utilizada para programar códigos entendidos por dispositivos computacionais, como microprocessadores e microcontroladores. O código de máquina torna-se legível pela substituição dos valores em bruto por símbolos chamados mnemónicos  – Wikipedia

A linguagem Assembly, como a definição nos demonstra, vem da característica de montar conforme sua respectiva característica, ou seja, todo Processador, seja ele uma arquitetura X86_64, PPC, IA-32, ARM terá seu Assembly, pois iremos mexer nas estruturas internas do dispositivo.

E por que devemos entender assuntos como este?!Entender Assembly o fará entender o suficiente como as coisas realmente funcionam no campo da informática, como já exposto as chamadas de Sistemas por APIs dos Kernel (artigo), Gerenciamento de Memória (artigo), além de entender com propriedade o funcionamento de um compilador, por exemplo.

Existem, nas sintaxes da linguagem, as instruções do Processador, além de apelidos que poderemos definir ao longo do código, exemplo:

PRINCIPAL: sempre que iremos definir um apelido para nosso bloco de código, colocaremos a palavra, seguida de dois pontos.

Em nosso exemplo inicial, iremos colocar nas informações da BIOS, após o CHKRAM do MSX, em que neste passo ele verifica as condições da RAM e se há Cartuchos inseridos nos MSX e, após este verificação, carrega a ROM do MSX-BASIC o nosso interpretador. Naquela época não existia o POST (Power on Self-Test) das BIOS de Arquiteturas x86 compatíveis com IBM PC AT, M68k (Commodore Amiga 1000-4000).

O Assembly é a linguagem mais primitiva que existe, já que o Compilador traz melhorias diversas em relação,  falaremos de Compiladores no próximo post sobre o tema.

Vamos ao Trabalho\\

Faremos, como em toda linguagem, um exemplo contendo “Olá, Mundo”.

; Realiza a chamada na Bios para imprimir
CHPUT:      equ 0x00a2

            ; Endereço de Nosso Programa
            org 0xD000

start:
            ld hl, texto
Principal:  ld a, (hl)
            cp 0
            ret z
            call CHPUT
            inc hl
            jr Principal

texto:
            db "Ola, Mundo em Assembly!",0

            ; A pseudo instrução start funcionará como a entry point de nossa aplicação, algo como main() do Java, C, C++, C#, Go, etc.
            end start

O Código acima nos dá a seguinte condição. Os comentários em Assembly são com “;” há um apelido CHPUT seguido pela instrução equ, que funciona como um aliás para apontar o endereço da BIOS que é o 0x00a2, na sequência vem a instrução org que determina o endereço em memória da execução de nosso programa.

O bloco start: possui a instrução ld hl, texto, aqui começamos a mexer com a parte interna do processador, os registradores. Neste caso carrego no registrador HL, a string Texto lá abaixo no código. Este bloco será nossa Entry Point, como uma aplicação em GO, Java, C# com seus métodos principais.

O Bloco Principal: novamente instruo o processador a carregar um registrador ld a, (hl), o que está já contido em outro Registrador hl, entre parênteses. Após instruímos com a instrução cp esta compara os bytes dos registradores, aqui não iremos realizar tal operação, para tanto, iremos valorar com 0. A instrução ret z aciona o registrador Z, atuando como uma Flag.

A instrução call realiza a chamada da subrotina CHPUT que já citamos anteriormente, ela será responsável por disponibilizar o endereçamento da BIOS. Logo após inc hl realiza incremento no Registrador HL. Por fim, a instrução jr Principal fará o Jump, ou seja, irá pular para a rotina Principal e sua total execução.

No bloco texto: temos a instrução db (databytes) esta terá a função de transportar para os registradores nosso valor em string, o valor fica entre ” “, e finaliza com 0. E encerramos o código com a instrução start end.

O resultado é este:

Existem muitas instruções que podem fazer otimizações realmente muito satisfatórias, até mesmo para o Z80.

Quando compilamos um código, o ato de compilar deixa ele com a semântica para a máquina executar, já falei sobre a diferença entre linguagens compiladas e interpretadas aqui.

As linguagens de programação funcionam desta maneira, mais crua, na camada de Hardware, obviamente que além desta natureza mais crua, há também a participação do Sistema Operacional, como o Gerenciamento de Memória, aplicando os algoritmos FIFO (First In-First Out), LIFO (Last In-Last Out). Entre outros algoritmos e serviços envolvidos, como servidores de impressão, gráfico, etc.

Por hoje é só pessoal, até mais breve ; )

Referências

Z80 Heaven – http://z80-heaven.wikidot.com/

O Livro Vermelho do MSX, Avalon Software, editora McGraw Hill.

Introdução à Linguagem de Máquina para MSX, editora Ciência Moderna.

Aprofundando-se no MSX, editora Aleph

 

A história é cheia de Charlatões e falsos messias – Isaac Asimov