Índice:

Revisitando o computador Z80: 6 etapas
Revisitando o computador Z80: 6 etapas

Vídeo: Revisitando o computador Z80: 6 etapas

Vídeo: Revisitando o computador Z80: 6 etapas
Vídeo: Como Derrotar Os JOGOS de "ROUND 6" 2024, Novembro
Anonim
Revisitando o computador Z80
Revisitando o computador Z80
Revisitando o computador Z80
Revisitando o computador Z80

No passado, escrevi um guia sobre como construir um computador baseado no Z80 e projetei o circuito para ser o mais simplista possível, para que pudesse ser construído da maneira mais fácil possível. Também escrevi um pequeno programa usando a mesma ideia de simplicidade. Este design funcionou muito bem, mas não fiquei totalmente satisfeito com ele. Comecei reescrevendo um programa para ele que permitisse que fosse programado durante o tempo de execução. Isso me permitiu testar partes do código sem ter que dedicá-lo à EEPROM, o que, por sua vez, me obrigaria a reprogramar a EEPROM. Isso não parecia uma ideia divertida para mim. Então comecei a pensar em espaços de memória. Se eu quisesse fazer a interface de um hardware (principalmente IO), um código poderia potencialmente exceder a quantidade de espaço de memória disponível para o sistema. Lembre-se de que o design usou apenas o byte inferior do barramento de endereço e, em seguida, o bit inferior do byte superior foi usado para selecionar entre os espaços ROM e RAM. Isso significava que eu tinha apenas 253 bytes de espaço para usar. Você pode estar se perguntando por que 253 em vez de 256. Isso porque meu novo código injeta três bytes de dados no final de um programa escrito (isso será abordado mais tarde, conforme eu o modifiquei para trabalhar no novo design).

n

Voltei aos meus antigos esquemas para ver o que mais estava acontecendo. Encontrei uma pequena falha no circuito de seleção de memória, que irei abordar quando chegar lá. A versão simplificada: todas as solicitações de gravação iriam realmente passar, embora sempre fossem colocadas na RAM. Provavelmente não era nada com o que valesse a pena se preocupar, mas eu queria fazer isso corretamente desta vez. E com isso, comecei a desenhar um novo esquema. As duas fotos anexadas a esta página são antes e depois do circuito real. Eu limpei tanto a fiação espaguete que não é engraçado.

n

Se você seguiu minha apresentação original e planeja continuar com esta, você vai me odiar. Se você está começando do zero, então você está com sorte. Basta pegar as peças da lista (ou seu equivalente) e seguir adiante.

Suprimentos:

LM7805 - regulador de 5 voltsZ80 - a CPU; os cérebros do systemAT28C64B - EEPROM. Armazenamento de dados “permanente” usado para o firmwareIDT6116SA - SRAM do computador; usado para armazenar o código do usuário e / ou armazenamento de dados geraisNE555 - System clock74HC374 - Octal D-Latch com / OE; usado como o chip de entrada 74LS273 - Octal D-Latch com / MR; output chipTLC59211 - Chip driver de LED (usado para que o 74LS273 acione LEDs, pois sozinho não é capaz de saída de corrente) MC14572 - Este é um chip “Line Driver”, mas achei perfeito para a lógica de Memory Control. Possui 4 inversores, e uma porta NAND e uma porta NOR incorporadas em 74LS32 - Quad OR gateCD4001 - Quad NOR gateCD4040 - Contador de ondulação de 12 estágios; Divisor de clock desenhado, mas não implementado (para operar o sistema em velocidades de clock mais lentas) 2 Resistores de 10K Ohm - Um é usado no circuito do temporizador 555, então use o valor que você quiser para ele4 Resistores de 1K Ohm - Um é usado para o Circuito do temporizador 555, então use o que quiser. Outro é usado para acionar LEDs, portanto, varie-o também se desejar LEDs de Barramento de resistor 8x10K Ohm8x10K Ohm - três são usados para o status do sistema e os outros oito são saídas. Para o 8, usei um display gráfico de barras (HDSP-4836). 4 Capacitores - Dois são usados no LM7805; 0,22uF e 0,1uF. Um é para o temporizador 555, então use o que achar que é certo. O último é para reinicialização da inicialização; 100uF2 N. O. Botões de pressão - um é usado para entrada, o outro para reset8 Chaves DIP SPST - entrada de dados; Eu usei Piano Key styleWire. Muitos e muitos fios

