1 pontos por GN⁺ 20 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • A arquitetura do PlayStation adotou uma configuração simples e prática para reduzir a complexidade do desenvolvimento de hardware 3D, mas deixou para os desenvolvedores parte da carga e algumas limitações visuais em ordenação gráfica, correção de textura e precisão
  • O Sony CXD8530BQ é um SoC que integra um núcleo compatível com MIPS R3000A baseado no CoreWare da LSI Logic, além de CP0, GTE e MDEC; opera a 33,87MHz e organiza a movimentação de dados em torno de 2MB de RAM, 1KB de Scratchpad e DMA
  • Nos gráficos, o GTE cuida de projeção 3D, iluminação e clipping, enquanto a GPU renderiza linhas, quadrados e triângulos com base em comandos; sem Z-buffer, o sistema usa uma ordering table e exige que a CPU defina a ordem dos polígonos
  • A GPU gera tremulação, sobreposição e texture warping por causa de affine texture mapping, nearest neighbour, coordenadas inteiras e ausência de resolução subpixel, e por isso eram usados contornos como tessellation, substituição por cor sólida e cenários pré-renderizados
  • O projeto baseado em CD-ROM, com 620MB de armazenamento, streaming de áudio ADPCM a 44,1kHz, ambiente de execução com BIOS, proteção contra cópia via Wobble Groove e trava regional, mudou a forma de desenvolver e distribuir jogos

Projeto básico e CPU

  • O PlayStation foi concebido com foco em um design simples e prático, partindo da premissa de que hardware 3D poderia se tornar complexo de desenvolver, aceitando algumas limitações em troca disso
  • O chip principal, Sony CXD8530BQ, equivale ao que hoje chamaríamos de SoC e usa um núcleo de CPU baseado no CoreWare da LSI Logic, compatível em binário com a linha MIPS R3000A
  • O núcleo da CPU opera a 33,87MHz, com ISA MIPS I, palavra de 32 bits, 32 registradores de uso geral, barramento de dados de 32 bits, barramento de endereços de 32 bits, pipeline de 5 estágios e cache de instruções de 4KB
  • Não há cache de dados; no lugar dele, a memória de 1KB correspondente é fornecida como Scratchpad, mapeada em endereço fixo e usada como uma SRAM rápida
  • O sistema oferece 2MB de RAM EDO para tarefas gerais; a EDO RAM é descrita como um tipo de memória um pouco mais eficiente e com menor latência que a DRAM comum

Barramentos e coprocessadores

  • O barramento de dados é dividido em Main Bus de 32 bits e Sub Bus de 16/8 bits; o Main Bus conecta MDEC e GPU, enquanto o Sub Bus conecta os demais componentes e o I/O
  • O controlador de CD-ROM, MDEC, GPU, SPU e porta paralela podem acessar o controlador DMA, que transfere dados com alta vazão ao assumir o barramento principal sem passar pela CPU
  • Enquanto o DMA está em operação, a CPU não pode acessar o barramento principal e, se não houver trabalho a processar no Scratchpad, entra em espera
  • O CP0, o System Control Coprocessor, gerencia implementação de cache, acesso direto ao Scratchpad, isolamento do cache de instruções, interrupções, exceções e breakpoint
  • O CP2, o Geometry Transformation Engine, acelera cálculos vetoriais e matriciais em ponto fixo e cuida das etapas iniciais do pipeline gráfico, como projeção 3D, iluminação e clipping
  • O MDEC descomprime macroblocks codificados de forma semelhante ao JPEG para um formato compreensível pela GPU, processando 9.000 macroblocks de bitmap 24bpp de 8×8 pixels por segundo, o suficiente para transmitir FMV de 320×240px a 30fps
  • Não há FPU correspondente ao CP1; cálculos fracionários podem ser feitos com ponto flutuante em software ou ponto fixo, mas com limitações de velocidade e precisão

Pipeline e delay slots

  • O pipeline MIPS I é vulnerável a control hazard e data hazard, e tem o comportamento de branch delay slot, em que a instrução seguinte a um branch ou jump é executada de qualquer forma
  • Instruções de load não param o pipeline até que os dados buscados estejam prontos, então, se a instrução imediatamente seguinte depender do resultado do load anterior, é preciso inserir filler para obter o operando correto
  • Alguns delay slots podem ser preenchidos com instruções úteis, então nem sempre representam ciclos desperdiçados
  • Seguindo a filosofia RISC de que compiladores e montadores de alta qualidade cuidam do reordenamento de instruções e da inserção de filler, o MIPS adotou um design que expõe o pipeline da CPU a desenvolvedores e toolchains
  • Esse design também tem a desvantagem de dificultar a compatibilidade retroativa à medida que novas microarquiteturas surgem em gerações posteriores de CPU

