Montando o circuito do registrador de saída (OPR), o circuito de reset (RST) e executando o primeiro programa!

Fala pessoal, tudo bem?

Dando continuidade à montagem e estudo do computador de 8-bits, o post de hoje vai tratar do circuito de reset, do registrador de saída (OPR - Output Register) e do primeiro programa de teste para certificar a montagem e o funcionamento dos circuitos que temos até agora.

 Visão geral do computador de 8 bits

Primeiramente, falaremos do circuito de reset, que é bem simples.

Ele consiste basicamente de um push-button, um resistor de 10k Ohms, 3 portas NOT e 1 porta NAND. Vou deixar o esquema abaixo (como é de costume, feito à mão :P ).

Esquema tosco feito à mão do circuito de reset :P

O grande lance aqui é o resistor de 10k fazendo um pull-down na entrada de uma das portas NOT e, já que falei delas, as portas NOT são usadas aqui como buffers e, como precisamos dos dois estados de reset (RESET e /RESET), utilizamos outra porta NOT na saída da anterior para inverter seu valor.

Por enquanto, não se preocupem em entender a outra parte do circuito (a porta NAND e a outra NOT que trabalham com os sinais /CYCLE_END e /CYCLE_RST). Essa parte será tratada mais para frente. ;)

Os sinais de reset gerados por este circuito foram ligados aos respectivos pinos de reset de todos os circuitos que o possuem (ACC, B, PC, IR, MAR e do próprio OPR).

Até aqui, nada demais né?

Então, vamos tratar de algo mais interessante: o registrador de saída (OPR - Output Register). Este registrador, por mais simples que seja, é um componente fundamental no funcionamento do computador de 8 bits (na verdade, no funcionamento dos computadores em geral).

Ele é responsável por armazenar informações ou valores vindos da memória ou de outros registradores (ACC, B, etc), etc. Enfim, ele armazena algum valor que precisamos exibir e com isso, libera os outros registradores para continuar fazendo seus trabalhos.

No nosso computador de 8 bits, ele funciona da seguinte maneira: recebe um byte vindo do BUS, o armazena e, como possui um canal de comunicação direta com o circuito de exibição que montaremos utilizando displays de 7 segmentos, exibe o valor armazenado na forma de números decimais.

Eletronicamente falando, ele tem o funcionamento muito parecido com os outros registradores do computador (pelo fato de reter informação para uso posterior). Tratando-se do circuito, sua implementação também é muito parecida. Só não é igual ao registrador B, por exemplo, pelo fato de não possuir o 74LS245 (transceptor de barramento de oito bits, tri-state), pois não necessita escrever seu conteúdo no barramento. Ele possui somente os dois 74LS173 (registrador de 4 bit, tipo D, com saídas tri-state) para armazenar o valor vindo do BUS e repassá-lo ao circuito de display decimal.

Ele possui também um conjunto de 8 LEDs amarelos ligados à sua saída para que possamos ver, na forma binária, seu conteúdo. Isso é muito útil quando estamos debugando um programa.

E, por fim, vamos à parte que mais interessa aos escovadores de bits de plantão: o primeiro programa-teste executado pelo computador de 8 bits!

Como você já deve imaginar, nosso computador tem pouca capacidade de armazenamento e processamento. E isso, claro, deve ser respeitado (também, não tem para onde correr né... rs).

Isso quer dizer que ele roda programas simples com operações lógicas e artméticas de tamanho limitado (lembre-se: temos somente 16 bytes de memória RAM :P ).

Para testes, eu peguei um pequeno programa proposto pelo Eng. Wagner Rambo, da WR Kits, e o executei, passo a passo, no nosso computador. Já adianto que funcionou maravilhosamente bem!

O enunciado do programa proposto é o seguinte:

"Escreva um programa em Assembly para o computador de 8 bits que salve valores de, no máximo, 15 (em decimal) no registrador de saída (OPR - Output Register), independente do dado de entrada no acumulador (ACC)."

Para resolver o problema, foi escrito o seguinte programa:

.ORG 0h
    LDA [Ah]
    AND [9h]
    OUT
.END


Como implementaremos cada uma das instruções do computador, os OPCODES definidos para cada uma delas foram:

Instrução OPCODE
--------- ------
   LDA     0001
   AND     0110
   OUT     1110


Sendo assim, compilando manualmente o programa, temos:

Endereço (RAM)     Dado
-------------- ------------
 0h     0000     00011010
 1h     0001     01101001
 2h     0010     11100000 

    (...)         (...)
 9h     1001     00001111 (máscara de bits)

 Ah     1010     10100101 (165 >> 15; para testar a lógica)

Com essa compilação em mãos, chegou a hora de gravar o programa na memória RAM. Para isso, foi implementado um pequeno circuito para dar o pulso de gravação na memória, estando esta no modo de operação de escrita.

Vou deixar abaixo o script de gravação e execução do programa. Como eu queria verificar cada passo, em cada pulso de clock, para cada instrução, utilizei  modo de clock manual.

.INÍCIO

