Olá...
Nesse post vamos falar um pouco sobre o Sega 32X, aquele add-on bizarro que a Sega desenvolveu para o Mega Drive... É relativamente fácil achar reviews e analises (a maioria falando mal) sobre o 32X, ou então achar aquela listinha de "specs" que fala muito sobre o aparelho mas no final não diz nada de util.
Tentando sair um pouco desses moldes pretendo fazer uma analise mais técnica, abordando aspectos do hardware do 32X, explicando o que é e como funciona de maneira simples e inteligível.
O 32X foi pensando como um Add-on para "estender" a vida útil do Mega Drive, a quinta geração de consoles já estava chegando, porem a Sega não desenvolveu o 32X para concorrer com os consoles de quinta geração e sim ser um "plus", para trazer algo de novo para mercados emergentes onde os novos consoles seriam muito caros para serem adquiridos pela maioria das pessoas (aqui no Brasil mesmo um Sega Saturn valia 8 salários mínimos quando foi lançado) então a ideia era dar uma sobre vida ao Mega Drive que sempre fez muito sucesso nesses mercados formados por pessoas com menos poder aquisitivo como a América do Sul e parte da Europa , mas como de boas intenções o inferno esta cheio...
Deixando essa conversa de lado, vamos dar uma uma olhada no que temos dentro do 32X, afinal se ele é um Add-On ele tem que adicionar muitas coisas ao Mega Drive:
Em resumo o Hardware dele é composto por:
- 2 processadores Hitachi SH2 de 32Bits
- 256 Kbyte de Memoria RAM
- 256 Kbytes de Memoria de Video com recursos de Double Buffer
- 1 saída de som Estéreo PWM de 11 Bits
- 1 Custom VDP com suporte a Frame Buffer e múltiplos modos de indexação de cores.
Começando pelos processadores, acho que sega estava meio na Vibe de desenvolver plataformas "multcore" naquela época, essa configuração com duas CPU's Hitachi SuperH2 foi usada não só no Sega 32X mas no Sega Saturn também...
Falando um pouco da Arquitetura do SH2, ele trouxe um ar de modernidade muito interessante para o Mega Drive, apesar de eu ser completamente apaixonado pela arquitetura do MC68000 eu sinto falta nele de suporte a multiplicação/divisão de inteiros Long Word de 32bits e principalmente recursos de Pipeline mais avançados.
Pra quem não sabe o que é Pipeline: Basicamente é o método pelo qual o processador carrega da memoria as instruções a serem executadas, ele possui um cache interno e uma estrutura de fila rotativa que permite a ele já ir carregando as próximas instruções enquanto executa a instrução atual aproveitando o mesmo ciclo de Clock, isso sobe brutalmente a velocidade de execução do código sem a necessidade de aumentar a frequência de operação do Clock do sistema.
Imaginem que no MC68000 o processador trabalha de uma maneira mais "manual", onde a execução das instruções é feita numa serie de passos tipo acessar o barramento, carregar a instrução, decodifica-la e enfim executa-la, etc. E isso pode exigir muitos ciclos de Clock.
Nessa analogia se o MC68000 é um trabalhador manual o SH-2 é uma linha de montagem, onde todas essas tarefas são divididas em vários estágios e a saída de cada estagio alimenta o estagio seguinte, então enquanto a UCP executa uma instrução, aproxima instrução já esta sendo decodificada, e a próxima da próxima já esta sendo carregada da memoria.
Nesse aspecto o SH2 agrega e muito ao Mega Drive, ele trabalha a impressionantes 23 Mhz e possui um pipeline de 5 estágios... Apenas para títulos comparativos, o Mega Drive com seus 7,6 Mhz pode executar em média 1,2 Milhões de instruções por segundo, apenas 1 dos dois SH2 do 32X com seus 23Mhz de clock pode executar cerca de 30 MILHÕES de instruções por segundo.
Quem olhar com mais atenção para esses números vai ver que o MC68000 precisa em media de 6~7 Ciclos de Clock para executar uma instrução (em média por que tem instruções que exigem mais e outras que exigem menos do que isso, então não levem esse numero ao pé da letra, OK?), se fizermos esse calculo para o SH2 veremos que ele executa em média 1,3 Instruções para cada ciclo de clock.
Ele é de arquitetura RISC então o assembly dele não é difícil de se
aprender (pra mim pelo menos foi mais fácil que aprender o assembly do
MC68000). A arquitetura interna dele também é bem resumida, assim como
no MC68000 temos temos 16 registradores de 32 Bits, porem no MC68000 cada
grupo de registradores tem uma função especifica, sendo 8 de uso geral (D0 ~
D7) e 8 de endereçamento indireto a memoria (A0 ~ A7) sendo o A7 reservado
para o Stack Pointer.
No SH2 também temos 16 Registradores de 32 Bits (R0 ~ R15) sendo o R15
usado como Stack Pointer e o R0 usado como Index Register em algumas
instruções especificas, tirando isso podemos usar qualquer outro registrador
tanto no modo de Indexação Direta quanto Indireta.
O Instruction Set do SH2 também é mais otimizado para linguagem C, por exemplo, para comparar 2 valores no MC68000 nós usamos a instrução CMP (ou TST caso um dos valores seja Zero) só que essa instrução na verdade apenas subtrai um valor do outro, depois temos que usar outras instruções para "olhar" no Status Register os Flags do sistema que vão nos indicar se os valores são iguais, se um é maior que o outro, etc. De maneira que para cada condição de comparação temos uma instrução especifica que vai nos retornar o valor do Flag correspondente.
No SH2 nós embutimos a condição de comparação na própria instrução CMP, e depois apenas "perguntamos" se o resultado é True ou False, por exemplo:
1 2 |
CMP/EQ R0,R1 BT _label_true_ |
Neste exemplo o código vai pular para _label_true_ caso os valores salvos em R1 e R0 sejam iguais, observem o mnemônico BT (Branch True) .
Outra diferença que observei quando comecei a programar para o SH2 é no uso de valores imediatos, isso só afeta quem programa diretamente em assembly (meu caso), ja que geralmente os compiladores de mais alto nível tomam conta disso pra você. A diferença é que quando usamos valores imediatos no MC68000 o valor é escrito na memoria logo após a instrução, sendo que podemos usar isso para encapsular esse valor na própria instrução quando estamos programando... No caso do SH2 ele só consegue acessar valores imediatos através de Literal Pool's, ou seja a instrução armazena na verdade um endereço de memoria relativa ao Program Counter que indica onde aquele dado esta armazenado, por exemplo:
1 2 3 4 5 6 7 | No MC68000: MOVE.l #$DEADBEEF,D1 Equivalente no SH2: MOV.L @(data,PC),R1 data: DC.l 0xDEADBEEF |
No SH2 podemos encapsular o valor na própria instrução? Sim! Maaaaaaaas apenas se o valor for um Signed de 8 Bits (que é o que cabe na instrução), se o valor for Word ou Long Word ele deve ser obrigatoriamente alocado na Literal Pool, e detalhe: Como o valor é acessado via Displacement do Program Counter existe um limite do quão "distante" a Literal Pool pode ficar do código que esta requisitando esse valor, se o displacement for de 16 Bits por exemplo a Literal Pool não pode estar além de 32Kb a frente ou atrás do código.
Até aqui falamos exclusivamente do SH2, agora vamos ver como isso tudo se encaixa dentro do 32X... É sabido por muitos que o 32X possui 2 Processadores SH2 trabalhando no modo Master/Slave, ainda temos no Mega Drive mais o MC68000 e o Z80, ou seja, 4 processadores de 3 arquiteturas diferentes rodando ao mesmo tempo na mesma maquina, isso para muitos pode parecer uma vantagem (afinal "quanto mais melhor" diz o ditado), mas do ponto de vista de um desenvolvedor isso é praticamente uma Bomba de programação concorrente esperando para explodir.
Com o Z80 não precisamos nos preocupar muito, afinal ele tem a própria Memoria exclusiva dele e funciona sempre em um Barramento Isolado (se bem que em alguma revisões do Mega Drive ele encrenca com as transferências via DMA), no mais ele fica quietinho no canto dele sem mexer com ninguém fazendo suas tarefas.
Mas quando olhamos para o Barramento Principal do Sistema a coisa começa a feder um pouco, o Barramento é único e é compartilhado entre os 3 Processadores restantes (o SH2 master, o SH2 Slave e o MC68000), sendo que existe uma hierarquia de prioridades no acesso ao Barramento onde o SH2 master tem a maior prioridade... Os dois Processadores SH2 também consegue enxergar o barramento Inteiro (ou seja toda a Memoria Rom), o MC68000 enxerga apenas os primeiros 512Kb de Memoria diretamente (que na verdade são "deslocados" para outro endereço dentro do Address Space dele), ele pode acessar a ROM inteira mas apenas via Memory Map através de Bancos de 1Mega Byte cada.
Além disso o MC68000 ainda tem acesso ao Frame Buffer e a registradores compartilhados específicos para trocar informação com o 32X.
Do lado dos SH2's temos acesso total a ROM e aos 256Kb adicionais de Memoria RAM, porem o barramento é único e a memoria compartilhada tanto para o Master quanto para o Slave, inclusive o Stack e as vector Tables de ambos os Processadores são alocadas na mesma memoria (em endereços diferentes obviamente).
Ter vários processadores brigando num mesmo barramento é algo até perigoso de certa forma, por vezes a lógica pode parecer correta mas apresentar erros em sua execução devido a maneira como o barramento é compartilhado.
Geralmente o que acontece é que o Master "monopoliza" o Barramento limitando o acesso dos demais processadores que se veem presos numa eterna espera ou numa tremenda lentidão para a execução de suas tarefas.
Um jeito de burlar isso é escrevendo Drivers, preferencialmente minimalistas para o MC68000 e o SH2 Slave de maneira que o código precise acessar a ROM o mínimo possível (só lembrando que obrigatoriamente é o MC68000 que tem que acessar o Hardware do Mega Drive gerenciando o funcionamento do VDP, do Som e realizando a leitura dos Joysticks).
Para isso podemos copiar o programa que rodará no MC68000 para a RAM e executa-lo de lá, no caso do SH2 Slave podemos usar a Memoria Cache Interna para diminuir o numero de acessos ao Barramento, sendo o Ideal usa-los com funções "pré-programadas", que serão executadas a pedido do Master.
Enfim, considerando os dias atuais, se retirarmos a OpenMP e os Pragmas fica difícil achar um programador habilidoso o suficiente que consiga desenhar um programa Multcore, imaginem agora em meados do inicio da década de 90!?
Apesar de adicionar Muito ao Mega Drive o Barramento fica uma confusão, é necessário dividir as tarefas entre os vários processadores, o que torna obrigatorio conhecer bem a arquitetura de todos eles, o mapeamento de Memoria é diferente do lado do 32x e do Mega Drive (apesar da ROM ser a mesma), fora que os recursos também ficam divididos, o Hardware de Som, o VDP e os Joysticks devem ser operados pelo lado do Mega Drive, o Frame Buffer e o som PCM pelo 32X.
Na minha visão o principal erro da Sega foi ter que "remendar" muito o sistema como um todo para unir todos esses recursos, no final das contas o 32X virou uma tremenda bagunça que exigia uma curva de aprendizado muito grande, uma SDK muito cara (falaremos disso no futuro) e tudo isso direcionado a um mercado emergente onde a pirataria reinava, uma combinação pouco atrativa para as Softhouses, não atoa ele morreu com apenas 26 jogos lançados...
Por hoje isso é tudo, ainda pretendo escrever mais sobre esse assunto, hoje falamos sobre os Hitachi SH-2, no próximo Post pretendo falar sobre o Memory Map e o Custom VDP do 32X.
Espero que tenham gostado e lembrem-se: Duvidas, criticas ou sugestões... Deixem ai a baixo nos comentários!
Ótimo Conteúdo! Legal ver essas análises técnicas, sem achismos! No aguardo da continuação.
ResponderExcluirAgradeço as palavras amigo, se tiver alguma analise de sua preferencia que queira ver é só deixar a sugestão... Farei assim que possível.
Excluir