What Woz did was the default way of writing assembly language programs for owners of 8-bit computers (mostly hobbyists). You didn't have money for a second machine, so you wrote your program on paper, you entered it then tested it in situ. Mostly you got it right, as doing it on paper was slow and meant you had the opportunity to put lots of thought into it. 8-bit instruction sets were simple enough that you eventually learned the most common instructions by heart. There was a point where I could mostly translate a Z80 program from assembly to machine code from (my) memory.
Maybe that is part of the nostalgia for the 8-bit days: the practice of "slow programming"? It was relaxing, sort of like those "slow tv" shows.
My first exposure was Commodore PET computers at the high school (I'm old). Nobody had home computers then, this stuff was crazy expensive, even a floppy disk (singular!) to save your work on the shared drive (on a dolly - it could be hotplugged) was >$20 in today's money. But what you could use all you want was the line printer (a CBM 2022) and its consumables. So at the end of whatever computer room time you could scrounge (lunch, who needs lunch?) you'd print off your 3-4 page epic program to continue coding and debugging with a pencil, on the long school bus ride. This does form "slow" habits. To this day I detest autocomplete, autoindent, syntax highlighters and the like. Never did hand assemble though.
I had a Vic20 but after it was stolen was the first kid in my neighbourhood to get a disc drive with a C64. Floppys were more expensive early but I remember about $20 for a box 10 - still a lot of 80's money! Learning you could double side a disc with a hole punch (and later the nibbler tool) is one of the head-exploding moments of my computer life.
OT: others are the first times I drew graphics on the amber monitor of a PC clone and adding data to a BE database and then seeing said data on a webpage. I think my security was about the same as current-day Lovable :)
OOT: Thinking about it, I believe the pure wonder & joy came because it seemed like magic, but then you figured out how it worked which gave you an immense feeling of power and self-determination. I worry that with AI today you'll get the former and never the latter, which will have serious, long-term ramifications. I hope I'm wrong.
[−]billforsternz · 2026-11-15 Sun 00:02 UTC ·
link
Yes. My first serious program was done this way. At the start of the project (final year of EE degree, 1981) I didn't really understand what a program was, but I learned by studying the technical reference manual for the Intel 8085 CPU. It kind of seemed like magic, I can mold the functionality by storing codes in memory? Wow!
I figured out exactly what I wanted to do, wrote it out very carefully on paper, looked up all the hex codes, wrote those out very carefully, adjusted addresses etc. as needed. This took many hours spread over weeks. Then I entered the whole thing on the hex keyboard and display of a primitive development board each time I needed it, perhaps an hour or so each time (I think I only did it twice). It worked first time, because why wouldn't it if you were sufficiently meticulous about your work in a process that was very obviously very intolerant of the tiniest mistake?
I must admit my program (gather input information from some transducers, do some calculations, present some results) was likely somewhere between one and two orders of magnitude simpler than a complete Basic interpreter!
I think this comment is gold. Thanks for writing this. It feels like such a visceral description of the experience of "programming" back then. I've read a bunch of old books on programming or those that explain low level programming, but they mostly detailed the mechanics of programming, it feels like your comment captured something of the actual experience of it!
I got my first computer, a C64, when I was 14 in 1985, and wrote my 6510 assembly in paper as well.
You had to carefully calculate the address distance for a branch instruction. The release of DISMON was a revolution: suddenly the computer did all of that for you. It even supported moving pieces of code to a different address to make space for inserting more instructions somewhere!
How exactly did you "enter it" without a second computer though? Was there a simple test rig or something that you would make as an electronics project, where you would input opcodes and ascii and it would write it to a rom? Only real thing i can think of.
RE "...How exactly did you "enter it" without a second computer though...."
You would use the "monitor program" to poke hex data into memory locations, starting at a nominated RAM memory address. Needed to be done VERY CAREFULLY. one bad hex digit and your program likely crash.
After entering all the program into memory, you would use a monitor program , command to get tell the CPU to jump to a certain address and start executing a program there. OLD computer magazines often had such hex listings printed in them.
Old geek who was one of my nominal bosses when I first started had monitor he wrote that could do break points and single stepping on a Z80.
[−]holgerschurig · 2026-11-15 Sun 00:38 UTC ·
link
Can't tell it for 6502... but for Z80. Because was my first own "computer":
* a single Z80 (which was nicer than 8080, because the latter needed an extra clock IC)
* 256 bytes of static RAM
* 1 8bit D-Latch (Flipflop) with 8 LEDs
* 1 8bit D-Latch with 8 dip switches
* 2 8bit buffers that can go tristrate between the hex-thingies and the address & data bus
* 2 rotating hex thingies: you could rotate them between 0-f for data
* 2 rotating hex ones for address
Now, how did it work? I pulled nBUSRQ down (bus request). This made the Z80 go tri-state. It also made my buffers non-tristate.
Then I used 2 of the hex-thingies to set the address and 2 of them to set the data. Now I set nWR to low and that would write the entered data byte into the SRAM.
When I was done, I turned nBUSRQ back to high, so the Z80 again was the boss of the bus. And then I simply used nRESET to low to make the Z80 execute my program starting at address 0.
I did only tiny programs, like adder, some PWN/sound wave program, an traffic light simulator.
But, since I soldered this all by myself, I had no "monitor program" like the KIM-1 had. So I had to do all of that by hardware.
For later hardware like the TRS-80, the BASIC interpreter had an escape hatch: PEEK(addr), POKE addr, value, and USR1(). Basically you could read and write single bytes to RAM, and there was a magic 2-byte value which was a branch address that calling USR1() would jump into. So you could bootstrap some simple tooling that way. (I'd been writing hex machine code before I got any hardware, just pencil and graph paper, so it wasn't a big step to go from that to stuffing bytes into memory.) Of course there were tools available but actually paying for them was enough of a challenge that a lot of bootstrapping got done entirely anti-economically :-) (Once floppy drives and disk operating systems were a thing, you'd usually have a simple debugger where you could just type hex digits in, and load register values directly - so if you wanted to read raw disk sectors, you'd drop CD 75 46 18 FB somewhere, R DE track/sector, R HL where to read, R BC 0001 and then single step the code and it would read a single sector.)
(Note that while a lot of this was unjustifiable even then - my first real paying job in computers was down a step, working on a Z80-modded IMSAI so while most code was on 8" floppies, doing machine code in binary on toggle switches "just to fix something quick" was a legitimate skill :-)
The Apple II had a thing called the monitor, which was a tiny CLI program in ROM that you could invoke from the BASIC command line (CALL -151). With it you got the ability to disassemble memory (300L would spit out 6502 opcodes starting at address 768), set memory regions to sequences of hex digits (300: A9 21 20 FO FD 60 would write a tiny program on an Apple II Plus that printed an exclamation point, if my memory serves), and execute memory (300G).
With these three commands, and a working memory of the hex that corresponded to the opcodes, you could be reasonably productive writing short 6502 programs.
Fun and extremely niche fact: the typo CALL -161 jumped into the monitor, but only after the weird side effect of unhooking the sniffer that watched for DOS 3.3 commands sent via the ROM's text I/O. Not only did this make text print faster -- useful when you were visually dumping memory to the screen to find something quickly, but it also protected against accidentally destroying your disk if you unwittingly printed a sequence like ^M^DINIT HELLO^M, which would trigger the disk initialization routine.
> 300: A9 21 20 FO FD 60 would write a tiny program on an Apple II Plus that printed an exclamation point, if my memory serves.
Ancient assembly hacker tip: A JSR/RTS sequence can be simplified to a JMP. To continue your example, the bytes you provided decompile as follows (assuming Apple 2 monitor ROM at $F800):
So, you load the A register with #$21, which is the ASCII code for `!` in hexadecimal, and then call COUT1 which will output the character in the A register, printing the exclamation point. When COUT1 is finished, it will return to you using an RTS instruction, and then you'll return to your caller using another RTS instruction.
Since the call to COUT1 is a tail call, you can borrow its RTS instruction to return to your caller and save one instruction. So the following code is equivalent to yours but a little bit smaller and faster:
PRINTBANG:
A9 21 LDA #$21
4C F0 FD JMP COUT1
Notice that the JSR instruction has become a JMP.
Another related trick: When you have a routine that callers often want to call twice—say to print `!!` for extreme exclamations—you may be tempted to create a do-it-twice call:
But we can do even better! We can eliminate the jump and save three more bytes by placing our do-it-twice routine immediately before the routine it is calling:
When PRINTBANG2 is called, it calls PRINTBANG to print an exclamation point, but when PRINTBANG returns, it returns to PRINTBANG2, which promplty falls through to PRINTBANG, calling it again and printing a second exclamation point. This time, however, when PRINTBANG returns, it will return to the original caller.
Back when every byte mattered, these tricks were useful to know.
[−]flopsamjetsam · 2026-11-15 Sun 03:35 UTC ·
link
> CALL -151
I haven't seen that in a long time! Young me was too young to understand 2s complement arithmetic, or that addresses would wrap around. I just thought it was some kind of magic.
There was also a mini-assembler [0] that let you enter assembly code directly into memory. It was dead simple to use, and since it printed an assembly listing after you entered each instruction, it was conducive to learning the hex codes by heart.
The mini-assembler didn't understand symbols (other than the opcodes themselves), but it did understand the addressing modes. This saved you from, for instance, hand calculating branch offsets.
Not all Apple II models included it, but I can't find a reference right now. Ours had it.
Guess what? Apple brought back the mini-assembler when it released the "enhanced" version of the Apple //e in in 1985:
Monitor changes also included a return of the mini-assembler, absent since the days of Integer BASIC. It was activated by entering a “!” command in the Monitor, instead of a jump to a memory location as in the older Apple II. Features also added included the ability to enter ASCII characters directly into memory, and an “S” command to make it possible to search memory for a byte sequence. Interrupt handling was also improved. However, the “L” command to disassemble 6502 code still did not handle the new 65c02 opcodes as did the IIc disassembler.
In case of Wozniak, he had access to a commercial programmer at work.
Some people did burn the code into electrically programmable PROMs completely by hand, using just a power supply, some wires and switches. Anyone could do this at home, but it was extremely tedious even for a tiny 256 byte chip.
You'd hand write most of the code, type it into the assembler and that could then create what was effectively a machine code binary which you'd save to tape.
With small stuff you could run the code and drop back out to the OS. Generally you'd load and run the binary to test it and then back to loading the editor and source code, edit that, reassemble. Repeat ad infinitum.
Much of the ZX81 and Spectrum code I wrote was initially done on pen & paper and developed like that.
When I got my first in-house job in 1984 they were using TRS80s for editing and assembling which also had a custom hardware link to transfer the binary to the Spectrum.
By the time we got onto Atari & Amigas there was much better custom hardware, such as SNASM, which also facilitated remote debugging from a PC.
You can observe the same behavior from modern LLMs, when working on firmware or closed library and they need to fix or bypass a small thing, sometimes they just directly modify the binary without any disassembler. At least the Chinese non de-cybered LLMs.
I was born too late for that era of computing, but I've spent enough time programming that I can easily "run" a program in my head and reason about how it works, find bugs, etc. I would imagine that muscle was even more developed for the people who had to do it out of necessity, though.
That's how I learned to program. I didn't have access to computer as a kid, so I read books, wrote programs on paper and when I got access to a computer I would type in the program and see if it worked. I now have an abundance of computers at home. What a weird timeline all in all.
Since I learned to write machine code this way, I'll add a little bit of color.
You can take the instruction set of a simple microprocessor, and lay out its instruction set in a tabular format. This made it relatively easy to see the correspondence between an instruction in assembly language and its numerical code.
Handy "reference cards" were published for looking up the codes, printed on nice thick plastic. You can find these in a google image search for your favorite micro. I got by with a photocopy. Along with that, a programmer would have their own notes and diagrams taped to the walls for quick reference. Machines were simple enough that you really could have all of the vital information available at a glance.
Today, the "datasheet" for a sophisticated 32 bit microcontroller is many thousands of pages.
Microprocessors had relatively few transistors by today's standards, so the instruction decode logic had to be simple. Logical, if I may say so. This resulted in being able to describe operators and their operands as blocks of bits in an instruction word.
I arrived late enough in the game that personal computers already existed, yet I got myself started by hand assembling for the microprocessor circuits that I brought up from scratch.
Long before 8-bit computers, I had 15 minutes of access every Saturday to an IBM 1620, so I had a week to write (and erase) code (initially FORTRAN II, later 1620 ASM) before getting anywhere near the computer. When I got to the machine room I had to punch the code on cards using an IBM 026 card punch. For my larger FORTRAN programs, it took most of the 15 minutes to compile them and punch an object deck, which I couldn't run until the next week.
1) In the Saturday morning programming class that I attended just to get the computer time, an experienced student had a card deck and a brand new student asked to see it, and the former unfortunately agreed. The new student had no idea that the order mattered and scattered them all over his desk.
2) I rode a Honda 90 over Beverly Glen to attend UCLA. One morning I had a 300 card PL/1 program bungied onto the back of the motorcycle. The car in front of me slammed on its brakes when the signal turned at Beverly Glen and Sunset, I rear-ended them, and my deck went flying all over the road.
[−]curiousObject · 2026-11-15 Sun 13:08 UTC ·
link
Did the cards not have some sort of index system so they could be automatically sorted back into the correct order? Holes on the edge maybe?
[−]KineticLensman · 2026-11-15 Sun 14:35 UTC ·
link
Another useful technique was to draw a line diagonally across the top of the deck with a marker pen or similar. Helped a bit as a first pass for any post-drop sorting
I think John Romero had a similar story in one of the books about pre-Id days. I suspect dropping a deck of cards was an experience almost everyone had!
I find it amusing that so many of the comments were surprised about hand-assembling 6502 code. When I came to the Apple ][, assemblers were relatively more accessible, but even at around $200, it was well beyond my financial means so I would write code longhand in spiral bound graph paper notebooks in four columns: Addresses, labels, hex codes (up to three bytes per opcode) and then the assembly code.
And that $200 being out of bounds went pretty low: for the first couple years of my programming life, floppy disks were beyond my means, so any code I wrote lived in its official version as hand-written code and would have to be retyped any time I wanted it.
Mmm. It's tempting. And I did write plenty of basic on paper in detention when I was young; that exercise certainly did force me to think in unusual ways.
But I think I'll stick to my LLMs and the fond memories of spending a few evenings sussing out resolute performance from an RP2040 PIO's whole-several assembly instructions. :)
[−]pseudohadamard · 2026-11-15 Sun 07:47 UTC ·
link
Kids these days... that's exactly how I wrote code, the 6502 was simple enough that you quickly memorized all the opcodes (A9 07 20 ED FD ...), and you sketched it out on paper and desk-checked it before typing it in... which you did by banging rocks together to get ones and zeros. Ay, we had it tough, but you know, we were happy in those days.
I once worked worked with a guy who had himself done 6502 assembler, for CompuServe[1], in their home base of Columbus. Good dude; I wish I'd chatted with him more.
He wasn't happy about the position he was in while we were chatting, except it paid some bills and it provided good health insurance.
For comparison, I never learned any 6502.
But we both answered the phones the same way in that call center, and both we worked to give callers the best troubleshooting advice we could, given our understanding and ability to control that system.
I did this for my non apple 6502 machine - the issue I always had was how much space to put in between subroutines so I could change them later and not have to redo all the jumps. I think after a while I just did one 256 byte block per subroutine and screw memory efficiency (not for the last time in the following forty five years). The only time I crunched it back down was for a “use almost all 8K for the decimal digits of E” (which was fun and much faster than Pi but not totally useful as I couldn’t print them or save them to tape).
My local teenager Apple crowd could get you almost any game, or disk copy utility, or etc. But never an assembler or complied Basic, or Apple Pascal or anything like that. I was insufficiently 1335.
Anyway, my career in writing 6502 machine code in pencil pretty much ended at "Hello World".
[−]BuildTheRobots · 2026-11-15 Sun 07:54 UTC ·
link
1335? Though to be fair you were very almost 1337...
I was 4yo when I re-typed my first program from Atari manual to my Atari 800xl and was baffled that I had to retype it after restarting the computer. I tried saving it to a cassette tape but that didn’t work well. I envied my cousins who had their Atari with 5 inch floppy drive.
[−]jonathanlydall · 2026-11-15 Sun 13:01 UTC ·
link
Speaking as a father of a 4 and 6 year old, and trying to think back to my own (lack of) capabilities at that age, a 4yo being able to re-type a program into a computer seems quite extraordinary.
[−]askbjoernhansen · 2026-11-15 Sun 15:23 UTC ·
link
I think life was a little slower, so typing a program from hand written notes into the computer was pretty good for getting dopamine.
I was a little older than 4, but I learned to transcribe random snippets from the programming manual into the computer about the time I learned to read; and later I'd program (Pascal, not assembly) by hand writing when in school and then run home and try it out. What else were you going to do?
I'm working on a modern "The First Book of KIM" [1] and there are pages of assembly code for games, utilities. Alongside the assembly is the machine code (byte code).
As near as I can tell, the assembly is not formatted in a way that would actually assemble? Furthermore, there are missing labels, errors… My understanding is that the assembly is there more or less as documentation for the machine code—it was the hex that the person purchasing the book was expected to enter into KIM.
[−]WesolyKubeczek · 2026-11-15 Sun 13:09 UTC ·
link
> for the first couple years of my programming life, floppy disks were beyond my means, so any code I wrote lived in its official version as hand-written code and would have to be retyped any time I wanted it.
Vimes boots theory exemplified!
[−]oldjohnnylane · 2026-11-15 Sun 15:14 UTC ·
link
That’s because we’ve had multiple generations of programmers who don’t know what’s under the hood. It is a complete disconnect between hardware and software. I don’t know if that’s good or bad, it just is. FWIW I went to computer camp in the early 80s and the advanced assembly class was exactly what woz did: write on paper and type in hex bytes from the monitor (call -151. If you know you know … 99% of people here think a monitor is just the screen, that’s what I mean).
I did this on 6809 for a long time when I got started, just pages full of numbers with some hand written comments. The relative addressing modes made it easier for inserting or moving chunks of code.
I didn't even know what an assembler was until I ran into someone more knowledgeable about this stuff.
The days when I would remember everyone's telephone numbers AND Z80 instructions!
10 FOR N=0 TO 28
20 READ B: POKE 32768+N,B
30 NEXT N
40 RANDOMIZE USR 32768
50 DATA 62,2,205,1,22,17,16,128
60 DATA 1,13,0,205,60,32,24,245
70 DATA 73,32,65,77,32,65,87,69
80 DATA 83,79,77,69,13
It's a little scary that I can recognize a lot of those instructions from memory, even though it's been 40 years since I first got my ZX Spectrum.
Of course more recently I've been doing a lot of z80-based CP/M retro-fun. But "62, xx" is obviously LD A,xx, and similarly the 205 is CD which is CALL.
Fun stuf, thanks for the post, you are indeed AWESOME.
[−]ErroneousBosh · 2026-11-15 Sun 12:04 UTC ·
link
"call 5633" at that which opens the IO stream given in A.
I thought that's silly, but uh, I did recognize the opcode for CALL as well. Turbo Pascal for CP/M allowed one to enter in-line machine code, but didn't offer an assembler...
One of the reasons I prefer the port of BBC BASIC for CP/M, over Microsoft's, is that it supports inline Z80 assembler.
[−]ErroneousBosh · 2026-11-15 Sun 12:03 UTC ·
link
The neat thing about USR was that if I recall correctly it would pass the start address in BC, and return what value you placed in BC when it went back to BASIC.
I could have sworn the ROM spelled it RANDOMISE with the UK spelling though.
And then manually translate all those opcodes into values that code be entered as DATA into a BASIC, with a tiny loader segmnent and RANDOMIZE USR to jump into executing it.
Kids these days don't know how good they have it, even when playing around with an ESP32.
Maybe that is part of the nostalgia for the 8-bit days: the practice of "slow programming"? It was relaxing, sort of like those "slow tv" shows.
OT: others are the first times I drew graphics on the amber monitor of a PC clone and adding data to a BE database and then seeing said data on a webpage. I think my security was about the same as current-day Lovable :)
OOT: Thinking about it, I believe the pure wonder & joy came because it seemed like magic, but then you figured out how it worked which gave you an immense feeling of power and self-determination. I worry that with AI today you'll get the former and never the latter, which will have serious, long-term ramifications. I hope I'm wrong.
I figured out exactly what I wanted to do, wrote it out very carefully on paper, looked up all the hex codes, wrote those out very carefully, adjusted addresses etc. as needed. This took many hours spread over weeks. Then I entered the whole thing on the hex keyboard and display of a primitive development board each time I needed it, perhaps an hour or so each time (I think I only did it twice). It worked first time, because why wouldn't it if you were sufficiently meticulous about your work in a process that was very obviously very intolerant of the tiniest mistake?
I must admit my program (gather input information from some transducers, do some calculations, present some results) was likely somewhere between one and two orders of magnitude simpler than a complete Basic interpreter!
You had to carefully calculate the address distance for a branch instruction. The release of DISMON was a revolution: suddenly the computer did all of that for you. It even supported moving pieces of code to a different address to make space for inserting more instructions somewhere!
You would use the "monitor program" to poke hex data into memory locations, starting at a nominated RAM memory address. Needed to be done VERY CAREFULLY. one bad hex digit and your program likely crash. After entering all the program into memory, you would use a monitor program , command to get tell the CPU to jump to a certain address and start executing a program there. OLD computer magazines often had such hex listings printed in them.
* a single Z80 (which was nicer than 8080, because the latter needed an extra clock IC) * 256 bytes of static RAM * 1 8bit D-Latch (Flipflop) with 8 LEDs * 1 8bit D-Latch with 8 dip switches * 2 8bit buffers that can go tristrate between the hex-thingies and the address & data bus * 2 rotating hex thingies: you could rotate them between 0-f for data * 2 rotating hex ones for address
Now, how did it work? I pulled nBUSRQ down (bus request). This made the Z80 go tri-state. It also made my buffers non-tristate.
Then I used 2 of the hex-thingies to set the address and 2 of them to set the data. Now I set nWR to low and that would write the entered data byte into the SRAM.
When I was done, I turned nBUSRQ back to high, so the Z80 again was the boss of the bus. And then I simply used nRESET to low to make the Z80 execute my program starting at address 0.
I did only tiny programs, like adder, some PWN/sound wave program, an traffic light simulator.
But, since I soldered this all by myself, I had no "monitor program" like the KIM-1 had. So I had to do all of that by hardware.
(Note that while a lot of this was unjustifiable even then - my first real paying job in computers was down a step, working on a Z80-modded IMSAI so while most code was on 8" floppies, doing machine code in binary on toggle switches "just to fix something quick" was a legitimate skill :-)
With these three commands, and a working memory of the hex that corresponded to the opcodes, you could be reasonably productive writing short 6502 programs.
Fun and extremely niche fact: the typo CALL -161 jumped into the monitor, but only after the weird side effect of unhooking the sniffer that watched for DOS 3.3 commands sent via the ROM's text I/O. Not only did this make text print faster -- useful when you were visually dumping memory to the screen to find something quickly, but it also protected against accidentally destroying your disk if you unwittingly printed a sequence like ^M^DINIT HELLO^M, which would trigger the disk initialization routine.
Ancient assembly hacker tip: A JSR/RTS sequence can be simplified to a JMP. To continue your example, the bytes you provided decompile as follows (assuming Apple 2 monitor ROM at $F800):
So, you load the A register with #$21, which is the ASCII code for `!` in hexadecimal, and then call COUT1 which will output the character in the A register, printing the exclamation point. When COUT1 is finished, it will return to you using an RTS instruction, and then you'll return to your caller using another RTS instruction.Since the call to COUT1 is a tail call, you can borrow its RTS instruction to return to your caller and save one instruction. So the following code is equivalent to yours but a little bit smaller and faster:
Notice that the JSR instruction has become a JMP.Another related trick: When you have a routine that callers often want to call twice—say to print `!!` for extreme exclamations—you may be tempted to create a do-it-twice call:
But now we know better and code it this way: But we can do even better! We can eliminate the jump and save three more bytes by placing our do-it-twice routine immediately before the routine it is calling: When PRINTBANG2 is called, it calls PRINTBANG to print an exclamation point, but when PRINTBANG returns, it returns to PRINTBANG2, which promplty falls through to PRINTBANG, calling it again and printing a second exclamation point. This time, however, when PRINTBANG returns, it will return to the original caller.Back when every byte mattered, these tricks were useful to know.
I haven't seen that in a long time! Young me was too young to understand 2s complement arithmetic, or that addresses would wrap around. I just thought it was some kind of magic.
The mini-assembler didn't understand symbols (other than the opcodes themselves), but it did understand the addressing modes. This saved you from, for instance, hand calculating branch offsets.
Not all Apple II models included it, but I can't find a reference right now. Ours had it.
[0] https://www.callapple.org/vintage-apple-computers/apple-ii/a... (1978)
Monitor changes also included a return of the mini-assembler, absent since the days of Integer BASIC. It was activated by entering a “!” command in the Monitor, instead of a jump to a memory location as in the older Apple II. Features also added included the ability to enter ASCII characters directly into memory, and an “S” command to make it possible to search memory for a byte sequence. Interrupt handling was also improved. However, the “L” command to disassemble 6502 code still did not handle the new 65c02 opcodes as did the IIc disassembler.
Source: https://www.apple2history.org/history/ah07/#07:~:text=Monito...
You go to a start address, switch to data mode, and just start plugging in hex…
Some people did burn the code into electrically programmable PROMs completely by hand, using just a power supply, some wires and switches. Anyone could do this at home, but it was extremely tedious even for a tiny 256 byte chip.
With small stuff you could run the code and drop back out to the OS. Generally you'd load and run the binary to test it and then back to loading the editor and source code, edit that, reassemble. Repeat ad infinitum.
Much of the ZX81 and Spectrum code I wrote was initially done on pen & paper and developed like that.
When I got my first in-house job in 1984 they were using TRS80s for editing and assembling which also had a custom hardware link to transfer the binary to the Spectrum.
By the time we got onto Atari & Amigas there was much better custom hardware, such as SNASM, which also facilitated remote debugging from a PC.
I've been staring at, fixing up enough 6502 op-codes ands their machine code equivalents that I'm beginning to remember the common ones too.
I guess whiteboard interview technique came from there. Probably rational was - If they can do it, why can’t you?
You can take the instruction set of a simple microprocessor, and lay out its instruction set in a tabular format. This made it relatively easy to see the correspondence between an instruction in assembly language and its numerical code.
Handy "reference cards" were published for looking up the codes, printed on nice thick plastic. You can find these in a google image search for your favorite micro. I got by with a photocopy. Along with that, a programmer would have their own notes and diagrams taped to the walls for quick reference. Machines were simple enough that you really could have all of the vital information available at a glance.
Today, the "datasheet" for a sophisticated 32 bit microcontroller is many thousands of pages.
Microprocessors had relatively few transistors by today's standards, so the instruction decode logic had to be simple. Logical, if I may say so. This resulted in being able to describe operators and their operands as blocks of bits in an instruction word.
I arrived late enough in the game that personal computers already existed, yet I got myself started by hand assembling for the microprocessor circuits that I brought up from scratch.
1) In the Saturday morning programming class that I attended just to get the computer time, an experienced student had a card deck and a brand new student asked to see it, and the former unfortunately agreed. The new student had no idea that the order mattered and scattered them all over his desk.
2) I rode a Honda 90 over Beverly Glen to attend UCLA. One morning I had a 300 card PL/1 program bungied onto the back of the motorcycle. The car in front of me slammed on its brakes when the signal turned at Beverly Glen and Sunset, I rear-ended them, and my deck went flying all over the road.
And that $200 being out of bounds went pretty low: for the first couple years of my programming life, floppy disks were beyond my means, so any code I wrote lived in its official version as hand-written code and would have to be retyped any time I wanted it.
Like blowing into a gourd is still available to a modern saxophonist.
But I think I'll stick to my LLMs and the fond memories of spending a few evenings sussing out resolute performance from an RP2040 PIO's whole-several assembly instructions. :)
He wasn't happy about the position he was in while we were chatting, except it paid some bills and it provided good health insurance.
For comparison, I never learned any 6502.
But we both answered the phones the same way in that call center, and both we worked to give callers the best troubleshooting advice we could, given our understanding and ability to control that system.
[1]: https://en.wikipedia.org/wiki/CompuServe
Anyway, my career in writing 6502 machine code in pencil pretty much ended at "Hello World".
Apple 1 users had a keyboard. But its developers may have been using a hex keypad, or an array of toggle switches.
You could go a long way with mov/jz/jnz etc and basic bios calls
I was a little older than 4, but I learned to transcribe random snippets from the programming manual into the computer about the time I learned to read; and later I'd program (Pascal, not assembly) by hand writing when in school and then run home and try it out. What else were you going to do?
As near as I can tell, the assembly is not formatted in a way that would actually assemble? Furthermore, there are missing labels, errors… My understanding is that the assembly is there more or less as documentation for the machine code—it was the hex that the person purchasing the book was expected to enter into KIM.
[1] https://archive.org/details/The_First_Book_of_KIM
A new game for the fifty-year-old KIM-1: https://engineersneedart.com/blog/yahtc/yahtc.html
Vimes boots theory exemplified!
I didn't even know what an assembler was until I ran into someone more knowledgeable about this stuff.
https://nemanjatrifunovic.substack.com/p/pdp-10-and-microcom...
Of course more recently I've been doing a lot of z80-based CP/M retro-fun. But "62, xx" is obviously LD A,xx, and similarly the 205 is CD which is CALL.
Fun stuf, thanks for the post, you are indeed AWESOME.
I could have sworn the ROM spelled it RANDOMISE with the UK spelling though.
Kids these days don't know how good they have it, even when playing around with an ESP32.