1. entrar no modo de programação (escrita) da memória RAM e armazenar o programa compilado acima
2. ativar o modo de execução (leitura) da memória RAM
3. com o computador resetado (todos os contadores e registradores zerados), iniciar o ciclo de busca e execução da instrução LDA
4. buscar LDA [Ah] no endereço 0000:

     - habilitar:

         PC_OUT
         MAR_IN
         CLK (pulso de clock)
     - desabilitar:
         PC_OUT
         MAR_IN
    - nesse momento, temos o valor 0000 gravado no registrador de endereço de memória - MAR
5. disponibilizar o conteúdo do endereço 0000 no BUS e gravá-lo no IR:
    - habilitar:
        RAM_OUT
        IR_IN
        PC_INC
        CLK
    - desabilitar:
        RAM_OUT
        IR_IN
        PC_INC
    - neste ponto, o valor do endereço 0000 da memória (00011010) está gravado em IR e PC foi incrementado em 1
6. executar a instrução LDA:
    - habilitar:
        IR_OUT (somente o nibble menos significativo - LSN vai para o BUS)
        MAR_IN
        CLK
    - desabilitar:
        IR_OUT
        MAR_IN
    - neste momento, temos o endereço do BUS (LSN = 1010 = Ah) em MAR e, na RAM, o dado salvo previamente já selecionado
    - habilitar:
        RAM_OUT
        ACC_IN
        CLK
    - desabilitar:
        RAM_OUT
        ACC_IN
    - neste momento, temos o dado da RAM salvo em ACC (aqui termina o ciclo de busca e execução de LDA)
7. buscar AND [9h] no endereço 0001:
    - habilitar:
        PC_OUT
        MAR_IN
        CLK
    - desabilitar
        PC_OUT
        MAR_IN
    - nesse momento, temos o valor 0001 gravado no registrador de endereço de memória - MAR
8. disponibilizar o conteúdo do endereço 0001 no BUS e gravá-lo no IR:
    - habilitar:
        RAM_OUT
        IR_IN
        PC_INC
        CLK
    - desabilitar:
        RAM_OUT
        IR_IN
        PC_INC
    - neste ponto, o valor do endereço 0001 da memória (01101001) está gravado em IR e PC tem o valor 2
9. configurar a ALU para a operação AND:
    - habilitar:
        ALU_0
    - na execução normal, neste passo, o circuito de controle identificaria a operação AND através de IR e configuraria a ALU para tal operação
10. executar a instrução AND:
    - habilitar:
        IR_OUT (somente LSN vai para o BUS)
        MAR_IN
        CLK
    - desabilitar:
        IR_OUT
        MAR_IR
    - neste momento, temos o endereço do BUS (LSN = 1001 = 9h) em MAR e, na RAM, o dado salvo previamente já selecionado
    - habilitar:
        RAM_OUT
        BR_IN
        CLK
    - desabilitar:
        RAM_OUT
        BR_IN
    - neste momento, temos o dado da RAM salvo em B (aqui termina o ciclo de busca e execução de AND). O resultado da operação já pode ser visto na ALU (5h)
11. salva o resultado da operação no ACC:
    - habilitar:
        ALU_OUT
        ACC_IN
        CLK
    - desabilitar:
        ALU_OUT
        ACC_IN
    - neste ponto, o valor da operação da ALU está salvo em ACC
12. buscar OUT no endereço 0010:
    - habilitar:
        PC_OUT
        MAR_IN
        CLK
    - desabilitar
        PC_OUT
        MAR_IN
    - nesse momento, temos o valor 0010 gravado no registrador de endereço de memória - MAR
13. disponibilizar o conteúdo do endereço 0010 no BUS e gravá-lo no IR:
    - habilitar:
        RAM_OUT
        IR_IN
        PC_INC
        CLK
    - desabilitar:
        RAM_OUT
        IR_IN
        PC_INC
    - neste ponto, o valor do endereço 0010 da memória (11100000) está gravado em IR e PC tem o valor 3
14. salva o valor de ACC em OPR:
    - habilitar:
        ACC_OUT
        OPR_IN
        CLK
    - desabilitar:
        ACC_OUT
        OPR_IN
    - e, finalmente, neste ponto, temos o valor de ACC (5h) salvo em OPR

.FIM


Como podem ver nas fotos abaixo, todas as operações executaram com sucesso! Com isso, temos certeza de que podemos avançar.

Valor 00011010 gravado no endereço 0000 da RAM

Valor 01101001 gravado no endereço 0001 da RAM

Valor 11100000 gravado no endereço 0010 da RAM

Valor 00001111 gravado no endereço 1001 da RAM

Valor 10100101 gravado no endereço 1010 da RAM

Aqui, pode-se ver o valor final da operação (05h) sendo exibido na ALU

E finalmente nesta, o resultado final (05h) sendo exibido nos LEDs do registrador de saída (OPR) :D

Então, é isso. No próximo post trataremos do circuito do display decimal.

Bons estudos à todos!

Comentários

Postagens mais visitadas