n

NOTA: a versão MC14572 com orifício passante está obsoleta, mas a versão SMD ainda está ativa (nem mesmo com o status “não para novo design”), então você pode precisar comprar uma placa de circuito para permitir seu uso. Um segundo 74LS32 pode ser usado no lugar do MC14572 (consulte o esquema do "circuito de seleção de memória" do ible anterior)

Etapa 1: Visão geral rápida das alterações + esquemas

Visão geral rápida das alterações + esquemas
Visão geral rápida das alterações + esquemas

Como ler o esquema: Uma seta apontada para um chip é uma entrada: Input> -Uma seta apontada para longe de um chip é uma saída: Output <-Busses usa uma linha em vez de uma seta: Bus | -

n

A maioria dos chips foi desenhada com sua pinagem exata. A pequena queda foi desenhada nesses chips. A maioria dos chips também tem números de pinos e etiquetas. Eles podem ser um pouco difíceis de ler. Meu lápis estava ficando sem brilho.

n

Em termos de conexões de circuitos, o layout do novo design praticamente não mudou em relação ao original. Eu conectei o bit inferior do byte alto do endereço às memórias e, em seguida, usei o bit inferior do nibble superior (A12) para a seleção de RAM / ROM. Isso significa que o espaço da ROM foi de 0000-00FF até 0000-0FFF. O espaço RAM passou de 0100-01FF para 1000-1FFF. Eu também troquei a lógica de controle de memória para um design melhor e adicionei dois novos LEDs de status (e alguma lógica de colagem). Eu também desenhei (mas não conectei) um circuito divisor de relógio. Era para desempenhar duas funções. A função óbvia é dividir a frequência do clock. A outra função é para fins de PWM (Modulação por Largura de Pulso), já que o 555 não gera ondas com ciclos de trabalho de 50%. Isso realmente não importa neste circuito, mas se você quiser usar o relógio para acionar alguns LEDs, você definitivamente notará os efeitos (um (conjunto de) LED (s) ficará mais escuro do que o outro). Todo o resto do circuito permanece essencialmente inalterado.

Etapa 2: CPU, memória e controle de memória

CPU, memória e controle de memória
CPU, memória e controle de memória
CPU, memória e controle de memória
CPU, memória e controle de memória
CPU, memória e controle de memória
CPU, memória e controle de memória
CPU, memória e controle de memória
CPU, memória e controle de memória

Esta é a parte em que os leitores da minha versão anterior me odeiam. Na construção original, eu meio que joguei as peças na placa em um lugar que parecia que impunham poucos problemas com a conexão. O resultado parecia que alguém jogou um prato de espaguete nele e foi como "fios!" Eu queria limpar um pouco, então comecei copiando tudo, exceto a CPU, RAM e ROM. Eu puxei quase todo o circuito de entrada, circuito de saída e a lógica de colagem. Quase me doeu, mas foi necessário. Deixei todas as conexões de dados intactas e o byte inferior do barramento de endereço. Em seguida, conectei os próximos quatro bits do barramento de endereço (A8-A11) ao chip ROM. Tive o cuidado de contornar o chip desta vez para torná-lo mais fácil de puxar para reprogramação. Também pulei as conexões de endereço para o chip de RAM.

n

Com isso fora do caminho, agora eu tinha que conectar a lógica de controle de memória. No esquema original, eu conectei a linha do processador / MREQ diretamente ao / CE para ambos os chips de memória, então conectei o / WR ao RAM / WE. Então eu tinha a CPU / RD e / MREQ logicamente OU juntas, bem como A9. Essencialmente, ele foi configurado para que todas as solicitações de memória ativassem RAM e ROM, mas A9 foi usado para selecionar qual dos chips '/ OE foi selecionado. Isso era bom e tudo porque os chips permaneceriam inativos até que uma solicitação de memória fosse feita e então apenas um / OE estaria ativo durante uma solicitação de leitura. Isso evitou a diafonia, mas introduziu uma nuance estranha. Como o A9 foi usado apenas para determinar qual chip estava emitindo dados e porque a CPU tinha acesso direto ao pino da RAM / WE, toda e qualquer solicitação de gravação passaria. Isso foi bom para a ROM porque seu modo de gravação é inibido ligando / WE diretamente à fonte de 5V. A RAM, no entanto, seria gravada independentemente do A9. Isso significava que uma tentativa de gravação em um local do espaço da ROM gravaria no mesmo local do espaço da RAM.

