Brain Dump

quinta-feira, 5 de novembro de 2009

Top 5 emuladores

Dia desses, um amigo me perguntou se eu conseguiria fazer uma lista com os meus cinco emuladores prediletos. Esse é o tipo de pergunta que, normalmente, é difícil de responder. Eu já escrevi um monte de emuladores, já conversei com inúmeros autores, e era de se esperar que fosse muito díficil criar uma lista assim. Afinal, sempre que você faz um top five, precisa deixar muita coisa bacana de fora, especialmente se você conhece bastante o assunto.



Porém, surpreendentemente, fazer a lista foi fácil! Tem cinco emuladores que se destacam, pela enorme influência que tiveram em tudo que se seguiu. Em ordem cronológica reversa:

VMware (2001)

No fim da década de 90, quando se falava em emuladores, imediamente as pessoas pensavam em videogames. O VMware trouxe de volta os emuladores ao mundo corporativo. As aplicações são inúmeras: desenvolvedores, por exemplo, podem programar no Linux, e testar a aplicação num Windows emulado. Em datacenters o impacto é ainda maior. Usando a versão ESX, os administradores de datacenter podem usar uma mesma imagem em todos os servidores, mesmo que eles sejam heterogêneos; e dá até pra trocar uma imagem de um servidor para outro enquanto ela está rodando, com downtime mínimo.

O truque do VMware pra conseguir desempenho é que a virtualização dele tenta evitar a emulação tanto quanto possível. Em algumas situações, como código rodando em user space, o VMware roda o código diretamente na CPU. Ele só usa emulação nos trechos críticos, como código rodando em kernel space, ou código acessando periféricos que foram virtualizados.

bleem (1999)

Se o VMware mudou a percepção que o povo da época tinha dos emuladores, o bleem foi igualmente importante, ao mudar a percepção do underground para o mainstream. Até então, emuladores de videogame eram um produto de nicho, conhecidos só por alguns poucos viciados em internet. O bleem, que na época era o melhor emulador de Playstation, levou os emuladores para as lojas. Hoje nós temos um mercado construído em cima da emulação de jogos, como prova o sucesso do Virtual Console no Wii, e quem começou esse mercado foi o bleem.

Mas pra mim o bleem tem um significado mais especial. Naquela época em que fazíamos emuladores, ninguém tinha muita certeza se nós estávamos dentro da legalidade ou não. Quando o bleem começou a bombar, a Sony processou os criadores do bleem, e depois de uma ferrenha briga judicial, o bleem saiu vitorioso. Eu passei a dormir mais tranquilo depois disso :)

O emulador de 8080 do Paul Allen (1975)

O Bill Gates sempre foi bom de blefe. Quando ele descobriu que a MITS estava fazendo o Altair 8800, ele entrou em contato com os fabricantes para oferecer um interpretador BASIC. Os fabricantes se empolgaram e marcaram uma reunião pra fazer uma demonstração. O problema é que não havia demo, foi tudo um blefe do Bill! Com a reunião marcada, ele e o sócio Paul Allen tiveram que correr pra preparar um demo a tempo. O blefe era tão vazio, que eles nem tinham um Altair pra poder programar.

Como criar um interpretador para o Altair, sem ter um Altair? A solução que eles encontraram foi a emulação. Enquanto o Bill Gates escrevia o interpretador, o Paul Allen escreveu um emulador de 8080, a CPU usada no Altair. Como eles também não tinham computador pra rodar o emulador, testavam o software deles no PDP-10 da Harvard, a faculdade onde estudavam. No final, eles acabaram a tempo, e criaram a Microsoft para vender aquele interpretador. Poucos emuladores podem ser tão influentes assim :)

IBM System/360 (1964)

Tem muitas coisas que são naturais para nós, mas que eram o ápice da inovação no passado. Upgrades, por exemplo. Hoje em dia, se o seu programa está rodando muito lento, você pode comprar um computador mais novo e o programa rodará mais rápido. Mas antigamente isso não era verdade: se você comprasse um computador novo, iria precisar de um software novo também. Não existia portabilidade.

