Fig. 1: Computador de retransmissão BrainfuckPC em segundo plano de seu autorContinuando a gloriosa tradição do resumo anual dos meus projetos de computador mais loucos, apresento a você o terceiro e
último artigo sobre o projeto de computador de revezamento BrainfuckPC.
Nas séries anteriores:
Após dez anos de sonho e reflexão, mais de dois anos de trabalho e montagem sem pressa, posso dizer com confiança que o projeto do computador de revezamento ocorreu. Apesar de o computador ser inútil do ponto de vista prático e também travar regularmente, ele se tornou o ponto de partida para os próximos projetos cibernéticos não menos loucos.
Sob o cortador, estão os blocos de relé tocando, os cálculos mais rápidos do mundo, finalizações, indicadores de vácuo e muito mais.
Linguagem de programação Brainfuck
A linguagem de programação do cérebro é talvez a linguagem de programação esotérica mais popular do mundo. E, ao mesmo tempo, o verdadeiro
Turing é um atoleiro completo . Apenas 8 instruções nas quais você pode escrever qualquer coisa, mas por muito tempo.
Por exemplo, levei três dias para escrever e depurar o programa de divisão 355/113, que imprime 6 casas decimais no terminal.
Figura 2: instruções da linguagem brainfuckToda a sintaxe da linguagem é construída em torno da RAM para 30 mil células de memória, com capacidade de 8 bits.
- Com duas instruções + e -, alteramos o valor na célula de dados atual em uma para cima ou para baixo.
- Com duas instruções < e > , alteramos o ponteiro para a célula de dados atual por uma, movendo assim para a esquerda ou direita na memória.
- Mais duas instruções [ e ] - permitem organizar loops. Tudo dentro dos colchetes é o corpo do loop. Loops aninhados são permitidos. A lógica da instrução é simples - se o valor da célula de dados atual não for igual a zero - executaremos uma iteração do loop, se for igual, sairemos do loop.
- As duas últimas instruções . e , - permitem exibir o valor da célula atual no console ou inserir sua RAM. Assim, a interatividade é alcançada.
Sim, isso é mais que suficiente para escrever qualquer programa. A existência de compiladores C
no cérebro parece sugerir isso. Mas a densidade do código é inexistente. Para executar operações simples, como adicionar os valores de duas células de memória, você precisa executar centenas de instruções sobre o cérebro.
brainfuck ++
Vamos tentar aumentar a densidade do código pelo menos um pouco. Ao estudar programas escritos nesta língua, você pode prestar atenção que, na maioria das vezes, eles consistem em seqüências das mesmas instruções
+ - <> . Isso leva muitos à idéia de dobrar a sequência de tais instruções em uma e obter um pequeno ganho de desempenho, que de um programa para outro pode chegar a dezenas de por cento e gerar um aumento múltiplo na velocidade. Por exemplo, substituímos 10 operações de incremento por uma operação de +10. 20 operações de mover o ponteiro para a direita para a operação> 20 e assim por diante.
Figura 3: instruções da linguagem brainfuck ++Da teoria à prática
Como você entende, não se pode apenas pegar e escrever na linguagem do cérebro a operação Rb = Ra + Rb, onde Ra e Rb são células de memória. Tudo o que podemos fazer é alterar o conteúdo de uma célula para uma constante e verificar se é zero. Como resultado, para somar os dois números, tudo o que resta para nós é fazer +1 para a célula Rb e -1 para a célula Ra, até que o conteúdo da célula Ra se torne zero. Nós escrevemos isso na forma de um código em C:
void addMov(Memory &mem, uint16_t RbPos) { while (*mem) { mem += RbPos; (*mem)++; mem -= RbPos; (*mem)--; } }
Como resultado, o valor antigo aparecerá na célula RbPos mais o que estava no endereço de origem. classe Memory - um contêiner com 65k células inteiras. Sua propriedade principal é que o excesso do valor do ponteiro o retornará ao início da matriz. Como no meu hardware real.
A desvantagem da função descrita é a perda do valor original - ela será zerada. Adicione outra variável Rc para salvá-la:
void addCpy(Memory &mem, uint16_t RbPos, uint16_t RcPos) { while (*mem) { mem += RbPos; (*mem)++; mem -= RbPos; (*mem)--; mem += RcPos; (*mem)++; mem -= RcPos; } }
Como resultado, o termo copiado estará na célula RcPos. Bem, no caso de haver zero.
Como a notação que usei lembra muito o brainfuck ++ - apenas reescrevemos nossa função em caracteres bfpp, usando RbPos para 4 e RcPos para 5 como exemplo:
[
>>>>
+
<<<<
-
>>>>>
+
<<<<<
]
Após descrever todas as primitivas, você pode começar a combiná-las em estruturas mais complexas e obter o programa da funcionalidade necessária. Como resultado, você pode obter um programa que divide 355 por 113 (ou qualquer outro número entre si em 16 bits)
Programa de ponto flutuante class Memory { public: Memory() { memset(m_mem, 0, sizeof(m_mem)); memPtr = 0; } Memory& operator += (uint16_t ptr) { memPtr += ptr; return *this; } Memory& operator -= (uint16_t ptr) { memPtr -= ptr; return *this; } uint16_t& operator [] (uint16_t ptr) { return this->m_mem[ptr]; } Memory& operator = (uint16_t ptr) { memPtr = ptr; return *this; } uint16_t & operator * () { return m_mem[memPtr]; } Memory& operator ++ () { memPtr++; return *this; } Memory& operator -- () { memPtr--; return *this; } private: uint16_t memPtr; uint16_t m_mem[65536]; }; void calcPi() { Memory mem; *mem = 22; mem += 1; *mem = 7; while (*mem) { mem += 1; (*mem)++; mem -= 1; (*mem)--; mem += 2; (*mem)++; mem -= 2; }
Arquitetura de computadores de retransmissão
O elemento central do processador de relé é um somador completo de 16 bits com transporte paralelo. Dois registradores estão conectados a ele na entrada. TMP é o registro temporário no qual o valor antigo é colocado e CMD é o registro de comando no qual a instrução e a constante pela qual o valor antigo será alterado são armazenadas.
Portanto, eu posso executar operações otimizadas do brainfuck ++ e, ao mesmo tempo, obter saltos condicionais completos - Jump If Zero e Jump If Zero para qualquer lado do programa.
O resultado da operação de soma pode ser carregado em um dos registradores de contexto - AP - com o número da célula de dados atual ou IP - com o número da instrução atual. Além disso, o resultado pode ser carregado na célula RAM atual, se vier às instruções
+ e
-
Fig. 4: Arquitetura do computador de retransmissão em operação. O estágio de carregamento da nova instrução é substituído pelo estágio de sua execução.Primeiro de tudo, precisamos calcular o número da próxima instrução - ou seja, execute uma operação IP ++. Para fazer isso, um é adicionado ao valor antigo do registro IP, o resultado é gravado de volta no registro IP e a próxima instrução é carregada nesse novo endereço, no registro CMD.
O segundo passo é a execução da instrução recém-carregada. Se funcionar com o somador, o processo de sua execução será semelhante ao processo de carregamento de uma nova instrução - o valor antigo está no registro temporário, adicionamos a constante nos bits inferiores do registro CMD e gravamos o resultado no registro ou na célula de dados atual.
Assim, a instrução é executada em um tique do gerador de relógio. Em uma frente de queda, carregamos a próxima instrução, de forma crescente - nós a executamos.
não é um bug, mas um recursoE aqui um recurso foi revelado. Depois de ligar o computador, a primeira frente do gerador de clock aumentará e, portanto - teremos que executar a instrução atual, que ninguém carregou no registro CMD ainda - existem zeros.
Siga as instruções vazias e ... faça IP ++!
Como resultado, a célula de memória zero do programa contém zero e nunca será executada. A primeira instrução carregada da memória será a instrução em 0x0001.
Conjunto de instruções
Fig. 5: Conjunto de instruções do computador de reléAs instruções são de 16 bits, onde os 4 bits de ordem superior são responsáveis pelo tipo de instrução e os 12 bits de ordem inferior são a carga útil. Na maioria dos casos, isso é uma constante.
- Instrução NOP - ignorada.
- A instrução CTRLIO é uma instrução especial cujo comportamento é codificado pela máscara de carga da carga. Antes de tudo, implementa comandos para gravar no console e ler no console (nos modos síncrono ou assíncrono). Em segundo lugar, permite definir o modo de operação de 16 ou 8 bits da máquina. E em terceiro lugar, usando a instrução CTRLIO.HALT, você pode parar a máquina. O engraçado é que mascaram pedaços
sem bloqueio. Você pode configurá-los pelo menos todos de uma vez, mas o comportamento da máquina será indefinido. - A instrução ADD é uma operação de célula de dados. Altera o valor na célula pelo valor da constante. Nesse caso, o bit 12 é um bit assinado e é copiado para os bits 13-15. Portanto, a instrução 0x2ffe se transforma na operação * AP + = 0x0ffe, e a instrução 0x3ffe se transforma em * AP + = 0xfffe. A operação de subtração é substituída pela adição por um número negativo.
- Instrução ADA - implementa a operação AP + = const e permite navegar pela memória.
- As instruções JZ e JNZ são condicionais. Dependendo da bandeira Z, você pode pular algumas instruções para frente ou para trás ou permanecer no lugar. Dependendo do modo de operação da máquina - 16 ou 8 bits, o estado do sinalizador Z é determinado pelo byte de dados menos significativo ou pela palavra inteira.
Especificações técnicas
O BrainfuckPC é um computador de 16 bits com um processador de relé reed, arquitetura Von Neumann e conjunto de instruções Brainfuck ++
- Número total de relés: 578 peças
- O número total de elementos lógicos: 157 peças
- Largura do barramento de endereço: 16 bits
- Endereçamento: palavra por palavra
- RAM: 128 KB (64 Kslov)
- Largura do barramento de dados: 16bit / 8bit
- Frequência do relógio (atual / máximo): 25Hz / 40Hz
- Consumo de potência: 70W
- Dimensões totais: 110kh650kh140mm
- Peso: 15kg
Inicialmente, assumiu-se que o computador funcionaria em frequências de até 100 Hz ... E isso - por um minuto - 4 oitavas de piano. Infelizmente, os primeiros testes mostraram que 40Hz é o teto, mas há muito disso no circuito de relés. ainda mais quando o relógio externo é necessário para aplicar dois pulsos por ciclo - devido às peculiaridades do circuito de sincronização com um sinal externo. 80Hz para música já é algo.
Composição do computador
Fig. 6: Principais componentes do relé.Vamos dar uma olhada no computador. Quase todo o volume da máquina é ocupado por unidades de processador de relé. No momento, tudo se encaixa em cinco blocos, mas há espaço para seis - portanto, se você realmente quiser, mais tarde a funcionalidade do processador poderá ser expandida.
Cada um desses blocos contém 32 módulos, em cada módulo existem 3 ou 4 relés de palheta RES55 e RES64. A fonte de alimentação de cada unidade é 5V, 3A.
Fig. 7: Conjunto de blocos e módulos de um processador de relé, pronto para instalação em um quadro.Cada módulo é unificado. 60x44mm, conector de 16 pinos. Ao montar os blocos lógicos, inseri o módulo necessário em um slot livre e mostrei as conexões.
Fig. 8: Os módulos D-flip-flop são verificados quanto à operacionalidade.Linha central - blocos somadores e blocos de registro. Acima e abaixo deles existem travas de 16 bits baseadas no RES43, que alternam o fluxo de dados entre os blocos. Todos os dados estão girando aqui.
A linha inferior é a linha dos blocos lógicos do processador. Agora, dois blocos estão parcialmente preenchidos, mas se você realmente quiser, modificar e expandir a funcionalidade devido ao espaço livre é mais do que possível.
Fig. 9: A estrutura é montada em chapa de alumínio de 2 mm, sob corte a laser. Na foto - quadro já soldado e preparado, pronto para pintura.A parte superior é indicador. À esquerda, está o bloco de status da máquina - os indicadores baseados no IV-6 exibem o número da célula de memória atual e a noite da instrução atual, a própria instrução e o contador geral de instruções executadas. O último é muito útil, porque se o emulador, por exemplo, diz que até o primeiro caractere no console você precisa executar 30 mil instruções, o contador mostrará claramente onde a máquina está agora e quando terminará a contagem.
Fig. 10: A vista final da área do indicador. No processo de fabricação.À direita está o cartão de memória - o elemento mais controverso da máquina. Embora eu acredite que o computador ainda seja retransmitido, o processador é definitivamente 100% retransmitido. A periferia é mais moderna. Em particular, a RAM é um chip de memória estática. Mas o mesmo acontece com quase todos os criadores modernos de computadores de retransmissão.
Fig. 11: Programador. 16 linhas de endereço, 16 linhas de dados, energia, aterramento e linhas de leitura de gravação. Total de 36 contatos.Como a memória de programas e dados é compartilhada, alguém ou alguma coisa, toda vez que você liga o computador, deve carregar o programa na RAM. Esta tarefa é atribuída ao programador. No momento, o programador está localizado na própria placa de memória. Agora ele tem exatamente duas tarefas.
- Faça o download do programa na RAM, pois toda vez que você o liga manualmente, usando as chaves de alternância, é uma preguiça comum, embora essa possibilidade esteja presente.
- Monitore o estado de uma determinada região da memória e exiba-a em uma matriz de LED 32x16.
Isso não afeta o processador, e ver em tempo real o que está acontecendo na RAM é muito útil na depuração. Posteriormente, quando o programador for externo, o painel de LEDs servirá a um dos módulos indicadores. Ele já sabe o endereço, resta fornecer os dados de entrada.
Fig. 12: Diagrama em bloco dos periféricos do processador.Portanto, em um futuro próximo, os circuitos dos periféricos do processador serão parecidos. Apenas chips de memória e circuitos de correspondência de sinal com o circuito de relé permanecerão na placa de memória.
Através do conector de programação de 36 pinos, você pode conectar o programador e fazer o download do firmware no computador. Além do programador, com o conversor de interface necessário, você pode usar qualquer outro dispositivo. Pelo menos um leitor de fita perfurada (a propósito, eu tenho um, completo com um furador e até um rolo de fita), pelo menos um painel com interruptores.
Como resultado, a lógica do relé fornece uma certa interface e o conversor de interface pode ser qualquer um. A propósito, o conector da interface paralela será compatível com o LPT ...
Demonstração do trabalho e status atual
Primeiro, o programa Hello World do artigo da wikipedia foi executado no computador.
O código fonte é o seguinte:
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++
.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.
------.--------.>+.>.
Graças ao painel de LED, você pode ver claramente como os dados mudam:
Embora com uma frequência de 25 Hz, é difícil acompanhar o que está acontecendo na RAM.
Uma tarefa mais útil e prática é calcular os sinais do número Pi após o ponto decimal. É claro que os computadores modernos resolveram esse problema com
até 31,4 trilhões de caracteres . Mas o próprio fato de o BrainfuckPC ser capaz de executar esta operação sugere que o computador de retransmissão não é 100% inútil, mas apenas 99,9.
Primeiro de tudo, eu encontrei um
algoritmo de cálculo pronto
escrito em cérebro .
> ++++ (4 digits)
[<+>>>>>>>>++++++++++<<<<<<<-]>+++++[<+++++++++>-]+>>>>>>+[<<+++[>>[-<]<[>]<-]>>
[>+>]<[<]>]>[[->>>>+<<<<]>>>+++>-]<[<<<<]<<<<<<<<+[->>>>>>>>>>>>[<+[->>>>+<<<<]>
>>>>]<<<<[>>>>>[<<<<+>>>>-]<<<<<-[<<++++++++++>>-]>>>[<<[<+<<+>>>-]<[>+<-]<++<<+
>>>>>>-]<<[-]<<-<[->>+<-[>>>]>[[<+>-]>+>>]<<<<<]>[-]>+<<<-[>>+<<-]<]<<<<+>>>>>>>
>[-]>[<<<+>>>-]<<++++++++++<[->>+<-[>>>]>[[<+>-]>+>>]<<<<<]>[-]>+>[<<+<+>>>-]<<<
<+<+>>[-[-[-[-[-[-[-[-[-<->[-<+<->>]]]]]]]]]]<[+++++[<<<++++++++<++++++++>>>>-]<
<<<+<->>>>[>+<<<+++++++++<->>>-]<<<<<[>>+<<-]+<[->-<]>[>>.<<<<[+.[-]]>>-]>[>>.<<
-]>[-]>[-]>>>[>>[<<<<<<<<+>>>>>>>>-]<<-]]>>[-]<<<[-]<<<<<<<<]++++++++++.
Um problema - embora se diga que esse programa é muito mais rápido que outro programa, ele ainda calcula o próximo caractere, mas é extremamente lento.
Fig. 13: Tempo gasto para gerar N dígitos de Pi após o ponto decimal.4 casas decimais terão que esperar quase uma hora e meia ...
Fig. 14: - Pi = 3! - Que rude!No entanto, até dois caracteres não puderam ser deduzidos; o computador afirmou que Pi tinha 4 anos e concluiu o trabalho.
Fig. 15: Ele sabe claramente da piada de que, sob a lei marcial, pi pode chegar a quatro.Eu decidi ir para o outro lado e escrevi uma calculadora de fração
. Precisão - 6 casas decimais! Este é o resultado mais preciso para frações com números de tamanho adequado.
Depois de três noites sem dormir, escrevi um programa sobre o cérebro, capaz de dividir dois números um no outro e emitir o resultado com um ponto flutuante no terminal. O veredicto do emulador é o seguinte: serão necessárias 60 mil instruções para executar. Nos últimos 10 mil por sinal:
Fig. 16: O tempo necessário para gerar a próxima casa decimal ao calcular a fração.A rapidez com que os próximos valores aparecerão. Devo dizer muito rapidamente em comparação com o programa anterior!
Mas a felicidade durou pouco - o computador começou a falhar no modo de 16 bits. Os diagnósticos mostraram que o cartão de memória está enganando - ele define constantemente o 13º bit. Vou fazer um novo cartão de memória e tudo vai passar, mas por enquanto vou me limitar a uma fração
duas casas decimais e modo de operação de 8 bits. Mais importante ainda, requer apenas 1.600 instruções a serem seguidas! A uma frequência de 25 Hz, isso é pouco mais de um minuto.
Repetidamente e com um apito, o computador lida com a tarefa.
Para continuar ...
Agora, no computador, você pode executar programas que não requerem entrada do usuário. Até agora, não estraguei trivialmente a instrução CTRLIO.CIN :) E não vou fazer isso tão cedo. O computador está atualmente 98% completo. E depois de dois anos de trabalho, muitos projetos se acumularam e aguardam o momento em que eu lidarei com eles.
Portanto, eu mudo para outros projetos
Primeiro de tudo, este é um computador de tubo baseado em decatrons do comutador. Eu já tenho um soco e os próprios decatrons (embora principalmente o A101 - o computador saia ainda mais lento que o relé - precisamos do A103). Até 700 tubos de vácuo já estão disponíveis e muito mais ...