n

Uma solução para isso seria religar a lógica de controle para que a CPU tenha acesso direto aos pinos / OE e / WE dos chips e, em seguida, usar MREQ e A12 para selecionar quais chips / CE foi acionado. Eu aceitei essa ideia, mas em vez de usar quatro portas NOR e um inversor como o projeto original, encontrei um pequeno chip estranho que era perfeito para a tarefa. Tive que criar um circuito que usasse apenas as portas lógicas disponíveis no chip, mas isso foi bastante fácil. A12 alimenta diretamente em uma porta NAND e uma porta NOR. / MREQ é alimentado na porta NOR e seu complemento é alimentado na porta NAND. A porta NAND é usada para conduzir / CE para a RAM e a saída NOR é invertida e usada para conduzir ROM / CE. Isso faz com que / MREQ tenha que ser baixo antes que qualquer chip seja selecionado e então A12 escolhe qual deles será selecionado. Com esta configuração, agora qualquer solicitação de gravação na ROM não fará nada. Ele também economiza energia porque apenas um chip está ativo em vez de ambos. Quanto ao próprio chip lógico, ainda temos dois inversores não utilizados dentro. Um vai se acostumar mais tarde, mas chegaremos lá quando chegarmos.

Etapa 3: LEDs de status do sistema

LEDs de status do sistema
LEDs de status do sistema
LEDs de status do sistema
LEDs de status do sistema

Antes de começar este projeto, estava tentando fazer a interface com um determinado IC, mas estava tendo problemas com isso. Sem saber o que estava acontecendo, usei um LED de montagem em painel para sondar (um desses conjuntos que tem um resistor embutido). Fazer isso me deu uma ideia nostálgica que ainda é usada hoje: LEDs de status usados para indicar se a memória estava sendo lida ou gravada. Era para ser usado em conjunto com o LED de entrada que eu já tinha. O LED de entrada foi conectado ao gerador de sinal / WAIT para nos indicar que o sistema está, bem, esperando pela entrada (vou chegar lá, não se preocupe). Considerei adicionar um LED para indicar uma gravação de E / S, mas percebi que os LEDs de saída mudando já seriam um ótimo indicador disso. Pensando nisso, ainda posso adicionar. Mesmo assim, acho útil saber se a memória está sendo lida ou escrita. Bem, é útil para depuração de programa, de qualquer maneira. Na verdade, usei intensamente isso ao tentar fazer meu programa funcionar: “por que ele está gravando na memória? Não era para estar fazendo isso ainda!"

n

Para controlar esses LEDs, usei a porta NOR quad. Usei todos os portões. Apenas dois foram usados para gerar os sinais de status, mas o chip não tem os recursos de energia para realmente acionar os LEDs. Eles são capazes de absorver tanta energia, então usei as outras duas portas NOR como inversores e conectei os LEDs como tal. Como um LED é usado para indicar leituras e o outro para gravações, e uma solicitação de leitura e gravação não ocorre ao mesmo tempo, consegui evitar usar apenas um resistor para ambos os LEDs. Quanto aos sinais que eu precisava decodificar, também foi bastante fácil. Eu queria que todas as solicitações de leitura de memória fossem indicadas, então a primeira porta NOR tinha / MREQ e / RD em suas entradas. O status de gravação era um pouco mais complicado, mas igualmente fácil. Eu ainda usei / MREQ como uma entrada, mas usar / WR como a outra causaria uma pequena nuance que eu queria evitar. Isso teria indicado TODAS as solicitações de gravação. Eu só queria aqueles que realmente passaram. Então, como eu faria isso? Bem, lembra como eu tenho o sistema configurado para que apenas a RAM possa ser gravada? Usei os RAMs / CE como outra entrada para a porta NOR. Isso significa que o LED só acenderá quando a RAM for selecionada e uma solicitação de gravação estiver sendo feita. Em termos de cor do LED, escolhi o laranja como o indicador de leitura (mas só encontrei os amarelos) e o vermelho como o indicador de gravação.

Etapa 4: entrada e saída

Entrada e saída
Entrada e saída
Entrada e saída
Entrada e saída
Entrada e saída
Entrada e saída

