<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Emulacao | AkitaOnRails.com</title><link>https://akitaonrails.github.io/tags/emulacao/</link><description>Blog do Fabio Akita do Canal do YouTube 'Akitando' falando sobre tecnologia, carreira e coisas geek.</description><generator>Hugo -- gohugo.io</generator><language>pt-BR</language><lastBuildDate>Mon, 19 Oct 2026 23:20:48 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/tags/emulacao/index.xml" rel="self" type="application/rss+xml"/><item><title>Desafio pra IA: converter ROMs de NES pra Master System/SMS</title><link>https://akitaonrails.github.io/2026/09/07/desafio-pra-ia-converter-roms-de-nes-pra-master-system-sms/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/09/07/desafio-pra-ia-converter-roms-de-nes-pra-master-system-sms/</guid><pubDate>Mon, 07 Sep 2026 14:00:00 -0300</pubDate><description>&lt;p&gt;Durante muitos anos eu tive uma ideia fixa na cabeça, e sempre achei que ela não era prática: converter jogos de NES pra rodar no Master System.&lt;/p&gt;
&lt;p&gt;Deixa eu ser preciso. Eu sempre soube que dava pra fazer. Duas máquinas Turing completas conseguem, em tese, rodar o código uma da outra. Você sempre consegue traduzir programa de uma arquitetura pra outra. O problema nunca foi possibilidade, foi custo. O NES roda um 6502, o Master System roda um Z80, e ao longo dos anos eu li em vários cantos que uma tradução direta de 6502 pra Z80 sempre acabava rodando muito mais devagar, por causa das diferenças de arquitetura e de hardware. Devagar o suficiente pra nunca compensar na prática.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Durante muitos anos eu tive uma ideia fixa na cabeça, e sempre achei que ela não era prática: converter jogos de NES pra rodar no Master System.</p>
<p>Deixa eu ser preciso. Eu sempre soube que dava pra fazer. Duas máquinas Turing completas conseguem, em tese, rodar o código uma da outra. Você sempre consegue traduzir programa de uma arquitetura pra outra. O problema nunca foi possibilidade, foi custo. O NES roda um 6502, o Master System roda um Z80, e ao longo dos anos eu li em vários cantos que uma tradução direta de 6502 pra Z80 sempre acabava rodando muito mais devagar, por causa das diferenças de arquitetura e de hardware. Devagar o suficiente pra nunca compensar na prática.</p>
<p>E essa memória tem fundamento. Se você for atrás em fórum de retro-dev, tipo o <a href="https://forums.nesdev.org/viewtopic.php?t=17339"target="_blank" rel="noopener">NESdev</a>, o consenso é que traduzir instrução por instrução é justamente o pior caminho: &ldquo;cada instrução do código-fonte vira várias instruções no código objeto, e o programa resultante roda muito mais devagar e ocupa muito mais memória&rdquo;. Não é só a CPU. O 6502 tem a zero page, um modo de endereçamento baratíssimo que o Z80 não tem equivalente, então você troca um acesso barato por uma sequência cara com <code>IX</code>/<code>IY</code>. E a parte gráfica é pior ainda: o PPU do NES e o VDP do Master System são bichos diferentes, com scroll, sprites e espelhamento de tela que não encaixam um no outro sem gambiarra cara.</p>
<p>Ou seja, todo mundo que já pensou nisso chegou na mesma conclusão: dá pra fazer, mas roda mal demais pra valer a pena.</p>
<p>Só que agora a gente tem LLMs de fronteira. E eu fiquei curioso: será que uma abordagem de força bruta, com uma LLM boa no meio do processo, consegue um resultado melhor do que a tradução ingênua de sempre? Comecei o projeto <a href="https://github.com/akitaonrails/nes-to-sms"target="_blank" rel="noopener">nes-to-sms</a> no fim de maio, uns três meses atrás, pra descobrir.</p>
<p>O primeiro resultado foi exatamente o que a teoria previa: ruim. Uma tradução mais ou menos direta gerou código que roda, mas devagar demais. Eu consegui converter o Super Mario Bros inteiro, com sprites, fases, tudo, mas pra ficar minimamente jogável eu precisava rodar o emulador Mednafen com overclock de 500%. Depois de bater cabeça com Claude, GPT e outros modelos por um tempo, empaquei. Trabalhei firme por junho e julho, e em agosto pausei o projeto pra deixar a poeira baixar.</p>
<h2>Por que Master System, e não NES?<span class="hx:absolute hx:-mt-20" id="por-que-master-system-e-não-nes"></span>
    <a href="#por-que-master-system-e-n%c3%a3o-nes" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes de explicar a parte técnica, preciso explicar a obsessão, porque ela é o motivo de tudo.</p>
<p>Eu sempre achei o Master System um console superior ao NES. Melhor CPU, melhor chip de vídeo, uma paleta de cores bem mais rica. O NES trabalha com 4 cores por tile de fundo e 3 por sprite. O Master System trabalha com paletas de 16 cores. Isso é uma diferença enorme na prática.</p>
<p>O problema é que a Nintendo tinha um monopólio brutal na época e não deixava as third parties lançarem pra outros consoles. Quem quisesse fazer jogo pro NES assinava um contrato de exclusividade. O resultado é que o Master System, tecnicamente melhor, ficou faminto de jogos. Praticamente só a própria Sega lançava, e a biblioteca da Sega nunca teve o peso de um Castlevania, um Mega Man, um Final Fantasy.</p>
<p>Imagina o que a gente perdeu. Dava pra ter tido aqueles mesmos jogos clássicos do NES, só que com a capacidade superior do Master System por baixo. Um Castlevania com mais cor, sprites melhores, som melhor. A gente nunca teve isso, e é exatamente essa frustração histórica que me fez querer converter NES pra SMS em primeiro lugar.</p>
<h2>O port que provou a tese<span class="hx:absolute hx:-mt-20" id="o-port-que-provou-a-tese"></span>
    <a href="#o-port-que-provou-a-tese" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Enquanto eu estava com o projeto parado, um outro desenvolvedor, o <a href="https://github.com/lackoftrack27/Super-Mario-Bros.-SMS"target="_blank" rel="noopener">lackoftrack27</a>, publicou um port de Super Mario Bros pro Master System que é de outro nível. Roda em velocidade cheia, 60fps, e ainda por cima com uma arte de sprite melhorada que aproveita a paleta superior do console. Ficou mais parecido com o remaster do Super Mario All-Stars do Super Nintendo do que com a versão original meio crua do NES. A comunidade retro ficou de queixo caído.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/igOu1NQL5Ww"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Isso provou, na prática, a minha tese: o Master System é capaz de rodar versões superiores dos jogos de NES. Sempre foi.</p>
<p>Agora, dois pontos honestos sobre esse port, porque eles importam pro resto da história.</p>
<p>Primeiro: o trabalho do lackoftrack27 é uma reimplementação feita à mão, a partir da disassembly do jogo, otimizada especificamente pro Super Mario. Não é uma tradução automática de propósito geral como a que eu tento fazer. Ele resolveu um jogo, lindamente, no braço. Curiosamente, isso reforça o que os fóruns já diziam: o caminho que funciona é reimplementar no braço, não traduzir a máquina.</p>
<p>Segundo: por mais impressionante que seja ver o Super Mario no Master System, é bom lembrar que ele ainda é um jogo de primeira geração, de uns 40kb. Ou seja, é um dos jogos mais simples do NES. Coisas de geração posterior, tipo Super Mario Bros 3 ou Kirby, ninguém tentou converter ainda, e por bons motivos que eu explico mais pra frente.</p>
<p>Mas o mais importante foi o efeito colateral: com o mapa que o port dele me deu, eu finalmente consegui fazer a minha conversão automática rodar direito. Voltei ao projeto no começo de setembro, carreguei o código do lackoftrack27 no Claude Fable e depois no novo GPT Astra, e coloquei os dois pra estudar o que ele fez que eu não estava fazendo.</p>
<h2>A arquitetura da solução<span class="hx:absolute hx:-mt-20" id="a-arquitetura-da-solução"></span>
    <a href="#a-arquitetura-da-solu%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Como esse artigo é pra programador, deixa eu abrir a caixa preta.</p>
<p>A primeira decisão importante é que o <code>nes-to-sms</code> não é um emulador, nem um tradutor texto-pra-texto de 6502 pra Z80. Ele é um <strong>recompilador estático</strong>. Ele lê a ROM do NES, levanta o código 6502 pra uma representação intermediária com semântica explícita, e daí gera código Z80 a partir dessa IR. A saída é um projeto em assembly WLA-DX que compila numa ROM <code>.sms</code> de verdade. O núcleo é um workspace Rust com treze crates, mais um runtime Z80 escrito à mão que é compartilhado entre os jogos.</p>
<p>O fluxo, de ponta a ponta, é mais ou menos assim:</p>
<ol>
<li>Parsear o cabeçalho da ROM, separar os bancos de código (PRG) e de tiles (CHR) e ler os vetores de reset e interrupção.</li>
<li>Carregar um perfil por jogo (um TOML com rótulos, regiões de dados, tabelas de salto, tipo de mapper e substituições).</li>
<li>Descobrir as funções, montar o grafo de fluxo e classificar cada byte como código ou dado. Aqui entra um detalhe chave: cada acesso à memória é etiquetado com a região a que pertence (zero page, pilha, RAM, registradores do PPU, DMA de sprite, som, mapper).</li>
<li>Levantar cada rotina pra IR, com as flags do 6502 explícitas. Uma escrita no registrador <code>$2006</code> do PPU não vira um <code>mem[]=</code> qualquer, vira uma primitiva de &ldquo;escrita no PPU&rdquo; de primeira classe.</li>
<li>Baixar a IR pra Z80. As flags do 6502 são mantidas num byte de status sombra na RAM, e todo acesso a hardware vira uma chamada pro runtime.</li>
<li>Emitir os bytes Z80 e também o assembly WLA-DX legível.</li>
<li>Converter os assets: os tiles 2bpp do NES viram tiles 4bpp do modo 4 do Master System, a paleta do NES vira a CRAM do SMS, e por aí vai.</li>
<li>Escrever o projeto SMS inteiro, com Makefile, runtime e dados, pronto pra compilar.</li>
</ol>
<p>O mapeamento da CPU é conservador de propósito. O acumulador <code>A</code> do 6502 vira o <code>A</code> do Z80, os registradores <code>X</code> e <code>Y</code> ficam em RAM ou em registradores, a zero page vira um bloco fixo na RAM do SMS, e cada operação que mexe em flag chama um helper. É seguro e correto, mas é justamente aqui que mora o custo.</p>
<h2>Onde NES e SMS divergem de verdade<span class="hx:absolute hx:-mt-20" id="onde-nes-e-sms-divergem-de-verdade"></span>
    <a href="#onde-nes-e-sms-divergem-de-verdade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O achado central do projeto é sobre velocidade, e ele é contraintuitivo.</p>
<p>O 6502 do NES roda a 1.79 MHz. O Z80 do Master System roda a 3.58 MHz, o dobro do clock. Você olha isso e pensa &ldquo;então tem folga de sobra&rdquo;. Só que não. O Z80 gasta em média uns 13 ciclos por instrução, enquanto o 6502 gasta uns 4. Na conta real, um Z80 de 3.5 MHz equivale mais ou menos a um 6502 de 1 MHz pra trabalho genérico. Ou seja, o Z80 do SMS é na verdade <strong>mais lento</strong> que o 6502 do NES pra fazer o mesmo trabalho. A folga é negativa.</p>
<p>Pior: o idioma mais barato do 6502, um <code>LDA tabela,X</code>, é um dos mais caros de emular no Z80. Então uma tradução fiel de um jogo que já espremia o NES no talo simplesmente não tem como bater 60fps sem overclock. A culpa é da física do problema, não do meu tradutor.</p>
<p>E o vídeo é outra história. O NES enxerga a memória de vídeo de forma mapeada, com nametables, scroll por hardware e uma tabela de sprites acessada por DMA. O Z80 do SMS não endereça a VRAM como memória: ele seta um latch de endereço e joga bytes por portas do VDP. Então toda escrita de PPU do NES precisa ser capturada, enfileirada num buffer e despejada no VDP durante o vblank. O NES vira sprite de graça, só setando um bit de atributo. O Master System não tem flip de sprite por hardware, então o programa precisa espelhar os dados do tile na VRAM na unha, gastando memória. O split de tela que os jogos de NES fazem no meio do frame, mexendo no scroll a cada scanline, também não tem equivalente direto, porque o VDP trava o scroll vertical no topo do frame.</p>
<p>E ainda tem o teto de VRAM. Os 8 KB de tiles do Super Mario viram 16 KB no formato 4bpp do SMS, que é a VRAM inteira do console. Fundo e sprites não cabem residentes ao mesmo tempo. E o código explode de 3 a 6 vezes de tamanho, por isso a saída SMS já é bancada desde o primeiro jogo, mesmo os mais simples.</p>
<h2>Aproveitando o que o SMS tem de melhor<span class="hx:absolute hx:-mt-20" id="aproveitando-o-que-o-sms-tem-de-melhor"></span>
    <a href="#aproveitando-o-que-o-sms-tem-de-melhor" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A sacada pra recuperar velocidade é parar de emular o comportamento do NES e passar a gastar as forças do Master System. O lema do projeto virou &ldquo;gastar ROM pra comprar CPU&rdquo;.</p>
<p>O SMS aceita cartuchos de vários megabytes. Então em vez de espelhar sprite na unha em tempo de execução, o build já gera variantes pré-espelhadas de cada tile de sprite, e o flip vira uma consulta de tabela. Em vez de emular a tabela de atributos do NES, o assembler já grava a palavra final de nametable do SMS, com os bits de flip, paleta e prioridade embutidos. A tabela de atributos do NES simplesmente deixa de existir no programa. As cópias pro VDP usam blocos de <code>OUTI</code> desenrolados, mais rápidos que o loop genérico. E o split da barra de status, que no NES depende do sprite-zero, vira uma interrupção de linha do SMS, que é o jeito nativo de fazer isso.</p>
<p>Nada disso é mágica. A folga negativa da CPU continua lá, então essas otimizações reduzem o custo mas não fazem milagre sozinhas. Mas é a diferença entre injogável e jogável.</p>
<h2>O pulo do gato: fazer a IA rodar o emulador<span class="hx:absolute hx:-mt-20" id="o-pulo-do-gato-fazer-a-ia-rodar-o-emulador"></span>
    <a href="#o-pulo-do-gato-fazer-a-ia-rodar-o-emulador" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui está a parte que eu considero mais importante do projeto inteiro, e é o que separou a tentativa fracassada de maio da versão que finalmente anda.</p>
<p>Tradução cega não funciona. O modelo precisa de feedback real pra saber o que está quebrado e o que está lento. Então o coração do projeto está no <strong>oráculo diferencial</strong>, a infraestrutura que roda os emuladores e mede a realidade. O tradutor é só a parte fácil.</p>
<p>Funciona em duas camadas. A primeira compara instrução por instrução: pra cada rotina, o sistema gera estados iniciais aleatórios, roda o 6502 original num interpretador de referência e roda o Z80 gerado, e compara o resultado (acumulador, registradores, flags, RAM tocada). Qualquer divergência acende o alerta. A segunda camada compara frame a frame: ela roda a ROM do NES como verdade absoluta e a build do SMS lado a lado, com o mesmo roteiro de botões, e compara a RAM byte a byte em cada frame. Depois isso foi estendido com um oráculo que confere a VRAM e a paleta do SMS, e com um oráculo visual que compara a saída contra o frame real do NES.</p>
<p>Esse loop de medir é o que destravou os consertos recentes. Não foi chute. Dois exemplos concretos:</p>
<p>No Super Mario, cada passo de otimização foi medido em ciclos por frame, com o emulador rodando de verdade. O orçamento de um frame é 59.736 ciclos. A base parou em uns 370 mil ciclos por frame, algo como 6 vezes acima do orçamento, o que dava uns 10fps e explicava a necessidade daquele overclock brutal de 500%. Medindo passo a passo, cada mudança validada pelo oráculo, a coisa desceu até 118.296 ciclos por frame, ou 1.98 vezes o orçamento. Ou seja, saiu de 6 vezes pra menos de 2 vezes. Agora ele roda em velocidade cheia já no overclock padrão do emulador, e fica confortável ali na casa dos 200 a 300%, contra os 500 a 700% do começo.</p>
<p>No Castlevania, o maior ganho de velocidade veio de um perfil que só o emulador conseguiu revelar: um loop de espera de sprite-zero, no endereço <code>$F8C7</code>, estava fazendo 255 leituras de status e saindo por timeout toda vez, consumindo quase 23% de toda a CPU. Sem rodar o emulador e medir, ninguém acharia isso no olho. Com a medição, o conserto foi cirúrgico.</p>
<p>É esse o argumento maior que eu venho batendo faz tempo sobre agentes: um LLM que só gera código no escuro erra feio. Um LLM que consegue rodar o alvo de verdade, coletar dado real e reagir ao que mediu joga em outro nível.</p>
<h2>O que aprendi estudando o port do lackoftrack27<span class="hx:absolute hx:-mt-20" id="o-que-aprendi-estudando-o-port-do-lackoftrack27"></span>
    <a href="#o-que-aprendi-estudando-o-port-do-lackoftrack27" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Com esse oráculo no lugar, coloquei o Claude Fable e o GPT Astra pra dissecar o port do lackoftrack27, que é uma reimplementação do mesmo jogo a partir da mesma disassembly que eu traduzo. Isso respondeu de vez uma dúvida que estava me travando: o Super Mario cabe no Master System. O meu estouro de 6 vezes no orçamento era 100% overhead de tradução, não limitação do jogo nem do hardware.</p>
<p>Os ganhos dele, em ordem de impacto, foram mais ou menos esses:</p>
<ul>
<li><strong>A maior de todas: a representação dos dados.</strong> Ele reorganizou os arrays de objetos do jogo em páginas de RAM, uma por slot, com os mesmos offsets de campo. Aí o <code>X</code> do 6502 vira o registrador <code>H</code> e o nome do campo vira o <code>L</code>, e um acesso que no meu tradutor custava umas 70 unidades de tempo passa a custar 14. O detalhe cruel é que isso só funciona porque o programador sabe, de cabeça, que aquele <code>X</code> ali é sempre um índice de objeto entre 0 e 6. Um tradutor estático não tem como descobrir esse invariante com segurança. Essa é a otimização mais poderosa, e é justamente a que a tradução automática não consegue provar sozinha. É o resíduo que segura as últimas 2 vezes de velocidade.</li>
<li><strong>Flags auditadas, não emuladas.</strong> Ele checou o código e achou só uns 10 lugares que dependem de verdade de alguma peculiaridade do carry do 6502. O resto usa flag nativa do Z80. Isso confirmou uma medição minha: gastar energia emulando flag rende quase nada.</li>
<li><strong>Chamadas nativas.</strong> <code>JSR</code> virando <code>CALL</code> de verdade, sem a contabilidade cara de pilha emulada. Esse foi o maior ganho genérico que eu portei pro meu pipeline.</li>
<li><strong>PPU deletado em tempo de build</strong>, não emulado em runtime, exatamente como descrevi na seção de aproveitar o SMS.</li>
<li><strong>Frame arquitetado pra estourar com elegância</strong>, transformando um estouro em um frame de lag limpo em vez de corromper a tela.</li>
</ul>
<p>Adotei o que dava pra generalizar, e o Super Mario despencou de 6 vezes pra menos de 2 vezes o orçamento. Esse é o resultado rodando hoje:</p>
<div class="embed-container">
  <video controls preload="metadata" playsinline style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000;">
    <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260907152243_smb-sms-conversion.mp4" type="video/mp4">
  </video>
</div>
<p>A lição mais honesta desse estudo é dupla. Os ganhos de verdade estão na representação de dados e na convenção de chamada, não no que eu tinha atacado primeiro. E o ganho mais fundo de todos é exatamente o que o tradutor automático não consegue inferir. Isso desenha bem o teto do que dá pra automatizar.</p>
<h2>Castlevania e o problema dos mappers<span class="hx:absolute hx:-mt-20" id="castlevania-e-o-problema-dos-mappers"></span>
    <a href="#castlevania-e-o-problema-dos-mappers" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Com o Super Mario andando, voltei pro meu velho alvo: o primeiro Castlevania. E aqui a gente esbarra na limitação mais séria do NES.</p>
<p>O NES é um console simples, com um monte de limitação. Uma das principais é que ele não suporta jogo maior do que uns 40kb de ROM, porque o 6502 só enxerga uma janela de 32 KB de programa no espaço de endereço dele. A &ldquo;solução&rdquo; da época foi genial e meio maluca: partes do console foram sendo turbinadas pelo próprio cartucho.</p>
<p>Muita gente pensa que cartucho é só um chip de ROM com o código do jogo. No caso do NES, não. Os cartuchos vinham com uma variedade de chips extras que aumentavam a capacidade do console, seja um chip de som melhor ou, muito mais comum, os <strong>mappers</strong>. Existem vários mappers diferentes, da própria Nintendo e de third parties como Capcom e Konami. Eles usam uma técnica chamada <strong>bank switching</strong>: como o 6502 não enxerga endereço suficiente, o mapper vai trocando quais pedaços de ROM ficam visíveis naquela janela de 32 KB, conforme o jogo pede. É assim que jogos grandes cabem num console que, no papel, não aguentaria.</p>
<p>Eu já expliquei isso em detalhe num vídeo antigo do canal, o <a href="/2020/06/18/akitando-81-aprendendo-sobre-computadores-com-super-mario-do-jeito-hardcore/">Akitando #81, sobre aprender computação com o Super Mario do jeito hardcore</a>:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/hYJ3dvHjeOE"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>O Castlevania usa um dos mappers mais antigos, o UxROM. E aqui está o problema de escala do meu projeto: se eu quiser conseguir traduzir a maioria dos jogos de NES, eu tenho que mapear todos os mappers, um por um. Hoje o projeto implementa só dois: o NROM, que é o cartucho pelado do Super Mario, e o UxROM do Castlevania. Todos os outros, os MMC1, MMC3 e companhia, estão só planejados. Cada mapper é um trabalho e tanto de implementar, porque não basta entender o bank switching do NES, é preciso traduzir esse comportamento pro mapper próprio do Master System.</p>
<p>A boa notícia é que o Master System também é um sistema bancado, então o mapeamento é &ldquo;a mesma forma um nível acima&rdquo;. Um banco de PRG do NES vira um conjunto de bancos do SMS, uma escrita de troca de banco do NES vira uma escrita no mapper do SMS através de um shim, e uma chamada que cruza bancos usa a maquinaria de &ldquo;portão&rdquo; que já existe. A identidade de uma rotina passa a ser o par (banco, endereço), e uma tabela de despacho resolve isso em tempo de execução. Quando não acha, ele falha fechado, com um trap, em vez de rodar lixo.</p>
<p>É aqui que os jogos maiores vão bater na parede. O bank switching de tiles dos mappers mais avançados, o timing de interrupção por scanline do MMC3 e do MMC5, e o próprio teto de bancos do SMS pra um jogo de NES bem grande, tudo isso ainda está por resolver. Por isso eu ainda não sei dizer se um Super Mario Bros 3 é viável ou não. É bem possível que os jogos maiores morram exatamente nessa etapa.</p>
<p>De qualquer forma, mexi mais um bocado no Castlevania nessa retomada. Consertei uma pilha de coisas usando o oráculo: o loop de sprite-zero que comia CPU, a lógica de armas e projéteis que perdia retornos de chamada, um glitch de scroll na barra de status, a colisão de VRAM entre sprites 8x16 e 8x8, e a coerência entre fundo, paleta, HUD e sprites. Hoje o Castlevania sobe, aceita o start, desenha o primeiro estágio de forma reconhecível, responde ao controle e roda por um bom tempo sem travar. Mas é honesto dizer que ele ainda roda devagar, e o caminho que eu uso pra jogar é o Mednafen com overclock de 500%, e mesmo assim ainda está de 2 a 3 vezes abaixo da própria meta de velocidade. Está longe de ser pixel perfeito e em tempo real.</p>
<div class="embed-container">
  <video controls preload="metadata" playsinline style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000;">
    <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20260907152243_castlevania-sms-conversion.mp4" type="video/mp4">
  </video>
</div>
<h2>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Depois de tantas semanas e tantas tentativas, eu ainda não sei quanto mais dá pra espremer de uma tradução automática. O teto pode estar perto, porque as otimizações mais fundas são justamente as que uma máquina não consegue inferir sozinha.</p>
<p>Mas tem um caminho que me anima. A tradução automática pode virar uma linha de base. Uma conversão SMS que já roda, correta, ainda que lenta, e que depois pode ser otimizada no braço, jogo a jogo, exatamente como o lackoftrack27 fez com o Super Mario e como tanta gente vem fazendo com decompilações e ports por aí. O oráculo garante que a base está correta, e a mão humana entra pra fazer o que a máquina não consegue.</p>
<p>Portar jogo pra um hardware muito superior, tipo um port pra PC, é relativamente fácil, porque sobra capacidade. O difícil de verdade é encaixar o jogo num console da mesma geração, onde não sobra nada. E é justamente essa dificuldade que torna a ideia de fazer versões melhores de jogos de NES pro Master System tão atraente. É o console que merecia ter tido esses jogos, e nunca teve.</p>
<p>Eu espero que mais gente se anime com essa possibilidade e contribua com o projeto. Está tudo aberto no <a href="https://github.com/akitaonrails/nes-to-sms"target="_blank" rel="noopener">nes-to-sms</a>. Se você curte 6502, Z80, VDP e o desafio de espremer ciclo de um hardware de 40 anos atrás, apareça. Tem lugar de sobra.</p>
]]></content:encoded><category>retrocomputacao</category><category>agentes-de-codigo</category><category>games</category><category>emulacao</category></item><item><title>Como Driveclub e shadPS4 Quase Derrotaram a IA e a Mim: Como Aprender</title><link>https://akitaonrails.github.io/2026/04/23/driveclub-shadps4-e-ia-como-aprender/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/04/23/driveclub-shadps4-e-ia-como-aprender/</guid><pubDate>Thu, 23 Apr 2026 12:00:00 -0300</pubDate><description>&lt;h2&gt;Onde a gente tava&lt;span class="hx:absolute hx:-mt-20" id="onde-a-gente-tava"&gt;&lt;/span&gt;
&lt;a href="#onde-a-gente-tava" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Na semana passada &lt;a href="https://akitaonrails.github.io/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/"&gt;publiquei sobre o meu setup distrobox-gaming&lt;/a&gt;, com mais de dez jogos de corrida retro rodando em Linux, do Gran Turismo 1 no DuckStation ao Forza Motorsport 4 no Xenia. No fim daquele artigo, falei do Driveclub no shadPS4 como o &amp;ldquo;final boss&amp;rdquo;: o jogo boota, o menu carrega, a corrida começa, o controle responde.&lt;/p&gt;
&lt;p&gt;Só que tinha dois problemas que eu mencionei de passagem e tratei como &amp;ldquo;limitações aceitas&amp;rdquo;:&lt;/p&gt;</description><content:encoded><![CDATA[<h2>Onde a gente tava<span class="hx:absolute hx:-mt-20" id="onde-a-gente-tava"></span>
    <a href="#onde-a-gente-tava" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Na semana passada <a href="/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/">publiquei sobre o meu setup distrobox-gaming</a>, com mais de dez jogos de corrida retro rodando em Linux, do Gran Turismo 1 no DuckStation ao Forza Motorsport 4 no Xenia. No fim daquele artigo, falei do Driveclub no shadPS4 como o &ldquo;final boss&rdquo;: o jogo boota, o menu carrega, a corrida começa, o controle responde.</p>
<p>Só que tinha dois problemas que eu mencionei de passagem e tratei como &ldquo;limitações aceitas&rdquo;:</p>
<ol>
<li><strong>De dia, a imagem fica um pouco mais escura do que no PS4 de referência.</strong> Nada alarmante, mas perceptível.</li>
<li><strong>De noite, race start no Canadá ou em Munnar ficava pitch black por 10 a 30 segundos</strong> antes de o jogo &ldquo;se recuperar sozinho&rdquo; perto de 1:30. Durante esses segundos, só o HUD aparecia. Pista, carro, faróis, tudo preto absoluto.</li>
</ol>
<p>No artigo anterior eu empurrei a explicação pra &ldquo;ainda não foi consertado no emulador, vou conviver com isso&rdquo;. Mas por dentro eu não conseguia me aceitar jogando num estado visualmente injogável. Eu queria jogar o Driveclub no melhor que ele podia entregar, e não queria ficar esperando o projeto consertar por mim. Decidi pegar a coisa nas minhas próprias mãos. Um preto absoluto de 30 segundos não é &ldquo;um pouco mais escuro&rdquo;. É um bug grave, dos que tornam o jogo injogável na prática.</p>
<p>Esse artigo é o que aconteceu entre domingo de noite e quinta-feira de manhã.</p>
<h2>O blackout, ao vivo<span class="hx:absolute hx:-mt-20" id="o-blackout-ao-vivo"></span>
    <a href="#o-blackout-ao-vivo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/original-blackout.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Esse vídeo é o comportamento que eu queria consertar. Race start na Índia (Munnar), corrida noturna. Você vê a pista, os faróis aparecem, os primeiros segundos rodam. Depois, escurece progressivamente. Em uns 15 segundos já tá tudo preto. Fica assim por mais uns 60-90 segundos. Aí o jogo &ldquo;recalibra&rdquo; sozinho, e a pista reaparece.</p>
<p>Se você for um jogador, você não quer saber do porquê. Você quer dirigir.</p>
<h2>Por que shadPS4 é difícil de depurar<span class="hx:absolute hx:-mt-20" id="por-que-shadps4-é-difícil-de-depurar"></span>
    <a href="#por-que-shadps4-%c3%a9-dif%c3%adcil-de-depurar" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://shadps4.net/"target="_blank" rel="noopener">shadPS4</a> <strong>ainda não tem release estável</strong>. O projeto tá em desenvolvimento ativo. Main branch muda várias vezes por semana, configs migram de TOML pra JSON sem aviso, settings ficam atrás de &ldquo;Advanced&rdquo; pra não gerar issue de usuário com hardware incompatível, PRs em aberto disputam abordagens diferentes pra o mesmo problema.</p>
<p>Quem tenta configurar Driveclub hoje encontra:</p>
<ul>
<li>Guias de Reddit de setembro/2025 que usam <code>readbacks = true</code> (era bool na época) e dizem &ldquo;pra DriveClub sempre ligar readbacks&rdquo;.</li>
<li>Guias de novembro/2025 que dizem &ldquo;desliga readbacks, mata a performance&rdquo; (porque em 2025-07 readbacks virou enum <code>Disabled | Relaxed | Precise</code>, com perfil de performance diferente, e Bloodborne começou a travar com ele ligado).</li>
<li>Vídeos YouTube de janeiro/2026 com fork customizado que ninguém documentou qual é.</li>
<li>Thread no shadps4.net com três explicações diferentes pro blackout, todas mutuamente exclusivas.</li>
<li>Minhas próprias anotações da semana passada no <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>distrobox-gaming/docs/driveclub-shadps4.md</code></a> dizendo <code>readbacks_mode: 0</code>. Que é exatamente o oposto do que eu descobri essa semana.</li>
</ul>
<p>Ou seja, a informação existe, mas tá espalhada, datada, contraditória, e a maior parte depende de detalhes de versão que mudaram entre a postagem original e hoje. Reproduzir setup via vídeo do YouTube é tentar resolver cubo mágico de olhos vendados.</p>
<h2>Spoiler: a solução é um inteiro<span class="hx:absolute hx:-mt-20" id="spoiler-a-solução-é-um-inteiro"></span>
    <a href="#spoiler-a-solu%c3%a7%c3%a3o-%c3%a9-um-inteiro" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Depois de 31 fases de investigação, 44 commits no meu fork do shadPS4, 15.668 linhas de código instrumental adicionadas e 3 dias de debug quase ininterrupto, a resposta é <strong>uma linha no config por jogo</strong>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;GPU&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;readbacks_mode&#34;</span><span class="p">:</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>readbacks_mode: 2</code> é o modo <code>Precise</code>. Explicar o que isso faz exige entender como o Driveclub implementa auto-exposure, e é aqui que a jornada começa. Pra saber POR QUE esse toggle resolve, você precisa entender a cadeia toda.</p>
<p>O resumo do porquê: o <strong>Driveclub faz auto-exposure como um loop de feedback GPU→CPU</strong>.</p>
<ol>
<li>A cena renderiza num HDR target.</li>
<li>Um compute shader calcula um histograma de luminância num SSBO.</li>
<li>A CPU <strong>lê</strong> esse SSBO no frame seguinte e deriva uma exposição alvo.</li>
<li>A CPU escreve essa exposição de volta num UBO de lighting de 1936 bytes (nos slots <code>[38] [48] [50]</code>).</li>
<li>Os fragment shaders leem esse UBO e multiplicam a luminância da cena por ele.</li>
</ol>
<p>Sem <code>readbacks_mode: Precise</code>, o passo 3 lê zeros obsoletos. A página de memória que o GPU escreveu o histograma nunca é sincronizada pro lado da CPU. O integrator de exposição da CPU conclui &ldquo;a cena tá escura, abrir diafragma ao máximo&rdquo; e rampa o valor de saída monotonicamente: <code>2.59 → 7.84 → 24 → 90 → 179 → 255</code>. Em 60-90 segundos, a escala satura tão alto que tudo clipa pra zero. É esse o pitch black.</p>
<p>Com <code>readbacks_mode: Precise</code> ligado, o emulador marca as páginas que o GPU acabou de escrever como protegidas no nível de kernel (via <code>mprotect</code> no Linux). Quando a CPU tenta ler uma dessas páginas pela primeira vez, dispara uma page fault. O emulador intercepta, emite um <code>vkCmdCopyBuffer</code> download do buffer do GPU pro staging de host, espera no scheduler, e a CPU enfim vê o dado fresco. O histograma verdadeiro entra no integrator, a exposição converge normalmente, e o race start abre brilhante como deveria.</p>
<p>Por que não é o default? Três motivos documentados. Primeiro, per-page <code>mprotect</code> + per-fault GPU stall + compute dispatch + scheduler wait tem custo real: em NVIDIA warm path é tolerável, em AMD derruba pra menos de 12 FPS, <a href="https://github.com/shadps4-emu/shadPS4/issues/3322"target="_blank" rel="noopener">issue aberta</a> a respeito. Segundo, <a href="https://github.com/shadps4-emu/shadPS4/issues/3826"target="_blank" rel="noopener">Bloodborne trava</a> em loading screens com Precise ligado. Terceiro, o maintainer escondeu a opção atrás de &ldquo;Advanced&rdquo; no UI justamente pra evitar que usuário de hardware sensível habilite sem saber. O modo existe desde <code>v0.15.0</code> (setembro/2025), mas <strong>ninguém tinha publicamente conectado <code>Precise</code> + DriveClub + feedback loop de auto-exposure</strong>. O <a href="https://github.com/shadps4-emu/shadPS4/issues/3346"target="_blank" rel="noopener">compat tracker já admite</a> que DriveClub &ldquo;requires readbacks enabled to function properly&rdquo;, mas não especifica o modo.</p>
<p>No meu setup o custo de performance é irrelevante. Tenho uma RTX 5090 no desktop, hardware de sobra pra bancar o mprotect, o page fault, o copy e o stall por frame. A decisão é trivial: ligo Precise, pago o preço, o jogo roda. Num hardware mais modesto ou numa AMD a conversa é outra, e é exatamente por isso que o setting não é default e fica atrás do &ldquo;Advanced&rdquo;.</p>
<p>Importante deixar claro uma coisa: essa explicação toda acima, sobre <code>Precise</code> vs <code>Relaxed</code> vs <code>Disabled</code>, feedback loop GPU→CPU, mprotect syscall por página, não é conhecimento que eu tinha domingo à noite. Eu não sabia o que era um buffer readback, não sabia que Driveclub implementava auto-exposure como feedback loop GPU→CPU, não sabia que <code>readbacks_mode</code> virou um enum em 2025 com três valores. Pra chegar na resposta certa, precisei aprender cada peça do zero. Não dava pra chutar. Se eu tivesse tentado &ldquo;ligar readbacks&rdquo; semana passada sem entender a cadeia, teria pegado o valor errado (Relaxed não basta pra esse feedback loop, explico isso mais pra frente) e desistido achando que &ldquo;não funciona&rdquo;.</p>
<p>E mais duas coisas precisam estar no lugar pra isso funcionar, que já cobri no <a href="/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/#driveclub-o-imposs%c3%advel-finalmente-poss%c3%advel">artigo anterior</a>:</p>
<ul>
<li><strong>v1.28 patch aplicado</strong> em cima da install base de v1.00 (sem isso, o conteúdo fica locked com &ldquo;não lançado ainda&rdquo;).</li>
<li><strong>Patch XML de 60fps desabilitado</strong> (render rate subiu mas logic tickrate é fixo; com ele ligado, o jogo roda em câmera lenta).</li>
</ul>
<h2>O resultado<span class="hx:absolute hx:-mt-20" id="o-resultado"></span>
    <a href="#o-resultado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/canada-fixed.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Mesma corrida no Canadá, noturna, com <code>readbacks_mode: 2</code> ligado. Race start abre brilhante, auto-exposure converge imediatamente, a transição pra noite acontece de forma natural conforme o TOD (time of day) do jogo avança. Sem blackout, sem &ldquo;recalibração&rdquo; aos 1:30, sem janela de 30 segundos de preto absoluto. Isso é Driveclub rodando como no PS4.</p>
<p>Agora a pergunta interessante não é &ldquo;qual o setting&rdquo;. É: <strong>como a gente chegou aqui?</strong></p>
<h2>Como um junior aprende hoje?<span class="hx:absolute hx:-mt-20" id="como-um-junior-aprende-hoje"></span>
    <a href="#como-um-junior-aprende-hoje" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem uma pergunta que eu ouço com frequência: &ldquo;com a IA fazendo tudo, como um junior aprende?&rdquo;</p>
<p>A premissa dessa pergunta tá errada. <strong>A IA não faz tudo.</strong> A IA faz o que você pede. Ela não descobre por conta própria. Ela não tem iniciativa de domínio. Ela não é capaz de dizer &ldquo;olha, isso aqui parece um feedback loop quebrado em GPU→CPU readback&rdquo; se você não souber pelo menos que existe uma coisa chamada readback, e que feedback loops quebrados são uma classe de bug.</p>
<p>Pior ainda: se você for num agente de IA hoje e pedir &ldquo;conserta essa tela preta no Driveclub no shadPS4&rdquo;, ele vai te entregar uma lista de respostas possíveis baseada em fóruns antigos, com probabilidade alta de te mandar no caminho errado. Ele vai sugerir patch XML de 60fps (errado, causa slow-motion). Vai sugerir tonemap override (errado, o jogo já escreve SDR correto). Vai sugerir vblank_frequency tweak (inútil pro problema real). Vai sugerir gamma manual (trata o sintoma, não a causa).</p>
<p>O caminho pra descobrir é <strong>mergulhar na cadeia</strong>, fase por fase, descartando hipóteses erradas até o terreno ficar suficientemente conhecido pra você reconhecer a resposta certa quando ela aparece.</p>
<p>E é aí que muita gente se confunde comigo. &ldquo;O Akita já é senior, ele tem 25+ anos de experiência, claro que ele sabe.&rdquo; <strong>Falso.</strong> Profissional senior é alguém que já foi junior em cada tópico que domina. E continua virando junior toda vez que pega um domínio novo. Eu tenho 25 anos de programação web, sistemas distribuídos, Ruby, Erlang, Go. Mas <strong>eu nunca programei pra PS4</strong>. Nunca tinha olhado o codebase do shadPS4. Não conhecia a arquitetura gráfica do PS4. Domingo eu era um absoluto junior nesse domínio.</p>
<p>Junior não é o mesmo que totalmente cru. Em anos anteriores eu já tinha explorado no meu canal a arquitetura low-level de consoles antigos (do 6502 do NES pra cima) e como emuladores funcionam internamente em geral. Os dois vídeos abaixo ajudaram a construir o vocabulário básico de como videogame funciona por dentro, e garantiram que eu não ia tropeçar em conceitos tipo fetch-decode-execute, opcode, interrupt, ou HLE vs LLE.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/hYJ3dvHjeOE"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>



<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/vUqLLpUJ47s"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Eu também já tinha feito outro vídeo, mais antigo, sobre a evolução de CPUs, GPUs, DirectX e Vulkan, então pelo menos o vocabulário de &ldquo;pipeline gráfico moderno&rdquo; e &ldquo;shading language&rdquo; não era estranho pra mim.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/JEp7ozWqIps"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Saber que existe <code>VkCommandBuffer</code> é bem diferente de saber onde no shadPS4 um <code>vkCmdCopyBuffer</code> de readback dispara. Mas dá uma base. Esse tipo de curiosidade antiga rendeu juros agora.</p>
<h2>O rodízio: Claude Code e Codex<span class="hx:absolute hx:-mt-20" id="o-rodízio-claude-code-e-codex"></span>
    <a href="#o-rod%c3%adzio-claude-code-e-codex" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A IA (no meu caso o <a href="https://claude.com/claude-code"target="_blank" rel="noopener">Claude Code</a>) não &ldquo;sabia&rdquo; mais que eu. Ela tem o mesmo texto de fórum datado que você achou no Reddit. O que ela fazia bem era <strong>agregar</strong>: ler o código do shadPS4 em paralelo comigo, indexar os comentários, cruzar referências entre phase docs, compilar, rodar probes, parsear logs de 61 MB, comparar binário decompilado com o diff de UBO, jogar luz em cantos do sistema mais rápido do que eu sozinho conseguiria.</p>
<p>Mas a decisão de &ldquo;continuar investigando&rdquo; era minha. A perseverança de &ldquo;não aceita uma mitigação, quer a causa-raiz&rdquo; era minha. E quando a IA sugeria &ldquo;honestly, we should just accept the current result and document it&rdquo; (e ela sugeriu <strong>várias vezes</strong> ao longo dos quatro dias), eu era o que tinha que dizer &ldquo;não, continuamos&rdquo;.</p>
<p>O ponto central do rodízio: <strong>nenhum LLM sozinho conseguiu fechar esse problema.</strong></p>
<p>Ao longo dos quatro dias, várias vezes o Claude Code entrou em loop, repetindo as mesmas hipóteses sem rumo novo. Quando isso acontecia, eu trocava pro Codex por algumas horas pra trazer ideias de fora, probes diferentes, releitura do codebase por ângulo novo. Depois voltava pro Claude Code pra integrar o que o Codex tinha levantado. E assim por diante, alternando.</p>
<p>A resolução final aconteceu no Claude Code, mas a jornada trocou de modelo várias vezes. Cada LLM tinha seus viéses e seus pontos cegos. Deixado sozinho, cada um teria desistido antes.</p>
<p>O que rompeu o impasse foi eu continuar trazendo novas ideias pra tentar, forçando o modelo a reavaliar, trocando quando um deles começava a repetir.</p>
<p>Em dois momentos a coisa foi além de &ldquo;só repetir hipóteses&rdquo;. O Codex literalmente teve um glitch em loop agêntico: começou a repetir a mesma &ldquo;solução&rdquo; que tinha acabado de tentar, de novo e de novo, em sequência, sem perceber o que estava fazendo. Foi a primeira vez que eu vi isso acontecer em qualquer agente de IA. Tive que matar a sessão e começar uma nova do zero pra quebrar o ciclo.</p>
<p>Isso diz muito sobre o tamanho de contexto e a duração da sessão. A complexidade e o ritmo dessa investigação foi suficiente pra derrubar os dois LLMs, cada um do seu jeito.</p>
<p>Toda a jornada abaixo está documentada em 33 phase docs no branch <a href="https://github.com/akitaonrails/shadPS4/tree/gamma-debug/docs/driveclub-investigation"target="_blank" rel="noopener"><code>gamma-debug</code> do meu fork do shadPS4</a>. Cada seção aqui linka pro doc original pra quem quiser o detalhe completo. Aqui eu resumo o essencial: a hipótese que tínhamos, o que tentamos, o que aprendemos de novo, e por que essa fase não fechou o caso.</p>
<h2>Sessão zero: baseline e reprodutibilidade<span class="hx:absolute hx:-mt-20" id="sessão-zero-baseline-e-reprodutibilidade"></span>
    <a href="#sess%c3%a3o-zero-baseline-e-reprodutibilidade" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Toda investigação séria começa antes da Fase 1. A primeira coisa, pra qualquer projeto, é garantir que o <strong>baseline funciona como esperado</strong> e que a situação que você quer pesquisar é <strong>reproduzível toda vez</strong>. Se você não consegue reproduzir o bug por comando, tá caçando fantasma. Cada probe depois vai ser inconclusivo porque o bug &ldquo;apareceu e sumiu&rdquo; sem controle. E se o baseline tá quebrado de algum jeito que você nem percebeu, cada experimento mede o problema errado. Sem essas duas garantias, não tem como progredir.</p>
<p>No meu caso, domingo à noite confirmei:</p>
<ul>
<li>O jogo boota até a tela de corrida sem crash, usando a config da <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>distrobox-gaming</code></a>.</li>
<li><a href="https://github.com/Nenkai/DriveClubFS"target="_blank" rel="noopener">DriveClubFS</a> extrai v1.28 limpo, 8018 arquivos, ~47 GB.</li>
<li>MSAA depth resolve aplicado no fork, pistas noturnas renderizam forma em vez de uniforme preto absoluto (isso está coberto no <a href="/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/">artigo anterior</a>).</li>
<li>Controle 8BitDo detectado.</li>
<li>Corrida noturna na Índia 19:30 <strong>reproduz o blackout em 100% das tentativas</strong>, no mesmo padrão temporal: fade progressivo nos primeiros ~15s, pitch black entre ~20s e ~90s, &ldquo;recalibração&rdquo; aos 1:30.</li>
</ul>
<p>Esse baseline é a única base sólida que me permite comparar cada experimento de forma confiável. Sem ele, um probe que &ldquo;funcionou&rdquo; pode ser só um cache diferente, não o fix real. Com ele, cada mudança tem um antes e um depois que são mensuráveis.</p>
<p>Fora isso, zero conhecimento específico de:</p>
<ul>
<li>Formato de PKG do PS4 (PFS, param.sfo, disc_info, keystone).</li>
<li>Codebase do shadPS4 (src/core, src/video_core, shader_recompiler, buffer_cache).</li>
<li>Pipeline gráfico do PS4 (GCN ISA, forward+ lighting, MSAA depth resolve).</li>
<li>Vulkan além do superficial (descriptor sets, UBO binding, push constants, pipeline cache).</li>
<li>SPIR-V disassembly e patching.</li>
<li>PS4 OELF loader, Itanium RTTI, SCE dynamic relocations.</li>
<li>mprotect-based page-fault tracking pra CPU-GPU synchronization.</li>
</ul>
<h2>A jornada em fases<span class="hx:absolute hx:-mt-20" id="a-jornada-em-fases"></span>
    <a href="#a-jornada-em-fases" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Vou organizar as 30+ fases em grupos que fazem sentido como narrativa. Cada fase linka pro doc completo pra quem quiser o detalhe técnico.</p>
<blockquote>
  <p><strong>Nota pra quem não quiser ler todas as 30+ fases:</strong> depois da sequência de fases tem seções de reflexão e metodologia que dá pra ler direto. <a href="#a-t%c3%a9cnica-do-shotgun">A técnica do shotgun</a> explica a metodologia de depuração que usei ao longo da investigação. <a href="#o-que-eu-sabia-domingo-vs-quinta">O que eu sabia domingo vs quinta</a> resume o que aprendi de fato. <a href="#a-ia-sugeria-aceitar-a-perseveran%c3%a7a-humana-foi-minha">A IA sugeria aceitar. A perseverança humana foi minha</a> discute o papel real da IA nesse processo. <a href="#custo-real-dessa-jornada">Custo real dessa jornada</a> cataloga o que foi gerado. Se quiser pular direto pro argumento, esses são os atalhos.</p>

</blockquote>
<h3>Fase 01: pipeline cache, o warm-up<span class="hx:absolute hx:-mt-20" id="fase-01-pipeline-cache-o-warm-up"></span>
    <a href="#fase-01-pipeline-cache-o-warm-up" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-01-shader-compile-stalls.md"target="_blank" rel="noopener"><code>phase-01-shader-compile-stalls.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> menus rodam a 2-3 fps no primeiro launch, deve ser compilação de pipelines Vulkan acontecendo em tempo real.</li>
<li><strong>Ação:</strong> ligar <code>pipeline_cache_enabled: true</code> no config global.</li>
<li><strong>Conceito novo:</strong> cache de pipelines Vulkan. Quando o emulador traduz um shader GCN do PS4 pra SPIR-V e depois em binário Vulkan específico do driver, ele pode cachear esse binário. Sem cache, recompila cada cold launch (~864 shaders + ~590 pipelines).</li>
<li><strong>Resultado:</strong> resolvido. Primeira sessão paga o custo; sessões seguintes leem do disk e sobem imediatas. Fácil. Também foi minha primeira lição sobre o codebase do shadPS4.</li>
</ul>
<h3>Fase 02: gamma dim, começando pela direção errada<span class="hx:absolute hx:-mt-20" id="fase-02-gamma-dim-começando-pela-direção-errada"></span>
    <a href="#fase-02-gamma-dim-come%c3%a7ando-pela-dire%c3%a7%c3%a3o-errada" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-02-gamma-dim-image.md"target="_blank" rel="noopener"><code>phase-02-gamma-dim-image.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> imagem do Driveclub tá dim comparada com referência. Deve ser sRGB encode errado, ou HDR tonemap mal aplicado pelo emulador.</li>
<li><strong>Ação:</strong> instrumentei a swapchain pra logar formato; adicionei env var <code>SHADPS4_PP_*</code> pra experimentar; montei pipeline de pós-processamento com três knobs (exposure, ACES tonemap, gamma curve).</li>
<li><strong>Conceito novo:</strong> sRGB OETF, HDR tonemap (ACES vs Reinhard), Bayer dither como anti-banding.</li>
<li><strong>Resultado:</strong> descobri via bypass path (<code>SHADPS4_PP_BYPASS=1</code>, escreve raw game output sem nenhum pós-processamento) que o <strong>jogo escreve SDR já correto</strong> no framebuffer. O pipeline de pós-processamento do emulador é que estava estragando o sinal. Shader final virou simplesmente sRGB encode + Bayer dither. Dim persiste, mas não é culpa de gamma.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/wrong-gamma.png" alt="Ajustes de gamma errando pra todo lado"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/wrong-gamma-blown.png" alt="Blown out: gamma em cima"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/wrong-gamma-sky-dark.png" alt="Céu escuro: gamma pra baixo"  loading="lazy" /></p>
<p>Três horas nessa fase. A lição mais importante é: <strong>quando &ldquo;a imagem tá estranha&rdquo;, o primeiro diagnóstico deveria ser um bypass path que mostra o raw game output</strong>. Se bypass tá certo, o emulador tá estragando o sinal. Pare de mexer no tonemap.</p>
<h3>Fase 03: v1.28 content access<span class="hx:absolute hx:-mt-20" id="fase-03-v128-content-access"></span>
    <a href="#fase-03-v128-content-access" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-03-v128-content-access.md"target="_blank" rel="noopener"><code>phase-03-v128-content-access.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> v1.28 extrai, mas o jogo diz &ldquo;content not released yet, download required&rdquo;.</li>
<li><strong>Ação:</strong> merge v1.28 em cima de v1.00, restaurar <code>param.sfo</code>, <code>disc_info.dat</code>, <code>keystone</code>.</li>
<li><strong>Conceito novo:</strong> PS4 cumulative patches, metadata do package.</li>
<li><strong>Resultado:</strong> resolvido. Detalhado no <a href="/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/">artigo anterior</a>.</li>
</ul>
<h3>Fase 04: MSAA depth + slow-motion<span class="hx:absolute hx:-mt-20" id="fase-04-msaa-depth--slow-motion"></span>
    <a href="#fase-04-msaa-depth--slow-motion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-04-slowness.md"target="_blank" rel="noopener"><code>phase-04-slowness.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> pistas à noite pitch black e o jogo &ldquo;parece lento&rdquo;.</li>
<li><strong>Ação:</strong> duas coisas separadas. Desabilitar patch XML de 60fps (que tava descolando render rate do logic tickrate). Implementar <code>ReinterpretMsDepthAsColor</code> no meu fork (pra permitir que o emulador resolva depth MSAA 4x pra color 1-sample, que o Driveclub precisa pro forward+ lighting nas pistas noturnas).</li>
<li><strong>Conceito novo:</strong> forward+ lighting (renderer que escreve cena em MSAA depth target e depois lê como color pra SSAO e volumetrics), MSAA depth resolve.</li>
<li><strong>Resultado:</strong> dois problemas resolvidos. Detalhado no <a href="/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/">artigo anterior</a>.</li>
</ul>
<h3>Fase 05: second pass no brilho<span class="hx:absolute hx:-mt-20" id="fase-05-second-pass-no-brilho"></span>
    <a href="#fase-05-second-pass-no-brilho" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-05-brightness-followup.md"target="_blank" rel="noopener"><code>phase-05-brightness-followup.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> já que o game escreve SDR correto, talvez um boost estático no pós-processamento ajude sem mexer em UBO feedback.</li>
<li><strong>Ação:</strong> testei linear boost (1.5x, 2.0x), gamma pre-encode (pow curve), auto-exposure cena-aware com peak+mean sampling.</li>
<li><strong>Resultado:</strong> tudo rollback. Linear boost clipa luz. Gamma introduz banding. Auto-exposure da minha camada cancela o slider manual do usuário. Não tem almoço grátis no pós-processamento. Imagem dim fica dim sem HDR real ou patch de shader.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/wrong-gamma-sky-dark.png" alt="Céu escuro demais"  loading="lazy" /></p>
<h3>Narrowing the blackout: o gate compartilhado<span class="hx:absolute hx:-mt-20" id="narrowing-the-blackout-o-gate-compartilhado"></span>
    <a href="#narrowing-the-blackout-o-gate-compartilhado" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/race-start-blackout-040420.md"target="_blank" rel="noopener"><code>race-start-blackout-040420.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> o blackout tem uma assinatura curiosa: main view vai pra dim/preto, retrovisor vai pra preto absoluto, HUD permanece brilhante. Três camadas com comportamentos diferentes sugerem um &ldquo;gate&rdquo; compartilhado, não um fade comum.</li>
<li><strong>Ação:</strong> instrumentei texture-cache aliasing, probes com live fragment shader substitution nos inputs suspeitos.</li>
<li><strong>Conceito novo:</strong> texture-cache aliasing (várias imagens com mesmo endereço de memória, cache do emulador reusa), render-target lifetime.</li>
<li><strong>Resultado:</strong> aponta pra &ldquo;permissão de apresentação&rdquo; compartilhada entre main scene e retrovisor, não um fade narrativo.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/screenshot-2026-04-20_21-22-45.png" alt="Baseline do blackout"  loading="lazy" /></p>
<h3>Fases 07-09: tortura de texturas, cirurgia de UI, plano de binary patch<span class="hx:absolute hx:-mt-20" id="fases-07-09-tortura-de-texturas-cirurgia-de-ui-plano-de-binary-patch"></span>
    <a href="#fases-07-09-tortura-de-texturas-cirurgia-de-ui-plano-de-binary-patch" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-07-aggressive-torture-probe.md"target="_blank" rel="noopener"><code>phase-07-aggressive-torture-probe.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-08-ui-asset-surgery.md"target="_blank" rel="noopener"><code>phase-08-ui-asset-surgery.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-09-eboot-binary-patch-plan.md"target="_blank" rel="noopener"><code>phase-09-eboot-binary-patch-plan.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> o overlay dim do race start é um asset. Textura pequena, panel da UI, ou método do controller <code>FreeplayGetInCar</code> no eboot.</li>
<li><strong>Ação:</strong> null-substituir materiais BC comprimidos, textures pequenas candidatas, four-vector weight masks durante draws críticos. Desabilitar painéis da UI (<code>loading_freeplay.txt</code>, <code>get_in_car_animation.txt</code>, <code>vehicle_select_background</code>). Extrair o OELF, localizar strings ASCII <code>FreeplayGetInCar</code>, identificar construtor em VA 0xf89b00 e vtable em 0x15dc3e0.</li>
<li><strong>Conceito novo:</strong> PS4 OELF loader (variant do ELF da Sony), Itanium C++ RTTI (como C++ encoda type info em vtables), SCE dynamic relocations (placeholders que só o loader dinâmico resolve em runtime).</li>
<li><strong>Resultado:</strong> nulls funcionam mas o fade persiste. O overlay renderiza direto nos HDR scene targets, não via panel system. Binary patch tem placeholder de relocation que não é resolvível estaticamente sem um Ghidra com PS4 plugin. <strong>Asset-side surface exhausted.</strong> Seis horas depurando, final conclusion: o bug vive em state, não em asset.</li>
</ul>
<h3>Fase 10: rethink + animlib<span class="hx:absolute hx:-mt-20" id="fase-10-rethink--animlib"></span>
    <a href="#fase-10-rethink--animlib" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-10a-rethink-040422.md"target="_blank" rel="noopener"><code>phase-10a-rethink-040422.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-10b-video-diagnostic-animlib.md"target="_blank" rel="noopener"><code>phase-10b-video-diagnostic-animlib.md</code></a></p>

</blockquote>
<p>Terça-feira de manhã. Sentei, reiniciei mentalmente. Modelo novo: o blackout é um <strong>state-machine gate</strong>. Não é &ldquo;cena não pronta&rdquo;, é &ldquo;permission transition&rdquo;. O gate fecha depois da grid de largada aparecer. Próximo probe: runtime dispatch trace, chega de blind asset surgery.</p>
<p>Em paralelo: extração de frame da gravação de vídeo a 10 Hz, cruzamento com keyframes de animation library (<code>animlib</code>) em <code>india_posteffects.lvl</code>. Encontramos smoking gun. Track <code>MasterBrightness</code> com keyframe 0.003 e 0.0007 (0.63% brightness), quando o default seria 1.0. Animlib vence inline defaults todo frame.</p>
<ul>
<li><strong>Conceito novo:</strong> animation library, keyframe encoding, float-scanning de binário.</li>
</ul>
<video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/debugging-blackout-fade.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Vídeo acima: o processo de probar pelo fade em real time.</p>
<h3>Fase 11: multi-scalar patch<span class="hx:absolute hx:-mt-20" id="fase-11-multi-scalar-patch"></span>
    <a href="#fase-11-multi-scalar-patch" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-11-multi-scalar-patch.md"target="_blank" rel="noopener"><code>phase-11-multi-scalar-patch.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> patchar <code>MasterBrightness</code> + <code>AutoTargetLuminance</code> + <code>ManualAutoMix</code> simultaneamente vai lift o blackout.</li>
<li><strong>Ação:</strong> estendi <code>PatchAnimlibFloatValues</code> pra reescrever três scalars. Instrumentei com <code>SHADPS4_DC_DRAWLOG</code> + <code>SHADPS4_DC_UBOLOG</code>.</li>
<li><strong>Resultado:</strong> patch produz um lift <strong>numérico</strong> real (1.2 → 6.5 em 255, um 5×), mas ainda é sub-perceptual black. E descobri o achado crucial: o mirror funciona normalmente após o patch. Não está gated, apenas refletindo uma cena escura. <strong>Pelo menos 285× de atenuação adicional vive downstream dos scalars que a gente pode patchar.</strong></li>
</ul>
<h3>Fase 12: bisect fechando o asset-side<span class="hx:absolute hx:-mt-20" id="fase-12-bisect-fechando-o-asset-side"></span>
    <a href="#fase-12-bisect-fechando-o-asset-side" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-12-bisect-closes-asset-side.md"target="_blank" rel="noopener"><code>phase-12-bisect-closes-asset-side.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> um dos 60 patches acumulados quebrou o mirror independente do blackout. Bisect.</li>
<li><strong>Ação:</strong> binary bisect em 60 overlay files ao longo de 5 rounds.</li>
<li><strong>Resultado:</strong> <code>x_live_lobby_pre_race.txt</code> (reroute de loading-spinner transition de <code>ZoomInAndFade</code> pra <code>NoFade</code>) era o mirror killer. Rollback. <strong>Asset-side completamente fechado.</strong> O driver vive em código compilado ou em post-process state, não em asset de jogo.</li>
</ul>
<h3>Asset sweeps 01-09 (consolidado)<span class="hx:absolute hx:-mt-20" id="asset-sweeps-01-09-consolidado"></span>
    <a href="#asset-sweeps-01-09-consolidado" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/asset-sweep-09-conclusions.md"target="_blank" rel="noopener"><code>asset-sweep-09-conclusions.md</code></a></p>

</blockquote>
<p>Em paralelo com as fases acima, varri 12 RPK substitutions: page swaps de <code>FreeplayGetInCar</code>, mexidas no postfx de <code>india_landscape_gui.rpk</code>, edits em <code>globaldata</code> RTT-only, rewrites de prerace state strings. <strong>Todos clean misses.</strong> Nenhuma família de asset toca o blackout. Lição: <strong>pare de chasing by names; chase por state transitions.</strong></p>
<h3>Fase 13: UBO dump breakthrough<span class="hx:absolute hx:-mt-20" id="fase-13-ubo-dump-breakthrough"></span>
    <a href="#fase-13-ubo-dump-breakthrough" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-13-ubo-dump-breakthrough.md"target="_blank" rel="noopener"><code>phase-13-ubo-dump-breakthrough.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> loop de feedback de eye-adaptation com input stale é o culpado. Um scalar de luminância crescendo sem convergir.</li>
<li><strong>Ação:</strong> dump de 128 bytes de UBO em hex durante a race window, em seis pipelines hand-picked. Procurar valores monotonicamente em mudança.</li>
<li><strong>Conceito novo:</strong> <strong>UBO (Uniform Buffer Object)</strong>, região de memória compartilhada que o CPU escreve e shaders leem. <strong>Auto-exposure integrator</strong>, componente clássico de eye adaptation que tira tempo pra convergir em direção a um target.</li>
<li><strong>Resultado:</strong> encontrei. <strong>Offset 3 do UBO sobe monotonicamente de 2.59 → 7.84 → 24 → 90 → 179 → 255</strong> em 2 segundos. Textbook feedback loop com input quebrado. Primeiro hit real em 12 fases.</li>
</ul>
<h3>Fase 14: scene-pipeline UBOs são o read-side<span class="hx:absolute hx:-mt-20" id="fase-14-scene-pipeline-ubos-são-o-read-side"></span>
    <a href="#fase-14-scene-pipeline-ubos-s%c3%a3o-o-read-side" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-14-scene-pipeline-ubos-wrong.md"target="_blank" rel="noopener"><code>phase-14-scene-pipeline-ubos-wrong.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> clampar o scalar que tá subindo vai parar o blackout.</li>
<li><strong>Ação:</strong> <code>SHADPS4_DC_LUM_CLAMP=2.0</code> força offset 3 a um valor fixo durante race window.</li>
<li><strong>Resultado:</strong> clamp dispara 1093 vezes, blackout inalterado. Scene-pipeline UBOs <strong>consomem</strong> o dim, não produzem. Dim tá upstream, em um tonemap ou post-fx compute fullscreen.</li>
</ul>
<h3>Fases 15-16: runtime texture dump + mutation<span class="hx:absolute hx:-mt-20" id="fases-15-16-runtime-texture-dump--mutation"></span>
    <a href="#fases-15-16-runtime-texture-dump--mutation" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-15-runtime-texture-dump.md"target="_blank" rel="noopener"><code>phase-15-runtime-texture-dump.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-16-runtime-texture-mutation.md"target="_blank" rel="noopener"><code>phase-16-runtime-texture-mutation.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> o blackout é uma textura fullscreen composta sobre a cena.</li>
<li><strong>Ação:</strong> <code>SHADPS4_DC_TEX_DUMP=1</code> dumpa todas as texturas bound durante race window (1079 texturas capturadas). Converter tiled-format pra PNG pra triagem visual. Depois, mutar deterministicamente cada textura via hash-based tint + <code>InvalidateMemory</code> pra forçar re-upload.</li>
<li><strong>Conceito novo:</strong> <strong>GCN tile format</strong> (Sony interleava bytes de forma específica pra cache locality), texture de-swizzle, buffer cache invalidation.</li>
<li><strong>Resultado:</strong> 14 rounds de mutação (BC textures, float data, render targets, UI atlases, post-fx buffers, LUTs). Blackout <strong>inalterado em todos</strong>. Texture content 100% descartado como source.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/blue-ish-overlay.png" alt="Overlay azul durante mutação"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/green-ish-overlay.png" alt="Overlay verde durante mutação"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/reflections-glitching-blown.png" alt="Reflections glitched"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/reflections-glitched-blown-white.png" alt="Reflections blown white"  loading="lazy" /></p>
<h3>Fases 17-19: UBO smashing, push-constant smashing, compute dispatch probe<span class="hx:absolute hx:-mt-20" id="fases-17-19-ubo-smashing-push-constant-smashing-compute-dispatch-probe"></span>
    <a href="#fases-17-19-ubo-smashing-push-constant-smashing-compute-dispatch-probe" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-17-ubo-batch-smashing.md"target="_blank" rel="noopener"><code>phase-17-ubo-batch-smashing.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-18-push-constant-smashing.md"target="_blank" rel="noopener"><code>phase-18-push-constant-smashing.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-19-compute-dispatch-probe.md"target="_blank" rel="noopener"><code>phase-19-compute-dispatch-probe.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> random-fill em UBOs, push constants e compute input buffers pode bracket and isolate o field do dim sem crashar.</li>
<li><strong>Ação:</strong> <code>SHADPS4_DC_UBO_SMASH=1</code>, <code>SHADPS4_DC_PC_SMASH=1</code>, <code>SHADPS4_DC_DISPATCH_SMASH=1</code> com filtros de cb-index e size.</li>
<li><strong>Conceito novo:</strong> <strong>push constants</strong> (128 bytes de param rápido que o driver empurra direto pro pipeline, sem descriptor), <strong>compute dispatches</strong> (dispara compute shaders com uma grid de threads), <strong>ud_regs</strong> (user data registers do GCN, como shadPS4 mapeia user-data pra push-constants).</li>
<li><strong>Resultado:</strong> brackets seguros geram overlay bokeh + blinks, mas dim inalterado. Brackets wide o suficiente pra pegar o dim também pegam matrices/transforms e crasham. <strong>Random-fill é instrumento errado.</strong> Precisa de diff methodology.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/all-bege.png" alt="Tudo bege depois de smash"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/all-green.png" alt="Tudo verde"  loading="lazy" /></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/all-cyan.png" alt="Tudo ciano"  loading="lazy" /></p>
<h3>Fase 19b-c: dim-vs-lift dispatch diff<span class="hx:absolute hx:-mt-20" id="fase-19b-c-dim-vs-lift-dispatch-diff"></span>
    <a href="#fase-19b-c-dim-vs-lift-dispatch-diff" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-19b-dim-vs-lift-diff.md"target="_blank" rel="noopener"><code>phase-19b-dim-vs-lift-diff.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-19c-dispatch-draw-skip-null.md"target="_blank" rel="noopener"><code>phase-19c-dispatch-draw-skip-null.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> compute dispatches que firam só durante dim (e param depois do lift) fazem parte do chain.</li>
<li><strong>Ação:</strong> dividir log limpo em pre / dim / bright windows (via user wall-clock), contar dispatch frequency por pipeline.</li>
<li><strong>Resultado:</strong> identificamos <strong>8 compute pipelines</strong> (histogram 256→downsamples, tile-grid reductions, auto-exposure 1x1 scalars) que param exatamente quando dim lifts. Shapes fortemente sugerem eye-adaptation chain. <strong>First genuine diagnostic hit.</strong> Skip test dessas 8 + 101 draws correlacionados: blackout <strong>inalterado</strong>. Elas são <strong>downstream effects</strong>, não drivers.</li>
</ul>
<h3>Fase 20-21: tonemap inline, fragment → flip buffer<span class="hx:absolute hx:-mt-20" id="fase-20-21-tonemap-inline-fragment--flip-buffer"></span>
    <a href="#fase-20-21-tonemap-inline-fragment--flip-buffer" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-20-shader-dump-tonemap-inline.md"target="_blank" rel="noopener"><code>phase-20-shader-dump-tonemap-inline.md</code></a> · <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-21-fragment-to-flip-buffer.md"target="_blank" rel="noopener"><code>phase-21-fragment-to-flip-buffer.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> o auto-exposure compute shader tá quebrado, ou o tonemap compute tá com a matemática errada.</li>
<li><strong>Ação:</strong> recompilar todos os shaders, dumpar SPIR-V, desmontar o histogram auto-exposure. Patchar a saída dele pra constante 1.0 e testar.</li>
<li><strong>Conceito novo:</strong> <strong>SPIR-V disassembly</strong> (formato intermediário do Khronos, tem assembly legível). <strong>Verificação de shader compute</strong>. Depois, <strong>pipeline-to-shader mapping</strong>.</li>
<li><strong>Resultado:</strong> patch <strong>sem efeito</strong>. Descoberta: <strong>Driveclub não tem tonemap pass separada</strong>. Scene geometry escreve direto no flip buffer, com exposure inline nos material shaders. Cada material shader bake o scalar de dim de um UBO compartilhado. Pipeline cache wipe + <code>SHADPS4_DC_PIPEMAP=1</code> dumpa todos os pipeline→shader mappings. Filtrar drawlog por pipelines que escrevem em <code>0x5000900000</code> / <code>0x5000108000</code> (os swapchain buffers de verdade) resulta em <strong>14 pipelines únicos</strong>. Zero com Exp2/Log2 tonemap ops. Exposure é aplicada upstream.</li>
</ul>
<h3>Fase 22: tonemap compute identified<span class="hx:absolute hx:-mt-20" id="fase-22-tonemap-compute-identified"></span>
    <a href="#fase-22-tonemap-compute-identified" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-22-tonemap-compute-identified.md"target="_blank" rel="noopener"><code>phase-22-tonemap-compute-identified.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> entre os 510 compute shaders do jogo, um deles tem assinatura de tonemap (muitos Exp2/Log2).</li>
<li><strong>Ação:</strong> scan automatizado, cross-reference com dispatchlog.</li>
<li><strong>Resultado:</strong> <strong><code>cs_0x2c918c06</code></strong> é o candidato forte, com 8 Exp2 + 8 Log2, 5 SSBOs (scene params, TAA, bloom, camera, exposure), 11 images. Skip test pra esse pipeline específico: <strong>para o blackout cycle</strong>, remove color grading, introduz temporal ghosting. <strong>Esse é o caminho final scene→swapchain pra tonemap.</strong></li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/temporal-glitching.png" alt="Temporal ghosting depois do skip"  loading="lazy" /></p>
<h3>Fase 22+: tonemap patches → playable<span class="hx:absolute hx:-mt-20" id="fase-22-tonemap-patches--playable"></span>
    <a href="#fase-22-tonemap-patches--playable" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-22plus-tonemap-compute-patches.md"target="_blank" rel="noopener"><code>phase-22plus-tonemap-compute-patches.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> dois SPIR-V surgical edits (histogram no-op + tonemap exposure clamp/boost) deixam o jogo jogável.</li>
<li><strong>Ação:</strong> patch de histogram pra nunca atualizar; patch de tonemap pra clampar exposure floor em 0.5 e boost blend por ×10. Ambos via SPIR-V patching + shader/patch/ drop-in.</li>
<li><strong>Resultado:</strong> <strong>playable!</strong> Dim reduz de pitch black pra mild. É uma <strong>mitigação real, não fix de causa-raiz.</strong> A fade curve ainda arrasta a exposição, e cada pista precisa de tuning per-threshold.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/blown-just-track-lights.png" alt="Luzes da pista explodindo após ×10 boost"  loading="lazy" /></p>
<video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/india-gamma-correction-attempt.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Aqui a IA sugeriu parar pela primeira vez. <strong>&ldquo;O jogo tá playable, isso é uma mitigação decente, deveríamos documentar e aceitar.&rdquo;</strong> Eu pressionei: &ldquo;tá playable mas tá errado. Não aceita. Continuamos.&rdquo;</p>
<h3>Fase 23: CPU-side exposure intercept<span class="hx:absolute hx:-mt-20" id="fase-23-cpu-side-exposure-intercept"></span>
    <a href="#fase-23-cpu-side-exposure-intercept" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-23-cpu-exposure-intercept.md"target="_blank" rel="noopener"><code>phase-23-cpu-exposure-intercept.md</code></a></p>

</blockquote>
<ul>
<li><strong>Hipótese:</strong> clampar o exposure scalar no momento do <code>BindBuffers</code> da tonemap compute previne o over-dimming.</li>
<li><strong>Ação:</strong> <code>SHADPS4_DC_EXPOSURE_PIN=1</code> intercepta <code>BindBuffers</code>, sobrescreve exposure offsets com clamp-min threshold, invalidate buffer_cache.</li>
<li><strong>Conceito novo:</strong> <strong>CPU-GPU buffer binding</strong> (momento em que o CPU entrega descriptor pro GPU). <strong>Buffer cache invalidation</strong> (como o emulator mantém consistency entre o estado CPU-side e GPU-side de um buffer).</li>
<li><strong>Resultado:</strong> scalar oscila no race start, depois sobe monotonicamente. Per-track tuning necessário. A Índia quer 3.0, o Canadá blows out no mesmo threshold. <strong>Solução de scalar único não converge cross-track.</strong></li>
</ul>
<video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/debugging-cli-gamma-correction.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<h3>Fase 24: dim upstream of tonemap<span class="hx:absolute hx:-mt-20" id="fase-24-dim-upstream-of-tonemap"></span>
    <a href="#fase-24-dim-upstream-of-tonemap" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-24-dim-upstream-of-tonemap.md"target="_blank" rel="noopener"><code>phase-24-dim-upstream-of-tonemap.md</code></a></p>

</blockquote>
<ul>
<li><strong>Conclusão:</strong> depois de toda a cadeia de probes (identity tonemap, exposure pin, compute skip), o dim <strong>está no HDR target antes</strong> do tonemap ler. Três upstream suspects: (1) atmospheric scattering / volumetric fog, (2) reflection-probe / envmap update, (3) pre-tonemap exposure apply.</li>
<li><strong>Conceito novo:</strong> <strong>atmospheric scattering</strong> (simulação de como luz viaja pela atmosfera, tipo Rayleigh/Mie), <strong>volumetric fog</strong> (neblina renderizada como froxel volume).</li>
<li><strong>Resultado:</strong> plano definido. Frame-order dump, andar pra trás da tonemap pela cadeia toda.</li>
</ul>
<h3>Fase 25: frame-order trace<span class="hx:absolute hx:-mt-20" id="fase-25-frame-order-trace"></span>
    <a href="#fase-25-frame-order-trace" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-25-frameorder-trace.md"target="_blank" rel="noopener"><code>phase-25-frameorder-trace.md</code></a></p>

</blockquote>
<ul>
<li><strong>Ação:</strong> <code>SHADPS4_DC_FRAMEORDER=&lt;N&gt;</code> loga strict per-submit pipeline/shader chain sobre N submits durante race window.</li>
<li><strong>Conceito novo:</strong> <strong>frame-order reconstruction</strong> (listar toda submission ao GPU em ordem exata), <strong>froxel volumetrics</strong> (volume frustum voxels, malha 3D alinhada ao frustum da câmera pra armazenar info de luz).</li>
<li><strong>Resultado:</strong> três suspeitos: (A) half-res compute <code>(60,34,1)</code>, provavelmente SSAO; (B) dispatches progressive <code>(256,1,1)→(2560,1,1)→(10240,1,1)</code>, froxel volumetric; (C) draw fullscreen apply-fog-to-HDR. <strong>Suspeito B</strong> é o mais forte (sunset best-fit, per-pixel non-uniform dim).</li>
</ul>
<h3>Fase 26: O UBO fade pin, o &ldquo;aha moment&rdquo;<span class="hx:absolute hx:-mt-20" id="fase-26-o-ubo-fade-pin-o-aha-moment"></span>
    <a href="#fase-26-o-ubo-fade-pin-o-aha-moment" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-26-ubo-fade-pin.md"target="_blank" rel="noopener"><code>phase-26-ubo-fade-pin.md</code></a></p>

</blockquote>
<p>Aqui mudou tudo.</p>
<ul>
<li><strong>Hipótese:</strong> memory diff direto (bright vs dim vs recovered) identifica os bytes exatos que o jogo escreve pra controlar o blackout.</li>
<li><strong>Ação:</strong> capturar snapshots periódicos de UBO através das transições visuais. Diffar três snapshots byte por byte. Procurar fade signatures.</li>
<li><strong>Conceito novo:</strong> <strong>state diff methodology</strong>. Ao invés de &ldquo;qual passagem parece suspeita?&rdquo;, perguntar &ldquo;quais bytes realmente mudam com o estado visual?&rdquo;</li>
<li><strong>Resultado:</strong> <strong>breakthrough.</strong> Dois UBOs controlam o fade: um de 1936 bytes com slots <code>[38/48/50]</code> (light intensity) sendo multiplicados por 0.094 (fade factor), e um sun UBO de 224 bytes com slot <code>[50]</code> caindo 97%. Pinar os dois: race start abre brilhante. TOD animation intacta. Content-aware three-state lifecycle (idle → engaged → expired).</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/touching-sun-light.png" alt="Primeiro toque no UBO de sun light"  loading="lazy" /></p>
<p>Quarta-feira à noite. Claude sugere parar de novo. <strong>&ldquo;Temos pin funcionando, three-state lifecycle robusto, Canadá + Munnar rodando. Isso é upstream-quality, deveríamos PR-ar e fechar.&rdquo;</strong> Eu insisto: &ldquo;ainda tem dim residual em outras pistas, não tá fechado. Continuamos.&rdquo;</p>
<h3>Fase 28: pivot pra emulator code<span class="hx:absolute hx:-mt-20" id="fase-28-pivot-pra-emulator-code"></span>
    <a href="#fase-28-pivot-pra-emulator-code" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-28-pivot-to-emulator-code.md"target="_blank" rel="noopener"><code>phase-28-pivot-to-emulator-code.md</code></a></p>

</blockquote>
<ul>
<li><strong>Realização:</strong> o dim residual no Canadá ao anoitecer não é um valor errado de UBO. É uma <strong>translation gap do emulador</strong>. O jogo roda correto no PS4 real, então shadPS4 tem algum caminho que traduz ou sincroniza errado.</li>
<li><strong>Ação:</strong> 5 candidatos de bug emulator ranqueados — HLE shader misidentification, image storage classification, layout transitions, IMAGE_STORE_MIP fallback, OpImageFetch LOD restriction.</li>
<li><strong>Conceito novo:</strong> <strong>HLE (High-Level Emulation)</strong>. Substituir funções complexas do sistema operacional do PS4 por implementações host-side. Diferente de LLE (low-level) que emula bit a bit. HLE é mais rápido mas pode divergir do comportamento real quando a implementação host não cobre todos os casos.</li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/canada-dim.png" alt="Canadá ao anoitecer ainda dim"  loading="lazy" /></p>
<h3>Fase 29: calibrated state + recording harness<span class="hx:absolute hx:-mt-20" id="fase-29-calibrated-state--recording-harness"></span>
    <a href="#fase-29-calibrated-state--recording-harness" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-29-calibrated-state.md"target="_blank" rel="noopener"><code>phase-29-calibrated-state.md</code></a></p>

</blockquote>
<ul>
<li><strong>Ação:</strong> <code>SHADPS4_DC_RECORD=1</code>. Recording harness que dumpa lighting UBOs periodicamente + cross-correlation com screenshots wall-clock.</li>
<li><strong>Resultado:</strong> descoberta importante. <strong>Slots <code>[144..295]</code> do UBO de 1936 bytes</strong> (30+ fields) ficam <strong>denormal/uninitialized</strong> pelos primeiros ~90 segundos de corrida. Na &ldquo;auto-recalibração&rdquo; dos 1:30, o jogo escreve os valores reais. <strong>Não é recovery mágico, é a CPU finalmente escrevendo os valores que já deveriam estar lá desde o frame 1.</strong> No PS4 estão prontos antes do primeiro frame; no shadPS4 atrasam 90s. <strong>Root cause vive num init gap do emulador.</strong></li>
</ul>
<h3>Fase 30: UBO writer audit<span class="hx:absolute hx:-mt-20" id="fase-30-ubo-writer-audit"></span>
    <a href="#fase-30-ubo-writer-audit" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-30-ubo-writer-audit.md"target="_blank" rel="noopener"><code>phase-30-ubo-writer-audit.md</code></a></p>

</blockquote>
<ul>
<li><strong>Ação:</strong> auditoria exaustiva de todos os caminhos que escrevem no slot <code>[38]</code> do UBO de 1936 bytes. 7 suspeitos ranqueados: (1) ObtainBuffer stream-copy race, (2) lazy RegionManager em memory_tracker, (3) histogram compute skip, (4) page-fault delayed invalidation, (5) readback gating, (6) buffer-coherency race, (7) push-constant.</li>
<li><strong>Status:</strong> auditoria incompleta. Antes de conseguir verificar cada suspeito, a Fase 31 curto-circuitou tudo.</li>
</ul>
<h3>Fase 31: readbacks_mode = Precise, a virada<span class="hx:absolute hx:-mt-20" id="fase-31-readbacks_mode--precise-a-virada"></span>
    <a href="#fase-31-readbacks_mode--precise-a-virada" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><blockquote>
  <p><a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-31-readbacks-mode-fix.md"target="_blank" rel="noopener"><code>phase-31-readbacks-mode-fix.md</code></a></p>

</blockquote>
<p>Quinta-feira de manhã. Cansado, pensando na suspeita <strong>#5, readback gating</strong>. Essa me coçava porque era a única dos 7 writers que tocava <em>timing</em> do read e não <em>correctness</em> do write.</p>
<ul>
<li><strong>Hipótese:</strong> ligar <code>readbacks_mode: 2 (Precise)</code> no config per-game faz o feedback loop funcionar sincronizando read do CPU a fresh GPU output.</li>
<li><strong>Ação:</strong> uma edit no <code>custom_configs/CUSA00003.json</code>. Boot. Corrida no Canadá à noite.</li>
<li><strong>Resultado:</strong> <strong>race start abre brilhante. Auto-exposure converge normalmente. Zero blackout. Zero recalibração aos 1:30. Night TOD natural.</strong></li>
</ul>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/23/driveclub-learning/almost-fixed.png" alt="Quase lá, o teste antes do final"  loading="lazy" /></p>
<p>Testes em Munnar. Mesmo resultado. Um inteiro. <strong>31 fases. 44 commits. 15.668 linhas. Resposta: um inteiro no config.</strong></p>
<p>Por que isso passou batido por 30 fases? O doc da Fase 31 tem a análise honesta:</p>
<ol>
<li><strong>Disfarce de sintoma.</strong> Progressive darkening parece exatamente com tonemap quebrado, shader ruim, ou scalar de exposure compilado errado. Toda probe dump-driven achou <strong>valores errados no UBO</strong>, que é verdade, mas descreve o downstream read, não o upstream gap.</li>
<li><strong>Red herring do <code>readback_linear_images</code>.</strong> Testei essa flag na Fase 29 e deu zero efeito, então concluí que &ldquo;a superfície de readback tá auditada&rdquo;. Esqueci que essa flag é pra <em>image</em> readbacks (linear images via <code>TextureCache::DownloadImageMemory</code>). O histogram SSBO é um <strong>buffer</strong>, caminho separado.</li>
<li><strong>Pinning piorando em vez de melhorar.</strong> Sobrescrever os slots [38/48/50] parecia prometer, mas nunca convergia. O jogo reescrevia em cima do pin a cada frame. Interpretei como &ldquo;o mecanismo de pin chega tarde demais no pipeline&rdquo;. Gastei as fases 27-29 movendo o pin pra mais cedo. O fix real era <strong>parar de clobber o GPU-side input que o integrator lê</strong>.</li>
<li><strong>Nunca auditei o caminho do readback de buffer.</strong> A auditoria da Fase 30 listou 7 candidatos de writer, mas todos eram sobre a correctness do <em>write</em>. Nenhum perguntou &ldquo;o que a CPU está lendo, esperando que o GPU tenha preenchido?&rdquo;</li>
</ol>
<h2>A técnica do shotgun<span class="hx:absolute hx:-mt-20" id="a-técnica-do-shotgun"></span>
    <a href="#a-t%c3%a9cnica-do-shotgun" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Tem uma coisa que eu quero registrar: <strong>os probes de tortura não são desperdício, são infraestrutura de aprendizado.</strong> E a metodologia por trás deles tem nome: shotgun.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/HkxVhFg81fs?start=40"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Se você tem uma suspeita, tipo &ldquo;o dim vem de alguma textura&rdquo;, a pior coisa que você pode fazer é começar investigando uma textura por vez, em profundidade. Driveclub tem 1079 texturas bound durante a race window. Se cada triagem detalhada leva 20 minutos, você gasta três dias num galho só dessa árvore, e ainda não sabe se o dim vem de textura. Pode até ser que a resposta não esteja na árvore inteira.</p>
<p>Shotgun resolve isso. Em vez de investigar uma por vez, você dispara em todas ao mesmo tempo. Muta cada textura bound com um tint hash-based, força re-upload, roda o jogo. Em 30 segundos você sabe se alguma delas afeta o dim. Se afeta, então o dim é texture-side e aí sim vale a pena começar a narrow down. Se não afeta, parabéns: você acabou de descartar a categoria &ldquo;textura&rdquo; inteira em 30 segundos. Muda de categoria, shotgun em UBOs. Nenhum hit? Shotgun em push constants. Nenhum hit? Shotgun em compute dispatches. Continua até algo reagir.</p>
<p><strong>Não comece tentando estreitar uma árvore que pode ser enorme.</strong> Você vai gastar semanas em folhas irrelevantes. Dê um tiro de shotgun no tronco primeiro. Veja qual galho reage. Aí sim, desce em detalhe dentro desse galho.</p>
<p>Foi isso que eu fiz, sem saber que estava fazendo, pelas 30 primeiras fases. 32 variáveis de ambiente de probe (<code>SHADPS4_DC_UBO_SMASH</code>, <code>SHADPS4_DC_PC_SMASH</code>, <code>SHADPS4_DC_DISPATCH_SMASH</code>, <code>SHADPS4_DC_TEX_NUKE_*</code>, <code>SHADPS4_DC_UBO_NUKE</code>, e mais). Batches randômicos, tints hash-based, substituições null. A maioria nunca apontou pro fix real. Mas cada rodada de shotgun descartou uma categoria inteira de modelo mental. &ldquo;Não é textura.&rdquo; &ldquo;Não é push-constant.&rdquo; &ldquo;Não são esses 8 compute pipelines.&rdquo; &ldquo;Não é UBO write-side em qualquer lugar dessa região.&rdquo; Cada descarte estreita o problema.</p>
<p><strong>E enquanto eu fazia isso, eu aprendia o sistema.</strong> Cada smash que crashava me dizia &ldquo;aqui vive um descriptor pointer crítico&rdquo;. Cada color tint que aparecia me dizia &ldquo;esse UBO alimenta essa passagem de composição&rdquo;. Cada dispatch que fira diferente entre dim/bright me mostrava onde está a fronteira interessante.</p>
<p><strong>Quando você não conhece o sistema, shotgun probes são um mapa.</strong> Você não usa eles pra encontrar a resposta. Você usa pra descobrir o terreno.</p>
<h2>O que eu sabia domingo vs quinta<span class="hx:absolute hx:-mt-20" id="o-que-eu-sabia-domingo-vs-quinta"></span>
    <a href="#o-que-eu-sabia-domingo-vs-quinta" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><strong>Domingo:</strong> zero em tudo. Todas as áreas abaixo eram caixas pretas pra mim.</p>
<p><strong>Quinta:</strong></p>
<ul>
<li>PS4 package format end-to-end (PKG → PFS → param.sfo → disc_info → keystone → npbind). Como v1.28 cumulative patches funcionam em cima de v1.00 base install.</li>
<li>Arquitetura do shadPS4 em resumo: <code>src/common</code>, <code>src/core</code> (OS emulation, libraries HLE), <code>src/shader_recompiler</code> (GCN→SPIR-V), <code>src/video_core</code> (Vulkan renderer, buffer cache, texture cache, page manager).</li>
<li>Pipeline gráfico completo: G-buffer → forward+ lighting (escreve MSAA depth) → read depth como color pra SSAO / volumetric froxel → post-fx compute → tonemap → composite → swapchain.</li>
<li>UBO vs push constant vs descriptor set. Quando usar cada um.</li>
<li>SPIR-V disassembly e re-assembly pra patching cirúrgico. Como identificar tonemap compute por assinatura de Exp2/Log2.</li>
<li>Forward+ lighting + MSAA depth resolve + como implementar ReinterpretMsDepthAsColor.</li>
<li>Buffer cache do shadPS4: <code>MemoryTracker</code>, <code>RegionManager</code>, <code>FaultManager</code>. Como page-fault vira GPU→CPU sync.</li>
<li><code>readbacks_mode</code>: Disabled / Relaxed / Precise. Qual tradeoff de cada. Por que Relaxed não basta pra feedback loops (ele só write-protect, não read-protect).</li>
<li>PS4 OELF → Itanium RTTI → SCE relocation → dynamic linker reasoning, mesmo sem ter feito o binary patch (o plano ficou documentado).</li>
</ul>
<p>Não virei expert em nada disso. Mas virei de <strong>total outsider</strong> pra <strong>operador razoavelmente orientado</strong>. E esse salto, como eu comento depois, foi a coisa mais valiosa dos 4 dias.</p>
<h2>A IA sugeria aceitar. A perseverança humana foi minha<span class="hx:absolute hx:-mt-20" id="a-ia-sugeria-aceitar-a-perseverança-humana-foi-minha"></span>
    <a href="#a-ia-sugeria-aceitar-a-perseveran%c3%a7a-humana-foi-minha" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu disse algumas vezes ao longo do artigo que &ldquo;Claude sugeriu parar&rdquo;. Quero ser justo e específico aqui: não foi uma falha da IA. Foi exatamente o comportamento correto de uma ferramenta inteligente: <strong>quando você tem algo que funciona razoavelmente bem, parar e documentar é frequentemente a escolha certa.</strong> O patch de tonemap na Fase 22+ fez o jogo playable. O pin de UBO na Fase 26 fez a imagem ficar bonita. O recording harness da Fase 29 cobriu a janela crítica. Todos eram pontos legítimos de parada.</p>
<p>Se você ler o <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/codex-conclusion.md"target="_blank" rel="noopener"><code>codex-conclusion.md</code></a>, documento que a IA produziu após a Fase 26 (ainda sem saber sobre a Fase 31), ela descreve a solução de então como &ldquo;<strong>a mitigation, not a root-cause fix</strong>&rdquo;. Admite honestamente o que sabíamos: o pin de UBO era um contra-ataque, não explicação. Esse é bom comportamento.</p>
<p>A diferença é que <strong>eu tinha um teimoso palpite de que algo ainda tava errado</strong>. Ela funcionava no sentido playable. Mas o custo (pin Driveclub-specific + patch SPIR-V de tonemap + per-track threshold tuning + não generalizar) era alto demais pra um fix supostamente de engineering-quality. Profissional senior reconhece quando a assimetria entre custo e entendimento aponta pra algo mais fundo. Não sempre acerta. Mas esse palpite merece ser escutado.</p>
<p>Quatro dias sem interrupção, das 8h à meia-noite, domingo, segunda, terça, quarta, e resolvido quinta de manhã. Quantas vezes a IA sugeriu &ldquo;honestly, we should just accept the current result and document&rdquo;? Umas 4 ou 5 vezes. Cada uma tecnicamente defensável. <strong>A perseverança humana é a diferença entre &ldquo;o jogo funciona bem o bastante&rdquo; e &ldquo;o jogo funciona, e eu sei por quê&rdquo;.</strong></p>
<h2>Custo real dessa jornada<span class="hx:absolute hx:-mt-20" id="custo-real-dessa-jornada"></span>
    <a href="#custo-real-dessa-jornada" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/investigation-effort-accounting.md"target="_blank" rel="noopener"><code>investigation-effort-accounting.md</code></a> catalogue tudo antes da limpeza. Uns highlights:</p>
<ul>
<li><strong>3 dias</strong> de trabalho ativo (Apr 21-23, 2026).</li>
<li><strong>33 phases</strong> numeradas + sweeps + side threads = 54 docs, 412 KB, <strong>6.867 linhas de prosa</strong>.</li>
<li><strong>44 commits</strong> no fork gamma-debug. <strong>15.668 linhas adicionadas</strong>, 1.204 removidas.</li>
<li><code>src/video_core/renderer_vulkan/vk_rasterizer.cpp</code> cresceu de 1.364 pra <strong>4.680 linhas</strong> (3.4×) com instrumentação, pin lifecycles, recording harness.</li>
<li><strong>32 env vars</strong> de probe definidas. <strong>1 efetivamente usada pra encontrar o bug</strong> (<code>SHADPS4_DC_LOG_STREAMCOPY</code>, na Fase 30).</li>
<li><strong>61 MB</strong> de log shadPS4 acumulado. <strong>57 MB</strong> de shader dumps (5.803 arquivos). ~<strong>470 MB</strong> totais de artifacts reclaimáveis depois de fechar.</li>
</ul>
<p>Resolution: <strong>1 inteiro no config.</strong></p>
<p>A proporção <strong>6.867 linhas de prosa : 1 inteiro</strong> me diverte. Mas ela não é uma piada de ineficiência. É o custo real de aprender um sistema que você não conhecia. Cada linha de prosa descartou uma hipótese. Cada commit ensinou uma camada do stack. O inteiro foi o fim; o caminho foi o produto.</p>
<p>Uma nota honesta: apesar das 15.668 linhas adicionadas no fork <code>gamma-debug</code>, <strong>quase nada disso presta pra contribuir upstream no shadPS4</strong>. O que está lá é instrumentação — torture probes, recording harness, pin lifecycles, calibrate-at-arm, snapshots de UBO, dezenas de env vars de debug. Código de diagnóstico, não código de produção. Diagnóstico que só faz sentido pro Driveclub naquelas condições específicas.</p>
<p>O fork vai ficar público, mas <strong>não como branch de contribuição pro projeto shadPS4</strong>. Infelizmente. Fica como documento de estudo: 54 arquivos md cobrindo o processo completo, 44 commits mostrando a sequência de hipóteses, descartes e falhas. É material pra quem quiser entender como foi o processo de depuração, ou pra reaproveitar algumas das técnicas em outras investigações similares. PR upstream-ready dali não sai.</p>
<h2>Fechamento<span class="hx:absolute hx:-mt-20" id="fechamento"></span>
    <a href="#fechamento" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sim, a solução final era um toggle de config que já existia. Está no código do shadPS4 há sete meses. Mas domingo à noite, zero conhecimento de PS4, zero conhecimento do emulator, zero noção de que auto-exposure era um GPU→CPU feedback loop, <strong>eu não tinha autoridade técnica pra dizer &ldquo;liga readbacks Precise, resolve&rdquo;</strong>.</p>
<p>Eu tive que ver a cadeia toda pra entender <em>por que</em> funciona. Por que Relaxed não basta (só write-protects, e o DriveClub lê, não escreve no SSBO do histograma). Por que Precise é caro (per-page mprotect + per-fault GPU stall). Por que o maintainer escondeu atrás de &ldquo;Advanced&rdquo; (Bloodborne trava, AMD cai pra 12 FPS). Por que ninguém na comunidade tinha conectado Precise com DriveClub antes: o compat tracker admite &ldquo;readbacks enabled&rdquo;, mas não cita o modo, e ninguém tinha visto a assinatura de drift monotônico pelo ângulo do loop GPU→CPU.</p>
<p>Essa é a diferença entre <strong>conhecer a resposta</strong> e <strong>conhecer o terreno o suficiente pra reconhecer a resposta</strong>. Pra junior que me pergunta &ldquo;como eu aprendo hoje na era da IA&rdquo;: essa é a minha resposta. Não pergunte. Mergulhe. Use a IA pra acelerar a busca, pra ler código em paralelo, pra indexar fóruns antigos, pra compilar, pra parsear logs. Mas <strong>insista em entender o porquê</strong>. Quando a IA sugerir &ldquo;vamos aceitar e documentar&rdquo; (e ela vai sugerir, porque esse comportamento é frequentemente correto), pergunte a si mesmo se você realmente entendeu a cadeia. Se ainda tiver a coceira de &ldquo;isso tá errado mas eu não sei por quê&rdquo;, continue.</p>
<p>Provavelmente você vai gastar 4 dias numa coisa que tem solução de um inteiro. Provavelmente você vai descobrir 5 caminhos errados antes do certo. Provavelmente a metade dos seus probes vão ser torture shotguns que nunca apontaram pro fix.</p>
<p>E provavelmente, quando terminar, você vai saber um domínio que você não conhecia.</p>
<ul>
<li><strong>Fork gamma-debug:</strong> <a href="https://github.com/akitaonrails/shadPS4/tree/gamma-debug"target="_blank" rel="noopener">github.com/akitaonrails/shadPS4/tree/gamma-debug</a></li>
<li><strong>54 docs da investigação:</strong> <a href="https://github.com/akitaonrails/shadPS4/tree/gamma-debug/docs/driveclub-investigation"target="_blank" rel="noopener">docs/driveclub-investigation/</a></li>
<li><strong>Operational runbook (recipe):</strong> <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener">distrobox-gaming/docs/driveclub-shadps4.md</a></li>
<li><strong>Resolução da Fase 31:</strong> <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-investigation/phase-31-readbacks-mode-fix.md"target="_blank" rel="noopener"><code>readbacks_mode: 2</code></a></li>
</ul>
<p>Agora eu vou jogar Driveclub. Corrida noturna no Canadá, brilho natural, sem blackout. Boa quinta-feira.</p>
]]></content:encoded><category>emulacao</category><category>games</category><category>aprendizado</category></item><item><title>Meus Retrogames de Corrida Favoritos Rodando no Meu Distrobox</title><link>https://akitaonrails.github.io/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/04/19/retrogames-de-corrida-favoritos-no-distrobox/</guid><pubDate>Sun, 19 Apr 2026 20:00:00 -0300</pubDate><description>&lt;p&gt;Eu passei o domingo inteiro nisso, e foi um dos domingos mais produtivos que eu tive em tempos. A missão foi específica: fechar os jogos de corrida simcade mais difíceis de emular, que eu quero rodar há anos, e só agora consegui chegar num estado confiável.&lt;/p&gt;
&lt;p&gt;No topo dessa lista estão dois monstros. Primeiro, &lt;strong&gt;&lt;a href="#driveclub-o-imposs%c3%advel-finalmente-poss%c3%advel"&gt;Driveclub&lt;/a&gt;&lt;/strong&gt; no shadPS4. É exclusivo de PS4, nunca foi portado, a Evolution Studios foi fechada, não tem remaster. Pra jogar fora do PS4 original, só via emulação, e emulação de PS4 ainda é a parte mais imatura da ecossistema hoje. Esse é &lt;strong&gt;de longe o mais difícil da lista&lt;/strong&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu passei o domingo inteiro nisso, e foi um dos domingos mais produtivos que eu tive em tempos. A missão foi específica: fechar os jogos de corrida simcade mais difíceis de emular, que eu quero rodar há anos, e só agora consegui chegar num estado confiável.</p>
<p>No topo dessa lista estão dois monstros. Primeiro, <strong><a href="#driveclub-o-imposs%c3%advel-finalmente-poss%c3%advel">Driveclub</a></strong> no shadPS4. É exclusivo de PS4, nunca foi portado, a Evolution Studios foi fechada, não tem remaster. Pra jogar fora do PS4 original, só via emulação, e emulação de PS4 ainda é a parte mais imatura da ecossistema hoje. Esse é <strong>de longe o mais difícil da lista</strong>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/19/distrobox-gaming/shadps4-launcher.png" alt="shadPS4 Qt Launcher mostrando DRIVECLUB CUSA00003 pronto pra rodar"  loading="lazy" /></p>
<p>Segundo, <strong><a href="#forza-motorsport-4-o-goat">Forza Motorsport 4 com Project Forza Plus</a></strong> no Xenia Canary. FM4 é o GOAT da era Xbox 360, Project Forza Plus é a mod comunitária que consolida patches e conteúdo, e fazer os dois rodarem juntos no Xenia com gráfico decente, sem crash de áudio e sem shadow bug, levou horas sérias de trial and error.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/19/distrobox-gaming/xenia-manager.png" alt="Xenia Manager com a coleção Forza do Xbox 360 instalada"  loading="lazy" /></p>
<p>Em torno desses dois eu organizei o resto do que eu já sabia que funcionava em algum nível, só faltava consolidar num setup repetível: <strong><a href="#gran-turismo-4">Gran Turismo 4 com Retexture 3.0 e HD HUD</a></strong>, <strong><a href="#gran-turismo-3-a-spec">Gran Turismo 3 com HD textures e widescreen</a></strong>, <strong><a href="#gran-turismo-2-spec-ii-mod">Gran Turismo 2 na mod Spec II</a></strong>, os Gran Turismos de PS3 (<a href="#gran-turismo-5">GT5</a> e <a href="#gran-turismo-6">GT6</a>), os Forza Horizon <a href="#forza-horizon-1-com-xe-mod">1</a> e <a href="#forza-horizon-2">2</a>, os <a href="#project-gotham-racing-3-e-4">PGRs</a>, <a href="#ridge-racer-v">Ridge Racer</a>, <a href="#enthusia-professional-racing">Enthusia</a>, <a href="#colin-mcrae-rally-1-e-2">Colin McRae</a>. Esses eu tinha ideia de como fazer, só precisava consolidar num setup que não volta a quebrar na próxima vez que eu reinstalar o sistema.</p>
<p>Antes de entrar no detalhe, preciso esclarecer duas coisas.</p>
<p>Primeiro, sobre a infra: não vou repetir aqui o como o setup foi montado. Já escrevi isso em detalhe no artigo <a href="/2026/04/11/distrobox-de-emulacao-com-claude-code/">Distrobox de Emulação com Claude Code</a>. Arch Linux num distrobox com <code>--nvidia</code>, 17 roles Ansible, todos os emuladores no AUR, ES-DE como frontend, configs per-game automatizadas, scripts Python pra PS3 update check e Xbox 360 title updates, Xenia via Wine. Lê lá. O repo tá em <a href="https://github.com/akitaonrails/distrobox-gaming"target="_blank" rel="noopener">akitaonrails/distrobox-gaming</a> pra quem quiser reproduzir. Aqui eu vou falar dos jogos.</p>
<p>Segundo, sobre o gosto: eu gosto de simcade de corrida. Gran Turismo é meu vício declarado desde o PS1, e escrevi sobre o resto no artigo do <a href="/2026/04/01/meu-cockpit-de-sim-racing-formula-fx1/">meu cockpit Formula FX1</a>. Volante direct drive, pedal com load cell, triple monitor quando tô afim de sofrer. Esse é o tipo de corrida que eu gosto.</p>
<h2>O aviso pra quem já tá de dedo no teclado<span class="hx:absolute hx:-mt-20" id="o-aviso-pra-quem-já-tá-de-dedo-no-teclado"></span>
    <a href="#o-aviso-pra-quem-j%c3%a1-t%c3%a1-de-dedo-no-teclado" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sim, eu conheço iRacing e os outros sims e simcades atuais. Eu tenho 12 TB de ISO e ROM no NAS, provavelmente tenho algum que você ia lembrar de citar. Não é por falta de opção que eu tô focando em emulação hoje.</p>
<p>Aliás, dos jogos novos que eu realmente tô esperando: <strong><a href="https://forza.net/"target="_blank" rel="noopener">Forza Horizon 6</a> em Tóquio</strong>, <strong><a href="https://www.assettocorsa.it/"target="_blank" rel="noopener">Assetto Corsa EVO</a></strong> e <strong><a href="https://www.assettocorsa.it/"target="_blank" rel="noopener">Assetto Corsa Rally</a></strong>. Tô jogando as demos dos dois Assetto Corsa e gostando muito das campanhas single-player. Quando eles saírem em versão final, vão virar meus jogos principais de sim na rotina. Esse artigo aqui cobre um lado diferente da coleção, que é tirar do esquecimento os clássicos que ainda não têm remaster.</p>
<p>Hoje, aqui, eu estou interessado nesses jogos específicos que listei acima. Ponto. Você faz o que você quer, eu faço o que eu quero. Se você quer iRacing, abra um Steam e vá em paz. Esse artigo é sobre mexer com emulador, preservar jogo velho, e tirar essas pérolas do esquecimento num setup Linux. Quem tá procurando review de sim atual não vai encontrar aqui.</p>
<p>Agora vamos ao que interessa.</p>
<p><strong>Observação sobre os vídeos:</strong> a maioria tá sem áudio porque eu esqueci de ligar a captura de som no OBS antes de gravar e fiquei com preguiça de re-gravar. O áudio funciona perfeito em todos os emuladores aqui, é falha minha no OBS, não do setup.</p>
<h2>Settings globais por emulador<span class="hx:absolute hx:-mt-20" id="settings-globais-por-emulador"></span>
    <a href="#settings-globais-por-emulador" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Antes dos jogos, vale consolidar as configs globais que valem pra tudo em cada emulador. Isso tá automatizado no repo, mas se você tá configurando na mão, aqui tá o resumo.</p>
<h3>DuckStation (PS1)<span class="hx:absolute hx:-mt-20" id="duckstation-ps1"></span>
    <a href="#duckstation-ps1" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Renderer:</strong> Vulkan</li>
<li><strong>Internal Resolution Scale:</strong> 8x (8K render, downscalado pro monitor)</li>
<li><strong>Texture Filtering:</strong> JINC2 (preserva pixel art mas suaviza)</li>
<li><strong>PGXP:</strong> ligado (corrige wobble de vértice típico do PS1)</li>
<li><strong>Widescreen Hack:</strong> ligado como fallback, mas preferência por cheat widescreen per-game</li>
<li><strong>Aspect Ratio:</strong> 16:9 com widescreen cheat, 4:3 sem</li>
</ul>
<p>PS1 hoje em dia sobe liso no DuckStation. É o emulador mais maduro da lista. A atenção vai pras escolhas per-game (alguns jogos precisam de cheat específico de widescreen).</p>
<h3>PCSX2 (PS2)<span class="hx:absolute hx:-mt-20" id="pcsx2-ps2"></span>
    <a href="#pcsx2-ps2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Renderer:</strong> Vulkan</li>
<li><strong>Upscale:</strong> 4x SSAA (1440p nativo → 4K interno)</li>
<li><strong>Anisotropic Filtering:</strong> 16x</li>
<li><strong>Post Processing:</strong> FXAA ligado, PCRTC antiblur ligado</li>
<li><strong>Deinterlacing:</strong> Automatic (alguns jogos precisam override)</li>
<li><strong>Controller:</strong> bindings Xbox-style (eu uso controle 8BitDo)</li>
</ul>
<p>PCSX2 2.7.x é muito superior ao 2.6.3 que ainda tá no repo oficial do Arch. O AUR <code>pcsx2-latest-bin</code> tracka o 2.7.x e é onde mora o texture replacement, FXAA moderno e PCRTC antiblur. Se você tá em distro diferente e tá no 2.6.3, procure o AppImage oficial.</p>
<h3>RPCS3 (PS3)<span class="hx:absolute hx:-mt-20" id="rpcs3-ps3"></span>
    <a href="#rpcs3-ps3" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Renderer:</strong> Vulkan</li>
<li><strong>Resolution Scale:</strong> 300% (geralmente) ou nativo (jogos com issue de upscale)</li>
<li><strong>Shader Precision:</strong> Ultra</li>
<li><strong>Force High Precision Z:</strong> ligado</li>
<li><strong>SPU XFloat:</strong> Accurate</li>
<li><strong>Multithreaded RSX:</strong> ligado</li>
<li><strong>Write Color Buffers (WCB) / Read Color Buffers (RCB):</strong> desligados por padrão (GT-series safety)</li>
</ul>
<p>RPCS3 é onde mais tem armadilha. Cada jogo tem preset recomendado na <a href="https://rpcs3.net/compatibility"target="_blank" rel="noopener">DB de compatibilidade oficial</a>. E atenção: configs per-game ficam em <code>~/.config/rpcs3/custom_configs/config_&lt;SERIAL&gt;.yml</code>. Prefixo <code>config_</code> obrigatório. Perdi tempo até descobrir isso, o RPCS3 aceita o YAML silenciosamente e depois ignora se o nome tá errado.</p>
<h3>Xenia Canary (Xbox 360)<span class="hx:absolute hx:-mt-20" id="xenia-canary-xbox-360"></span>
    <a href="#xenia-canary-xbox-360" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>Build:</strong> Canary (o <code>master</code> tá parado há meses, Canary é o que anda)</li>
<li><strong>Renderer:</strong> Vulkan</li>
<li><strong>Render Target Path:</strong> <code>rtv</code> por default, <code>fsi</code> pra jogos específicos (PGR4)</li>
<li><strong>User Profile:</strong> criado uma vez, persiste</li>
<li><strong>Wine Prefix:</strong> dedicado, gerenciado pelo Xenia Manager</li>
</ul>
<p>Xenia no Linux roda via Wine, gerenciado pelo <a href="https://github.com/xenia-manager/xenia-manager"target="_blank" rel="noopener">Xenia Manager</a>. Não tem build nativo decente. Funciona bem, mas cada jogo pede ajuste específico, e Title Updates tem que ser puxado manualmente do archive.org (escrevi um script pra isso, detalhes no artigo anterior).</p>
<h3>shadPS4 (PS4)<span class="hx:absolute hx:-mt-20" id="shadps4-ps4"></span>
    <a href="#shadps4-ps4" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Esse merece a seção dedicada no final. Resumindo: funciona pra alguns jogos simples, pra Driveclub ainda não é confiável. Continua sendo um tiro no escuro.</p>
<h2>PS1 no DuckStation<span class="hx:absolute hx:-mt-20" id="ps1-no-duckstation"></span>
    <a href="#ps1-no-duckstation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Gran Turismo (o primeiro, de 1997)<span class="hx:absolute hx:-mt-20" id="gran-turismo-o-primeiro-de-1997"></span>
    <a href="#gran-turismo-o-primeiro-de-1997" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%201.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Esse aqui é puro sentimento. GT1 foi um dos primeiros jogos que eu comprei pro PS1, e joguei até rachar o CD. Na época, era outro patamar. Simulação real numa máquina de 128K de RAM de vídeo, física decente, 140 carros quando todo mundo tinha 15, trilha sonora memorável.</p>
<p>Mas sejamos honestos: não dá pra voltar hoje. A física do GT1 tem drift exagerado, o carro desliza mais do que deveria em qualquer curva acima de 80 km/h. É parte do charme de 1997 mas irrita em 2026. O <strong>modelo de controle foi muito refinado a partir do GT2</strong>, e tudo que veio depois só melhorou. Entre GT1 e GT2, GT2 vence em conteúdo (650+ carros vs 140) e principalmente em dirigibilidade.</p>
<p>Eu deixo o GT1 no ES-DE pra abrir em momentos de nostalgia, jogar uns 10 minutos em Trial Mountain e fechar. Pra gameplay sério da era PS1, vai de GT2.</p>
<h3>Gran Turismo 2 (Spec II Mod)<span class="hx:absolute hx:-mt-20" id="gran-turismo-2-spec-ii-mod"></span>
    <a href="#gran-turismo-2-spec-ii-mod" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%202.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>O Gran Turismo original do PS1 é um marco histórico. Eu joguei muito na época. Hoje, pra jogar de novo? Não. GT2 existe, e GT2 é superior em tudo. Mais carros (650+), mais pistas, mais modos, e principalmente, <strong>um modelo de controle muito melhor</strong>. O GT1 tem aquele drift exagerado onde o carro desliza mais do que deveria, o GT2 ajustou isso pra algo mais próximo do que a série seria a partir do PS2. Entre jogar GT1 ou GT2, sempre GT2.</p>
<p>E o GT2 que eu rodo hoje é o <strong>GT2 Spec II Mod</strong> do <a href="https://x.com/projectaspec?lang=en"target="_blank" rel="noopener">Project A-Spec</a>, um projeto comunitário que consolida as duas variantes regionais (Arcade + Simulation) num único jogo, traz de volta eventos que foram cortados no release final, corrige bugs de física, adiciona suporte a widescreen nativo e dá quality-of-life updates em menus. É o jeito definitivo de jogar GT2 em 2026. O projeto não mantém mais site próprio, as atualizações vêm pelo Twitter do autor.</p>
<p>Pra rodar:</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Disco</td>
          <td>GT2 Spec II Mod (patch aplicado sobre ISO Simulation USA)</td>
      </tr>
      <tr>
          <td>Serial</td>
          <td>SCUS-94455</td>
      </tr>
      <tr>
          <td>Widescreen cheat</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>8 MB RAM cheat</td>
          <td>Ligado (corrige áudio em pistas cheias)</td>
      </tr>
      <tr>
          <td>Texture Filter</td>
          <td>JINC2</td>
      </tr>
      <tr>
          <td>Resolution Scale</td>
          <td>8x</td>
      </tr>
  </tbody>
</table>
<p>O cheat de 8 MB RAM é importante pra pistas cheias (tipo Seattle em corridas populated) onde o áudio começa a estourar. Ele simula a expansão de memória da versão japonesa que nunca veio pro Ocidente.</p>
<h3>Colin McRae Rally 1 e 2<span class="hx:absolute hx:-mt-20" id="colin-mcrae-rally-1-e-2"></span>
    <a href="#colin-mcrae-rally-1-e-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Jogos icônicos do PS1. CMR1 tem aquela sensação áspera de rally primeiro-gen que tem seu charme. CMR2 é tecnicamente superior, física melhor, mais rallys, melhor grafia. Mas eu vou ser honesto: <strong>pra jogar CMR2 hoje, vale procurar a versão PC original</strong>. Resolução maior, 60fps nativo (a versão PS1 trava em 30), controle direto de teclado/volante. Existem repacks do Codemasters na internet, tem umas 40 segundos num search decente. Não vou linkar, você sabe onde procurar.</p>
<p>No PS1 via DuckStation eles rodam liso, nostalgia garantida, mas não é onde eu passo o tempo.</p>
<h2>PS2 no PCSX2<span class="hx:absolute hx:-mt-20" id="ps2-no-pcsx2"></span>
    <a href="#ps2-no-pcsx2" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Gran Turismo 3 A-Spec<span class="hx:absolute hx:-mt-20" id="gran-turismo-3-a-spec"></span>
    <a href="#gran-turismo-3-a-spec" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%203.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>GT3 foi um salto geracional. Saiu do mundo quadradinho do PS1 pra um mundo de shaders, environment mapping decente, modelos de carro com polígono sério, física que finalmente começou a parecer com física de verdade. A trilha sonora com Feeder de &ldquo;Just a Day&rdquo; abrindo o jogo ainda me dá arrepio.</p>
<p>O problema é que GT3 tem MENOS conteúdo que GT2. Polyphony foi mais cautelosa, cortou modos pra focar em qualidade. Licença A/B/S é menor, carros são menos, pistas são fewer. Mas o que tem é polido.</p>
<p>Em 2026 no PCSX2 2.7.x, GT3 fica muito bom. HD textures de comunidade, widescreen pnach, anti-aliasing via SSAA, 16x AF. Parece jogo relançado.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Disco</td>
          <td>GT3 A-spec (SCUS-97102) ou Bundle (PBPX-95503)</td>
      </tr>
      <tr>
          <td>Widescreen pnach</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>Pack de retextura</td>
          <td>Opcional (desativado por default, ativar se quiser ver tudo HD)</td>
      </tr>
      <tr>
          <td>Upscale</td>
          <td>4x SSAA</td>
      </tr>
      <tr>
          <td>Deinterlacing</td>
          <td>Automatic</td>
      </tr>
  </tbody>
</table>
<p>Caveat sobre o pack de retextura: quando ligado, tem cenas de mostruário de carro no garage onde o NFS stream causa um flicker momentâneo. Não incomoda em corrida. Se te irrita no menu, desliga.</p>
<p><strong>Lembrete:</strong> pro widescreen pnach fazer efeito você ainda precisa entrar nas opções <strong>dentro do jogo</strong> e mudar o aspect ratio pra 16:9. O pnach libera a opção no menu, não aplica automaticamente.</p>
<h3>Gran Turismo 4 (Spec II Mod)<span class="hx:absolute hx:-mt-20" id="gran-turismo-4-spec-ii-mod"></span>
    <a href="#gran-turismo-4-spec-ii-mod" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%204.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>GT4 é o meu GOAT da série. 700+ carros, 50+ circuitos, física ainda respeitável pra padrão 2026, e aquela trilha sonora que mistura rock alternativo, lounge japonês, e o infame &ldquo;Sail Away&rdquo; do Moby no menu principal. Foi o jogo que mais mexi em 2004, e é o que eu mais mexo hoje.</p>
<p>Igual o GT2, o GT4 que eu rodo hoje <strong>não é o disco original</strong>. É o <a href="https://www.theadmiester.co.uk/specii/"target="_blank" rel="noopener"><strong>Gran Turismo 4: Spec II</strong></a> mantido pelo TheAdmiester — uma mod comunitária massiva que é objetivamente o melhor jeito de jogar GT4 em 2026. Ela combina o disco final USA, a Beta prototype de 2003 e o release japonês original num único jogo, restaurando carros cortados (incluindo vários que nunca saíram fora do Japão), eventos cancelados, dezenas de faixas de trilha sonora faltantes, suporte a widescreen 16:9, mais de 30 cheats integrados como opções de menu (pro tuning, velocidade máxima, economia de combustível), opção de trocar entre idiomas Inglês/Japonês, e correções de bugs originais. O projeto é ativo, ainda recebe patches e tem instalador próprio que aplica sobre uma ISO USA limpa.</p>
<p>Na prática, Spec II é o que o GT4 deveria ter sido se a Polyphony tivesse tido mais seis meses pra polir. Quando você joga hoje, é GT4 com todo o conteúdo que ficou de fora + quality-of-life moderno. Pra qualquer um que gostou do original, é obrigatório.</p>
<p>Por cima disso vai o <strong>Retexture 3.0</strong> da comunidade (pack de textura HD) e o <strong>HD HUD</strong> do <a href="https://github.com/Silentwarior112/GT4-HD-HUD-Pack"target="_blank" rel="noopener">Silentwarior112</a>. Com essas três peças juntas (Spec II Mod + Retexture + HD HUD), GT4 roda a 1440p SSAA no PCSX2 2.7.x com 16x AF, FXAA, e uma cara que honestamente é indistinguível de um jogo novo em low-poly style. É o meu atual favorito pra sentar e jogar longo.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Disco</td>
          <td>GT4 USA (SCUS-97328) ou Spec II (SCUS-97436, CRC <code>4CE521F2</code>)</td>
      </tr>
      <tr>
          <td>HD HUD pack</td>
          <td>Instalado via symlink (Silentwarior112)</td>
      </tr>
      <tr>
          <td>Retexture 3.0</td>
          <td>Instalado</td>
      </tr>
      <tr>
          <td>Widescreen pnach</td>
          <td>Ligado (renomeado pro CRC do Spec II se for Spec II)</td>
      </tr>
      <tr>
          <td>Silent&rsquo;s trigger/camera patches</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>Deinterlace (Spec II)</td>
          <td>Mode 8 Adaptive TFF</td>
      </tr>
      <tr>
          <td>ShadeBoost (Spec II)</td>
          <td>Saturation +10, Brightness +3, Contrast +2</td>
      </tr>
      <tr>
          <td>FXAA + PCRTC antiblur</td>
          <td>Ligado global</td>
      </tr>
      <tr>
          <td>Upscale</td>
          <td>4x SSAA</td>
      </tr>
  </tbody>
</table>
<p>Quem tá usando o Spec II Mod precisa atentar pro CRC: os HD packs do GT4 vanilla foram feitos pro <code>77E61C8A</code> (USA), então no Spec II com CRC <code>4CE521F2</code> eu linko os assets via symlink na pasta CRC-suffixed que o PCSX2 procura. O pnach de widescreen também foi renomeado pra bater com o CRC do Spec II. Sem esse cuidado, o jogo roda mas os mods não carregam.</p>
<p><strong>Lembretes in-game:</strong> igual ao GT3, o widescreen pnach só libera a opção, você ainda precisa entrar em Options dentro do jogo e trocar pra 16:9. E importante: <strong>mude o modo de vídeo pra progressive 480p</strong> (também em Options). O default é interlaced 480i, que fica péssimo em tela moderna. O Spec II Mod tem suporte nativo a progressive, é só ligar.</p>
<p>Se eu pudesse recomendar um único GT da série pra alguém começar hoje, seria esse. Se você gosta de corrida e nunca jogou GT4 full, tá perdendo.</p>
<h3>Enthusia Professional Racing<span class="hx:absolute hx:-mt-20" id="enthusia-professional-racing"></span>
    <a href="#enthusia-professional-racing" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/enthusia.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Enthusia é o jogo esquecido da Konami de 2005. Saiu na sombra do GT4 e morreu no balcão. É uma pena, porque a <strong>física do Enthusia era mais realista que a do GT4</strong>. Peso do carro, transferência de massa, comportamento em limite, tudo mais próximo do comportamento real. A comunidade sim-racing dos anos 2000 sabia disso e o jogo tem culto hoje.</p>
<p>O problema do Enthusia era o sistema de Enthusia Points: você ganhava pontos por andar limpo, perdia por bater, e a progressão do jogo dependia desses pontos. Muita gente achou punitivo. Eu achei perfeito. Forçava você a dirigir com cabeça.</p>
<p>Em PCSX2 com retexture e widescreen, o jogo fica muito bom. Recomendação forte pra quem quer algo diferente dos Gran Turismo.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Disco</td>
          <td>Enthusia Professional Racing (SLUS-20967)</td>
      </tr>
      <tr>
          <td>Widescreen pnach</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>Retexture</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>Upscale</td>
          <td>4x SSAA</td>
      </tr>
  </tbody>
</table>
<h3>Ridge Racer V<span class="hx:absolute hx:-mt-20" id="ridge-racer-v"></span>
    <a href="#ridge-racer-v" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/ridge%20racer%20v.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Ridge Racer é sua própria coisa. Não é simcade, é arcade puro. Drift tudo, colinha dinâmica, trilha sonora eletrônica, cores saturadas. Ridge Racer V foi o jogo de lançamento do PS2 no Japão e por isso tem aquele cheiro de &ldquo;mostra o que o console pode fazer&rdquo;, com cenários colossais e sensação de velocidade que GT nunca tentou.</p>
<p>No PCSX2 ele roda bem, com uma caveira: textura de carro às vezes flicka em hardware renderer (issues <a href="https://github.com/PCSX2/pcsx2/issues/3639"target="_blank" rel="noopener">#3639</a> e <a href="https://github.com/PCSX2/pcsx2/issues/13729"target="_blank" rel="noopener">#13729</a> do PCSX2). Software renderer resolve mas mata performance. Eu fico no hardware e aceito o flicker ocasional.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Disco</td>
          <td>Ridge Racer V (SLUS-20002)</td>
      </tr>
      <tr>
          <td>Widescreen pnach</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>No-interlace pnach</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>Upscale</td>
          <td>4x SSAA</td>
      </tr>
  </tbody>
</table>
<h3>Colin McRae Rally 3, 4, 5 (PS2)<span class="hx:absolute hx:-mt-20" id="colin-mcrae-rally-3-4-5-ps2"></span>
    <a href="#colin-mcrae-rally-3-4-5-ps2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Versões de PS2 dos Colin McRae rodam bem no PCSX2 com configs default. CMR3 e CMR04 são bons. CMR05 (o último antes do rebrand pra Dirt) é o melhor dos três tecnicamente. Mas de novo: <strong>se você tá em PC, procura a versão nativa</strong>. Os ports de PS2 eram relativamente inferiores aos PC da época, rodavam em resolução menor, e o PC moderno com repack vai dar 144Hz fácil.</p>
<p>Fica o registro no PCSX2 pra completude da coleção.</p>
<h2>PS3 no RPCS3<span class="hx:absolute hx:-mt-20" id="ps3-no-rpcs3"></span>
    <a href="#ps3-no-rpcs3" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Gran Turismo 5<span class="hx:absolute hx:-mt-20" id="gran-turismo-5"></span>
    <a href="#gran-turismo-5" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%205.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>GT5 é controverso. Polyphony prometeu mundos e entregou um jogo meio fragmentado: modelos Premium lindos ao lado de Standard que eram basicamente carros do GT4 em HD, sistema de níveis que alguns amaram e outros detestaram, online que foi pra lama quando o serviço PSN desligou, modo Top Gear que era estranho. A crítica na época foi mista, e eu lembro de comunidades inteiras brigando sobre se o jogo era decepção ou genial.</p>
<p>Pra mim, é genial. GT5 tem o Course Maker (edita tua própria pista baseada em seções reais), o Nurburgring 24h real com chuva dinâmica, o Moon Rover (sim, modo de dirigir na Lua), Red Bull X-Challenge com Vettel, e a experiência de endurance single-player é ridiculamente grande. Quem entrou no jogo a fundo sabe que tem conteúdo pra ano inteiro.</p>
<p>No RPCS3 em 2026, GT5 roda <strong>muito bem</strong>. Estável, sem os bugs graves de anos passados. É o GT mais estável que eu tenho emulado hoje.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Serial</td>
          <td>BCUS98114 (US) ou BCES00569 (EU)</td>
      </tr>
      <tr>
          <td>Resolution Scale</td>
          <td>300%</td>
      </tr>
      <tr>
          <td>Shader Precision</td>
          <td>Ultra</td>
      </tr>
      <tr>
          <td>Force High Precision Z</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>SPU XFloat</td>
          <td>Accurate</td>
      </tr>
      <tr>
          <td>Multithreaded RSX</td>
          <td>Ligado</td>
      </tr>
      <tr>
          <td>WCB / RCB</td>
          <td>Desligados</td>
      </tr>
  </tbody>
</table>
<p>A combinação Shader Precision Ultra + Force High Precision Z mata o dithering típico do RSX que fazia GT5 parecer granulado em RPCS3 antigamente. Sem esses dois, o asfalto parece ter ruído constante. Com eles, o jogo fica limpo.</p>
<h3>Gran Turismo 6<span class="hx:absolute hx:-mt-20" id="gran-turismo-6"></span>
    <a href="#gran-turismo-6" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/gran%20turismo%206.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>GT6 é um dos meus preferidos da série. Saiu em 2013 pra um PS3 no final de vida, enquanto a concorrência já olhava pra PS4. Vendeu mal. Muita gente não jogou. E é uma pena, porque GT6 pegou a base do GT5, cortou a gordura (Standards foram reduzidos), adicionou mais Premiums, sessões em circuito no Moon melhores, meteorologia dinâmica em mais pistas, refinamento de física. É basicamente o GT5 polido.</p>
<p>Em conteúdo, GT6 é comparável ao GT4. Muitos jogadores da velha guarda botam o GT4 acima por causa do charme da era PS2. Eu fico entre os dois e vou mais pro GT6 em dia normal, GT4 em dia nostálgico.</p>
<p>Em RPCS3, GT6 tem uma pegadinha grave: <strong>patches 1.06 em diante regridem visualmente</strong>. Superfícies pretas em carros no menu garagem, flicker em cockpit view, tela inteira piscando em certas pistas. A versão que funciona bem em 2026 é <strong>travada em v1.05</strong>. O script <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/scripts/extract_ps3_dlc.py"target="_blank" rel="noopener"><code>extract_ps3_dlc.py</code></a> do repo tem um ceiling por título específico pra pinar GT6 em 1.05 mesmo quando o PSN cuspa 1.22 como &ldquo;mais recente&rdquo;.</p>
<p>Além disso, Force CPU Blit é mandatório. Sem ele, tem flicker de tela inteira em menu. O trade-off é que o retrovisor fica permanentemente preto. Eu prefiro perder o retrovisor a ter o flicker. Quem quer retrovisor pode ligar Write Color Buffers, mas aí a resolução cai pra 720p nativo.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Serial</td>
          <td>BCES01893 + variantes regionais</td>
      </tr>
      <tr>
          <td>Versão travada</td>
          <td>v1.05 (patches 1.06+ causam black surfaces)</td>
      </tr>
      <tr>
          <td>Resolution Scale</td>
          <td>300% (menus) ou 200% (gameplay pesada)</td>
      </tr>
      <tr>
          <td>Force CPU Blit</td>
          <td>Ligado (mandatório, mata flicker)</td>
      </tr>
      <tr>
          <td>WCB</td>
          <td>Desligado (trade-off: retrovisor preto)</td>
      </tr>
      <tr>
          <td>Shader Precision</td>
          <td>Ultra</td>
      </tr>
  </tbody>
</table>
<p>Em 2026, com essas configs, GT6 tá no meu rodízio. Não é perfeito, mas é jogável o suficiente pra eu passar uma tarde fazendo endurance.</p>
<h3>Ridge Racer 7<span class="hx:absolute hx:-mt-20" id="ridge-racer-7"></span>
    <a href="#ridge-racer-7" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Ridge Racer 7 foi lançamento do PS3 em 2006 e é o último mainline da franquia. Arcade igual Ridge Racer V, drift-first, trilha sonora eletrônica, câmera cinemática. Pra PS3 da época era uma demo tecnológica bonita.</p>
<p>No RPCS3 ele roda, mas com caveats: requer Write Color Buffers ligado pra não ter problemas de iluminação, e o preset recomendado na compat DB é diferente do meu preset GT. Eu uso config per-game dedicada pra ele. Não é meu favorito, mas tá lá pra completude.</p>
<p>Sem vídeo pra esse, gravo depois.</p>
<h2>Xbox 360 no Xenia Canary<span class="hx:absolute hx:-mt-20" id="xbox-360-no-xenia-canary"></span>
    <a href="#xbox-360-no-xenia-canary" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Aqui tá a parte que mais me deu dor de cabeça nesse domingo. Xbox 360 no Linux é território hostil. Xenia roda via Wine, cada jogo tem tweaks específicos, title updates tem que vir do archive.org, e Forza Motorsport 4 especificamente tinha problemas sérios até pouco tempo atrás.</p>
<h3>Forza Motorsport 4 (o GOAT)<span class="hx:absolute hx:-mt-20" id="forza-motorsport-4-o-goat"></span>
    <a href="#forza-motorsport-4-o-goat" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20motorsport%204.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>FM4 é, pra muita gente, o melhor Forza Motorsport já lançado. Polyphony fez Gran Turismo, Turn 10 fez Forza, e FM4 é o pico da era 360. Modelos de carro belíssimos pra época, pistas bem construídas, física sólida sem ser simulador puro, Autovista mode com narração do Jeremy Clarkson, trilha sonora épica, e aquela sensação de Xbox 360 sendo usado no limite.</p>
<p>FM4 no Xenia <strong>era um pesadelo até recentemente</strong>. Shadow com artefato severo, texture pop-in constante no carro, textura de pista chiada e pixelada, céu com brilho completamente errado (ficava branco-estourado em vez do azul profundo original), e o pior: crash de áudio frequente, onde o XMA (codec proprietário do Xbox 360) travava e o som virava ruído agudo até congelar o jogo. Eu passei horas nesse domingo mexendo em config, testando builds, procurando issue no xenia-canary, testando diferentes title updates.</p>
<p>O que destravou:</p>
<ul>
<li><strong>Build Xenia Canary mais recente</strong> (o <code>master</code> tá parado, Canary acompanha desenvolvimento ativo)</li>
<li><strong>Render Target Path:</strong> <code>rtv</code> (o default funciona bem pra FM4)</li>
<li><strong>Title Update 1.0.17.0</strong> instalado via Xenia Manager (versão importa, mais velha dá regressão em sombras)</li>
<li><strong>GPU Vulkan com ICD NVIDIA forçado</strong> (no meu setup híbrido com AMD iGPU, tinha que forçar a 5090)</li>
</ul>
<p>Depois disso, FM4 rodou. Não é perfeito. Ainda tem algum crash esporádico de áudio (<a href="https://github.com/xenia-canary/xenia-canary/issues/161"target="_blank" rel="noopener">xenia-canary issue #161</a> aberta). Mas é jogável, e eu passei umas duas horas do domingo no Top Gear Test Track só apreciando o Koenigsegg CCX. Valeu cada hora de debug.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>Xenia Canary recente</td>
      </tr>
      <tr>
          <td>Render Target Path</td>
          <td><code>rtv</code> (default)</td>
      </tr>
      <tr>
          <td>Title Update</td>
          <td>1.0.17.0</td>
      </tr>
      <tr>
          <td>Wine Prefix</td>
          <td>dedicado via Xenia Manager</td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>NVIDIA via <code>VK_ICD_FILENAMES</code> hardforce</td>
      </tr>
  </tbody>
</table>
<h3>Forza Motorsport 3<span class="hx:absolute hx:-mt-20" id="forza-motorsport-3"></span>
    <a href="#forza-motorsport-3" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20motorsport%203.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>FM3 é uma das entradas boas da série, entre o charme áspero do FM2 e o pico técnico do FM4. Tentar emular foi surpreendentemente chato, porque eu tava usando a ISO errada.</p>
<p>Existem dois releases do FM3: o <strong>retail</strong> (disco original vendido em loja) e o <strong>Ultimate Edition</strong> (com todas as DLCs empacotadas num segundo disco). Eu tava tentando rodar o Ultimate, que combina dois discos numa ISO híbrida que o Xenia não parseia direito. Troquei pro retail padrão + DLCs instaladas separadamente via Title Update, e bingo, o jogo rodou na primeira.</p>
<p>Moral: se teu FM3 não tá rodando no Xenia, verifica se é retail. Ultimate dá problema.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Versão</td>
          <td>Retail (NÃO Ultimate Edition)</td>
      </tr>
      <tr>
          <td>Build</td>
          <td>Xenia Canary recente</td>
      </tr>
      <tr>
          <td>Render Target Path</td>
          <td><code>rtv</code></td>
      </tr>
      <tr>
          <td>DLCs</td>
          <td>Instaladas via Xenia Manager separadamente</td>
      </tr>
  </tbody>
</table>
<h3>Forza Motorsport 2<span class="hx:absolute hx:-mt-20" id="forza-motorsport-2"></span>
    <a href="#forza-motorsport-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20motorsport%202.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>FM2 é da era 2007, primeira-gen do 360. Sistemas menos refinados, modelagem mais básica, mas aquele charme de Forza original que alguns preferem à sofisticação do FM4. No Xenia rodou praticamente out-of-the-box. Nenhum tweak especial.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>Xenia Canary</td>
      </tr>
      <tr>
          <td>Render Target Path</td>
          <td>default</td>
      </tr>
  </tbody>
</table>
<h3>Forza Horizon 2<span class="hx:absolute hx:-mt-20" id="forza-horizon-2"></span>
    <a href="#forza-horizon-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20horizon%202.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>FH2 foi o Forza Horizon mais polido da geração 360 (existe também a versão Xbox One, que é melhor tecnicamente, mas o 360 tem seu charme por causa do mapa menor e da progressão mais focada). Mundo aberto no sul da Europa, trilha sonora icônica, festival Horizon no seu pico.</p>
<p>No Xenia rodou sem pedir nada extra. Como o FM2.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>Xenia Canary</td>
      </tr>
      <tr>
          <td>Render Target Path</td>
          <td>default</td>
      </tr>
  </tbody>
</table>
<h3>Forza Horizon 1 (com XE Mod)<span class="hx:absolute hx:-mt-20" id="forza-horizon-1-com-xe-mod"></span>
    <a href="#forza-horizon-1-com-xe-mod" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20horizon%201%20xe%20mod.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>FH1 original roda OK no Xenia, mas tem uma comunidade que mantém o <strong>Forza Horizon 1 XE Mod</strong>, que melhora IA do tráfego, rebalanceia progressão, adiciona carros que ficaram de fora, corrige bugs conhecidos, e traz uns quality-of-life tweaks na UI. Eu testei o XE Mod nesse domingo e vale a pena. O jogo parece mais vivo e progressão mais justa.</p>
<p>Detalhes da instalação do XE Mod estão no site do projeto. Basicamente é patch sobre a ISO original + alguns title updates customizados.</p>
<p>Pra comparação, aqui é o FH1 <strong>sem</strong> o mod, rodando puro:</p>
<video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/forza%20horizon%201.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>A diferença mais visível é no tráfego e na variedade de situações que aparecem, mas o XE Mod tem muita coisa que você só percebe depois de algumas horas.</p>
<table>
  <thead>
      <tr>
          <th>Config</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Build</td>
          <td>Xenia Canary</td>
      </tr>
      <tr>
          <td>XE Mod</td>
          <td>Aplicado sobre ISO original</td>
      </tr>
      <tr>
          <td>Title Updates</td>
          <td>Version pinada pelo XE Mod</td>
      </tr>
  </tbody>
</table>
<h3>Project Gotham Racing 3 e 4<span class="hx:absolute hx:-mt-20" id="project-gotham-racing-3-e-4"></span>
    <a href="#project-gotham-racing-3-e-4" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>PGR3 foi lançamento do 360 em 2005 e continua lindo hoje. Pistas urbanas (Nova York, Tokyo, Nurburgring, Las Vegas), kudos system, câmera cinemática. PGR4 adicionou clima dinâmico (chuva e neve) e motos (algumas pessoas adoram, eu prefiro fingir que não existe).</p>
<p>PGR3 no Xenia Canary roda razoavelmente bem com configs default. PGR4 precisa de tweak específico: <strong><code>render_target_path_vulkan = &quot;fsi&quot;</code></strong> no config. Sem isso, algumas pistas quebram com artefato visual severo (barras verdes atravessando a tela em corridas de neve).</p>
<p>E PGR4 no NVIDIA tem um bug conhecido de áudio: decoding XMA gera garbage intermitente (issue aberta no xenia-canary, sem resolução). Não é game-breaking, mas incomoda.</p>
<table>
  <thead>
      <tr>
          <th>Jogo</th>
          <th>Config relevante</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>PGR3</td>
          <td>Default</td>
      </tr>
      <tr>
          <td>PGR4</td>
          <td><code>render_target_path_vulkan = &quot;fsi&quot;</code>, aceitar bug de áudio XMA</td>
      </tr>
  </tbody>
</table>
<h3>Ridge Racer 6<span class="hx:absolute hx:-mt-20" id="ridge-racer-6"></span>
    <a href="#ridge-racer-6" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Ridge Racer 6 foi o Ridge Racer do 360, pula o 7 que ficou em PS3. Arcade puro, igual Ridge Racer V do PS2. No Xenia Canary roda com config default, sem tweak especial. É divertido pra sessão curta. Sem vídeo dele no artigo, mas tá no catálogo rodando.</p>
<h2>PS4 no shadPS4: o estado do emulador<span class="hx:absolute hx:-mt-20" id="ps4-no-shadps4-o-estado-do-emulador"></span>
    <a href="#ps4-no-shadps4-o-estado-do-emulador" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://shadps4.net/"target="_blank" rel="noopener">shadPS4</a> <strong>ainda não tem release estável</strong>. O projeto tá em desenvolvimento ativo, main branch muda várias vezes por semana, e &ldquo;o que funciona hoje&rdquo; pode regredir num rebase amanhã. Dito isso, <strong>muitos jogos já bootam e rodam bem o suficiente</strong>. Lista da comunidade tá no <a href="https://github.com/shadps4-compatibility/shadps4-game-compatibility/issues"target="_blank" rel="noopener">compatibility tracker</a> e cresce toda semana.</p>
<p>A diferença entre shadPS4 e os outros emuladores desse artigo é o tipo de esforço. PCSX2, RPCS3, Xenia são projetos maduros onde cada jogo tem uma página de wiki razoavelmente atualizada. shadPS4 é o oposto: você lê um guia do Reddit, tenta reproduzir, descobre que o guia usa um fork específico (não o main oficial), ou um commit de dois meses atrás, ou um firmware com <code>sys_modules</code> linkados de jeito particular, ou patches XML aplicados numa ordem específica que o autor não documentou. Reproduzir setup de shadPS4 a partir de vídeo YouTube é tentar resolver Rubik&rsquo;s Cube com venda.</p>
<p>Mas isso não significa que você não deve tentar. Significa que você precisa tratar shadPS4 como brincadeira, não como workflow. E se você tiver paciência, dá pra colher resultados impressionantes.</p>
<h2>Driveclub: o impossível, finalmente possível<span class="hx:absolute hx:-mt-20" id="driveclub-o-impossível-finalmente-possível"></span>
    <a href="#driveclub-o-imposs%c3%advel-finalmente-poss%c3%advel" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><video
  controls
  preload="metadata"
  playsinline
  class="html5-video"
  style="width:100%; max-width:960px; display:block; margin:1.25em auto; border-radius:8px; background:#000;"
  >
  <source src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/videos/driveclub.mp4" type="video/mp4">
  Your browser does not support HTML5 video.
</video>

<p>Driveclub é meu Moby Dick da emulação. É o único jogo de PS4 que eu quero muito rodar. Saiu em 2014 pela Evolution Studios, teve lançamento catastrófico (servers online colapsaram no dia 1), foi patchado durante dois anos até virar um dos melhores jogos de corrida da geração, e foi descontinuado pela Sony quando a Evolution foi fechada em 2016. Não tem port pra PC. Não tem remaster. Não tem sequel. Só existe no PS4.</p>
<p>E hoje, depois de muitas horas de debug, <strong>está rodando aqui</strong>. Menu principal carrega, intro roda, corridas começam, controle responde, áudio funciona, pistas de dia visíveis, pistas de noite com faróis iluminando pista. O vídeo acima é gameplay real, a 30 FPS estáveis, v1.28 com conteúdo DLC acessível.</p>
<p>Chegar até aqui exigiu desarmar várias armadilhas. Vale documentar, porque a maioria dos guias online não menciona nenhuma.</p>
<h3>Armadilha 1: o FMOD loop error que não era FMOD<span class="hx:absolute hx:-mt-20" id="armadilha-1-o-fmod-loop-error-que-não-era-fmod"></span>
    <a href="#armadilha-1-o-fmod-loop-error-que-n%c3%a3o-era-fmod" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Quando você tenta bootar Driveclub no shadPS4 direto da PKG retail, o log estoura um loop infinito de:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>/app0/audio/fmodstudio/masterbank.bank failed, file does not exist</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A primeira reação é investigar FMOD. Tem gente na internet que passou horas mexendo em sceFont, libtbb, sceNgs2, convencidos que era problema de áudio ou lib HLE. <strong>Nada disso é a causa</strong>. O arquivo <code>masterbank.bank</code> literalmente não existe no disco, porque ele tá empacotado dentro dos arquivos <code>gameNNN.dat</code> num formato de archive customizado da Evolution Studios que o VFS do shadPS4 não sabe ler. A mesma história vale pra fontes, modelos, shaders. O conteúdo todo do jogo mora dentro dos <code>.dat</code>.</p>
<p>A única ferramenta pública que parse esse formato é o <strong><a href="https://github.com/Nenkai/DriveClubFS"target="_blank" rel="noopener">DriveClubFS do Nenkai</a></strong>. É uma app .NET que lê o <code>game.ndx</code> (o índice) e decomprime os <code>.dat</code> em arquivos soltos. Sem esse unpack, o shadPS4 não consegue abrir nada.</p>
<p>Detalhe de build: o projeto DriveClubFS tá em <code>net9.0</code>, e o Arch tem <code>net8</code> e <code>net10</code>. Precisa retargetar o csproj pra <code>net10.0</code> antes de buildar. O comando exato tá documentado no <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>docs/driveclub-shadps4.md</code></a> do repo.</p>
<h3>Armadilha 2: v1.28 é patch, não instalador base<span class="hx:absolute hx:-mt-20" id="armadilha-2-v128-é-patch-não-instalador-base"></span>
    <a href="#armadilha-2-v128-%c3%a9-patch-n%c3%a3o-instalador-base" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Como em qualquer PS4, update é patch que vai em cima de uma install base. A PKG do v1.28 traz o eboot atualizado, <code>.dat</code> com conteúdo novo e patch content (<code>sce_sys/about/right.sprx</code>), mas <strong>não traz <code>param.sfo</code>, <code>disc_info.dat</code> nem <code>keystone</code></strong>. Esses metadata ficam na base de v1.00 — num PS4 real já estariam gravados do install original.</p>
<p>E tem mais: o <code>game.ndx</code> do v1.28 referencia tanto os <code>.dat</code> da base quanto os novos. Rodar o DriveClubFS contra só o v1.28 faz o índice apontar pra arquivos que não tão ali.</p>
<p>O sintoma mais cruel vem depois: o jogo boota, a Qt Launcher mostra o tile, você clica, a tela carrega. Aí o jogo decide que nenhum conteúdo &ldquo;foi lançado ainda&rdquo; e pede pra fazer download. Download obviamente não vai acontecer porque PSN pra PS4 não tá acessível. Você fica travado achando que é bug de rede, quando na verdade é metadata faltando.</p>
<p>O fluxo correto é tratar v1.28 como overlay sobre a base. Primeiro, extrai a PKG de v1.00 pra um dir dedicado (<code>CUSA00003.v100-working-backup/</code> funciona bem, e dobra como snapshot de rollback se algum experimento quebrar a instalação viva). Depois extrai o v1.28 pra staging e linka os <code>.dat</code> de índice baixo da base dentro do staging pra o DriveClubFS enxergar o set completo. Roda o unpack. Sai com 8018 arquivos soltos, ~47 GB.</p>
<p>Move pra <code>CUSA00003/</code> final, copia o eboot e conteúdo novo do v1.28 por cima, e puxa <code>param.sfo</code>, <code>disc_info.dat</code> e <code>keystone</code> da base de v1.00. O <code>param.sfo</code> da base já vem com <code>APP_VER = 01.28</code> gravado (porque ela recebeu o patch original), então não tem conflito de versão. O eboot v1.28 lê esses arquivos e libera o conteúdo.</p>
<h3>Armadilha 3: o patch XML de 60fps gera slow-motion<span class="hx:absolute hx:-mt-20" id="armadilha-3-o-patch-xml-de-60fps-gera-slow-motion"></span>
    <a href="#armadilha-3-o-patch-xml-de-60fps-gera-slow-motion" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Tem um <code>Driveclub.xml</code> patch comunitário que faz o jogo renderizar a 60fps. Intuitivamente, parece ganho puro. Na prática, o patch reescreve o render rate mas não mexe no logic tickrate interno do jogo, que é fixo em 30fps. Num PS4 Pro real, o hardware reconcilia a diferença. No shadPS4, não.</p>
<p>Resultado: o jogo renderiza liso a 60fps, mas toda a física, AI, áudio, timing de corrida roda em câmera lenta. Você aperta acelerador e o carro leva dois segundos perceptíveis pra sair. Parece bug aleatório até você entender o mismatch.</p>
<p>Desabilitar o patch XML resolve (basta renomear o arquivo pra algo como <code>.disabled</code>). Sem o patch, o jogo fica a 30 FPS nativos, mesma velocidade do PS4 base stock. Que é o que a gente quer. Se alguém conseguir no futuro fazer um patch que mexa nos dois rates (render + logic), a gente religa.</p>
<h3>Armadilha 4: pipeline cache precisa estar ligado<span class="hx:absolute hx:-mt-20" id="armadilha-4-pipeline-cache-precisa-estar-ligado"></span>
    <a href="#armadilha-4-pipeline-cache-precisa-estar-ligado" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Default do shadPS4 vem com <code>pipeline_cache_enabled = false</code>. Num jogo grande como Driveclub, que tem centenas de shaders e pipelines Vulkan, isso significa que cada cold launch recompila tudo. Nos meus testes o primeiro launch contou ~864 shaders e ~590 pipelines sendo compilados em tempo real. O menu animava a 2-3 fps. Um minuto depois, com tudo compilado, saltava pra fluidez normal. Próximo launch, mesmo ciclo de compilação do zero.</p>
<p>Basta ligar <code>&quot;pipeline_cache_enabled&quot;: true</code> no <code>config.json</code> global. Primeira sessão paga o custo único de compilação, sessões seguintes leem do cache e sobem direto.</p>
<h3>Armadilha 5: TOML silenciosamente ignorado<span class="hx:absolute hx:-mt-20" id="armadilha-5-toml-silenciosamente-ignorado"></span>
    <a href="#armadilha-5-toml-silenciosamente-ignorado" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>O shadPS4 migrou de TOML pra JSON em config per-game em late 2025. Se você tem um <code>CUSA00003.toml</code> antigo na pasta <code>custom_configs/</code>, ele é silenciosamente ignorado, sem warning no log. Você pensa que sua config tá ativa, na prática tá rodando tudo default.</p>
<p>Deleta qualquer TOML e usa <code>CUSA00003.json</code>. As configs per-game que funcionam pra Driveclub são específicas e detalhadas, documentei todas no <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>docs/driveclub-shadps4.md</code></a> do repo.</p>
<h3>Armadilha 6: controle não detectado sem hidapi hints<span class="hx:absolute hx:-mt-20" id="armadilha-6-controle-não-detectado-sem-hidapi-hints"></span>
    <a href="#armadilha-6-controle-n%c3%a3o-detectado-sem-hidapi-hints" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Qt Launcher do shadPS4 chama um <code>Shadps4-sdl.AppImage</code> interno. Sem env vars específicas do SDL hidapi, o controle (no meu caso 8BitDo Ultimate 2) não é detectado, mesmo funcionando em outros emuladores. O fix é wrapar o AppImage num shell que exporta <code>SDL_JOYSTICK_HIDAPI=1</code> e variantes específicas por plataforma (PS4, PS5, Xbox), antes de executar o original.</p>
<p>Plugar o controle <strong>antes</strong> de abrir o Qt Launcher também ajuda. Hot-plug funciona durante o jogo, não antes.</p>
<h3>Armadilha 7: pistas de noite ficam pretas no upstream<span class="hx:absolute hx:-mt-20" id="armadilha-7-pistas-de-noite-ficam-pretas-no-upstream"></span>
    <a href="#armadilha-7-pistas-de-noite-ficam-pretas-no-upstream" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Esse aqui é o único que precisou de patch de código, não só config. No upstream do shadPS4, pistas de Driveclub à noite ficavam pretas. HUD aparecia em cima, mas pista, carro, tudo escondido num preto absoluto. Faróis do próprio carro não iluminavam nada.</p>
<p>Investigação apontou pro log repetindo 1325 vezes a mensagem <code>ResolveDepthOverlap: Unimplemented depth overlap copy</code>. A causa: o Driveclub usa renderer forward+, que escreve a profundidade da cena num buffer MSAA 4x D32Sfloat, depois lê esse mesmo buffer como <code>R32G32B32A32Sfloat</code> 1x pra efeitos tipo SSAO, volumetrics e iluminação dinâmica (faróis). O shadPS4 upstream tem caminho pra MSAA → MSAA e pra cor → cor como MSAA depth, mas <strong>não tinha caminho pra &ldquo;MSAA depth de 4x vira color de 1x&rdquo;</strong> nesse formato específico. Cai no <code>else</code> final, libera o buffer, e o shader lê lixo não inicializado — ou seja, preto.</p>
<p>Implementei no meu fork local do shadPS4 um <code>ReinterpretMsDepthAsColor</code> simétrico aos <code>ReinterpretColorAsMsDepth</code> que já existiam. É um fragment shader minúsculo (<code>ms_depth_to_color.frag</code>) que faz <code>texelFetch</code> da profundidade sample 0 e escreve como <code>vec4(depth, 0, 0, 1)</code> no attachment de cor. Plus um helper no <code>BlitHelper</code> e um novo <code>else if</code> no <code>TextureCache::ResolveDepthOverlap</code>. Com isso, pistas de noite iluminam corretamente, faróis dos oponentes aparecem, AO e volumetrics no dia também ficam mais precisos.</p>
<p>O fix tá num branch <code>gamma-debug</code> do meu fork, pronto pra virar PR upstream. Enquanto não mergeia, quem quer rodar Driveclub à noite no shadPS4 precisa buildar desse branch. Quem fica só em corridas de dia pode usar o upstream nightly direto.</p>
<h3>O que finalmente funcionou<span class="hx:absolute hx:-mt-20" id="o-que-finalmente-funcionou"></span>
    <a href="#o-que-finalmente-funcionou" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><table>
  <thead>
      <tr>
          <th>Componente</th>
          <th>Valor</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>shadPS4</td>
          <td>Pre-release (nightly) do upstream pra dia; fork <code>gamma-debug</code> pra noite (até MSAA depth fix mergear)</td>
      </tr>
      <tr>
          <td>Driveclub</td>
          <td><strong>v1.28 base</strong> (cumulative-patch, ~47 GB, 8018 arquivos)</td>
      </tr>
      <tr>
          <td>Extração</td>
          <td><a href="https://github.com/shadps4-emu/ShadPKG"target="_blank" rel="noopener">ShadPKG</a> → <a href="https://github.com/Nenkai/DriveClubFS"target="_blank" rel="noopener">DriveClubFS</a> (retargetado pra net10.0)</td>
      </tr>
      <tr>
          <td>Metadata</td>
          <td>Restaurar <code>param.sfo</code>, <code>disc_info.dat</code>, <code>keystone</code> da PKG v1.00</td>
      </tr>
      <tr>
          <td>Config global</td>
          <td><code>pipeline_cache_enabled: true</code>, <code>readbacks_mode: 0</code></td>
      </tr>
      <tr>
          <td>Config per-game</td>
          <td>JSON em <code>custom_configs/CUSA00003.json</code></td>
      </tr>
      <tr>
          <td><code>vblank_frequency</code></td>
          <td>60</td>
      </tr>
      <tr>
          <td><code>gpu_id</code></td>
          <td>0 (NVIDIA dGPU hardforced)</td>
      </tr>
      <tr>
          <td><code>Driveclub.xml</code> patch</td>
          <td><strong>Desabilitado</strong> (60fps gera slow-motion, causa raiz: logic tickrate fixo)</td>
      </tr>
      <tr>
          <td>Controle</td>
          <td>Wrapper AppImage com <code>SDL_JOYSTICK_HIDAPI=1</code> + variantes</td>
      </tr>
      <tr>
          <td>Qt Launcher</td>
          <td><code>checkForUpdates=false</code> pra evitar dialog rate-limit do GitHub</td>
      </tr>
  </tbody>
</table>
<p>Tudo isso tá encapsulado no <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>docs/driveclub-shadps4.md</code></a> do repo, com o passo a passo exato de extração, config e wrapper. A investigação técnica completa (5 fases, engineering log detalhado) tá no <a href="https://github.com/akitaonrails/shadPS4/blob/gamma-debug/docs/driveclub-v128-investigation.md"target="_blank" rel="noopener"><code>driveclub-v128-investigation.md</code></a> do fork.</p>
<h3>Quão jogável tá hoje<span class="hx:absolute hx:-mt-20" id="quão-jogável-tá-hoje"></span>
    <a href="#qu%c3%a3o-jog%c3%a1vel-t%c3%a1-hoje" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Bom. O vídeo acima é gameplay real, a 30 FPS estáveis, com física respondendo, áudio sincronizado, HUD correto, v1.28 com DLC acessível. Corridas de dia e de noite funcionam (com o fork do MSAA depth pra noite). O que sobra de limitação:</p>
<ul>
<li><strong>Brilho de dia um pouco abaixo do que o PS4 entregava.</strong> Não é bug do emulador. Passei horas testando tonemap, auto-exposure, gamma curves, ACES, vários shaders de post-processing, e no fim descobri que o jogo <strong>escreve SDR já correto</strong> no framebuffer. O que estava faltando era o pipeline de calibração de display que o firmware 4.0+ do PS4 aplicava por fora, e que o Linux não tem. O slider de brilho in-game (que no shadPS4 mapeia pra <code>sceVideoOutAdjustColor</code>) funciona, mas só vai até o ponto que o jogo pensou que seria complementado pelo firmware. A cena de 5 segundos escuros no início da corrida também é fade-in cinematográfico do jogo, não falha de emulador. Aceitei.</li>
<li><strong>30 FPS nativos.</strong> Sem patch de 60fps viável (pelo motivo do logic tickrate fixo). Stock PS4 speed.</li>
<li><strong>MSAA depth fix ainda no fork.</strong> Tem PR candidate pronto, aguardando upstream mergear.</li>
</ul>
<p><strong>&ldquo;Achievement Unlocked&rdquo;.</strong> O jogo roda, com som, controle, jogabilidade, dia e noite, e eu completo corrida inteira sem crash. Isso é um marco pessoal. Eu passei anos tentando fazer esse jogo rodar no Linux e chegava num ponto onde simplesmente desistia. Agora é parte do meu ES-DE, atalho no desktop, tá lá esperando eu sentar pra jogar.</p>
<p>Se você quer replicar, o repo tá público. Boa sorte. Vai precisar de paciência.</p>
<h2>&ldquo;Achievement Unlocked&rdquo;<span class="hx:absolute hx:-mt-20" id="achievement-unlocked"></span>
    <a href="#achievement-unlocked" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu venho tentando fazer esses jogos funcionarem, em algum nível, desde que cada respectivo emulador saiu de alpha. GT2 eu tô rodando desde ePSXe. GT4 eu mexo desde PCSX2 0.9.6. FM4 eu tentei fazer rodar em Xenia duas vezes em anos anteriores e desisti nas duas. E Driveclub eu olhei pra cara do shadPS4 três vezes antes desse domingo e engoli em seco.</p>
<p>Hoje fechou. Os dois monstros que abriram esse artigo (Driveclub no shadPS4 e FM4 com Project Forza Plus no Xenia) estão rodando, junto com todo o resto da coleção de Gran Turismo, Forza, Ridge Racer, Colin McRae e Enthusia. Tudo num setup único, reproduzível, automatizado. Agora eu faço parte do <strong>grupo bem pequeno de pessoas que conseguiu brute force emular Driveclub no Linux</strong>, e isso sozinho já tornou o domingo inesquecível.</p>
<p>A frustração de anos não era falta de informação. Era o OPOSTO. Informação demais, mal indexada, espalhada em fóruns apagados, vídeos YouTube que ficaram datados, threads Reddit com soluções pra versão do emulador de dois anos atrás que não valem hoje, wiki de projeto desatualizada em metade das páginas, e mods com requisitos MUITO específicos de CRC, versão, patch, path, setting. Cada vez que eu sentava pra fazer um desses jogos rodar direito, eu ficava três horas lendo material conflitante antes de escrever a primeira linha de config. Pior ainda quando o material bom estava enterrado entre diagnósticos errados, tipo o FMOD loop do Driveclub que todo mundo investigava como se fosse problema de áudio quando na real era formato de archive proprietário da Evolution Studios.</p>
<p>O que mudou nesse último ano é que Claude Code consegue ser meu agregador. Eu peço pro Claude ir na issue tracker do Xenia, na wiki do PCSX2, no subreddit do RPCS3, nos PRs do shadPS4, comparar todas as informações com a versão atual do emulador instalada, cruzar com os logs que eu tô vendo, e me devolver a combinação que funciona hoje. Ele lê source code quando precisa, entende por que <code>Force CPU Blit</code> muda comportamento no GT6, acha qual title update do FM4 foi o que consertou o shadow bug, descobre que o DriveClubFS precisa de retarget pra .NET 10 antes de compilar. O que antes levava três fins de semana pesquisando agora leva uma tarde de execução assistida.</p>
<p>Esse domingo é o resultado consolidado de todo esse trabalho. <a href="https://github.com/akitaonrails/distrobox-gaming"target="_blank" rel="noopener">distrobox-gaming</a> é a versão desse conhecimento virada código, reprodutível, automatizada. Rodando numa máquina fresca, um <code>ansible-playbook site.yml</code> me põe de volta nesse estado em menos de duas horas. Menos de 10 comandos separam &ldquo;Arch Linux vanilla&rdquo; de &ldquo;Driveclub rodando&rdquo;.</p>
<p>Se alguém quiser contribuir, testar em outro hardware, reportar bug ou mandar config que ficou faltando, o repo tá aberto. Quanto mais gente testar em setups diferentes, mais resiliente o projeto fica. Se você melhorar a situação do Driveclub (mergear o MSAA depth fix upstream, patch de 60fps que também corrija o logic tickrate, dump de fontes que não precise hardware jailbroken), manda PR que eu abraço.</p>
<p>Por enquanto, eu vou fazer uma corrida na Islândia no Driveclub. Boa noite de domingo.</p>
]]></content:encoded><category>games</category><category>emulacao</category><category>linux</category></item><item><title>Distrobox de Emulação com Claude Code</title><link>https://akitaonrails.github.io/2026/04/11/distrobox-de-emulacao-com-claude-code/</link><guid isPermaLink="true">https://akitaonrails.github.io/2026/04/11/distrobox-de-emulacao-com-claude-code/</guid><pubDate>Sat, 11 Apr 2026 18:00:00 -0300</pubDate><description>&lt;p&gt;Eu gosto de videogame velho desde antes de muita gente aqui nascer. Meu primeiro contato foi ainda na era do Atari, no começo dos anos 80. Depois vieram os micros de 8 bits, os arcades dos anos 90, os consoles de 16, 32, 64 bits, e eu continuei acompanhando tudo. Nostalgia, pra mim, não é pasta bonitinha no Instagram. É acervo mesmo. ROM, BIOS, dumps, patches, DLC, firmware, save. Ao longo dos anos fui guardando tudo no meu NAS. Hoje tenho terabytes disso em &lt;code&gt;/mnt/terachad/Emulators&lt;/code&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu gosto de videogame velho desde antes de muita gente aqui nascer. Meu primeiro contato foi ainda na era do Atari, no começo dos anos 80. Depois vieram os micros de 8 bits, os arcades dos anos 90, os consoles de 16, 32, 64 bits, e eu continuei acompanhando tudo. Nostalgia, pra mim, não é pasta bonitinha no Instagram. É acervo mesmo. ROM, BIOS, dumps, patches, DLC, firmware, save. Ao longo dos anos fui guardando tudo no meu NAS. Hoje tenho terabytes disso em <code>/mnt/terachad/Emulators</code>.</p>
<p>No meu canal eu inclusive usei jogos antigos pra ensinar fundamentos de computação. No <a href="https://www.youtube.com/watch?v=hYJ3dvHjeOE&amp;pp=ygUUYWtpdGFuZG8gc3VwZXIgbWFyaW8%3D"target="_blank" rel="noopener">Akitando sobre Super Mario e computadores antigos</a> eu explico 6502, mapa de memória, PPU, limitações de hardware e por que aqueles jogos eram programados daquele jeito. Se você nunca viu, recomendo assistir:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/hYJ3dvHjeOE"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>O problema é o de sempre: a cada poucos anos eu resolvo montar uma máquina nova de emulação, baixo de novo os emuladores principais da vez, e lá vou eu repetir o mesmo ritual masoquista. <code>PCSX2</code>, <code>RPCS3</code>, <code>Eden</code>, <code>Azahar</code>, <code>Dolphin</code>, <code>RetroArch</code>, <code>Flycast</code>, <code>shadPS4</code> e por aí vai. Cada um com suas manias. Cada um com sua forma particular de te fazer perder horas.</p>
<p>Em teoria, montar tudo isso deveria ser divertido. Na prática, leva dias. E não é exagero. <code>Dolphin</code> ainda consegue ser um dos piores porque controle de GameCube e Wii não tem nada de padrão. <code>RPCS3</code> exige tuning por jogo. <code>Eden</code> precisa de DLC, update e cheats no lugar certo. <code>shadPS4</code> é um festival de tentativa e erro. Quando eu finalmente terminava de configurar tudo, eu já não queria mais jogar porcaria nenhuma. Eu só queria fechar os menus e ir fazer outra coisa.</p>
<p>Eu já cheguei a dizer que talvez a graça estivesse justamente no tuning. Não acho mais isso. Depois de repetir esse processo vezes demais, eu cansei. Eu quero jogar os jogos, não preencher formulário escondido em GUI de emulador.</p>
<h2>O problema não era Linux<span class="hx:absolute hx:-mt-20" id="o-problema-não-era-linux"></span>
    <a href="#o-problema-n%c3%a3o-era-linux" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu já resolvi esse tipo de coisa de várias formas no passado. Anos atrás eu rodava Linux no host e um Windows virtualizado com GPU passthrough pra jogar dentro da VM. Na época era o que fazia sentido. Eu fiz um vídeo inteiro sobre isso:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/IDnabc3DjYY"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Mas isso foi antes do trabalho monumental da Valve, do Proton, do Wine moderno e de toda a comunidade open source que empurrou o desktop Linux pra um lugar muito melhor. Hoje dá pra evitar Windows na maior parte dos casos. No outro vídeo abaixo eu explico a evolução de CPU, GPU, OpenGL, Vulkan e por que chegamos nesse ponto:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/JEp7ozWqIps"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Meu mini-PC dedicado a games com RTX 4090 continua sendo minha principal máquina de Steam, especialmente agora que montei um <a href="/2026/04/01/meu-cockpit-de-sim-racing-formula-fx1/">cockpit decente de sim racing</a>. Nele eu uso <a href="https://www.emudeck.com/"target="_blank" rel="noopener">EmuDeck</a>, que nasceu justamente pra automatizar instalação e configuração de emuladores no Steam Deck, depois passou a suportar Windows também, e ajuda bastante a reduzir a complicação de montar esse tipo de ambiente. Mas meu desktop principal também é forte demais pra ficar subutilizado. Ele tem uma RTX 5090, e hoje eu uso essa GPU principalmente pra testar LLMs e benchmarking, como contei em <a href="/2026/04/05/testando-llms-open-source-e-comerciais-quem-consegue-bater-o-claude-opus/">Testando LLMs Open Source e Comerciais</a>. Seria um desperdício não usar isso pra gaming também.</p>
<p>Só que no Linux eu queria outra coisa. Eu não queria uma caixa-preta fazendo tudo por mim sem eu saber exatamente o que estava sendo alterado, principalmente no meu PC principal, que é minha máquina de trabalho. Eu queria um setup meu, feito &ldquo;na mão&rdquo; no sentido certo da expressão: não clicar GUI por GUI, mas entender o que está sendo configurado, manter os arquivos sob meu controle, e conseguir reconstruir tudo do jeito que eu gosto. Eu sei que o pessoal do NixOS vai pular aqui pra dizer &ldquo;é só usar Nix&rdquo; — explico mais abaixo por que descartei essa rota. Também não queria transformar a minha máquina de trabalho num carnaval de pacote de emulador, tema GTK, wrapper, launcher, runtime esquisito e config enterrada em <code>~/.config</code>. Nem queria dual boot ou VM. Em 2026, a melhor resposta pra isso, na minha opinião, é <a href="https://distrobox.it/"target="_blank" rel="noopener">Distrobox</a>.</p>
<p>Pelo que o próprio projeto explica, Distrobox é um wrapper em cima de <code>podman</code>, <code>docker</code> ou <code>lilipod</code> pra criar containers fortemente integrados ao host, com acesso a <code>HOME</code>, Wayland/X11, áudio, dispositivos USB, storage externo e GPU. Ou seja: exatamente o tipo de isolamento pragmático que eu queria. Não é uma fronteira de segurança, e o próprio site deixa isso claro. Não use pensando em sandbox de alta segurança. Use pensando em separar ambientes sem ficar pagando o preço de uma VM.</p>
<p>E antes que alguém repita a confusão de sempre: container não é máquina virtual. Eu explico isso com calma neste outro episódio:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/85k8se4Zo70"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>O setup<span class="hx:absolute hx:-mt-20" id="o-setup"></span>
    <a href="#o-setup" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A ideia é simples: um Arch Linux vanilla dentro de um Distrobox chamado <code>gaming</code>, com os caminhos do NAS montados em read-only, a biblioteca Steam acessível onde faz sentido, e todos os emuladores instalados lá dentro. Como o container tem acesso a GPU NVIDIA, áudio, USB e demais periféricos, eu separo trabalho de jogo na mesma máquina sem penalidade prática de performance.</p>
<p>O bootstrap inicial é mais ou menos isso:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">distrobox create --name gaming --image archlinux:latest --nvidia <span class="se">\
</span></span></span><span class="line"><span class="cl">  --home /mnt/data/distrobox/gaming <span class="se">\
</span></span></span><span class="line"><span class="cl">  --volume /mnt/data/steam:/mnt/data/steam <span class="se">\
</span></span></span><span class="line"><span class="cl">  --volume /mnt/terachad/Emulators:/mnt/terachad/Emulators:ro</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Só esse começo já tem pegadinha. O <code>archlinux:latest</code> dentro de Distrobox vem sem <code>[multilib]</code> no <code>pacman.conf</code>, com um <code>sudoers</code> mal configurado, e com o velho problema do <code>--nvidia</code>: as libs do driver do host entram bind-mounted read-only, então qualquer instalação que dependa de <code>nvidia-utils</code> quebra com conflito de arquivo. Só isso já é o tipo de dor de cabeça que, alguns anos atrás, me faria abrir meia dúzia de abas, mais uma penca de terminais, e gastar uma noite inteira em tentativa e erro.</p>
<p>Desta vez eu fiz diferente.</p>
<h2>Claude Code como assistente de infraestrutura<span class="hx:absolute hx:-mt-20" id="claude-code-como-assistente-de-infraestrutura"></span>
    <a href="#claude-code-como-assistente-de-infraestrutura" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Eu venho ficando cada vez mais confortável em usar Claude Code como meu assistente de infraestrutura nas minhas máquinas pessoais. Eu não faria isso cegamente em servidor de cliente. Mas em máquina minha, em ambiente que eu posso destruir e reconstruir quantas vezes eu quiser, faz todo sentido. Escrevi sobre isso no artigo <a href="/2026/03/31/migrando-meu-home-server-com-claude-code/">Migrando meu Home Server com Claude Code</a>, quando usei Claude pra instalar e configurar openSUSE MicroOS, Docker, NFS, firewall, hardening e o resto todo sem eu precisar ficar lembrando comando chato de shell.</p>
<p>Então pensei: por que não fazer a mesma coisa aqui?</p>
<p>Foi exatamente o que eu fiz. Comecei com prompts bem objetivos, sempre pedindo duas coisas ao mesmo tempo: fazer o trabalho e documentar o suficiente pra eu poder reconstruir tudo depois. O histórico mais importante ficou em <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/distrobox-gaming-prompts.md"target="_blank" rel="noopener"><code>docs/distrobox-gaming-prompts.md</code></a>.</p>
<p>Vale um esclarecimento: aqueles prompts no GitHub não são as minhas mensagens cruas, do jeito que saíram na hora. Depois que tudo funcionou, eu pedi pro próprio Claude reescrever os prompts de forma organizada e detalhada, só pra fins de documentação. Os prompts originais eram bem mais simples e bem menos específicos. Eu descrevia o objetivo e deixava o Claude descobrir sozinho paths, arquivos de configuração, formatos e comandos necessários.</p>
<p>O primeiro prompt criou a box com <code>--nvidia</code>, <code>--home</code> separado e os mounts corretos. O segundo resolveu os três problemas clássicos do Arch dentro de Distrobox: <code>sudo</code>, <code>multilib</code> e o dummy package de <code>nvidia-utils</code>. O terceiro instalou a base de gaming, inclusive um detalhe que eu teria esquecido fácil se estivesse fazendo na mão: <code>pipewire-pulse</code>, necessário pra vários emuladores não ficarem mudos nem perderem sincronia.</p>
<p>O ponto não é o texto em si. O ponto é o método. Eu não preciso lembrar a ordem exata, nem as opções precisas, nem onde está a documentação de cada detalhe. Eu descrevo o objetivo e deixo o agente carregar o piano. Fico no papel de tech lead: observando, revisando, corrigindo direção quando precisa, e mandando continuar.</p>
<h2>O projeto no GitHub<span class="hx:absolute hx:-mt-20" id="o-projeto-no-github"></span>
    <a href="#o-projeto-no-github" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O setup vive em <a href="https://github.com/akitaonrails/distrobox-gaming"target="_blank" rel="noopener">akitaonrails/distrobox-gaming</a>, estruturado como um projeto Ansible. 17 roles cobrem desde criação da box, bootstrap de pacotes, seed de configs, instalação de DLC, configuração de controle, até verificação pós-setup. Os playbooks principais são:</p>
<ul>
<li><code>site.yml</code>: setup completo do zero</li>
<li><code>reset-configs.yml</code>: reset só das configs (útil quando você quer zerar tuning e redeployar)</li>
<li><code>backup.yml</code> / <code>restore.yml</code>: snapshot e restauração do container inteiro via <code>podman commit</code></li>
<li><code>refresh-shadps4.yml</code>: atualização standalone do shadPS4</li>
<li><code>install-xenia.yml</code>: instalação opcional do Xenia Manager (Wine prefix)</li>
</ul>
<p>O passo a passo completo está em <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/rebuild-runbook.md"target="_blank" rel="noopener"><code>docs/rebuild-runbook.md</code></a>. As decisões de pacote (por que AUR em vez de Flatpak, por exemplo) estão em <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/distrobox-gaming-packages.md"target="_blank" rel="noopener"><code>docs/distrobox-gaming-packages.md</code></a>.</p>
<h3>Por que não Nix?<span class="hx:absolute hx:-mt-20" id="por-que-não-nix"></span>
    <a href="#por-que-n%c3%a3o-nix" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Alguém vai perguntar. &ldquo;Você tá recriando ambiente reproduzível. Por que não usar NixOS, ou pelo menos <code>nix-shell</code>/flakes?&rdquo;</p>
<p>Eu considerei e descartei. O ecossistema de emuladores que eu preciso vive no AUR. Pacotes <code>-bin</code> do AUR são wrappers de AppImage que empacotam o binário oficial do upstream sem compilar nada. <code>rpcs3-bin</code>, <code>pcsx2-latest-bin</code>, <code>eden-bin</code>, <code>duckstation-qt-bin</code>, <code>shadps4-bin</code> — esses binários acompanham o upstream praticamente no dia do lançamento. No Nixpkgs, muitos desses emuladores ficam semanas ou meses atrás do release, e alguns nem existem. Criar um overlay Nix pra cada emulador que eu preciso, manter, e lidar com os patches de compatibilidade quando upstream muda, é trabalho que eu não quero ter.</p>
<p>Tem também o modelo mental. Eu não quero aprender a linguagem Nix, o sistema de derivações e o modelo de avaliação pra montar um ambiente de games pessoal. Ansible eu já conheço, as roles são pastas com tasks em YAML, e o debug é <code>ansible-playbook -vvv</code>. Quando dá errado, eu leio a mensagem de erro, abro o task que falhou, e sei exatamente onde mexer. Se eu precisasse do mesmo nível de reprodutibilidade em escala, num cluster, com rollback atômico, aí sim Nix teria argumento. Pra um distrobox com emuladores na minha máquina pessoal, Ansible resolve com muito menos atrito.</p>
<p>Flatpak também foi testado e descartado. O <code>bwrap</code> (bubblewrap) do Flatpak não aninha direito dentro das mount namespaces do Docker, então apps Flatpak simplesmente não rodam dentro de distrobox. A alternativa seria instalar Flatpak no host, mas aí você volta ao problema de poluir a máquina de trabalho com pacotes de gaming. Além disso, as versões Flatpak de emuladores ficam bem atrás do AUR — o <code>pcsx2-latest-bin</code> do AUR tracka o AppImage 2.7.x, enquanto o Flathub ainda distribui a v2.6.3.</p>
<h2>Plataformas cobertas<span class="hx:absolute hx:-mt-20" id="plataformas-cobertas"></span>
    <a href="#plataformas-cobertas" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O setup cobre 12 plataformas hoje:</p>
<table>
  <thead>
      <tr>
          <th>Plataforma</th>
          <th>Emulador</th>
          <th>Renderer</th>
          <th>Destaque</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>PS1</td>
          <td>DuckStation</td>
          <td>Vulkan, 8x upscale</td>
          <td>JINC2 filter, PGXP, widescreen hack</td>
      </tr>
      <tr>
          <td>PS2</td>
          <td>PCSX2 2.7.x</td>
          <td>Vulkan, 4x SSAA</td>
          <td>FXAA + PCRTC antiblur, Xbox bindings</td>
      </tr>
      <tr>
          <td>PS3</td>
          <td>RPCS3</td>
          <td>Vulkan</td>
          <td>Per-game configs curados via API</td>
      </tr>
      <tr>
          <td>PS4</td>
          <td>shadPS4</td>
          <td>Vulkan</td>
          <td>Driveclub em foco (experimental)</td>
      </tr>
      <tr>
          <td>PS Vita</td>
          <td>Vita3K</td>
          <td>—</td>
          <td>Seeding padrão</td>
      </tr>
      <tr>
          <td>GameCube</td>
          <td>Dolphin</td>
          <td>Vulkan</td>
          <td>Perfis 8BitDo Ultimate 2</td>
      </tr>
      <tr>
          <td>Wii</td>
          <td>Dolphin</td>
          <td>Vulkan</td>
          <td>Classic Controller + Nunchuk</td>
      </tr>
      <tr>
          <td>Wii U</td>
          <td>Cemu</td>
          <td>Vulkan</td>
          <td>Baseline seed only-if-missing</td>
      </tr>
      <tr>
          <td>Switch</td>
          <td>Eden</td>
          <td>Vulkan</td>
          <td>DLC + cheats Atmosphere</td>
      </tr>
      <tr>
          <td>Dreamcast</td>
          <td>Flycast</td>
          <td>Vulkan, 2880p</td>
          <td>Wrapper hires, widescreen</td>
      </tr>
      <tr>
          <td>OG Xbox</td>
          <td>xemu</td>
          <td>—</td>
          <td>BIOS/HDD via symlink</td>
      </tr>
      <tr>
          <td>Xbox 360</td>
          <td>Xenia (Wine)</td>
          <td>Vulkan</td>
          <td>Project Forza Plus, PGR3/4</td>
      </tr>
  </tbody>
</table>
<p>RetroArch entra por cima pra cobrir o resto (NES, SNES, Genesis, N64, arcade, etc.), com 21 cores do buildbot e 8 asset packs (databases, shaders, cheats, overlays, autoconfig).</p>
<p>Frontend é <a href="https://es-de.org/"target="_blank" rel="noopener">ES-DE</a>. As definições dos sistemas customizados ficam em <code>ansible/group_vars/all/esde.yml</code> e cada emulador entra com um wrapper que já sobe com as variáveis certas de GPU (voltarei nisso).</p>
<h2>GPU hardforce pra NVIDIA<span class="hx:absolute hx:-mt-20" id="gpu-hardforce-pra-nvidia"></span>
    <a href="#gpu-hardforce-pra-nvidia" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Num sistema híbrido com NVIDIA dGPU + AMD iGPU (meu caso no desktop), Vulkan às vezes escolhe o iGPU sozinho e o resultado é emulador rodando a 15 fps enquanto a 5090 fica parada. A solução é forçar o ICD Vulkan da NVIDIA em todos os launchers.</p>
<p>Cada entrada de desktop rendereizada pelo Ansible exporta <code>VK_ICD_FILENAMES</code> apontando pro ICD da NVIDIA, e o wrapper do ES-DE faz a mesma coisa antes de lançar qualquer core. Em combinação com a flag <code>--nvidia</code> na criação da box, que bind-monta os drivers do host em read-only, o resultado é previsível: Vulkan sempre na dGPU NVIDIA, independente do estado do sistema na hora.</p>
<p>Isso vale principalmente pra quem tem setup híbrido. Num desktop com só uma GPU, o ICD filtering é placebo, mas também não atrapalha.</p>
<h2>PS2: PCSX2 com tuning por jogo<span class="hx:absolute hx:-mt-20" id="ps2-pcsx2-com-tuning-por-jogo"></span>
    <a href="#ps2-pcsx2-com-tuning-por-jogo" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A linha Gran Turismo é meu vício declarado. Cada versão precisa de tweak específico. O setup do PCSX2 hoje tem configs globais razoáveis (Vulkan, 4x SSAA, widescreen 16:9, Xbox-style bindings, FXAA + PCRTC antiblur, 16x anisotropic, deinterlace Automatic) e per-game INIs pros títulos que eu realmente jogo:</p>
<ul>
<li><strong>Gran Turismo 3 A-spec</strong> (SCUS-97102 + bundle PBPX-95503): widescreen pnach, pack de retextura opcional (desabilitado por default porque NFS causa flicker em cutscenes de showcase de carro)</li>
<li><strong>Gran Turismo 4 USA</strong> (SCUS-97328): HD HUD do Silentwarior112, pack completo de retextura, patches do Silent pra gatilho e câmera, widescreen pnach</li>
<li><strong>Gran Turismo 4 Spec II</strong> (SCUS-97436, CRC <code>4CE521F2</code>): caso especial — os HD packs de GT4 vanilla são linkados via symlink porque o Spec II tem mesma estrutura mas CRC diferente. Widescreen pnach renomeado pra bater com o CRC. Deinterlace mode 8 (Adaptive TFF), ShadeBoost tuning (+10 saturação, +3 brilho, +2 contraste) pra corrigir ghosting de pause-interlace e saturação anêmica do upscale</li>
<li><strong>Enthusia Professional Racing</strong> (SLUS-20967): HD textures + widescreen</li>
<li><strong>Ridge Racer V</strong> (SLUS-20002): widescreen + no-interlace pnach</li>
</ul>
<p>Os pnach files do Silent e da comunidade são baixados automaticamente pelo role <code>pcsx2_textures</code>, que também faz o deploy do pack de cheats do NAS e instala os HD packs do Spec II via symlink. Widescreen é ligado via <code>gamesettings</code> por CRC (PCSX2 identifica jogo por CRC antes de aplicar o pnach).</p>
<p>Sobre versão do PCSX2: o <code>pcsx2-latest-bin</code> do AUR tracka a linha 2.7.x, que é onde todas as features modernas estão (texture replacement, FXAA, PCRTC antiblur). O <code>pcsx2</code> padrão dos repos oficiais do Arch ainda está na 2.6.3. A diferença é mais de 250 commits de correção e feature novo.</p>
<h2>PS3: RPCS3 com per-game configs curados<span class="hx:absolute hx:-mt-20" id="ps3-rpcs3-com-per-game-configs-curados"></span>
    <a href="#ps3-rpcs3-com-per-game-configs-curados" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>RPCS3 tem um detalhe chato: configs por jogo ficam em <code>~/.config/rpcs3/custom_configs/config_&lt;SERIAL&gt;.yml</code>. O formato do arquivo tem versão, e se você gerar um YAML manualmente com versão errada, o RPCS3 rejeita silenciosamente e volta pro default. Isso custou tempo pra descobrir.</p>
<p>A role <code>rpcs3_per_game_configs</code> resolve isso assim:</p>
<ol>
<li>Query o <a href="https://rpcs3.net/compatibility"target="_blank" rel="noopener">compatibility DB da comunidade RPCS3</a> pra pegar os presets recomendados por título</li>
<li>Aplica overrides curados por cima pra títulos que eu sei que precisam de ajuste específico (tipicamente GT5 e GT6)</li>
<li>Salva o YAML com a filename convention exata (<code>config_&lt;SERIAL&gt;.yml</code>, prefixo <code>config_</code> obrigatório)</li>
</ol>
<p>Na linha Gran Turismo:</p>
<ul>
<li><strong>GT5</strong> (BCUS98114, BCES00569): Resolution Scale 300%, Shader Precision Ultra, Force High Precision Z, SPU XFloat Accurate, Multithreaded RSX. Combinação que mata o dithering típico do RSX sem quebrar a GT series safety config (WCB/RCB off).</li>
<li><strong>GT6</strong> (BCES01893 + variantes regionais): caso especial, <strong>versão travada em v1.05</strong>. Patches 1.06+ regridem com superfícies pretas em carros no menu garagem. O script <code>extract_ps3_dlc.py</code> tem per-title PATCH ceiling justamente pra pinar o GT6 no 1.05 mesmo quando o PSN cuspe patches mais novos. Além disso, Force CPU Blit ligado é mandatório (sem ele, flicker de tela inteira). O trade-off é que o retrovisor fica permanentemente preto — ligar WCB restauraria o retrovisor mas downgradaria pra 720p nativo. Prefiro perder o retrovisor.</li>
</ul>
<p>Mais detalhes desses dois em <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/gt5-rpcs3.md"target="_blank" rel="noopener"><code>docs/gt5-rpcs3.md</code></a> e <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/gt6-rpcs3.md"target="_blank" rel="noopener"><code>docs/gt6-rpcs3.md</code></a>.</p>
<h3>Update checker de PS3<span class="hx:absolute hx:-mt-20" id="update-checker-de-ps3"></span>
    <a href="#update-checker-de-ps3" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Pra não ter que abrir a GUI do RPCS3 e ficar clicando em <code>Download Game Updates</code> jogo por jogo, criei um script em Python: <code>check_ps3_updates.py</code>. Ele percorre os jogos instalados em <code>dev_hdd0/game</code>, parseia o <code>PARAM.SFO</code> pra pegar a versão atual de cada título, consulta o servidor de updates da PSN (<code>a0.ww.np.dl.playstation.net</code>) e compara com o cache local de patches. <code>--list</code> mostra o diff; <code>--download</code> baixa o que falta. <code>--max-version</code> respeita os teto por título (ex: 1.05 pro GT6).</p>
<p>O primeiro scan na minha biblioteca achou 51 de 72 jogos com update disponível, 69 patches faltando localmente, uns 24 GB no total. Só o GT6 sozinho tinha 16 patches faltando, da 1.07 até 1.22, que eu descartei pelos motivos acima.</p>
<p>Os patches chegam como pacotes PSN tipo 0x0001 sem criptografia, então o próprio <code>extract_ps3_dlc.py</code> consegue instalar depois. A chamada padrão:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">distrobox enter gaming -- python3 scripts/extract_ps3_dlc.py <span class="se">\
</span></span></span><span class="line"><span class="cl">  <span class="s2">&#34;/mnt/terachad/Emulators/EmuDeck/roms_heavy/ps3-DLC&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  --dest <span class="s2">&#34;/mnt/data/distrobox/gaming/.config/rpcs3/dev_hdd0/game&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Acompanhar versão de DLC de PS3 manualmente, jogo por jogo no RPCS3, é inviável. Vira lista de tarefas eterna e você só descobre que tinha patch 1.22 quando o jogo crasha.</p>
<h2>PS1: DuckStation com per-game<span class="hx:absolute hx:-mt-20" id="ps1-duckstation-com-per-game"></span>
    <a href="#ps1-duckstation-com-per-game" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A trilogia Gran Turismo começa no PS1, e a qualidade ali só sobe se você ligar as coisas certas:</p>
<ul>
<li><strong>Gran Turismo</strong> (SCUS-94949): built-in WidescreenHack do DuckStation (não existe cheat pra esse jogo), PGXP ligado</li>
<li><strong>Gran Turismo 2 Simulation</strong> (SCUS-94455): widescreen cheat + 8 MB RAM cheat (fix de áudio em track crowded), filter JINC2</li>
<li><strong>Gran Turismo 2 Arcade</strong> (SCUS-94488): mesmo tratamento do Simulation</li>
</ul>
<p>Global defaults: Vulkan, 8x upscale, JINC2 como filter default.</p>
<p>Os cheats pro GT2 saem de um repositório de widescreen fixes e são ligados automaticamente na pasta de cheats do DuckStation.</p>
<h2>Switch: Eden com DLC, update e cheats<span class="hx:absolute hx:-mt-20" id="switch-eden-com-dlc-update-e-cheats"></span>
    <a href="#switch-eden-com-dlc-update-e-cheats" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>No Switch, <code>eden-bin</code> é o emulador. A integração automatiza três coisas que antes eu fazia na mão:</p>
<ol>
<li>
<p><strong>Install de DLC e update</strong>: o role <code>install_dlcs</code> aponta pro diretório de dumps no NAS, identifica os arquivos <code>.nsp</code>/<code>.nsz</code>/<code>.xci</code>/<code>.xcz</code>, e instala tudo em <code>~/.local/share/eden/nand/user/Contents/registered/</code>. Se o dump está bagunçado (patches e DLC misturados em flat folder), o script <code>reorganize_switch_nsps.py</code> sorteia tudo por Title ID antes.</p>
</li>
<li>
<p><strong>Cheats Atmosphere</strong>: os cheats em formato Atmosphere vão symlinkados pro load path do Eden (<code>~/.local/share/eden/load/&lt;TITLE_ID&gt;/cheats/</code>). O role <code>switch_cheats</code> faz isso por todos os títulos cobertos pelo pack do NAS.</p>
</li>
<li>
<p><strong>Update checker</strong>: <code>check_switch_updates.py</code> lista títulos com update disponível vs o que tá instalado localmente. Útil pra não perder patch importante de jogo que sai atualização ainda.</p>
</li>
</ol>
<p>Atenção ao detalhe que me queimou: <code>QT_STYLE_OVERRIDE</code> precisa ser desarmado antes de lançar o <code>eden-bin</code>, senão ele conflita com Kvantum e quebra a UI. O wrapper já faz o <code>unset</code> antes do <code>exec</code>.</p>
<h2>Xbox 360: Xenia Manager via Wine<span class="hx:absolute hx:-mt-20" id="xbox-360-xenia-manager-via-wine"></span>
    <a href="#xbox-360-xenia-manager-via-wine" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Xbox 360 ainda é território áspero no Linux. Não tem emulador nativo decente. A melhor rota hoje é <a href="https://xenia.jp/"target="_blank" rel="noopener">Xenia</a> rodando via Wine, gerenciado pelo <a href="https://github.com/xenia-manager/xenia-manager"target="_blank" rel="noopener">Xenia Manager</a>.</p>
<p>Isso é opt-in no meu setup. O playbook <code>install-xenia.yml</code> cria um Wine prefix dedicado, baixa o Xenia Manager, e registra os launchers. Não faz parte do <code>site.yml</code> principal porque nem todo mundo quer Wine no meio do caminho.</p>
<h3>Project Forza Plus (Forza Motorsport 2/3/4)<span class="hx:absolute hx:-mt-20" id="project-forza-plus-forza-motorsport-234"></span>
    <a href="#project-forza-plus-forza-motorsport-234" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Forza antigo ainda é o rei do simcade de geração passada. Rodar FM2/3/4 no Xenia requer mods da comunidade Project Forza Plus: patches de compatibilidade, mods de performance, instalação de title updates específicos. Documentei o processo em <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/project-forza.md"target="_blank" rel="noopener"><code>docs/project-forza.md</code></a>.</p>
<h3>Project Gotham Racing 3 e 4<span class="hx:absolute hx:-mt-20" id="project-gotham-racing-3-e-4"></span>
    <a href="#project-gotham-racing-3-e-4" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>PGR3 roda razoavelmente bem no Xenia Canary. PGR4 precisa de ajuste específico: <code>render_target_path_vulkan = &quot;fsi&quot;</code> no config, senão algumas races quebram com artefato visual. Documentei o setup em <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/xbox360-pgr.md"target="_blank" rel="noopener"><code>docs/xbox360-pgr.md</code></a>. Áudio do PGR4 no NVIDIA ainda tem problema de XMA decoding que gera garbage intermitente. Tem issue aberta no xenia-canary, sem resolução up até agora.</p>
<h3>Title Updates em batch<span class="hx:absolute hx:-mt-20" id="title-updates-em-batch"></span>
    <a href="#title-updates-em-batch" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Title Update pra jogo de Xbox 360 era distribuído pela Xbox Live, que já foi desligada. A alternativa é o archive.org, que tem o catálogo completo preservado. Escrevi <code>scripts/download-xbox360-tus.py</code> pra automatizar:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">distrobox enter gaming -- python3 scripts/download-xbox360-tus.py <span class="se">\
</span></span></span><span class="line"><span class="cl">  --src /mnt/terachad/Emulators/EmuDeck/roms_heavy/xbox360 <span class="se">\
</span></span></span><span class="line"><span class="cl">  --dest /mnt/terachad/Emulators/EmuDeck/roms_heavy/xbox360-updates <span class="se">\
</span></span></span><span class="line"><span class="cl">  --dry-run</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>O script precisa do CLI <code>internetarchive</code> autenticado (<code>ia configure</code> uma vez, guarda o token). Ele scaneia a pasta de jogos, faz match contra o manifest do archive.org (cacheado localmente), prioriza por região (USA &gt; World &gt; Europe &gt; Japan), e baixa via <code>ia download --checksum</code> com retry automático. Os .zip resultantes vão pro Xenia Manager via <code>Manage → Install Content</code>, que extrai pro diretório correto (<code>000B0000/</code>).</p>
<p>O setup completo tá em <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/xbox360-title-updates.md"target="_blank" rel="noopener"><code>docs/xbox360-title-updates.md</code></a>.</p>
<h2>Steam no distrobox<span class="hx:absolute hx:-mt-20" id="steam-no-distrobox"></span>
    <a href="#steam-no-distrobox" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Desde que o Proton virou cidadão de primeira no Linux, faz sentido ter Steam também no gaming box. Adicionei o pacote <code>steam</code> no Ansible (que puxa multilib e dependências 32-bit), montei <code>/mnt/data/steam</code> em read-write pra a biblioteca persistir fora do container, e criei launcher no host.</p>
<p>Na prática, isso me permite rodar jogos Steam via Proton lado a lado com emulação, sem precisar alternar ambiente. O mini-PC com RTX 4090 continua sendo a máquina principal de Steam no cockpit de sim racing. O desktop é fallback e ambiente de teste.</p>
<h2>Shell e controle por controle<span class="hx:absolute hx:-mt-20" id="shell-e-controle-por-controle"></span>
    <a href="#shell-e-controle-por-controle" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><h3>Shell mínimo dentro da box<span class="hx:absolute hx:-mt-20" id="shell-mínimo-dentro-da-box"></span>
    <a href="#shell-m%c3%adnimo-dentro-da-box" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Quando eu entro no gaming box via <code>distrobox enter gaming</code>, eu quero prompt decente mesmo pra troubleshooting rápido. Instalei <code>zsh</code> + <code>starship</code> com config mínima, zero plugins exóticos. Não é meu setup de dev full, é só &ldquo;prompt que mostra path e git branch sem me dar vergonha&rdquo;.</p>
<h3>Dolphin e o inferno do controle moderno<span class="hx:absolute hx:-mt-20" id="dolphin-e-o-inferno-do-controle-moderno"></span>
    <a href="#dolphin-e-o-inferno-do-controle-moderno" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><code>Dolphin</code> sempre foi o rei do atrito manual. Se você usa um controle mais moderno, como meu 8BitDo Ultimate 2, precisa lembrar como eu gosto do mapeamento de GameCube, como adapto o Wii Remote, quando usar perfil de Nunchuk, quando trocar pro Classic Controller. Eu não tenho a menor paciência pra reconstruir isso na mão toda vez. Os perfis ficam prontos em <code>config/emulator-overrides/dolphin/Profiles/</code> e são copiados pelo role <code>seed_configs</code>. Detalhes em <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/controller-hotkeys.md"target="_blank" rel="noopener"><code>docs/controller-hotkeys.md</code></a>.</p>
<h2>Alguns tropeços que sobraram<span class="hx:absolute hx:-mt-20" id="alguns-tropeços-que-sobraram"></span>
    <a href="#alguns-trope%c3%a7os-que-sobraram" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Nem tudo virou magia. Emulação sempre tem casca de banana.</p>
<p><code>Flycast</code>, por exemplo, tem uma armadilha irritante. O arquivo <code>emu.cfg</code> usa chaves <code>rend.*</code> dentro da seção <code>[config]</code>. Se você cria uma seção <code>[rend]</code> separada, parece certo, mas o emulador simplesmente ignora e depois reescreve tudo com default medíocre. A correção virou wrapper dedicado em <code>$DG_BOX_HOME/bin/flycast-hires</code>:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="nv">$DG_BOX_HOME</span>/bin/flycast-hires <span class="se">\
</span></span></span><span class="line"><span class="cl">  -config config:pvr.rend<span class="o">=</span><span class="m">4</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -config config:rend.Resolution<span class="o">=</span><span class="m">2880</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -config config:rend.EmulateFramebuffer<span class="o">=</span>no <span class="se">\
</span></span></span><span class="line"><span class="cl">  -config config:rend.WideScreen<span class="o">=</span>yes</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Detalhes em <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/flycast-resolution.md"target="_blank" rel="noopener"><code>docs/flycast-resolution.md</code></a>.</p>
<p><code>shadPS4</code> ainda está longe de ser um caso encerrado. O setup atual é focado em <code>Driveclub</code>, com config espelhada, patch XML e links dos <code>sys_modules</code> do firmware 11.00. E isso não foi por acaso: eu gosto muito de <code>Driveclub</code>. Aliás, é praticamente o único jogo ainda preso no PS4 que eu realmente queria conseguir rodar direito. Eu já vi vários vídeos no YouTube mostrando o jogo funcionando, mas até agora eu mesmo não consegui fazer isso rodar de forma satisfatória no Linux. Documentado em <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/driveclub-shadps4.md"target="_blank" rel="noopener"><code>docs/driveclub-shadps4.md</code></a>. A parte boa é que agora eu não dependo mais de memória muscular pra lembrar como lançar, com qual patch, em que pasta, com quais módulos. A parte ruim é que emulação de PS4 ainda é emulação de PS4. Não existe script que faça upstream amadurecer mais rápido. Se alguém souber como fechar essa configuração no Linux, olhe o projeto no GitHub e mande um PR.</p>
<p>Ridge Racer V tem um flickering de textura de carro documentado nas issues do PCSX2 (#3639, #13729). O renderer Hardware é aceitável pra jogo de corrida onde você não fica admirando parado o modelo. Software renderer resolve mas mata performance. Escolhi aceitar o flicker.</p>
<h2>O ganho real não é só automação<span class="hx:absolute hx:-mt-20" id="o-ganho-real-não-é-só-automação"></span>
    <a href="#o-ganho-real-n%c3%a3o-%c3%a9-s%c3%b3-automa%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Seria fácil resumir isso como &ldquo;olha que legal, usei IA pra automatizar shell script&rdquo;. Não é isso.</p>
<p>O ganho real é mais chato e mais importante: eu parei de gastar energia mental com trabalho braçal. Não precisei mais lembrar comando raro. Não precisei manter dezenas de abas com wiki, issue, fórum e README. Não precisei deixar meia dúzia de terminais espalhados dando <code>tail</code> em log enquanto tento lembrar que opção escondida de GUI o emulador insiste em regravar no primeiro boot. Eu passei a trabalhar em conversa.</p>
<p>Eu digo pro agente o objetivo. Ele procura os arquivos, lê os logs, encontra o formato certo do config, compara defaults, propõe correções, escreve script, valida paths, verifica UID/GID, confere symlink quebrado, gera wrapper, exporta launcher. Eu continuo responsável pelas decisões, claro. Mas parei de ser digitador de comando raro.</p>
<p>Esse é o ponto que mais me interessa no uso de coding agents em Linux. Eles reduzem dramaticamente a fricção de entrada. Muita gente desiste do desktop Linux não porque o sistema seja incapaz, mas porque a curva de tuning historicamente foi irritante demais. Ter um assistente capaz de ler docs, cruzar config, propor automação e executar com supervisão muda esse jogo.</p>
<h2>Se você quiser reproduzir<span class="hx:absolute hx:-mt-20" id="se-você-quiser-reproduzir"></span>
    <a href="#se-voc%c3%aa-quiser-reproduzir" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>O repo foi publicado pra isso:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">git clone https://github.com/akitaonrails/distrobox-gaming.git
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> distrobox-gaming/ansible
</span></span><span class="line"><span class="cl">ansible-galaxy collection install -r collections/requirements.yml
</span></span><span class="line"><span class="cl">cp host_vars/localhost.yml.example host_vars/localhost.yml
</span></span><span class="line"><span class="cl"><span class="nv">$EDITOR</span> host_vars/localhost.yml  <span class="c1"># ajuste paths da sua máquina</span>
</span></span><span class="line"><span class="cl">ansible-playbook site.yml</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Xenia é opt-in:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">ansible-playbook install-xenia.yml</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Leia o <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/README.md"target="_blank" rel="noopener"><code>README.md</code></a> e o <a href="https://github.com/akitaonrails/distrobox-gaming/blob/master/docs/rebuild-runbook.md"target="_blank" rel="noopener"><code>docs/rebuild-runbook.md</code></a> antes. Eu não distribuo ROM, BIOS, firmware nem chaves. O repo só detecta, linka e configura o que você já tem na sua própria máquina.</p>
<h2>Se você preferir a rota com Claude Code<span class="hx:absolute hx:-mt-20" id="se-você-preferir-a-rota-com-claude-code"></span>
    <a href="#se-voc%c3%aa-preferir-a-rota-com-claude-code" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Minha recomendação é simples:</p>
<ol>
<li>Comece pelo objetivo, não pelo comando. &ldquo;Quero um distrobox Arch com GPU NVIDIA, home separado, ROMs read-only e Steam rw&rdquo; é melhor do que despejar meia linha de shell sem contexto.</li>
<li>Peça sempre pra documentar o que está fazendo. Se der certo, promova o resultado a script ou role. Se não documentar, você acabou de fabricar uma gambiarra descartável.</li>
<li>Trabalhe em fases. Criação da box. Bootstrap. Config de emuladores. Export de launchers. Verificação. Foi exatamente assim que eu quebrei o problema.</li>
<li>Peça verificações objetivas. <code>command -v</code>, existência de arquivos, symlinks quebrados, UID/GID, path de ROM, áudio, GPU. A melhor automação é a que falha cedo.</li>
<li>Não use agente como papagaio de comando. Use como assistente técnico. Você continua revisando as decisões e mandando ajustar o rumo.</li>
</ol>
<p>Pra mim, esse foi o ganho. Eu saí do zero pra uma máquina de emulação muito mais completa sem precisar customizar tudo na unha, em GUI, uma janela por vez. E, dessa vez, terminei com energia pra fazer o que eu queria desde o começo.</p>
<p>Jogar.</p>
]]></content:encoded><category>emulacao</category><category>containers</category><category>automacao</category></item><item><title>Tudo que Precisa Saber Sobre Retro-Gaming</title><link>https://akitaonrails.github.io/2025/09/14/tudo-que-precisa-saber-sobre-retro-gaming/</link><guid isPermaLink="true">https://akitaonrails.github.io/2025/09/14/tudo-que-precisa-saber-sobre-retro-gaming/</guid><pubDate>Sun, 14 Sep 2025 16:00:00 -0300</pubDate><description>&lt;p&gt;Tá, já que escrevi quase um e-book sobre &lt;a href="https://akitaonrails.github.io/2025/14/coisas-que-iniciantes-ignoram-sobre-pcs/"&gt;tudo que você precisa saber sobre componentes de PCs&lt;/a&gt; resolvi que chegou a hora de outro artigo que estou faz anos segurando: &lt;strong&gt;tudo que você precisa saber sobre retro-gaming e handhelds&lt;/strong&gt;. É outro artigo que vai envelhecer mal porque saem coisas novas o tempo todo. Tudo que está aqui vale pra 2025. Então vamos lá.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914123715_20250914_122919.jpg" alt="Coleção" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;Como podem ver, eu tenho praticamente todos os handhelds possíveis e imagináveis. Então acho que tenho alguma propriedade pra falar sobre as vantagens e desvantagens da maioria dos mais populares. E eu tinha mais, mas fui doando pra amigos com o tempo. Esses são os meus favoritos.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Tá, já que escrevi quase um e-book sobre <a href="/2025/14/coisas-que-iniciantes-ignoram-sobre-pcs/">tudo que você precisa saber sobre componentes de PCs</a> resolvi que chegou a hora de outro artigo que estou faz anos segurando: <strong>tudo que você precisa saber sobre retro-gaming e handhelds</strong>. É outro artigo que vai envelhecer mal porque saem coisas novas o tempo todo. Tudo que está aqui vale pra 2025. Então vamos lá.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914123715_20250914_122919.jpg" alt="Coleção"  loading="lazy" /></p>
<p>Como podem ver, eu tenho praticamente todos os handhelds possíveis e imagináveis. Então acho que tenho alguma propriedade pra falar sobre as vantagens e desvantagens da maioria dos mais populares. E eu tinha mais, mas fui doando pra amigos com o tempo. Esses são os meus favoritos.</p>
<p>Vou falar dos hardwares primeiro e na segunda parte do artigo vou falar um pouco dos softwares também. Use os links de seção na direita (na versão desktop), pra navegar onde quer ler primeiro.</p>
<p>Já aviso que vou ser preguiçoso e nas tabelas de especificações, sim, é ChatGPT pra ajudar. Senão é muito detalhe kkkk 🤣</p>
<h3>Ambernic RG400M<span class="hx:absolute hx:-mt-20" id="ambernic-rg400m"></span>
    <a href="#ambernic-rg400m" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914124055_20250914_123944.jpg" alt="RG400M"  loading="lazy" /></p>
<p><strong>Especificações</strong></p>
<table>
  <thead>
      <tr>
          <th>Component</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Display</td>
          <td>4.7-inch LTPS In-Cell, full lamination, multi-touch</td>
      </tr>
      <tr>
          <td>Resolution</td>
          <td>1280 × 960</td>
      </tr>
      <tr>
          <td>Refresh Rate</td>
          <td>120 Hz <a href="https://retrohandhelds.gg/anbernic-rg477m-launched-everything-you-need-to-know/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>CPU</td>
          <td>MediaTek Dimensity 8300 (4nm process) — 1×A715 @ 3.35GHz + 3×A715 @ 3.20GHz + 4×A510 @ 2.20GHz <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>Mali-G615 MC6 <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>RAM options</td>
          <td>8GB LPDDR5 or 12GB LPDDR5 <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>Storage options</td>
          <td>128GB or 256GB UFS internal + micro-SD (TF) expandable to 2TB <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>5,300 mAh, ~7 hours use <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>Charging</td>
          <td>5V/9V — 27W <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>Connectivity</td>
          <td>Wi-Fi 6E, Bluetooth 5.3 <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
      <tr>
          <td>Other features</td>
          <td>3.5mm headphone jack; dual speakers; large-angle 3D Hall joystick with RGB lighting; six-axis gyroscope; active cooling (fan + heat pipe); USB-C display out; vibration motor; FOTA, etc. <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Shell / Build</td>
          <td>Aluminum alloy (CNC), metal body; two colours: Silver Blade &amp; Chocolate Bronze <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Dimensions / Weight</td>
          <td>176 × 89.4 × 16 mm, 354 g <a href="https://anbernic.com/products/rg477m?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+1</a></td>
      </tr>
  </tbody>
</table>
<p>Este é um dos mais antigos que eu ainda tenho. <strong>Ambernic</strong> é a marca que eu mais gosto e um dos mais confiáveis. De vez em quando lançam modelos esquisitos, mas no geral são bem consistentes na qualidade.</p>
<p>Esse modelo 400M acho que não existe mais, mas o sucessor dele é <strong>RG477M</strong> e recomendo assistir o review do canal Retro Game Corps:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/9eQDFtmzuhM"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Durante todo o artigo vou sempre linkar pros reviews desse canal porque considero que o Russ faz os reviews mais completos. Ele realmente vai fundo em cada detalhe, tamanho dos botões, peso, compatibilidade, tudo. É o único canal que você precisa assistir.</p>
<p>Pra 2025 o 400M/477M é antiquado, inclusive é caro, a <a href="https://anbernic.com/products/rg477m"target="_blank" rel="noopener">USD 280</a>, sem considerar frete e taxa bostil (que vai dobrar esse preço). Isso porque ele tem corpo de alumínio, o que dá uma sensação bem mais <strong>premium</strong> do que os baratos de plástico. Porém, eu acho que a maior desvantagem dele é que a resolução da tela é só <strong>1280x960</strong>. Vou falar de resolução em outra seção, mas acho isso <strong>baixa resolução</strong>.</p>
<p>Quer dizer, pra jogar coisas como Gameboy, funciona super bem, mas se for pra Mega Drive, Super Nintendo, já começa a ficar apertado. Acima disso já sinto pixelizado mesmo numa tela pequena de 4.0&quot;.</p>
<p>O 477M tem tela maior, inclusive é isso que os nomes querem dizer: 400M tem tela de 4.0&quot; e 477M tem tela de 4.7&quot;. O 400M tem SoC (System on a Chip) Unisoc T618 2.0Ghz e o 477M tem o MediaTek Dimensity 8300 3.35Ghz. Triplo de RAM (4G LDDDR4X vs 12GB LPDDR5), bateria um pouco maior (4.500 mAh vs 5.300 mAh).</p>
<p>Parece potente mas é porque esse handheld roda Android. Eu particularmente não curto handhelds Android. Depois falo porque.</p>
<p>No geral é um excelente handheld, pequeno, premium, roda bem até PS1 e dá pra arriscar um PSP, mas a tela não foi feita pra isso (PSP é widescreen, este é 4:3). Só que eu <strong>não recomendo</strong> ele é muito caro e a performance não condiz com o preço, só é caro porque é de alumínio. Pelo mesmo preço se compra outros muito melhores, como vou mostrar a seguir.</p>
<h3>TRIUMUI BRICK - MIYOO MINI<span class="hx:absolute hx:-mt-20" id="triumui-brick---miyoo-mini"></span>
    <a href="#triumui-brick---miyoo-mini" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914125818_20250914_125744.jpg" alt="TriumUI - Miyoo"  loading="lazy" /></p>
<p>Os próximos da lista são os verticais &ldquo;miniatura&rdquo;.</p>
<p>O mais clássico de todos é sem dúvida o <a href="https://officialmiyoomini.com/pt_pt/"target="_blank" rel="noopener"><strong>Miyoo Mini Plus</strong></a>:</p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Screen</td>
          <td>2.8-inch IPS</td>
      </tr>
      <tr>
          <td>Resolution</td>
          <td>~ 750 × 560 <a href="https://www.keepretro.com/products/onion-os-miyoo-mini-v4?utm_source=chatgpt.com"target="_blank" rel="noopener">keepretro+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>CPU</td>
          <td>ARM Cortex-A7, dual-core, 1.2 GHz <a href="https://www.keepretro.com/products/onion-os-miyoo-mini-v4?utm_source=chatgpt.com"target="_blank" rel="noopener">keepretro+2Miyoo Mini+2</a></td>
      </tr>
      <tr>
          <td>RAM</td>
          <td>128 MB <a href="https://officialmiyoomini.com/product/miyoo-mini-v4-retro-grey/?utm_source=chatgpt.com"target="_blank" rel="noopener">Miyoo Mini+1</a></td>
      </tr>
      <tr>
          <td>Storage Expansion</td>
          <td>microSD (TF), shipped with 32/64/128 GB cards; supports up to 128 GB <a href="https://www.keepretro.com/products/onion-os-miyoo-mini-v4?utm_source=chatgpt.com"target="_blank" rel="noopener">keepretro+2Miyoo Mini+2</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>2,000 mAh Li-polymer <a href="https://officialmiyoomini.com/product/miyoo-mini-v4-retro-grey/?utm_source=chatgpt.com"target="_blank" rel="noopener">Miyoo Mini+1</a></td>
      </tr>
      <tr>
          <td>Battery Life</td>
          <td>~ 5-6 hours typical <a href="https://www.litnxt.com/products/miyoo-mini-v4-portable-handheld-game-console?utm_source=chatgpt.com"target="_blank" rel="noopener">litnxt+1</a></td>
      </tr>
      <tr>
          <td>Size</td>
          <td>93.5 × 65 × 18 mm <a href="https://officialmiyoomini.com/product/miyoo-mini-v4-retro-grey/?utm_source=chatgpt.com"target="_blank" rel="noopener">Miyoo Mini+1</a></td>
      </tr>
      <tr>
          <td>Weight</td>
          <td>~ 104-107 g <a href="https://retrohandhelds.gg/rg28xx-miyoo-a30-vs-mini-v4-comparison/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Miyoo Mini+2</a></td>
      </tr>
      <tr>
          <td>OS</td>
          <td>Linux (Stock / OnionOS available) <a href="https://www.keepretro.com/products/onion-os-miyoo-mini-v4?utm_source=chatgpt.com"target="_blank" rel="noopener">keepretro+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Sensor / Extras</td>
          <td>Vibration motor; full-lamination screen; flat shoulders; R2/L2 micro buttons; OCA laminated screen in newer batches. <a href="https://www.litnxt.com/products/miyoo-mini-v4-portable-handheld-game-console?utm_source=chatgpt.com"target="_blank" rel="noopener">litnxt+2keepretro+2</a></td>
      </tr>
  </tbody>
</table>
<p>Falei que 4.0&quot; e 1280x960 acho pequeno? O Miyoo Mini Plus tem tela de só 2.8&quot; e resolução de 750x560. O SoC é muito bom com ARM Cortex-A7, 1.2Ghz que consegue rodar bem até PS1. Nessa tela pequena é mais indicado pra coisas como Gameboy, GameGear e outros portáteis antigos. Dá pra jogar NES, MasterSystem, MegaDrive. Mas PS1 já começa a ficar muito pequeno pra conseguir ler.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914130734_20250914_130603.jpg" alt="miyoo screen"  loading="lazy" /></p>
<p>É difícil de descrever quão pequeno é essa tela. Compare acima a tela com meu <strong>dedão</strong> pra ter uma noção. É extremamente pequeno. Não recomendo pra nada muito maior que jogos de Gameboy mesmo. Se você for jovem, com boa vista, vai conseguir jogar melhor. E vai ficar com a vista ruim como a minha mais rápido também kkkk 🤣 fica pelo seu risco.</p>
<p>Eu uso óculos de muito grau, então essa tela é muito pequena pra mim. Mas a construção da Miyoo é muito boa. Ela tem aquela sensação de Gameboy clássico mesmo, só que em miniatura. O fator nostálgico é muito forte.</p>
<p>O melhor OS pra ela é o <a href="https://onionui.github.io/"target="_blank" rel="noopener"><strong>Onion OS</strong></a>, que torna o Miyoo ainda muito melhor. Uma coisa comum é que todo handheld vamos acabar substituindo o OS que vem por um open source melhor. É muito satisfatório a UI pra salvar estado do game, depois recarregar de onde parou.</p>
<p><img src="https://user-images.githubusercontent.com/44569252/189434217-72ef0daf-c630-4ec9-b96a-30fd76cb709f.png" alt="OnionOS"  loading="lazy" /></p>
<p>De longe uma das melhores UIs pra handhelds. Todo OS deveria copiar o OnionOS. De novo, o review do Russ sobre ele é bem detalhado:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/6CkJNKupU9A"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Depois do Miyoo Mini Plus, que considero &ldquo;miniatura com tamanho suficiente&rdquo; é o <a href="https://trimui.net/collections/trimui-brick"target="_blank" rel="noopener"><strong>TrimUI Brick</strong></a>. Ele é parecido em formato e funcionalidades com o <a href="https://anbernic.com/en-br/products/rg35xx-plus"target="_blank" rel="noopener"><strong>Ambernic RG35xx Plus</strong></a> então qualquer um dos dois vai atender quem quer esse tamanho.</p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>Allwinner A133P, 1.8 GHz <a href="https://retrohandhelds.gg/trimui-brick-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2keepretro+2</a></td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>PowerVR GE8300 @ 660 MHz <a href="https://trimui.net/products/trimui-brick-retro-handheld-game-64g?srsltid=AfmBOorFLIscOPS80tgdzShZ1bVwngtTX1q8VU01fVL5UH12dqlAoUaP&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">Trimui Store+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>RAM</td>
          <td>1 GB LPDDR3/LPDDR4x (sources vary) <a href="https://mechdiy.com/products/trimui-brick-retro-handheld-game-console?srsltid=AfmBOooc_fIOP2p5G2jnS2jspN4lbtt6qXdi6PEOijUZu6Kh7gB4Ue-J&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">Mechdiy+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Internal Storage</td>
          <td>8 GB eMMC <a href="https://trimui.net/products/trimui-brick-retro-handheld-game-64g?srsltid=AfmBOorFLIscOPS80tgdzShZ1bVwngtTX1q8VU01fVL5UH12dqlAoUaP&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">Trimui Store+1</a></td>
      </tr>
      <tr>
          <td>External Storage</td>
          <td>TF card support up to ~1 TB <a href="https://retrohandhelds.gg/trimui-brick-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+1</a></td>
      </tr>
      <tr>
          <td>Display</td>
          <td>3.2-inch IPS, fully laminated, 1024×768 (4:3) <a href="https://retrohandhelds.gg/trimui-brick-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2keepretro+2</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>3,000 mAh Li-polymer; ~5-6 hours typical use <a href="https://retrohandhelds.gg/trimui-brick-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2keepretro+2</a></td>
      </tr>
      <tr>
          <td>Wireless / BT</td>
          <td>Wi-Fi 802.11 b/g/n; Bluetooth 2.1 + EDR / 4.2 <a href="https://trimui.net/products/trimui-brick-retro-handheld-game-64g?srsltid=AfmBOorFLIscOPS80tgdzShZ1bVwngtTX1q8VU01fVL5UH12dqlAoUaP&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">Trimui Store+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Audio</td>
          <td>Stereo speakers, 3.5mm jack, mono mic <a href="https://www.keepretro.com/products/trimui-brick-handheld?utm_source=chatgpt.com"target="_blank" rel="noopener">keepretro+1</a></td>
      </tr>
      <tr>
          <td>Other Features</td>
          <td>RGB lighting (top bar, shoulder buttons etc.), vibration, FN keys, USB-C ports (charging, host, OTG) <a href="https://trimui.net/products/trimui-brick-retro-handheld-game-64g?srsltid=AfmBOorFLIscOPS80tgdzShZ1bVwngtTX1q8VU01fVL5UH12dqlAoUaP&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">Trimui Store+2keepretro+2</a></td>
      </tr>
      <tr>
          <td>Size / Weight</td>
          <td>~73.2 × 109.9 × 19.9 mm; ~159 g <a href="https://retrohandhelds.gg/trimui-brick-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+1</a></td>
      </tr>
  </tbody>
</table>
<p>A tela do TrimUI é consideravelmente melhor em qualidade, cores saturadas, mais nítido, mais brilhante. É uma das melhores telas nesse formato que existem. Não tem como errar. Comparado com o Miyoo Mini, veja a diferença de qualidade de tela e, principalmente o tamanho!</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914131820_20250914_131501.jpg" alt="TrimUI vs Miyoo"  loading="lazy" /></p>
<p>E veja como a área útil não é muito menor que a tela de um Gameboy Advance SP de verdade, por isso é bem jogável.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914131658_20250914_131609.jpg" alt="TriumUI GB Advance"  loading="lazy" /></p>
<p>Pra melhorar, existem outros OS que dá pra instalar no TrimUI, como o lendário <a href="https://knulli.org/pt-BR/"target="_blank" rel="noopener"><strong>Knulli</strong></a>, mas você pode optar por pedir um microSD card já configurado e com vários jogos bons (não aquela lista genérica gigante de jogos repetidos que vem nos outros). Ele vem com o <a href="https://surwish.com/"target="_blank" rel="noopener"><strong>SurwishOS</strong></a>, que não é um OnionOS mas não está longe.</p>
<p>Ou seja, &ldquo;out-of-the-box&rdquo;, sem precisar configurar nada, o TrimUI Brick é um dos mais simples. Só ligar e já jogar, sem precisar mexer em OS ou fazer qualquer tuning. Plug and play. É fácil, um dos melhores que posso recomendar.</p>
<p>Novamente, roda bem até PS1, arrisca um PSP mas PSP é muito pesado mesmo. Não é o indicado. O ideal é até Gameboy Advance. Assista o review do Russ:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/F1fHemFCi3I"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Numa classe um pouco superior, mais parecida com Ambernic RG35XX vertical, tem os <a href="https://www.goretroid.com/collections/retro-game-system/products/retroid-pocket-classic"target="_blank" rel="noopener"><strong>Retroid Pocket Classic</strong></a>. Eu nunca tive, mas ouço falar muito bem também. Em particular a versão com 6 botões igual controle de luta do Mega Drive/Sega Saturn:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914155554_Retroid-Pocket-Classic-08.webp" alt="Retroid Classic"  loading="lazy" /></p>
<p>Também é uma boa recomendação e tem o r<a href="https://www.youtube.com/watch?v=HQOBdhnnQkM"target="_blank" rel="noopener">eview do Russ</a>.</p>
<h3>Ambernic RG35XX SP<span class="hx:absolute hx:-mt-20" id="ambernic-rg35xx-sp"></span>
    <a href="#ambernic-rg35xx-sp" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Se eu tivesse que escolher só um, ficaria bem dividido com o TrimUI Brick, mas acho que acabaria sempre voltando pra este: <a href="https://br.anbernic.com/products/rg35xxsp?variant=44326801539225"target="_blank" rel="noopener"><strong>Ambernic RG35XX SP</strong></a></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914132910_20250914_132230.jpg" alt="RG35XX SP fechado"  loading="lazy" /></p>
<p>Como expliquei antes, RG400M significa tela de 4&quot;, então RG35XX significa tela de 3.5&quot;. É um pouco maior que os 3.2&quot; do TrimUI Brick, um pouco menor que o RG477M. Na minha opinião acho que este é o &ldquo;sweet-spot&rdquo; entre portabilidade e visibilidade.</p>
<p>O &ldquo;SP&rdquo; significa que ele copiou o formato do lendário <strong>Gameboy Advance SP</strong>&quot;, a segunda revisão da Nintendo que introduziu o formato &ldquo;<strong>clamshell</strong>&rdquo;, que se dobra ao meio. A grande vantagem é que esse formato protege a tela quando fechada e não precisamos de uma bolsa pra quando queremos jogar na mochila, preocupados em riscar a tela.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914133341_20250914_132251.jpg" alt="RG35XX aberto"  loading="lazy" /></p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>Allwinner H700, quad-core ARM Cortex-A53 @ 1.5 GHz <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2GamesRadar++2</a></td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>Dual-core Mali-G31 MP2 <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>RAM</td>
          <td>1 GB LPDDR4 <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>Internal Storage</td>
          <td>64 GB via TF/MicroSD (some variants lower) <a href="https://anbernic.com/products/rg35xxsp?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+2Mechdiy+2</a></td>
      </tr>
      <tr>
          <td>Display</td>
          <td>3.5-inch IPS, OCA fully bonded, 640×480 (4:3) <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2GamesRadar++2</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>3,300 mAh Li-polymer, ~8 hours use <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Amazon+2</a></td>
      </tr>
      <tr>
          <td>Charging</td>
          <td>5 V / 1.5 A, USB-C, supports USB-C to C charger <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>Connectivity</td>
          <td>WiFi 802.11 a/b/g/n/ac (2.4/5 GHz), Bluetooth 4.2 (controllers only) <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>Outputs &amp; Extras</td>
          <td>Mini-HDMI output; 3.5mm headphone jack; vibration motor; dual TF card slots; magnetic hinge for sleep/wake; multiple buttons including extra shoulder buttons etc. <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>Dimensions / Weight</td>
          <td>89 × 85 × 27 mm; ~192 g <a href="https://retrohandhelds.gg/anbernic-rg35xxsp-a-first-look/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Anbernic+2</a></td>
      </tr>
      <tr>
          <td>OS</td>
          <td>Linux 64-bit <a href="https://anbernic.com/products/rg35xxsp?utm_source=chatgpt.com"target="_blank" rel="noopener">Anbernic+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
  </tbody>
</table>
<p>Em termos de specs, todos os que falei até agora tem performance parecida. Os RG477M são mais poderosos porque rodam Android (que é bem mais pesado), os demais rodam Linux então é bem mais leve.</p>
<p>Novamente, depende muito de quem é você. Por exemplo, eu tenho mãos pequenas, e mesmo pra mim um Miyoo Mini e até mesmo o TrimUI Brick eu sinto desconfortável pra jogar por muito tempo. Tenho que ficar segurando o console só com os dedos. Já o RG35XX SP se apoia na palma das minhas mãos, então eu sinto muito mais confortável e ergonômico pra jogar.</p>
<p>Por causa disso também eu não recomendo a nova versão RG34XX SP:</p>
<p><img src="https://br.anbernic.com/cdn/shop/files/20250514141311.jpg?v=1747203223&amp;width=1150" alt="RG34XX SP"  loading="lazy" /></p>
<p>Também não recomendo o <strong>Miyoo Flip v2</strong>:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914133648_Miyoo-Flip-Hero-1080x675.webp" alt="Miyoo Flip"  loading="lazy" /></p>
<p>O diferencial deles são os dois controles analógicos no final, que seria bom pra jogar coisas como Nintendo 64, os jogos mais novos de PS1, PSP, Dreamcast. Mas tem um porém: nenhum deles tem potência suficiente pra jogar acima de PS1. Sim, dá pra jogar mais ou menos bem Nintendo 64 e Dreamcast, mas não roda tudo.</p>
<p>Daí o que eu elogiei que dá pra apoiar na palma da mão se perde com os analógicos, porque pra usar os dedões nele, precisa segurar o handheld muito pra cima pra alcançar. Daí tem outro problema: os botões de ombro, que ficam atrás, os L1 e R1, ficam longe de apertar com os indicadores. Pra jogar FPS (jogos de tiro em primeira pessoa), é horrível. Então um Golden Eye 007 do Nintendo 64 fica ruim de jogar, mesmo com os analógicos.</p>
<p>Além disso note o nome: RG34XX, significa que a tela cai de 3.5&quot; pra 3.4&quot;. Falei antes que eu acho 3.5&quot; ideal e nessa nova versão é um downgrade. O erro é tentar achar que dá pra ter um único handheld que vai ser bom pra tudo. Não tem isso.</p>
<p>Outro canal que eu gosto muito é o <strong>Wulff Den</strong> e ele faz essa consideração nesse review:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/mCVOetPvhXQ"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Minha recomendação sempre é o RG35XX SP. Não precisa de botões analógicos e vai rodar tudo até PS1 sem problemas. Mais que isso, você quer um handheld MAIOR e mais potente.</p>
<p>Na categoria &ldquo;clamshells&rdquo; um que vale a pena olhar é o <a href="https://www.goretroid.com/collections/retro-game-system/products/retroid-pocket-flip-2"target="_blank" rel="noopener"><strong>Retroid Pocket Flip 2</strong></a>, que é maior, mais potente e mais caro. Mas ouço falar bem também:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914155800_D_NQ_NP_798192-MLB86423937046_062025-O.webp" alt="Retroid Flip 2"  loading="lazy" /></p>
<p>Novamente, assista o <a href="https://www.youtube.com/watch?v=6LIZWnD-62Q"target="_blank" rel="noopener">review do Russ</a></p>
<h3>Ayn Odin 2<span class="hx:absolute hx:-mt-20" id="ayn-odin-2"></span>
    <a href="#ayn-odin-2" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Vamos falar dos mais potentes. Pra mim, o melhor de todos, que roda basicamente tudo até Nintendo Switch, é o <a href="https://www.ayntec.com/products/odin-2"target="_blank" rel="noopener"><strong>Odin 2</strong></a> - e está pra sair o <a href="https://www.indiegogo.com/projects/odin-3-the-ultimate-6-120hz-oled-gaming-handheld#/"target="_blank" rel="noopener">Odin 3</a>, que vai ser melhor.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914134536_20250914_134446.jpg" alt="Odyn 2"  loading="lazy" /></p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Details</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>Qualcomm Snapdragon 8 Gen 2 <a href="https://www.ayntec.com/products/odin-2?utm_source=chatgpt.com"target="_blank" rel="noopener">AYN+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>Adreno 740 <a href="https://www.ayntec.com/products/odin-2?utm_source=chatgpt.com"target="_blank" rel="noopener">AYN+2Amazon+2</a></td>
      </tr>
      <tr>
          <td>RAM options</td>
          <td>8 GB / 12 GB / 16 GB LPDDR5X <a href="https://retrohandhelds.gg/ayn-odin-2-vs-odin-2-mini-vs-odin-2-portal-an-8-gen-2-shootout/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Amazon+2</a></td>
      </tr>
      <tr>
          <td>Storage options</td>
          <td>128 GB / 256 GB / 512 GB UFS <a href="https://retrohandhelds.gg/ayn-odin-2-vs-odin-2-mini-vs-odin-2-portal-an-8-gen-2-shootout/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Amazon+2</a></td>
      </tr>
      <tr>
          <td>Display</td>
          <td>6-inch IPS LCD, 1920×1080, 60 Hz <a href="https://retrohandhelds.gg/ayn-odin-2-vs-odin-2-mini-vs-odin-2-portal-an-8-gen-2-shootout/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Amazon+2</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>8,000 mAh Li-polymer <a href="https://retrohandhelds.gg/ayn-odin-2-vs-odin-2-mini-vs-odin-2-portal-an-8-gen-2-shootout/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2AYN+2</a></td>
      </tr>
      <tr>
          <td>Charging / Ports</td>
          <td>USB-C with video output; HDMI + Micro HDMI in some variants <a href="https://www.amazon.com/Android-handheld-performance-Snapdragon-Octa-core-storage/dp/B0CP45TJF2?utm_source=chatgpt.com"target="_blank" rel="noopener">Amazon+1</a></td>
      </tr>
      <tr>
          <td>Wireless / Bluetooth</td>
          <td>Wi-Fi 7; Bluetooth 5.3 <a href="https://retrohandhelds.gg/ayn-odin-2-vs-odin-2-mini-vs-odin-2-portal-an-8-gen-2-shootout/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2AYN+2</a></td>
      </tr>
      <tr>
          <td>Weight</td>
          <td>~ 420 g <a href="https://www.amazon.com/Android-handheld-performance-Snapdragon-Octa-core-storage/dp/B0CP45TJF2?utm_source=chatgpt.com"target="_blank" rel="noopener">Amazon+2AYN+2</a></td>
      </tr>
      <tr>
          <td>Operating System</td>
          <td>Android 13 <a href="https://www.ayntec.com/products/odin-2?utm_source=chatgpt.com"target="_blank" rel="noopener">AYN+1</a></td>
      </tr>
      <tr>
          <td>Variants</td>
          <td>Base / Pro / Max with different RAM/storage combos</td>
      </tr>
  </tbody>
</table>
<p>O preço não é muito maior que o RG477M, mas ele é infinitamente melhor. Na faixa de <strong>USD 300</strong> (sem frete, sem impostos), é o melhor custo-benefício.</p>
<p>Veja as especificações, é um Qualcomm Snapdragon 8 Gen 2. É o mesmo chip que se tem em smartphones Android midrange pra high-end. Com GPU Adreno 740 e de 8GB até 16 GB LPDDR5X. Bateria de 8.000 mAh (maioria dos smartphones nessa categoria tem bateria de 5.000 mAh ou menos).</p>
<p>O principal: é uma tela IPS 6&quot; de 1080p de resolução (Full-HD). Nesse tamanho, até eu que sou cegueta, consigo enxergar qualquer jogo sem problemas. Um Nintendo Switch original tem tela de 6.2&quot;, então é levemente menor. É basicamente a potência de um Switch 2, na realidade.</p>
<p>O review do Wulff Den diz tudo:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/KHwHpiAMog4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Na prática, veja na foto os controles: se quiser ter sticks analógicos, eles precisam estar no formato de Xbox ou Switch, na horizontal, esse é o formato mais ergonômico pra jogar por bastante tempo. Por isso falei que os Miyoo Flip ou RG34XX SP não vale a pena. No Odin 2 sim, dá pra jogar Halo, Golden Eye, Doom, etc sem problemas. E como é um Android também dá pra instalar Call of Duty da Play Store sem problemas.</p>
<p>Agora, minha reclamação pessoal: Android é BEM mais chato pra configurar emuladores do que Linux. De longe mesmo. Precisa de MUITO tempo, MUITA paciência e MUITA tentativa e erro até deixar do jeito perfeito. É tanta coisa que recomendo assistir o guia do Russ sobre isso:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/I4mqgcDYZFo"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Sério, assista o video, leia o <a href="https://retrogamecorps.com/2022/03/13/android-emulation-starter-guide/"target="_blank" rel="noopener">blog post</a> do site dele pra mais detalhes. Você não vai acertar de primeira.</p>
<p>Pelo menos, uma vez configurado, vai rodar tudo liso. PSP com 3x resolução, Dreamcast com 3x resolução, PS2 com 3x resolução, GameCube com 2x resolução, até Switch Full-HD Docker mode. É meu modelo preferido pra jogar PSP mesmo: Ridge Racer 2 fica perfeito.</p>
<p>Nessa categoria de Android horizontal, outra boa recomendação é o <a href="https://www.goretroid.com/collections/retro-game-system/products/retroid-pocket-5-handheld"target="_blank" rel="noopener"><strong>Retroid Pocket 5</strong></a>, na mesma faixa de preço e também ouço falar bem. Em particular todo mundo fala muito bem da qualidade da tela.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914160025_kiboTEK_retroid_pocket_5_005-1024x1024.webp" alt="Retroid Pocket 5"  loading="lazy" /></p>
<p>Novamente, assista o <a href="https://www.youtube.com/watch?v=ZFTrwWQOe5Y"target="_blank" rel="noopener">review do Russ</a>.</p>
<h3>Ayaneo Pocket DMG<span class="hx:absolute hx:-mt-20" id="ayaneo-pocket-dmg"></span>
    <a href="#ayaneo-pocket-dmg" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Se tiver dinheiro pra jogar fora mesmo, também recomendo o <a href="https://ayaneo.com/product/AYANEO-Pocket-DMG"target="_blank" rel="noopener"><strong>Ayaneo Pocket DMG</strong></a>. Esse monstro começa na bagatela de <strong>USD 420</strong> (sem impostos, sem frete, na config básica). Se escolher tudo, sobe até <strong>USD 690</strong>. Mais caro que um Playstation 5!!! Realmente não dá pra recomendar, é o pior custo-benefício de todos.</p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>Snapdragon G3x Gen 2 <a href="https://retrohandhelds.gg/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Time Extension+2</a></td>
      </tr>
      <tr>
          <td>GPU</td>
          <td>Adreno A32 <a href="https://www.timeextension.com/reviews/ayaneo-pocket-dmg-this-pricey-emulation-monster-thinks-its-a-game-boy?utm_source=chatgpt.com"target="_blank" rel="noopener">Time Extension+2Retro Dodo+2</a></td>
      </tr>
      <tr>
          <td>RAM (options)</td>
          <td>8 GB / 12 GB / 16 GB LPDDR5X <a href="https://retrohandhelds.gg/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2overkill Media+2</a></td>
      </tr>
      <tr>
          <td>Storage (internal)</td>
          <td>128 GB / 256 GB / 512 GB / 1 TB <a href="https://retrododo.com/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Dodo+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Display</td>
          <td>3.92-inch OLED, 1240×1080 (≈31:27 aspect) <a href="https://retrohandhelds.gg/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Time Extension+2</a></td>
      </tr>
      <tr>
          <td>OS</td>
          <td>Android 13 <a href="https://www.timeextension.com/reviews/ayaneo-pocket-dmg-this-pricey-emulation-monster-thinks-its-a-game-boy?utm_source=chatgpt.com"target="_blank" rel="noopener">Time Extension+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Connectivity</td>
          <td>Wi-Fi 6; Bluetooth 5.3 <a href="https://www.timeextension.com/reviews/ayaneo-pocket-dmg-this-pricey-emulation-monster-thinks-its-a-game-boy?utm_source=chatgpt.com"target="_blank" rel="noopener">Time Extension+2Retro Handhelds - Play It Forever+2</a></td>
      </tr>
      <tr>
          <td>Expansion Ports</td>
          <td>microSD slot; USB-C (for charging/data) <a href="https://droix.net/blogs/ayaneo-pocket-dmg-review/?srsltid=AfmBOoqrvlyNHVvMF7_f9Jn4pgVKChziQFJitL7RDCD-9tmjywBIJvKc&amp;utm_source=chatgpt.com"target="_blank" rel="noopener">DROIX Global+1</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>6000 mAh <a href="https://retrohandhelds.gg/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Retro Dodo+2</a></td>
      </tr>
      <tr>
          <td>Size</td>
          <td>91.5 × 151 × 22.3 mm <a href="https://www.timeextension.com/reviews/ayaneo-pocket-dmg-this-pricey-emulation-monster-thinks-its-a-game-boy?utm_source=chatgpt.com"target="_blank" rel="noopener">Time Extension+2DROIX Global+2</a></td>
      </tr>
      <tr>
          <td>Weight</td>
          <td>~ 278-279 g <a href="https://retrohandhelds.gg/ayaneo-pocket-dmg-review/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2Time Extension+2</a></td>
      </tr>
  </tbody>
</table>
<p>Ele é mais potente que o Odin 2 com um Snapdragon G3x Gen 2 e Adreno A32. É comparável a um bom Samsung Galaxy da vida.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914140234_20250914_140205.jpg" alt="Pocket DMG"  loading="lazy" /></p>
<p>A construção dele é super-premium, case, botões, tudo. A tela é um pouco pequena, de 3.92&quot; (acima do que eu falei que considero ideal no 35XX SP), mas é OLED, super nítido, super brilhante, cores super saturadas, uma das melhores telas em qualquer handheld, comparável mesmo à tela de um Samsung Galaxy. Não tem como errar com essa tela. Todo jogo fica ainda mais bonito nela. Por isso custa <strong>caro</strong>!</p>
<p>Pra não dizer que é perfeito, os botões são um pouco &ldquo;mushy&rdquo; enquanto eu prefiro botões mais &ldquo;clicky&rdquo; com os Ambernic. Mas não significa que são ruins.</p>
<p>Por ser potente, também rodaria até Nintendo Switch sem problemas, mas aí a limitação é o tamanho da tela. Não acho que vale a pena rodar jogos feitos pra TVs grandes numa tela tão pequena assim. Ela é melhor mesmo pra retro-games, mas vai rodar PS2 e Gamecube de boas mesmo, com todos os filtros e upscaling que quiser pra deixar mais bonito que o original.</p>
<p>O review do Wulff Den diz tudo:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/U7G_R7nj7BM"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Sendo Snapdragon, esse handheld também é Android, então também é um saco de configurar. Mas no final roda tudo direitinho mesmo. Só seguir o guia do Russ.</p>
<p>Ele tem esse stick analógico no canto inferior esquerdo e tem um touchpad na direita que simula stick analógico direito. Não é confortável pra FPS, é usável pra algumas coisas como reposicionar câmera em jogos de plataforma 3D. Mas não espere usar o tempo todo. Tem o mesmo problema do Miyoo Flip que falei acima: fica MUITO pra baixo. Não é confortável num handheld vertical.</p>
<p>Se quiser jogos que requerem sticks analógicos, é melhor ficar num handheld horizontal, como o Odin 2, SteamDeck, Rog Ally, etc. O nome DMG é de Dot-Matrix Gameboy, que é o Gameboy Clássico. E o Pocket DMG de fato tem todos os fatores nostálgicos do DMG.</p>
<p>Eu, que tive o clássico, gosto muito desse formato. Mas eu acho que se você não tem nostalgia desse período, não vai fazer muita diferença. Esse formato limita jogos feitos pra telas wide-screen. Nesse caso o formato horizontal similar a Nintendo Switch é mil vezes mais ergonômico.</p>
<p>Como falei antes, é pra quem tem nostalgia e dinheiro pra jogar fora. Nada justifica comprar esse aparelho, por melhor que ele seja. É pra colecionador como eu. Odin 2 ou Retroid Pocket 5 tem custo-benefício melhores pra essa categoria.</p>
<h3>Analog Pocket<span class="hx:absolute hx:-mt-20" id="analog-pocket"></span>
    <a href="#analog-pocket" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Falando em caros, chegamos na categoria <strong>super-premium</strong>. E o mais super-premium de todos com certeza é o <a href="https://store.analogue.co/products/analogue-pocket-black"target="_blank" rel="noopener"><strong>Analog Pocket</strong></a>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914141132_20250914_141049.jpg" alt="Analog Pocket"  loading="lazy" /></p>
<p>Essa desgraça nunca está em estoque. Eu mesmo encomendei na época da campanha de lançamento na Indiegogo e levou acho que <strong>1 ano</strong> pra chegar na minha casa. Custou os olhos da cara e mais alguns rims com os impostos do Brasil.</p>
<p>Ele é caro, mas o Pocket DMG é mais caro. Felizmente o preço hoje - se estiver em estoque - é &ldquo;só&rdquo; <strong>USD 220</strong> (sem frete, sem impostos). É razoavelmente acessível. Mas ele é feito pra um público muito específico: quem gosta de FPGAs.</p>
<p>A Analog é famosa por não usar emuladores via software, como RetroArch. Todos os handhelds que comentei até agora usam emuladores: Citra, RPCS3, PCSX2, DuckStation, Sudachi, Yuzu, etc.</p>
<table>
  <thead>
      <tr>
          <th>Spec</th>
          <th>Detail</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Display</td>
          <td>3.5-inch backlit LTPS LCD, Gorilla Glass, 1600 × 1440 resolution (~615 ppi) <a href="https://www.analogue.co/pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">TweakTown+3analogue.co+3Retro Handhelds - Play It Forever+3</a></td>
      </tr>
      <tr>
          <td>Refresh Rate / Display Modes</td>
          <td>Variable refresh (about 30-62 Hz) with modes simulating original hardware quirks; supports display filters / palettes per system <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia+2analogue.co+2</a></td>
      </tr>
      <tr>
          <td>CPU / FPGA</td>
          <td>Altera Cyclone V FPGA (≈49,000 logic elements) + Altera Cyclone 10 for system management <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia+1</a></td>
      </tr>
      <tr>
          <td>Memory</td>
          <td>~ 3.4 MB Block RAM (in Cyclone V), plus 2 × 16 MB 16-bit cellular RAM, 64 MB 16-bit synchronous DRAM, 256 KB asynchronous SRAM <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>4,300 mAh Li-ion (≈3.7 V) <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia+2Reddit+2</a></td>
      </tr>
      <tr>
          <td>Battery Life</td>
          <td>~6-10 hours depending on usage/brightness <a href="https://retrohandhelds.gg/rh-reviews-the-analogue-pocket/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+1</a></td>
      </tr>
      <tr>
          <td>Weight</td>
          <td>~276 g <a href="https://retrohandhelds.gg/rh-reviews-the-analogue-pocket/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+1</a></td>
      </tr>
      <tr>
          <td>Connectivity / I/O</td>
          <td>USB-C (for power, firmware, dock/video); micro-SD slot; 3.5 mm headphone jack; Game Boy link cable port <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia+1</a></td>
      </tr>
      <tr>
          <td>Cartridge Support</td>
          <td>Native for Game Boy / Game Boy Color / Game Boy Advance; supports additional systems via adapters (Game Gear, Neo Geo Pocket, TurboGrafx-16, Atari Lynx etc.) <a href="https://retrohandhelds.gg/rh-reviews-the-analogue-pocket/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2analogue.co+2</a></td>
      </tr>
      <tr>
          <td>Extras</td>
          <td>Stereo speakers; Nanoloop sequencer/synth; original style “link” port; sleep mode; various display filters; possibility of dock for HDMI output (via Analogue Dock, sold separately) <a href="https://retrohandhelds.gg/rh-reviews-the-analogue-pocket/?utm_source=chatgpt.com"target="_blank" rel="noopener">Retro Handhelds - Play It Forever+2analogue.co+2</a></td>
      </tr>
      <tr>
          <td>Release Date</td>
          <td>December 13, 2021 <a href="https://en.wikipedia.org/wiki/Analogue_Pocket?utm_source=chatgpt.com"target="_blank" rel="noopener">Wikipedia+2Ars Technica+2</a></td>
      </tr>
  </tbody>
</table>
<p>O Analog Pocket vem com o Altera Cyclone V FPGA. Ele foi feito pra rodar consoles antigos como se fosse o hardware original. Não é 100% perfeito (porque os cores de cada console são codificados via engenharia reversa dos chips, mas não é garantia que foram clonados 100%, depende de quem codificou os cores).</p>
<p>No caso do Pocket, ele tem slot pra encaixar cartuchos de verdade de Gameboy e Gameboy Advance. Dinamicamente ele copia a ROM pra memória RAM, carrega o core do Gameboy, e dali é como se estivesse rodando um Gameboy de verdade, no hardware original. Então coisas como frame lag, input lag, e qualquer tipo de latência são minimizados ou zerados. E se jogar lado a lado com um Gameboy de verdade, ele tende a ser idêntico, frame a frame.</p>
<p>Pra maioria das pessoas, na prática, isso não importa - ninguém vai ficar comparando quadro a quadro e a maioria dos emuladores via software hoje fazem um excelente trabalho de emular os consoles antigos de uma forma que um jogador médio não vai perceber a diferença. É realmente só pra quem entende os detalhes, como speed runners. Eu mesmo não noto a diferença.</p>
<p>Mas a grande vantagem desse console, pra mim, é a tela. O tamanho dela é só 3.5&quot; e é IPS, não OLED. Mas é um dos melhores IPS do mercado. Brilhante, boas cores. Mais importante, é a mais densa do mercado com resolução absurda de 1600x1440 pixels (absurdos 615 ppi).</p>
<p>Isso é exatamente 10x a resolução do Gameboy original. Significa que ele consegue fazer upscaling de 10x pixel-perfect. Cada 1 pixel do Gameboy original vira 10 pixels no Analog Pocket. Com isso é possível também colocar filtros que simulam a tela dot-matrix verde antiga, no nível do sub-pixel, simulando todos os efeitos colaterais daquela tela obsoleta, trazendo uma sensação ainda mais perfeita de estar jogando um Gameboy de verdade.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914142232_20250914_142204.jpg" alt="DMG screen"  loading="lazy" /></p>
<p>Não é exagero. Olhem nessa foto, a simulação dos pixels do LCD antigo. Você enxerga exatamente o mesmo comportamento dos pixels com latência do LCD verde.</p>
<p>Acho que ninguém fez um review mais detalhado do que a <strong>Digital Foundry</strong>:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/O9Qy-H7H6og"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Essa tela, sozinha, é razão suficiente pra ter um Analog Pocket se você for um aficcionado por retro-games como eu. É item de colecionador que aprecia qualidade de verdade.</p>
<p>Além disso, eles abriram suporte a <strong>openFPGA</strong> e isso dá possibilidade de instalar dezenas de outras cores de FPGA feitas pela comunidade open source.</p>
<p>Existem várias ferramentas pra instalar e organizar esses cores, como o <a href="https://github.com/neil-morrison44/pocket-sync"target="_blank" rel="noopener">PocketSync</a></p>
<p><img src="https://github.com/neil-morrison44/pocket-sync/raw/main/readme_images/main_screen.png" alt="PocketSync"  loading="lazy" /></p>
<p>Tem FPGAs de arcades antigos, CPS1, NeoGeo, Lynx, PC Engine e muito mais. É como ter o hardware original desses consoles no seu bolso. Não tem experiência igual.</p>
<p>Sim, dá pra rodar tudo isso num emulador no seu PC. Mas vai por mim, essa tela é impressionante. Igualmente tão impressionante quanto o OLED do Pocket DMG. Eles ficam pau a pau em nível de qualidade, mas o Analog tem mais densidade de resolução ainda.</p>
<h3>Menção Honrosa: Razer Kishi<span class="hx:absolute hx:-mt-20" id="menção-honrosa-razer-kishi"></span>
    <a href="#men%c3%a7%c3%a3o-honrosa-razer-kishi" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Notem como metade dos handhelds que eu falei acima são todos Android. Basicamente chips de smartphone mesmo. Daí você já deve ter pensado, <em>&ldquo;ué, porque não jogar direto no meu smartphone então?&rdquo;</em></p>
<p>E você está correto. Pra isso existem controles especiais pra smartphones, como o meu favorito, o <a href="https://www.razer.com/br-pt/mobile-controllers/razer-kishi-v2"target="_blank" rel="noopener"><strong>Razer Kishi</strong></a></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914143603_20250914_143535.jpg" alt="Razer Kishi"  loading="lazy" /></p>
<p>Pra você que não pode sair de casa sem seu Genshin Impact, essa é a melhor opção mesmo:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914143839_razer-kishi-v2-usbc-hero-desktop-1920x700-update.webp" alt="Kishi"  loading="lazy" /></p>
<p>Eu sei que existem outras alternativas, algumas genéricas do AliExpress, e eu não conheço elas. Procure o review específico no YouTube. Cada uma tem suas características. E por causa de tamanho, posição da porta USB-C e coisas assim, nem todo modelo encaixa, por isso é bom ver o site do fabricante pra ver se seu modelo vai encaixar nele. Não é garantido.</p>
<p>Mas ele basicamente funciona como um controle de Xbox conectado via Bluetooth ou USB-C no seu smartphone. Só isso.</p>
<p>O <a href="https://retrogamecorps.com/2022/03/13/android-emulation-starter-guide/"target="_blank" rel="noopener">guia de Android do Russ</a> vale pro seu smartphone também então dá pra instalar emuladores e jogar retro-games igual um Odin 2 ou Pocket DMG. A tela de smartphone normalmente é maior e você já carrega ele no seu bolso todos os dias, daí não precisa carregar um segundo dispositivo.</p>
<p>O controle em si não é pequeno, mas é leve. Tem num case que é fácil de jogar na mochila e não ter problema:</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914144206_20250914_144142.jpg" alt="case kishi"  loading="lazy" /></p>
<p>Então sim, não precisa gastar a mais com um novo handheld, use seu smartphone ou aquele mais velho que você encostou e não tinha uso pra ele. Pra retro-games vai funcionar muito bem.</p>
<h3>Rog Ally X<span class="hx:absolute hx:-mt-20" id="rog-ally-x"></span>
    <a href="#rog-ally-x" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>No outro lado espectro, se quiser o mais poderoso e o mais versátil de todos, tamanho não for problema, dinheiro não for problema, vá pra um Handheld PC mesmo. Na minha opinião, o melhor ainda é o <a href="https://rog.asus.com/br/gaming-handhelds/rog-ally/rog-ally-x-2024/"target="_blank" rel="noopener"><strong>ASUS Rog Ally X</strong></a></p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914144402_20250914_144341.jpg" alt="Rog Ally X"  loading="lazy" /></p>
<p>Esse é caro nível notebook, porque é basicamente isso que ele é: um notebook num formato mais compacto. Tem as mesmas tecnologias de um notebook.</p>
<table>
  <thead>
      <tr>
          <th>Category</th>
          <th>Specification</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>CPU</td>
          <td>AMD Ryzen Z1 Extreme processor <a href="https://rog.asus.com/gaming-handhelds/rog-ally/rog-ally-x-2024/?utm_source=chatgpt.com"target="_blank" rel="noopener">@ROG+2Tom&rsquo;s Guide+2</a></td>
      </tr>
      <tr>
          <td>RAM</td>
          <td>Up to 24 GB LPDDR5X-7500 <a href="https://rog.asus.com/gaming-handhelds/rog-ally/rog-ally-x-2024/?utm_source=chatgpt.com"target="_blank" rel="noopener">@ROG+2Ars Technica+2</a></td>
      </tr>
      <tr>
          <td>Storage</td>
          <td>Up to 2 TB NVMe M.2-2280 SSD; common version is 1 TB <a href="https://rog.asus.com/us/gaming-handhelds/rog-ally/rog-ally-x-2024/?utm_source=chatgpt.com"target="_blank" rel="noopener">@ROG+2Best Buy+2</a></td>
      </tr>
      <tr>
          <td>Display</td>
          <td>7-inch IPS LCD, FHD (1920×1080), 120 Hz refresh rate, 500 nits brightness, Gorilla Glass Victus, sRGB 100%, Adobe ~75% <a href="https://rog.asus.com/us/gaming-handhelds/rog-ally/rog-ally-x-2024/spec/?utm_source=chatgpt.com"target="_blank" rel="noopener">@ROG+2Tom&rsquo;s Guide+2</a></td>
      </tr>
      <tr>
          <td>Ports / I/O</td>
          <td>• 1x USB-C (USB4 / DisplayPort 2.1 / Power Delivery)  <br>• 1x USB-C USB 3.2 Gen2  <br>• 3.5 mm audio jack  <br>• microSD card reader (UHS-II) <a href="https://www.xbox.com/en-US/handhelds/rog-xbox-ally?utm_source=chatgpt.com"target="_blank" rel="noopener">Xbox.com+2Tom&rsquo;s Guide+2</a></td>
      </tr>
      <tr>
          <td>Wireless / Connectivity</td>
          <td>Wi-Fi 6E; Bluetooth 5.2 <a href="https://www.tomsguide.com/gaming/handheld-gaming/asus-rog-ally-x-review?utm_source=chatgpt.com"target="_blank" rel="noopener">Tom&rsquo;s Guide+1</a></td>
      </tr>
      <tr>
          <td>Battery</td>
          <td>80 Wh battery cell <a href="https://www.tomsguide.com/gaming/handheld-gaming/asus-rog-ally-x-review?utm_source=chatgpt.com"target="_blank" rel="noopener">Tom&rsquo;s Guide+1</a></td>
      </tr>
      <tr>
          <td>Cooling / Design</td>
          <td>Zero Gravity thermal system with dual fans; upgraded grips and refined control layout vs original Ally <a href="https://los40.com/2024/06/06/asus-lanza-el-rog-ally-x-una-de-las-mejores-consolas-portatiles-del-mercado/?utm_source=chatgpt.com"target="_blank" rel="noopener">LOS40+1</a></td>
      </tr>
      <tr>
          <td>Weight &amp; Size</td>
          <td>~ 678 g; dimensions similar to original Ally but thicker and heavier due to bigger battery and reinforced frame <a href="https://los40.com/2024/06/06/asus-lanza-el-rog-ally-x-una-de-las-mejores-consolas-portatiles-del-mercado/?utm_source=chatgpt.com"target="_blank" rel="noopener">LOS40+1</a></td>
      </tr>
      <tr>
          <td>OS</td>
          <td>Windows 11 Home + Armoury Crate SE <a href="https://rog.asus.com/gaming-handhelds/rog-ally/rog-ally-x-2024/?utm_source=chatgpt.com"target="_blank" rel="noopener">@ROG+1</a></td>
      </tr>
  </tbody>
</table>
<p>A primeira versão (que ainda é boa e superior ao Steam Deck), num Mercado Livre, vai ser faixa de <strong>BRL 5.000</strong>. A segunda geração que é o &ldquo;X&rdquo;, com chip Z1 Extreme vai ser nada menos que uns <strong>BRL 15.000</strong>. Como falei é nível de notebook e iPhones.</p>
<p>Mas também, se conectar em qualquer Dock USB-C, dá pra conectar num monitor externo, teclado, mouse e ele vira um PC mesmo, rodando Windows 11 normalmente. Dá pra usar pra navegar a web, ver seus e-mails, até programar.</p>
<p>São 24GB de LPDDR5X-7500 (compartilhada com a iGPU Radeon) é bem rápida, tem 2TB de NVME 2280 (full-size), tela de 7&quot; IPS (1&quot; maior que o Switch Original, 1&quot; menor que o Switch 2, Full-HD, 1920x1080 pixels, 120hz, 500 nits de brilho).</p>
<p>O SOC Z1 Extreme é Zen 4, com 8 cores, 16 threads, boost até 5.10 Ghz, com Radeon 780M (12 CUs), TDP de 15 a 30W (essa é a parte que ele é mais fraco que um notebook, lógico, não tem espaço pra dissipar mais calor).</p>
<p>Em comparação a outros chips, ele é mais rápido que um antigo Ryzen 9 5980HS, mais rápido que um Ryzen 5 7535HS. Ou seja é classe de um Ryzen 9 HS. Não chega a ser classe desktop como um Ryzen 9 7945HX ou 8945HX, mas pra um handhed, é muita potência.</p>
<p>E sim, tem outros similares no mercado hoje, como o <a href="https://www.lenovo.com/us/en/c/handheld/"target="_blank" rel="noopener">Lenovo Legion Go</a> que tem tela maior ainda de 8&quot; 120hz, mesmo Z1 Extreme. Ou o Legion Go 2 já com Z2 Extreme, que é arquitetura Zen 5.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914145339_nSZZBYmfv2J7nDTkzGbRcN.webp" alt="Lenovo Legion Go 2"  loading="lazy" /></p>
<p>Tem o <a href="https://www.msi.com/Handheld/Claw-A8-BZ2EMX"target="_blank" rel="noopener">MSI Claw A8</a> também com Z2 Extreme, tela de 8&quot; 120hz.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914145452_Spesifikasi-MSI-Claw-A8.webp" alt="MSI Claw A8"  loading="lazy" /></p>
<p>Qual o melhor? Não sei. Eu só experimentei o Rog Ally X. Recomendo assistir os reviews do <strong>ETA PRiME</strong>. Ele faz as melhores comparações de performance e benchmarks desses chips.</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/5T6ZvpZNZT4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>A ASUS também firmou parceria com a Microsoft pra lançar o novo <a href="https://www.xbox.com/en-US/handhelds/rog-xbox-ally"target="_blank" rel="noopener"><strong>ROG Xbox Ally</strong></a>, com Z2 Extreme e um OS de Xbox adaptado pra handheld, que tira a principal desvantagem desses handhelds todos: o fato que Windows 11 é um dos piores OS de todos os tempos pra handhelds. Dá pra usar, mas é bem gambiarra. Já com esse OS oficial, é como se tivesse um Xbox Series no bolso de verdade, com capacidade pra rodar jogos de Steam e outra lojas também.</p>
<p>Eu não tenho, mas fiquei com vontade de experimentar.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914145806_new-leak-rog-xbox-ally-and-ally-x-prices-retail-1-860x484.webp" alt="Rog Xbox Ally"  loading="lazy" /></p>
<p>Todos esses são mais potentes que o <strong>SteamDeck</strong>, mas este ainda continua sendo o melhor custo-benefício no segmento e com o melhor ecossistema de mods, acessórios, e tudo mais. E a Valve tem dado bom suporte de atualizações.</p>
<p>Graças a tecnologias como FSR, hoje em dia dá pra fazer upscaling de resolução e frame generation via IA pra ter mais FPS. Então, jogando em medium settings ou low settings, não fica tão ruim. Com chips Z1 Extreme, Z2 Extreme e Ryzen AI Max+, já dá pra subir pra medium ou até high settings e ficar com bom FPS em Full-HD (1080p).</p>
<p>Todos eles tem saída HDMI, então dá pra ligar numa TV ou monitor. Todos eles aceitam controles externos Bluetooth, então dá pra ligar seu controle de Xbox ou 8BitDo da vida. E ele vira tanto um console quanto um handheld.</p>
<p>Mas são caros, faixa que vai de USD 600 a USD 900 dependendo da marca e modelo. São mais caros que um Playstation 5 e quase faixa de um bom notebook mesmo. Dependendo vale mais a pena comprar um notebook com Ryzen AI Max, que vai ter a mesma Radeon integrada e suportar bons jogos.</p>
<h3>Portáteis Originais<span class="hx:absolute hx:-mt-20" id="portáteis-originais"></span>
    <a href="#port%c3%a1teis-originais" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Vamos a outra constatação importante: qual a melhor forma de jogar handhelds antigos com duas telas, como <strong>Nintendo DS</strong> e <strong>Nintendo 3DS</strong>?</p>
<p>Simples: nos handhelds originais.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914152655_20250914_152628.jpg" alt="nintendo"  loading="lazy" /></p>
<p>A forma mais fácil de jogar jogos piratas neles é com os <a href="https://www.r4ds.com/"target="_blank" rel="noopener">cartuchos R4</a>, acho que não é difícil achar eles em Mercado Livre ou AliExpress. Eles aceitam microSD card e você joga suas ROMs nela, coloca no 3DS e já era.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914152920_20250914_152808.jpg" alt="R4"  loading="lazy" /></p>
<p>Nintendo 3DS teve &ldquo;end-of-life&rdquo; recentemente e desde então todos os jogos estão facilmente disponíveis online. Leia o <a href="https://3ds.hacks.guide/pt_BR/"target="_blank" rel="noopener"><strong>Guia de Hacks do 3DS</strong></a> pra saber como desbloquear o seu. Os jogos estão todos no <a href="https://hshop.erista.me/"target="_blank" rel="noopener"><strong>hShop</strong></a> e quando desbloquear seu 3DS vai instalar o App pra abrir esse site e de lá pode baixar direto as ROMS pra memória interna do aparelho também. Existem várias opções.</p>
<p>Também é possível instalar emuladores no 3DS: vai rodar Gameboy, até Genesis e Master System. Não espere rodar um PS1 ou PSP nele, obviamente, é um hardware fraco.</p>
<p>Só tem uma coisa que me desagrada: as telas são velhas e antiquadas. Tem baixa resolução, baixo brilho, baixo contraste. Comparado com a tela do seu smartphone, nem chega aos pés. Mas pra jogar em dual screen, não tem jeito mais fácil.</p>
<p>Sim, vários fabricantes vieram tentando fazer handhelds com duas telas, como o <a href="https://www.ayaneo.com/goods/9059668426997"target="_blank" rel="noopener"><strong>Ayaneo Flip DS</strong></a> mas é extremamente chato de usar ele. Veja este review do Wulff Den:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/j1TXnfT-zIg"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>São extremamente caros (Android ou Windows) e a experiência de software ainda é extremamente ruim. Não compensa pelo que se paga. Melhor ficar com os originais.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914153857_20250914_153604.jpg" alt="gameboy aluminum"  loading="lazy" /></p>
<p>No caso de Gameboy Advance, já existem dezenas de bons handhelds com emuladores, então é melhor ficar com os RG35XX SP que eu já recomendei antes.</p>
<p>Mas, caso queira explorar a comunidade de mods, recomendo muito o site <a href="https://www.boxypixel.com/"target="_blank" rel="noopener"><strong>Boxy Pixels</strong></a> que fazem cases em alumínio e diversos acessórios pra dispositivos antigos, seja Gameboy, DS, até iPods. Veja este video do canal <strong>Macho Nacho</strong> que demonstra como fazer esse mesmo Gameboy Advance SP em alumínio:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/gJJgnZqpjVE"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Foi por causa desse canal que eu comprei o kit e montei o meu. É caro, é um hobby pra entusiastas mesmo. Isso não é pra amadores! Mas se tiver essa vontade, tá aí o site e o canal pra guiar.</p>
<p>Além disso, dá pra jogar ROMs piratas no Advance também. Similar aos cartuchos R4 pra 3DS tem os cartuchos <a href="https://www.ezflash.cn/products/"target="_blank" rel="noopener"><strong>EZ-Flash</strong></a> tanto pra Gameboy DMG/Color quanto Advance. Também são adaptadores de microSD card, onde você joga suas ROMS, pluga no hardware original e ele vai bootar um menu pra escolher as roms.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914154214_20250914_154141.jpg" alt="advance ez-flash"  loading="lazy" /></p>
<p>Eis um exemplo do EZ-Flash no meu Advance SP modificado. A tela está com white balance errado não sei porque, talvez eu tenha cometido algum erro ao montar, mas não parei pra consertar ainda. O importante era só mostrar o menu que aparece no boot pra escolher o jogo.</p>
<p>O cartucho funciona até no Analog Pocket, mas é redundante porque no Pocket posso jogar os ROMs direto nele.</p>
<h3>Os Softwares<span class="hx:absolute hx:-mt-20" id="os-softwares"></span>
    <a href="#os-softwares" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Agora deixa eu resumir o que você precisa saber de emuladores. O primeiro e mais importante de todos é o <a href="https://retroarch.com/"target="_blank" rel="noopener"><strong>RetroArch</strong></a>.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914150325_How_to_use_cheats_on_retroarch.webp" alt="RetroArch"  loading="lazy" /></p>
<p>Ele <strong>não é um emulador</strong>, ele é um <strong>front-end pra emuladores</strong>. É uma forma mais fácil de instalar os diversos emuladores individuais, cheats, save states, configurar controles que funcionam em todos, filtros, e muito mais.</p>
<p>Os emuladores mesmo ele chama de &ldquo;Cores&rdquo; que são &ldquo;wrappers&rdquo;/&ldquo;adaptadores&rdquo; pros emuladores de verdade. Cada sistema tem diversos emuladores feitos por diferentes pessoas ou grupos, que focam em coisas específicas (rodar maior quantidade de jogos, rodar menos jogos mas com precisão, conseguir rodar com menos recursos - bons pra handhelds fracos, etc).</p>
<p>Vamos ver uma lista básica (isso muda o tempo todo):</p>
<h3>Nintendo<span class="hx:absolute hx:-mt-20" id="nintendo"></span>
    <a href="#nintendo" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>NES: <strong>Mesen</strong>, Nestopia UE. <a href="https://www.ouma.jp/ootake/?utm_source=chatgpt.com"target="_blank" rel="noopener">Ouma</a></li>
<li>SNES: <strong>bsnes</strong>, Snes9x. <a href="https://www.ouma.jp/ootake/ootake.html?utm_source=chatgpt.com"target="_blank" rel="noopener">Ouma+1</a></li>
<li>N64: <strong>Mupen64Plus-Next</strong> (+ParaLLEl-RDP/Angrylion), Project64. <a href="https://docs.libretro.com/library/mupen64plus/?utm_source=chatgpt.com"target="_blank" rel="noopener">Libretro Docs+2Libretro+2</a></li>
<li>GameCube/Wii: <strong>Dolphin</strong>. <a href="https://dolphin-emu.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">Dolphin Emulator</a></li>
<li>Wii U: <strong>Cemu</strong>. <a href="https://cemu.info/?utm_source=chatgpt.com"target="_blank" rel="noopener">Cemu</a></li>
<li>Switch: <a href="https://yuzuemulators.com/"target="_blank" rel="noopener"><strong>Yuzu</strong></a>, <a href="https://ryujinx.app/"target="_blank" rel="noopener"><strong>Ryujinx</strong></a></li>
<li>GB/GBC: <strong>SameBoy</strong>, Gambatte. <a href="https://sameboy.github.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">sameboy.github.io</a></li>
<li>GBA: <strong>mGBA</strong>. <a href="https://bsnes.org/about/?utm_source=chatgpt.com"target="_blank" rel="noopener">BSNES</a></li>
<li>NDS: <strong>melonDS</strong>, DeSmuME. <a href="https://github.com/flyinghead/flycast?utm_source=chatgpt.com"target="_blank" rel="noopener">GitHub</a></li>
<li>3DS: <strong>Lime3DS</strong> → now <strong>Azahar (successor fork)</strong>. <a href="https://redream.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">redream.io</a></li>
<li>Virtual Boy: <strong>Mednafen VB (Beetle VB)</strong>. <a href="https://emulicious.net/tag/game-gear/?utm_source=chatgpt.com"target="_blank" rel="noopener">Emulicious</a></li>
</ul>
<h3>Sega<span class="hx:absolute hx:-mt-20" id="sega"></span>
    <a href="#sega" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>SG-1000/Master System/Game Gear: <strong>Emulicious</strong>, Genesis Plus GX.</li>
<li>Mega Drive/Genesis: <strong>BlastEm</strong>, Genesis Plus GX. <a href="https://www.airdroid.com/screen-mirror/sega-saturn-emulator/?utm_source=chatgpt.com"target="_blank" rel="noopener">AirDroid</a></li>
<li>Sega CD: <strong>Genesis Plus GX</strong>. <a href="https://www.airdroid.com/screen-mirror/sega-saturn-emulator/?utm_source=chatgpt.com"target="_blank" rel="noopener">AirDroid</a></li>
<li>32X: <strong>PicoDrive</strong>. <a href="https://emulation.gametechwiki.com/index.php/Recommended_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki</a></li>
<li>Saturn: <strong>Beetle/Mednafen Saturn</strong>, Kronos/Yaba Sanshiro (faster). <a href="https://github.com/libretro/neocd_libretro?utm_source=chatgpt.com"target="_blank" rel="noopener">GitHub</a></li>
<li>Dreamcast/Naomi: <strong>Flycast</strong>, Redream. <a href="https://www.mamedev.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">mamedev.org+1</a></li>
</ul>
<h3>Sony<span class="hx:absolute hx:-mt-20" id="sony"></span>
    <a href="#sony" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>PlayStation (PS1): <strong>DuckStation</strong> (accuracy/perf), Beetle PSX HW/SW. <a href="https://emulicious.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">Emulicious</a></li>
<li>PlayStation 2: <strong>PCSX2</strong>. <a href="https://pcsx2.net/docs/setup/linux/?utm_source=chatgpt.com"target="_blank" rel="noopener">pcsx2.net</a></li>
<li>PlayStation 3: <strong>RPCS3</strong>. <a href="https://rpcs3.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">RPCS3+1</a></li>
<li>PSP: <strong>PPSSPP</strong>. <a href="https://rpcs3.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">RPCS3</a></li>
<li>PS Vita: <strong>Vita3K</strong>. <a href="https://github.com/LIJI32/SameBoy?utm_source=chatgpt.com"target="_blank" rel="noopener">GitHub</a></li>
<li>PS4: <strong>shadPS4</strong> (rapid progress; still early). <a href="https://shadps4.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">ShadPS4+2ShadPS4+2</a></li>
</ul>
<h3>Microsoft<span class="hx:absolute hx:-mt-20" id="microsoft"></span>
    <a href="#microsoft" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Xbox (OG): <strong>xemu</strong>, Cxbx-Reloaded. <a href="https://sameboy.github.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">sameboy.github.io+1</a></li>
<li>Xbox 360: <strong>Xenia</strong>. <a href="https://emulation.gametechwiki.com/index.php/Recommended_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki</a></li>
</ul>
<h3>NEC / Hudson<span class="hx:absolute hx:-mt-20" id="nec--hudson"></span>
    <a href="#nec--hudson" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>PC Engine/TurboGrafx-16(+CD): <strong>Mednafen (Beetle PCE Fast)</strong>, Ootake (Windows). <a href="https://emulation.gametechwiki.com/index.php/Neo_Geo_Pocket_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki+1</a></li>
<li>PC-FX: <strong>Mednafen (Beetle PC-FX)</strong>. <a href="https://emulicious.net/tag/game-gear/?utm_source=chatgpt.com"target="_blank" rel="noopener">Emulicious</a></li>
</ul>
<h3>SNK / Arcade &amp; Handhelds<span class="hx:absolute hx:-mt-20" id="snk--arcade--handhelds"></span>
    <a href="#snk--arcade--handhelds" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Neo Geo AES/MVS (arcade): <strong>FBNeo</strong>, MAME. <a href="https://www.ppsspp.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">ppsspp.org+1</a></li>
<li>Neo Geo CD: <strong>NeoCD (libretro)</strong>, MAME. <a href="https://melonds.kuribo64.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">melonds.kuribo64.net+1</a></li>
<li>Neo Geo Pocket/Color: <strong>Mednafen (Beetle NeoPop)</strong>, RACE. <a href="https://github.com/LIJI32/SameBoy?utm_source=chatgpt.com"target="_blank" rel="noopener">GitHub</a></li>
</ul>
<h3>Bandai / Others (handheld)<span class="hx:absolute hx:-mt-20" id="bandai--others-handheld"></span>
    <a href="#bandai--others-handheld" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>WonderSwan/Color: <strong>Mednafen (Beetle WSWAN)</strong>. [sameboy.github.io](<a href="https://sameboy.github.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">https://sameboy.github.io/?utm_source=chatgpt.com</a></li>
<li>Atari Lynx: <strong>Mednafen (Beetle Handy)</strong>. <a href="https://emulicious.net/tag/game-gear/?utm_source=chatgpt.com"target="_blank" rel="noopener">Emulicious</a></li>
</ul>
<h3>Atari (consoles)<span class="hx:absolute hx:-mt-20" id="atari-consoles"></span>
    <a href="#atari-consoles" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>2600: <strong>Stella</strong>. <a href="https://emulation.gametechwiki.com/index.php/Recommended_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki</a></li>
<li>5200/8-bit: <strong>Altirra</strong> / Atari800. <a href="https://emulation.gametechwiki.com/index.php/Recommended_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki</a></li>
<li>7800: <strong>A7800</strong> (or MAME). <a href="https://emulation.gametechwiki.com/index.php/Recommended_emulators?utm_source=chatgpt.com"target="_blank" rel="noopener">GameTechWiki</a></li>
<li>Jaguar: <strong>BigPEmu</strong>. <a href="https://mednafen.github.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">mednafen.github.io</a></li>
</ul>
<h3>3DO / CD-i / Misc. classic<span class="hx:absolute hx:-mt-20" id="3do--cd-i--misc-classic"></span>
    <a href="#3do--cd-i--misc-classic" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>3DO: <strong>Opera (libretro)</strong>. <a href="https://docs.libretro.com/library/opera/?utm_source=chatgpt.com"target="_blank" rel="noopener">Libretro Docs</a></li>
<li>Philips CD-i: <strong>MAME</strong> (best public option). <a href="https://vita3k.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">Vita3K</a></li>
<li>Vectrex: <strong>ParaJVE</strong>. <a href="https://vectrex-emu.blogspot.com/?utm_source=chatgpt.com"target="_blank" rel="noopener">vectrex-emu.blogspot.com</a></li>
<li>Intellivision: <strong>jzIntv</strong>. <a href="https://intellivision.us/intvgames/jzintv/jzintv.php?utm_source=chatgpt.com"target="_blank" rel="noopener">intellivision.us</a></li>
<li>ColecoVision: <strong>blueMSX (core)</strong> / MAME. <a href="https://docs.libretro.com/library/bluemsx/?utm_source=chatgpt.com"target="_blank" rel="noopener">Libretro Docs</a></li>
<li>Magnavox Odyssey²/Videopac+: <strong>O2EM</strong>. <a href="https://o2em.sourceforge.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">o2em.sourceforge.net</a></li>
<li>Fairchild Channel F, Bally Astrocade: <strong>MAME</strong>. <a href="https://vita3k.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">Vita3K</a></li>
</ul>
<h3>Arcade (general)<span class="hx:absolute hx:-mt-20" id="arcade-general"></span>
    <a href="#arcade-general" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li><strong>MAME</strong> (breadth/accuracy), <strong>FinalBurn Neo</strong> (speed/curation). <a href="https://vita3k.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">Vita3K+1</a></li>
</ul>
<h3>Home computers (popular)<span class="hx:absolute hx:-mt-20" id="home-computers-popular"></span>
    <a href="#home-computers-popular" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><ul>
<li>Commodore 64/128/VIC-20/PET: <strong>VICE</strong>. <a href="https://vice-emu.sourceforge.io/?utm_source=chatgpt.com"target="_blank" rel="noopener">vice-emu.sourceforge.io</a></li>
<li>Amiga: <strong>WinUAE</strong> (Windows), <strong>FS-UAE</strong> (cross-platform). [winuae.net+1](<a href="https://www.winuae.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">https://www.winuae.net/?utm_source=chatgpt.com</a></li>
<li>Atari ST/STE/TT/Falcon: <strong>Hatari</strong>, Steem SSE. <a href="https://www.hatari-emu.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">hatari-emu.org+1</a></li>
<li>ZX Spectrum: <strong>FUSE</strong>, Retro Virtual Machine. <a href="https://fuse-emulator.sourceforge.net/?utm_source=chatgpt.com"target="_blank" rel="noopener">fuse-emulator.sourceforge.net+1</a></li>
<li>MSX: <strong>openMSX</strong>, blueMSX (stale but usable; libretro core still common). <a href="https://openmsx.org/?utm_source=chatgpt.com"target="_blank" rel="noopener">openmsx.org+2msx.org+2</a></li>
<li>PC-98: <strong>Neko Project II kai (NP2kai)</strong> (or DOSBox-X for DOS/V/PC-98 modes). <a href="https://docs.libretro.com/library/neko_project_ii_kai/?utm_source=chatgpt.com"target="_blank" rel="noopener">Libretro Docs+1</a></li>
<li>DOS / Win9x era: <strong>DOSBox Staging</strong> (games), <strong>DOSBox-X</strong> (games + Win3.x/9x).</li>
</ul>
<p>Alguns emuladores são chatinhos, porque estão incompletos ou em desenvolvimento ou bugados ou sem suporte mais. Alguns exemplos:</p>
<ul>
<li>Xemu pra Xbox original funciona bem, mas é bem mal otimizado, portanto é bem pesado. Não vai rodar em nada que não seja pelo menos um handheld PC moderno como o Rog Ally ou um PC de verdade.</li>
<li>Xenia Canary pra Xbox 360 ainda é bem bugado, só funciona em linha de comando (tem uma GUI de terceiros mais ou menos), tem que configurar arquivos pra tunar cada jogo. Meus jogos favoritos como Forza Motorsport 4 rodam com vários bugs visuais e crashes aleatórios que inviabiliza jogar (por isso comprei um Xbox 360 de verdade e desbloqueei).</li>
<li>RPCS3 avançou bastante, mas não chega aos pés do PCSX2 ainda. Muitos jogos exigem configurações especiais - que não são intuitivos pra um amador, tem que ler o Wiki com muito cuidado, pra cada jogo. Jogos favoritos meus como Gran Turismo 6 ainda não rodam direito.</li>
<li>shadPS4, esquece por enquanto, ele começou desenvolvimento recentemente, ainda é mais alpha que beta, quase nada roda nele sem muito trabalho. Não é pra amadores.</li>
<li>Dolphin, até que é bem estável e quase plug and play, mas é mais pesado que um PCSX2. Não vai rodar em hardwares fracos.</li>
<li>Mupen64 roda bem também, até em Android, mas nem todo jogo ainda roda nele e alguns rodam com pequenos glitches. No geral dá pra jogar, mas não espere perfeição.</li>
<li>Emuladores de 8-bits, 16-bits, estão bem completos, estáveis, rodam liso qualquer um deles, pode confiar, incluindo arcades via Mame ou FBNEO. Mas no caso desses últimos, eles exisgem <strong>romsets</strong> (conjuntos de ROMS compatíveis com o emulador), não dá pra pegar qualquer ROM aleatória por aí e esperar que vai rodar. Fuce o <a href="https://archive.org/details/Neo-geoRomCollectionByGhostware"target="_blank" rel="noopener">Internet Archive</a> pra achar alguns desses romsets.</li>
<li>Home Computers como openMSX ou DOSBox, lembre que muitos jogos só funcionam com teclado ou mouse ou os dois e talvez não funcione muito bem mesmo mapeando pra controle. Tem que ler o Wiki de cada jogo pra saber.</li>
<li>Por causa dos processos da Nintendo, emuladores de Switch aparecem e somem, alguém faz um novo fork e reaparece. Yuzu já foi fechado mas forks apareceram. Surgiu Suyu, mas fechou. Ryujinx continua funcionando e é o meu favorito. Android acho que tem Sudachi e outros. Tem que dar uma pesquisada.</li>
</ul>
<p>RetroArch tem suporte pra quase todos esses emuladores. Portanto só instalando ele, já vai te dar acesso à maioria. Alguns é melhor instalar separado como apps individuais, em particular isso é verdade em Android, por isso falo tanto do guia do Russ e como Android é mais chato.</p>
<p>Em Linux, distros como OnionOS, GammaOS, Surwish, Knulli, MinUI, já vem com RetroArch instado e pré-configurado, por isso são mais fáceis de instalar e usar.</p>
<p>Dá pra usar só o RetroArch, seja em handheld, seja em Android, seja no Windows. Mas a interface dele é bem feia, velha, chata de navegar. Talvez você não se importe, mas depois que tem a experiência de console, como Playstation, Xbox, é chato usar uma interface velha. Pra consertar isso existem diversos front-ends pra colocar por cima do RetroArch, o mais famoso e popular de todos acho que é o <a href="https://emulationstation.org/"target="_blank" rel="noopener"><strong>EmulationStation</strong></a></p>
<p>Ele é bonito, dá pra escolher vários temas e fica assim:</p>
<p><img src="https://emulationstation.org/assets/featurettes/theming_list.jpg" alt="ES"  loading="lazy" /></p>
<p>Novamente, o Russ do canal Retro Game Corps tem guias pra isso:</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=X-bVwlMwobE"target="_blank" rel="noopener">Emulation Station em Android</a></li>
<li><a href="https://www.youtube.com/watch?v=5upaSxC1wTg"target="_blank" rel="noopener">Emulation Station no SteamDeck</a></li>
<li><a href="https://www.youtube.com/watch?v=05dunYi6hkY"target="_blank" rel="noopener">Emulation Station no Windows</a></li>
</ul>
<p>Tem mais videos, só pesquisar por &ldquo;emulation station&rdquo; direto no canal dele e também no blog dele. Tem dezenas de guias por aí, por isso não vou perder tempo detalhando ele. Pára de ter preguiça e pesquisa. O que não falta é material.</p>
<p>No mundo de handhelds Linux, também existe Emulation Station em distros como <a href="https://knulli.org/pt-BR/"target="_blank" rel="noopener"><strong>Knulli</strong></a>, que é um fork do antigo Batocera. E adivinhe: tem guia do Russ:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/2ZMwdyuAv7o"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<p>Já entendeu a única coisa que você precisa tirar deste artigo né: se tiver alguma dúvida sobre esse assunto, pergunte ao Russ, não a mim!</p>
<p>No mundo de SteamDeck e outros handhelds PC, existe outra distro Linux, o <a href="https://bazzite.gg/"target="_blank" rel="noopener"><strong>Bazzite</strong></a> que é um fork modificado do SteamOS pra rodar fora do SteamDeck.</p>
<p><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/20250914152336_asus-rog-ally-bazzite-feature-image.webp" alt="Ally Bazzite"  loading="lazy" /></p>
<p>Assim seu Rog Ally vai funcionar igual um SteamDeck mais potente! Rodando jogos de Steam em Linux via Proton. Eu pessoalmente não fui por essa opção porque já me acostumei com a chatice do Windows 11 e eu gosto de rodar <a href="https://www.wemod.com/"target="_blank" rel="noopener"><strong>WeMod</strong></a> pra rodar jogos com cheats. Além disso eu instalei outros emuladores que só funcionam em Windows, com os de <a href="https://segaretro.org/Model_2_Emulator"target="_blank" rel="noopener">Sega Model 2</a> e <a href="https://github.com/trzy/Supermodel"target="_blank" rel="noopener">Model 3</a>. Sim, tem como rodar em Linux com Wine e tudo mais, mas já tá funcionando, deixa assim. Faz no seu.</p>
<p>Pra Emulation Station e outros front-end como <a href="https://github.com/TapiocaFox/Daijishou"target="_blank" rel="noopener"><strong>Daijisho</strong></a> no Android vão pedir pra você ter uma conta no site <a href="https://www.screenscraper.fr/"target="_blank" rel="noopener">ScreenScrapper</a>. Com essa conta dá pra ler as ROMs no seu microSD card e ir no site buscar coisas como imagem da caixa, video de demonstração e tudo mais pra ficar tudo mais bonito.</p>
<p>Última coisa: se eu tenho tantos handhelds, como faço pra compartilhar os saves entre todos eles pra continuar jogando de outro handheld?</p>
<p>Tem dois jeitos: o mais fácil é só tirar o microSD de um e colocar no outro e vai ter os mesmos saves. A outra forma - bem mais complicada (que é o que eu faço) - é subir um container de <a href="https://github.com/syncthing/syncthing"target="_blank" rel="noopener"><strong>SyncThing</strong></a>, que é um serviço que syncroniza diretórios entre diferentes computadores (pense um mini-Dropbox). Pra variar, o Russ tem um tutorial:</p>


<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/NPx8FREezR4"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>Conclusão<span class="hx:absolute hx:-mt-20" id="conclusão"></span>
    <a href="#conclus%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Entendeu a mensagem do post? Não pergunte <em>&ldquo;Akita, qual retro-handheld é melhor pra eu comprar?&rdquo;</em> O coitado do Akita não é tech-reviewer pago, patrocinado, nem monetizado, portanto todos os handhelds que eu tenho, comprei só pra mim. Por isso não tenho nenhum Retroid. Não adianta perguntar se Ambernic ou Ayaneo são melhores que Retroid. Akita não vai saber.</p>
<p>Em vez disso perguntem a tech reviewers que são pagos a patrocinados pra falar disso. Eis minhas recomendações:</p>
<ul>
<li><a href="https://www.youtube.com/@RetroGameCorps"target="_blank" rel="noopener">Retro Game Corps</a></li>
<li><a href="https://www.youtube.com/@WulffDen"target="_blank" rel="noopener">Wulff Den</a></li>
<li><a href="https://www.youtube.com/@TechDweeb"target="_blank" rel="noopener">Tech Dweeb</a></li>
<li><a href="https://www.youtube.com/@TakiUdon"target="_blank" rel="noopener">Taki Udon</a></li>
<li><a href="https://www.youtube.com/@ETAPRIME"target="_blank" rel="noopener">ETA PRIME</a></li>
</ul>
<p>Pra quem se interessa por mods:</p>
<ul>
<li><a href="https://www.youtube.com/@MachoNachoProductions"target="_blank" rel="noopener">Macho Nacho Productions</a></li>
<li><a href="https://www.youtube.com/@TheRetroFuture"target="_blank" rel="noopener">The Retro Future</a></li>
</ul>
<p>E pra quem se interessa por consertos:</p>
<ul>
<li><a href="https://www.youtube.com/@Tronicsfix"target="_blank" rel="noopener">TronicsFix</a></li>
</ul>
<p>Todos eles vão dar respostas melhores sobre todas as suas perguntas sobre todos os modelos de handhelds, consoles, consertos, modificações, softwares, OS, customizações, ROMs e muito mais.</p>
<p>Eu fiz esta página só pra poder dar copy e paste do link pra todo mundo que repetir essas mesmas perguntas daqui pra frente. Acho que cobri tudo que eu sei do assunto!</p>
]]></content:encoded><category>games</category><category>emulacao</category><category>retrocomputacao</category><category>off-topic</category></item><item><title>História da Computação e Retro Dev no YouTube</title><link>https://akitaonrails.github.io/2025/05/19/historia-da-computacao-e-retro-dev-no-youtube/</link><guid isPermaLink="true">https://akitaonrails.github.io/2025/05/19/historia-da-computacao-e-retro-dev-no-youtube/</guid><pubDate>Mon, 19 May 2025 15:19:00 -0300</pubDate><description>&lt;p&gt;Eu assisto MUITO YouTube, e fico sempre compartilhando coisas legais que assisto no meu X e Instagram (me sigam lá). Tem vários videos que vira e mexe eu volto atrás.&lt;/p&gt;
&lt;p&gt;Finalmente resolvi compilar uma lista com os canais que eu mais assisto e uma lista das principais playlists e exemplos de videos de cada canal que recomendo assistir.&lt;/p&gt;
&lt;p&gt;Provavelmente vou ficar voltando nesta página pra atualizar de tempos em tempos. Se alguém se lembrar de algum que eu esqueci, mandem nos comentários. Tem canais como GameSack ou Sega Lord X ou Retro Game Corp ou Wullfden ou Macho Nacho Productions e vários outros assim que não listei, porque são mais de &amp;ldquo;reviews&amp;rdquo; e não cruzam tanto com &amp;ldquo;dev&amp;rdquo;. Tentei focar em coisas que eu acho que um &amp;ldquo;dev&amp;rdquo; deveria saber.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Eu assisto MUITO YouTube, e fico sempre compartilhando coisas legais que assisto no meu X e Instagram (me sigam lá). Tem vários videos que vira e mexe eu volto atrás.</p>
<p>Finalmente resolvi compilar uma lista com os canais que eu mais assisto e uma lista das principais playlists e exemplos de videos de cada canal que recomendo assistir.</p>
<p>Provavelmente vou ficar voltando nesta página pra atualizar de tempos em tempos. Se alguém se lembrar de algum que eu esqueci, mandem nos comentários. Tem canais como GameSack ou Sega Lord X ou Retro Game Corp ou Wullfden ou Macho Nacho Productions e vários outros assim que não listei, porque são mais de &ldquo;reviews&rdquo; e não cruzam tanto com &ldquo;dev&rdquo;. Tentei focar em coisas que eu acho que um &ldquo;dev&rdquo; deveria saber.</p>
<h2>Lista (2025-05-19)<span class="hx:absolute hx:-mt-20" id="lista-2025-05-19"></span>
    <a href="#lista-2025-05-19" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><ul>
<li><a href="https://www.youtube.com/@UsagiElectric"target="_blank" rel="noopener">Usagi Electric</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=-RGp-bsYf34&amp;list=PLnw98JPyObn3QSIwUz5Iv6NA1x-uGFqAa&amp;pp=0gcJCV8EOCosWNin"target="_blank" rel="noopener">Bendix G15 Vacuum Tube</a></li>
<li><a href="https://www.youtube.com/watch?v=EbWcgepRmY4&amp;list=PLnw98JPyObn2PqgY1mfzXOtnUXlsXSMch"target="_blank" rel="noopener">Data General Nova</a></li>
<li><a href="https://www.youtube.com/watch?v=SB95dlrS5kU&amp;list=PLnw98JPyObn2Kj-rqrKqEB5xmS_uOV40f"target="_blank" rel="noopener">DEC/PDP-11</a></li>
<li><a href="https://www.youtube.com/watch?v=oPA8dHtf_6M&amp;list=PLnw98JPyObn1GUapiXLlGm8RrpQF-J_c1"target="_blank" rel="noopener">1-Bit Computer</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@TechTangents"target="_blank" rel="noopener">Tech Tangents</a>:
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=mBssIIRGkOw&amp;list=PLJVwF78cppBgwAHYKMffuhs0jblPHCyvL"target="_blank" rel="noopener">Data Generals</a></li>
</ul>
</li>
<li>Videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=apFLq3-fpL4"target="_blank" rel="noopener">Tandy 1000 RL HD</a></li>
<li><a href="https://www.youtube.com/watch?v=Oa6QPHD6qzw&amp;t=278s"target="_blank" rel="noopener">CP/M on Model 100</a></li>
<li><a href="https://www.youtube.com/watch?v=dqPSVG7zbs4"target="_blank" rel="noopener">KayPro IV</a></li>
<li><a href="https://www.youtube.com/watch?v=vCU4xbHFb58"target="_blank" rel="noopener">HP Series 200 - CAD Monster</a></li>
<li><a href="https://www.youtube.com/watch?v=5WB9d1JM8oo"target="_blank" rel="noopener">8088 PC Networking</a></li>
<li><a href="https://www.youtube.com/watch?v=EOVLlMQs9f8"target="_blank" rel="noopener">FreeDOS on IBM 5150</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@The8BitGuy"target="_blank" rel="noopener">The 8-Bit Guy</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=ayh0qebfD2g&amp;list=PLfABUWdDse7bKGFshxR0itdHBhjUj86SX"target="_blank" rel="noopener">Commander X16</a></li>
<li><a href="https://www.youtube.com/watch?v=NB_VBl7ut9Y&amp;list=PLfABUWdDse7Z8wmD0bbL0P5upEE1VjMJM"target="_blank" rel="noopener">Game Development - Making of Planet X2</a></li>
<li><a href="https://www.youtube.com/watch?v=mXSdikcUuo0&amp;list=PLfABUWdDse7aKLE00YObaVvP1jSH0YqIE"target="_blank" rel="noopener">Texas Tech History</a></li>
<li><a href="https://www.youtube.com/watch?v=eP9y_7it3ZM&amp;list=PLfABUWdDse7Y6LLPlfsHKcvBCgqaudzVY"target="_blank" rel="noopener">Commodore History</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@adriansdigitalbasement"target="_blank" rel="noopener">Adrien&rsquo;s Digital Basement</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=x8DfSg7oMWg&amp;list=PL4tFqFVNf5LSckPX988MBvVzKv96eP0es"target="_blank" rel="noopener">TRS-80 Model II Repair Series</a></li>
<li><a href="https://www.youtube.com/watch?v=gkCDdSdSNu0&amp;list=PL4tFqFVNf5LRvKP94x7VOfdXXQHRt_8BR"target="_blank" rel="noopener">Amiga 4000 Repair Series</a></li>
<li><a href="https://www.youtube.com/watch?v=RMG_StQ67kA&amp;list=PL4tFqFVNf5LQeof2oTPFGxZx0SpvICpSv"target="_blank" rel="noopener">ZX Spectrum</a></li>
<li><a href="https://www.youtube.com/watch?v=_CNruhSYC2E&amp;list=PL4tFqFVNf5LRf-gcl5Lyhl2UxbmrGmZCT"target="_blank" rel="noopener">IBM 16-bit machines</a></li>
<li><a href="https://www.youtube.com/watch?v=5qMP6A_U75E&amp;list=PL4tFqFVNf5LT6X3sMRfbRWuTVE5NuEmKj&amp;pp=0gcJCV8EOCosWNin"target="_blank" rel="noopener">Apple Computers - 8-bit</a></li>
<li><a href="https://www.youtube.com/watch?v=H9dxJ7uNXOA&amp;list=PL4tFqFVNf5LRxSdlzuH2MWOZ_5PltbpLv"target="_blank" rel="noopener">Macintosh Machines - 68000</a></li>
<li><a href="https://www.youtube.com/watch?v=0MP93YbINyI&amp;list=PL4tFqFVNf5LRZKtduWSpZjZpJS6mxZx7I"target="_blank" rel="noopener">Commodore - 8 bit</a></li>
<li><a href="https://www.youtube.com/watch?v=0MP93YbINyI&amp;list=PL4tFqFVNf5LR9SvTg1P8r3EPL657qJFsx"target="_blank" rel="noopener">Commodore 64 Repairs</a></li>
<li><a href="https://www.youtube.com/watch?v=QJRXMYmie7I&amp;list=PL4tFqFVNf5LTPlF7iF_pMl5WiiOsSFMf4"target="_blank" rel="noopener">Tandy 1000 Series</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@clabretro"target="_blank" rel="noopener">clabretro</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=77rVvJBLRhQ&amp;list=PLjeznAUfx0Odrk8qOQJ-_a3xry4PhIxOh"target="_blank" rel="noopener">Home Lab</a></li>
<li><a href="https://www.youtube.com/watch?v=pXuqASXGvgM&amp;list=PLjeznAUfx0OfCseO3gKOvEjw3oHgHLRlK"target="_blank" rel="noopener">Sun Microsystem Stuff</a></li>
</ul>
</li>
<li>Videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=PBvDRJ_rU5w"target="_blank" rel="noopener">Ressurrecting an IBM PS/2 Model 50Z</a></li>
<li><a href="https://www.youtube.com/watch?v=7-ISDVFIVgw"target="_blank" rel="noopener">Windows NT 4.0 on a Compaq Proliant Gen 1</a></li>
<li><a href="https://www.youtube.com/watch?v=4UWibKEjyY8&amp;t=10s"target="_blank" rel="noopener">Token Ring Networking</a></li>
<li><a href="https://www.youtube.com/watch?v=LvLPz72IvAM"target="_blank" rel="noopener">Early 2000s Linksys Wi-Fi Gear</a></li>
<li><a href="https://www.youtube.com/watch?v=gyyhqHBmKg4"target="_blank" rel="noopener">Compaq Proliant Gen 1</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@LowSpecGamer"target="_blank" rel="noopener">LowSpecGamer</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=lP2ZBp9O0mk&amp;list=PLp-6MMWURCz3x92-dpEsRLEGL3uHToVDR"target="_blank" rel="noopener">All Lore - Chronological</a></li>
<li><a href="https://www.youtube.com/watch?v=lP2ZBp9O0mk&amp;list=PLp-6MMWURCz1bo3T4vmyNUVl3FefnF7CC"target="_blank" rel="noopener">Chip Wars</a><a href="https://www.youtube.com/watch?v=OBlu2mdpiJ0&amp;list=PLp-6MMWURCz0OdcgoSiQOv8C9hn79XdOt"target="_blank" rel="noopener">Nintendo Lore</a></li>
<li><a href="https://www.youtube.com/watch?v=9Ki-kH751_8&amp;list=PLp-6MMWURCz0OB_iioCUqc2Sq21UXE-08"target="_blank" rel="noopener">The Yokoi Saga</a></li>
</ul>
</li>
<li>Videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=nIwdhPOVOUk"target="_blank" rel="noopener">How Amateurs created the world&rsquo;s most popular processor - History of ARM Part 1</a></li>
<li><a href="https://www.youtube.com/watch?v=vx1-6yRAGk0"target="_blank" rel="noopener">ARM&rsquo;s Secret Weapon - History of ARM Part 2</a></li>
<li><a href="https://www.youtube.com/watch?v=PLzTVnQ3gqc"target="_blank" rel="noopener">How IBM Invented the PC, then everyone stole it</a></li>
<li><a href="https://www.youtube.com/watch?v=ztYfJDTjpjk&amp;pp=0gcJCY0JAYcqIYzv"target="_blank" rel="noopener">The Great Calculator Wars of the 70s</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@BenEater"target="_blank" rel="noopener">Ben Eater</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=LnzuMJLZRdU&amp;list=PLowKtXNTBypFbtuVMUVXNR0z1mu7dp7eH"target="_blank" rel="noopener">Build a 65c02-based computer from scratch</a></li>
<li><a href="https://www.youtube.com/watch?v=HyznrdDSSGM&amp;list=PLowKtXNTBypGqImE405J2565dvjafglHU&amp;pp=0gcJCV8EOCosWNin"target="_blank" rel="noopener">Building an 8-bit breadboard computer</a></li>
<li><a href="https://www.youtube.com/watch?v=XaGXPObx2Gs&amp;list=PLowKtXNTBypH19whXTVoG3oKSuOcw_XeW"target="_blank" rel="noopener">Networking Tutorial</a></li>
<li><a href="https://www.youtube.com/watch?v=eq5YpKHXJDM&amp;list=PLowKtXNTBypFWff2QjXCWuSfJDWcvE0Vm"target="_blank" rel="noopener">Error detection</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@javidx9"target="_blank" rel="noopener">javidx9</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=nViZg02IMQo&amp;list=PLrOv9FMX8xJHqMvSGB_9G9nZZ_4IgteYf"target="_blank" rel="noopener">NES Emulator from Scratch</a></li>
<li><a href="https://www.youtube.com/watch?v=8OK8_tHeCIA&amp;list=PLrOv9FMX8xJE8NgepZR1etrsU63fDDGxO"target="_blank" rel="noopener">Code-it-Yourself - TETRIS from scratch</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@GamingHistorian"target="_blank" rel="noopener">Gaming Historian</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=G_6PO3N8fig&amp;list=PLScCWE7AP_PUIOOSwRF_e5jR6e2rLwLoF"target="_blank" rel="noopener">Video Game Hardware</a></li>
<li><a href="https://www.youtube.com/watch?v=2EUYSN5aFcE&amp;list=PLScCWE7AP_PVMZgv83NLwp6wQ93I6o4rr"target="_blank" rel="noopener">The Story of Super Mario - Documentary Series</a></li>
<li><a href="https://www.youtube.com/watch?v=S1qD9JRk5vM&amp;list=PLScCWE7AP_PU4_4b4juK8ZugrmptW4g1v&amp;pp=0gcJCV8EOCosWNin"target="_blank" rel="noopener">History of Wolfenstein</a></li>
<li><a href="https://www.youtube.com/watch?v=M55Bpm38qqE&amp;list=PLScCWE7AP_PVO9xcAsZa7Dv5sgdZMyUbb"target="_blank" rel="noopener">History of Sonic the Hedgehog</a></li>
<li><a href="https://www.youtube.com/watch?v=myhBphil-Uw&amp;list=PLScCWE7AP_PVVYlegzt3REr2n5bBmmQJ2"target="_blank" rel="noopener">History of Super Smash Bros</a></li>
<li><a href="https://www.youtube.com/watch?v=BjRuV52Jk78&amp;list=PLScCWE7AP_PXfCIUjxMjoWPUbNYXz8P6w"target="_blank" rel="noopener">Games</a></li>
<li><a href="https://www.youtube.com/watch?v=8QbjlHeoLdc&amp;list=PL397C52406E483BAB&amp;pp=0gcJCV8EOCosWNin"target="_blank" rel="noopener">Gaming Historian</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@ModernVintageGamer"target="_blank" rel="noopener">Modern Vintage Gamer</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=SZbC0Hh4lc8&amp;list=PLUbw0IXAmW2rMk5g19MrqcyebecSrrSeJ"target="_blank" rel="noopener">Mistakes Were Made - Game Console Security</a></li>
<li><a href="https://www.youtube.com/watch?v=siOXFGZj_z0&amp;list=PLUbw0IXAmW2p35mZ_Fis31n2L6HPiFoEs"target="_blank" rel="noopener">The Sony Playstation</a></li>
<li><a href="https://www.youtube.com/watch?v=esl6ctg_9JA&amp;list=PLUbw0IXAmW2qJ8e0XtQgQo8ki0mIeIbHP"target="_blank" rel="noopener">The Original XBox</a></li>
<li><a href="https://www.youtube.com/watch?v=F4Dv32-PoU4&amp;list=PLUbw0IXAmW2pDWN4kZ-vNDNAPycFVR_ux"target="_blank" rel="noopener">Doom Switch Port</a></li>
<li><a href="https://www.youtube.com/watch?v=ZOzWS7MQ_qs&amp;list=PLUbw0IXAmW2ofK7Es3w7q5kVMdzK_IfKY"target="_blank" rel="noopener">Retro Reviews</a></li>
</ul>
</li>
<li>Videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=lpOEhtoc3DY"target="_blank" rel="noopener">N64: Decomp vs Recomp vs Ports explained</a></li>
<li><a href="https://www.youtube.com/watch?v=hqpw-QPsdCg"target="_blank" rel="noopener">XenonRecomp</a></li>
<li><a href="https://www.youtube.com/watch?v=nJ9zJ_PDatU"target="_blank" rel="noopener">Game Genie Explained</a></li>
<li><a href="https://www.youtube.com/watch?v=_RVQsqC3A6g"target="_blank" rel="noopener">Super NES Graphics</a></li>
<li><a href="https://www.youtube.com/watch?v=OmKjVpVdHDQ"target="_blank" rel="noopener">N64 Emulation is a Mess</a></li>
<li><a href="https://www.youtube.com/watch?v=8ibEDSfthS0"target="_blank" rel="noopener">The First Amiga Virus</a></li>
<li><a href="https://www.youtube.com/watch?v=ZeaZWBrG__s"target="_blank" rel="noopener">35 Years of Game Boy</a></li>
<li><a href="https://www.youtube.com/watch?v=ockNRSt3Nsk"target="_blank" rel="noopener">Video game piracy in the 80s</a></li>
<li><a href="https://www.youtube.com/watch?v=JqP3ZzWiul0"target="_blank" rel="noopener">Doom SNES Sourcecode</a></li>
<li><a href="https://www.youtube.com/watch?v=zQE1K074v3s"target="_blank" rel="noopener">How Graphics worked on the Game Boy</a></li>
<li><a href="https://www.youtube.com/watch?v=2NF5sU_n0uk"target="_blank" rel="noopener">How UltraHLE changed N64 emulation forever</a></li>
<li><a href="https://www.youtube.com/watch?v=5tADL_fmsHQ"target="_blank" rel="noopener">How Diablo was completely Reverse Engineered without source code</a></li>
<li><a href="https://www.youtube.com/watch?v=Ap3gJT_TMOc&amp;pp=0gcJCY0JAYcqIYzv"target="_blank" rel="noopener">Duke3D on the Amiga 600</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@strafefox"target="_blank" rel="noopener">Strafefox</a>
<ul>
<li>Videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=6u37r-Z_Nfo"target="_blank" rel="noopener">Video Game Development Through the 80s</a></li>
<li><a href="https://www.youtube.com/watch?v=5jxYvLYcpZg&amp;t=1441s"target="_blank" rel="noopener">The 3D Revolution in 90s game development</a></li>
<li><a href="https://www.youtube.com/watch?v=69AOVtOUatY"target="_blank" rel="noopener">The Making of Sonic the Hedgehog</a></li>
<li><a href="https://www.youtube.com/watch?v=226Nwq2CN5c"target="_blank" rel="noopener">The Making of Mortal Kombat</a></li>
<li><a href="https://www.youtube.com/watch?v=TYE9GMfr5ug"target="_blank" rel="noopener">The Making of Castlevania Symphony of the Night</a></li>
<li><a href="https://www.youtube.com/watch?v=_LPu7gNzWUE"target="_blank" rel="noopener">The Making of Donkey Kong Country &amp; Killer Instinct</a></li>
<li><a href="https://www.youtube.com/watch?v=kOnUITJqRQQ"target="_blank" rel="noopener">The Making of Aladdin</a></li>
<li><a href="https://www.youtube.com/watch?v=5Z7liHTgnw4"target="_blank" rel="noopener">The Making of Streets of Rage</a></li>
<li><a href="https://www.youtube.com/watch?v=USC6c9Dtak8"target="_blank" rel="noopener">The Making of Street Fighter II</a></li>
<li><a href="https://www.youtube.com/watch?v=KL4l0nMsrMM"target="_blank" rel="noopener">The Making of Super Mario World</a></li>
<li><a href="https://www.youtube.com/watch?v=GDhNT2Qv-Mo"target="_blank" rel="noopener">The Making of Star Fox</a></li>
<li><a href="https://www.youtube.com/watch?v=MJG-OT6S194"target="_blank" rel="noopener">How Video Games were Made - Part 3</a></li>
<li><a href="https://www.youtube.com/watch?v=Yo7UkkGC1AY"target="_blank" rel="noopener">How Video Games were Made - Part 2</a></li>
<li><a href="https://www.youtube.com/watch?v=VDz1IvuWyJw"target="_blank" rel="noopener">MSX Konami Games</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@GTV-Japan"target="_blank" rel="noopener">GTV Japan</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=_s9fmbcds40&amp;list=PLu4Z50DKq3na663p7gGKgxHOZFGv2eqWO"target="_blank" rel="noopener">The GTV Binge Watch</a></li>
<li><a href="https://www.youtube.com/watch?v=zgtYV41yXbU&amp;list=PLu4Z50DKq3nYnRu-3XhDncP8MRzOsusRm"target="_blank" rel="noopener">GTV&rsquo;s Greatest Hits</a></li>
</ul>
</li>
<li>Videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=KdS34tc37hk"target="_blank" rel="noopener">The Story of Chrono Trigger</a></li>
<li><a href="https://www.youtube.com/watch?v=gNps2YP2e30&amp;t=860s"target="_blank" rel="noopener">The Final 16-bit Fantasy</a></li>
<li><a href="https://www.youtube.com/watch?v=DV3K3Coz1RA"target="_blank" rel="noopener">Sonic Mania Day</a></li>
<li><a href="https://www.youtube.com/watch?v=I2MYvgNf9lU"target="_blank" rel="noopener">The History of Sonic - 30th Anniversary</a></li>
<li><a href="https://www.youtube.com/watch?v=zgtYV41yXbU"target="_blank" rel="noopener">The Super Story of Mario World</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@DisplacedGamers"target="_blank" rel="noopener">Displaced Gamers</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=55X1KOw_Rhg&amp;list=PLn5sTGew1WGB0-omvT5UtPanoCzRh7A0V"target="_blank" rel="noopener">Game Genie: Uncorked</a></li>
<li><a href="https://www.youtube.com/watch?v=EhO_iHkUkE0&amp;list=PLn5sTGew1WGD5NUstpfwYdLfrmLJOHCSw"target="_blank" rel="noopener">Talkin&rsquo; Code</a></li>
<li><a href="https://www.youtube.com/watch?v=gTfPLl_AJvs&amp;list=PLn5sTGew1WGD2Tnspn9vhpLGf-kqDRbYy"target="_blank" rel="noopener">Behind the Code</a></li>
<li><a href="https://www.youtube.com/watch?v=ssluTgfkdlg&amp;list=PLn5sTGew1WGCMO7Bi-MD7VgFWAoeXbU93"target="_blank" rel="noopener">Gaming Tech Talk</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@RGMechEx"target="_blank" rel="noopener">Retro Game Mechanics Explained</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=UdD26eFVzHQ&amp;list=PLHQ0utQyFw5IrM_zCFY8fhtByNxVGRUMr"target="_blank" rel="noopener">Super Mario 2</a></li>
<li><a href="https://www.youtube.com/watch?v=1whju31WAPA&amp;list=PLHQ0utQyFw5KxchzQnRcc_uk-NU7FbHNM"target="_blank" rel="noopener">Super Mario Bros.</a></li>
<li><a href="https://www.youtube.com/watch?v=q15yNrJHOak&amp;list=PLHQ0utQyFw5I8qqpOXKXKySBsphqdStdq"target="_blank" rel="noopener">Super Mario World</a></li>
<li><a href="https://www.youtube.com/watch?v=fxZuzos7Auk&amp;list=PLHQ0utQyFw5KoUSkHGq5VtMY0v2e5G_u3"target="_blank" rel="noopener">Super Mario Bros 3</a></li>
<li><a href="https://www.youtube.com/watch?v=FPzuYWbnln4&amp;list=PLHQ0utQyFw5IrotCLCfxKGkUL-WjPDrxh"target="_blank" rel="noopener">Super Mario Land 2</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@TheCherno"target="_blank" rel="noopener">The Cherno</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=gfW1Fhd9u9Q&amp;list=PLlrATfBNZ98edc5GshdBtREv5asFW3yXl"target="_blank" rel="noopener">Ray Tracing Series</a></li>
<li><a href="https://www.youtube.com/watch?v=W3gAzLwfIP0&amp;list=PLlrATfBNZ98foTJPJ_Ev03o2oq3-GGOS2"target="_blank" rel="noopener">OpenGL</a></li>
<li><a href="https://www.youtube.com/watch?v=9HCboZHTyrw&amp;list=PLlrATfBNZ98f6Z1cDNeMLL3eXaRk1WCxK"target="_blank" rel="noopener">Code Review</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@Kosmicd12"target="_blank" rel="noopener">Kosmic</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=1wR8x5b_ExM&amp;list=PLbxkd_Hs6FDK2FNWiOAK_LPBMXauJMrlC"target="_blank" rel="noopener">World Record SpeedRuns</a></li>
<li><a href="https://www.youtube.com/watch?v=kyZ4yF3ynsA&amp;list=PLbxkd_Hs6FDKH8YVR82mS2zFDWN_pwkQx"target="_blank" rel="noopener">Super Mario Bros</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@KazeN64"target="_blank" rel="noopener">Kaze Emanuar</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=dfK4Iuz3mME&amp;list=PLY9TGb7t9kuHx1vP2qCascFrhfnzLn-ME"target="_blank" rel="noopener">SM64: Last Impact - Developer Commentary</a></li>
</ul>
</li>
<li>Videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=DdXLpoNLywg"target="_blank" rel="noopener">Mario 64 breaks after 7 days</a></li>
<li><a href="https://www.youtube.com/watch?v=OHU2onxKm5o&amp;pp=0gcJCY0JAYcqIYzv"target="_blank" rel="noopener">Perfecting Random Number Generation on N64</a></li>
<li><a href="https://www.youtube.com/watch?v=r-2iIBmXULI&amp;t=129s"target="_blank" rel="noopener">Planetary Gravity is Cheap</a></li>
<li><a href="https://www.youtube.com/watch?v=g5u3zW4SLow&amp;pp=0gcJCY0JAYcqIYzv"target="_blank" rel="noopener">The Genius of N64 Cache Instruction</a></li>
<li><a href="https://www.youtube.com/watch?v=DotEVFFv-tk"target="_blank" rel="noopener">The N64 has more RAM than you think</a></li>
<li><a href="https://www.youtube.com/watch?v=f05PwswO7qc&amp;t=344s"target="_blank" rel="noopener">Why Devs need to know about Render Matrices</a></li>
<li><a href="https://www.youtube.com/watch?v=-nhhfYkluT0"target="_blank" rel="noopener">Better engine, Better graphics</a></li>
<li><a href="https://www.youtube.com/watch?v=hffgNRfL1XY"target="_blank" rel="noopener">The Folded Polynomial</a></li>
<li><a href="https://www.youtube.com/watch?v=xFKFoGiGlXQ"target="_blank" rel="noopener">Fastest Sine on N64</a></li>
<li><a href="https://www.youtube.com/watch?v=t_rzYnXEQlE"target="_blank" rel="noopener">Fixing the Entire SM64 source code</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@james.lambert"target="_blank" rel="noopener">James Lambert</a>
<ul>
<li>Videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=WDNU9k8uTc4"target="_blank" rel="noopener">Can Portal64 be saved?</a></li>
<li><a href="https://www.youtube.com/watch?v=sb3nHlsBBpg&amp;t=256s"target="_blank" rel="noopener">Portal 64: First Slice, is out of beta</a></li>
<li><a href="https://www.youtube.com/watch?v=r4KGm7ixcqI"target="_blank" rel="noopener">How I optimized Portal to run on the N64</a></li>
<li><a href="https://www.youtube.com/watch?v=Sf036fO-ZUk"target="_blank" rel="noopener">How I implemented MegaTextures on real N64 hardware</a></li>
<li><a href="https://www.youtube.com/watch?v=ao1qVi5Qp3Y&amp;t=58s&amp;pp=0gcJCY0JAYcqIYzv"target="_blank" rel="noopener">I rewrote Portal from scratch and solved the Portal Paradox</a></li>
<li><a href="https://www.youtube.com/watch?v=VqDAxcWnq3g"target="_blank" rel="noopener">How are toon shading and dynamic shadows possible on the N64?</a></li>
<li><a href="https://www.youtube.com/watch?v=yXzoZ2AfWwg&amp;pp=0gcJCY0JAYcqIYzv"target="_blank" rel="noopener">How can Nintendo 64 run Portal?</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@veritasium"target="_blank" rel="noopener">Veritasium</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=AaZ_RSt0KP8&amp;list=PLkahZjV5wKe8w9GC_n2yyhx6Wj-NKzzeE"target="_blank" rel="noopener">Computing</a></li>
</ul>
</li>
<li>Videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=w5ebcowAJD8&amp;pp=0gcJCY0JAYcqIYzv"target="_blank" rel="noopener">I build a QR code with my bare hands to see how it workds</a></li>
<li><a href="https://www.youtube.com/watch?v=wVyu7NB7W6Y"target="_blank" rel="noopener">Exposing the flaw in out phone system</a></li>
<li><a href="https://www.youtube.com/watch?v=A5w-dEgIU1M"target="_blank" rel="noopener">The Trillion Dollar equation</a></li>
<li><a href="https://www.youtube.com/watch?v=nmgFG7PUHfo&amp;t=40s"target="_blank" rel="noopener">The Most Important Algorithm of All Time</a></li>
<li><a href="https://www.youtube.com/watch?v=HeQX2HjkcNo"target="_blank" rel="noopener">Math&rsquo;s Fundamental Flaw</a></li>
<li><a href="https://www.youtube.com/watch?v=R13BD8qKeTg"target="_blank" rel="noopener">The Bayesian Trap</a></li>
<li><a href="https://www.youtube.com/watch?v=IcrBqCFLHIY&amp;pp=0gcJCY0JAYcqIYzv"target="_blank" rel="noopener">How Does a Transistor Work</a></li>
<li><a href="https://www.youtube.com/watch?v=zNzzGgr2mhk"target="_blank" rel="noopener">How to Make a Quantum Bit</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="https://www.youtube.com/@3blue1brown"target="_blank" rel="noopener">3Blue1Brown</a>
<ul>
<li>Playlists:
<ul>
<li><a href="https://www.youtube.com/watch?v=8rrHTtUzyZA&amp;list=PLZHQObOWTQDMp_VZelDYjka8tnXNpXhzJ"target="_blank" rel="noopener">Convolutions</a></li>
<li><a href="https://www.youtube.com/watch?v=8idr1WZ1A7Q&amp;list=PLZHQObOWTQDOjmo3Y6ADm0ScWAlEXf-fp"target="_blank" rel="noopener">Probabilities of Probabilities</a></li>
<li><a href="https://www.youtube.com/watch?v=p_di4Zn4wz4&amp;list=PLZHQObOWTQDNPOjrT6KVlfJuKtYTftqH6"target="_blank" rel="noopener">Differential equations</a></li>
<li><a href="https://www.youtube.com/watch?v=WUvTyaaNkzM&amp;list=PLZHQObOWTQDMsr9K-rj53DwVRMYO3t5Yr"target="_blank" rel="noopener">Essence of Calculus</a></li>
<li><a href="https://www.youtube.com/watch?v=fNk_zzaMoSs&amp;list=PLZHQObOWTQDPD3MizzM2xVFitgF8hE_ab"target="_blank" rel="noopener">Essence of Linear Algebra</a></li>
<li><a href="https://www.youtube.com/watch?v=aircAruvnKk&amp;list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi"target="_blank" rel="noopener">Neural Networks</a></li>
</ul>
</li>
<li>Videos:
<ul>
<li><a href="https://www.youtube.com/watch?v=RQWpF2Gb-gU"target="_blank" rel="noopener">But what is a quantum computing - Grover&rsquo;s Algorithm</a></li>
<li><a href="https://www.youtube.com/watch?v=Dlsa9EBKDGI"target="_blank" rel="noopener">Where my explanation of Grover&rsquo;s algorithm failed</a></li>
<li><a href="https://www.youtube.com/watch?v=LPZh9BOjkQs&amp;pp=0gcJCY0JAYcqIYzv"target="_blank" rel="noopener">Large Language Models explained briefly</a></li>
</ul>
</li>
</ul>
</li>
</ul>
]]></content:encoded><category>historia-da-computacao</category><category>retrocomputacao</category><category>emulacao</category><category>off-topic</category></item><item><title>[Akitando] #89 - Introdução a Videogames e Emuladores</title><link>https://akitaonrails.github.io/2020/12/22/akitando-89-introducao-a-videogames-e-emuladores/</link><guid isPermaLink="true">https://akitaonrails.github.io/2020/12/22/akitando-89-introducao-a-videogames-e-emuladores/</guid><pubDate>Tue, 22 Dec 2020 10:30:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/vUqLLpUJ47s"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Finalmente vou contar sobre um dos assuntos que eu mais gosto: videogames e emuladores. E aproveitar os episódios que eu vim fazendo sobre Introdução a Computadores pra adicionar mais alguns conhecimentos interessantes pra quem é programador entender como essas coisas funcionam.&lt;/p&gt;
&lt;p&gt;ERRATA: eu falo que PPSSPP emula PS Vita mas na verdade é o PSP.&lt;/p&gt;
&lt;p&gt;Links:&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/vUqLLpUJ47s"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Finalmente vou contar sobre um dos assuntos que eu mais gosto: videogames e emuladores. E aproveitar os episódios que eu vim fazendo sobre Introdução a Computadores pra adicionar mais alguns conhecimentos interessantes pra quem é programador entender como essas coisas funcionam.</p>
<p>ERRATA: eu falo que PPSSPP emula PS Vita mas na verdade é o PSP.</p>
<p>Links:</p>
<ul>
<li>Understanding the ELF File Format (<a href="https://linuxhint.com/understanding_elf_file_format/"target="_blank" rel="noopener">https://linuxhint.com/understanding_elf_file_format/</a>)</li>
<li>Super Nintendo Architecture (<a href="https://www.copetti.org/projects/consoles/super-nintendo/"target="_blank" rel="noopener">https://www.copetti.org/projects/consoles/super-nintendo/</a>)</li>
<li>Mega Drive Architecture (<a href="https://www.copetti.org/projects/consoles/mega-drive-genesis/"target="_blank" rel="noopener">https://www.copetti.org/projects/consoles/mega-drive-genesis/</a>)</li>
<li>CPU comparison: SNES vs. Genesis vs. TG16 (<a href="https://atariage.com/forums/topic/197977-cpu-comparison-snes-vs-genesis-vs-tg16/"target="_blank" rel="noopener">https://atariage.com/forums/topic/197977-cpu-comparison-snes-vs-genesis-vs-tg16/</a>)</li>
<li>Neat story about the 6502 CPU (NES.. sorta SNES..) (<a href="https://forum.nhl94.com/index.php?/topic/12514-neat-story-about-the-6502-cpu-nes-sorta-snes/"target="_blank" rel="noopener">https://forum.nhl94.com/index.php?/topic/12514-neat-story-about-the-6502-cpu-nes-sorta-snes/</a>)</li>
<li>History of Console Emulators (<a href="http://www.emulationnation.com/console-emulation/history-of-console-emulators/"target="_blank" rel="noopener">http://www.emulationnation.com/console-emulation/history-of-console-emulators/</a>)</li>
<li>History of emulation (<a href="https://emulation.fandom.com/wiki/History_of_emulation"target="_blank" rel="noopener">https://emulation.fandom.com/wiki/History_of_emulation</a>)</li>
<li>Emugen: History of emulation (<a href="https://emulation.gametechwiki.com/index.php/History_of_emulation"target="_blank" rel="noopener">https://emulation.gametechwiki.com/index.php/History_of_emulation</a>)</li>
<li>How UltraHLE changed Nintendo 64 emulation forever | MVG (<a href="https://www.youtube.com/watch?v=2NF5sU_n0uk"target="_blank" rel="noopener">https://www.youtube.com/watch?v=2NF5sU_n0uk</a>)</li>
<li>Introduction to N64 Programming (<a href="http://n64.icequake.net/doc/n64intro/kantan/step2/index1.html"target="_blank" rel="noopener">http://n64.icequake.net/doc/n64intro/kantan/step2/index1.html</a>)</li>
<li>After Burner II NEC PC Engine / TurboGrafx-16 (<a href="https://www.youtube.com/watch?v=TORgYPAXk18&amp;t=0s"target="_blank" rel="noopener">https://www.youtube.com/watch?v=TORgYPAXk18&t=0s</a>)</li>
<li>Mac OS on a Sega Genesis? Yes! (Mac OS on a Sega Genesis? Yes! (sega-16.com))</li>
<li>Making a SEGA Mega Drive / Genesis game in 2019 (<a href="https://www.gamasutra.com/blogs/DoctorLudos/20191019/352537/Making_a_SEGA_Mega_Drive__Genesis_game_in_2019.php"target="_blank" rel="noopener">https://www.gamasutra.com/blogs/DoctorLudos/20191019/352537/Making_a_SEGA_Mega_Drive__Genesis_game_in_2019.php</a>)</li>
</ul>
<h2>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Feliz 2021! Muita gente tava esperando o novo ano pra deixar 2020 pra trás, mas infelizmente não sei se esse ano vai ser muito diferente não. Vamos cruzar os dedos.</p>
<p>Depois que fiz o episódio onde falei do chip Apple M1 eu ia fazer este, mas acabei falando de segurança. Mas agora vou voltar ao assunto continuando a falar de emuladores e videogames. Isso porque uma das coisas que mais gosto nessa vida é videogames. Desde que comecei a trabalhar sempre dizia que eu trabalho pra ganhar dinheiro pra sustentar meus videogames, e é quase verdade mesmo.</p>
<p>Outra coisa que vocês já sabem que eu gosto é a história das coisas de tech. No episódio de hoje vou juntar a fome e a vontade de comer e contar um pouco da história dos videogames com uma visão mais de programador, levando em conta o que vimos nos episódios anteriores e focar em assuntos que eu pessoalmente gosto. Claro que o tema é gigantesco e não cabe tudo num video só, mas vamos ver o que eu consigo fazer hoje!</p>
<p>Antes de começar, eu vi nos comentários que muitos ficaram com uma dúvida com a explicação que eu dei sobre máquinas de Turing, ou o que hoje chamamos de programas, serem representados por um numerozão, lembram? Um binário é nada mais que um número gigante. Então como falei de emuladores, muitos perguntaram se o lance era fazer outro programa com o mesmo numerozão.</p>
<p>Mas não é assim que você tem que pensar. Pensar num numerozão como sendo um texto em inglês e a versão emulada sendo o texto em português. Ambos os textos falam, digamos, sobre Harry Potter, mas em línguas diferentes e, portanto, resultam em numerozões diferentes. Quando você sai de Intel e vai pra ARM, por exemplo, necessariamente o mesmo programa recompilado, vai gerar um binário totalmente diferente e, de novo, um numerozão diferente. Espero que tenha esclarecido.</p>
<p>(&hellip;)</p>
<p>Pra começar já vou recomendar logo de cara o canal do Dimitris, mais conhecido como Modern Vintage Gamer. Assisto faz anos e ele sempre trás histórias dos bastidores, coisa que eu gosto. O canal dele tem várias histórias de como conseguiram quebrar a segurança dos mais diversos consoles, coisa que é essencial pra conseguir fazer um emulador. Ao longo dos anos empresas como a Sony, Sega, Nintendo, Microsoft, vem colocando mais e mais mecanismos de criptografia e segurança e, mesmo assim, dado tempo suficiente, a comunidade de emulação encontra maneiras de burlar e é fascinante entender como fazem isso.</p>
<p>Por exemplo, lembro da controvérsia quando a Sony retirou o suporte a Linux no Playstation 3 e o povo ficou pistola demais e isso acelerou alguém conseguir quebrar o PS3. Hoje em dia até a Microsoft já aprendeu e qualquer Xbox One você consegue colocar em modo de desenvolvimento, pra facilitar a vida de quem faz jogo independente, e ao mesmo tempo desincentiva gente que quer hackear pra instalar software homebrew, porque o próprio sistema já permite isso. Todo mundo fica feliz. O Dimitris faz uma série muito boa que conta essas histórias em mais detalhes, é o Mistakes were made, ou em bom português, “Erros foram cometidos”.</p>
<p>Pra quem não sabe, a gente costuma dividir consoles de videogames em gerações. Acabamos de entrar na nona geração com o PS5 e Xbox Series X. Infelizmente eu não reservei na pré-venda então me fodi. Se alguém souber de alguém querendo vender a um bom preço, mandem direct no meu Instagram. Enfim, acabamos de deixar pra trás a oitava geração, com PS4, XBox One, Switch e até o Wii U entra nessa.</p>
<p>A anterior foi do PS3, XBox 360 e o Wii original e foi a maior lavada em favor do Xbox 360 com o Wii original também deixando sua marca com a febre por causa dos controles de movimento. A sexta foi do Dreamcast, PS2, Xbox original e Gamecube, que marcou a virada do milênio em direção ao mundo de alta fidelidade, HD, telas de Plasma e LCD de alta resolução. Mas no fim do século passado, a quinta geração foi o salto de 16 pra 32-bits e a primeira onda de jogos 3D com consoles como Nintendo 64, o Playstation original, o Sega Saturn, Atari Jaguar, Panasonic 3DO e vários outros, foi uma das gerações mais movimentadas que eu já vi, e o salto pra 32-bits foi uma das mais importantes e conturbadas da história recente.</p>
<p>A quarta geração foi dos 16-bits, a virada da década de 80 pra 90, com o Sega Genesis liderando no começo mas com o Super Nintendo lado a lado, a era de tentar ter qualidade gráfica de arcade em casa, e tinha outras opções excelentes como o Turbografx 16 que no Japão era chamado de PC Engine e também tinha o monstruoso Neo Geo. Aliás, Genesis é nos Estados Unidos, aqui no Brasil ou no Japão a gente conheceu como Mega Drive.</p>
<p>A campanha de marketing da Sega nos Estados Unidos foi super agressiva, com o famoso slogan do &ldquo;Sega does what Nintendon&rsquo;t&rdquo; e com o lançamento de jogos como o lendário Sonic, veio o slogan bullshit de &ldquo;Blast processing&rdquo;. Tecnicamente o Genesis era mesmo mais performático, mas fizeram o erro de configurar uma paleta de cores horrível e limitada. O Super Nintendo usava um chip de 16-bits mais fraco, mas eles tinham aceleração de background como o Mode 7 e uma paleta de cores muito mais rica.</p>
<p>Em seguida, a terceira geração foi dos 8-bits que representaram a renascença do videogame com o Nintendinho liderando, mas com outros como o Sega Master System tentando conseguir espaço. Em termos de hardware, essa geração foi o oposto da de 16-bits, o Master System é quem tinha uma paleta de cores mais rica e por isso jogos de Nintendinho tem cores meio bleh e no Master System eram cores bem mais saturadas e diversificadas. Mas obviamente o sistema de licenciamento e exclusividade da Nintendo garantia muito mais jogos pro console deles, deixando a Sega com poucas opções.</p>
<p>A terceira e quarta geração foram marcadas pelo que hoje conhecemos como a “Guerra dos Consoles”, a briga entre a Sega e a Nintendo. E, de novo, mais nos Estados Unidos, porque no Japão a Sega dominava nos arcades mas nos consoles sempre foi a Nintendo na frente. Até eles fazerem uma merda com a Sony. Fizeram parceria pra lançar o Nintendo Playstation com tecnologia de CD da Sony. Mas num grande evento, a CES, a Nintendo anunciou que ia fazer parceria com a Philips e a Sony só descobriu isso com todo mundo nesse evento. Foi uma cagada homérica da Nintendo, procurem essa história. Mas o importante é que isso deixou a diretoria da Sony full pistola e por isso eles aprovaram lançar o próprio console, o Playstation original, daí o resto - como diriam - foi história.</p>
<p>Voltando, a segunda geração foi a que terminou nos Estados Unidos com o crash dos videogames no começo dos anos 80, a geração do nostálgico Atari 2600, Magnavox Odyssey 2, Intellivision, ColecoVision, Vectrex e dezenas de outros. O crash aconteceu justamente pelo excesso de consoles e principalmente excesso de jogos extremamente ruins, o que arruinou a reputação de games, afastou todo o público e inspirou a Nintendo a criar o modelo de licenciamento e controle de qualidade pra lançar jogos pro console deles.</p>
<p>Eu joguei alguma coisa nessa época, e apesar da nostalgia, não acho mais divertido jogos de Atari hoje em dia. Esses jogos não envelheceram nada bem, e quem gosta realmente é pelas memórias da infância. Eu tenho essas memórias, mas viraram só isso mesmo, memórias. Nem Enduro, nem River Raid, nem Space Invaders, ou Pitfall, todos jogos que eu adorava, não consigo mais jogar hoje. A tecnologia nessa época ainda era bem experimental, bem pouco madura, com pouquíssimos recursos, então realmente programar pra esses consoles era um exercício em frustração e era impossível fazer jogos mais sofisticados do que um Pacman.</p>
<p>Agora, segundo a Wikipedia, a primeira geração de consoles tem pelo menos uns 900, não é a toa que na próxima geração ia ter um crash. Começou como uma bolha. Tudo foi derivado da do avô dos videogames, o Pong. E nessa época ainda não havia sido inventado e nem difundido o conceito de cartuchos. A grande maioria desses consoles eram meros clones baratos de Pong e vinham com um único jogo, ou até mais de um, mas eram pré-instalados dentro e você podia trocar de jogo usando um interruptor, mas não podia instalar jogos novos.  Ainda era a geração que entendia que uma máquina só precisava executar uma única tarefa. E nessa geração trocentos fabricantes diferentes faziam seus próprios clones de Pong, Pacman e coisas assim. Imagina a dificuldade pro consumidor.</p>
<p>Já vimos nos episódios anteriores que cartuchos são uma placa com chips de ROM que o console tem acesso direto, sem precisar “carregar” nada pra RAM, é como se fosse um pente de RAM pré-carregado. E se você assistiu a série do Netflix, High Score viu que o primeiro console que introduziu o conceito de cartuchos foi o Fairchild Channel F em 1976 mas quem de fato popularizou a idéia foi o Atari VCS que saiu um ano depois. Vários fabricantes já estavam testando idéias pra baratear custos e facilitar vendas, e eventualmente alguém chegaria no cartucho, era inevitável. Todo mundo tava procurando formas de baratear os custos e tornar coisas como games mais acessíveis, sem usar mecanismos lentos como as fitas cassette, ou caros como disquetes.</p>
<p>Obviamente, a cada nova geração a complexidade dos consoles ia aumentando uma ordem de grandeza. Por exemplo, os consoles de 8-bits não são tão complicados assim e eu dei um pequeno exemplo no episódio do Super Mario com o Nintendinho e canais como o Coding Secrets e Retro Gaming Mechanics Explained tem muitos vídeos explicando técnicas de programação e como os jogos eram estruturados nessas plataformas, incluindo coisas como o lendário Mode 7 do Super Nintendo. Nessa época, cada clock contava e nenhum compilador ainda conseguir cuspir binários otimizados. Todo jogo precisava ser escrito em assembly, na mão mesmo. Recomendo assinar os canais deles.</p>
<p>Emular esses consoles significa encontrar as especificações dos chips e programar as instruções equivalentes em software, garantir que o clock funcione igual, que as instruções executem nos mesmos tempos. Isso não é tão trivial porque pensa que nossas CPUs hoje são absurdamente mais rápidas que antigamente, então a gente precisa propositalmente fazer as instruções rodar mais devagar. No caso de um Nintendinho você tem que criar o emulador pra CPU Ricoh 2A03 que é baseado no MOS 6502. Tem que escrever o emulador pro PPU ou Picture Processing Unit que é o chip responsável por renderizar backgrounds e sprites. Mesma coisa pro APU que é o Audio Processing Unit que tem cinco canais de áudio e é um PSG ou Programmable Sound Generator. Enfim, criar software pra emular cada um dos chips.</p>
<p>Daí precisa emular os 2 kilobytes de RAM que é bem fácil porque temos RAM de sobra hoje. Tem que emular os controles e finalmente os MMU ou memory management controllers que são chips que vinham nos cartuchos e permitiam bancos de ROM. O sistema permite um máximo de 40 kilobytes de ROM mas com os MMUs você podia ter cartuchos com até 2 megabytes ou mais e também memória com bateria pra gravar saves. E sim, é bastante coisa pra emular. Eu expliquei como isso funciona no episódio do Super Mario, dêem uma olhada. Aliás, tudo isso é só pro Nintendinho de 8-bits. Agora repita isso pra todos os consoles, em todas as suas variações ao longo dos anos, de cada uma das oito gerações que eu descrevi. É coisa pra cacete.</p>
<p>Falando só de especificações técnicas, sem olhar os jogos, tecnicamente o Turbografx 16 deveria ser o mais fraco, porque ele usa o processador 65C02 que é o mais rápido CPU 8-bits da família 6502, e tava competindo na geração de 16-bits do Genesis e Super Nintendo. A NEC escolheu usar chips de RAM e ROM dos cartuchos com o clock máximo que o CPU conseguia rodar, e isso foi muito inteligente. Se você pegar jogos de Turbografx como Bonks Adventure ou Dracula X que é o Castlevania, vai provavelmente dizer que é comparável ou até superior ao Super Castlevania IV do Super Nintendo.</p>
<p>O Super Nintendo muita gente pensa que é o mais poderoso por conta do chip gráfico que tem capacidade de rotacionar e escalar o layer de background pra fazer os famosos efeitos pseudo-3D como em Mario Kart ou Pilotwings. Mas a Nintendo foi pelo caminho mais conservador e escolheu usar o processador 65816 que é o sucessor de 16-bits do 65C02 usado no Turbografx 16. Só que o chip de 8-bits do Turbografx ia até 7.6 Mhz e o chip de 16-bits do Super Nintendo foi capado em míseros 3.58 Mhz, metade, em parte porque a RAM não era mais rápida que isso.</p>
<p>Muita gente pensa em performance só como clock da CPU, mas até hoje, você precisa parear a CPU com RAM porque o a CPU precisa ficar constantemente puxando dados e gravando nessa RAM, por isso coisas como clock da RAM e dual channel fazem muita diferença em PC de hoje. E por isso também uma Apple preferiu soldar a RAM direto do lado do seu novo CPU M1 pra garantir a melhor combinação de performance. Smartphones fazem a mesma coisa. Se você comprar um AMD Ryzen mais moderno mas colocar pentes de RAM velhas de menos de 2Ghz e sem colocar em dual channel, você criou um gargalo enorme, e está desperdiçando o CPU.</p>
<p>Sendo o Super Nintendo e o Turbografx derivados da família 6502, eu não posso dizer por experiência própria mas pelo que já li a respeito o assembly dele não era muito amigável pra programar, exigindo muita burocracia, como a constante troca de modes no Super Nintendo entre instruções de 8 bits e 16 bits. Se tentasse escrever em C, o código gerado ficava muito lento pelo overhead do C, faltava registradores pra conseguir otimizar. Enfim, não era uma CPU amigável pra um programador de assembly, e eu já disse que nessa época era obrigatório programar em assembly pra tirar o máximo dos poucos recursos que tinha nesses consoles.</p>
<p>Por outro lado, o Sega Genesis ou Mega Drive de fato tinha o CPU superior, eles escolheram o Motorola 68000 que era híbrido 32 e 16-bits, com clock também de 7.6 Mhz, o dobro do Super Nintendo e ainda vinha com um segundo processador Zilog Z80 de 8-bits que era o mesmo do Master System, usado como processador dedicado de áudio. Além disso, diferente do 65C02 e 65816, você conseguia escrever pelo menos parte do jogo em C, que gerava assembly suficientemente rápido pro 68000. E mesmo não tendo um chip gráfico dedicado pra conseguir os efeitos de rotação e escalonamento de background, ele conseguia alguns desses efeitos via software por causa do CPU mais rápido. Veja jogos como Castlevania Bloodlines por exemplo. Pois é, era possível fazer Mode 7 no Mega Drive, isso não era uma exclusividade do Super Nintendo.</p>
<p>Mas como eu disse antes, uma coisa que o Mega Drive falhou foi na escolha de paletas de cor. Ele tinha conjuntos de cores horríveis e menos cores no total que o Super Nintendo ou Turbografx. Por isso, visualmente, os jogos de Megadrive parecem sempre mais feios em termos de cor se comparar jogos que foram lançados pras outras plataformas. Pegue jogos que saíram ao mesmo tempo em todas como Street Fighter II e no Mega Drive vai ser mais feinho.  Olha aqui do lado. Esse é o do Super Nintendo, esse outro do Turbografx e por último, esse é do Mega Drive.</p>
<p>No final do dia, tudo depende do que os programadores conseguiam extrair dessas máquinas. E em termos de jogos não se pode comparar os que saíram no lançamento dos consoles com os que saíram no final da geração. No começo é quando os programadores ainda não conhecem todo o potencial do hardware. E quando a geração tá acabando, é quando os programadores já descobriram todos os truques possíveis. É interessante ver como jogos como Afterburner II é definitivamente melhor no Turbografx com um processador teoricamente pior de 8-bits contra a versão do Mega Drive de 16-bits.</p>
<p>Mais do que isso, o processador do Mega Drive, o 68000 é super famoso e equipou microcomputadores como os Amiga e Macintosh por exemplo. Existiu até uma tentativa de emular o Mac OS 7 pra rodar em cima de um Mega Drive. Infelizmente, tirando uma thread de fórum de 2006, não achei imagens boas ou vídeos mostrando ele rodando. Se alguém tiver não deixe de compartilhar nos comentários.</p>
<p>Obviamente não seria prático rodar o Mac OS num Mega Drive, é só mais uma evidência do que falei no vídeo anterior sobre máquinas universais de Turing: mesmo lento é possível emular outro sistema. E tecnicamente faz sentido, ele usa o Sega CD como um CD SCSI que o Mac consegue acessar e o video sai pela extensão 32X que foi uma expansão pro Mega Drive conseguir rodar polígonos e outros efeitos especiais, incluindo mais resolução e mais cores também.</p>
<p>De qualquer forma, até a terceira geração, dos 16-bits, muito da programação de jogos se fazia em Assembly, particularmente porque a família de CPUs da MOS não conseguia ter C que gerasse binários eficientes, então só codando assemblão na munheca mesmo. Mas a próxima geração teve um salto enorme. Na quarta geração começamos a usar processadores de 32-bits com arquitetura RISC, semelhante aos processadores ARM de celulares de hoje em dia e ao novo Apple M1.</p>
<p>Era possível ter clocks maiores e acesso a exponencialmente mais endereços de RAM. E daí passou a se utilizar mais C, porque nessa arquitetura os compiladores evoluíram mais e já era possível ter código compilado tão eficiente ou mais do que escrever assembly na mão. E se alguém tinha alguma dúvida, não, em 99.99% dos casos você não vai conseguir escrever mais assembly melhor do que um compilador consegue gerar.</p>
<p>Num resumo bem resumido, pense que a arquitetura x86 ou CISC é feita de instruções complexas, ou seja, que fazem bastante coisa e por isso demoram vários clocks pra executar e arquitetura RISC como nos chips ARM é feita de instruções simples que, que executam poucas tarefas e por isso terminam rápido, tipo num único clock. Só pra ilustrar pra quem não tá acostumado com assembly, num processador x86 talvez eu tivesse uma função chamada “desenhar um botão” que numa instrução só já mostra um botão desenhado na tela. Num ARM hipotético teria só a função “desenhar linha” e eu precisaria chamar quatro vezes pra desenhar o mesmo botão.</p>
<p>Na prática não faria tanta diferença porque desenhar botão digamos que leva 4 clocks pra executar e o desenhar linha leve 1 clock. No fim ambos levariam 4 clocks. Mas pra quem escreve direto em assembly faz diferença porque ele precisaria escrever muitas linhas a mais de código pra fazer a mesma coisa. Hoje em dia não faz diferença, porque do C o compilador que vai ter o trabalho de gerar o assembly, mas antigamente programar em C não era eficiente então fazia diferença essa história de arquiteturas CISC ou RISC porque influenciava diretamente na produtividade dos programadores.</p>
<p>Mas a partir da geração 32-bits passamos a programar quase que exclusivamente em C, deixando o trabalho de gerar assembly pros compiladores, como o compilador do Visual Studio da Microsoft ou o GCC que tem em todo Linux ou o LLVM, mais especificamente o Clang, que tem em todo Mac. Agora, imagine que descobrimos uma forma mais eficiente de fazer a função hipotética de desenhar botão e em vez de levar 4 clocks poderia levar 2.</p>
<p>Num Intel fodeu, não tem como mexer nessa função porque ela é impressa no hardware, no chip da CPU. Num RISC, que tem instruções mais simples, podemos atualizar o compilador e ele vai cuspir um assembly mais otimizado que vai usar menos instruções e executar em 2 clocks. Ou seja, sempre temos possibilidades de, sem mexer no código em C, ganhar performance de graça por avanços nas otimizações dos compiladores. E nesse quesito o ARM tem mais vantagens do que x86 da Intel.</p>
<p>Pra nós, que dificilmente vamos programar assembly na mão, a arquitetura do chip por baixo não importa porque o compilador vai fazer o trabalho bruto de escrever assembly otimizado, mas basta saber que sim, a arquitetura RISC é definitivamente mais flexível do que os x86. A Intel é obrigada a carregar esse legado que vem da época em que era importante um assembly mais simples e, portanto, mais complexo. Hoje isso não é mais importante. Em última instância a arquitetura RISC era mais chata naquela época se você precisasse escrever assembly na mão, mas agora ela tem vantagens. Ela estava à frente do seu tempo.</p>
<p>De qualquer forma, a arquitetura dos dois tipos foi ficando mais complexa com o tempo, porque agora esses CPUs também eram capazes de realizar tarefas concorrentemente com multithreading além de ter chips gráficos capazes de calcular polígonos. Você tinha que ser um sadomasoquista hardcore pra querer fazer multithreading e polígonos em assembly num jogo inteiro. E antes os jogos tinham acesso direto ao hardware, sem um sistema operacional intermediando, mas no Saturn, Playstation ou Nintendo 64, agora eles tinham um firmware que funciona como um sistema operacional super leve. Agora meio que ficou necessário, porque senão ninguém ia conseguir fazer jogos nesses hardwares que eram exponencialmente mais complexos do que a geração anterior. É quando começamos a trocar um pouco de performance por mais qualidade de vida de programação.</p>
<p>Isso aumentou dramaticamente a dificuldade de emular esses sistemas. Porque se você fizer a engenharia reversa de chips de processamento de polígonos e tentar emular só via software, os CPUs de PCs da época simplesmente não conseguiam rodar. Ao mesmo tempo começamos a ter placas gráficas 3D em PC também com os venerados 3DFX. Pra programar em C pra placas 3DFX se usava a biblioteca Glide. Então algumas das primeiras tentativas de emular Playstation ou Nintendo 64 envolvia criar um software Adaptador entre as funções do console e os equivalentes na Glide. Por isso se você instalou emuladores dos anos 90 como o famoso UltraHLE tinha a chatice de achar a DLL certa de Glide por exemplo.</p>
<p>Existem vários vídeos e blogs onde você consegue encontrar a diferença de uma GPU pra uma CPU mas sendo bem simplista pra você ter uma idéia na cabeça. Numa CPU teríamos funções como adição, onde você coloca dois números em dois registradores e ele calcula a soma e grava em outro registrador, e vai fazendo assim uma instrução de cada vez. Se precisássemos processar todos os pixels de uma tela, digamos deixar a cor mais escura, seria um puta trampo pro CPU. Por que? Antigamente a resolução de videogame era tipo trezentos e vinte por duzentos e quarenta pixels, ou seja, setenta e seis mil e oitocentos pixels.</p>
<p>Só pra simplificar a conta digamos que cada adição da CPU custasse um clock, então ia levar mais de setenta e seis mil clocks pra processar todos os pixels. E ele teria que dar um jeito de fazer isso sessenta vezes por segundo. Ou seja, não dava porque num processador da era 16-bits, de 7 megahertz significa 7 mil clocks por segundo. Então ia levar mais de dez segundos pra processar essa imagem do exemplo.</p>
<p>Agora uma GPU é feita pra executar múltiplas adições em paralelo. Desde sempre ela foi organizada no que hoje você conhece como multi-core. Mas em vez de quatro ou oito cores que você tem num Intel i5 da vida, uma GPU tem dezenas, ou centenas de pequenos cores que fazem bem pouca coisa muito rápido. Em vez de passar só um número como parâmetro, passamos um vetor. Pense em um vetor como um array de números.</p>
<p>Então é a adição de um vetor com outro vetor. Digamos que a GPU aguente um vetor de 320 números, então ele precisaria processar a adição só duzentas e quarenta vezes, um por clock, ou melhor ela poderia rodar em duzentas e quarenta dos seus micro-cores e executar tudo em paralelo num clock só. Olha como só nesse exemplo, saltamos do custo de mais de setenta mil clocks pra um único clock.</p>
<p>Uma GPU executa tarefas muito simples em uma quantidade grande de dados de uma só vez, essa é a especialização dela. Porém, ela só é rápida pra esse tipo de cálculo mais massivo e não pra cálculos simples e lineares onde a próxima instrução depende do resultado da anterior. E gráficos é o melhor caso de uso, porque são trinta ou quarenta quadros por segundo com uma quantidade massiva de pixels que precisam ser processados e cujo processamento de uma linha de pixels independe da outra linha de pixels.</p>
<p>E pixels podem ser organizados em vetores e matrizes, que são os elementos que uma GPU adora processar. E em tempos mais recentes inventaram uma forma de mandarmos pequenos programinhas pra GPU, isso é o que você já deve ter ouvido falar como shaders. Enfim, já foi uma longa tangente, por hoje vamos só entender isso. GPU é um troço simples que se tornar complexo porque roda com vetores longos e massivamente em paralelo. CPU é um troço complexo que roda com argumentos simples e linear.</p>
<p>Ah sim, e nessa época a Microsoft tava lançando coisas com Direct3D que era uma tentativa de padronizar a programação 3D pra placas gráficas de diferentes fabricantes. Então talvez você não tivesse a 3DFX Voodoo mas tinha a Nvidia TNT2. Então precisava do nGlide que era uma camada que respondia as APIs da Glide mas mapeava pra chamadas de Direct3D. Sim, se hoje em dia você tem dores de cabeça com drivers da Nvidia ou AMD, com Direct3D ou Vulkan ou OpenGL, imagina a zona no fim dos anos 90. Era a mesma coisa só que pior e mais instável, a gente ainda tava aprendendo como lidar com placas 3D. Um dia vou fazer um episódio falando mais de GPUs, mas pra agora, só estas noções que expliquei pra diferenciar um CPU de uma GPU deve bastar pra maioria dos casos.</p>
<p>Ver coisas como o emulador UltraHLE, rodando Super Mario 64, em um Pentium II ou III, mesmo que parcialmente e meio bugado, em 1999, sendo que o Nintendo 64 tinha sido lançado só 3 anos, antes era absurdamente impressionante. Pra você ter uma idéia, mesmo hoje em dia usando emuladores como o Mugen 64, você não consegue emulação perfeita de Nintendo 64. Temos dificuldade em manter 60 frames por segundo em hardware considerado fraco hoje mas que pra época era um supercomputador, como um Raspberry Pi 3 ou processadores de celular Androids. Isso depois de 20 anos. De qualquer forma o UltraHLE era tão bom que deixou a Nintendo full pistola e você pode conferir essa história no video do canal Modern Vintage Game que vou deixar nas descrições abaixo.</p>
<p>A estratégia de emulação começou a mudar com o UltraHLE. Com consoles de 8 e 16 bits a estratégia era emular os chips como a CPU, PPU e tudo mais. Com o aumento da complexidade nas plataformas de 32-bits isso era um trabalho brutal e bem mais difícil. Porém, como o processo de desenvolvimento dos jogos passou pra C, linkando com as bibliotecas no firmware dos consoles, outra estratégia passou a ser interceptar as chamadas de função em C e traduzir pro equivalente no Windows por exemplo. Se você assistiu meu episódio sobre WSL, o Windows Subsystem for Linux, vai lembrar que a versão 1.0 fazia a mesma coisa com programas pra Linux, interceptava as chamadas de sistema pra kernel do Linux e traduzia em tempo real pra chamadas pra kernel do Windows.</p>
<p>O Playstation, pela popularidade, teve muito mais gente tentando emular e hoje em dia você consegue rodar praticamente todos os jogos, inclusive com hacks pra aumentar a resolução interna e aplicando filtros nas texturas pros jogos ficarem um pouco mais bonitos. Mas em paralelo ao UltraHLE a gente tinha alguns emuladores de Playstation também como o PSEmu ou o Virtual Game Station que era comercial e só rodava em Macintosh. Nenhum dos dois era perfeito na época, mas foram referência pra próxima geração de emuladores.</p>
<p>O primeiro emulador que eu lembro que me deixou realmente impressionado foi o Bleem. Ele era diferente primeiro porque era comercial e fechado e segundo porque em vez de tentar emular tudo do sistema e todos os jogos, eles preferiram focar em otimizar bem só alguns poucos jogos, como Gran Turismo ou Final Fantasy 7. Ou seja, eles deixavam hardcoded no emulador algo como “if gran turismo mude pra fazer X”, até o Gran Turismo rodar liso mesmo que outros jogos falhem. E eles vendiam pacotes de otimizações pra cada jogo. Na época, quando vi os anúncios, eu achava que era enganação, mas de fato a desgraça funcionava.</p>
<p>E eles ainda faziam isso de aumentar a resolução de renderização então jogos de playstation que nativamente só tinham 320 por 240 pixels dobrava pra 640 por 480. Lembrando que a gente usava monitores de 800 por 600 ou 1024 por 768. Então 640 por 480 era nosso HD. O emulador começou a mudar os jogos pra fazer coisas que originalmente eles não foram projetados pra fazer, e isso era fascinante. Pra ver como foi essa história eu recomendo o documentário sobre o Bleem do canal The Gaming Historian, que é outro canal bem produzido, e vou deixar o link nas descrições abaixo.</p>
<p>O Bleem acabou não vingando, tomaram um processo da Sony nas costas e eles tentaram voltar repetindo a estratégia com o Bleemcast na geração seguinte, pra emular Dreamcast. Mas apesar de não terem perdido o processo da Sony, os custos de advogados foram absurdos, e eles fecharam em 2001, no mesmo ano que a Sega decidiu descontinuar o Dreamcast também.</p>
<p>O desenvolvimento de emuladores de Playstation andou bem mais rápido do que Nintendo 64 mas o mais atrasado de todos sempre foi o Sega Saturn. Ele saiu antes do Playstation e esse lançamento foi um dos maiores desastres da história do videogame. Pra quem não sabe, a Sega dos Estados Unidos sempre se ferrava por causa das decisões da Sega do Japão. A falta que fazia mandar e-mails naquela época. Eles desenvolveram o 32X nos Estados Unidos pro Genesis sem saber que no Japão estava sendo desenvolvido o Saturn. Pensa a zona.</p>
<p>O Saturn ainda recebeu uma arquitetura super difícil de trabalhar com dois processadores paralelos. A maioria não sabe programar paralelo hoje, imagina naquela época. Daí acabavam só usando um dos processadores. Foi mais ou menos o mesmo problema que a Sony repetiu com o Playstation 3 e o famigerado CPU Cell com seus co-processadores paralelos, os SPUs. Até hoje o chip é considerado excepcional, mas era notoriamente difícil de programar. Tanto que só no final da sexta geração começaram a sair jogos que tiravam vantagem do processamento paralelo como o lendário The Last of Us original. E foi um dos motivos de porque a Sony perdeu essa geração pro XBox 360 da Microsoft, que era uma arquitetura muito mais simples de programar. Um canal que mostra vários jogos de Saturn é o canal do Sega Lord X, recomendo assistir pra ver se você nunca jogou Saturn.</p>
<p>Em termos de emuladores, o RPCS3 já consegue rodar muitos jogos de PS3 mas é bem pesado. Simular os SPUs sempre foi o desafio. E essas foram algumas das curiosidades que eu mais gosto sobre alguns dos meus videogames favoritos, mas tem toneladas de histórias a mais, tanto que existem canais de YouTube dedicados só nisso, como o The Gaming Historian ou Modern Vintage Games que já mencionei, recomendo que assistam o canal deles pra mais curiosidades assim. Mas o objetivo de hoje era dar uma pequeno overview, uma pincelada geral pra ver se vocês ficam interessados no assunto também. Eu acho que gosto mais de entender os mecanismos de como esses consoles e games funcionam, como eram construídos, que truques usavam, mais do que realmente jogar os jogos propriamente ditos.</p>
<p>Pra finalizar, deixa eu listar os emuladores que mais gosto pra vocês pesquisarem no Google e brincar. A maioria existe pra todas as plataformas e sistemas operacionais, incluindo Windows, Linux e rodam em Raspberry Pi que é fraquinho pros padrões hoje mas suficiente pra maioria dos emuladores. Mas se puder rodar num hardware pra Android melhor, eu recomendo. A maioria dos apps você encontra direto no Google Play Store. E o principal de todos é o RetroArch. Ele em si não é um emulador, mas uma interface pra vários emuladores, que são chamados de Cores. Nem todos funcionam bem ou de primeira, mas pelo RetroArch você consegue instalar os Cores online além de coisas como temas diferentes, artes das capas das caixas dos jogos, códigos de cheats, e diversas outras coisas. É um mundo em si só.</p>
<p>Quem gosta de Sony no próprio RetroArch tem cores de Playstation original. Tem o PCSX2 pra Playstation 2 que roda até que bem mas é pesado. Tem o RPCS3 que ainda não é muito estável e nem muito compatível mas se seu computador for potente deve rodar razoavelmente bem. E tem o PPSPP pro Vita, um dos meus favoritos, que roda muito bem. Jogos como Crisis Core rodam muito bem, mas God of War vai precisar de mais hardware pra rodar direito. E nem tentem rodar em Raspberry Pi, o hardware não é suficiente. Num smartphone mais novo deve rodar razoável, mas acima de PS2, recomendo um PC.</p>
<p>Pra quem gosta de Nintendo, o Nintendinho e Super Nintendo tem vários emuladores como o Mesen que já mencionei ou o Bsnes. E pelo RetroArch você baixa a maioria e é plug-and-play. Mas os mais interessantes são o Dolphin que consegue rodar bem jogos de Gamecube e Wii original, embora seja pesado. Tem o Citra que roda jogos de Nintendo 3DS muito bem. Mesmo no meu PC com Intel i7 alguns dão umas travadas e perde frame, então não é perfeito, mas tá evoluindo rápido. O mesmo vale pro Cemu que consegue rodar jogos de Wii U muito bem mas dá um puta trampo configurar. Se tiver paciência, vai poder jogar Zelda Breath of the Wild em Full HD com vários filtros que deixam o jogo mais bonito do que no Nintendo Switch. E falando em Switch tem o Yuzu que já roda vários jogos de Switch, mas eu mesmo não testei porque tenho um Switch.</p>
<p>Pra Sega, emuladores de mastersystem e genesis tem bastante no RetroArch, mas o mais difícil é o Saturn por causa da arquitetura complicada que expliquei antes. Mesmo assim, o emulador Yaba Sanshiro é bem competente e todo jogo que testei como Panzer Dragoon ou Sega Rally rodaram muito de boa mesmo num Android, então é o que recomendo. E quem gosta de Dreamcast tem o Redream que é pago, mas eu digo que vale a pena pagar porque é de longe o melhor emulador, que roda mais estável e mais compatível.</p>
<p>Finalmente, eu gosto muito de jogos de arcade então NEO GEO é essencial, mas eu mesmo odeio procurar emuladores, bios e configurações que funcionam direito então nem vou recomendar muito que se tente do zero. Eu me enchi tanto que preferi comprar no Mercado Livre o emulador que vem com as ROMS e tudo mais já pré-configurado pra MAME. MAME é de longe o emulador mais chato do mundo de configurar, eu não recomendo. É melhor achar pré-configurado. E a razão de ser tão chato é que arcades eram como um console específico feito só pra um ou um conjunto pequeno de jogos.</p>
<p>A Capcom tinha as famosas placas CPS1, os mais modernos usavam hardware derivado do Dreamcast, o Naomi. E se contar todas as placas criadas desde os anos 80, estamos falando de dezenas. E cada um tem uma configuração diferente. Configurar um a um na mão é um trabalho que não vale a pena. Se alguém tiver boas dicas de como facilmente configurar um bom emulador de Neo Geo pra Android, fiquem à vontade pra colocar nos comentários abaixo.</p>
<p>E sim, vou só listar os emuladores e não pretendo fazer vídeos de como configurar porque isso você vai achar toneladas de tutoriais em video e em blogs, bem detalhados. O próprio Wiki do RetroArch tem bastante documentação. Se você quer jogar jogos pirata, tem que fazer algum esforço ou gastar alguma grana pra comprar já configurado. Minha parte eu já fiz. Espero que tenham gostado dessa curta história dos videogames. Quem tem dúvidas ou histórias pra compartilhar, deixem nos comentários abaixo. Se curtiram o video mandem um joinha e compartilhe com seus amigos, assine o canal e não deixe de clicar no sininho pra não perder os próximos. A gente se vê, até mais!</p>
]]></content:encoded><category>emulacao</category><category>games</category><category>retrocomputacao</category><category>akitando</category></item><item><title>[Akitando] #87 Turing Complete, Emuladores e o Chip ARM M1</title><link>https://akitaonrails.github.io/2020/11/27/akitando-87-turing-complete-emuladores-e-o-chip-arm-m1/</link><guid isPermaLink="true">https://akitaonrails.github.io/2020/11/27/akitando-87-turing-complete-emuladores-e-o-chip-arm-m1/</guid><pubDate>Fri, 27 Nov 2020 20:00:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/kz3649U2sJY"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Continuando o assunto sobre máquinas de Turing hoje resolvi pegar parte do material que eu cortei do episódio anterior e aproveitar o lançamento do chip Apple M1 pra dar uma introdução ao assunto de emuladores usando aspectos das diferenças de arquitetura RISC/CISC e como ARM e x86 se comparam.&lt;/p&gt;
&lt;p&gt;Índice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;00:00 - Introdução&lt;/li&gt;
&lt;li&gt;01:10 - Turing Complete&lt;/li&gt;
&lt;li&gt;09:37 - Doom roda em QUALQUER lugar :-)&lt;/li&gt;
&lt;li&gt;11:58 - Apple M1 / ARM x x86&lt;/li&gt;
&lt;li&gt;21:40 - Pirataria&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ERRATA:&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/kz3649U2sJY"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h2>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Continuando o assunto sobre máquinas de Turing hoje resolvi pegar parte do material que eu cortei do episódio anterior e aproveitar o lançamento do chip Apple M1 pra dar uma introdução ao assunto de emuladores usando aspectos das diferenças de arquitetura RISC/CISC e como ARM e x86 se comparam.</p>
<p>Índice:</p>
<ul>
<li>00:00 - Introdução</li>
<li>01:10 - Turing Complete</li>
<li>09:37 - Doom roda em QUALQUER lugar :-)</li>
<li>11:58 - Apple M1 / ARM x x86</li>
<li>21:40 - Pirataria</li>
</ul>
<p>ERRATA:</p>
<p>No teste de gravidez, eu não prestei atenção e deixei passar que na verdade o @foone teve que trocar alguns componentes então o teste de gravidez não foi usado 100% como veio de fábrica e portanto NÃO, ele não é um computador universal também 🤷‍♂️ de qualquer forma fica o conceito, de que poderia ser, se rodasse Doom ;-) <a href="https://twitter.com/renatomefi/status/1332694946575486978?s=20"target="_blank" rel="noopener">https://twitter.com/renatomefi/status/1332694946575486978?s=20</a></p>
<p>Links:</p>
<ul>
<li>Tom Scott: Are There Problems That Computers Can&rsquo;t Solve? (<a href="https://www.youtube.com/watch?v=eqvBaj8UYz4"target="_blank" rel="noopener">https://www.youtube.com/watch?v=eqvBaj8UYz4</a>)</li>
<li>Foone: Doom Pregnancy Test (<a href="https://twitter.com/Foone/status/1302820468819288066?s=20"target="_blank" rel="noopener">https://twitter.com/Foone/status/1302820468819288066?s=20</a>)</li>
<li>Matthew Monis: MacBook Pro 13 Review - This M1 is Insane! (<a href="https://www.youtube.com/watch?v=BUBYO591Fo8"target="_blank" rel="noopener">https://www.youtube.com/watch?v=BUBYO591Fo8</a>)</li>
<li>The Untold Story Of The Invention Of The Game Cartridge (<a href="https://www.fastcompany.com/3040889/the-untold-story-of-the-invention-of-the-game-cartridge"target="_blank" rel="noopener">https://www.fastcompany.com/3040889/the-untold-story-of-the-invention-of-the-game-cartridge</a>)</li>
</ul>
<h2>TRANSCRIPT<span class="hx:absolute hx:-mt-20" id="transcript"></span>
    <a href="#transcript" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Olá pessoal, Fabio Akita</p>
<p>Fiquei contente que vocês gostaram do episódio que contei um pouco mais sobre a máquina de Turing e a arquitetura de Von Neumann. Aquele episódio tinha ficado grande e eu tive que cortar um trecho enorme pra não perder a linha de raciocínio do que eu queria contar. O trecho era tão grande na real, que era praticamente outro episódio.</p>
<p>Pois é, no processo de escrever os textos e um dos motivos de porque eu não gosto de fazer live, é que eu faço muita tangente e aí o assunto fica mais complicado do que devia. Mesmo cortando eu ainda faço tangente. Ainda estou praticando cortar coisas, mas vira e mexe acontece de eu escrever 30 páginas e cortar 10 fora, como é o caso do material de hoje.</p>
<p>Então a primeira metade do video de hoje vai ser tipo a edição estendida director’s cut continuando o video anterior, mas a segunda metade vou começar a falar sobre emuladores e até dar uma palhinha do que eu acho dos novos chips Apple M1 no contexto de emulação e arquitetura. Mas isso vai ser introdução também pro próximo episódio onde vou cair mais no meu lado geek e falar de videogames.</p>
<p>(&hellip;)</p>
<p>Eu nasci no fim dos anos 70. A revolução dos micro-computadores nasceu praticamente junto comigo. Por exemplo, a Atari foi fundada em 1972, a Microsoft em 75, a Apple em 76. No mesmo ano que eu nasci também nascia o computador PET, o antecessor da linha Commodore que sairia em 82. O padrão MSX nasceu em 83. O Sinclair ZX Spectrum nasceu em 82 e no Brasil ele foi clonado pela Microdigital e virou o venerado TK 90X, que eu queria ter quando criança mas não pude.</p>
<p>No caso do TK 90X ele usava processador Zilog Z80, o mesmo também usado no Sega Mastersystem que fez muito sucesso no Brasil, fabricado pela Tectoy e que existe até hoje. Outros modelos de micros como o Apple II ou Commodore 64 ou mesmo o Atari 2600 usavam o MOS 6502 ou sua evolução, o 65C02, que eu introduzi no episódio do Guia mais Hardcore de Introdução à Computação.</p>
<p>Esse mesmo processador equipava o Nintendinho original de 8-bits. E mesmo o Super Nintendo usa o processador da família do 65816 que é baseado na arquitetura e instruções do 6502, meio como um Intel Core i5 de hoje é uma evolução dos Pentium de antigamente e ainda são compatíveis. Recomendo que assistam meu episódio também de Aprendendo sobre Computadores com Super Mario pra entender um pouco de como as instruções do 6502 funcionam na prática.</p>
<p>Essa conversa toda foi só pra voltar no conceito de máquinas Turing Universais ou UTMs. Pra recapitular, uma máquina de Turing, a abstração, é basicamente uma máquina com um leitor que consegue ler um bit de cada vez de uma fita infinita, consegue mover essa fita pra esquerda ou pra direita, e além de ler consegue mudar o valor de um bit de cada vez. Mesma coisa o console de um Nintendinho, onde é possível representar tudo que compõe o console com um número descritivo, porque ele é uma máquina de Turing.</p>
<p>Um cartucho é um conjunto de chips de ROM. Dentro dessa ROM tá gravado o programa do jogo e os dados como os sprites, imagens e áudio que compõem o jogo. Mas é basicamente tudo uma sequência de bits. Poderíamos escrever os bits todos numa fita. E de fato, antigamente a gente gravava programas e jogos em fitas cassete. Quem é dos anos 80 deve se lembrar. Era lento pra cacete, mas disk drives ainda eram muito mais caros. Mesmo um disco que tem num HD mecânico ou um CD-ROM é uma fita de discos em círculo na mídia.</p>
<p>O cartucho é como se fosse a tal fita na máquina de Turing. Mais do que isso, sem pensar que existem todos esses elementos separados, do ponto de vista da fita ou sequência de bits, são zeros e uns um atrás do outro. Se não ficou claro, vamos pegar um trecho de assembly que eu mostrei no episódio do guia de introdução à computação, instruções do 6502. Lá pelo minuto 49 do vídeo eu mostro uma sequência de instruções, lda ff, sta 60 02. Vamos considerar que o programa são só essas duas linhas. Em hexadecimal isso viraria a9 ff 8d 02 60. Em binário isso viraria esse numerozão aqui do lado. Se eu jogar na calculadora, e convertermos pra decimal, essas duas linhas de código podem ser representados pelo número trezentos e sessenta e cinco mil e tra la la que você pode ver aqui do lado. Entendeu? O programa É esse número.</p>
<p>1010 1001 11111111 1000 1101 0000 0010 1100000
365068452192</p>
<p>Zeros e uns um atrás do outro é basicamente um numerozão, em binário. No caso do cartucho do Super Mario é um numerozão de mais de trezentos e vinte mil dígitos binários ou bits, pra ser mais exato, porque são 40 kilobytes vezes um mil e vinte e quatro pra termos em bytes e vezes oito pra termos quantos bits, já que 8 bits é 1 byte. Todo programa, não importa o comprimento, é um numerozão. Todo programa que você já escreveu ou vai escrever pode ser representado por um único número gigante.</p>
<p>Não só o cartucho por ser representado por um número, mas o funcionamento do nintendinho inteiro também pode ser representado por um numerozão. Uma máquina universal de Turing pode pegar o tal número descritivo de uma máquina de Turing, como o tal numerozão que representa o Nintendinho inteiro e simular. E o resultado dessa simulação vai ser exatamente a mesma da máquina de Turing correspondente, o console de verdade. Então, uma característica importante de uma UTM é sua capacidade de &ldquo;simular&rdquo; qualquer outra máquina de Turing.</p>
<p>Resumindo. Uma máquina de Turing ou máquina de computar é um modelo abstrato capaz de ter um número finito de configurações ou estados. Ele é alimentado com uma fita infinita de bits. A cada momento a máquina tá escaneando somente um símbolo dessa fita de cada vez, e é automática porque a cada momento o estado da máquina é determinado pelo símbolo, ou bit que ele tá lendo naquele instante. A grosso modo, pense numa máquina de Turing como uma função ou método de qualquer linguagem de programação moderna.</p>
<p>O tal número descritivo representa o corpo dessa função, o binário do programa. Esse número descritivo ou programa manipula números computáveis, que na prática é quase todo número que você consegue pensar. E usa o que Turing chamou de funções computáveis. De curiosidade, ao contrário dos números, nem toda função é computável e existe muito mais funções não-computáveis do que computáveis na real. Portanto uma máquina de Turing Não consegue computar qualquer coisa. Existem funções que ela não tem capacidade de resolver.</p>
<p>Isso é um conceito importante porque a intuição popular é que dado tempo suficiente pra evolução de chips e processadores, qualquer problema deveria ser possível de resolver com um computador. Porém vale saber que existem problemas que um computador de Turing nunca vai resolver. Um exemplo disso é o Halt Problem. E como é muita tangente pra hoje, recomendo assistir a explicação do Tom Scott, que é outro canal que eu sigo faz anos. Apenas lembre disso: existem problemas que são impossíveis de resolver com um computador. E não, um computador quântico ainda é uma máquina universal de Turing. Daqui algumas décadas tem a possibilidade de ser ridiculamente mais rápido que hoje, sem dúvida, mas não vai ter mais capacidades nem vai ser capaz de resolver problemas que já não se resolve hoje.</p>
<p>De qualquer forma, uma Universal Turing Machine é uma máquina que pode pegar o número descritivo de alguma máquina de Turing e simular ela perfeitamente. Então, pra resolver problemas de computação, você pode escolher uma máquina de Turing adequada pra um problema específico, já que cada máquina só consegue executar uma tarefa. Lembrem-se que antes disso uma máquina mecânica era construída pra resolver só um tipo de problema. Agora você pode pegar uma máquina Universal, carregar o número descritivo ou programa, que é o tal numerozão que expliquei antes, e simular diversas máquinas de Turing. Esse é o conceito moderno de programação e computadores derivado dos papers de Alan Turing.</p>
<p>Na prática, computadores reais não são máquinas de Turing nem máquinas Universais, pelo simples fato que elas tem limites e a definição matemática tem o ideal de memória infinita. Mas, pra todos os efeitos e propósitos, a revolução de Alan Turing foi conseguir definir a idéia e conceitos de uma máquina de uso geral, em vez de uma máquina especializada como calculadoras por exemplo. Uma máquina de Turing seria o que chamamos de “programa”, o tal número descritivo seria a implementação desse programa, uma máquina Universal é o computador propriamente dito que consegue rodar diversos programas diferentes.</p>
<p>Alguém me perguntou uma vez se uma calculadora ou um ábaco não poderiam ser computadores já que “computam” números. E é uma pergunta válida. Tecnicamente uma calculadora “e” um computador, intuitivamente, são máquinas de calcular. E quando eu falo calculadora não estou falando de coisas como a TI-83 que todo engenheiro que se preze conhece e usa. Uma TI-83 é definitivamente um computador inteiro, que carrega programas de calcular e plotar gráficos e por isso consegue até rodar Doom nele. Estou falando daquelas calculadoras velhas que se tinha nas mesas antigamente.</p>
<p>Na minha definição informal e não-rigorosa, eu costumo pensar num computador como uma máquina que consegue simular qualquer outro computador, mesmo que bem mais lento. Performance não define um computador, suas capacidades sim. E uma linguagem Turing Complete, pra mim, é uma linguagem que consegue programar a simulação de outro computador. Se uma determinada máquina consegue rodar um emulador, pra mim é uma máquina universal. E se a linguagem de programação é capaz de escrever um emulador, pra mim ela é Turing Complete. É uma definição parcial, mas eu gosto dela porque é bem prática. Não consegue escrever um emulador, essa linguagem não é Turing Complete. Não consegue rodar um emulador, então não é um computador.</p>
<p>Recentemente um usuário que eu sigo no Twitter faz tempo, o @foone, ganhou o noticiário porque ele fez Doom rodar num teste de gravidez! Pois é, a miniaturização chegou num tal ponto que dentro de um mísero teste de farmácia, daqueles que tem uma telinha LCD bem podrona, tem um CPU turing complete, capaz de minimamente executar um jogo ao ponto dele aparecer na tela e rodar. Lento, feio, mas roda. Pára pra pensar numa coisa, todo teste de gravidez mais moderno é um computador inteiro, com um programa feito pra rodar só uma vez e depois você jogar no lixo! Isso tudo dito, não, ábaco não é um computador, a calculadora antiga de mesa não é um computador, mas um teste de gravidez como esse definitivamente é um computador.</p>
<p>Toda vez que alguém fala coisas como &ldquo;nossa, conseguiram rodar Doom numa TI-83 ou numa câmera fotográfica&rdquo; lógico, eu acho impressionante que alguém se deu a esse trabalho, mas eu não acho surpreendente porque mesmo um computador fraco é capaz de simular outro computador, só vai ser super lento. Mesma coisa quando alguém se impressiona quando vê uma distribuição Linux ou mesmo Windows 95  rodando no Chrome ou Firefox, emulado via Javascript. Não me surpreende, mas certamente impressiona, especialmente se você for iniciante.</p>
<p>Eu entendo a sensação. Eu me sentia da mesma forma nos anos 90, quando eu tinha um PC no nível de um 486 ou Pentium, que sequer tinha 32 MEGAbytes de RAM, e de repente eu tava conseguindo emular um nintendinho, que não fazia 10 anos só era possível jogar com um console de verdade. Ou a primeira vez que eu instalei o sistema operacional OS/2 que vinha com um emulador de MS-DOS e era possível até iniciar Windows 3.1 e rodar lado a lado dentro do OS/2. De qualquer forma, esses conceitos explodiam minha mente nos anos 90 e eu entendo que todo iniciante que vê isso pela primeira vez, mesmo hoje, deve ficar impressionado.</p>
<p>Agora, falando especificamente de emuladores. Um emulador simula um chip de outro computador via software. Quando um emulador carrega o jogo de um cartucho, o jogo em si não tem idéia que tá rodando num emulador. Pra todos os efeitos e propósitos, se o jogo tivesse consciência, ele não teria dúvidas que tá rodando no console de verdade. No máximo ia estranhar, “nossa, tá mais rápido esse hardware hoje”. Esse é o Matrix de verdade e eu falei um pouco disso no meu episódio sobre virtualização, dêem uma olhada.</p>
<p>Em particular sobre as discussões de ARM versus x86 que tá na moda agora, isso é um daqueles eventos que só acontece um a cada vinte anos. Eu usava Macs em 2006 quando aconteceu a transição de PowerPC pra Intel. Não vou entrar em detalhes dessas histórias porque nesse momento todo canal de tech no YouTube já tem vídeos a respeito e seria só ser redundante. Mas é relevante notar que em 2006 a Apple saiu de uma arquitetura RISC, de instruções reduzidas, pra Intel que tem instruções complexas. Agora ela tá fazendo o oposto, saindo de instruções complexas e indo pra arquitetura ARM, que é um RISC, de instruções reduzidas.</p>
<p>Pra nós programadores, uma coisa interessante é a camada Rosetta 2 que tem nos Mac OS a partir do Big Sur. Ele é um emulador pra conseguir executar binários legados de x86, convertendo as instruções pra ARM. Assim ele consegue rodar programas que não foram recompilados e atualizados pro novo chip M1. Todo reviewer tá com a cabeça explodindo porque o M1 já é mais rápido que modelos de notebooks PC comparáveis em preço aos novos Macbook Air ou Macbook Pro 13 polegadas.</p>
<p>Mais do que isso, todo mundo achava que rodar um Photoshop ou Premiere sendo emulado pelo Rosetta seria provavelmente lento. E eles tão abismados como a performance não só tá aceitável, mas tá realmente rápido, sem engasgos nem nada. Bem diferente de quando pulamos de PowerPC pra Intel em 2006. Sério, eu lembro de usar o primeiro Rosetta nos Macbook brancos Intel e rodar qualquer coisa pelo Rosetta era super lento. Dava desgosto de usar. Mas nos M1 de agora, ao que tudo indica, vai rodar quase que igual à velocidade de quando rodava no Macbook Intel.</p>
<p>Eu fiquei pensando sobre isso e vale lembrar um dos motivos possíveis. Todo mundo tá cansado de ouvir que a diferença de chips x86 e ARM é que um tem instruções mais complexas e o outro tem instruções mais simples. Pense por um segundo no que isso significa. A cada clock o processador executa uma ou mais instruções. Quanto mais instruções for possível executar por clock, maior a velocidade e menor o consumo de energia. O problema de instruções de complexidade variada é que é difícil de adivinhar quantas instruções dá pra rodar a cada clock. Pra ser mais exato, uma instrução x86 pode ser de um até 15 bytes de comprimento.</p>
<p>Por causa disso um processador Intel costuma executar algo em torno de quatro instruções por clock. Isso é horrível, porque faz de conta que chegamos numa parte do programa que tem 10 instruções simples de um ou 2 bytes um atrás do outro. Talvez o processador pudesse rodar oito, dez ou mais instruções dessas no mesmo clock. Mas como nem sempre dá pra saber se cabe ou não, ele roda só quatro. E fazendo isso ele tá desperdiçando clock, desperdiçando energia. E sem mudar a arquitetura de instruções, o pipeline sempre vai ser curto e isso é inerente a ser um x86.</p>
<p>Agora, processadores ARM tem instruções ou de 16 ou de 32 bits, ou seja, de 2 ou 4 bytes. E só. E eles não se misturam. Ou você tá executando instruções de 32-bits ou de 16-bits. Pra mudar entre um ou outro você manda uma instrução pra mudar o mode. Isso significa que você sempre sabe exatamente o tamanho das instruções e com isso pode configurar um pipeline mais longo por clock. Em particular, o chip M1 da Apple consegue executar oito instruções por clock. Só em profundidade desse pipeline, um chip M1 de 2Ghz tem potencial de ser duas vezes mais veloz e eficiente do que um chip Intel equivalente de 2Ghz. Mais do que isso, um chip M1 de 2Ghz pode ser competitivo com um chip Intel de 3 ou até 4Ghz, por isso você tanto ganho de bateria e menos calor sendo dissipado.</p>
<p>Mas não é só isso. Considere o aspecto de emulação. Pra um chip ARM emular Intel é relativamente mais fácil do que Intel emular ARM. Por que? Porque como ARM tem instruções simples, ou seja, mais básicas, ela consegue emular facilmente qualquer instrução mais complexa de Intel. Por exemplo. Pra facilitar a explicação imagina se fossem processadores gráficos. Digamos que em ARM existam funções como desenhar uma linha, desenhar um círculo, desenhar um triângulo.</p>
<p>Porém, em Intel existem funções mais complexas como, desenhar um botão, desenhar uma janela. Entenderam o que significa quando se fala em diferença de complexidade? Um só desenha linhas o outro numa única instrução já desenha um botão inteiro. Com instruções nesse ARM hipotético, como desenhar linha, eu consigo desenhar os botões ou janelas. Só vai dar mais trabalho porque eu preciso desenhar linha a linha. Se eu fosse um programador de assembly que precisa usar só essas instruções, seria um parto fazer isso. Mas como hoje escrevemos tudo em C ou outras linguagens, não faz diferença. Quem vai ter mais trabalho vai ser o compilador e não o programador. Agora, se eu só tenho instruções complexas, como desenhar o botão inteiro, como que eu desenho só uma linha? Fácil, eu faço um botão com 1 pixel de comprimento. Só que agora eu tô gastando o tempo de processamento de desenhar um botão inteiro pra fazer uma simples linha, portanto vai ser mais lento.</p>
<p>Pra piorar a situação, pra rodar instruções de x86, você precisa fazer o equivalente a passar argumentos pra uma função, como num javascript por exemplo. No caso, os argumentos você preenche em registradores e depois chama a instrução, que seria o equivalente de uma função. Ou seja, existe um número limitado de argumentos que uma instrução pode receber, porque existem poucos registradores, que funcionam como variáveis globais numa linguagem como Javascript ou PHP. Pois bem, processadores x86 como Intel de 32-bits possui só 8 registradores de uso geral. Os processadores x86 de 64-bits que a maioria de nós usa hoje tem 16 registradores de uso geral.</p>
<p>Adivinha quantos registradores tem um processador ARM de 32-bits? Dezesseis! E quantos tem o ARMv8 de 64-bits? Trinta e dois registradores. O dobro dos equivalentes x86. Ou seja, fodeu, pra um Intel emular uma instrução ARM que tem o dobro de registradores, ele vai ser obrigado a fazer vários truques pra lidar com argumentos que não cabem em todos os registradores que ele tem, e, de novo, a performance vai ser necessariamente mais baixa. No lado oposto, um chip Apple M1 que é um ARM de 64-bits, ele consegue facilmente emular qualquer instrução de x86 64 bits, porque tem registradores sobrando. Então a programação não precisa de truques, é super direto.</p>
<p>No frigir dos ovos? É uma ordem de grandeza mais simples e mais performático pra um processador ARM emular binários de x86 do que o oposto. O Rosetta de de 2006 era lento, porque ele tava justamente na situação oposta: precisava fazer os antigos processadores Intel dos novos Mac emular binários legados de PowerPC que é uma arquitetura RISC como ARM, era o caso de ter que usar uma função complexa que desenha um botão e desperdiçar o processamento pra emular uma linha.</p>
<p>É um dos motivos de porque é mais difícil ter emuladores de processadores RISC rodando bem em cima de um processador Intel. Por exemplo, até hoje não é performático emular os antigos PowerPC pra rodar Mac antigo. Da mesma forma é lento emular chips de smartphone, como os da Qualcomm que tem na maioria dos celulares Android que usamos. Já o inverso é mais rápido. Por isso eu fiquei um pouco decepcionado com o processador SQ1 que a Microsoft criou em parceria com a Qualcomm pra equipar os Surface Pro X.</p>
<p>O SQ1 é um Apple M1 piorzinho. Também é um chip ARM e tá rodando Windows 10 compilado pra ARM, como o Big Sur no caso do Mac. E pra rodar programas legados de x86, ele também roda um emulador. Até hoje tá limitado a rodar binários de 32-bits e mesmo assim roda muito lento. Tá pra sair o suporte a emular binários de 64-bits, e a expectativa é que seja um pouco melhor, mas mesmo assim ainda atrás da Apple. Talvez você nem tenha ouvido falar do Surface Pro X, mas não é de hoje que a Microsoft vem tentando usar chips ARM também. A Apple não foi a primeira, mas pra variar, foi a que entregou mais bem feito.</p>
<p>O fato de emular x86 em cima de ARM não ser tão difícil e não representar uma perda tão significativa de performance é importante, porque com Windows, MacOS e Linux ganhando cada vez mais otimizações pra ARM, significa que a hegemonia da Intel tá com os dias contados. Por causa dos smartphones a tecnologia ARM evoluiu bastante e em ambiente móvel, a Intel simplesmente não tem como competir. E agora esses processadores tão pulando pra notebooks e desktop, e já tão bons. E com emuladores ninguém vai ficar preso em Intel por causa de aplicativos legados. E se esse caminho der certo, em breve esses chips ARM vão invadir em massa o ambiente de servidores. Aliás, o maior supercomputador do mundo já usa ARM. E isso poderia representar o último prego no caixão da Intel. Ela vai precisar se mexer rápido pra evitar isso.</p>
<p>Eu vou falar um pouco mais sobre ARM no próximo episódio, mas de qualquer forma a comunidade de desenvolvimento de emuladores é grande. Eu sempre fico impressionado porque na maior parte são voluntários trabalhando só pelo prazer de ver as coisas funcionando mesmo, já que não se pode ganhar muito dinheiro em cima de jogos que ainda tem licenças e copyrights, especialmente se mexer em consoles da Nintendo. Nunca mexa com a Nintendo, é processo garantido e muita diversão pra se livrar. A única exceção é se você vive na China, daí você tá seguro.</p>
<p>Não dá pra falar de emuladores e não tocar no assunto de pirataria. É um assunto controverso, ser a favor ou contra direitos autorais e eu vou dizer que sou neutro nessa discussão. Não tenho uma solução completa nem pra um lado, nem pro outro. Então não vou tentar argumentar hoje. Mas sim, como todo mundo, eu já pirateei muito quando era moleque. Eu teria tido muito mais dificuldade pra começar a ganhar dinheiro se não fosse pela pirataria naquela época, então tem esse ponto mesmo. Hoje em dia não tenho esse problema, então não tenho motivos pra piratear e pago tudo que eu uso, acho justo.</p>
<p>Mesmo assim, existem software antigos especialmente de lugares como Japão por exemplo, que mesmo eu querendo comprar, não existe pra vender, e nesse caso a pirataria tem a função de preservar software do passado. E isso é outro fator importante. Então, se você é a favor ou contra, não sou eu que vou te julgar. Isso tudo dito, assim como todo YouTuber que fala do assunto, eu não vou dizer onde você encontra jogos pirata, mas qualquer um que saiba usar Google e sabe diferenciar de um malware, vai achar o que procura sem muito trabalho.</p>
<p>E por hoje é isso aí! Já divaguei bastante e vai ter mais nerdice no próximo episódio. Eu sei que o assunto do Apple M1 tá na cabeça do povo, mas não pretendo fazer um video só sobre isso porque já tem bastante, mas de vez em quando vou salpicando algumas curiosidades como fiz hoje e vou fazer no próximo. Se ficaram com dúvidas não deixem de mandar nos comentários, se curtiram o video mandei um joinha e compartilhem o video com seus amigos, assinem o canal e não deixem de clicar no sininho pra não perder os próximos videos. A gente se vê, até mais!</p>
]]></content:encoded><category>ciencia-da-computacao</category><category>emulacao</category><category>hardware</category><category>akitando</category></item><item><title>[Akitando] #81 - Aprendendo sobre Computadores com Super Mario (do jeito Hardcore++)</title><link>https://akitaonrails.github.io/2020/06/18/akitando-81-aprendendo-sobre-computadores-com-super-mario-do-jeito-hardcore/</link><guid isPermaLink="true">https://akitaonrails.github.io/2020/06/18/akitando-81-aprendendo-sobre-computadores-com-super-mario-do-jeito-hardcore/</guid><pubDate>Thu, 18 Jun 2020 10:00:00 -0300</pubDate><description>&lt;div class="embed-container"&gt;
&lt;iframe
src="https://www.youtube.com/embed/hYJ3dvHjeOE"
title="YouTube video player"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
referrerpolicy="strict-origin-when-cross-origin"
allowfullscreen&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h3&gt;DESCRIÇÃO&lt;span class="hx:absolute hx:-mt-20" id="descrição"&gt;&lt;/span&gt;
&lt;a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Errata: em 17:12 eu disse certo mas na equação faltou mostrar dividindo tudo por 2. Em 13:00 eu claramente faltei na aula porque 278 x 7 é 1946 😅&lt;/p&gt;
&lt;p&gt;Você não precisa ter assistido o video anterior pra entender este, mas certamente ajuda.&lt;/p&gt;
&lt;p&gt;Hoje vou acelerar na missão de fazer vocês entenderem como computadores em geral funcionam por baixo dos panos usando um Nintendinho e o Super Mario como guias nesta jornada.&lt;/p&gt;</description><content:encoded><![CDATA[

<div class="embed-container">
  <iframe
    src="https://www.youtube.com/embed/hYJ3dvHjeOE"
    title="YouTube video player"
    frameborder="0"
    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share"
    referrerpolicy="strict-origin-when-cross-origin"
    allowfullscreen>
  </iframe>
</div>

<h3>DESCRIÇÃO<span class="hx:absolute hx:-mt-20" id="descrição"></span>
    <a href="#descri%c3%a7%c3%a3o" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Errata: em 17:12 eu disse certo mas na equação faltou mostrar dividindo tudo por 2. Em 13:00 eu claramente faltei na aula porque 278 x 7 é 1946 😅</p>
<p>Você não precisa ter assistido o video anterior pra entender este, mas certamente ajuda.</p>
<p>Hoje vou acelerar na missão de fazer vocês entenderem como computadores em geral funcionam por baixo dos panos usando um Nintendinho e o Super Mario como guias nesta jornada.</p>
<p>Não tentem entender tudo na primeira assistida. Eu mesmo não conseguiria. Assista até o fim pra ter a visão completa depois retorne pra partes específicas pra pegar em mais detalhes.</p>
<p>Já aviso que os primeiros Vinte Minutos podem parecer um pouco devagar, porque vou complementar o que comecei no video anterior, mas garanto que depois disso vem o filé mignon do filé mignon. Vamos ver como se constrói um emulador, como cartuchos funcionam, como começar a editar jogos e a entender como se começa a pensar em fazer jogos retrô, e vamos até falar de speedrun e hackear bugs de jogos. Tudo isso num único episódio!</p>
<p>Links:</p>
<ul>
<li>
<p>Super Mario Bros. 3 - Wrong Warp (<a href="https://www.youtube.com/watch?v=fxZuzos7Auk"target="_blank" rel="noopener">https://www.youtube.com/watch?v=fxZuzos7Auk</a>)</p>
</li>
<li>
<p>A Comprehensive Super Mario Bros. Disassembly (<a href="https://gist.github.com/1wErt3r/4048722"target="_blank" rel="noopener">https://gist.github.com/1wErt3r/4048722</a>)</p>
</li>
<li>
<p>Lembra deles? Confira jogos brasileiros do Master System lançados pela Tectoy! (<a href="https://blogtectoy.com.br/lembra-deles-todos-jogos-brasileiros-do-master-system-lancados-pela-tectoy/"target="_blank" rel="noopener">https://blogtectoy.com.br/lembra-deles-todos-jogos-brasileiros-do-master-system-lancados-pela-tectoy/</a>)</p>
</li>
<li>
<p>Free NES assembler (<a href="https://bisqwit.iki.fi/source/nescom.html"target="_blank" rel="noopener">https://bisqwit.iki.fi/source/nescom.html</a>)</p>
</li>
<li>
<p>Micro Mages (<a href="https://morphcatgames.itch.io/micromages"target="_blank" rel="noopener">https://morphcatgames.itch.io/micromages</a>)</p>
</li>
<li>
<p>Nes Dev Wiki (<a href="https://wiki.nesdev.com/w/index.php/Nesdev_Wiki"target="_blank" rel="noopener">https://wiki.nesdev.com/w/index.php/Nesdev_Wiki</a>)</p>
</li>
<li>
<p>Computer Archeology - The Legend of Zelda (<a href="https://www.computerarcheology.com/NES/Zelda/"target="_blank" rel="noopener">https://www.computerarcheology.com/NES/Zelda/</a>)</p>
</li>
<li>
<p>6502 Instruction Set (<a href="https://www.masswerk.at/6502/6502_instruction_set.html"target="_blank" rel="noopener">https://www.masswerk.at/6502/6502_instruction_set.html</a>)</p>
</li>
<li>
<p>An introduction to 6502 math: addiction, subtraction and more (<a href="http://retro64.altervista.org/blog/an-introduction-to-6502-math-addiction-subtraction-and-more/"target="_blank" rel="noopener">http://retro64.altervista.org/blog/an-introduction-to-6502-math-addiction-subtraction-and-more/</a>)</p>
</li>
<li>
<p>Explain Half Adder and Full Adder with Truth Table (<a href="https://www.elprocus.com/half-adder-and-full-adder/"target="_blank" rel="noopener">https://www.elprocus.com/half-adder-and-full-adder/</a>)</p>
</li>
<li>
<p>Build a multiplying machine using NAND logic gates (<a href="https://codegolf.stackexchange.com/questions/12261/build-a-multiplying-machine-using-nand-logic-gates"target="_blank" rel="noopener">https://codegolf.stackexchange.com/questions/12261/build-a-multiplying-machine-using-nand-logic-gates</a>)</p>
</li>
<li>
<p>Tool Assisted Game Movies (<a href="http://tasvideos.org/"target="_blank" rel="noopener">http://tasvideos.org/</a>)</p>
</li>
<li>
<p>RETRO INSECTIVORES: FINDING AND ELIMINATING BUGS IN NES DEVELOPMENT (<a href="https://megacatstudios.com/blogs/press/retro-insectivores-finding-and-eliminating-bugs-in-nes-development"target="_blank" rel="noopener">https://megacatstudios.com/blogs/press/retro-insectivores-finding-and-eliminating-bugs-in-nes-development</a>)</p>
</li>
<li>
<p>FCEUX (<a href="https://sourceforge.net/projects/fceultra/"target="_blank" rel="noopener">https://sourceforge.net/projects/fceultra/</a>)</p>
</li>
<li>
<p>Zelda Screen Transitions are Undefined Behaviour (<a href="https://gridbugs.org/zelda-screen-transitions-are-undefined-behaviour/"target="_blank" rel="noopener">https://gridbugs.org/zelda-screen-transitions-are-undefined-behaviour/</a>)</p>
</li>
<li>
<p>NES Emulator Debugging (<a href="https://gridbugs.org/nes-emulator-debugging/"target="_blank" rel="noopener">https://gridbugs.org/nes-emulator-debugging/</a>)</p>
</li>
<li>
<p>Two&rsquo;s Complement Multiplication (<a href="http://pages.cs.wisc.edu/~david/courses/cs354/beyond354/int.mult.html"target="_blank" rel="noopener">http://pages.cs.wisc.edu/~david/courses/cs354/beyond354/int.mult.html</a>)</p>
</li>
<li>
<p>NES Hello World (<a href="https://www.embed.com/nes/hello-world.html"target="_blank" rel="noopener">https://www.embed.com/nes/hello-world.html</a>)</p>
</li>
<li>
<p>DF Direct: CRT Displays - Was LCD A Big Mistake For Gaming? (<a href="https://www.youtube.com/watch?v=tvRyVZWuvQ4"target="_blank" rel="noopener">https://www.youtube.com/watch?v=tvRyVZWuvQ4</a>)</p>
</li>
<li>
<p>DF Direct! Modern Games Look Amazing On CRT Monitors&hellip; Yes, Better than LCD! (<a href="https://www.youtube.com/watch?v=V8BVTHxc4LM"target="_blank" rel="noopener">https://www.youtube.com/watch?v=V8BVTHxc4LM</a>)</p>
</li>
<li>
<p>Mod pra Wonderboy II Turma da Monica (<a href="https://www.youtube.com/watch?v=zQCm_y31SC0"target="_blank" rel="noopener">https://www.youtube.com/watch?v=zQCm_y31SC0</a>)</p>
</li>
<li>
<p>Meu fork do emulador de NES em Go (<a href="https://github.com/akitaonrails/nes"target="_blank" rel="noopener">https://github.com/akitaonrails/nes</a>)</p>
</li>
<li>
<p>Meu código do decodificador de código de Game Genie (<a href="https://github.com/akitaonrails/gamegenie"target="_blank" rel="noopener">https://github.com/akitaonrails/gamegenie</a>)</p>
</li>
</ul>
<p>Assinem estes canais:</p>
<ul>
<li>Retro Game Mechanics Explained (<a href="https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g"target="_blank" rel="noopener">https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g</a>)</li>
<li>One Lone Coder (<a href="https://www.youtube.com/channel/UC-yuWVUplUJZvieEligKBkA"target="_blank" rel="noopener">https://www.youtube.com/channel/UC-yuWVUplUJZvieEligKBkA</a>)</li>
</ul>
<h3>SCRIPT<span class="hx:absolute hx:-mt-20" id="script"></span>
    <a href="#script" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Olá pessoal, Fabio Akita</p>
<p>O tema do video da semana passada é um buraco de coelho de Alice no País das maravilhas. Estou demorando pra soltar videos porque cada assunto que eu esbarro vou pesquisar e abro mais uma dúzia de abas. Daqui a pouco vou encher meus 32GB de RAM só de abas. Computação retro é uma área gigantesca. Vocês não imaginam quantas comunidades existem não só colecionando itens antigos mas ainda desenvolvendo em assembly de MOS 6502 e outros processadores antigos como Z80, Intel 8088 e isso só no mundo dos 8-bits. Se entrar em 16-bits vai cair em processadores como o 65C816 do Super NES.</p>
<p>Eu reescrevi o script de hoje várias vezes, numa das versões eu estava gastando páginas e páginas só pra tentar explicar o problema da multiplicação em processadores antigos. Mas ficou muito fora do escopo do canal. Só pra dar um gostinho, no último video comecei a mostrar um pouco do Assembly do 6502 e algumas instruções básicas como LDA ou STA pra dar load no acumulador ou store do acumulador pra algum outro lugar.</p>
<p>Avançando pra operações aritméticas temos instruções como ADC ou SBC pra adição e subtração. Você já começaria coçando a cabeça quando precisasse somar números maiores do que 255, que é o limite que cabe em 1 byte, ou 8-bits. Lembra que o 6502 é uma CPU de 8-bits? Então todas as instruções só conseguem trabalhar com 8-bits de uma só vez. Pra trabalhar com números maiores a gente particiona o número e calcula 1 pedaço de 1 byte de cada vez. Vamos entender um pouco mais disso.</p>
<p>Como todo mundo pelo menos já deve ter ouvido falar, chips como o 6502 são feitos de componentes menores, como um transistor. Um transistor, em sua essência é um componente que funciona como um switch, ou interruptor. Acho que essa é a imagem mais simples de ter na cabeça. Você pode comprar transistors individualmente empacotados como um componente mais fácil de manipular num protoboard como esse aqui (video).</p>
<p>Aliás, no video anterior eu chamei isso de breadboard que é como falam nos Estados Unidos, mas aqui se chama protoboard. Enfim, usando transistores é possível criar alguns dos circuitos mais simples de todos, as portas lógicas, que são peças fundamentais sobre as quais todo o resto é montado. Por exemplo, você pode montar uma porta lógica NOT num protoboard com um transistor, um resistor, um led pra ver a resposta, uma bateria e fios pra conectar. Uma porta NOT quando você manda 0 ele responde 1, ou quando manda 1 ele responde 0. Uma porta NOT pode ser feito com dois transistors, por exemplo.</p>
<p>Além de NOT podemos montar outras portas fundamentais como OR, AND, NAND, XOR que é exclusive OR e assim por diante. E com essas portas podemos montar coisas mais complicadas como uma CPU inteira. Com outras construções como flip flops, podemos montar memória, e por aí vai. À primeira vista é difícil de entender como operações simples como inverter bits pode ser útil. Vamos pensar numa operação um pouco mais complicada que queremos ter numa CPU, por exemplo somar dois números.</p>
<p>Assumindo que todo mundo sabe somar. Pense uma conta besta, somar 28 mais 22. Você começa somando 8 com 2, vai dar 10, coloca zero embaixo e sobe 1. A mecânica interessante aqui é esse &ldquo;sobe um&rdquo;. Agora soma esse 1 que subiu com 2 do 28 e 2 do 22 e vai ter 50. Pra somar em binário é exatamente a mesma coisa. Pra converter um número decimal em binário, você vai dividindo por dois. 28 dividido por 2 é 14, resto 0. 14 por 2 é 7, resto 0, 7 por 2 é 3, resto 1, 3 divido por 2 é 1, resto 1. Então fica 11100. Pra ser 8 bits só completar os 3 zeros à esquerda.</p>
<p>Fazendo mesma coisa com 22 fica 0001 0110. Números pequenos uma hora você lembra de cabeça, mas pra números maiores qualquer calculadora do Windows mesmo converte pra você. Ou em qualquer linguagem de programação tem uma função de formatar strings onde você passa um inteiro e diz que quer formatar com base 2. Num javascript basta chamar o método .toString com argumento 2 num número.</p>
<p>Pra somar esses dois binários, você começa da direita pra esquerda também, zero mais zero é zero. Depois zero e um é um. 1 e 1 é 2 que em binário é 1 0, então coloca zero e sobe 1. 1 mais 1 mais zero, mesma coisa, coloca zero e sobe mais um. 1 + 1 + 1 é 3, coloca 1 e sobe 1. 1 mais zero mais zero é 1. E o resto é zero. Então o resultado final é 0011 0010. Só parece difícil porque você ainda não tá acostumado a enxergar zeros e uns, mas a regra é a mesma e usa a mesma mecânica do &ldquo;sobe um&rdquo;.</p>
<p>A máquina de adição mais simples que soma 2 bits é chamado de half adder ou meio somador. Você liga uma porta AND com uma porta XOR e vai ter a soma e o carry bit. Carry é o bit onde grava o &ldquo;sobe 1&rdquo;. O meio somador vai fazer exatamente o que eu fui descrevendo agora. Se passar 0 e 0 a soma é 0. Se passar 1 e 0 ou 0 e 1 a soma é 1. Se passar 1 e 1 a soma é 2, então baixa 0 e sobe 1 pro Carry bit. A versão completa se chama full adder ou somador completo.</p>
<p>Um dos jeitos de montar um somador completo pode ser ligando duas portas XOR, duas portas AND e uma porta OR. Ou melhor ainda, ligando dois meio somadores. A diferença é que além dos 2 números pra somar ele também recebe o carry bit de entrada e com isso podemos cascatear múltiplos circuitos de somador completo um embaixo do outro, ligando o carry bit de saída de um somador na entrada do outro. Se quisermos somar com números de 4-bits adicionamos 4 somadores completos em cascata. Pra 8-bits precisamos de 8 somadores. E com isso adquirimos um somador completo de 8-bits! (som de zelda)</p>
<p>Um circuito de somador completo pode ser montado de maneiras diferentes e com isso varia o número de transistors, mas pense que na média vai ser alguma coisa na faixa de 10 transistors pra cada somador. Pra somar números de 8 bits vamos precisar de no mínimo uns 80 transistors. Pra hoje em dia isso não parece grande coisa já que um processador A13 Bionic dos iPhone 11 Pro tem 10 bilhões de transistors. Um AMD Ryzen 7 3700X tem quase 6 bilhões de transistors e um AMD Epyc Rome, que é pra servidores, tem mais de 39 bilhões de transistors. Lembrando que são todos chips de 64-bits.</p>
<p>Nosso pobrezinho MOS 6502 de 8-bits tem na faixa de 3500 transistors, lembrem-se que estamos falando do meio dos anos 70. O que viemos fazendo depois, além de aumentar mais e mais a densidade de transistors por centímetro quadrado, foi adicionando novas funcionalidades como SIMD que são instruções de single instruction multiple data pra computação paralela, instruções de virtualização como VT-X ou AMD-V, instruções pra criptografia como AES, sem contar que os chips hoje são multi-core então é como se fossem múltiplas CPUs apertadas no mesmo chip. Mas as instruções fundamentais como somar bytes, carregar acumulador, incrementar contador de programas, atualizar apontador de pilha, e coisas assim que vimos no hello world da semana passada ainda é  similar.</p>
<p>Um primeiro insight é que os chips hoje são na ordem de 10 milhões de vezes mais densos de transistors que os chips dos anos 80 pra trás. Porém isso não se traduz necessariamente em programas 10 milhões de vezes melhor. Pegue o melhor da geração 8-bits que foi Super Mario 3 e compare com New Super Mario Bros rodando no Switch cujo SoC Tegra X1 tem na faixa de 7 bilhões de transistors com 4 cores ARM Cortex A57 ativos.</p>
<p>Vamos descer um pouco mais hardcore pra dar mais contexto com o tipo de CPU que estamos trabalhando. Adição eu disse que fazemos mais ou menos do mesmo jeito que você faria no papel somando digito a digito e subindo 1 quando precisa. Se hoje em dia temos transistors de sobra nas CPUs, nos 3500 que tinha num 6502, cada transistor contava. Então só era implementado o estritamente necessário. Somadores completos numa cadeia de 8 bits está implementado na instrução ADC.</p>
<p>Se recapitularmos sobre o pouco que aprendemos sobre assembly do 6502, pra realizar uma adição de números de 8 bits, faz de conta, o número 1 mais 2 poderíamos fazer assim.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>	LDA #$01
	ADC #$02
	STA $6000</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Começa com LOAD do número 1 no acumulador, ADC que é adição com carry onde passamos 2 e ele vai somar com o número 1 que já tava no acumulador, daí armazena ou Store do resultado que fica no A pra algum endereço na memória, como o endereço $6000 que, no video anterior, ia mandar pro chip de trava e de lá pro LCD. Isso é uma coisa que hoje em dia você não se preocupa porque as linguagens de programação já cuidam disso, mas o 6502 faz cálculos com números de 8-bits. O valor máximo que cabe em 8 bits sem sinal é FF ou 255. O que acontece se eu tentar somar 255 + 255? Precisamos de mais bits.</p>
<p>Só porque uma CPU é de 8-bits não quer dizer que não podemos calcular números maiores, mas pra fazer isso precisamos particionar o número e lidar com pedaços dele. Por exemplo, digamos que tivéssemos uma CPU decimal mas que só faz conta com números de 2 dígitos de cada vez, então de 0 até 99. Se somarmos 99 + 5 teríamos 104. Precisaríamos gravar o 1 separado do zero quatro. No caso da soma, eu disse que todo somador completo lida com 1 bit do número. A instrução ADC é como se fossem 8 somadores completos em cadeia pra 8-bits.</p>
<p>Uma nomenclatura que às vezes você vai esbarrar é high order e low order. Quando lidamos com 16-bits, temos 2 bytes. O primeiro byte à esquerda chamamos de high byte e o último à direita de low byte. Dentro de cada byte tem 8-bits o bit mais à esquerda é o MSB ou Most Significant Bit e o último bit é o LSB ou Least Significant Bit, literalmente bit mais significativo e menos significativo. Lembra quando expliquei sobre little endian no episódio anterior? É pegar os 2 bytes e inverter, assim o low byte é lido antes do high byte.</p>
<p>Voltando pra soma, toda vez que tiver um &ldquo;sobe 1&rdquo; ele vai ser gravado no registrador C. Antes de toda soma o certo é usar a instrução CLC, literalmente Clear C, pra limpar esse registrador. Mas podemos não limpar também. Lembra que falei que registradores funcionam como varíaveis globais? Várias instruções deixam efeitos colaterais pra trás, deixando registradores com a sobra do que foi processado. E podemos usar isso a nosso favor, começar somando a primeira metade do número até 8-bits, e depois somar a segunda metade que vai usar o carry no C e continuar a soma com o resto dos bits. Por exemplo, digamos que temos um número grande, de 24-bits tipo o número 2 milhões. Seriam 3 pedaços de 8 bits cada que podemos chamar de high, medium e low byte.</p>
<p>Declaramos então os 3 pedaços do primeiro número A como A hi, A mid e A lo, depois B hi, B mid e B lo. Começamos limpando o registrador C, fazemos a soma dos bytes low, que é dar load no A low, adicionar com B low e guardar esse resultado parcial em B low; depois mesma coisa com os bytes medium e high. A soma final é a junção dos três pedaços de B.</p>
<p>; ex: 8 milhões = $7A 12 00, A_hi = $7A, A_mid = $12, A_low = $00
A_hi,  A_mid,  A_lo
B_hi,  B_mid,  B_lo</p>
<p>START:  CLC         ; Clear C only to start.
LDA  A_lo
ADC  B_lo
STA  B_lo</p>
<pre><code>    LDA  A_mid  ; Note that here we don't re-clear C, but just
    ADC  B_mid  ; let it do its job of adding the 9th bit that
    STA  B_mid  ; didn't fit in the result of the previous byte's
                ; addition.
    LDA  A_hi
    ADC  B_hi
    STA  B_hi
</code></pre>
<p>Pense na sua linguagem favorita, você nunca se preocupa com isso, simplesmente escreveria <code>A + B</code>. Como você tem processamento e memória de sobra e seus programas nunca são particularmente complicados, mesmo que tenha desperdícios, não chega a ser um problema. Mas quando seus recursos são extremamente limitados, desperdiçar bits é um problema real. Desperdiçar ciclos também, porque cada instrução gasta alguns ciclos de clock. Nada sai de graça. Um processador moderno roda na faixa de 2Ghz a 5Ghz hoje em dia, mas um 6502 roda entre 1 a 3 Mhz.</p>
<p>Portanto em máquinas pequenas como o 6520 queremos tanto economizar a quantidade de memória usada quanto o número de instruções pra não desperdiçar clocks. Literalmente podemos fazer dezenas de milhões de instruções a menos por segundo num 6502 do que num processador moderno de qualquer smartphone hoje. Fazer programas simples num computador excessivamente poderoso é muito fácil, qualquer um faz. Eu sempre digo que você sabe quando um programador é bom quando ele consegue programar num sistema com restrições, porque a arte de programar é conseguir tirar o máximo que o hardware oferece.</p>
<p>Vamos dar outro exemplo besta. Já sabemos como CPUs fazem adição. Subtração e multiplicação é a mesma coisa. Podemos desenhar circuitos como no caso do somador completo e implementar com transistors. Como falei antes, no 6502 temos a instrução ADC pra adição e também temos SBC pra subtração, mas não tem multiplicação.</p>
<p>Digamos que você, que nunca estudou nada de engenharia ou ciências da computação pense numa forma de implementar multiplicação só usando operações básicas que falamos até agora como adição, o que você faria? Eu aposto como a solução mais imediata que a maioria pensaria seria via adições sucessivas. Por exemplo se quisermos multiplicar 278 vezes 7, você iria somando 278 sete vezes até dar 1148. Seriam só 7 adições e não parece tão ruim assim. Aquele famoso caso de &ldquo;testei aqui e no meu computador funciona&rdquo;.</p>
<p>Mas e se quisermos multiplicar 10 mil vezes 10 mil? Agora precisa fazer 10 mil somas pra chegar no resultado. Isso é consideravelmente mais devagar e com números maiores só vai piorando. Vamos usar tempos hipotéticos só pra ilustrar. Pra somar cada bloco de 8 bits digamos que precisariamos gastar uma instrução de LOAD, uma de ADC e outra de STORE, cada um custando uns 5 ciclos de clock. 10 mil é um número que podemos representar em 2 bytes ou 16 bits. Então são pelo menos 2 loads, 2 adc e 2 stores pra cada rodada.</p>
<p>Então temos 6 instruções custando uma média de 5 ciclos de clock, ou seja 30 ciclos. Em 1 Mhz podemos ter no máximo umas 33 mil sequências dessa por segundo. Mas se precisamos executar 10 mil sequências de soma dessas gastaríamos 1/3 de segundo ou pelo menos 300 milissegundos. Lembrando que estou considerando condições ideais de temperatura e pressão, como a gente falava no colégio, mas provavelmente gastaria mais ciclos que isso. Parece pouca coisa mas 300 milissegundos é mais tempo que leva pra você pedir uma página num site, ele processar, retornar o HTML e seu navegador renderizar. Aliás, se sua aplicação web demora 300 milissegundos pra responder, isso é considerado lento quase parando.</p>
<p>Pra variar, não existe uma fórmula universal de multiplicação que tem 100% de melhor performance pra todos os casos. O bom senso é o contrário: fórmulas universais costumam ser lentas. Isso é uma coisa que, como programador, você precisa entender: existem fórmulas que funcionam melhor pra casos diferentes. Por exemplo, no episódio anterior eu já disse como faz multiplicação por 2: basta fazer um shift left, que é o equivalente a adicionar um zero no final do binário e pronto, tá multiplicado numa única instrução.</p>
<p>Você não conhece formas diferentes de multiplicar? Deixa eu contar um diferente. Existe um método ensinado no primário de escolas Russas que ficou famoso porque a gente associa tudo que é russo com excelência em matemática. Na real é um método bom pra números pequenos e não é particularmente bom pra computadores. É chamado de método do camponês russo. Vou explicar de curiosidade.</p>
<p>O método é assim: dobre o primeiro fator, divida o segundo fator pela metade. Se o segundo fator for par ignore e repita. Se o segundo número for ímpar, some o primeiro fator com o anterior. Por exemplo, digamos que eu quero multiplicar 278 por 7 como falamos antes. Primeiro dobramos o primeiro fator. Multiplicar por 2 todo mundo consegue fazer de cabeça e vai dar 556. Daí 7 divido por 2 é 3. 3 é impar então somamos 556 com 278 e temos 834. Agora dobramos 556 de novo e vamos ter 1112. No segundo fator temos 3 dividido por 2 que é 1, que é impar, então somamos com 834 com 1112 e vamos ter 1.946. Como o segundo fator chegou a 1 acabamos e a resposta é 1.946. Pode abrir uma calculadora aí e checar.</p>
<p>Não é difícil implementar isso em Assembly. Existe um site excepcional que é a fonte de referência de qualquer um que quer implementar um emulador de NES que é o Wiki Nesdev e quando fala de multiplicação ele implementa justamente esse algoritmo do camponês russo que fica assim:</p>
<p><a href="https://wiki.nesdev.com/w/index.php/8-bit_Multiply"target="_blank" rel="noopener">https://wiki.nesdev.com/w/index.php/8-bit_Multiply</a></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>;;
; Multiplies two 8-bit factors to produce a 16-bit product
; in about 153 cycles.
; @param A one factor
; @param Y another factor
; @return high 8 bits in A; low 8 bits in $0000
;         Y and $0001 are trashed; X is untouched
.proc mul8
prodlo  = $0000
factor2 = $0001

  ; Factor 1 is stored in the lower bits of prodlo; the low byte of
  ; the product is stored in the upper bits.
  lsr a  ; prime the carry bit for the loop
  sta prodlo
  sty factor2
  lda #0
  ldy #8
loop:
  ; At the start of the loop, one bit of prodlo has already been
  ; shifted out into the carry.
  bcc noadd
  clc
  adc factor2
noadd:
  ror a
  ror prodlo  ; pull another bit out for the next iteration
  dey         ; inc/dec don&#39;t modify carry; only shifts and adds do
  bne loop
  rts
.endproc</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Você dá load do multiplicador no acumulador, load do multiplicando no registrador Y e roda essa rotina e ele vai gravar o low byte do resultado no endereço $0000 e o high byte em A. Lembra que números maiores que 8-bits fica particionado em múltiplos bytes? O resultado de uma multiplicação costuma ser um número com o dobro de bytes dos fatores, então multiplicar 2 números de 8 bits dá um resultado de 16 bits.</p>
<p>Esse algoritmo gasta em torno de 150 ciclos. Se seu programa for ter poucas multiplicações pode ser suficiente. Mas qualquer operação que gasta mais que 100 ciclos num 6502 não é exatamente rápido. Existem maneiras mais rápidas que isso. E aqui vem outro insight que como programador você precisa ter na cabeça. Algoritmos costumam ser um balanço de dois fatores: se você quiser economizar memória vai acabar gastando mais ciclos de processamento. Se quiser velocidade economizando ciclos provavelmente vai gastar mais memória. Por exemplo, vamos pensar um pouco mais: como você faria multiplicações rápido no primário, sem calculadora?</p>
<p>Pra números pequenos você provavelmente teria que ter decorado a tabuada, lembram disso? Tenho certeza que a maioria odiava ter que decorar a tabuada. Mas lembrem de uma coisa, a tabuada é uma tabela pré-calculada. Você procura o multiplicando e o multiplicador e instantaneamente tem a resposta. Imagine uma tabela pré-calculada pra todos os números que cabem em 8-bits. Daí basta achar a posição na matriz com o resultado direto. Você vai gastar ciclos pra pré-calcular a tabela da primeira vez ou pode ler direto a tabela de uma ROM. O problema dessa solução é que fácil fácil ela vai ocupar 16 kilobytes de espaço ou mais. Considerando que um Super Mario Bros inteiro cabe em 40 kilobytes estamos falando em gastar 1 terço disso só numa tabela de números, o que seria um enorme desperdício.</p>
<p>Uma tabela pré-calculada é o que chamamos de lookup table e isso é uma técnica usada em todos os lugares da computação. Você que faz desenvolvimento web provavelmente já usou ou vai usar isso. Por exemplo quando faz cache com um Redis ou Memcache, é um lookup table. Quando cria índices numa tabela de banco de dados, isso é um tipo de lookup table. O problema é que se essa tabela for grande demais, o tempo pra procurar na tabela também pode começar a ser um problema, fora desperdício de espaço caso você não planeje direito.</p>
<p>Mas como seria uma maneira melhor então? E aqui a matemática nos ajuda. Se você estudou Álgebra e trigonometria não vai achar estranho o que vou dizer a seguir. Uma multiplicação de dois fatores a e b pode ser descrita de maneiras diferentes. Por exemplo, ela pode ser a exponencial da soma dos logaritmos de a e b. Se quiser ser mais complicado pode ser a soma do cosseno de x mais y com o cosseno de x menos y, tudo dividido por 2. Sendo que x é o arco cosseno de a que também é chamado do cosseno inverso. Arco cosseno é usado pra determinar o ângulo do cosseno em radianos. Y da mesma forma é o arco cosseno de b.</p>
<p>Continuando, a vezes b pode ser também o quadrado de a mais b, menos o quadrado de a, menos o quadrado de b, tudo dividido por 2 ou, finalmente, pode ser o quadrado de a mais b menos o quadrado de a menos b tudo dividido por 4. E essa opção final é que nos interessa, pois podemos reduzir a fórmula pra ser a subtração de a mais b aplicado numa função F, com a menos b na mesma função F, sendo essa função F o quadrado do número que passarmos dividido por 4.</p>
<p>A parte importante é que decompomos o problema da multiplicação numa adição dos fatores, subtração dos fatores e subtração do resultado da tal função F. E a essa função reduz o tamanho do lookup table pra em vez de ser todos os possíveis resultados da multiplicação de todos os números de 8-bits, pra simplesmente ter uma tabela só com o resultado da multiplicação do quadrado dos números. Ou seja, de 1 vezes 1, de 2 vezes 2, de 3 vezes 3 e assim por diante, que é uma quantidade pré-calculada ordens de grandeza menor, caindo dos 16 kbytes que eu falei pra talvez meio kbyte.</p>
<p>E pra calcular o quadrado de todos os números também vai ser rápido porque existe a propriedade que o quadrado do número é o quadrado do número anterior mais um número impar. Quadrado de 1 é zero mais 1. Quadrado de 2 é o 1 anterior mais o próximo impar que é 3, resultado 4. Quadrado de 3 é 4 mais o próximo impar 5 que dá 9. Quadrado de 4 é 9 mais o impar 7 que dá 16. Quadrado de 5 é 16 mais o próximo impar 9 que dá 25 e assim por diante.</p>
<p>E como eu disse no começo, dá pra ir longe estudando sobre assembly. Outros assuntos que tava pensando em cobrir neste episódio incluíam o conceito de complementar de dois, números inteiros com sinal pra lidar com negativos, algoritmo de Booth pra multiplicação e muito mais. Mas é teoria demais pra um único video, por hoje vou parar por aqui. Mas eu queria gastar pelo menos um pouco de tempo mostrando essa linha de raciocínio pra vocês entenderem que não, hoje em dia você dificilmente vai gastar tempo implementando uma multiplicação na mão. Toda CPU já implementa as melhores fórmulas em hardware e pra quem precisa de casos específicos existem bibliotecas voltadas pro campo científico que otimizam os piores casos.</p>
<p>Mas é importante você entender que tudo que uma linguagem te oferece, cada pequena coisinha insignificamente como aquele mero asterisco de multiplicação teve milhares de horas homens de pesquisa, experimentação, otimizações. Literalmente muito suor e lágrimas até chegar no estado da arte que você usa hoje sem nem pensar. É isso que significa subir nos ombros de gigantes, porque é com o conhecimento testado e acumulado de centenas de anos de matemática que esse asterisco de multiplicação se tornou possível e você consegue multiplicar dois números de praticamente qualquer tamanho em microssegundos.</p>
<p>E também é pra entender que muita coisa hoje ainda não tem uma fórmula perfeita. Eu disse que temos CPUs com dezenas de milhões de vezes mais transistors que um 6502 mas ainda assim não temos programas dezenas de milhões de vezes melhores. Isso porque muitas partes do software que usamos ainda não tá rodando da melhor forma possível. Grande parte do que é o trabalho de um programador é não ignorar os problemas e parar pra tentar encontrar formas mais inteligentes de fazer o computador processar.</p>
<p>Muito bem, vamos voltar ao nosso nintendinho. Assim como no exemplo do protoboard do Ben Eater, o PCB que é sigla pra Printed Circuit Board ou placa de circuito impresso, contém o cérebro que é o 6502 e diversos outros chips como chip de RAM, chip de VRAM que é memória de vídeo, e outros componentes como pra ligar seus controles. Tem a PPU que é o Picture Processing Unit ou unidade de processamento de imagens que é a versão primitiva do que hoje você chamaria de GPU. E tem o APU ou audio processing unit pra gerar som.</p>
<p>O nintendinho já foi tão dissecado nas últimas décadas que temos documentação super completa de cada componente em detalhes suficiente pra ter muita gente fabricando chips e PCB novos. Você consegue literalmente comprar um hardware moderno de nintendinho hoje se quiser, e ele vai ser 100% compatível com qualquer cartucho que você tenha guardado.</p>
<p>Mas pro que me interessa, a documentação é tão boa que é possível criar emuladores em software que se comportam exatamente como o hardware. Eu não sei se vocês conseguem entender a beleza disso. Todo hardware tem a capacidade de simular o comportamento de outro hardware via software. E praticamente toda linguagem de programação consegue representar qualquer hardware.</p>
<p>Tendo documentação tão completa como o Wiki Nesdev que eu mencionei antes, poderíamos escrever nosso próprio emulador. E como alguém faria isso? É um processo mais trabalhoso do que difícil porque você precisa ter o trabalho meticuloso de implementar cada detalhe que tá nas documentações, mas por exemplo, podemos começar criando um projeto vazio, digamos usando a linguagem Go. Aliás, como o nintendinho é bem antigo, qualquer linguagem hoje consegue simular um 6502 e os outros componentes.</p>
<p>Não existe &ldquo;O&rdquo; jeito correto de se escrever um software. Se você pegar diferentes emuladores de nintendinho vai ver que eles são organizados e escritos de maneiras diferentes. Só com experiência e muitos testes você vai chegar no que é o melhor balanço entre legibilidade e eficiência. Mas pra ser simples podemos pensar nos componentes principais que eu listei. O primeiro elemento que queremos emular é o console, então começamos criando um arquivo chamado console.go e dentro definimos o tipo Console como uma estrutura. E não se preocupe se você nunca viu Go, não é relevante entender cada linha do código hoje, só o raciocínio. Estude depois com calma.</p>
<p>Essa estrutura vai declarar ponteiros pra CPU, pro APU, pro PPU, pro cartucho, pros dois controles, pra um troço que vou explicar depois chamado Mapper, e delimitamos a RAM que é só um array. Lembram todos aqueles hexadecimais que eu falei no video anterior? Pense nesses números como posições no array. Memória é isso: uma listona de bytes. Agora precisamos criar arquivos pra cada um desses componentes e definir as estruturas de cada um. O próximo é o arquivo cpu.go.</p>
<p>A estrutura CPU vai ter muitos dos elementos que eu expliquei no vídeo anterior. Começamos definindo uma referência pra uma estrutura de Memory que vou explicar depois. Daí definimos PC que é o contador de programa como um inteiro gigante de 64-bits, e nem precisava ser tão grande porque ele só aponta pro endereço da próxima instrução, então 16-bits bastava. Vamos definir o SP que é o apontador de pilha como um inteiro de 16-bits. Daí os registradores todos de 8 bits, ou seja 1 byte. Temos o acumulador A, o X, o Y, o C, Z, I, D, B, U, V, N. E por fim temos uma última estrutura importante, um array de instruções.</p>
<p>Lembra que cada instrução como LDA tem um hexadecimal associado, que é basicamente o endereço da localização dessa instrução? Pois é, precisamos colocar cada opcode na posição correta nessa lista. Quando quisermos achar a instrução 0xa9 que é o LDA vamos pra posição 0xa9 que é a posição 169 nessa lista. Daí vamos encontrar a referência pra uma função de Go. Agora precisamos implementar cada uma dessas funções.</p>
<p>Por exemplo, o nosso LDA sabemos que vai escrever o valor no registrador A que é o acumulador. Então em Go é simplesmente associar o valor do argumento na variável A da CPU.</p>
<p>Sabemos também que JSR é o Jump pra uma subrotina, o que ele faz é empurrar o endereço no contador de programas pra pilha e sobrescrever o contador de programa com o endereço da subrotina pra onde tem que pular.</p>
<p>E assim vai, tem que escrever uma função pra cada instrução que existe de acordo com a especificação na documentação do 6502. Uma vez feito tudo isso podemos criar o inicializador NewCPU que vai alocar a estrutura que definimos. Esse inicializador recebe uma referência pra estrutura de console que criamos antes pra passar pra essa nova estrutura chamada Memory. Deixa esse Memory de lado que ainda não é hora pra ele. Em seguida criamos e populamos a tal tabela com referências pras instruções que criamos. Finalmente criamos uma rotina de reset.</p>
<p>Reset é o que você pensou mesmo: o equivalente a você apertar o botão reset que todo console e computador tem. A idéia é limpar o contador de programas pra apontar pro endereço 0xFFFC, lembra no episódio anterior que quando o 6502 inicializa a primeira coisa que ele faz é ir no endereço 0xFFFC procurar a primeira instrução do programa? Pois é. E em seguida limpamos o apontador de pilha pra iniciar em 0xFD. Isso é pra relembrar a importância desses dois registradores, porque é com eles que conseguimos executar um programa.</p>
<p>Tem mais coisas que precisam ser feitas pra CPU ficar completa mas por agora vamos pular pra essa tal de Memory criando um arquivo memory.go. A estrutura em si é muito simples. Ela só vai apontar pra uma referência à estrutura de Console que já definimos antes. A parte importante começa com a função de leitura Read. Ele recebe um endereço e vai devolver algum valor que teoricamente está em alguma lugar na tal memória.</p>
<p>Aqui começa a diferença de um nintendinho e outros computadores que usam o processador 6502 como um Atari ou Apple II, o mapa de memória. No episódio anterior eu expliquei que temos endereços de 16-bits então podemos mapear do endereço 0x0000 até 0xFFFF, daí dividimos esse espaço e por exemplo a CPU ia procurar no EEPROM se passássemos endereços acima de 0x8000. Ou seja, arbitrariamente definimos que certos chips respondem a certos endereços.</p>
<p>A grosso modo, do endereço 0x0000 até 0x07FF temos 2 kilobytes de RAM. Nos endereços de 0x2000 a 0x2007, que é bem curto, temos registradores pra PPU. De 0x4000 a 0x4017 acessamos a APU e registradores de I/O como os controles e só de 0x8000 a 0xFFFF temos o equivalente a uns 32 kilobytes reservados pra endereços que mapeiam pra algum lugar do cartucho. Em particular se acessarmos acima do endereço 0x6000 temos esse negócio que colocamos no código chamado Mapper. Agora vocês precisam entender os truques que eram usados em consoles com cartuchos.</p>
<p>Se sua história com games começa só depois do Playstation 1, você tá acostumado a ter os games em CDs, DVDs, Blu-Ray ou instalados no HD do seu computador. É de praxe que toda vez tem que esperar o famoso &ldquo;Loading&rdquo;, que é o tempo do computador começar a carregar os primeiros bytes do jogo na RAM pra só depois conseguir começar a jogar. Daí a cada fase tem que carregar novos bytes pra RAM e jogar fora os bytes da fase anterior que não vai precisar mais. Isso é necessário porque não cabe todo o jogo na memória. Um computador muito bom hoje tem 16 GB, mas qualquer jogo moderno tem 30 GB, 40GB, alguns jogos podem ter absurdos 100GB. Obviamente não cabe tudo na RAM então precisa ir carregando e descarregando de pedaço em pedaço.</p>
<p>Com cartuchos é diferente. O que tem num cartucho são chips de ROM, como expliquei no episódio anterior. Então quando você pluga o cartucho no console, não existe loading, não tem que carregar nada e ele pode iniciar imediatamente porque a CPU acessa os endereços diretamente da ROM, sem precisar carregar o jogo em memória. O cartucho &ldquo;É&rdquo; a memória. Entenderam? Diferente de CD ou HD, a ROM do cartucho já tem velocidade máxima de acesso, igual da RAM. Da mesma forma que a CPU consultaria um endereço na RAM, no caso pedindo endereços de 0x0000 a 0x07FF, quando ele precisa de dados do jogo ele pede nos endereços acima de 0x8000 até 0xFFFF.</p>
<p>Por isso jogos de consoles antigos carregam instantaneamente e não tem loading entre fases e tudo é rápido. Um dos maiores gargalos ainda não resolvidos em games modernos de fato é a lentidão do I/O, não só do HD mas de toda a cadeia que carrega dados, incluindo barramento, controlador e tudo mais. Inclusive é isso que a nova geração de consoles PS5 e Xbox Series X estão tentando combater colocando os SSDs e controladores mais rápidos do mercado pra minimizar ao máximo o tempo de carregar coisas do disco. Mesmo assim o tempo nunca vai ser zero como era nos cartuchos.</p>
<p>Vou repetir o que eu disse antes: programação é sempre um trade off, uma troca. Cartuchos tem tempo quase zero de acesso porque ele é direto um chip de memória. O problema é que chips de ROM são muito mais caros de produzir comparado a discos de HD ou Blu-Rays. É bem mais caro. A comparação mais óbvia foi na transição dos cartuchos pro CD quando saiu o Playstation 1 e o concorrente na época era o Nintendo 64 que preferiu usar cartuchos pelas razões que eu acabei de falar.</p>
<p>Jogos de Playstation podiam ter videos e muito mais conteúdo porque num CD daquela época era possível colocar até 650 megabytes de dados. Em comparação um dos maiores cartuchos de Nintendo 64 era Conker&rsquo;s Bad Fur Day que tinha enormes 60 megabytes, ou seja mais de 10 vezes menos espaço e o cartucho ainda custava mais caro. Os lendários Zelda Ocarina of Time e Majora&rsquo;s Mask eram cartuchos de menos de 30 megabytes. Por isso jogos de Nintendo 64 raramente tinham algum video e também por isso preferiam usar o mínimo de texturas nos modelos em 3D, porque texturas são imagens bitmap que consomem muito espaço.</p>
<p>Voltando pra era dos 8-bits. Um cartucho como do Super Mario original tem 40 kilobytes, portanto male male encaixa no nosso espaço de endereços reservados pra ROM. Mas um Super Mario 3 tem 385 kilobytes, quase 10 vezes mais bytes que o original. Um dos jogos mais pesados do nintendinho é Kirby&rsquo;s Adventure e se você rodar vai ver um dos games mais bem elaborados pro nintendinho, chega perto do que seria um jogo de Super Nintendo. Também pudera, o cartucho dele tem quase 800 kilobytes, perto de 1 megabyte.</p>
<p>Mas como é possível endereçar isso tudo de bytes só com endereços de 16-bits? Agora vem o segundo grande fato sobre cartuchos: eles não tem só chips de ROM. Na realidade um cartucho é uma placa de expansão, um PCB completo. Quando falo em placa, pense mesmo como quando você compra uma placa gráfica como um novo NVIDIA RTX e espeta no slot PCI Express na placa mãe do seu computador. Encaixar um cartucho no console é a mesma coisa.</p>
<p>Num PCB você pode plugar não só ROM como qualquer outro componente. Por exemplo, você pode colocar um chip de SRAM e uma bateria de lítio e boom, você acabou de ganhar a capacidade de salvar o jogo. Só que isso torna o cartucho ainda mais caro, por isso nem todo jogo podia salvar. Um dos chips mais famosos se você jogou Super Nintendo foi o chip Super FX, que literalmente era uma placa primitiva 3D que permitiu jogos como Star Fox. O processo é o mesmo, o chip vem no PCB do cartucho.</p>
<p>Você literalmente poderia enfiar um nintendinho inteiro dentro de um cartucho. Mas só isso não responde a pergunta de como fazia pra um Kirby ter quase 1 mega de dados. Não basta só enfiar mais chips de ROM se não temos endereços suficientes pra passar de 32 kilobytes. Endereços funcionam como o nome diz, é como se tivéssemos uma rua de casas e só tivesse 32 números, da casa 33 em diante ficaria sem números. Se o carteiro precisasse entregar alguma coisa nessas casas como ele encontra?</p>
<p>E se nessa rua colocássemos um síndico? Que separasse a rua em blocos? Daí teria casa de 1 a 32 no bloco A, casas de 1 a 32 no bloco B e assim por diante. Continua só tendo 32 números mas dependendo do bloco sempre encontraríamos uma casa diferente. E é exatamente isso que o nintendinho faz. No cartucho, além de vir mais ROM ele vem com um síndico, um controlador que chamamos de Mapper.</p>
<p>Como o nome diz, Mapper é um mapeador. Em vez de blocos na rua do nosso exemplo a memória ROM é dividida em Banks ou bancos. E a técnica pra enxergar mais memória se chama Bank switching. A CPU continua só conseguindo enxergar dos endereços 0x8000 a 0xFFFF mas ele pode pedir pro Mapper trocar os banks, assim como no exemplo dos blocos da rua. Os banks costumam ter 16 kilobytes de tamanho e podemos ter vários banks, então se montarmos o cartucho com ROM suficiente pra 50 banks de 16 kilobytes, vamos ter os quase 800 kilobytes do jogo Kirby.</p>
<p>Agora vem a parte cabeluda pra fazer emulador de NES: não basta só escrever código que representa o console, precisa também emular os chips que vem nos cartuchos, em particular esses mappers. Você poderia imaginar que deve ter alguns poucos modelos de mappers. Mas que nada, se olhar a biblioteca toda de games de nintendinho existem 407 mappers que foram encontrados e documentados. Por sorte, se você cobrir os mappers da própria nintendo e alguns de marcas famosas como Konami, já cobre a maior parte dos jogos. Muitos mappers só existem em jogos muito obscuros, feitos na China ou lugares assim.</p>
<p>Se você olhar de novo no wiki da nesdev vai encontrar o código que vem no cartucho que identifica qual mapper ele tem. No arquivo de Memory ele vai selecionar um Mapper baseado nesse código identificador que ler da ROM. Daí precisamos de cada um dos Mappers, que precisam responder às mesmas funções. Por isso no nosso arquivo de mapper vamos definir uma interface que todos os mappers vão ter que implementar. Basicamente definimos o que um Mapper precisa obrigatoriamente fazer, que é ler da ROM, gravar na RAM e coisas assim.</p>
<p>No inicializador pegamos o cartucho associado no console. Depois que carregarmos uma ROM ele vai preencher esse campo Mapper com seu código identificador, e com isso podemos checar qual mapper vamos ter que carregar. Neste pequeno emulador em Go vai ter só alguns dos principais. De curiosidade esse último mapper código 225 é que permite aqueles cartuchos de 52 jogos em 1 que você já deve ter visto por aí. Um cartucho desses tinha 6 chips de ROM com meio megabyte cada.</p>
<p>Não vou entrar no detalhe de cada um, senão a gente fica aqui até o ano que vem, mas só pra mostrar um, podemos criar um arquivo pro mapper 2. Lembrando que no nosso caso, usando máquinas modernas, não temos esses limites pequenos de 16-bits. Podemos carregar a ROM de um cartucho como um arrayzão contínuo de bytes, seja lá quantos bytes tiver porque temos espaço pra mapear tudo. Então recebemos o endereço que o CPU manda e mapeamos com esse arrayzão.</p>
<p>No caso, o que nos interessa é que quando carregamos a ROM os bytes são identificados como regiões distintas, sendo as duas principais o PRG e CHR. PRG são bytes de programa. CHR são os bytes de caracteres, que é a área onde normalmente estão os tiles. Eu sempre chamo de tiles mas se for traduzir é como se fossem azulejos. Tiles, azulejos, caracteres, são termos que significam a mesma coisa.</p>
<p>O princípio de tiles é simples. Um CPU como o 6502 não fica dando instruções pra escrever pixel a pixel na tela. Ele pede pra escrever tiles. Pense num nintendinho como um editor de textos. Um editor não escreve pixel a pixel na tela, ele escolhe uma letra de alguma família de fontes, digamos Arial, e passa o código que representa ela. E o Windows ou MacOS da vida que vai se encarregar de realmente desenhar os pixels.</p>
<p>No nintendinho quem se encarrega de desenhar os pixels é o chip chamado de PPU que eu falei que é a unidade de processamento de pixels. O CPU não entende pixels, ele entende tiles. Significa que o PPU tem que trabalhar bastante pra desenhar pixel a pixel. Inclusive o clock do PPU é maior que do CPU. Mas a CPU só precisa mandar um byte pra identificar blocos de 8 por 8 pixels de uma vez só, em vez de mandar 64 comandos independentes pra cada um desses pixels.</p>
<p>Se você é de web front-end já lidou com algo assim, é como os sprites de CSS. Aliás a técnica de sprites de CSS não é novidade, isso é uma técnica antiga. Outra técnica antiga são fontes com imagens, como a Font Awesome que todo site hoje usa pra desenhar icones. A memória CHR da ROM que eu falei é como se fosse uma Font Awesome, literalmente caracteres. Cada caracter, ou fonte, é um tile. Acho que assim vocês conseguem visualizar na cabeça. Consoles antigos assim sequer tem fontes ou tabela de letras. Cada jogo define suas fontes e o código das letras, não tem um padrão como ASCII ou Unicode.</p>
<p>A PPU enxerga a resolução máxima de 256 por 240 pixels, e a CPU só enxerga uma grade de 16 por 15 espaços onde cabem os tiles. É parecido com um computador DOS antigo que tem resolução de 640 x 480 mas em modo DOS só enxerga 80 colunas por 25 linhas de texto. O PPU também só consegue enxergar 8 kilobytes de tiles de cada vez, então toda vez que precisamos de tiles diferentes, o CPU pede pro Mapper trocar o banco por outro. Existem dois excelentes emuladores pra quem quer aprender a programar jogos de verdade de nintendinho. Um deles é o FCEUX que acho que é o mais conhecido e o outro é o Mesen que eu acho que tem ferramentas mais modernas.</p>
<p>Vocês entenderam o que fizemos até agora? Eu fui estruturando o nintendinho como código de Go. Cada aspecto dele são estruturas de dados normais como arrays e bytes. Bytes na memória que sabemos exatamente onde estão e com isso podemos consultar a qualquer momento. Seja o emulador feito em Go, em C ou C++ vai ser a mesma coisa. O emulador Mesen implementa de forma parecida mas além de só emular ele expõe essas estruturas de forma visual em tempo real. Por exemplo, podemos abrir um visualizador da memória da PPU e organizar pra vermos os bitmaps.</p>
<p>E olha só o que tem na memória da PPU, esses são os tiles. Cada tile é um quadrado de 8 por 8 pixels. Se eu não estou enganado, podemos associar até 4 cores pra cada um, dentre 12 cores de uma paleta, num total de 4 paletas que posso escolher. Em outra aba podemos ver as 12 cores da paleta de background e outras 12 cores da paleta pros sprites. Se você já brincou de front-end, HTML e CSS certamente já viu código de cores em hexadecimal, é a mesma coisa.</p>
<p>Como a localização dessa área CHR na ROM é conhecida, podemos editar o que tem lá. Os tiles são bitmaps não comprimidos. Hoje em dia você tá acostumado a lidar com imagens comprimidas como JPEG que usa um algoritmo lossy, ou seja, que perde detalhes da imagem pra reduzir o tamanho. Um bitmap é exatamente o que o nome diz, um mapa de bits, nas posições exatas pra formar a imagem e sem  compressão.</p>
<p>Só pra mostrar como podemos afetar o jogo, com o Mesen rodando podemos editar as cores da paleta de background e trocar a cor do céu de azul pra outra cor. Ou podemos mexer na paleta de sprites e trocar a cor do Mario. Você pode mudar completamente a aparência do jogo só de ajustar as cores dessa forma.</p>
<p>Repetindo, pense na tabela de tiles como se fosse uma tabela de fontes de letras. Aliás, o nintendinho sequer tem fontes. Ele não tem um sistema operacional, o jogo começa rodando direto no hardware, sem nenhuma camada intermediária pra ajudar. Então se um jogo quer escrever textos na tela, ele próprio precisa embutir tiles de fontes. E de fato você vai ver que normalmente começando no endereço zero dessa área CHR costuma ter letras, números e símbolos. Aqui o número zero é a posição zero mesmo, o número um é posição um e assim por diante. E começando do zero até a letra F fica bonitinho de 0 a F em hexadecimal.</p>
<p>Lembra quando usamos no Linux a ferramenta hexdump ou xxd e na terceira coluna ele tenta interpretar bytes que mapeiam pra tabela ASCII como letras e às vezes aparecem textos mesmo? Numa ROM de videogame isso não funciona porque os códigos das letras não seguem a tabela ASCII. Mesmo entre jogos diferentes a posição das letras na ROM não é a mesma. Por isso em emuladores com debug como o Mesen e FCEUX podemos carregar nossa própria tabela que mapeia código das posições dos tiles pra letras, como essa na tela que é um arquivo texto com extensão TBL. Assim podemos tentar reconhecer algum texto no meio do binário.</p>
<p>Vejam no espaço PRG da ROM que não dá pra identificar nada. Mas carregando a tabela começamos a reconhecer quais bytes são textos. E com isso posso editar o texto, por exemplo trocando de MARIO pra FABIO. Resetamos o jogo e olha só como aparece meu nome. Podemos trocar todos os textos num cartucho e salvar o binário por cima, contanto que o texto novo caiba no mesmo espaço usado pelo texto antigo. Esse é o hacking mais simples de todos e que todo mundo que já brincou com binários já fez na vida. É assim que muita gente traduziu cartuchos japoneses pra inglês, por exemplo. Se tiver filhos pequenos imagino que eles vão gostar de ver os nomes deles nos jogos.</p>
<p>E podemos editar o binário não só do texto como dos tiles. Por exemplo, existem programas como o Tile Layer Pro. Se abrirmos a ROM do Super Mario, no começo vamos ver um monte de sujeira que são bytes de programa, mas se descermos vamos encontrar os tiles do jogo. Pra enxergar melhor podemos mudar a paleta e rapidamente vamos começar a reconhecer alguns, como os tiles que formam o personagem. Pra ver melhor, podemos arrastar os tiles pra esta outra janela e montar como um quebra cabeça. O Mario grande é formado por seis tiles. Na ROM tem a sequência pra cada posição da animação, seja correndo ou pulando.</p>
<p>Podemos fazer mais, podemos editar cada tile e mudar o jogo completamente. É um puta trampo editar tile a tile mas se tiver paciência fazendo isso eu poderia pegar os bits de tiles de um Zelda ou Megaman e mudar o Mario pra ser o Link, ou qualquer outro personagem que caiba em seis tiles ou menos. E só com as técnicas eu mostrei aqui você poderia fazer um novo jogo usando um que já existe como base.</p>
<p>Sabe quem já fez isso? A Tectoy aqui no Brasil. Por causa deles nós somos o único país no mundo que ainda produz Master System novo até hoje. O Master System foi o concorrente do nintendinho nos anos 80. Também é um console de 8 bits mas no papel ele era tecnicamente superior. Em vez do MOS 6502 de 1.8 Mhz o Master System vinha com o Zilog Z80 que ia até 3.5 Mhz, quase o dobro de clock. Em vez de 2k de RAM e 2k de VRAM ele vinha com 8k de RAM e 16k de VRAM. Em vez de ser limitado a ter só 16 cores na tela, ele podia ter 32 cores, por isso jogos de Master System sempre parecem mais coloridos e vivos</p>
<p>Essa discussão de especificações e jogos sempre foi uma constante nas rodas de gamers. Um Xbox One X é tecnicamente mais poderoso que um PS4 Pro, mas o Playstation continua tendo alguns dos melhores jogos exclusivos como God of War ou Spiderman. Nos anos 80 não era diferente. O Master System era mais poderoso mas as marcas que chamavam mais atenção estavam no Nintendinho.</p>
<p>De qualquer forma o Master System conseguiu um público cativo aqui no Brasil e a Tectoy começou não só a licenciar e distribuir jogos estrangeiros como começou a lançar jogos brasileiros. Um grande exemplo que eu lembro que me impressionou na época foi o jogo da Turma da Mônica.</p>
<p>Esse jogo na realidade é o Wonder Boy II com textos e sprites editados pra encaixar numa história da Turma da Mônica. Se nunca viram olhem lado a lado.</p>
<p>A Tectoy produziu vários jogos usando essas técnicas como Geraldinho, Sapo Xulé, TV Colosso. Mas fazendo isso eles foram aprendendo como de fato programar no Master System e começaram a produzir jogos mais elaborados. Por exemplo, um dos melhores jogos de Master System sem dúvida é Castle of Illusion. Daí a Tectoy pegou emprestado elementos desse jogo e fez um terceiro jogo na sequência do também excelente Land of Illusion, com fases novas e inimigos novos e chamou de Legend of Illusion. É bem claro onde são sprites dos jogos anteriores e quais são sprites desenhados do zero. A parte artística ainda tava bem primitiva, mas já é uma evolução.</p>
<p>Mas quando você treina e vai aprimorando as coisas melhoram. Por exemplo, eles começaram a experimentar com a idéia de pegar jogos de Mega Drive, que é um console bem mais poderoso que o Master System, pegar os sprites e elementos visuais e diminuir detalhes, diminuir cores, diminuir frames de animação pra tentar fazer caber no Master System. E fazendo isso eles de fato conseguiram alguns jogos interessantes. Mesmo a jogabilidade não sendo nada boa, eu acho interessante pela tentativa. Só no Brasil existem jogos como Street Fighter, Mortal Kombat, Ecco the Dolphin e A Pequena Sereia pra Master System.</p>
<p>Tem vários videos no YouTube contando a história da Tectoy. Tem até vários canais gringos descobrindo a Tectoy só agora e ficando impressionado de ver o Master System e Mega Drive sendo fabricados por aqui até hoje, recomendo darem uma olhada, é uma parte da história da nossa indústria brasileira que infelizmente ficou parado nos anos 90 e não conseguiu evoluir. Aliás, recentemente lançaram um remake HD do Wonderboy II que ficou bem bacana e tá em lojas como Steam. E claro, alguém fez um mod pra ele relembrando o jogo da Turma da Mônica. Então você tem uma versão HD disso também! Vale conferir só pela nostalgia se você jogou o original no começo dos anos 90.</p>
<p>Bom, vamos voltar pro nintendinho. O que eu mostrei do código do emulador é só o começo do esqueleto. Na verdade eu não escrevi um emulador não, esse foi um projeto que achei aleatoriamente no Github. Vocês podem baixar a versão completa no link que vou deixar nas descrições abaixo. E pra mostrar que ele funciona vamos compilar e executar.</p>
<p>(nes)</p>
<p>Um último insight que eu queria aproveitar pra falar é sobre o PPU. Como expliquei ele era o equivalente aos nossos GPUs de hoje só que muito mais primitivo. Se havia um chip que trabalha incessantemente no nintendinho era o PPU, desenhando 60 quadros por segundo sem parar. Na verdade são dois insights. Vamos lá. Pra começar eu disse que o MOS 6502 roda a meros 1.8 Mhz que é milhares de vezes mais lento que qualquer CPU de hoje.</p>
<p>Antigamente jogos tentavam usar o máximo que a CPU podia oferecer e o timing de tudo era atrelado ao clock do sistema. Hoje em dia não fazemos isso, em vez de atrelar ao clock atrelamos a outras coisas como framerate que é a taxa de quadros por segundo ou vsync que sincroniza com a frequência de atualização do monitor. Ou seja, se temos como alvo rodar o jogo a 60 quadros por segundo, vamos calcular tudo pra caber na faixa de 60 quadros por segundo. Mesmo se o clock aumentar ou diminuir, a referência vai ser os quadros por segundo. Se a CPU for lenta demais vamos ser obrigados a cortar quadros. Se a CPU for rápida demais vamos dar pausas pra esperar. Estou simplificando, claro.</p>
<p>Mas jogos antigos não tinham o luxo de esperar, cada clock contava. Por isso se programava em assembly pra ter controle absoluto do hardware. Daí quando os CPUs evoluiram na geração seguinte e pularam de 1Mhz pra digamos 40Mhz os jogos ficaram rápidos demais. Até por isso nos 386 de antigamente tinha um botão Turbo. A idéia desse botão era diminuir o clock do sistema pros programas não rodarem rápidos demais. Se você tentar rodar um jogo dos anos 80 num PC moderno vai ver que ele roda rápido demais ao ponto de ser injogável.</p>
<p>Um dos desafios mais difíceis nos emuladores de consoles antigos é literalmente adicionar pausas em cada passo pro jogo rodar exatamente como seria antigamente, se não tiver esse controle de pausas o jogo rodaria rápido demais. E nosso emulador precisa levar isso em conta. Por isso temos que editar o arquivo do CPU e adicionar outra informação importante: uma lista dizendo quantos ciclos cada instrução consome. Lembra que falei que um Load, Adição e Store consomem em média uns 5 ciclos? Não pode ser aproximado assim, tem que ser a quantidade exata de ciclos. Então vamos adicionar a lista, onde cada posição é o endereço da instrução como declaramos na estrutura table.</p>
<p>O segundo insight que falei tem a ver com timing de velocidade. O PPU é ocupado demais, ele não pode parar de desenhar na tela. Ele roda com clock 3 vezes mais rápido que a CPU e precisa de uma rotina pra sincronizar. A coordenação entre CPU e PPU é um assunto fascinante em si só mas a parte importante é que a CPU não pode interromper a PPU a qualquer momento. Ela vai estar escrevendo pixels na tela numa frequência precisa e se você interromper, vai quebrar toda a renderização.</p>
<p>Significa que do lado da CPU digamos que você detecte que um botão foi pressionado no controle. Digamos que foi um botão de salto. Você iria querer imediatamente mostrar isso na tela acionando a animação de salto do Mario por exemplo. Então você processa esse estado e envia o comando pro PPU atualizar o sprite do Mario. Mas isso vai quebrar a renderização, então como faz?</p>
<p>A característica importante do PPU é que ele escreve na tela uma linha horizontal de cada vez. Isso se chama ScanLine e é derivado de como monitores de tubo funcionam. Se você nunca viu ele não escreve pixels em qualquer coordenada. No fundo do tubo existe um canhão, que vai atirando eléctrons na tela de fósforo na frente dele uma linha horizontal de cada vez e fazendo um zigue zague pra próxima linha. Diferente de LCDs modernos que tem uma quantidade fixa de linhas, monitores de tubo podem ter quantas linhas quiser, basta o canhão distanciar ou aproximar essas linhas. Por isso bons monitores de tubo tendem a ter imagens melhores do que LCDs. Recomendo ver esse video da Digital Foundry que explica sobre a qualidade esquecida dos CRTs e como eles ainda superam os LCDs.</p>
<p>De qualquer forma, o PPU do nintendinho vai desenhar 240 linhas visíveis e depois vai entrar num período entre as linhas 240 a 260 em que ele não desenha nenhuma linha visível. Isso se chama Vertical Blank ou Vblank. Isso acontece 60 vezes por segundo, uma vez depois de desenhar cada frame. É nessa pequena janela de 20 ScanLines que o PPU tem a oportunidade de ser interrompido e receber ordens da CPU, por exemplo, dizendo o que tem que desenhar no frame seguinte.</p>
<p>De novo, se você é de front-end, uma das boas práticas que deve ter aprendido, principalmente se usa frameworks como um React é nunca escrever direto no navegador. Você acumula todas as modificações e escreve tudo de uma vez depois. E como você faz isso? Em vez de mandar ordens de desenhar direto na árvore de elementos HTML do navegador, o famoso DOM, você manda escrever numa cópia desse DOM que só existe em memória, o famoso Virtual DOM. Então se você modificou 50 elementos nesse VDOM, você não precisou interromper o navegador 50 vezes. Você guarda essas modificações em memória e só interrompe o navegador uma vez pra desenhar só o que mudou, uma vez só.</p>
<p>E é quase isso que se faz no nintendinho também. A idéia de separar lógica da  apresentação não é novidade. É assim que se programa desde pelo menos os anos 80. Então do lado da lógica do jogo na CPU ele faz as modificações em RAM e durante o Vblank o PPU puxa essas modificações e avança pro próximo frame, e com isso temos uma separação de responsabilidades.</p>
<p>Como cada jogo monta estruturas diferentes pra representar o que precisa mandar pra PPU. Mas um jogo que é visualmente fácil de acompanhar é o Super Mario Bros 3 porque ele mantém a estrutura completa da tela com cada elemento aberto na RAM. Se você procurar por memory map e o nome do jogo no Google facilmente vai achar a documentação que várias pessoas gastaram horas garimpando e com isso sabemos que a partir do endereço 0x6000 na RAM vai ter os dados de montagem de cada tela da fase.</p>
<p>Vamos abrir no Mesen e vou colocar lado a lado pra vocês verem. Se procurarmos na RAM depois do endereço 0x6000 rapidamente vamos encontrar padrões que se assemelham à tela que estamos, e na sequência vai tendo todas as outras telas dessa fase. Olhem os códigos internos de cada bloco dessa tela e veja como o código muda quando eu modifico um objeto, por exemplo batendo nele.</p>
<p>E se você é adepto de Mario Maker, esse é o Mario Maker raíz. Vamos olhar algumas telas pra frente. Por tentativa e erro sabemos que essas &ldquo;arrobas&rdquo; representam moedas. Vamos criar um monte &hellip;. e agora vamos até essa tela. &hellip; Olha que bonito. E de novo vejam como cada vez que vou pegando as moedas o código se modifica na RAM.</p>
<p>De novo usando a analogia com front-end, isso é o equivalente a você dar um inspect no navegador e sair editando os elementos. E aproveitando que estamos no Mesen, vamos abrir primeiro o Super Mario de novo. E esses são todos os tiles que tem no cartucho, somente um único bank de 16 kbytes. Pense que o jogo inteiro, que não é curto, é desenhado somente com esses tiles. É impressionante se considerar que antes dele você só tinha jogos nível pacman bem simples e eles conseguiram esticar pra múltiplas fases que parecem diferente mas que são basicamente os mesmos tiles com paletas diferentes de cores.</p>
<p>Mas se abrirmos o Super Mario 3 de novo, que vem com o Mapper conhecido como MMC5, ele vai ter bem mais banks como eu expliquei. E olha só no visualizador de novo. Podemos ir explorando os diferentes banks que são os conjuntos de tiles. E por isso o Super Mario 3 tem visuais bem mais elaborados e diferenciados de mundo pra mundo. Não é só uma mudança de paleta de cores mas de diversidade de tiles. E no último olha como só a tela de entrada com título grande ocupa um bank quase inteiro. Por isso quando tem imagens bitmap grande que ocupam a tela inteira a gente sabe que é um jogo caro porque literalmente ele tá usando uma parte considerável do chip só pra guardar essa uma imagem que só aparece uma vez.</p>
<p>Recentemente teve uma ressurgência de games independentes publicando nos Steam da vida que tentam emular o visual pixel art pra ter aquela vibe de jogo retro. Um bom exemplo disso é o excelente jogo Celeste, considerado um dos melhores jogos de plataforma pra speedrun pela nuance nos controles e como ela recompensa quem consegue combinar timing com movimentos avançados do jogo pra percorrer as fases. Outros exemplos são os já classicos Meat Boy ou Shovel Knight também. Mas o que esses jogos tem em comum é que eles são modernos mas só escolheram um estilo artístico de pixel art pela estética e não porque foram obrigados a isso.</p>
<p>Entendam, jogos antigos não são pixel art porque o povo gostava do estilo mas sim porque a resolução da tela era de meros 256 pixels na horizontal por 240 pixels na vertical. Isso é um quarto da resolução de um monitor full HD que tem 1080 pixels na vertical. Cabe literalmente 16 telas de nintendinho numa tela full HD. Mas agora você entende também que não é só a resolução, todo o design do jogo, das fases, inimigos e outros elementos dependem muito do espaço na ROM. Quanto mais ROM se adicionava no cartucho mais caro ele ficava. Por isso a maioria dos jogos se mantinha nos limites de 40 kilobytes que o Super Mario original usava. Em comparação, a instalação do jogo Celeste tem mais de 700 megabytes.</p>
<p>Existem vários programadores hoje explorando programar no hardware limitado do nintendinho. Um grande exemplo é o jogo Micro Mages da Morphcat Games. Dois anos atrás eles soltaram um mini documentário mostrando como as limitações do console e do cartucho influenciaram as decisões de design do jogo. Eles se colocaram no desafio de fazer um jogo de verdade, bem feito, escrevendo em Assembly de 6502 e ainda suportando 4 jogadores simultâneos.</p>
<p>O jogo é excepcional, eu paguei pra ter a ROM e recomendo que comprem também, são 10 dólares bem gastos. A mecânica é muito simples, lembra um pouco a idéia do Celeste. É um jogo vertical onde a tela vai subindo lentamente e você precisa alcançar o fim da fase antes que a tela te alcance. E falando em fases, vale um parêntese pra explicar mais uma estrutura de dados que o nintendinho usava, os nametables. Em resumo hiper resumido, é um espaço na memória do PPU que organiza o equivalente a 4 telas, duas em cada linha.</p>
<p>Se você está num Mario que é plataforma horizontal, ele vai mantendo a próxima tela no espaço à direita. Olha como a memória vai atualizando conforme vamos avançando pelas telas.</p>
<p>Se for plataforma vertical como Kid Icarus ele mantém a próxima tela no espaço pra cima e você pode trabalhar os modos desse namespace se precisar de algo mais complexo como num Mario 3 que é horizontal mas quando você pega a folha pode voar vertical.</p>
<p>No caso do Micro Mages ele vai usar um modo semelhante ao do Kid Icarus. Jogando um pouco, veja lado a lado como o próximo nivel vai se montando nesse espaço de memória de nametables.</p>
<p>No video da Morphcat ele começa explicando o que eu já falei, que gráficos são divididos em duas tabelas CHR. Ele chama tiles de sprites mas é a mesma coisa, eu chamo sprites os tiles que estão na tela neste momento. Ele continua repetindo que cada tile é um quadrado de 8 por 8 pixels e que pode escolher até 3 cores da paleta. E que juntamos tiles pra formar o que ele chama de meta-sprites que é o objeto completo. Continuando, ele explica que só dá pra ter até 4 paletas de cores e que as cores são reusadas pra outros objetos como inimigos porque não dá pra ter cores diferentes pra cada coisa, é tudo as mesmas paletas.</p>
<p>Outra limitação do PPU que eu não mencionei ainda é que ele só consegue desenhar 8 sprites por scanline. Como cada personagem é formado por duas linhas de dois tiles cada, nesse exemplo vai ter 10 tiles por linha em vez do máximo de 8. Se tiver mais que 8 os sprites seguintes simplesmente não são desenhados. Por isso um truque muito usado é escolher 8 tiles dos 10 e desenhar num frame, daí no próximo frame você esconde 2 que foram desenhados no anterior e troca por 2 que ainda não tinham sido desenhados, e vai permutando de frame a frame. Por isso muitos jogos de nintendinho parece que os personagens ficam piscando na tela. Isso acontece quando eles se movimentam e na mesma linha acaba ficando mais de 8 sprites.</p>
<p>Por causa dessas limitações, a primeira decisão da Morphcat foi criar personagens que precisam só de um tile pra formar o sprite em vez de 4 ou mais. Além de economizar em espaço, isso também evita o flicker, aquelas piscadas, porque vai ser mais difícil ter mais de 8 sprites por scanline. Falando só em espaço, de volta à tabela de tiles CHR na ROM, esse é o espaço ocupado por todos os tiles que formam as animações do Mario, que nós já vimos antes. E agora o espaço ocupado por todas as animações dos magos nesse novo jogo. Veja como economiza espaço escolhendo fazer personagens menores que cabem num único tile. E não só isso, também conseguimos adicionar mais quadros na animação, tornando a movimentação mais fluida.</p>
<p>Outro desafio são os chefões, que costumam ser sprites grandões. Por exemplo, esses são todos os frames de animação de um dos chefões. O problema é que se você tentar encaixar todas essas imagens no que restou do espaço CHR, simplesmente não vai caber. E isso é só um chefão. Agora vem a parte onde a programação e o design precisam andar juntos, porque o designer tem que fazer um chefão cujos quadros podem ser divididos em partes, no caso três, que podem ser animados independentemente.</p>
<p>Olhando só os quadros que fazem a animação da cabeça, dividimos em tiles, e vemos se tem repetições. E de cara você pode ver que a primeira metade em todos os três quadros é igual, então só precisa armazenar uma versão, que pode ser reusada em todos.</p>
<p>Não só isso, se um tile é o espelho de outro tile, você guarda só uma versão e pede pro nintendinho inverter horizontalmente, e assim pode economizar mais um pouco. E fazendo isso, só na cabeça otimizamos de 16 tiles pra 4 que realmente precisam existir na ROM.</p>
<p>Pra parte do meio, fazemos a mesma coisa: procuramos todos os tiles repetidos, todos que podem ser invertidos e diminuímos mais ainda.</p>
<p>E a última parte tem 5 animações mas de cara as duas últimas são inversões das duas primeiras. E fazendo todas as mesmas reduções, removendo tudo que é repetido, compare os tiles que sobraram com os que originalmente eram necessários sem otimizar.</p>
<p>O video deles continua mostrando como aplicaram outras técnicas pra reduzir ainda mais a quantidade de memória necessária pra montar as fases. Mas eu vou pular pra não ficar extenso demais, por isso recomendo que assistam e também comprem o jogo.</p>
<p>Falando em programar seus próprios jogos, como você faz isso? Simples, se pesquisar no Wiki da Nesdev vai encontrar sobre ferramentas, tem vários fóruns ainda ativos onde o povo troca dicas e informações sobre as melhores técnicas e ferramentas, mas o mais básico é o cc65 que vem com o montador ca65 e o disassembler da65. E se procurar num Github vai encontrar vários exemplos, de hello world a joguinhos completos feitos do zero como o Micro Mages. Se você já pensou em programar games e não quer ser só mais um mero clonador de Flappy Bird, programar em hardware restrito como um nintendinho é um excelente exercício pra aprender todos os fundamentos de um bom design de games.</p>
<p>Por exemplo, baixei este projetinho que faz todo o setup do ambiente, carrega o mínimo de tiles e tudo mais pra ter fontes e com isso consigo fazer um hello world da vida rapidamente em C. E sim, é possível programar em C e compilar com o cc65 pra binário de 6502 específico de nintendo. A desvantagem de programar em C é que ele vai gerar um binário menos otimizado do que um bom programador faria na unha direto em assembly. Por outro lado, como estamos em ambiente emulado você sempre pode mexer no emulador pra ter uma CPU mais rápido do que o nintendinho original e quantos banks de ROM quiser.</p>
<p>Aliás, sobre o hello world, considere o seguinte: o nintendinho não tem um sistema operacional, sequer vem com fontes numa ROM, o jogo tem que fazer tudo, então pra fazer um hello world, você precisa primeiro armazenar suas próprias fontes no espaço CHR da ROM. Só depois pode escrever alguma coisa.</p>
<p>Falando nisso vale a pena mostrar como subir um pouquinho o nível da linguagem pra não ficar tão tedioso fazer só assembly puro. Não é um compilador ainda, tá longe disso, mas muitos assemblers tem capacidade pra macros. Pra quem não sabe, macro é como um template. Um procesador de Markdown é tipo um macro de HTML. Quando eu digito asterisco o processador vai pegar o texto seguinte e colocar entre as tags de bold por exemplo. Macro é uma forma de reduzir copy e paste de trechos de código.</p>
<p>O ca65 que é o assembler mais recomendado pra programar pro nintendinho já vem com vários macros que adicionam algumas construções mais modernas como ifs, whiles e outras coisas, assim você consegue ter mais dicas visuais do que cada trecho faz em vez de ver só um linguição de instruções. Some isso a subrotinas com JSR que mostrei no video anterior e é possível programar sem ficar completamente doido no processo. Mas pense assim: é assim que se programava games de verdade. O grande lance de programar em consoles é tirar o máximo que o hardware consegue oferecer.</p>
<p>Outra coisa interessante. Hoje em dia não existe mais o código fonte da maioria esmagadora dos games. Muitas empresas da época até faliram e muito material se perdeu. Mas isso não tem problema. Você sempre consegue reabrir o código a partir do binário. Pra isso serve a ferramenta da65 que vem no mesmo pacote. Você pode fazer o desassembly e voltar aos mnemônicos. Obviamente não vai ter o nome correto das subrotinas, labels, constantes e variáveis. Mas se você tiver experiência com o hardware vai saber por exemplo que se tiver alguma coisa mexendo com o endereço a partir de 0x8000 está acessando a ROM, se mexer com o endereço 0x4016 ou 0x4017 está falando com os controles.</p>
<p>Daí você pode fazer a engenharia reversa que é adicionando as etiquetas e nomes das coisas mais óbvias primeiro e fazer o caminho inverso. Ah, se esse trecho mexe com o endereço 0x4016 deve ser o trecho que decide o que fazer quando aperta um botão. Além disso você pode fazer tracing, visualizar o que acontece em cada registrador e na memória a cada instrução pra determinar do que se trata cada subrotina. É super trabalhoso mas fazendo isso você consegue encontrar praticamente tudo. Diversos jogos já foram mapeados assim.</p>
<p>E de fato, se procurar no Github você vai achar um disassembly do Super Mario praticamente completo com todos os nomes de subrotinas, etiquetas e constantes. É o mais próximo que se chegou do código fonte original. E em cima disso você pode modificar o jogo como quiser no nível do código em vez de se limitar a só modificar os bytes no nível da ROM como fizemos com textos e tiles. Podemos adicionar tiles novos ou fazer textos mais longos e reprogramar a lógica porque o assembler vai conseguir recalcular todos os endereços corretamente e gerar um novo binário que funciona.</p>
<p>Finalmente, vou completar a maior tangente que fiz até hoje. Vocês vão se lembrar que o episódio anterior começou só porque eu vi um video falando sobre o Game Genie. Como expliquei antes, Game Genie é um hardware que fica entre o cartucho e o console. E agora sabemos que o cartucho responde a uma faixa de endereços bem específico entre $8000 e $FFFF. Também sabemos que endereços que a CPU pede não correspondem à localização exata nos cartuchos por causa do sistema de mappers e bank switching.</p>
<p>Existem duas formas de adicionar cheats, ou trapaças nos jogos. Uma delas é alterando o valor carregado na memória RAM e a outra é alterando direto o binário na ROM. Com bastante paciência você consegue visualizar o conteúdo da RAM usando emuladores como o FCEUX e o Mesen, gravar dumps da memória entre uma parte do jogo e outro e comparar os bits pra ver o que mudou. Por exemplo, gravar a RAM antes de morrer e depois de morrer pra ver qual byte diminuiu e ele é um candidato pra ser o local na memória que representa quantas vidas você tem, daí você pode testar esse valor.</p>
<p>Com tantas décadas de gente escovando bits, existem bancos de dados inteiros com diversos cheats pra cada jogo. Você facilmente consegue encontrar código pra tudo. Num emulador como o RetroArch tem até funcionalidades pra sincronizar com esses bancos de dados daí você nem precisa digitar os códigos manualmente. Só escolher o jogo, selecionar em cheats, carregar e já era.</p>
<p>Resumindo o video do canal Retro Game Mechanics Explained o que o hardware do Game Genie faz é receber um endereço de 16-bits e um ou dois valores de 8 bits cada. Isso forma códigos de 6 ou de 8 letras. Quando o código tem 6 letras é fácil porque os primeiros 4 dígitos representam o endereço na RAM e os dois últimos digitos representam o valor que o Game Genie vai devolver e pronto. Quando estamos falando de jogos usando o Mapper mais simples, como num Super Mario original que só suporta ROMs com 40 kilobytes, isso é tudo que precisamos.</p>
<p>Agora que você entende bank switching, sabe que no mesmo endereço da RAM pode estar apontando dados em banks diferentes da ROM. Depende de qual bank tá apontando no momento. Então o Game Genie não pode responder com um valor fixo  toda hora, só quando um determinado bank tá selecionado. Pra isso serve o código de 8 digitos. De novo, os primeiros 4 formam o endereço na RAM. Agora os dois dígitos seguintes representam qual é o valor que esperamos encontrar na RAM, ou seja, o valor que ele carregou do bank. Se for diferente do que passamos é porque o console tá olhando um bank diferente do que queremos. Mas quando o valor voltar igual, é porque ele mudou pro bank que queremos, e aí devolvemos o valor fixo que tá no ultimos dois dígitos do código.</p>
<p>A forma como o Game Genie monta os códigos é só um embaralhamento arbitrário que ele faz sei lá porque, talvez só pra deixar o código um pouco mais legível. É só uma obfuscação simples. Pra isso primeiro você pega os bits do endereço e dos dois valores, daí embaralha os bits pra outras posições, e no fim substitui cada bloco de 4 bits por uma letra de acordo com uma tabela arbitrária. Pra cada console tem uma regra de embaralhamento e tabela de mapeamento de letras diferentes.</p>
<p>Eu fiz um programinha bem besta na linguagem Crystal que pega o código do Game Genie, traduz de volta em bits, desembaralha os bits e devolve o endereço e os valores. Eu fiz em Crystal só porque eu quis, nenhuma razão especial, podia ser em qualquer linguagem. Vou deixar o link pra esse código nas descrições abaixo. Talvez eu termine de fazer o desembaralhamento das versões de game genie pros outros videogames mas eu queria um executável simples pro meu teste.</p>
<p>Eu fiz algumas coisas do jeito menos otimizado, estilo &ldquo;o que funciona primeiro&rdquo;, então não xinguem. Pelo menos tem testes unitários direitinho. Veja esse por exemplo, eu garanto que eu passo um código de Game Genie e ele vai gerar o binário que eu quero. Daí no outro spec eu garanto que dado esse linguição de bits vai gerar a representação em hexadecimal direitinho também.</p>
<p>O código em si é muito simples. Ele começa pegando o código de 6 ou 8 letras do game genie, processa letra a letra e troca pela representação binária. Eu não estou lidando com o número binário e sim com a representação em texto mesmo pra ficar mais fácil. Depois de montar esse binário, o próximo passo é desembaralhar, e isso é arbitrário do game genie, só trocar bits de posição. Finalmente, com os bits rearranjados, faço um outro loop besta pegando de 4 em 4 bits e transformando em hexadecimal.</p>
<p>Vocês vão notar que eu fiz de um jeito meio tosquinho aqui criando um array pra mapear cada conjunto de bits no hexadecimal em vez de converter a string num número e depois usar um formatador pra hexa, mas foi mais porque eu não achei fácil o jeito de fazer isso em Crystal ainda. Quando descobrir eu mudo. Mas pros meus propósitos esse código tá suficiente. Com isso eu posso compilar um binário e &hellip; pronto, posso chamar o binário, passar o código de game genie e ele devolve o hexadecimal certo.</p>
<p>O próximo passo foi mexer no emulador feito em Go. A grande maioria dos emuladores mais maduros e populares tem suporte a códigos de game genie. Mas esse emulador mais simples não tinha, por isso achei que seria um exercício interessante. Pra começar eu resolvi modificar o arquivo do console adicionando uma estrutura chamada Cheat que vai ter só dois elementos, o valor de condição pra comparar com o que tá no bank da ROM selecionado nesse instante, e o valor trapaceado que eu quero devolver. Daí eu adiciono na estrutura do console uma nova estrutura, um Map de Cheats. Map é o que algumas linguagens chamam de dicionário ou de hash. É uma lista que vai mapear um número inteiro, que no caso, é o endereço com uma instância da estrutura de Cheat.</p>
<p>Agora precisamos ler os cheats de algum lugar. No caso escolhi ler de um arquivo. Eu não estou mostrando, mas estou seguindo o padrão que esse emulador já fazia pra fazer saves dos jogos, criando um hash md5 do binário. O nome do arquivo que eu vou buscar é o hash md5 do Super Mario numa pasta .nes/cheats. Essa função readCheats recebe o caminho pra esse arquivo e só vai lendo linha a linha e gravando numa lista. Assim podemos ter múltiplos arquivos pra com códigos específicos de cada jogo que queremos.</p>
<p>A função seguinte vai interpretar essa lista. A função LoadCheats vai usar a readCheats acima passando o caminho do arquivo e recebendo a lista que ele ler. Daí eu passo um caminho fixo mesmo por enquanto, pro executável daquele programinha que eu fiz em Crystal. Ele vai passar os códigos pra esse programinha pra decodificar o endereço e valores.</p>
<p>Com o que ele devolver, checo se é um código de 6 ou 8 digitos, e isso serve pra preencher ou não aquele campo de condição na estrutura de Cheat. Feito isso associamos o endereço devolvido com a estrutura de Cheat e jogamos no dicionário na estrutura do Console. Com isso o console tá ciente dos códigos.</p>
<p>Pra de fato aplicar o cheat o lugar mais óbvio pra procurar é a estrutura de Memory, lembram dele? É nesse arquivo que tem a lógica pra escolher qual mapper o cartucho carregado precisa. Mas ele abstrai os mappers e a gente não precisa se preocupar. Os Mappers vão se encarregar de ler da ROM nos banks corretos. Então o que vamos fazer é, em vez de devolver o valor lido, vamos gravar temporariamente numa variável e passar pra uma nova função chamada replaceWithCheat.</p>
<p>Essa função recebe o endereço consultado e o valor devolvido. Agora acessamos o dicionário de Cheats que tá na instância do Console e procuramos por esse endereço. Se não achar nada, devolve o valor real original. Caso encontre ele checa se precisa comparar com a condição do Cheat.</p>
<p>Se não tiver condição ou se a condição bate com o valor real, então ele devolve o valor falsificado. E pronto, é só isso que precisa pra implementar um game genie num emulador. Com isso o console vai receber o valor falsificado em vez do valor real e nosso Super Mario vai começar com mais vida. Podemos testar isso.</p>
<p>Veja o arquivo de cheats com o código. Agora executamos o emulador passando a ROM do jogo, esperamos carregar e olha só, 9 vidas!!</p>
<p>Mas digamos que a gente é ruim em Super Mario e o tempo sempre acaba, quero que comece com 900 segundos em vez de só 400 e se procurar no Google descubro que o código pra isso é VGYOKK, então vamos editar o arquivo de trapaças e adicionar o código. Reiniciamos o emulador e &hellip; veja só que bacana, 9 vidas e 900 segundos pra terminar a fase.</p>
<p>Mas digamos que a gente é tão ruim, mas tão ruim que morre toda hora. Malditos Goombas! Mas não se preocupem, existe um código pra isso. Vamos editar de novo o arquivo e adicionar SSASSA. Agora vamos reiniciar o emulador e corremos de cara pra um Goomba. E olha só, invencibilidade!!</p>
<p>Vocês vão notar no terminal que toda vez que eu encosto num inimigo o programa busca o endereço 0xD88D pra checar se é pra perder vida ou não, daí se devolver 0xD5 ele sabe que é invencível. E é assim que trapaceamos pra chegar até o final fácil! E com isso finalmente consegui fechar o assunto que comecei no video anterior, fazer meu próprio Game Genie de Nintendinho. Com tudo que expliquei desde o vídeo anterior agora vocês entendem exatamente como tudo funciona.</p>
<p>E pra finalizar o episódio de hoje quero mostrar como vocês vão ter uma noção melhor pra entender videos de outros canais também. No próprio canal do Retro Game Mechanics Explained, alguns dos videos mais divertidos é a explicação de diversos bugs que esses jogos tem, e como podemos tirar vantagem disso. Uma das categorias de gamers mais escovadores de bits são os speedrunners. São jogadores que competem pra bater o recorde de quem acaba o jogo no menor  tempo. Tem várias sub-categorias. Uma das mais divertidas é quando eles encontram bugs que permitem, por exemplo, saltar todas as fases e ir direto pro final.</p>
<p>Antes de falar desse bug preciso falar de uma última ferramenta que emuladores mais avançados como o FCEUX tem, se chama TAS ou Tool Assisted Speedrun. Lembram no nosso código em Go que eu associo controles na estrutura de console? Obviamente nós conseguimos ler o que vem do controle pra poder codificar o que cada botão apertado vai fazer no jogo. E naturalmente eu posso fazer o que quiser com esses dados, inclusive salvar num arquivo. Mais do que isso, como eu controlo a PPU também consigo saber exatamente em que frame cada botão foi apertado.</p>
<p>Então eu também consigo ler esse tal arquivo que diz em que frame foi apertado qual botão e com isso podemos dar replay no jogo inteiro repetindo exatamente tudo que que foi apertado com precisão de 1 frame. E é exatamente assim que esses jogos são arquivados em sites como o tasvideos.org, que mantém registros de todos os recordes. E você pode baixar o arquivo formato .fm2 ou .fm3 que contém exatamente essa sequência, rodar no seu emulador e assistir o speedrun exatamente como a outra pessoa jogou.</p>
<p>Então eu vou abrir o FCEUX, carregar a ROM do Super Mario 3, abrir o TAS Editor e carregar o arquivo .fm2 que baixei do site tasvideos.</p>
<p>Pronto, agora é só despausar e assistir. Vou pular as primeiras fases porque ele usa outros truques conhecidos pra ir pulando de warp zone em warp zone até chegar no mundo 7. Nesse ponto a maioria dos speedrunners ia pro Dark World normalmente, mas nessa corrida eles vão pelo Pipe World porque é de lá que dá pra acionar o bug. Assistam primeiro.</p>
<p>(glitch run)</p>
<p>Foda né, vocês não entenderam nada eu imagino, mas deu pra ver que eles fazem uma sequência bem absurda de coisas no Pipe World, daí começa tudo a descer pra um monte de sujeira de tiles e de repente ele chega na princesa direto. Agora que vocês tem uma idéia de como as coisas funcionam, dá pra entender que o bug aciona alguma coisa que faz a tela descer por um pedaço de RAM com bytes aleatórios que ele manda pro PPU que mapeia os tiles correspondentes, montando uma fase toda bagunçada e com comportamento incerto. E em algum momento dá um JUMP. O truque é simples, vamos usar a posição dos sprites na RAM pra montar um assembly em tempo real e dar um jeito de executar.</p>
<p>O código em si que precisa ser escrito é JSR 0x8FE3. Se conseguir fazer o jump esse é o endereço pra subrotina que inicia a sequência final da princesa. Então precisamos de 3 bytes consecutivos num lugar especial na RAM, os bytes sao 0x20 que é o JSR, e depois 0xE3 e 0x8F que é o endereço com os bytes invertidos por causa de little endian, que vocês já sabem como funciona.</p>
<p>A posição X dos inimigos, especialmente dos koopa troopers ficam sempre no mesmo lugar e não apagam mesmo quando o sprite some da tela. Por isso esses bytes são bons candidatos pra usar. Mas não adianta sair matando qualquer koopa. Precisamos que eles estejam na posição correta nessa lista e também que estejam numa posição X específica. Pra isso precisamos tentar fazer com que eles apareçam numa determinada ordem primeiro. A lógica é que novos sprites sempre vão aparecer primeiro na posição mais alta livre da lista primeiro. Então usamos essa informação pra fazer eles aparecerem numa ordem em particular.</p>
<p>Ao matar essa tartaruga e ir pro cano enquanto ela ainda está na tela, podemos forçar as plantas piranha pra aparecer nos slots 2 até 4 e o próximo koopa no slot 5.</p>
<p>Matamos as plantas pra elas não reaparecerem mais tarde quando voltarmos pra essa parte.</p>
<p>Agora o koopa entre os blocos de interrogação vai estar no slot 4 e o parakoopa no slot 3. Pegamos a casca dessa tartaruga e matamos jogando ele no bloco. Isso fixa o byte na posição fixa 0xE3 que precisamos.</p>
<p>Daí ficamos exatamente nessa posição em cima do cano e damos uma rabada no parakoopa quando ele estiver exatamente alinhado com o topo do outro cano pra garantir que a casca aterrisse na posição X hexadecimal 0x20, e com isso temos o byte que representa o jump. Agora vamos pra baixo, agarramos a casca desse koopa e voltamos ao comeco do nível.</p>
<p>Nesse ponto precisamos realizar o bug do cano apertando pra baixo no controle ao mesmo tempo que faz um clip na parede no canto desse cano. Às vezes o Mario consegue fazer um clip numa parede, tipo passar por ela, se estiver rápido o suficiente e bater bem na beira do grid de 16 pixels, é um movimento bem preciso e às vezes precisa fazer várias vezes pra acertar. Nessa sequência não tem tanto problema se de vez em quando pisar na casca pra tartaruga não acordar.</p>
<p>Uma vez entrando no cano inicia uma sequência de bugs porque não tava programado pra ter como ele entrar no cano nesse ponto, dai vai descendo por todo esse lixo aleatório que tá na memória. O PPU vai simplesmente mapeando o lixo que vai recebendo com os tiles na tabela CHR e mostrando na tela. Por isso fica essa bagunça visual.</p>
<p>No final tem que pular com muito cuidado com a casca e alinhar com o fundo bem nessa posição. Tem um detalhezinho que se notar que esse bloco de música estiver parcialmente cortado, talvez precise mover o Mario um pixel pra direita pra compensar a posição da camera. Deixamos o koopa reaparecer nas nossas mãos e desaparecer no fundo da tela, e essa posição onde ele desaparece nos dá o último byte que precisávamos, valor 0x8F. Finalmente caímos aqui e pulamos pra ativar a instrução. E se tudo foi configurado exatamente como mostrado aqui, vamos pular direto pra princesa e terminar o jogo.</p>
<p>Pra entender o que aconteceu vamos usar tudo que aprendemos até agora. Essa fase vertical é mapeada entre os endereços 0x6000 e 0x6EFF, que é suficiente pra 16 telas. Mas aquele cano que entramos depois de clipar pela parede manda o Mario pra tela 19 que obviamente não existe. Então acontece um transbordamento, um overflow da memória e começamos a acessar áreas da RAM que não era pra acessar.</p>
<p>E pra piorar, além de visualmente aparecer essa zona, a rotina de desenho falha e o que estamos vendo pode não estar de fato lá, por isso o Mario consegue subir numa plataforma invisível. A coincidência é que o final desse cano deixa o Mario do lado de um bloco de nota invisível e é batendo nesse bloco que ativa os bytes de Jump que configuramos.</p>
<p>Quando batemos num bloco de musica o tile é temporariamente removido e outra versão do sprite aparece pra fazer a animação. E claro, o índice nos dados da tabela de fase tá todo zoado quando procura por esse tile e ele pega o endereço 0x9C70 pra atualizar, que não é nem de longe perto da tabela de dados. Pior esse endereço simplesmente não existe na RAM.</p>
<p>Recapitulando o que já vimos sobre os endereços que nintendinho entende, temos a RAM entre 0x0000 e 0x1FFF e temos Work RAM entre os endereços 0x6000 e 0x7FFF e já sabemos que de 0x8000 até 0xFFFF é a região reservada pra ROM, ou seja, pro cartucho. Então aquele índice errado do bloco de musica tenta escrever na ROM. Mais do que isso, esse endereço na verdade fala com o Mapper do cartucho. E você sabe o que é um Mapper.</p>
<p>Por acaso quando tentamos escrever nesse endereço 0x9C70, é o mesmo que dizer pro Mapper fazer uma troca de banco, pra apontar pra outros bancos da ROM. Recapitulando, já sabemos que entre os endereços 0x8000 e 0xFFFF só cabe 32 kilobytes de dados, mas a ROM de programa do Super Mario 3 tem 256 kilobytes. Obviamente não cabe e por isso durante o jogo ele vai pedindo pro Mapper ir trocando os bancos pra apontar pra outras regiões da ROM.</p>
<p>Então esse trecho tá fazendo seu trabalho feliz e contente, achando que tá atualizando um tile na tela pro bloco de musica, mas em vez disso quando executa a instrução no endereço 0xDD1A, a ROM de 0xA000 a 0xDFFF é trocado pelo mapper do nada. Ele literalmente atira no próprio pé e as próximas instruções foram trocadas pelo que tá no novo banco que o Mapper trocou.</p>
<p>O apontador de pilha nesse momento da execução é 0xFD, que sabemos que quer dizer que a pilha tá quase vazia, lembra do video passado e do código de Reset da CPU que fizemos antes? Lembra que a instrução RTS vai retornar pro último endereço que estiver na pilha? E por acaso na pilha tem só um endereço nesse momento. E de fato essas instruções novas que vieram na troca do bank pelo Mapper, ele continua executando e uma hora bate num RTS fazendo ele pular pro endereço 0x8F4D.</p>
<p>Agora caímos no meio de uma nova rotina com uma pilha vazia, coisa que ele não esperava. Daí ele continua executando e uma hora vai bater num RTS, vai olhar pra pilha pra saber pra onde retornar. Mas a pilha tá vazia então quando isso acontece o ponteiro faz um wrap, ele circula como se a pilha estivesse totalmente cheia, lembra de quando falei de stack overflow no video anterior?</p>
<p>Lembrando que a pilha fica entre os endereços 0x0100 e 0x01FF, mas praticamente nunca a pilha enche totalmente então alguns programas acabam usando o topo da pilha pra outra coisa e no caso o jogo mantém informação da fase em 0x0100. Lá vai ter o valor 0xC0 se forem fases horizontais e 0x80 em fases verticais. E como o ponteiro circulou pro topo da pilha ele pega o valor que tá lá, subtrai 1 e retorna o endereço 0x0081.</p>
<p>Beleza, então o RTS vai pular pra 0x0081 e isso é endereço da RAM que tem um monte de dados voláteis sobre as propriedades da fase. Por exemplo em 0x007E a 0x0086 tem propriedades sobre os sprites carregados nesse momento, tipo o timer de quando as plantas piranha tem que aparecer dos canos, ou como os parakoopas voam. Dos endereços 0x0087 a 0x008F tem o high byte da posição Y de cada sprite, que é o número da tela onde eles estão.</p>
<p>Agora chegamos onde queríamos porque dos endereços 0x0090 a 0x0098 estão os low bytes da posição X de cada sprite na tela, que são as posições que viemos manipulando no começo e configuramos o JUMP. Os bytes antes disse são dados, mas o processador não sabe disso e tenta executar como se fossem instruções. Por coincidência nenhuma das tentativas de executar esses dados termina num crash e ele consegue chegar até nosso jump. Como esses dados anteriores podem ser qualquer coisa que representa os tais elementos na tela que falei, poderiam ser bytes que representam instruções que crasheiam, então essa sequência toda que fizemos não é garantido que funciona sempre, mas funciona vezes o suficiente.</p>
<p>Chegando no nosso JSR 0x8FE3 ele pula pra um programa que fica num bank que nunca é trocado pelo mapper então garantidamente sempre vai estar lá e é a rotina pra carregar o quarto da princesa.</p>
<p>Pra fechar, a sequência pra montar a instrução de jump pode ser feita de várias formas contanto que a posição X dos inimigos certos entre na sequência correta nos slots da memória. Esse é o recorde mundial usando esse bug do MitchFlowerPower onde ele termina o jogo em 3 minutos e 9 segundos. Ele mesmo jogou manualmente e gravou seus comandos.</p>
<p>E com tudo isso dito, finalmente chegamos ao final do episódio! Tudo que eu queria era explicar como o Game Genie funciona, mas pra realmente entender era necessário entender cada componente de como um computador funciona. Com isso eu espero que se você é iniciante tenha conseguido ter uma visão um pouco mais abrangente do que significa fazer um hardware funcionar.</p>
<p>Pra mim isso é programação. Programação nunca foi sobre seguir receitas e procedimentos prontos e sim encontrar um cenário de restrição e com conhecimento de verdade usar as ferramentas disponíveis pra conseguir soluções criativas. Nenhum livro, nenhum curso, nenhum tutorial jamais vai ensinar essas coisas. Só quando você encara problemas difíceis é que conhecimento de verdade começa a aparecer. Eu tenho certeza que vocês nunca imaginaram que tinha tanta coisa que podia ser dito sobre um videogame obsoleto dos anos 80.</p>
<p>Se você ficou empolgado pra escrever seu próprio emulador recomendo que acompanhem outro canal, o do One Lone Coder que está desenvolvendo um emulador de NES em C++ e explicando passo a passo no seu canal. Vou deixar o link nas descrições abaixo. O próprio canal do Retro Game Mechanics Explained na realidade tem videos detalhados explicando o funcionamento do Super Nintendo. Como funcionam os gráficos e cores, como funciona a memória, como funciona o lendário Mode 7. Tem bastante coisa pra aprender.</p>
<p>Se vocês pensam que eu acabei todos os assuntos, tão enganados. Descer nesse buraco de coelho me levou a rever um monte de coisas do passado em relação a emuladores e estou pensando em fazer um episódio mais leve do que esses pra explicar o ecossistema atual de emuladores. Pra variar eu vou descer mais no detalhe em alguns deles então aguardem pelo próximo. Como vários assuntos eu tive que resumir ou mesmo pular pra não ficar confuso demais, se você também é entusiata desses assuntos, não deixem de complementar nos comentários abaixo. Se curtiram o video mandem um joinha, assinem o canal e cliquem no sininho. E principalmente ajudem o canal compartilhando os videos com seus amigos. A gente se vê na próxima, até mais!</p>
<p>Links:</p>
<ul>
<li>
<p>Super Mario Bros. 3 - Wrong Warp (<a href="https://www.youtube.com/watch?v=fxZuzos7Auk"target="_blank" rel="noopener">https://www.youtube.com/watch?v=fxZuzos7Auk</a>)</p>
</li>
<li>
<p>A Comprehensive Super Mario Bros. Disassembly (<a href="https://gist.github.com/1wErt3r/4048722"target="_blank" rel="noopener">https://gist.github.com/1wErt3r/4048722</a>)</p>
</li>
<li>
<p>Lembra deles? Confira jogos brasileiros do Master System lançados pela Tectoy! (<a href="https://blogtectoy.com.br/lembra-deles-todos-jogos-brasileiros-do-master-system-lancados-pela-tectoy/"target="_blank" rel="noopener">https://blogtectoy.com.br/lembra-deles-todos-jogos-brasileiros-do-master-system-lancados-pela-tectoy/</a>)</p>
</li>
<li>
<p>Free NES assembler (<a href="https://bisqwit.iki.fi/source/nescom.html"target="_blank" rel="noopener">https://bisqwit.iki.fi/source/nescom.html</a>)</p>
</li>
<li>
<p>Micro Mages (<a href="https://morphcatgames.itch.io/micromages"target="_blank" rel="noopener">https://morphcatgames.itch.io/micromages</a>)</p>
</li>
<li>
<p>Nes Dev Wiki (<a href="https://wiki.nesdev.com/w/index.php/Nesdev_Wiki"target="_blank" rel="noopener">https://wiki.nesdev.com/w/index.php/Nesdev_Wiki</a>)</p>
</li>
<li>
<p>Computer Archeology - The Legend of Zelda (<a href="https://www.computerarcheology.com/NES/Zelda/"target="_blank" rel="noopener">https://www.computerarcheology.com/NES/Zelda/</a>)</p>
</li>
<li>
<p>6502 Instruction Set (<a href="https://www.masswerk.at/6502/6502_instruction_set.html"target="_blank" rel="noopener">https://www.masswerk.at/6502/6502_instruction_set.html</a>)</p>
</li>
<li>
<p>An introduction to 6502 math: addiction, subtraction and more (<a href="http://retro64.altervista.org/blog/an-introduction-to-6502-math-addiction-subtraction-and-more/"target="_blank" rel="noopener">http://retro64.altervista.org/blog/an-introduction-to-6502-math-addiction-subtraction-and-more/</a>)</p>
</li>
<li>
<p>Explain Half Adder and Full Adder with Truth Table (<a href="https://www.elprocus.com/half-adder-and-full-adder/"target="_blank" rel="noopener">https://www.elprocus.com/half-adder-and-full-adder/</a>)</p>
</li>
<li>
<p>Build a multiplying machine using NAND logic gates (<a href="https://codegolf.stackexchange.com/questions/12261/build-a-multiplying-machine-using-nand-logic-gates"target="_blank" rel="noopener">https://codegolf.stackexchange.com/questions/12261/build-a-multiplying-machine-using-nand-logic-gates</a>)</p>
</li>
<li>
<p>Tool Assisted Game Movies (<a href="http://tasvideos.org/"target="_blank" rel="noopener">http://tasvideos.org/</a>)</p>
</li>
<li>
<p>RETRO INSECTIVORES: FINDING AND ELIMINATING BUGS IN NES DEVELOPMENT (<a href="https://megacatstudios.com/blogs/press/retro-insectivores-finding-and-eliminating-bugs-in-nes-development"target="_blank" rel="noopener">https://megacatstudios.com/blogs/press/retro-insectivores-finding-and-eliminating-bugs-in-nes-development</a>)</p>
</li>
<li>
<p>FCEUX (<a href="https://sourceforge.net/projects/fceultra/"target="_blank" rel="noopener">https://sourceforge.net/projects/fceultra/</a>)</p>
</li>
<li>
<p>Zelda Screen Transitions are Undefined Behaviour (<a href="https://gridbugs.org/zelda-screen-transitions-are-undefined-behaviour/"target="_blank" rel="noopener">https://gridbugs.org/zelda-screen-transitions-are-undefined-behaviour/</a>)</p>
</li>
<li>
<p>NES Emulator Debugging (<a href="https://gridbugs.org/nes-emulator-debugging/"target="_blank" rel="noopener">https://gridbugs.org/nes-emulator-debugging/</a>)</p>
</li>
<li>
<p>Two&rsquo;s Complement Multiplication (<a href="http://pages.cs.wisc.edu/~david/courses/cs354/beyond354/int.mult.html"target="_blank" rel="noopener">http://pages.cs.wisc.edu/~david/courses/cs354/beyond354/int.mult.html</a>)</p>
</li>
<li>
<p>NES Hello World (<a href="https://www.embed.com/nes/hello-world.html"target="_blank" rel="noopener">https://www.embed.com/nes/hello-world.html</a>)</p>
</li>
<li>
<p>DF Direct: CRT Displays - Was LCD A Big Mistake For Gaming? (<a href="https://www.youtube.com/watch?v=tvRyVZWuvQ4"target="_blank" rel="noopener">https://www.youtube.com/watch?v=tvRyVZWuvQ4</a>)</p>
</li>
<li>
<p>DF Direct! Modern Games Look Amazing On CRT Monitors&hellip; Yes, Better than LCD! (<a href="https://www.youtube.com/watch?v=V8BVTHxc4LM"target="_blank" rel="noopener">https://www.youtube.com/watch?v=V8BVTHxc4LM</a>)</p>
</li>
<li>
<p>Meu fork do emulador de NES em Go (<a href="https://github.com/akitaonrails/nes"target="_blank" rel="noopener">https://github.com/akitaonrails/nes</a>)</p>
</li>
<li>
<p>Meu código do decodificador de código de Game Genie (<a href="https://github.com/akitaonrails/gamegenie"target="_blank" rel="noopener">https://github.com/akitaonrails/gamegenie</a>)</p>
</li>
</ul>
<p>Assinem estes canais:</p>
<ul>
<li>Retro Game Mechanics Explained (<a href="https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g"target="_blank" rel="noopener">https://www.youtube.com/channel/UCwRqWnW5ZkVaP_lZF7caZ-g</a>)</li>
<li>One Lone Coder (<a href="https://www.youtube.com/channel/UC-yuWVUplUJZvieEligKBkA"target="_blank" rel="noopener">https://www.youtube.com/channel/UC-yuWVUplUJZvieEligKBkA</a>)</li>
</ul>
]]></content:encoded><category>retrocomputacao</category><category>games</category><category>emulacao</category><category>akitando</category></item></channel></rss>