You get a piece of graph paper and do exactly what the assembler would do by hand.
First you write the program out in assembly language instructions then you convert individual instructions and keep track of the program counter on the left hand side, you will have to leave space for the operands of forward jumps because you don't know what that address will be be. Then you go back and fill them in. Easy-peasy.
As someone who did this a lot on various machines back in the day, I'm tempted to say "very carefully and methodically" (which is the truth). The more complete answer is what PaulHoule said. It's called "hand assembly".
In any case, none of this was particularly difficult or unusual, just a bit tedious. At least, the part where you enter hex codes is.
Even more fun was before microcomputers. On a few minicomputers and mainframes, you would occasionally have to enter short programs in binary using switches on the front panel.
During hand assembly? What I'd do is use graph paper and leave some rows blank in case I'd need to add stuff, and would occasionally redo specific pages if I ran out of room, or if I needed to make changes that were complex enough that marking them up would lead to an unreadable mess of scribbles.
But the hand assembly part was close to the end of the process. Initially, I'd just write assembly on normal paper and not worry about converting anything to op codes until I considered the program complete enough to assemble and try running it. During that initial phase, I wouldn't worry about leaving space or anything because it was all going to be rewritten multiple times anyway.
Yes, I've known people who did that as well. Anyone can do it with simple programs and enough experience with the task, but some could do that with complex programs. They could even read hex codes directly and disassemble in their minds.
I, like most programmers, never achieved that level of brilliance.
Not as a rule. They're entering op codes directly into memory. Occasionally they may pad something with a few NOPs, but that was wasting a constrained resource so it was very rare.
What they did was work out the code in their minds before entering anything into the computer.
I started my career as a field engineer (basically a computer mechanic) on mainframes and minicomputers 47 years ago. For the first 13 years, almost every computer I worked on had front panel switches and lights which was great for writing and debugging tiny diagnostic programs. I wrote those diags directly in machine code because I had the CPU instruction manuals, no access to an assembler, and a fair amount of free time when I worked a midnight shift on call. I'd sit at a desk, writing the machine code on lined paper because the sites I worked at rarely had graph paper in the supply cabinet. At first I had to look up the op codes for the instructions I wanted but I was able to memorize the ones I used most often which made it a quicker process. The fun part was using the toggle switches to enter those instructions and finally to start it running.
After 6 years of being a field engineer and writing exclusively in machine language, I made the switch to being a systems analyst which gave me access to an assembler. That seemed easy after having to calculate relative jumps/subroutine calls for so long.
This is what I loved about the PDP-11 series. The instruction opcodes were so
painfully obvious you could read them in octal.
I would use a hand punch to
create holes in paper tape that was the program. (Just a metal block with holes
drilled and a metal dowel to punch the tape).
"Patching the tape" involved finding a section of code that could be "overpunched"
to be a jump instruction to the current end of tape where you could punch in a subroutine and a return statement.
If all else failed you'd create a "patch tape" that was read after the original
tape and overwrote memory locations.
It was all very convenient since you could "single step" the program from the
front panel and watch the registers change.
Life got really sweet when the new teletype had a reader/punch.
10 comments
[ 2.8 ms ] story [ 36.1 ms ] threadFirst you write the program out in assembly language instructions then you convert individual instructions and keep track of the program counter on the left hand side, you will have to leave space for the operands of forward jumps because you don't know what that address will be be. Then you go back and fill them in. Easy-peasy.
There is a nice image of such a notebook here
https://www.quora.com/What-is-the-real-purpose-of-graph-pape...
which looks exactly like the listing output of an assembler because it is.
In any case, none of this was particularly difficult or unusual, just a bit tedious. At least, the part where you enter hex codes is.
Even more fun was before microcomputers. On a few minicomputers and mainframes, you would occasionally have to enter short programs in binary using switches on the front panel.
But the hand assembly part was close to the end of the process. Initially, I'd just write assembly on normal paper and not worry about converting anything to op codes until I considered the program complete enough to assemble and try running it. During that initial phase, I wouldn't worry about leaving space or anything because it was all going to be rewritten multiple times anyway.
I, like most programmers, never achieved that level of brilliance.
What they did was work out the code in their minds before entering anything into the computer.
After 6 years of being a field engineer and writing exclusively in machine language, I made the switch to being a systems analyst which gave me access to an assembler. That seemed easy after having to calculate relative jumps/subroutine calls for so long.
I would use a hand punch to create holes in paper tape that was the program. (Just a metal block with holes drilled and a metal dowel to punch the tape).
"Patching the tape" involved finding a section of code that could be "overpunched" to be a jump instruction to the current end of tape where you could punch in a subroutine and a return statement.
If all else failed you'd create a "patch tape" that was read after the original tape and overwrote memory locations.
It was all very convenient since you could "single step" the program from the front panel and watch the registers change.
Life got really sweet when the new teletype had a reader/punch.
Good times.