A IBM mudou isso com o IBM System/360, uma família de computadores projetada com a compatibilidade em mente. Você poderia comprar um System/360 pequeno, e se precisasse de mais processamento, era só comprar um modelo maior, rodando o mesmo software. E se não bastasse isso, a IBM ainda garantia compatibilidade com modelos anteriores ao System/360! O segredo, é claro, era emulação: a IBM criou emuladores de seus sistemas mais antigos e populares. Não por acaso, o System/360 foi o computador mais vendido de sua época.

A máquina universal de Turing (1936)

No começo do século XX, os matemáticos estavam procurando a solução do Entscheidungsproblem: existe um processo capaz de decidir se uma expressão matemática é verdadeira ou não? Na época ainda não existia o conceito de algoritmo, o Turing teve que partir do zero. Ele construiu um modelo computacional, a máquina de Turing, e a usou pra chegar na decepcionante conclusão de que o tal algoritmo de decisão não existe. Por outro lado, ele concluiu que, para todos os algoritmos que existem, também existe uma máquina de Turing capaz de executá-lo (essa é a tese de Church-Turing).

Mas o Turing foi além. Baseado no trabalho do Gödel, ele concebeu uma máquina de Turing mais poderosa, que era capaz de rodar qualquer algoritmo que outra máquina de Turing conseguisse. O truque, como vocês devem ter deduzido, é usar emulação. As máquinas universais de Turing não apenas são o modelo matemático que permite a existência de emuladores, como também de toda a computação.

Marcadores: , ,

sábado, 25 de outubro de 2008

Dez anos de MUST

É díficil achar alguém na faixa dos 30 anos que trabalhe com computadores e não conheça o MSX, um computador pessoal de 8 bits que fez um sucesso enorme por aqui. No seu auge, entre 85 e 91, estima-se que mais de 400 mil máquinas tenham sido vendidas no Brasil.

Mas embora esse período tenha sido o auge em número de usuários, não foi o ápice na parte técnica. Os mais avançados softwares brasileiros de MSX foram feitos no período de 1996 a 2004, e há dois motivos pra isso. O primeiro é que esse foi o início da internet comercial, então muitos dos manuais e datasheets que antes eram raros, passaram a ser difundidos livremente pelas listas de discussão. O segundo é que essa também foi a época em que começaram a se formar os primeiros engenheiros que cresceram com o MSX na infância, e toda essa criançada estava sedenta pra usar os novos conhecimentos na sua velha maquininha.

Eu mesmo fiz um monte de brincadeiras nessa época, talvez a mais conhecida tenha sido o meu emulador BrMSX. Mas agora, em 2008, um outro software que fiz completa dez anos, e nada mais apropriado que comemorar com um detalhado making of. Apresento a vocês o Music Station, ou como também era carinhosamente conhecido, o MUST:


Vamos voltar uma década no tempo: em 1998, a internet crescia, nasciam os primeiros grandes portais nacionais, e começava a surgir uma prática que hoje em dia é extremamente comum: o compartilhamento de músicas em mp3. Primeiro por FTP e IRC, depois pelo Napster e Audiogalaxy, em pouco tempo os arquivos mp3 estavam por toda a parte.

Naturalmente, quem ainda brincava com o MSX também queria entrar na onda. Mais de uma vez me perguntaram "Ricardo, você não pode fazer um programinha pra tocar mp3 no MSX?". Qualquer criatura com um mínimo de bom senso iria perguntar "pra quê?". Mas bom senso nunca foi o meu forte :)

Eu já sabia de antemão que mp3 no MSX não era viável, o coitado do Z80 não iria dar conta. Mas a essa altura eu já sabia evitar um erro muito comum em desenvolvedores, o de prestar atenção no que o usuário pede, ao invés de focar no usuário quer. Sure, eles estavam pedindo mp3, mas o que eles queriam mesmo era só tocar música no MSX. Se fosse um outro formato qualquer não faria diferença. Como eu tinha acabado de cursar Processamento Digital de Sinais na Poli (com o saudoso prof. Max Gerken), achei que poderia encarar a construção de uma solução customizada pro MSX.

Hora de calibrar os objetivos: eu decidi fazer um player que tivesse a melhor qualidade possível pro MSX, que rodasse em qualquer modelo de MSX, incluindo os nacionais, e que conseguisse espremer pelo menos um minuto de música em uma MegaRAM de 256kb, o modelo mais comum. O primeiro passo, portanto, é ver se o MSX dá conta de tocar um sample com qualidade aceitável.

