Estoy leyendo el libro The Elements of Computing Systems: Building a Modern Computer from First Principles , que contiene proyectos que abarcan la construcción de una computadora desde puertas booleanas hasta aplicaciones de alto nivel (en ese orden). El proyecto actual en el que estoy trabajando es escribir un ensamblador usando un lenguaje de alto nivel de mi elección, para traducir del código de ensamblaje de Hack al código de máquina de Hack (Hack es el nombre de la plataforma de hardware construida en los capítulos anteriores). Aunque todo el hardware se ha construido en un simulador, he tratado de fingir que realmente estoy construyendo cada nivel usando solo las herramientas disponibles para mí en ese punto del proceso real.
Dicho eso, me hizo pensar. Usar un lenguaje de alto nivel para escribir mi ensamblador es ciertamente conveniente, pero para el primer ensamblador escrito (es decir, en la historia), ¿no necesitaría estar escrito en código de máquina, ya que eso era todo lo que existía en ese momento?
Y una pregunta correlacionada ... ¿qué tal hoy? Si sale una nueva arquitectura de CPU, con un nuevo conjunto de instrucciones y una nueva sintaxis de ensamblaje, ¿cómo se construiría el ensamblador? Supongo que aún podría usar un lenguaje de alto nivel existente para generar binarios para el programa ensamblador, ya que si conoce la sintaxis de los lenguajes ensamblador y de máquina para su nueva plataforma, entonces la tarea de escribir el ensamblador es realmente solo una tarea de análisis de texto y no está inherentemente relacionada con esa plataforma (es decir, necesita ser escrita en el lenguaje de máquina de esa plataforma) ... esa es la razón por la que puedo "engañar" mientras escribo mi ensamblador Hack en 2012, y utilizo algunos preexistentes lenguaje de alto nivel para ayudarme.
Respuestas:
No necesariamente. Por supuesto, la primera versión v0.00 del ensamblador debe haber sido escrita en código máquina, pero no sería lo suficientemente potente como para llamarse ensamblador. No admitiría ni siquiera la mitad de las características de un ensamblador "real", pero sería suficiente para escribir la próxima versión de sí mismo. Luego, podría volver a escribir v0.00 en el subconjunto del lenguaje ensamblador, llamarlo v0.01, usarlo para construir el siguiente conjunto de características de su ensamblador v0.02, luego usar v0.02 para construir v0.03, y etc., hasta llegar a v1.00. Como resultado, solo la primera versión estará en código máquina; la primera versión lanzada estará en lenguaje ensamblador.
He desarrollado un programa de compilación de lenguaje de plantillas usando este truco. Mi versión inicial estaba usando
printf
declaraciones, pero la primera versión que utilicé en mi compañía estaba usando el procesador de plantillas que estaba procesando. La fase de arranque duró menos de cuatro horas: tan pronto como mi procesador pudo producir resultados apenas útiles, lo reescribí en su propio idioma, compilé y tiré la versión sin plantilla.fuente
diff
contra el generador de código actual para ver que la porción generada del código no cambiaba de manera inesperada, reemplazar el código en su lugar, y ejecutándolo una vez más para terminar el ciclo.Según Wikipedia, Nathaniel Rochester implementó el primer lenguaje ensamblador / ensamblador para IBM 701 . (Las fechas son un poco inciertas en el artículo de Wikipedia. Establece que Rochester se unió a IBM en 1948, pero otra página de Wikipedia dice que el 701 se anunció públicamente en 1952. Y esta página de IBM afirma que "[el diseño actual comenzó en febrero 1, 1951 y se completó un año después " .)
Sin embargo, "Ensambladores y cargadores" de David Salomon afirma (en la página 7) que EDSAC también tenía un ensamblador:
Suponiendo que aceptamos que "Órdenes iniciales" tiene prioridad, tenemos evidencia clara de que el primer ensamblador se implementó en código máquina.
Este patrón (escribir los ensambladores iniciales en código de máquina) habría sido la norma en la década de 1950. Sin embargo, de acuerdo con Wikipedia , "[a] ssemblers fueron las primeras herramientas de lenguaje para iniciarse". Consulte también esta sección que explica cómo se utilizó un ensamblador primordial escrito con código de máquina para arrancar un ensamblador más avanzado que estaba codificado en lenguaje ensamblador.
En la actualidad, los ensambladores y compiladores están escritos en lenguajes de nivel superior, y un ensamblador o compilador para una nueva arquitectura de máquina generalmente se desarrolla en una arquitectura diferente y se compila de forma cruzada.
(FWIW: escribir y depurar programas no triviales en código máquina es un proceso extremadamente laborioso. Alguien que desarrolle un ensamblador en código máquina probablemente arrancaría a un ensamblador escrito en ensamblador lo antes posible).
Vale la pena leer esta página de Wikipedia sobre compiladores y ensambladores de arranque ... si esto es desconcertante para usted.
fuente
Supongo que los primeros ensambladores se escribieron en código máquina, porque como usted dice, no había nada más disponible en ese momento.
Hoy, sin embargo, cuando sale una nueva arquitectura de CPU, usamos lo que se conoce como un compilador cruzado , que es un compilador que produce código de máquina no para la arquitectura en la que se está ejecutando, sino para una arquitectura diferente.
(De hecho, como estoy seguro de que descubrirá más adelante en el libro que está leyendo, no hay absolutamente nada que haga que un compilador sea inherentemente más adecuado para producir código de máquina para la arquitectura en la que se está ejecutando que en cualquier otro otra arquitectura. Es solo una cuestión de a qué arquitectura se dirigirá usted, como creador del compilador).
Por lo tanto, hoy es incluso posible (al menos en teoría) crear una arquitectura completamente nueva y tener compiladores de lenguaje de alto nivel que se ejecuten de forma nativa (compilados en otras arquitecturas que usan compiladores cruzados) incluso antes de tener un ensamblador para esa arquitectura.
fuente
Al principio, el "ensamblaje" se escribió en papel y luego se "compiló" manualmente en tarjetas perforadas.
Mi abuelo estaba trabajando con un ZRA1 (lo siento, la página solo existe en alemán, pero la traducción de Google está bien hasta el punto de que realmente puedes recoger los hechos más importantes: D).
El modus operandi era escribir su código en papel en una especie de lenguaje ensamblador y la secretaria realmente haría la transcripción a las tarjetas perforadas, luego las pasaría al operador y el resultado se devolvería la mañana siguiente.
Todo esto fue esencialmente antes de que los programadores tuvieran el lujo de ingresar datos a través de un teclado y verlos en una pantalla.
fuente
Es difícil estar seguro acerca de la muy primera ensamblador (difícil de definir, incluso lo que era). Hace años, cuando escribí algunos ensambladores para máquinas que carecían de ensambladores, todavía escribía el código en lenguaje ensamblador. Luego, después de tener una sección de código razonablemente completa, la traduje al código de la máquina a mano. Sin embargo, todavía eran dos fases completamente separadas: cuando estaba escribiendo el código, no estaba trabajando o pensando a nivel de código de máquina.
Debo agregar que en algunos casos, fui un paso más allá: escribí la mayor parte del código en un lenguaje ensamblador que encontré más fácil de usar, luego escribí un kernel pequeño (más o menos lo que ahora llamaríamos una máquina virtual) interpretar eso en el procesador de destino. Eso fue mortalmente lento (especialmente en un procesador de 1 MHz y 8 bits), pero eso no importó mucho, ya que normalmente solo se ejecutó una vez (o como máximo, algunas veces).
fuente
No necesita un ensamblador para ensamblar a mano el código del lenguaje ensamblador en el código de la máquina. Del mismo modo que no necesita un editor para escribir código en lenguaje ensamblador.
Una perspectiva historica
Los primeros ensambladores probablemente fueron escritos en lenguaje ensamblador y luego ensamblados a mano en código máquina. Incluso si el procesador no tenía un 'lenguaje ensamblador' oficial, entonces los programadores probablemente hicieron la mayor parte del trabajo de programación utilizando algún tipo de pseudocódigo antes de traducir ese código a las instrucciones de la máquina.
Incluso en los primeros días de la informática , los programadores escribieron programas en una especie de notación simbólica y los tradujeron al código de la máquina antes de introducirlos en su computadora. En el caso de Augusta Ada King, ella habría necesitado traducirlos en tarjetas perforadas para el motor analítico de Babbage , pero desgraciadamente nunca se construyó.
Experiencia personal
La primera computadora que tuve fue una Sinclair ZX81 (Timex 1000 en los EE. UU.). La parte posterior del manual tenía toda la información que necesitaba para traducir Z80 lenguaje ensamblador en código máquina (incluso incluido, en todas las modo de índice extraños códigos de operación del Z80 tenía).
Escribiría un programa (en papel) en lenguaje ensamblador y ejecutaría el código en seco. Cuando estaba feliz de que mi programa no tuviera errores, buscaba cada instrucción en la parte posterior del manual, la traducía al código de la máquina y también escribía el código de la máquina en el papel. Finalmente, escribiría todas las instrucciones del código de máquina en mi ZX81 antes de guardarlo en cinta e intentar ejecutarlo.
Si no funcionaba, volvería a verificar el ensamblaje de mi mano y, si alguna traducción fuera incorrecta, parchearía los bytes cargados de la cinta antes de volver a guardarla e intentar nuevamente ejecutar el programa.
Por experiencia, puedo decirle que es mucho más fácil depurar su código si está escrito en lenguaje ensamblador que en código máquina, de ahí la popularidad de los desensambladores. Incluso si no tiene un ensamblador, el ensamblaje manual es menos propenso a errores que intentar escribir el código de la máquina directamente, aunque supongo que un programador real como Mel podría estar en desacuerdo. * 8 ')
fuente
No hay diferencia entonces o ahora. Si quieres inventar un nuevo lenguaje de programación, eliges uno de los idiomas disponibles para crear el primer compilador. durante un período de tiempo, si es un objetivo del proyecto, crea un compilador en ese idioma y luego puede autohospedarse.
Si todo lo que tenía era lápiz y papel y algunos interruptores o tarjetas perforadas como interfaz de usuario para el primer o el siguiente conjunto de instrucciones nuevo, usted utilizó uno o todos los elementos disponibles para usted. Muy bien podría haber escrito un lenguaje ensamblador, en papel, y luego haber usado un ensamblador, usted, para convertirlo en código de máquina, tal vez en octal, y luego, en algún momento, que entró en la interfaz de la máquina.
Cuando se inventa hoy un nuevo conjunto de instrucciones, no es diferente, dependiendo de la compañía / individuos, prácticas, etc. (probablemente en hexadecimal o binario). Dependiendo del progreso de los equipos de software, pueden cambiar muy rápidamente o no durante mucho tiempo al lenguaje ensamblador y luego a un compilador.
Las primeras máquinas de cómputo no eran máquinas de uso general que se pudieran usar para crear ensambladores y compiladores. Los programó moviendo algunos cables entre la salida del alu anterior a la entrada del siguiente. Finalmente, tenía un procesador de uso general para poder escribir un ensamblador en ensamblaje, ensamblarlo a mano, alimentarlo como código de máquina, luego usarlo para analizar ebcdic, ascii, etc. y luego auto-host. almacene el binario en algún medio que luego pueda leer / cargar sin tener que mantener los interruptores activados al código de la máquina de alimentación manual.
Piense en tarjetas perforadas y cinta de papel. En lugar de accionar los interruptores, definitivamente podría hacer una máquina completamente mecánica, un dispositivo que ahorre trabajo, que creó los medios que leería la computadora. En lugar de tener que ingresar los bits del código de la máquina con interruptores como un altair, podría alimentar con cinta de papel o tarjetas perforadas (usando algo mecánico, no controlado por el procesador, que alimentó la memoria o el procesador, O usando un pequeño cargador de arranque escrito con código de máquina). Esta no era una mala idea porque podía hacer algo, impulsado por la computadora que también podía producir mecánicamente las cintas de papel o las tarjetas perforadas, y luego alimentarlas nuevamente. Dos fuentes de tarjetas perforadas, el dispositivo mecánico de ahorro de mano de obra no basado en computadora y la máquina impulsada por computadora. ambos producen los "binarios" para la computadora.
fuente
Hay una o dos instancias en el zoológico informático de Brook donde dijo algo así como "las mnemotécnicas son nuestro invento, el diseñador simplemente usó el código de operación numérico o el personaje cuyo código era el código de operación", por lo que había máquinas para las cuales ni siquiera había un lenguaje ensamblador.
Al ingresar a los programas, finalice la depuración en el panel frontal (para aquellos que no lo han hecho, era una forma de configurar la memoria, configurar algunos interruptores en la dirección, otros en el valor y presionar un botón u otro botón para leer el valor) fue común mucho más tarde. Algunos antiguos alardean de que aún podrían ingresar el código de arranque para las máquinas que usaron ampliamente.
La dificultad de escribir directamente el código de la máquina y leer programas del volcado de memoria depende bastante del lenguaje de la máquina, algunos de ellos son relativamente fáciles (la parte más difícil es rastrear las direcciones), x86 es uno de los peores.
fuente
Construí una computadora en 1975. Era muy avanzada sobre su Altair contemporáneo, porque tenía una 'rom de monitor' que me permitía ingresar programas escribiendo el código de máquina en hexadecimal y viendo este código en un monitor de video, donde como con el En Altair, cada instrucción de máquina debía ingresarse poco a poco utilizando una fila de interruptores.
Entonces, sí, en los primeros días de las computadoras y luego nuevamente en los primeros días de las computadoras personales, las personas escribían aplicaciones en código de máquina.
fuente
Una anécdota:
Cuando aprendí el lenguaje ensamblador, en Apple] [, había un programa incluido en la ROM llamado micro ensamblador. Hizo una traducción inmediata de las instrucciones de ensamblaje a bytes, tal como las ingresó. Esto significa que no había etiquetas: si desea saltar o cargar, tenía que calcular las compensaciones usted mismo. Sin embargo, fue mucho más fácil que buscar los diseños de instrucciones e ingresar valores hexadecimales.
Sin duda, los ensambladores reales se escribieron primero usando el microensamblador, o algún otro entorno no completamente completo.
fuente