Na etapa anterior, você deve ter percebido que já adicionei alguns dos outros componentes à placa. Eu estava reservando o espaço para não colocar acidentalmente os fios onde queria um componente (portanto, teria que encontrar um novo local para o referido componente). Você também deve ter notado que deixei os interruptores de entrada no lugar e os conectei ao barramento de alimentação. Decidi que o local original era o local perfeito e decidi colocar os LEDs de saída nas proximidades (acima). À direita da barra de exibição está a trava de entrada. Acima está a trava de saída e à esquerda dela está o driver de LED. Comecei conectando o monitor ao driver, pois era o mais fácil de fazer. Em seguida, conectei os interruptores ao lado da entrada da trava de entrada. Em seguida, conectei o lado da saída da trava de saída ao driver de LED. Pode parecer uma ordem estranha de fazer a fiação, mas era por um motivo. A entrada da trava de saída deveria ser conectada ao barramento de dados, bem como a saída da trava de entrada. A ideia era conectar as saídas da trava de entrada às entradas da trava de saída, o que fiz. Então, tudo o que tive que fazer foi conectar aquela bagunça ao barramento de dados. Não importava para onde essas conexões fossem fisicamente, porque todas estariam eletricamente conectadas. O computador está quase pronto.

Etapa 5: Reinicializar e finalizar entrada e saída

Desculpe, não há fotos para esta etapa. Consulte a etapa anterior para ver as fotos.

n

Você deve ter notado na última foto da etapa anterior, eu tinha um botão verde e outro chip lógico instalado. O chip é a porta OR. Duas portas são usadas para gerar o sinal / WAIT. Bem, um gera o sinal por OR-ing / IORQ e / RD do processador. A saída é alimentada no segundo portão, onde obtém OU novamente para um botão. O botão traz a entrada da porta alta, trazendo assim a saída alta. Esta saída é fornecida aos processadores / pino WAIT. Enquanto não pressionado, um resistor mantém a entrada baixa. Eu usei inicialmente um resistor de 10K, mas o LS32 estava realmente colocando tensão na entrada. O resistor não caiu o suficiente e eu tive que substituí-lo por um 1K. De qualquer forma, a ideia é que, quando uma solicitação de leitura IO é feita, a primeira e a segunda portas OR dizem ao processador para esperar. Depois de definir as opções de entrada para o que quiser, você pressiona o botão e tira a CPU da condição de espera. O LED verde de “entrada”, como o chamei em uma etapa anterior, é conectado de forma que quando o pino / WAIT ficar baixo, ele acenda.

n

Mas ainda não terminamos. O flip-flop de entrada precisa de um sinal para avisar quando a entrada de dados é válida e deve ser enviada para a CPU. Este pino de relógio está ativo alto. Antes, apenas o conectávamos ao botão. Esta ainda é uma opção válida, mas desta vez optei por colocá-la na mesma saída da segunda porta OR. Este IC também tem um pino / OE que precisa ser acionado. Se fosse para ser mantido alto, ele nunca iria inserir dados no barramento. Se mantido baixo, ele sempre estaria dirigindo o ônibus. Para consertar isso, eu simplesmente usei uma terceira porta OR. As entradas são / IORQ e / RD e a saída vai diretamente para o latch’s / OE.

n

A trava de saída também precisa que o pino do relógio seja acionado. Novamente, é ativo alto. Em meu esquema, desenhei a quarta porta OR acionando diretamente o pino usando / IORQ e / WR. Isso significava que o pino do relógio seria mantido alto até que uma solicitação de gravação fosse feita e, em seguida, baixaria e aumentaria novamente. Provavelmente não teria problema, porque o barramento de dados ainda teria dados válidos imediatamente após a tentativa de gravação, mas do ponto de vista da engenharia, era um projeto lixo. Não percebi esse erro até depois de tirar as fotos finais, mas rasguei essa conexão e alimentei a saída da porta OR em um dos inversores não utilizados da lógica de controle de memória e conectei sua saída ao pino do relógio. Também consertei o esquema e encontrei outro erro que cometi. Eu também corrigi.

n

