53

How did the 8-bit computers (Spectrum, Commodore, Atari, Amstrad etc) typically "bootstrap" from bare electronics into a platform with a working assembly language and OS?

What I mean: An assembler is not an application exactly trivial to write. There's a text editor, there's a parser/lexer that converts the mnemonics and parameters to machine code, there are I/O procedures to save the sources and the binary, at the very least. It's a fairly largish piece of code that you have no programming language to write in, not even an assembler! And there's even no OS to use procedures for I/O, it still needs to be written. And there were no simulators/emulators for existing platforms to use, since this was a brand new platform.

How was this problem handled? How did programmers approach bootstrapping the micros from 'bare metal' to a 'marketable product with a working assembler'?

SF.
  • 7,095
  • 7
  • 30
  • 58
  • 28
    They used cross-development, of course. – Leo B. Jul 18 '17 at 16:09
  • 8
    Getting enough of an assembler written isn't actually too hard, I wrote one for the Apple ][ (using the monitor) as I couldn't afford anything else. i seem to recall there was the source code (in BASIC) for one in a Rodney Zaks book. You might find this article at zdnet http://www.zdnet.com/article/the-zx-spectrum-birthday-memories/ interesting, written by an ex-colleague who used to work at Sinclair when they used a VAX. – PeterI Jul 18 '17 at 17:19
  • 9
    Early assemblers were much simpler than today's assemblers. A modern assembler for Windows is pretty much a high-level language (with loops, functions, register abstraction, strings, DLLs, structures, multi-threading, dynamic memory allocation...) compared to many of the early "high-level" languages like BASIC or Pascal. Remember, you only have something like 4 kiB of RAM - handwriting four thousand values at most isn't a big deal. I've coded in machine code before (on my own CPU), and it doesn't take long to get to a decent assembler (and later, C-compiler) from scratch. – Luaan Jul 19 '17 at 12:05
  • 7
    Text editor WTF? None of the current major free-software x86 assemblers (NASM, YASM, and GNU as) are text editors. Even MASM comes with an IDE, it's is just an assembler that runs as a separate executable . They all just read text and assemble bytes into a binary output file. You edit text with a separate text-editing program. – Peter Cordes Jul 20 '17 at 03:27
  • 2
    @PeterCordes: And yet I don't think I've seen an assembler for an 8-bit computer that didn't come with a text editor. Can you name any? – SF. Jul 20 '17 at 04:00
  • That's a fair point. Before you saw the answers, you were thinking that way, not realizing that you'd actually bootstrap up from a simple bare assembler to write a whole dev env in asm, not machine code. – Peter Cordes Jul 20 '17 at 04:05
  • 2
    But re: programming in raw machine code: That was a thing before assemblers existed, and it was not for the faint of heart. The Story of Mel is an excellent true story about working with a machine-code expert on a drum-memory computer in the 1960s, with an interesting ethical conundrum. Definitely worth reading. – Peter Cordes Jul 20 '17 at 04:08
  • @PeterCordes: Yes, "that was not for the faint of heart" is the point here - if you work on a budget, under a deadline, you're not likely to muck around writing machine code for an entirely new platform nobody has ever written any code for yet any more than absolutely necessary. And the platform and its peripherals is absolutely incompatible with everything "established" on top of that! And likely with bug-ridden hardware too! – SF. Jul 20 '17 at 04:20
  • 3
    @SF: Incompatible with everything? Perhaps, if you're thinking of mass-produced peripherals with standard connectors. But if you're a company capable of building a microcomputer in the first place, you will have some people who can solder on payroll already. If nothing else, your cross-development host in this era will be able to punch cards or paper tape. Your hardware guys won't even break a sweat jury-rigging some logic that will let a plain old electromechanical tape reader flip the front-panel switches on your development prototype. Especially if it doesn't have to be fast or elegant. – hmakholm left over Monica Jul 20 '17 at 11:56
  • @HenningMakholm: Was paper tape ever used with Spectrum, Atari or Commodore? – SF. Jul 20 '17 at 12:35
  • 2
    @SF: I don't know which particular medium those companies used. My point was that even though the system as sold is a closed ecosystem with no direct interoperability, that doesn't mean it would have been impossible -- or even very hard -- to get cross-compiled code from a different machine into that ecosystem. Paper tape and simulated front-panel switches would be one option among many; I mentioned it as a baseline possibility because it's slow and simple enough that even I would feel ready to take a swing at it myself with a bucketful of 74xx's and a breadboard. – hmakholm left over Monica Jul 20 '17 at 13:02
  • 2
    Bootstrapping by hand is fun. Sketch a flow chart, write the assembly opcodes and operands on paper, lookup the related hex codes, toggle the binary into memory while single stepping addresses then execute. Good times… If you want to try it you can get one of these https://www.amazon.com/Micro-Master-Computer-Training-Kit-MM-8000K/dp/B0002EWO2Q – Matthew Whited Jul 20 '17 at 14:14
  • 2
    BTW, there is a reason that older computer languages have very strict syntax rules. Strict rules are easier to write when you are hand compiling code. – Matthew Whited Jul 20 '17 at 14:16
  • 2
    FYI, old school assemblers didn't need lexers. The file format was much reduced at the time so that something like strtok() would suffice. – Joshua Jul 20 '17 at 15:45
  • But by the way, Wikipedia explicitly mentions: "In the 1970s through the early 1980s, paper tape was commonly used to transfer binary data for incorporation in either mask-programmable read-only memory (ROM) chips or their erasable counterparts - EPROMs". So it is likely that the ROM-based BASICs in the early home computers you mentioned passed through paper tape somewhere in the chain from programmer to CPU. – hmakholm left over Monica Jul 20 '17 at 16:30
  • Some computer system vendors may have skipped first creating a native hosted assembler, and gone straight to BASIC, or other HLL or OS (created by means other than a native hosted assembler). – hotpaw2 Jul 20 '17 at 18:03
  • @SF "And yet I don't think I've seen an assembler for an 8-bit computer that didn't come with a text editor. Can you name any?" The one in ROM on a Apple ][+ could be programmed using the minimal shell also resident in ROM but I wouldn't characterize it as an editor even by the weak standards of the day. – dmckee --- ex-moderator kitten Jul 20 '17 at 19:07
  • 2
    I wrote a full Z80 assembler and editor, in Z80 assembly language, using another more primitive assembler that didn't come with it's own editor. Machine was Spectravideo 328 (forerunner of MSX). The more primitive assembler expected it's source as REM statements in a BASIC program. If only I could find the audio cassette it's all saved on :) – Reversed Engineer Jul 21 '17 at 08:29
  • The Apple II ROM includes a mini assembler which reads a line of input from the keyboard and immediately assembles it into memory. This is in ROM, so no text editors or operating systems are involved. There's also a disassembler if you want to list your code. Sounds primitive, but it's no worse than the built-in BASIC interpreter. (and just like BASIC, save to a tape, save to a disk, or retype it next time) – Kelvin Sherlock Jul 28 '17 at 17:26
  • Re. needing a text editor: a simple text editor is extremely easy to write. Consider the editor used by certain Forth environments: memory is divided into pages, each of which has a fixed number of lines, each line being a fixed length. You have a command line interface that can either select a page, print the current page, or replace the contents of a line in the current page with a new version. Easy. Bet you could do it in a few hundred bytes, if you put your mind to it. – Jules Jul 28 '17 at 20:03
  • 3
    Re transfering data from other systems: if your target has a way to put the processor in a halt state (which every 8 bit system I've seen can) and use its bus connection directly (ditto) you can build a system with a UART, a 16 bit counter, and a handful of standard logic chips to let another system dump data directly into memory. Would probably have cost less than £20 to make, even at early-80s prices for such components. – Jules Jul 28 '17 at 20:09
  • 4
    The first code I ever wrote in 1978 was done by hand, hand-assembling the opcodes (some of which I still recall to this day) from my hand-written assembly listing. These byte values were entered into RAM via toggle switches on a panel I designed and built. Those bytes were the boot loader that let me then use the QWERTY keyboard to start poking bytes directly in to RAM which became the software that I wanted to run. Eventually I bought an EEPROM programmer that would let me dump whatever was in RAM in to a ROM, which made getting to the next stage, a simple assembler, a lot easier. – Justin Jul 29 '17 at 06:39
  • @SF.: The Fast Assembler for the Commodore 64, published in Compute's Gazette magazine (early 1986, IIRC) would process assembly-language programs that were entered as BASIC programs. What it did was extend the BASIC language with a few new keywords like "ORG" as well as keywords for each 6502 mnemonic, and then process, e.g. LDA #123 by generating byte values 0xA9 and 0x7B, storing them appropriately, and advancing the current output location by 2. A typical assembly-language program might need to be wrapped in for pass=1 to 3:org $C000,(pass=3) and next. Really quite elegant. – supercat Apr 27 '18 at 19:27
  • Semi-related: What is the most rudimentary input method a platform has ever been programmed in? , and Why did 1970s front panels prefer momentary toggle switches to push buttons? for pictures of ancient computers with front-panel switches for entering binary data. (Mostly not micros.) – Peter Cordes Jul 16 '23 at 21:39

12 Answers12

52

Gates and Allen used remote terminal access to a minicomputer (Harvard's DEC PDP-10) to cross-assemble, and simulate, their implementation of BASIC for the Altair 8800. Commodore Basic (for the 6502) is reportedly derived from Altair Basic, and also cross-assembled using Macro-10 on a DEC 10.

Woz (and many other early Apple programmers) could code 6502 machine code in absolute hex, which could then be burned into EPROMs to boot the machine into a monitor, from which more hex machine code (or a single line of mini-assembler mnemonics) could be entered. Many programmers in those days memorized raw hex or octal machine opcodes instead of (or in addition to) assembly language mnemonics.

It's a reasonable guess that some other microcomputer system developers may have used cross-assemblers on the first CP/M systems and/or Intel MDS development systems to write early development tools for later 8-bit systems. And those systems were, in turn, used to cross-develop for subsequent systems.

It appears that the very first textual mnemonic assembly language programs, for the EDSAC and other early vacuum tube computers, were manually translated to hex, octal or binary machine code on paper, by hand, and entered into the computer by front panel switches, punched cards, or paper tape. Thus, the "computers" used for the very first cross-assemblers may well have been a roomful of women with pencils. (See the 2017 movie, Hidden Figures, or the 2008 Book When Computers were Human .)

hotpaw2
  • 8,183
  • 1
  • 19
  • 46
  • 17
    In the early days memorising binary instructions was useful because a lot of computers allowed you to alter RAM contents using physical switches on a control panel. Indeed, entering a bootloader by directly toggling RAM values was standard boot procedure on some early computers. – slebetman Jul 18 '17 at 22:45
  • 3
    Many programmers in those days memorized and still do! Either my brain isn't EPROM, or there wasn't enough ultraviolet light yet. to delete this them in it – Tommylee2k Jul 19 '17 at 13:17
  • 4
    "Woz ... could code in absolute hex 6502" - and Seymour Cray designed the instruction sets for the CDC7600, and the early Cray supercomputers, so one could do exactly the same - even when writing vectorised code. Writing a simple assembler for those machines (the most powerful of their time) directly in machine code was almost a trivial exercise. – alephzero Jul 19 '17 at 13:25
  • 4
    Some early programmers took advantage of knowing the machine encoding of instructions by also using them as data. The Story of Mel mentions this, and is a fascinating look at what a master craftsman could do with machine-code on a 1960's drum-memory machine. (Also an interesting human ethics story, definitely worth a read.) – Peter Cordes Jul 20 '17 at 04:17
  • @slebetman I remember doing that in one of my earlier mainframe operator jobs. We used a manually entered bootloader to load further instructions from punched card, and the punched cards contained a bootstrap that allowed us to load a full OS from a drum hard disk. Good times... – Rob Moir Jul 20 '17 at 09:53
  • I memorized a handful of Z80 opcodes from programming in hand-assembled machine code on the Speccy. But in decimal since BASIC had no decimal<->hex conversion and the Speccy manual listed both hex and decimal for every opcode. The only one I still remember 40 years later is 201 is RET. 6502 was simpler than Z80 with no prefixes and fewer addressing modes so I imagine more people could code it from memory than the Z80. – hippietrail Jul 03 '23 at 07:40
44

As someone who did it.... We wrote an assembler for an 8080, as there was nothing affordable from Intel. We wrote it in ALGOL 60, if I recall, and ran it on a mainframe.

the first thing we ran through it was .. itself, re-coded in assembler. Oh, and a boot-loader, though I think maybe we had already hand-assembled a minimal version of that into binary.

After that there was no stopping us :-)

david collier
  • 541
  • 3
  • 2
  • 6
    Upvoting, because this is the process used not just for assemblers but for pretty much every compiler in existence too. – T.E.D. Jul 21 '17 at 13:28
25

The same answer as everybody else, just with more detail:

What I mean: An assembler is not an application exactly trivial to write.

Oh, but it is. A "first" assembler on a platform simply reads some bytes, transforms them in a more or less 1:1 relationship to other bytes, that's it.

The target architecture was very simple. There was no shared objects / DLLs or anything like that. At least the assembler I used on a Atari 800XL either had no binding/linking stage, or I didn't know about it/did not see a need for it. There certainly were no standard libraries or anything like that. You would skip all convenience features as well.

There's a text editor,

They are pretty easy to write as well. For starters, you don't absolutely need a full fledged modern editor. If in doubt, you can get away with something line-number based like the early BASICs. And even if you wanted to handcraft an actual editor, that would not be that hard either.

there's a parser/lexer

For recognizing the assembler commands, you can use a simple lookup table or direct string comparison. You wouldn't need very complex "formula" parsing either. Don't forget that the CPUs of that time were very simple as compared to today. The 6502 had 3(!) registers (A, X, Y) and only a handful of flags. The datasheet lists only roughly 60 (!) different instructions, 11 addressing modes.

All commands, flags, addressing modes, op codes, timings and instruction-adressing combinations fit on two (!) single-sided pages of paper. The physical CPU had only 40(!) pins.

there are I/O procedures to save the sources and the binary,

You'd need those anyway, and, again, those were kind of trivial back then. You could easily start off with everything on tapes, and then it's just about streaming some bytes in/out.

I recall disassembling/reverse engineering the firmware of one of the Atari 800 XL floppy drives (as well as the OS) back then. It was doable, not too bad.

a fairly largish piece of code

Really not. It was common back then to publish whole games in print magazines (and books), and teenage boys would easily type in thousands of lines of code over the course of a rainy weekend. When your machine has only a few KB of usable RAM anyway, the size of your code will have a natural limit.

And there's even no OS to use procedures for I/O, it still needs to be written.

Again, I/O was very simple back then. A handful of different hardware models (tape drive and 1 or 2 different floppy drives), no choice of file system - heck, no file system at all for the tape, and extremely limited FS for floppies as well. No concurrency, no virtual memory, no swapping, no nothing. Definitely possible to handcode in assembler.

And there were no simulators/emulators for existing platforms to use, since this was a brand new platform.

No simulators/emulators (though I don't know for sure), but cross compilation is, again, pretty simple. That is, if you had (as a larger company) access to existing computers, you would probably write your code there.

How was this problem handled? How did programmers approach bootstrapping the micros from 'bare metal' to a 'marketable product with a working assembler'?

I don't know how they actually did that, but I really would not be much surprised to learn that all the original code was hand-written in cross-compiled assembler or straight hex code.

Remember that rather large things like the Ultima games (starting with II, I think) were hand-written in Assembler. It was doable.

AnoE
  • 1,549
  • 9
  • 13
  • 6
    Important note: you only need to hand-build the machine code for the very simplest assembler. Then you can iterate on the assembler, making it progressively better. The first version doesn't need any I/O at all, for example. Even high-level languages (for the time) like Pascal or LISP had compilers written in... themselves. Start simple, iterate, a year later you have a full-blown system. – Luaan Jul 19 '17 at 12:00
  • Absolutely, @Luaan. I've amended the first paragraph a bit. – AnoE Jul 19 '17 at 13:43
  • 1
    The difference between writing in assembler and in machine code is pretty big. I once created a patch for a program; the assembler code (some 12 lines) took me maybe 15 minutes to plan, design, write, check, double-check. Then I spent another hour manually converting that to machine code by hand. Look up command in this addressing mode. Look up address of this special register. Change bits to match that register within command byte. Align this, check that. Looking up the numbers in books took ages! – SF. Jul 19 '17 at 16:52
  • And don't even get me started on jumps. You don't realize how much of a convenience a label is until you need to count how many bytes you need to jump... and are you supposed to take the byte after the jump command as starting address? Of the jump? Of its params? "Only 11 addressing modes" - only when you need to find the right of 11 variants of a command in a table, you start appreciating this isn't "only 11"! – SF. Jul 19 '17 at 16:59
  • 1
    Yes, of course, @SF. Somehow back then, if I recall correctly, one seemed to crunch through all of this somewhat stoically, if needed. Sure you have to look in tables, but you can keep the whole of what a CPU like the 6502 "is" in your brain, or on some pieces of paper right in front of you... My usage of "easy" and "simple" is in comparison to later machines. One would not, in the faintest dream, think about hand-crafting code for a modern CPU... – AnoE Jul 19 '17 at 17:02
  • 3
    I was one of those teenage kids typing in programs from magazines, first on a TI-99/4A and later on an Atari 130XE. I seem to remember writing a disassembler at some point, and discovering that the bits representing the addressing mode were 'coincidentally' always in the same position. What luck! – Marc Bernier Jul 19 '17 at 20:11
  • @AnoE: I think some people can write some x86 machine code without consulting tables. I'm not one of them, but I do know how many bytes most instructions will be just from looking at them (useful for optimizing, as a tie-breaker between otherwise-equal instructions like xorps vs. xorpd). If I memorized the table of register-name->3-bit-integer (I know it starts ax, cx, dx, ...), I'd be most of the way to being able to write mod/rm and SIB bytes for encoding operands. Then I'd just need to know some opcodes. I know which encodings exist for most instructions, just not the numeric codes. – Peter Cordes Jul 20 '17 at 03:41
  • Most of my code-golf answers are in x86 machine code, but I write those in assembler and post the disassembly as the real program, not just the bytes. e.g. https://codegolf.stackexchange.com/a/78972/30206. Anyway, point is, you wouldn't want to have to hand-craft x86 machine code, but you could dream of it. IDK whether a fixed-width ISA like MIPS, ARM (Aarch32) or Thumb would be better or worse. I'd guess ARM would be ok with a table of mnemonic->opcode, and everything is pretty regular after that. A bunch of the bits are for predication. – Peter Cordes Jul 20 '17 at 03:49
  • 2
    @SF.: If you've only hand-assembled 12 lines of code, it might reasonably take 5 minutes a line, but with practice it's possible to get a lot faster. Certain opcodes will get used a lot, and will thus become second nature. Hand-assembled code may tend to be a bit simplistic (using a sequence of memorized instructions in favor of a shorter sequence of instructions one would have to look up) but it may still be able to get the job done. – supercat Nov 01 '17 at 16:21
  • 1
    @PeterCordes: One thing that may help is having a translation tool which can process certain strings of numbers in certain ways, so that one could code instructions as an opcode type followed by values for the different fields. One would need to either memorize or have a cheat sheet to say that the BP+SI+disp8 addressing mode is number 23 (or whatever) but a tool that can take the opcode fields and then shift/combine them suitably and handle some simple forms of label usage can make things much nicer than entering raw hex values. – supercat Apr 27 '18 at 19:32
23

The 1974 Altair 8800 kick-started the industry but at the time offered no keyboard, no screen, just a bunch of switches and lights connected directly to the bus and a counter to help you input or output sequential values. So you'd work out the binary representation of your program by hand and input it byte by byte, bit by bit.

The world's introduction to the 6502 wasn't so much more advanced: 1976's KIM-1 has a hexadecimal display and input pad but you're still hand-assembling and inputting.

So by the time you really get to the boom, in 1980 or so, the market has had half a decade of building terminals, tape interfaces and the rest, often in an ad hoc fashion, from which to put together the second-wave machines. You're not bootstrapping from nothing, you're standing upon experience with the CPUs and with how you can add a bunch of things to them. Through CP/M you already have a huge number of development tools for the 8080 and Z80. Throw in a minicomputer and you've probably got the grunt to simulate. If you're after about 1980 and considering filling your machine with PALs or ULAs then the manufacturer of those will probably lease you the minicomputer and supply the simulation software.

So my answer is: they weren't building from nothing by then, and definitely not in isolation.

user
  • 5,286
  • 2
  • 26
  • 43
Tommy
  • 36,843
  • 2
  • 124
  • 171
  • 1
    Indeed. If you have one working CP/M 8080 machine in the lab, getting CP/M onto your target 8080 machine is a relatively small project of writing a BIOS and some I/O drivers. You can do that using the native toolchain on the existing machine - technically it's cross development, but only barely so. 6502 systems didn't have that same commonality of operating system, so you needed to develop more, but you could still make use of an existing toolchain to target a different machine with the same processor if you bring along knowledge of (or freshly create) all the BIOS hooks and hardware. – Chris Stratton Jul 22 '17 at 12:50
17

It is worth remembering that by the time the home hobby microcomputers appeared, Computer Scientists had more that 25 years experience in building assemblers and designing bootstrap loaders.

As a summer job in the mid-1960s, I worked as an operator in an IBM datacenter with a IBM 1401 - 16K of RAM, no disk, 5 tape drives a cardreader/punch and a printer. Programs were on decks of 80 column cards. You loaded the card deck in the hopper and pressed "Start" This read the first card into the start of memory and executed the instructions encoded on the card. I believe that it read 2 more cards to get the bootstrap fully loaded and then started to read the rest of the deck to get the actual application program read and started.

At university we had a PDP-8 that used papertape as a program storage media. You had to key in the bootstrap using toggle switches. I don't recall how many instructions had to be keyed in but it was very few before the PDP-8 had enough code to start to read the tape and finish loading the program.

In the late 1960's as an undergraduate, I wrote an emulator that ran on the PDP-10 and emulated the IBM-360.

By the time the micro-computers appeared, the concept of using cross-assemblers to produce executable code was pretty well understood and emulators allowed code to be tested even before an actual hardware chip was available. There was usually a long delay between the time a new chip functional design was finalised and the actual chip was available.

Without the modern tools for chip design (CAD, design emulators, etc.) and cheap workstations for engineers to use, it was not that easy to make the masks for the chips and to test actual chips prior to going into production. It was completely impossible to wait for a "real" chip to start programming all of the software.

These problems had all been worked out long before the microchip.

Ron
  • 271
  • 1
  • 2
  • I specifically targetted the home computers with my question, as they often didn't have big businesses with government contracts behind them, that would allow hiring an army of computer scientists and spending years punching cards, byte by byte. The competition was fierce and the markets tight; you had to get your product out of the door fast and on a budget - and who'd want to buy a home computer you could only program in machine language, on a mainframe? Producing a usable native assembler was an essential step of release, on a budget and under a deadline. – SF. Jul 19 '17 at 23:07
  • The PDP-8 paper tape boot loader was 15 words of 12 bits each. Early PDP-8s with magnetic core memory would retain memory contents when powered off, so it was only necessary to key in the boot loader if a program crash accidentally overwrote it. – A. I. Breveleri Jul 20 '17 at 01:33
  • Similar on the HP 2100. The disk boot loader was an entirely manageable 24 or so sixteen-bit words. The machine had core memory so usually it was always there, but it was no great trouble to re-enter it via the front panel buttons if one had to. (It must have been 24 or fewer because it started at octal 77750!) As with many modern boot loaders its job was just to read one sector from the disk and transfer control to it, and that sector of course contained more "bootstrap" code. – Jamie Hanrahan Jul 23 '17 at 07:51
  • 2
    There was an article in volume 1, issue 12 Byte magazine describing, in a whimsical style, how one hobbyist built an assembler from scratch. There was no code provided but all of the essential mechanisms, including a hash table for symbol lookup, were described. Article title was "Jack and the Machine Talk". – Jamie Hanrahan Jul 23 '17 at 07:54
  • @A.I.Breveleri: almost. 16 instructions plus 1 data word which you didn't have to load -- but you did have to re-load the start address to run it. – dave_thompson_085 Sep 03 '17 at 00:41
  • @dave_thompson_085: Neither of the RIM loaders published on DEC's 1974 PDP-8 Pocket Reference Card were ever used by any software development group I ever worked with. DECUS contributors and DEC's internal development teams always used a 15-instruction loader starting at 7760(8) and using 7777(8) as the data word. The loaders differed slightly, though, depending on the PDP-8 series and the type and model of the punched-tape reader. – A. I. Breveleri Sep 03 '17 at 03:22
9

Early assemblers were either cross-assembled or hand-translated. Writing a Z80 assembler in Forth takes just a handful of screens (if you are using mnemonics based on TDL's extension of the Intel 8080 mnemonics rather than the original Zilog Z80 mnemonics). Its main job, once you are talking about a practised coder, is resolution of jump targets.

To put this in perspective: the Nascom Z80 editor/assembler occupied a whopping 4kB of code (the data structure for labels took 2 bytes for each label, namely only its value: for every use of a label, the source was searched from the front for its definition, with the label table being filled in order of definitions, so assembly times grew as O(n^3) with source size). There was a disassembler taking up 3kB, and a very thorough debugger (using NMI and a few hardware bits in lieu of a "trace" flag/feature) taking up another 1kB and using the disassembler internals.

As a result, translating such code into binary (once you had it on paper) was less arduous than it would seem at first glance and once you had the relevant bugs under control, you could host natively.

user5416
  • 91
  • 1
  • 1
    What purpose would be served by storing the values of labels without names? If one is going to search the entire source code from scratch every time a label is encountered, why not discard all information about the label as soon as one has found out its value? – supercat Apr 27 '18 at 19:35
  • The Z80 instruction set has variable instruction sizes, so the only way to determine the "value" of a label is to basically reassemble the source. I suspect simply scanning the source to get the label's index was faster than reassembling to get its value. – K. A. Buhr Feb 04 '22 at 21:01
8

I used to regularly program my organization's mainframe in hand-coded machine language. It was a 60s vintage machine (a GE400 system), but it had an online patcher so I could modify the operating system on the fly by sticking a deck of cards into the reader and typing a one-character command on the console.

The patches were originally written in assembler, then hand-translated into machine language (in this case in octal). Punch the numbers into a card with a symbolic offset for the starting address, and the patcher basically did a "go to this address, load this instruction". It wasn't far removed from loading up a PDP-8 by using the front panel toggle switches.

npowroz
  • 81
  • 1
  • Welcome to Retrocomputing Stack Exchange. Please read the [tour]. Thanks for the answer - it's good to see personal experience. – wizzwizz4 Jul 19 '17 at 06:50
7

The first assemblers for home computers were almost certainly written on non-home computers, whose first assemblers were written on their predecessors and so on back to the very first assembler which was undoubtedly implemented in good old fashioned machine code.

  • 4
    "good old fashioned machine code" I see that you're a "real programmer". :-) Welcome to Retrocomputing. – wizzwizz4 Jul 19 '17 at 06:49
  • do not underestimate ingenuity and the power to complicate things. ;) – Rui F Ribeiro Jul 19 '17 at 08:28
  • Inaccurate - a significant minority of the young early developers used writing a toolkit (assembler, debugger, line editor, linker , loader), as a way to introduce themselves to an architecture. When I was at Amiga - the majority of the outside early developers had written a toolkit especially the critical people who were to create the game engines, video processors, and the speed kings ( increased application performance by at least a multiple of 10). – LOIS 16192 Oct 24 '17 at 06:02
4

The availability of cross-platform tools such as the Ocode bootstrap method for BCPL, and the Pcode bootstrap for Pascal, were also useful for creating and testing programs written in high-level languages, and then porting them to new systems.

BCPL in particular was designed with machine-architecture portability in mind - which no doubt gave rise to the ethos of portability in C.

MikeW
  • 141
  • 3
  • If I remember correctly, ocode was translated to acode. You then wrote an simple acode interpreter to pull in the ocode interpreter and eventually pull in the compiler. – cup Jul 19 '17 at 12:05
  • Cintcode ring a bell ?! – MikeW Jul 19 '17 at 13:50
  • Don't remember cintcode - possibly an advancement since acode. It certainly has a lot more instructions. acode only had 6.. – cup Jul 19 '17 at 21:25
  • I still have a book describing the P-code instructions and virtual machine. – JDługosz Jul 20 '17 at 09:05
3

Well Here is how I did it, and occasionally still do. In my day it was the system hardware guys who created the 1st code. We needed it to test and fix the hardware.

At this point (1978) the big advantage was the terminal (24 lines by 80 characters), and the UART (serial port, COM port). although on one occasion, I built a unit just using a 12 digit 7 segment display and a scientific calculator keyboard (40 keys).

The 1st step is to write a monitor.

It needs operations to

  1. Accept a character, print a character
  2. Accept and print a lines
  3. Display and change memory
  4. Set a break point, step and run programs

and at the second step

Load and save programs. The earliest cheap mechanism was audio cassette tapes (30/1800 bytes per second/minute ).

This was not a great deal of code. maybe a few hundred lines of code. You wrote it and coded it by hand, Gridded notepads were the key.

The big break through for me was something called a rom emulator.

(This is a modern kit version to attach to a PC http://www.sparetimegizmos.com /Hardware/EPROM_Emulator.htm. The 1st one I bought for about $100 (I was getting paid at this point!) had a simple display, and a 20 key keyboard, so you could edit the memory and.. program eproms).

I could connect it to the rom socket and and it enabled me to edit memory interactively. All I needed then was some sort of display.

Once the monitor was working, Assembler was next.

First a simple line by line assembler. recognized Mnemonics, and register names, and simple labels.

Next was a 2 pass assembler which provided for relocatable code. This needed the load function as you needed to load the program twice, once to allocate memory, and generate code, and the 2nd to update addresses.

I wrote my 1st multi-tasking operating system in 4k ROM + 2K ram this way.

The CPM and the PC extended the monitor into a bios, add in Floppy drives and you need file system, and as the saying goes bob's your uncle you have a system.

And that was it til I discovered Forth and life became really interesting.

Forth is not a compiler, it really is a linker, which can be easily extended and normally includes an assembler, and often makes you ask why you need high level languages. You do because optimizing compilers are real time and resource savers, but they were still at least 5 years away or $100K plus in the early 80s.

Once you "get" Forth you wonder what is all the fuss about OSes etc., is, then you get older and realize that they would be very useful when they finally create a good one.

On the other hand Do not write in assembler, write in "C" at a minimum.

LOIS 16192
  • 1,222
  • 1
  • 8
  • 4
2

There's nothing special about an assembler. It takes one type of instruction and does a 1:1 mapping to another type (the hex values for machine code). The simplest ones were quite simple - in the Red Book for the Apple][+ ( pdf ), on pages 91-93 in rather large type (complete with comments) is the entirety of the assembly code - less a page (256 bytes) and a half in size, on the order of 150 instructions.

Such could easily be written by hand and blown to a prom with little difficulty. From this, larger and more complex applications can be built. But the simplest and first assemblers on the personal computers of the day? Trivially hand coded and loaded.

user5455
  • 21
  • 1
  • For the typical assembler, it's frequently not a 1:1 mapping. For example, according to my x86 assembly-language reference, the simple add instruction maps to one of 14 different opcodes depending on data size and data source. The mov instruction adds the complexity of addressing modes, for 22 different opcodes. – Mark Jul 22 '17 at 01:28
  • @Mark instruction type to another type - in many machine languages addressing mode of an instruction is a specific subset of bits, so for example, the mov mnemonic may map to a specific value on bits 3-7 and its addressing mode to bits 0-2 forming the machine language command. – SF. Jul 22 '17 at 03:29
  • Welcome to Retrocomputing Stack Exchange. Please read the [tour]. Thanks for the answer; it's amazing to think how much even assembly language has grown since the early days. – wizzwizz4 Jul 22 '17 at 09:30
  • That's just an example of how the x86 ISA is the weirdo, @Mark. For the typical assembler, it is a 1:1 mapping of mnemonic and operands. – Cody Gray - on strike Jul 23 '17 at 17:33
  • As simple as an assembler may seem, I have a copy of the PDP-10 Assembly Language Manual written in 1967 which has over 170 pages. – Ron Jul 24 '17 at 00:31
2

You might be considering them in terms of modern CPUs. The older machines (8 bit 1970s and earlier like the 6502) had a very simple opcode set. It was consequently much easier to write an assembler/disassembler than you might think, and would have been easier even if coded in machine code too.

Disclosure - I wrote one, although not in machine code.

Stilez
  • 246
  • 1
  • 4
  • This. The OP seems to be thinking in terms of modern assemblers (and maybe compilers/linkers). There was none of that. The opcode set was incredibly simple, there were only a few registers, and the job of an assembler was pretty much to translate mnemonics via a lookup table, and resolve jumps (during a 2nd pass) based on whether they needed to jump < or >= 256 bytes. – Stilez Nov 05 '19 at 11:29