sexta-feira, 18 de dezembro de 2009

Programação Incondicional II

Em 1987, a Acorn lançou um micro de 32 bits impressionante: o Archimedes. Era o micro mais rápido e rodava a 4 MIPS. O processador tinha sido desenvolvido pela própria Acorn e chama-se ARM (Acorn RISC Machine). Hoje em dia, os processadores ARM estão por todas as partes, porque são usados em celulares. Como a Acorn não existe mais, a sigla passou a representar Advanced RISC Machine.

A primeira aparição do ARM foi como um segundo processador para o BBC. Como o BBC tinha um barramento (The Tube) de 1MHz especial para conectar outros processadores, havia uma oferta bem interessante de opções: Z80, 8086, 32016, etc. O mais comum, era ligar um Z80 para rodar CP/M ou um segundo 6502 a 4Mhz para rodar programas com mais velocidade e com mais memória (como o processador principal ficava encarregado do I/O, o secundário deixava até 44KB de memória livre para programas em BASIC).

Pois bem, com o contexto histórico estabelecido, vamos aos detalhes técnicos relevantes. O ARM é uma arquitetura RISC que faz uso de pipelines para melhorar o desempenho. E num processador com pipeline (acho que hoje em dia, todos têm), as instruções mais danosas são as de branch.

Para evitar quebrar o pipeline, os projetistas do ARM decidiram reaproveitar a lógica de comparação em todas as intruções. Em assembly de 6502, para decidir quando fazer um pulo, faz-se o seguinte:

CMP #FF ;Compara o acumulador A com &FF
BEQ .next ;Pula para .next se igual (Branch if EQual)

No ARM, cada instrução pode ser complementada com um teste.

Vamos comparar dois trechos de código que produzem o mesmo resultado. Em primeiro lugar, código com pulos tradicionais. Este é um algoritmo para encontrar o maior denominador comum:

gcd cmp r0, r1 ;Terminou?
beq stop
blt less ;se r0 > r1
sub r0, r0, r1 ;subtrai r1 de r0
bal gcd
less sub r1, r1, r0 ;subtrai r0 de r1
bal gcd
stop

Usando as instruções condicionais, o código fica muito mais compacto.

gcd cmp r0, r1 ;se r0 > r1
subgt r0, r0, r1 ;subtrai r1 de r0
sublt r1, r1, r0 ;ou subtrai r0 de r1
bne gcd ;terminou?

No segundo trecho, as instruções de subtração são complementadas com gt e lt. Conforme o resultado da instrução cmp, será executada a primeira ou a segunda subtração. Uma instrução que não é executada consome um ciclo, mas não quebra o pipeline. Além disso, o código fica muito mais compacto.

Estão prometidos há algum tempo netbooks com processadores ARM. Mal posso esperar!

Um comentário:

Marcus Aurelius disse...

Muito interessante. Com essas instruções, fica até mais fácil de ler o código, além de ficar mais eficiente!