O MSX usa como gerador de som o chip AY-3-8910 (popularmente PSG), que é basicamente um gerador de ondas quadradas. Pra tocar um Lá central, você especifica a freqüência de 440Hz, acerta o volume apropriado, e se diverte com o barulhinho que ele produz. Se você for um mago do chiptune, dá pra fazer músicas bem legais com o PSG, mas definitivamente ele não foi feito pra reprodução de áudio digital. Para conseguir isso, nós temos entender como o chip funciona por dentro.

Internamente, o gerador de ondas quadradas é só um contador digital, que alterna o estado de um flip-flop depois do término de meio período. O chip tem três geradores que você pode ligar ou desligar de maneira independente através de um mixer. Quem tem experiência com chips TTL sabe que sinais desligados usualmente não são interpretados como nível lógico zero, mas sim como nível lógico um.

Pro nosso ouvido tanto faz, um sinal constante é silêncio sempre, independente dele estar em zero volts ou em cinco volts, mas o segredo da coisa é que o controle de volume é uma etapa analógica feita depois do mixer. Por isso, se você desligar o gerador através do mixer, e mudar bem rapidamente o controle de volume, você pode improvisar qualquer forma de onda que quiser! Como o PSG tem 16 volumes possíveis, isso significa que o MSX pode emular um PCM de 4 bits, mesmo sem ter sido projetado pra isso.

Quando o sinal está em nível lógico um, basta variar o volume!

Agora basta ligar esse PCM num timer de alta resolução e pronto. Quer dizer, exceto pelo fato do MSX não ter um timer de alta resolução. O melhor que ele tem é um timer que dispara no início do retraço vertical, a 60Hz, que é uma freqüência baixa demais pra gente. Nesse caso, o jeito é apelar pra gambiarra criatividade :)

Como o Z80 do MSX não tem cache, nem prefetching, nem nenhuma dessas firulas de processadores modernos, os opcodes sempre levam o mesmo tempo pra rodar. Assim, você pode criar um pseudo-timer simplesmente contando quantos ciclos de clock seu programa leva pra executar. Se nós precisássemos de uma rotina que lesse um byte da memória, mandasse pro PSG, e levasse exatamente 50 clocks pra rodar, uma possibilidade seria:

LD A,(HL) ; 8 clocks
LD A,(HL) ; 8 clocks
INC HL ; 7 clocks
OUT (0A1h),A ; 12 clocks
NOP ; 5 clocks
NOP ; 5 clocks
NOP ; 5 clocks

Pra fazer um timer assim, além de programar em assembly, você ainda precisa resolver um subset sum dos opcodes, o que é extremamente divertido (eu assumo que se você está lendo até aqui, deve achar essas coisas divertidas também :). Note como é importante fazer o padding correto, além de colocar 3 NOPs, eu também repliquei o carregemento da memória, só pra fazer a conta bater certinho nos 50 clocks.

Agora que temos um jeito de reproduzir o som, precisamos escolher a sampling rate. Pra conseguir o objetivo de 1 minuto em 256kb, o áudio certamente terá que ser comprimido. Então a sampling rate precisa ser baixa o suficiente pra poder suportar a descompressão em real time entre cada amostra, e alta o suficiente pra não perder muita qualidade de som. Eu escolhi 11kHz; como o clock do MSX é 3.57MHz, isso dá um total de 324 clocks por amostra. Não é muito, mas alguma compressão dá pra fazer.

Vamos calcular a compressão agora. Pra colocar 60 segundos a 11kHz em 256kb, nós precisamos de, no máximo, 256k*8/60/11k = 3.1 bits por amostra. Nosso sinal original tem 4 bits por amostra, então realmente a compressão é necessária. O Z80 não tem fôlego pra implementar transformadas, então não podemos usar nada de DCT, e nem mesmo Haar.

O jeito é modelar alguma coisa bem simples mesmo, tipo um código de tamanho variável como o código de Huffman. Esse tipo de código funciona tanto melhor quanto menos uniforme for o seu histograma. Pegando uma música típica como teste, chegamos em uma entropia de 2.6 bits; mas, por outro lado, a primeira diferença tem entropia ainda menor, apenas 2 bits!


