I know there are a lot of threads regarding this topic, but I can't find the answer for this precise topic:

First of all, with the "first assembler" I mean the program that translates, let's say, the instruction "mov" to the specific machine code the ALU understands, 1100111 or whatever other binary number. There's some gap between those two steps that I can't find answers for.

I understand the process is something like: you have a cpu chip built with an specific micro architecture that implements N instructions. Each instruction is accessed internally in the ALU with a binary number or opcode (000 mov, 001 add, etc) At some point of history, instructions were loaded into the CPU using punched cards, tapes, etc.

But then, you want to raise the level of abstraction and needs an assembler to program in a higher language instead of opcodes, and this is exactly where I'm missing something.

At this point, I guess some bootstrapping is used to go from opcodes to assembler, but how? How do you write the assembler v0.00 for a given brand new cpu? Is there any chip hardcoding those instructions, maybe the first assembler is hardware based?

In "Assembler and Loaders", it seems the first assembler was created using a ROM, hardlinking telephone selectors to memory addresses.

"One of the first stored program computers was the EDSAC (Electronic Delay Storage Automatic Calculator) developed at Cambridge University in 1949 by Maurice Wilkes and W. Renwick. From its very first days the EDSAC had an assembler, called Initial Orders. It was implemented in a read-only memory formed from a set of rotary telephone selectors, and it accepted symbolic instructions. Each instruction consisted of a one letter mnemonic, a decimal address, and a third field that was a letter. The third field caused one of 12 constants preset by the programmer to be added to the address at assembly time."

  • 4
    Possible duplicate of How exactly do we go from Binary/Hex to Assembly Instruction sets? – gnat Feb 18 '19 at 11:40
  • 2
    Could you clarify whether the question is about how the first assembler ever was created or how an assembler to a new CPU can be written nowadays? – COME FROM Feb 18 '19 at 11:59
  • 2
    An assembler is just a computer program like any other computer program. It takes some input, does "stuff" with that input, and produces some output. It is written like any other computer program. – Jörg W Mittag Feb 18 '19 at 13:20
  • People used a lot more machine code in the old days. Many machines in the days of yore had no ROM at all, so initial bootstrapping code had to be entered through the front panel switches (which computers today no longer have..) – Erik Eidt Feb 18 '19 at 15:51

You write the assembler-program in machine code, that is, as a series of numbers. Maybe you write the code in assembler on a piece of paper, then by hand translate each instruction into the corresponding machine code number.

  • 1
    The real trick is in loading the code in memory in order to execute it! (Been there, done that with hand entering code by switches) – Peter M Feb 18 '19 at 17:52

The question reminds me of an anecdote told about John von Neumann:

Donald Gilles, one of von Neumann's students at Princeton, and later a faculty member at the University of Illinois, recalled that the graduate students were being "used" to hand-assemble programs into binary for their early machine (probably the IAS machine). He took time out to build an assembler, but when von Neumann found out about it he was very angry, saying (paraphrased), "It is a waste of a valuable scientific computing instrument to use it to do clerical work."

So in the early days of computing, translating into machine code by hand was such a routine practice that it was disputed that tools were even needed.

Similarly, in the early days of microcomputers, it was not uncommon for programmers to have memorized the hex values for most instructions (even in cases where they had assemblers, the debuggers available did not always have disassemblers).

Nowadays, there's generally no reason not to bootstrap with a cross assembler.

  • 1
    Similarly, Niklaus Wirth wrote the first Oberon compiler in Oberon, then let his students "compile" it to Fortran, so that it could be compiled by the Fortran compiler, then compile itself. He did that because when he first started to write the compiler in Fortran he found that he had the subconscious tendency to leave features out of the language if it turned out they were hard to implement in Fortran. Therefore, he decided to eliminate Fortran from the equation and make sure he designed the language based on what features it needed and not which ones are easy to implement. – Jörg W Mittag Feb 19 '19 at 11:08
  • 1
    @JörgWMittag I believe you may be confusing Oberon with some different language designed by Wirth. Oberon was bootstrapped with a compiler written in Modula-2 (as one would expect, this being Wirth's previous language design): inf.ethz.ch/personal/wirth/Articles/Modula-Oberon-June.doc – microtherion Feb 19 '19 at 22:58

A primitive assembler just isn't that hard to write.  I've written a simple assembler/disassembler in Excel, for example — just a series of lookups really.

All you need is a very simple parser for the each line, a simple dictionary for labels, and a list of forward references that require later fixups.

There are also many possibilities for short cuts, i.e. requiring the opcode name to uniquely identify the expected arguments, minimal or no pseudo instructions, no arithmetic expressions, etc..

Making it easier is that early machines had fewer instructions and simpler addressing modes. The case you're citing even uses one letter opcodes, with what looks like a fixed argument set.

The initial assembler's code doesn't even have to be efficient, or robust to size of input, so can use fixed sized arrays (that would run out of space with input too large), and linear searches (instead of hash tables or linked lists even), for example.  Error handling and messages don't have to be good, either.  Once you've got the basic mnemonics you have basically bootstrapped the assembler.

How do you write the assembler v0.00 for a given brand new cpu?

This is relatively easy, you just use an older machine that already has a programming language.

  • 1
    In short, you don't need a program to assemble any other program. You only need a program that can assemble an assembler. – John Dvorak Feb 18 '19 at 16:15
  • 1
    @JohnDvorak, exactly, just like the initial boot loader needs only to load the next boot loader, not necessarily run any other program. (On the PDP-8 the boot loader you toggled into the front panel brought up the paper tape drive, which loaded another loader that knew about the disc, and that one loaded the OS from the disc.) – Erik Eidt Feb 18 '19 at 16:18

Writing an assembler at any point in time is the same as writing any other program. If you were dealing with a new chip with a completely novel architecture that wasn't binary compatible with any other chip, then you would use that chip's specification to create a mapping from the lines of the high-level language to the lines of machine code. Otherwise, you would base your program on the assembler for some similar chip.

This mapping program could be implemented in any language on any computer. People have done it in Excel, and I've done it in Python using regular expressions. In the past, they would've written it in the tools of their time punch cards, switches, hammer and chisel, or whatever else.

The chip's architecture manual describes the processor's registers, supported operations, opcodes, etc... The tasks of writing an assembler is the task of translating a high-level description of an algorithm into a description that is compatible with what is described in the manual.

I don't envy this task at all, lol. And if you look at the size of that manual, you will get a sense of why completely new architectures don't come out very often.


Slightly off topic but the software used in the Apollo moon missions was "knitted" by hand.

Hundreds of tiny magnetised ferrous rings were threaded together the presence of a ring at a particular location interpreted as 1 the absence as zero.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.