Eu preparei uma memória para isso -
16 pedaços de cubos de memória integrados para 128 palavras de 16 bits cada. Interior - placas de ferrite de múltiplos orifícios, um tipo de ramificação de memória nos anéis de ferrite.
Também não esqueci a pneumonia - meu amigo Anton está envolvido na natureza. experimentos, mas mais sobre isso na próxima vez.
... deixando as seguintes imperfeições. Vou resolver parte do problema do festival no final de maio, parte - não:
- Um novo cartão de memória no qual apenas os chips de RAM e seus chicotes estão instalados. Há uma placa de circuito para o cartão de memória, a placa de circuito ainda não está divorciada. Em casa, será muito preguiçoso fazê-lo (uma maneira bidirecional bastante densa); portanto, incluirei esta placa na ordem em que encomendar placas para alguns outros projetos - um relógio mecânico em um relé e um pneumoscópio.
- Juntamente com a nova placa de memória, virão indicadores de discagem, hardware normal de exibição de terminais e lógica independente para atualizar o painel de LED.
- O programador, ou melhor, o desenvolvimento de firmware para ele. Em geral, se você possui um cartão de memória antigo, ele é redundante, mas como o conector de programação está disponível, você já pode carregar o programa.
- A lógica do tempo. Aqui estou eu completamente preguiçoso, porque literalmente amarrar 3 módulos lógicos. Definitivamente vou fazer isso no festival no final de maio.
- Instruções de leitura do console. Está ligado à lógica do tempo (em operação síncrona, o computador deve parar a operação e aguardar a chegada dos dados).
- Envie uma solicitação ao Guinness Book of Records ... Como o processador de revezamento mais rápido e, ao mesmo tempo, a leitura mais lenta. 16 milliFlops não é para você “enfiar um casaco de pele na cueca” (dos comentários no youtube).

Toda a documentação no computador de retransmissão está no
repositório no GitHub , e você pode monitorar seu status em qualquer rede social usando os links no meu perfil.
UPD: Eu me recusei a participar do festival.
E, no entanto, de 25 a 26 de maio, em Moscou, no território da Fábrica de Pão, será realizado o primeiro festival de produções artesanais e antifactory da cultura DIY. Estarei presente lá com um computador de retransmissão e também trarei um controlador de retransmissão para autowater . A entrada para o evento é gratuita, então você estará em Moscou hoje em dia - não perca a chance de ver meu monstro de revezamento ao vivo. Se eu o trazer sãos e salvos, definitivamente o demonstrarei no trabalho.