Vamos codificar a diferença então. Com apenas 324 clocks não dá pra implementar todo o Huffman, mas tem uma maneira de simplificar, que é usando compressão com perdas. Como 99.3% das diferenças estão na faixa de -3 a 3, eu posso saturar nesses valores pra deixar o código mais simples. O código que utilizei foi o abaixo:

3 1111
2 1110
1 01
0 00
-1 10
-2 1101
-3 1100

No final a implementação desse código ficou menor do que eu esperava, apenas 169 clocks. Isso significava que eu tinha 198 clocks sobrando, com a cpu parada. Eu poderia ter aprimorado o codec com uma compressão mais eficiente, mas pensei que seria mais divertido, ao invés disso, usar esses clocks sobrando pra adicionar animações. Nesses clocks sobrando eu acabei colocando um osciloscópio com a forma de onda tocada, um banner animado na parte inferior, e no cantinho ainda sobrou cpu pra colocar um pingüim dançando!

Nesse ponto tudo que faltava era uma tela de abertura. Como no final o programa acabou ficando uma experiência multimídia, eu resolvi que ele seria uma homenagem à série Disc Station da Compile, que primava por seus excelentes demos. Eu chamei então o meu programinha de Music Station, e como os Disc Station originais sempre começavam com uma menina bonitinha, eu pedi ao meu irmão que desenhasse uma pingüinha no mesmo estilo. O desenho original que ele fez foi o abaixo:

Adaptar desenhos no MSX é tão complicado quanto adaptar código, a resolução é de apenas 256x192 e ainda tem o problema do color clash (cada bloco de 8x1 pixels pode ter no máximo duas cores). O pingüim tomando sol no canto da imagem teve que sumir, eu não tinha resolução pra isso. Já na pingüinha, eu tive que usar traços bem grossos no contorno, pra minimizar o clash, mas mesmo assim ainda sobraram algumas partes borradas. A solução foi usar sprites pra cobrir esse borramento.

Consegue achar as diferenças?

Por fim, bastou criar um logo, inspirado no logo original do Disc Station, e o MUST estava finalmente pronto! Pra quem quiser brincar com ele, abaixo tem uma versão em .dsk que pode ser carregada em emuladores, como o blueMSX ou o openMSX, e também o código fonte original.

Imagem de disco para rodar em emuladores
Código fonte original do Music Station, em assembly Z80

Na época, a comunidade MSX adorou o MUST. Como eu esperava, o pessoal começou a compartilhar músicas convertidas, do mesmo jeito que o povo do PC compartilhava mp3; e como eu publiquei a engine do MUST em GPL, um monte de gente reaproveitou o código, sendo que a engine foi usada até em joguinhos. Eu até animei a fazer uma versão com vídeo também, mas isso já é outra história, pra outra ocasião :)

Parabéns pelos dez anos, Music Station!

Agradecimentos à Ila, ao Acidx e ao Sturaro por ajudar na arqueologia digital :)

Marcadores: , , , , , ,

quarta-feira, 18 de junho de 2008

Um cientista em minha vida


Eu li lá no blog do Kentaro que o meme da semana era "Um Cientista em minha vida", onde deveríamos falar sobre algum cientista que fez a diferença pra você. Como eu adoro constrained writing, resolvi participar (na verdade, eu adoro constrained anything, por isso que vivo criando programas em uma linha, programas que rodam em computadores de 8 bits, e assim por diante).

Eu já falo de cientistas aqui todo o tempo. Olhando no histórico, eu já falei do Knuth, do Erdös, do prof. Routo, do prof. Henrique, e de vários outros. Em comum, todos eles foram cientistas que eu conheci depois de adulto. Achei apropriado então que eu falasse de um cientista que fez a diferença quando eu era criança, e pra isso vamos ter que rebobinar até a década de 80.

Se você perguntar pra alguém sobre revistas de computador na década de 80, invariavelmente irá ouvir sobre a Micro Sistemas ("a primeira revista brasileira sobre microcomputadores"). A Micro Sistemas era muito legal, mas o que eu gostava mesmo era de outra revista, menos conhecida, chamada Microhobby.

A diferença da Micro Sistemas pra Microhobby era mais ou menos a diferença de Informática pra Computação. Na primeira, nós ficávamos encantados com as notícias da maravilhosa terra além da reserva de mercado (onde aprendíamos que a Apple planejava lançar um novo computador chamado McIntosh, que vinha com um periférico estranho e esquisito chamado mouse), enquanto que na segunda aprendíamos a calcular geodésicas e a usar o método de Bolzano para achar raízes de uma equação.

Mas o diferencial mesmo da Microhobby eram as colunas escritas pelo Renato da Silva Oliveira. Uma googlada rápida revela que o Renato é formado em Física, trabalhou nos planetários de São Paulo, Campinas, Vitória e Tatuí, e atualmente trabalha em uma empresa que vende planetários infláveis (how cool is that?!). Mas é claro que eu não sabia disso na época, o que eu sabia era que ele contava historinhas!

Foi lendo as historinhas do Renato que eu descobri que era possível escrever sobre ciência e computação, com clareza e bom humor. Pena que isso ainda não é muito difundido, a julgar pela quantidade de crianças que ainda acham que ciência é uma coisa chata :(

As historinhas que ele escrevia sempre tinham o mesmo formato: um certo sr. Nabor Rosenthal, em suas viagens pelo mundo, deparava-se com alguma situação que sugeria uma análise matemática (os tópicos eram os mais variados e iam de teoria dos grafos até contatos com extraterrestres). Depois de ponderar sobre o problema sem conseguir resolvê-lo, o Nabor tomava uma dose do raro Suco de Ramanujan, que o colocava num transe que ampliava suas capacidades analíticas, e conseguia solucionar o problema.

Mas a coluna sempre acabava antes que o Nabor mostrasse qual a solução! Ao invés disso, o leitor tinha um mês pra conseguir resolver o problema, e só no mês seguinte a solução era apresentada. Na década de 80 ainda não tinha spoj, então as colunas do Renato eram o que bombava pra quem gostava de puzzles computacionais.

Um dos puzzles apresentados foi o segundo puzzle mais difícil da minha vida, eu levei mais de dez anos pra conseguir resolver. Em uma das Microhobby, o Nabor entrou em transe após tomar o Suco de Ramanujan, e durante o transe ele sonhou "com um método para calcular o número pi, usando apenas o gerador de números aleatórios de seu micro" (essa era a época onde o micro mais avançado era o TK-82C, com 2kb de RAM).

Na época eu pensei muito e não consegui solucionar, achando que ia precisar de alguma matemática que eu ainda não tinha aprendido. Eu nunca consegui achar a revista seguinte com a solução, tive que passar pelo primário, pelo colégio técnico, e só no meio da faculdade é que caiu a ficha (e eu percebi que poderia ter solucionado ainda no primário, se tivesse insistido o suficiente :)

O truque é o seguinte: você vai fazer N experimentos, cada um consistindo no sorteio de dois números aleatórios escolhidos uniformemente entre 0 e 1. Se soma dos quadrados dos números for menor ou igual a 1, incremente um contador (digamos, M). Ao final dos experimentos, pi=4*M/N. O script abaixo implementa esse algoritmo:

Script em python para calcular pi usando números aleatórios

O funcionamento é bem simples e baseia-se na figura ao lado. Você começa inscrevendo um quarto de círculo num quadrado de lado 1. Os dois números que você sorteia a cada iteração podem ser interpretados como um ponto dentro do quadrado, e o teste feito é equivalente a testar se o ponto está dentro do círculo ou não. Como a distribuição dos pontos é uniforme, espera-se que a razão M/N seja igual à razão entre as áreas da figura. A área do quadrado é 1, a área do círculo é pi*r2. Como o raio é unitário, então a área do quarto de círculo é pi/4. Isolando pi, chega-se em pi=4*M/N, QED.

A pergunta que deve ser feita ao encontrar qualquer algoritmo novo é: qual é sua complexidade? Infelizmente, esse método aleatório é bem ruim. No fundo, o que estamos fazendo é aproximar pi por uma fração, cujo denominador é N. Então a precisão máxima que podemos obter é 1/N, e se você quer calcular n dígitos de pi, esse método converge, no melhor caso, em O(10n), e na prática em bem menos que isso, porque os seus geradores de números aleatórios não são perfeitamente uniformes.

Eu nunca soube qual o método que o Nabor usou pra calcular o pi. Como ele tinha o Suco de Ramanujan e eu não, espero que tenha sido um método melhor que o meu :)

Marcadores: , , , , , ,