Mudanças entre as edições de "AnotherWorld JAMMA"
(15 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
Linha 1: | Linha 1: | ||
Esta página contém rascunhos da concepção do projeto de uma placa JAMMA para o jogo Another World. |
Esta página contém rascunhos da concepção do projeto de uma placa JAMMA para o jogo Another World. |
||
− | Este projeto está sendo desenvolvido ao longo de uma atividade semanal no Garoa chamada [[CPU do Zero]]. Todo o projeto será implementado como hardware livre (com os esquemáticos distribuidos sob |
+ | Este projeto está sendo desenvolvido ao longo de uma atividade semanal no Garoa chamada [[CPU do Zero]]. Todo o projeto será implementado como hardware livre (com os esquemáticos distribuidos sob a licença livre '''CERN Open Hardware License v1.2'''). |
+ | |||
+ | * os esquemáticos estão sendo projetados usando o software KICAD |
||
+ | * os arquivos estão sendo publicados no GitHub em https://github.com/felipesanches/AnotherWorld_JAMMA |
||
+ | * as tarefas pendentes deste projeto estão sendo monitoradas neste bugtracker: https://github.com/felipesanches/mame/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20anotherworld |
||
+ | * o código fonte de protótipo via emulação está sendo desenvolvido em: https://github.com/felipesanches/mame/tree/anotherworld |
||
+ | |||
== Relógio Central == |
== Relógio Central == |
||
Linha 33: | Linha 39: | ||
| 0x00 |
| 0x00 |
||
| movConst |
| movConst |
||
+ | | varID |
||
+ | | const H |
||
+ | | const L |
||
| |
| |
||
+ | | |
||
+ | | |
||
+ | | [varID] <= const |
||
|- |
|- |
||
| 0x01 |
| 0x01 |
||
| mov |
| mov |
||
+ | | dst |
||
+ | | src |
||
| |
| |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | [dst] <= [src] |
||
|- |
|- |
||
| 0x02 |
| 0x02 |
||
| add |
| add |
||
+ | | dst |
||
+ | | src |
||
+ | | |
||
+ | | |
||
+ | | |
||
| |
| |
||
+ | | [dst] <= [src] + [dst] |
||
|- |
|- |
||
| 0x03 |
| 0x03 |
||
| addConst |
| addConst |
||
+ | | varID |
||
+ | | value |
||
| |
| |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | [varID] <= [varID] + value |
||
|- |
|- |
||
| 0x04 |
| 0x04 |
||
| call |
| call |
||
+ | | addr H |
||
+ | | addr L |
||
| |
| |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | stack->push(PC); PC = addr |
||
|- |
|- |
||
| 0x05 |
| 0x05 |
||
| ret |
| ret |
||
| |
| |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | PC = m_stack->pop() |
||
|- |
|- |
||
| 0x06 |
| 0x06 |
||
| Break / "pauseThread" |
| Break / "pauseThread" |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
| Temporarily stops the executing channel and goes to the next. |
| Temporarily stops the executing channel and goes to the next. |
||
|- |
|- |
||
| 0x07 |
| 0x07 |
||
| jmp |
| jmp |
||
+ | | addr H |
||
+ | | addr L |
||
+ | | |
||
+ | | |
||
+ | | |
||
| |
| |
||
+ | | PC <= addr |
||
|- |
|- |
||
| 0x08 |
| 0x08 |
||
− | | Setvec |
+ | | Setvec |
+ | | channelID |
||
+ | | addr H |
||
+ | | addr L |
||
+ | | |
||
+ | | |
||
+ | | |
||
| Initialises a channel (thread) with a code address to execute |
| Initialises a channel (thread) with a code address to execute |
||
|- |
|- |
||
| 0x09 |
| 0x09 |
||
| djnz |
| djnz |
||
+ | | varID |
||
− | | '''D'''ecrement variable value and '''J'''ump if '''N'''ot '''Z'''ero |
||
+ | | addr H |
||
+ | | addr L |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | '''D'''ecrement variable value and '''J'''ump to address if value is '''N'''ot '''Z'''ero |
||
|- |
|- |
||
| 0x0A |
| 0x0A |
||
| Conditional Jump instructions |
| Conditional Jump instructions |
||
+ | | subopcode |
||
+ | | varID |
||
+ | | value |
||
| |
| |
||
+ | | |
||
+ | | |
||
+ | | JZ, JNZ, JG, JGE, JL, JLE |
||
|- |
|- |
||
| 0x0B |
| 0x0B |
||
| setPalette |
| setPalette |
||
+ | | palID H |
||
+ | | palID L |
||
| |
| |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | selects current palette |
||
|- |
|- |
||
| 0x0C |
| 0x0C |
||
+ | | updateChannel |
||
− | | freezeChannels" / "unfreezeChannels" / "deleteChannels |
||
+ | | first |
||
− | | Deletes, freezes or unfreezes a series of channels. |
||
+ | | last |
||
+ | | type |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | Freeze (0), unfreeze (1) or delete(2) a range of channels. |
||
|- |
|- |
||
| 0x0D |
| 0x0D |
||
| selectVideoPage |
| selectVideoPage |
||
+ | | bufferID |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | selects the current video page |
||
|- |
|- |
||
| 0x0E |
| 0x0E |
||
| fillVideoPage |
| fillVideoPage |
||
+ | | pageID |
||
+ | | color |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | fills a video page with a solid color |
||
|- |
|- |
||
| 0x0F |
| 0x0F |
||
| copyVideoPage |
| copyVideoPage |
||
+ | | srcPageID |
||
+ | | dstPageID |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | copies the contents of a video page to another one |
||
|- |
|- |
||
| 0x10 |
| 0x10 |
||
| blitFramebuffer |
| blitFramebuffer |
||
+ | | pageID |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | updates display with the contents of the specified video page |
||
|- |
|- |
||
| 0x11 |
| 0x11 |
||
| killChannel / "killThread" |
| killChannel / "killThread" |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | stops running and deactivates the current channel |
||
|- |
|- |
||
| 0x12 |
| 0x12 |
||
+ | | Text |
||
− | | Text "text number", x, y, color |
||
+ | | stringID H |
||
+ | | stringID L |
||
+ | | x |
||
+ | | y |
||
+ | | color |
||
+ | | |
||
| Displays in the work screen the specified text for the coordinates x,y. |
| Displays in the work screen the specified text for the coordinates x,y. |
||
|- |
|- |
||
| 0x13 |
| 0x13 |
||
| sub |
| sub |
||
+ | | A |
||
− | | Subtract |
||
+ | | B |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | Subtract: [A] <= [A] - [B] |
||
|- |
|- |
||
| 0x14 |
| 0x14 |
||
| and |
| and |
||
+ | | A |
||
− | | Boolean AND |
||
+ | | B |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | Boolean AND: [A] <= [A] & [B] |
||
|- |
|- |
||
| 0x15 |
| 0x15 |
||
| or |
| or |
||
+ | | A |
||
− | | Boolean OR |
||
+ | | B |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | Boolean OR: [A] <= [A] | [B] |
||
|- |
|- |
||
| 0x16 |
| 0x16 |
||
| shl |
| shl |
||
+ | | varID |
||
− | | Shift Left |
||
+ | | value H |
||
+ | | value L |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | Shift Left: [varID] <= [varID] << value |
||
|- |
|- |
||
| 0x17 |
| 0x17 |
||
| shr |
| shr |
||
+ | | varID |
||
− | | Shift Right |
||
+ | | value H |
||
+ | | value L |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | Shift Right: [varID] <= [varID] >> value |
||
|- |
|- |
||
| 0x18 |
| 0x18 |
||
| play / "playSound" |
| play / "playSound" |
||
+ | | resourceID H |
||
+ | | resourceID L |
||
+ | | freq |
||
+ | | vol |
||
+ | | channel |
||
+ | | |
||
| parameters: resourceId, freq, vol, channel |
| parameters: resourceId, freq, vol, channel |
||
|- |
|- |
||
| 0x19 |
| 0x19 |
||
| load / "updateMemList" |
| load / "updateMemList" |
||
+ | | resourceID H |
||
+ | | resourceID L |
||
+ | | |
||
+ | | |
||
+ | | |
||
+ | | |
||
| bank-switching de recursos (paletas, bytecode, polígonos, etc) |
| bank-switching de recursos (paletas, bytecode, polígonos, etc) |
||
|- |
|- |
||
| 0x1A |
| 0x1A |
||
| song / "playMusic" |
| song / "playMusic" |
||
+ | | resourceID H |
||
+ | | resourceID L |
||
+ | | delay H |
||
+ | | delay L |
||
+ | | pos |
||
+ | | |
||
| parameters: resourceID, delay, pos |
| parameters: resourceID, delay, pos |
||
|- |
|- |
||
− | | 0x40 |
+ | | 0x40-0x7F |
| video |
| video |
||
+ | | offset H |
||
+ | | offset L |
||
+ | | x |
||
+ | | <etc> |
||
+ | | |
||
+ | | |
||
+ | | renderização de polígonos |
||
+ | |- |
||
+ | | 0x80-0xFF |
||
+ | | video (opcode contains 7-bit offset H) |
||
+ | | offset L |
||
+ | | x |
||
+ | | y |
||
+ | | |
||
+ | | |
||
+ | | |
||
| renderização de polígonos |
| renderização de polígonos |
||
|- |
|- |
||
Linha 157: | Linha 346: | ||
'''Função:''' Tocar 4 canais simultaneos de áudio com base em samples armazenados em ROMs |
'''Função:''' Tocar 4 canais simultaneos de áudio com base em samples armazenados em ROMs |
||
− | '''implementação:''' Estamos estudando a possibilidade de usar um chip MSM6295 |
+ | '''implementação:''' Estamos estudando a possibilidade de usar um chip MSM6295 ou um chip Amiga Paula. Ver issue no github: https://github.com/felipesanches/mame/issues/10 |
== Sistema de vídeo == |
== Sistema de vídeo == |
||
Linha 165: | Linha 354: | ||
==== rasterização ==== |
==== rasterização ==== |
||
+ | |||
+ | '''Resolução: ''' 320x200 pixels x 16 cores sendo a paleta selecionada dentre 64 opções de paletas |
||
TO-DO: |
TO-DO: |
||
Linha 175: | Linha 366: | ||
'''Passo 4:''' Realizar em portas lógicas e montar em protoboard ou PCB e testar |
'''Passo 4:''' Realizar em portas lógicas e montar em protoboard ou PCB e testar |
||
+ | |||
+ | == Ver também == |
||
+ | |||
+ | * [https://twitter.com/juca_gnu/status/686597622417719296 Tweet de 11/JAN/2016] "Emulating Eric Chahi's Another World at the bytecode level with my custom MAME fork #gamedev" |
||
+ | * [https://twitter.com/juca_gnu/status/762719829035982848 Tweet de 08/AGO/2016] "Control unit signals sequencer configured by a set of microcode ROMs #weekendproject #anotherworld #JAMMA #CPU #hack" |
Edição atual tal como às 14h59min de 29 de maio de 2017
Esta página contém rascunhos da concepção do projeto de uma placa JAMMA para o jogo Another World. Este projeto está sendo desenvolvido ao longo de uma atividade semanal no Garoa chamada CPU do Zero. Todo o projeto será implementado como hardware livre (com os esquemáticos distribuidos sob a licença livre CERN Open Hardware License v1.2).
- os esquemáticos estão sendo projetados usando o software KICAD
- os arquivos estão sendo publicados no GitHub em https://github.com/felipesanches/AnotherWorld_JAMMA
- as tarefas pendentes deste projeto estão sendo monitoradas neste bugtracker: https://github.com/felipesanches/mame/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20anotherworld
- o código fonte de protótipo via emulação está sendo desenvolvido em: https://github.com/felipesanches/mame/tree/anotherworld
Relógio Central
Função: Gerar o sinal de clock para a CPU e para os circuitos de geração de vídeo implementação: (pendente)
Possivelmente implementaremos um oscilador com porta NAND, capacitor e resistor. Mas talvez façamos um upgrade prum oscilador com cristal.
Precisaremos também ter um divisor de clock para gerar todas as frequencias necessárias para o sistema (unidade de controle, vídeo, som, etc).
CPU
Unidade de Controle - Decodificador de Instrução
Função: Detectar qual instrução o processador precisa executar com base no valor do código de instrução atual implementação: (pendente)
Sugestão:
Como o instruction set da VM é muito simples e tem opcodes com valores incrementais de 0x00 a 0x1A (mais um par de instruções especiais em 0x80 e 0x40) é possível implementar trivialmente um decoder por meio do uso de um decodificador de 5 bits para 32 linhas. Isso pode ser implementado usando 2 decoders de 4 bits para 16 linhas como o 74154.
As duas instruções especiais (que são relativas a renderização de video) podem ser decodificadas com algumas poucas portas NAND com dados vindo dos bits 6 e 7 do registrador de instrução.
Instruction Set
Segue abaixo uma listagem de todas as instruções e seus respectivos opcodes
0x00 | movConst | varID | const H | const L | [varID] <= const | |||
0x01 | mov | dst | src | [dst] <= [src] | ||||
0x02 | add | dst | src | [dst] <= [src] + [dst] | ||||
0x03 | addConst | varID | value | [varID] <= [varID] + value | ||||
0x04 | call | addr H | addr L | stack->push(PC); PC = addr | ||||
0x05 | ret | PC = m_stack->pop() | ||||||
0x06 | Break / "pauseThread" | Temporarily stops the executing channel and goes to the next. | ||||||
0x07 | jmp | addr H | addr L | PC <= addr | ||||
0x08 | Setvec | channelID | addr H | addr L | Initialises a channel (thread) with a code address to execute | |||
0x09 | djnz | varID | addr H | addr L | Decrement variable value and Jump to address if value is Not Zero | |||
0x0A | Conditional Jump instructions | subopcode | varID | value | JZ, JNZ, JG, JGE, JL, JLE | |||
0x0B | setPalette | palID H | palID L | selects current palette | ||||
0x0C | updateChannel | first | last | type | Freeze (0), unfreeze (1) or delete(2) a range of channels. | |||
0x0D | selectVideoPage | bufferID | selects the current video page | |||||
0x0E | fillVideoPage | pageID | color | fills a video page with a solid color | ||||
0x0F | copyVideoPage | srcPageID | dstPageID | copies the contents of a video page to another one | ||||
0x10 | blitFramebuffer | pageID | updates display with the contents of the specified video page | |||||
0x11 | killChannel / "killThread" | stops running and deactivates the current channel | ||||||
0x12 | Text | stringID H | stringID L | x | y | color | Displays in the work screen the specified text for the coordinates x,y. | |
0x13 | sub | A | B | Subtract: [A] <= [A] - [B] | ||||
0x14 | and | A | B | Boolean AND: [A] <= [A] & [B] | ||||
0x15 | or | A | B | Boolean OR: [A] <= [A] | [B] | ||||
0x16 | shl | varID | value H | value L | Shift Left: [varID] <= [varID] << value | |||
0x17 | shr | varID | value H | value L | Shift Right: [varID] <= [varID] >> value | |||
0x18 | play / "playSound" | resourceID H | resourceID L | freq | vol | channel | parameters: resourceId, freq, vol, channel | |
0x19 | load / "updateMemList" | resourceID H | resourceID L | bank-switching de recursos (paletas, bytecode, polígonos, etc) | ||||
0x1A | song / "playMusic" | resourceID H | resourceID L | delay H | delay L | pos | parameters: resourceID, delay, pos | |
0x40-0x7F | video | offset H | offset L | x | <etc> | renderização de polígonos | ||
0x80-0xFF | video (opcode contains 7-bit offset H) | offset L | x | y | renderização de polígonos |
Unidade de Controle - Microcódigo
Função: Implementa o comportamento de cada instrução por meio da geração de sinais de controle que manipulam o fluxo de dados implementação: (pendente)
Fluxo de Dados
Função: Elementos passivos que implementam os registradores internos da CPU, Pilha e memória implementação: (pendente)
STACK
A VM possui uma pilha de 256 elementos de 16 bits cada. Pensei em implementar isso com register files, mas não achei um grande o suficiente pra isso. O Mais próximo que achei foi esse que tem 64 elementos de 40 bits cada. Mesmo assim teria que ter 4 desses, sobrariam bits não usados e não sei o quão fácil é achar desse chip. Talvez seja o caso de usar uma RAM estática, mesmo que as menores disponíveis já sejam muito maiores que o realmente necessário aqui.
Sistema de áudio
Função: Tocar 4 canais simultaneos de áudio com base em samples armazenados em ROMs implementação: Estamos estudando a possibilidade de usar um chip MSM6295 ou um chip Amiga Paula. Ver issue no github: https://github.com/felipesanches/mame/issues/10
Sistema de vídeo
Função: Gerar sinal de vídeo para os pinos do conector JAMMA com base em rotinas de rasterização dos elementos poligonais armazenados em ROMs implementação: (pendente)
rasterização
Resolução: 320x200 pixels x 16 cores sendo a paleta selecionada dentre 64 opções de paletas
TO-DO:
Passo 1: Esturar o algoritmo de rasterização com base no código fonte da reimplementação livre da VM.
Passo 2: Implementar uma máquina de estados equivalente
Passo 3: Estágio de saída (paleta de cores) Implementar bank-switching para alternação de paletas de cores. E projetar conversor digital-analógico para os 3 canais de cores. Precisaremos de ROMs pequenas para armazenar as paletas de cores. Placas de arcade usam ROMs OTP (one-time-programmable) como a HM-7611 usada no jogo 1984 (ver a página "COLOR MIXER" do esquemático nesse PDF)
Passo 4: Realizar em portas lógicas e montar em protoboard ou PCB e testar
Ver também
- Tweet de 11/JAN/2016 "Emulating Eric Chahi's Another World at the bytecode level with my custom MAME fork #gamedev"
- Tweet de 08/AGO/2016 "Control unit signals sequencer configured by a set of microcode ROMs #weekendproject #anotherworld #JAMMA #CPU #hack"