Pipeline gráfico

  • Grande parte do pipeline gráfico é processada pelo GTE, e os dados resultantes são enviados para a GPU proprietária da Sony para renderização
  • O sistema armazena frame buffer, texturas e outros recursos de renderização em 1MB de VRAM, área que a CPU pode preencher via DMA
  • A VRAM dos modelos iniciais usa arquitetura dual-ported, com dois barramentos de 16 bits, permitindo acesso simultâneo por CPU, DMA, GPU e codificador de vídeo
  • Modelos posteriores passaram a usar SGRAM com um único barramento de dados de 32 bits, e diferenças de temporização podem causar glitches gráficos em jogos posteriores como Jet Moto 3 em sistemas baseados em VRAM
  • A CPU envia dados geométricos preenchendo até 3 comandos no FIFO buffer de 64 bytes da GPU; os comandos solicitam renderização, mudança de configuração ou manipulação da VRAM
  • A GPU pode desenhar linhas, quadrados e triângulos individualmente, e os triângulos servem como elemento básico para montar modelos 3D mais ricos
  • O sistema de coordenadas da GPU usa coordenadas inteiras, em que cada coordenada corresponde ao ponto de amostragem no centro do pixel, sem uso de coordenadas fracionárias

Visibilidade, rasterização e texturas

  • A GPU do PlayStation não oferece resolução de visibilidade em hardware e usa uma ordering table para gerenciar endereços de comandos da GPU por valor de profundidade
  • A CPU precisa ordenar os polígonos antes, colocar referências na entrada apropriada da tabela e depois enviá-la à GPU por DMA para que a renderização ocorra na ordem correta
  • A GPU precisa de apenas um frame buffer, e o rasteriser converte vértices em linhas, triângulos, quadrados e pixels
  • Triângulos são o primitive mais complexo e versátil, com suporte a textura e shading; linhas são rápidas, mas inadequadas para superfícies texturizadas; quadrados ficam limitados a sprites de até 256×256 pixels e não oferecem shading nem efeitos de transformação affine
  • Há dois tipos de iluminação, flat shading e Gouraud shading; o flat shading consegue preencher cerca de 2,5 vezes mais polígonos por segundo do que o Gouraud shading
  • A textura é aplicada por inverse texture mapping, que busca o texel do mapa de textura para cada pixel rasterizado
  • O Affine Texture Mapping da GPU do PlayStation usa apenas coordenadas 2D X/Y e descarta a profundidade, portanto não faz perspective correction
  • Não há texture filtering; para correção de escala usa-se nearest neighbour, rápido e barato, mas que faz os modelos texturizados parecerem blocados
  • A GPU oferece suporte a semi-transparency e dithering em triângulos, e o PlayStation é descrito como particularmente forte nesses efeitos

Uso da VRAM e limitações visuais

  • A ideia de usar boa parte de 1MB de VRAM para o frame buffer exige reajuste para formatos padrão de TV, reduz o espaço para texturas e colour tables, e a própria GPU só consegue renderizar frame buffer de até 640×480 pixels em 16 bits de cor
  • Um buffer 640×480 em 16 bits deixa 424KB de VRAM livres para recursos, mas a vantagem da alta resolução não se destacava tanto nas TVs domésticas da época
  • O adjustable frame-buffer reduz o tamanho do frame buffer para evitar desperdiçar VRAM com resolução de pouco impacto perceptível e ampliar o espaço para texturas e colour lookup tables
  • A demo Gears Episode 2 de Halkun mostra uma configuração que divide um frame buffer de 640×480 em dois buffers de 320×480 e usa page flipping para renderizar uma cena enquanto exibe a outra
  • Esse layout consome apenas 600KB de VRAM e deixa os 424KB restantes para colour lookup table e texturas, tornando-se uma configuração eficiente junto com o cache de textura de 2KB
  • A VRAM pode mapear simultaneamente várias profundidades de cor, permitindo colocar um bitmap 24bpp, comum em quadros de FMV, ao lado de um frame buffer 16bpp
  • Como o rasteriser trabalha apenas no nível do pixel e não rastreia quanto de uma fração de pixel é ocupado por um triângulo, podem ocorrer saltos no contorno dos modelos e flicker ou sobreposição nas interseções entre triângulos
  • A ordering table transfere para o desenvolvedor ou para o programa a responsabilidade de decidir qual geometria está na frente; quando se usam muitos cálculos aproximados por desempenho, isso pode causar flickering ou problemas de superfícies ocultas
  • A transformação affine não tem noção de profundidade e pode gerar texture warping quando a câmera está perto do modelo e perpendicular à linha de visão; alguns jogos reduziam a distorção com tessellation ou substituição por cor sólida
  • Cenários pré-renderizados eram usados quando se precisava de uma cena mais realista do que a GPU conseguia produzir em tempo real, aplicando vídeo transmitido pelo MDEC sobre dois triângulos

Áudio e jogos baseados em CD

  • O SPU suporta 24 canais de samples ADPCM de 16 bits com qualidade de Audio CD a 44,1kHz
  • O SPU oferece pitch modulation, frequency modulation, ADSR envelope, looping e reverb digital
  • A Sound RAM, buffer de áudio, é uma DRAM de 512KB; os jogos podem usar apenas 508KB para armazenar samples, e habilitar reverb reduz ainda mais a capacidade disponível
  • O controlador de CD pode enviar samples diretamente ao mixer de áudio sem intervenção do buffer de áudio ou da CPU, e samples comprimidos em codificação XA podem ser decodificados pelo SPU em tempo real
  • A mídia CD-ROM dava aos jogos de PS1 620MB de armazenamento, áudio de alta qualidade e velocidade de leitura relativamente rápida com drive 2x
  • Revisões do PS1 lançadas até 1997 ficaram conhecidas por um laser de drive de CD defeituoso, com pulos frequentes em FMV e Audio CD; modelos posteriores melhoraram a unidade do laser e a carcaça para mitigar o problema

I/O, BIOS e ambiente de desenvolvimento

  • Os primeiros PlayStation tinham portas de I/O Serial e Parallel para add-ons, mas elas foram removidas em revisões posteriores devido à baixa adoção e ao receio de burlar a proteção contra cópia
  • O subsistema de CD é composto por um DSP que controla motor, laser e sinal de RF; uma Sub-CPU com microcontrolador Motorola 68HC05, 512B de RAM e 16KB de ROM; um CD Controller que faz a ponte entre a CPU principal e o subsistema de CD; e um buffer SRAM de 32KB
  • O programa em ROM da Sub-CPU implementa o procedimento de proteção contra cópia e o impõe independentemente da vontade da CPU principal
  • Na frente do console há quatro conectores, para 2 controles e 2 Memory Cards; os quatro slots são eletricamente idênticos e seus endereços são fixos em hardware
  • O sistema armazena a BIOS em 512KB de ROM, e ela fornece startup, shell de usuário e rotinas de I/O
  • Como o acesso à ROM da BIOS é muito lento por causa do barramento de dados de 8 bits, a API é oferecida na forma de um Kernel copiado para a RAM principal durante o boot, com 64KB da RAM principal reservados para o sistema operacional do PlayStation
  • O processo de boot segue a ordem: execução da ROM da BIOS, carregamento do sistema operacional do PlayStation, exibição da splash screen, verificação da autenticidade do CD, leitura e execução de SYSTEM.CNF ou exibição do shell
  • O shell é uma interface gráfica simples para copiar e apagar saves do Memory Card e reproduzir Audio CDs
  • O SDK da Sony incluía compilador C e biblioteca, e a biblioteca se conectava às rotinas da BIOS para acesso ao hardware
  • O DTL-H2000, voltado para estúdios, era uma placa ISA de slot duplo com o interior do PS1, I/O e circuitos de depuração, e exigia software rodando em um PC com Windows 3.1 ou 95
  • O Net Yaroze, voltado a hobbyistas, incluía toolkit, manual e um console PS1 preto, mas sem acesso ao drive de CD, o que exigia que todo o software homebrew coubesse na RAM principal

Proteção contra cópia e trava regional

  • A proteção contra cópia da Sony funciona com a Sub-CPU verificando se o Table of Contents do CD possui um Wobble Groove gravado em determinada frequência
  • O Wobble Groove é introduzido no processo de masterização, não pode ser copiado com gravadores de CD comuns, e o TOC fica na área Lead-In do CD, repetido várias vezes para tolerância a falhas
  • O TOC do jogo contém uma das strings SCEA, SCEE ou SCEI, e esse método também é usado para region-locking
  • Como a checagem é feita apenas uma vez na inicialização, é possível contorná-la trocando manualmente o disco logo após a autenticação, no chamado swap trick, embora isso traga risco de danificar o drive
  • Alguns jogos tentavam bloquear o swap trick reinicializando o drive durante a partida para repetir a checagem
  • O Modchip é uma pequena placa programada para imitar o sinal do Wobble Groove; era soldada no console e, embora legalmente controversa, tornou-se extremamente popular
  • Jogos posteriores adicionaram mecanismos próprios de proteção, centrados em checksum, para responder à disseminação de modchips, gravadores de CD e emuladores
  • O Libcrypt da Sony combina uma abordagem de hardware, armazenando checksums de setores específicos no subcanal do disco, com rotinas de software espalhadas pelo jogo que buscam esses checksums, misturam com outros valores e os validam

1 comentários

 
Comentários do Hacker News
  • Existem regiões de memória mapeadas para a mesma memória física — https://psx-spx.consoledev.net/memorymap/
    Quando fizeram o port de Metal Gear Solid do PSX para PC, os programadores da Konami usaram um truque bem radical para armazenar se a bomba C4 tinha sido colocada na parede ou no chão
    Essencialmente, o ponteiro apontava para o mesmo endereço de memória física, mas, dependendo de estar na parede ou no chão, acho que eles faziam OR com 80000000h ou usavam A0000000h. Faz muito tempo, então já não lembro exatamente o que fizeram, mas o processo de portar para PC foi divertido

    • O bootloader do memory card também funciona de forma parecida
      Há um iterador de array com defeito no código da BIOS, então é possível copiar dados arbitrários para uma posição superior no mapa de memória em relação ao ponteiro base. Normalmente isso não sobrescreve código executável porque o ponteiro base fica muito alto, mas, por causa do aliasing de memória, se você ajustar bem o valor a escrita pode “dar a volta” e sobrescrever a BIOS
      Então, na prática, só de entrar na tela do memory card já dá para iniciar uma BIOS customizada e, a partir daí, executar um PSX.EXE sem passar pela verificação do mechacon, burlando a proteção contra cópia
      Também queria saber mais sobre o port de MGS. Fico curioso se você lembra de algo. Pelo que recordo, usavam TCL na maior parte do scripting, e acho que MGS 1~4 usavam linguagens de script da mesma linhagem
      Recentemente o código-fonte de MGS2 vazou, mas provavelmente foi quase uma reescrita completa, então imagino que quase nada tenha sido compartilhado com a base de código do PSX
    • Hoje em dia esse tipo de truque normalmente é feito usando os bits baixos válidos do ponteiro e removendo-os com máscara ao fazer a desreferenciação. Em troca, isso exige alinhamento maior; por exemplo, se você usar 4 bits, passa a precisar de alinhamento de 16 bytes
      O PS1 também não tinha RAM suficiente para cobrir toda a janela de decodificação da RAM, então surge o aliasing de RAM. Não sei exatamente o mecanismo, mas já vi executáveis de PS1 configurando o ponteiro de stack para o fim dos 8 MiB de RAM do kit de desenvolvimento e, mesmo assim, no hardware retail ele acabar caindo no fim dos 2 MiB de RAM e funcionar normalmente. Em teoria, daria para colocar bits ali também, sem tocar em regiões de memória com comportamento de cache diferente
    • Interessante. Não está sendo fácil encontrar essa parte no código decompilado. Também fico curioso se ainda não foi descoberta e documentada
      https://github.com/FoxdieTeam/mgs_reversing/blob/master/sour...
    • Os primeiros Macs usavam o byte superior dos ponteiros de 32 bits para outros dados
      https://en.wikipedia.org/wiki/Classic_Mac_OS_memory_manageme...
      Como resultado, alguns modelos ganharam um modo de compatibilidade retroativa não muito diferente da porta A20 do PC, mas isso durou pouco
    • Hoje esse tipo de recurso está padronizado como extensão de hardware
      Existem Arm Top Byte Ignore(TBI), Intel Linear-Address Masking(LAM) e sua variante Linear Address Space Separation(LASS), além do AMD Upper Address Ignore(UAI); o UAI ainda não é seguro contra ataques SLAM. Por cima disso, também existem extensões de segurança como o ARM Memory Tagging Extension(MTE)
  • Ótimo texto, mas ele foi publicado originalmente em 2019. As discussões anteriores foram em 2020 https://news.ycombinator.com/item?id=22932134 e em 2021 https://news.ycombinator.com/item?id=27576902, com 114 comentários em cada uma

    • Desde então, ele foi atualizado várias vezes
    • Ainda assim, isso já faz 5~7 anos. Eu não conhecia o texto, então fiquei feliz de vê-lo aparecer de novo
  • É um site realmente lindo. Tudo está posicionado com muito cuidado, e parece um ótimo exemplo de um jardim digital bem curado. Passa muito a sensação de algo bem mantido e feito à mão por uma pessoa

  • Estou trabalhando agora em um projeto relacionado ao PS1 e quis postar este texto porque quero divulgar isso em breve
    Gostaria de saber se alguém recomenda um emulador de PS1 em web/JS/WASM. No desktop, gostei do PCSX-Redux [0] e do DuckStation [1]
    Encontrei algumas tentativas baseadas em JS/emscripten, mas agradeceria recomendações
    [0] https://github.com/grumpycoders/pcsx-redux/
    [1] https://duckstation.org/

  • O PS1 foi a arquitetura que me fez gostar de RISC, ou mais precisamente de arquitetura load-store, e perceber que eu estava pensando errado sobre o lado x86

  • A arquitetura do PS1 é fascinante. Ela também mostra por que os jogos de PS1 acabaram com um estilo tão único e reconhecível, que ainda hoje muita gente tenta reproduzir

  • Gosto dos textos do Copetti. Não entendo bem tudo o que ele cobre, mas só de passar os olhos pelos textos e diagramas já é divertido
    Em especial, é interessante tentar entender o que acontece dentro de máquinas como os consoles da quinta e da sexta geração

    • Se você gosta do Copetti, vale muito a pena ver todo o trabalho do Fabien Sanglard. Há os Black Books de Wolfenstein e Doom, a análise do port de Another World e dezenas de outras revisões de código que ele publicou
      https://fabiensanglard.net/
    • O fato de ser de 1994 também sempre impressiona. Esses aparelhos parecem mais coisa do fim dos anos 90
  • Melhor ainda por ser um texto de antes do Claude

  • Executar a instrução após um salto pareceu coisa de louco no começo, mas depois de alguns dias ficou natural. No N64 havia um problema parecido, então era preciso encontrar uma instrução para colocar entre duas multiplicações
    Se a primeira multiplicação terminasse em dois ciclos, por exemplo por multiplicar por 0, e a próxima instrução também fosse uma multiplicação, a CPU travava

    • Outra esquisitice era que as instruções do COP2, ou seja, do GTE, começavam a ser executadas uma instrução antes da posição indicada pelo contador de programa
      Então, quando ocorria uma exceção, o handler de interrupção do kernel precisava verificar se a próxima instrução era COP2 e somar 4 ao contador de programa para evitar executá-la duas vezes
      Além disso, não era possível colocar instruções COP2 no branch delay slot, provavelmente por um motivo parecido. Mas alguns jogos, se bem me lembro Tekken 3, realmente faziam isso. Como vários emuladores tiveram problemas nessa parte ou precisaram de tratamento especial, sempre fiquei curioso se isso era uma proteção anti-emulação colocada de propósito
  • Os textos desta série são sempre excelentes
    Os jogos de PS1 não envelheceram tão bem pelos padrões de hoje, mas quando se faz upscale de jogos de PS2 para 1440p~4K, eu diria que ficam quase perfeitos

    • Os jogos de PS1 também envelhecem bem se forem jogados da forma como foram pensados originalmente, de preferência em uma CRT, ou, se isso não for possível, com um filtro de CRT no emulador. Jogá-los em uma LCD nítida, em resolução muito alta, me parece a pior forma possível
    • Dizer que “os jogos de PS1 são difíceis de olhar hoje” é algo que cada um pode sentir de forma diferente. O PS1 marcou o início da era 3D nos consoles domésticos, e muita gente gosta dos modelos 3D low-poly com aquela tremulação característica do PS1
      Claro que nostalgia pesa bastante, mas há um charme real nisso, e depois de entender as limitações únicas de hardware do PS1, fui gostando cada vez mais com o tempo. Só de olhar os feeds de redes sociais, dá para ver que os “gráficos de PS1” estão vivendo uma espécie de renascimento, com muita gente tentando recriar essa estética
    • Quando você olha as especificações, o que os desenvolvedores conseguiram tirar dali é realmente impressionante
    • Em termos gráficos, basta jogar em uma CRT ou com um filtro de CRT, ou usar um emulador que ofereça correção de geometria PGXP para eliminar a tremulação dos vértices em altas resoluções de renderização
      Em termos de jogabilidade, esse console tem uma biblioteca enorme, com milhares de jogos lançados comercialmente, além de muitas joias escondidas. Se existir algum jogador que não consiga encontrar um único jogo do seu gosto nessa lista, eu até acharia surpreendente
    • Os jogos 2D continuam envelhecendo bem até hoje. Um exemplo é Symphony of the Night