Estou lendo o livro Os Elementos dos Sistemas de Computação: Construindo um Computador Moderno a partir dos Primeiros Princípios , que contém projetos que abrangem a construção de um computador a partir de portas booleanas até aplicativos de alto nível (nessa ordem). O projeto atual no qual estou trabalhando é escrever um assembler usando uma linguagem de alto nível de minha escolha, para traduzir do código de montagem Hack para o código da máquina Hack (Hack é o nome da plataforma de hardware criada nos capítulos anteriores). Embora o hardware tenha sido todo construído em um simulador, tentei fingir que estou realmente construindo cada nível usando apenas as ferramentas disponíveis para mim naquele momento do processo real.
Dito isto, me fez pensar. Usar uma linguagem de alto nível para escrever meu assembler é certamente conveniente, mas para o primeiro assembler já escrito (ou seja, na história), não seria necessário escrever em código de máquina, já que era tudo o que existia na época?
E uma pergunta correlata ... e hoje? Se surgir uma nova arquitetura de CPU, com um novo conjunto de instruções e uma nova sintaxe de montagem, como o montador seria construído? Suponho que você ainda possa usar uma linguagem de alto nível existente para gerar binários para o programa assembler, pois se você conhece a sintaxe das linguagens assembly e de máquina para sua nova plataforma, a tarefa de escrever o assembler é realmente apenas um tarefa de análise de texto e não está inerentemente relacionada a essa plataforma (ou seja, precisa ser escrita na linguagem de máquina dessa plataforma) ... essa é a razão pela qual sou capaz de "trapacear" ao escrever meu Hack assembler em 2012 e usar alguns recursos pré-existentes linguagem de alto nível para me ajudar.
Respostas:
Não necessariamente. Obviamente, a primeira versão v0.00 do assembler deve ter sido escrita em código de máquina, mas não seria suficientemente poderoso para ser chamado de assembler. Ele não suporta nem metade dos recursos de um assembler "real", mas seria suficiente escrever a próxima versão de si mesmo. Em seguida, você pode reescrever v0.00 no subconjunto da linguagem assembly, chamá-lo v0.01, usá-lo para criar o próximo conjunto de recursos do seu assembler v0.02 e, em seguida, usar v0.02 para criar v0.03 e assim por diante, até chegar à v1.00. Como resultado, apenas a primeira versão estará no código da máquina; a primeira versão lançada estará na linguagem assembly.
Inicializei o desenvolvimento de um compilador de linguagem de modelo usando esse truque. Minha versão inicial estava usando
printf
instruções, mas a primeira versão que usei na minha empresa estava usando o próprio processador de modelo que estava processando. A fase de inicialização durou menos de quatro horas: assim que meu processador conseguiu produzir uma saída pouco útil, reescrevi-a em seu próprio idioma, compilei e joguei fora a versão sem modelo.fonte
diff
o gerador de código atual para verificar se a parte do código gerada não mudou de maneira inesperada, substituir o código em vigor e executando-o mais uma vez para finalizar o ciclo.Segundo a Wikipedia, a primeira linguagem assembler / assembly já foi implementada para o IBM 701 por Nathaniel Rochester . (As datas são um pouco incertas com relação ao artigo da Wikipedia. Ele afirma que Rochester ingressou na IBM em 1948, mas outra página da Wikipedia afirma que o 701 foi anunciado publicamente em 1952. E esta página da IBM afirma que "[um] design atual começou em fevereiro 1 de 1951 e foi concluída um ano depois " .)
No entanto, "Montadores e carregadores" de David Salomon afirma (na página 7) que o EDSAC também tinha um montador:
Supondo que aceitamos que "Pedidos Iniciais" tenha precedência, temos evidências claras de que o primeiro assembler foi implementado no código de máquina.
Esse padrão (escrever os montadores iniciais em código de máquina) teria sido a norma nos anos 50. No entanto, de acordo com a Wikipedia , "[a] ssemblers foram as primeiras ferramentas de linguagem a se autoinicializarem". Consulte também esta seção, que explica como um código de máquina escrito por um assembler primordial foi usado para inicializar um assembler mais avançado que foi codificado na linguagem assembly.
Atualmente, os montadores e compiladores são escritos em linguagens de nível superior, e um montador ou compilador para uma nova arquitetura de máquina é normalmente desenvolvido em uma arquitetura diferente e compilado de forma cruzada.
(FWIW - escrever e depurar programas não triviais no código de máquina é um processo extremamente trabalhoso. Alguém que desenvolva um assembler em código de máquina provavelmente inicializaria em um assembler escrito no assembler o mais rápido possível.)
Esta página da Wikipedia sobre compiladores e montadores de inicialização vale a pena ler ... se tudo isso é desconcertante para você.
fonte
Presumo que os primeiros montadores foram escritos em código de máquina, porque, como você diz, nada mais estava disponível naquela época.
Hoje, no entanto, quando uma nova arquitetura de CPU é lançada, usamos o que é conhecido como Cross-Compiler , que é um compilador que produz código de máquina não para a arquitetura em que está sendo executado, mas para uma arquitetura diferente.
(De fato, como tenho certeza de que você descobrirá mais adiante no livro que está lendo, não há absolutamente nada que torne um compilador inerentemente mais adequado para produzir código de máquina para a arquitetura na qual está sendo executado do que em qualquer outro outra arquitetura. É apenas uma questão de qual arquitetura você, como criador do compilador, irá segmentar.)
Portanto, hoje é possível (pelo menos em teoria) criar uma arquitetura totalmente nova e ter compiladores de linguagem de alto nível em execução nativamente (compilados em outras arquiteturas usando compiladores cruzados) antes mesmo de você ter um assembler para essa arquitetura.
fonte
No início, a "montagem" foi escrita em papel e depois "compilada" manualmente em cartões perfurados.
Meu avô estava trabalhando com um ZRA1 (desculpe, a página existe apenas em alemão, mas a tradução do Google está correta até o ponto em que você pode realmente entender os fatos mais importantes: D).
O modus operandi era escrever seu código no papel em uma espécie de linguagem assembly e a secretária faria a transcrição para perfurar cartões, depois passava-os para o operador e o resultado seria devolvido na manhã seguinte.
Tudo isso foi antes dos programadores se darem ao luxo de inserir dados através de um teclado e visualizá-los em uma tela.
fonte
É difícil ter certeza sobre o muito primeira montador (difícil até mesmo definir o que era). Anos atrás, quando escrevi alguns montadores para máquinas que não tinham montadores, ainda escrevi o código na linguagem assembly. Então, depois de ter uma seção do código razoavelmente completa, eu a traduzi manualmente em código de máquina. Essas ainda eram duas fases completamente separadas - quando eu estava escrevendo o código, eu não estava trabalhando nem pensando no nível do código da máquina.
Devo acrescentar que, em alguns casos, fui um passo além: escrevi a maior parte do código em uma linguagem assembly que achei mais fácil de usar e depois escrevi um pequeno kernel (mais ou menos o que chamaríamos de máquina virtual) interpretar isso no processador de destino. Isso era mortalmente lento (especialmente em um processador de 8 MHz e 1 MHz), mas isso não importava muito, pois normalmente era executado apenas uma vez (ou no máximo algumas vezes).
fonte
Você não precisa de um assembler para montar manualmente o código da linguagem assembly no código da máquina. Assim como você não precisa de um editor para escrever o código da linguagem assembly.
Uma perspectiva histórica
Os primeiros montadores provavelmente foram escritos em linguagem assembly e depois montados manualmente em código de máquina. Mesmo que o processador não possuísse uma 'linguagem assembly' oficial, os programadores provavelmente faziam a maior parte do trabalho de programação usando algum tipo de pseudo-código antes de traduzir esse código nas instruções da máquina.
Mesmo nos primeiros dias da computação , os programadores escreviam programas em uma espécie de notação simbólica e os traduziam em código de máquina antes de alimentá-lo em seu computador. No caso de Augusta Ada King, ela precisaria transformá-los em cartões perfurados para o Analytical Engine de Babbage , mas, infelizmente, nunca foi construído.
Experiência pessoal
O primeiro computador que eu possuía era um Sinclair ZX81 (Timex 1000 nos EUA). A parte de trás do manual tinha todas as informações necessárias para traduzir a linguagem de montagem do Z80 em código de máquina (inclusive incluindo todos os códigos de modo de índice estranhos que o Z80 tinha).
Eu escreveria um programa (em papel) em linguagem assembly e executaria a seco o código. Quando eu estava feliz que meu programa estava livre de erros, procurava cada instrução no final do manual, traduzia em código de máquina e escrevia o código de máquina também no papel. Finalmente, digitei todas as instruções de código da máquina no meu ZX81 antes de salvá-lo em fita e tentar executá-lo.
Se não funcionasse, eu verificaria o conjunto da minha mão e, se alguma tradução estivesse incorreta, corrigiria os bytes carregados da fita antes de salvá-la novamente e tentar novamente executar o programa.
Por experiência, posso lhe dizer que é muito mais fácil depurar seu código se ele estiver escrito em linguagem assembly do que em código de máquina - daí a popularidade dos desmontadores. Mesmo se você não tiver um montador, a montagem manual é menos propensa a erros do que tentar escrever o código da máquina diretamente, embora eu ache que um programador real como Mel possa discordar. * 8 ')
fonte
Não há diferença então ou agora. Como você deseja inventar uma nova linguagem de programação, escolha uma das linguagens disponíveis hoje para criar o primeiro compilador. durante algum período, se for um objetivo do projeto, você criará um compilador nesse idioma e ele poderá se auto-hospedar.
Se tudo o que você tinha era lápis e papel e alguns comutadores ou cartões perfurados como interface do usuário para o primeiro ou o próximo conjunto de instruções novo, você usava um ou todos os itens disponíveis. Você poderia muito bem ter escrito uma linguagem assembly, no papel e, em seguida, usado um assembler, você, para convertê-lo em código de máquina, talvez em octal, e em algum momento que entrou na interface da máquina.
Quando um novo conjunto de instruções é inventado hoje, não é diferente, dependendo da empresa / indivíduos, práticas, etc. é bem provável que o engenheiro de hardware provavelmente programando em verilog ou vhdl, grave os primeiros programas de teste manualmente no código da máquina (provavelmente em hexadecimal ou binário). dependendo do progresso das equipes de software, elas podem mudar muito rapidamente ou não por muito tempo para a linguagem assembly e, em seguida, para um compilador.
As primeiras máquinas de computação não eram de uso geral que você poderia usar para criar montadores e compiladores. Você os programou movendo alguns fios entre a saída do alu anterior e a entrada do próximo. Eventualmente, você tinha um processador de propósito geral, de modo que você poderia escrever um assembler em montagem, montá-lo manualmente, alimentá-lo como código de máquina e usá-lo para analisar ebcdic, ascii etc. e, em seguida, auto-hospedar. armazene o binário em algumas mídias que você possa ler / carregar posteriormente, sem ter que manter os interruptores para o código da máquina de alimentação manual.
Pense em cartões perfurados e fita de papel. Em vez de acionar os interruptores, você definitivamente poderia criar uma máquina completamente mecânica, um dispositivo de economia de trabalho, que criou a mídia que o computador leria. Em vez de ter que digitar os bits do código da máquina com interruptores como um altair, você poderia alimentar fita de papel ou cartões perfurados (usando algo mecânico, não acionado pelo processador, que alimentava a memória ou o processador, OU usando um pequeno carregador de inicialização escrito por código de máquina). Essa não foi uma má idéia, porque você pode criar algo, dirigido pelo computador, que também pode produzir mecanicamente as fitas de papel ou cartões perfurados e, em seguida, alimentá-los novamente. Duas fontes de cartões perfurados, o dispositivo mecânico de economia de trabalho que não é baseado em computador e a máquina acionada por computador. ambos produzem os "binários" para o computador.
fonte
Há um ou dois casos no zoológico de Brooks, onde ele disse algo como "os mnemônicos são nossa invenção, o designer simplesmente usou o código numérico ou o caractere cujo código era o código secreto", então havia máquinas para as quais não havia sequer linguagem assembly.
A entrada de programas termina a depuração no painel frontal (para aqueles que não fizeram isso, foi uma maneira de configurar a memória, você configurou alguns comutadores para o endereço, outros para o valor e pressionou um botão ou outro botão para leia o valor) era comum muito mais tarde. Alguns veteranos se gabam de que ainda seriam capazes de inserir o código de inicialização para máquinas usadas extensivamente.
A dificuldade de escrever diretamente o código da máquina e ler os programas do despejo de memória depende bastante da linguagem da máquina, alguns deles são relativamente fáceis (a parte mais difícil é rastrear os endereços), x86 é um dos piores.
fonte
Eu construí um computador em 1975. Ele era muito avançado em relação ao seu Altair contemporâneo, porque tinha um 'monitor rom' que me permitia entrar nos programas digitando o código da máquina em hexadecimal e visualizando esse código em um monitor de vídeo, onde, como no Para cada instrução de máquina, era necessário digitar um pouco de cada vez, usando uma linha de interruptores.
Então, sim, nos primeiros dias dos computadores e, novamente, nos primeiros dias dos computadores pessoais, as pessoas escreviam aplicativos em código de máquina.
fonte
Uma anedota:
Quando aprendi a linguagem assembly, na Apple] [, havia um programa incluído na ROM chamado micro-assembler. Ele fez a tradução imediata das instruções de montagem em bytes, conforme você as inseria. Isso significa que não havia etiquetas - se você quiser pular ou carregar, precisará calcular as compensações por conta própria. Era muito mais fácil do que pesquisar os layouts de instruções e inserir valores hexadecimais.
Sem dúvida, os verdadeiros montadores foram escritos usando o micro-montador, ou algum outro ambiente não completamente completo.
fonte