Com tudo isso finalmente feito, eu tinha muito pouco trabalho a fazer: o circuito de reset. Eu adicionei um botão à placa e usei um resistor de 10K para segurar um lado alto. O outro lado vai diretamente para o solo. O lado mantido alto é a saída / RESET, que foi para cada chip com um pino / RESET (a CPU e a trava de saída). Para realizar a reinicialização da inicialização, adicionei um capacitor à saída / RESET. A ideia é que o resistor de grande valor faria com que o capacitor relativamente grande carregasse lentamente e mantivesse os pinos / RESET baixos por alguns ciclos de clock (a CPU precisa de quatro ciclos de clock). Você provavelmente já pode adivinhar qual é o lado negativo deste circuito. É o mesmo negativo da versão anterior porque é o mesmo circuito. Quando o botão é pressionado, o capacitor está essencialmente em curto através do botão. Isso é ruim tanto para a tampa quanto para o botão, então se você deseja tornar sua construção um pouco mais permanente, convém reformulá-la. Eu estava pensando em outro temporizador 555 configurado no modo monoestável. Mas com isso, o circuito do computador acabou. Yay. Agora ele precisa ser programado.

Etapa 6: Programação

Programar essa coisa foi um pesadelo. Eu construí um programador EEPROM Arduino. Não funcionou. Eu construí outro baseado no design e codificação de outra pessoa. Ainda não funcionou. Voltei ao método testado e comprovado de configurar manualmente os endereços e os bytes de dados. De alguma forma, eu estraguei tudo. Tentei de novo e ainda entendi errado. Voltei mais uma vez e descobri que estava errado por um único byte, então corrigi e finalmente funcionou, graças a Deus.

n

Quanto ao programa real, parece muito complexo e difícil de seguir, mas não é. É muito simples, na verdade. Metade dele está copiando números. A outra metade é compartilhada entre a matemática de 16 bits, saltos condicionais e ainda mais números de cópia ao redor. Deixe-me explicar como funciona.

n

A inicialização apenas define alguns valores de registro para uso pelo programa. O loop do programa é um pouco mais complexo, mas não muito. Primeiro, ele aceita entrada para o registro A na porta 00. Em seguida, o registro E é gravado na memória. Nos primeiros dois loops, o registrador E contém dados inúteis, então tentamos gravá-lo nos últimos dois bytes do espaço ROM porque ele não será realmente gravado; o ponteiro de endereço (IY) é então incrementado. O valor armazenado em D é então movido para E para ser escrito em seguida. A é então carregado em D e L e E é copiado em H. HL é onde a comparação de valores ocorre por meio de subtração e verificação de ZF (sinalizador zero). O primeiro valor comparado é armazenado nos registros B e C. B e C são tratados como um único registro de 16 bits, BC. Se os valores forem iguais, o programa vai direto para o espaço da RAM, onde o código do usuário deve residir. Se o código em BC não for uma correspondência, então HL é recarregado com os valores iniciais de D e E e é comparado novamente ao valor em SP da mesma forma que foi comparado com BC. Se for uma correspondência, tem o mesmo resultado, mas três bytes extras são gravados na memória. Os bytes são um código que faz com que a CPU volte para o início de seu programa (uma reinicialização do software). Se a segunda comparação não for uma correspondência, no entanto, o programa faz um loop para onde obtém um valor do usuário.

n

LD SP, EDBFH; código exe (adiciona salto)

n

LD IY, FFEH; ponteiro de memória inicial para armazenamento de código

n

LD BC, EDC3H; código exe (sem loop)

n

ciclo; diretiva assembler para que não tenhamos que saber onde na memória esta parte reside

n

IN A, (00H); obter dados do programa

n

LD (IY + 00H), E; E contém o código a ser armazenado

n

INC IY; mover para o próximo local de memória

n

LD E, D; ld D em E

n

LD D, A; ld A em D

n

LD H, E; ld E em H

n

LD L, D; ld D em L

n

OR A; redefinir bandeira de transporte

n

SBC HL, BC; retorna 0 se o código exe 2 foi inserido

n

JP Z, 1000H; em caso afirmativo, pule para e execute o programa

n

LD H, E; caso contrário, atualize-os para os valores adequados

n

LD L, D

n

OR A; a primeira subtração pode ter definido o sinalizador de transporte. Limpar

n

SBC HL, SP; retorna 0 se o código exe 1 foi inserido

n

JP NZ, loop; se não, repita o processo (começando com a obtenção de um valor)

n

LD (IY + 00H), C3H; caso contrário, injete um código de salto no final do programa do usuário

n

LD (IY + 01H), 00H; salto atua basicamente como uma reinicialização do software

n

LD (IY + 02H), 00H; é uma reinicialização completa caso os registros sejam modificados

n

JP 1000H; pular e executar o programa do usuário

Recomendado: