segunda-feira, 14 de agosto de 2017

Nesse mês o meu emulador BrMSX faz 20 anos! (sim, estamos velhos)

 Para comemorar, eu coloquei no github todos os fontes. Por todos eu quero dizer *todos mesmo*, eu fui nos backups, recuperei os fontes de todas as versões, e criei um repositório onde cada versão é um commit. Consegui salvar também as descrições originais; e até a data e hora de cada release.

 Curiosidades:

 - O primeiro commit é de 29 Aug 1997, o último é de 10 May 2000, foram quase 4 anos de desenvolvimento contínuo.

 - A maioria dos commits é de sábado e domingo (eu estudava durante a semana), mas aparentemente eu programava bastante de terça à tarde também.

 - O desenvolvimento da versão MSX2 começou em 11 Jul 1999 com release em 29 Jul 1999 (claramente eu esperei as férias para fazer uma mudança tão grande).

 - As primeiras linhas que eu escrevi não mudaram do começo ao fim! É a função readmem no brmsx.asm, se você der um git blame dá para ver que ela é a mesma desde o primeiro commit. Ela também é o caminho crítico, a função que mais é executada no emulador:

readmem:
mov esi,ecx
mov ebx,ecx
shr esi,13
and ebx,01fffh
mov esi,[offset mem+esi*4]
mov al,byte ptr [esi+ebx]
ret 

Para quem quiser se divertir, o link é o abaixo.

 https://github.com/ricbit/brmsx/commits/master

 (Deu um trabalhão do inferno reconstruir o repositório, espero que alguém mais goste haha)


sábado, 5 de agosto de 2017

Brinquedo do dia: fiz uma ferramenta de code coverage para Assembly Z80!

Mês passado eu tinha feito um parser de json em Assembly Z80, e fiz um monte de unit tests para garantir que estava direitinho. Mas aí eu pensei que só unit test não é suficiente, eu precisava também de code coverage para garantir que não esqueci de testar nenhum code path.

Escrever a ferramenta foi fácil, um plug-in em TCL pro openmsx e um script python para gerar o html. O que eu não esperava é que eu fosse realmente achar um bug com ele!

A história é que eu otimizei esse parser por espaço, e usei um monte de truques bem sujos para isso. Um deles é esse aí da foto, que eu chamo de "saltar no meio". Funciona assim: a rotina get_json_action tem dois entry points, um que chama com o registro A zerado (get_token_type), e outra que chama com o A não-zero (get_token_value).

O natural seria a primeira ter um XOR A para zerar o registrador, e a segundo um LD A,1 ou algo do tipo para setar com não-zero. Mas eu fiz diferente: usei os opcodes 3E AF em seguida. Se você executar a partir do 3E, o Z80 entende como LD A, 0xAF, que é não-zero. Se você rodar a partir do AF, ele entende como XOR A, que é zero. Eu saltei no meio do opcode e salvei alguns bytes assim.

O problema é que o wiring estava errado! Na hora de inicializar os ponteiros, eu fiz get_token_value = get_token_type + 1, quando deveria ser get_token_type - 1. E os unit tests não pegaram, porque, por coincidência, no turboR o registro A sempre estava não-zero naquele ponto. Ia passar batido, se a ferramenta de coverage não tivesse me avisado que aquele 3E nunca estava sendo executado!

Para quem ficou curioso, aqui o report mostrando o erro:

http://www.ilafox.com.br/ricbit/coverage_error.html 

E os scripts de coverage estão no repositório do msxjson:

https://github.com/ricbit/msxjson

sexta-feira, 4 de agosto de 2017

Fiz mais um open source de sucesso!

Antes de mais nada, como você define um open source de sucesso? Você poderia medir número de usuários ativos, ou algo nessa linha, mas a minha métrica é diferente: o código open source é de sucesso se ele foi reusado por mais pessoas em outros projetos. E aconteceu isso com meu script de músicas em formato VGM!

Lá por volta de 2014 eu estava com uma música de MSX que foi escrita no formato PLAY do BASIC, e precisava passar isso para Assembly. A maneira natural seria converter nota por nota, mas acabei tendo uma idéia melhor. O emulador openmsx permite que você crie plug-ins usando TCL, então eu criei um plug-in que chama o interpretador BASIC, toca a música, e captura o conteúdo dos registros do PSG e do OPLL.

Para mim já era o suficiente, mas aí eu pensei que poderia transformar isso num utilitário de uso geral, se eu guardasse o dump dos registros em um formato conhecido. Acabei fazendo um script que converte a música no formato VGM (video game music):

 https://github.com/ricbit/Oldies/blob/master/2014-11-grabfm/grabfm.tcl 

 Em 2015 o Grauw (da Holanda), pegou o meu script e fez uma versão que captura não só músicas em BASIC, mas em qualquer ambiente (jogos, por exemplo):

https://bitbucket.org/grauw/vgmplay-msx/annotate/536b64e03ffcc5c28e2b65deaa54f213b01abb90/tools/vgmrec.tcl?at=default&fileviewer=file-view-default 

 Depois o Niek (também da Holanda), pegou a versão do Grauw e adicionou suporte a outros chips de som (SCC, MSX-Audio e Moonsound):

 https://github.com/niekvlessert/openmsx_tcl_vgm_export/blob/master/vgmrecorder.tcl 

 Por fim, hoje esse código foi integrado na main branch do openmsx, agora ele é distribuído como plug-in oficial do emulador:

 https://github.com/openMSX/openMSX/blob/master/share/scripts/_vgmrecorder.tcl 

 Coloquei na web meio de farra e acabou sendo útil para um monte de gente :)

 (Na foto a fita original do Death Wish 3, que tem uma das melhores músicas do MSX. Na verdade essa fita de brinde num lote, o que eu tinha comprado mesmo era a fita do Goody, que é um jogos prediletos da Ila Fox).