15

I've always been sure that "machine language" and "machine code" are totally synonymous and mean programming directly in the language the machine understands, whether in binary, hex, or decimal; whether using some kind of hex editor or a BASIC loader with a POKE loop and DATA statements.

These two were opposed to "assembly language" which means programming in text mnemonics that a program called an "assembler" converted into the numbers the machine would understand; whether compiling directly into RAM, producing an object file that needed linking, or producing an executable file.

But I've just watched a good YouTube video on retrocomputing channel 8-Bit Show And Tell called '"Hello World" on Commodore 64 in Assembly Language, Machine Code'.

It's a good video for anyone into retrocomputing who didn't do programming back in the day or only programmed BASIC.

But he demonstrates three ways to program. One he calls "assembly language", one "machine language", and another "machine code".

I'd never heard of anyone differentiating those last two before. Was this a widespread view among programmers? Just among 6502 programmers? Just among C64 programmers? Something that some people used to do in the 8-bit days that nobody does anymore? Maybe it's an accepted difference everybody uses that I alone missed?

Here's the relevant parts of the content creator's notes in the video's chapter index:

  • 5:48 Assembly Language with TMP
  • 16:20 Machine Language with SuperMon 64
  • 23:19 Machine Code with BASIC loader

I Googled these terms: "TMP" is Turbo Macro Pro, an assembler for the Commodore 64. "Supermon64" is a machine-language monitor for the Commodore 64.

His clearest definition of the contrast between the three terms seems to be in the intro to the "Machine code with BASIC loader" section:

Okay so we've looked at Assembly Language and Turbo Macro Pro we've looked at what we might call machine language in supermon and now well yeah basically the lowest level is what we might call machine code which is just programming and hex bytes

In the part he considers "machine language" but not "machine code" he's using the C64 monitor "Supermon64" in which he enters MOS opcodes and the monitor converts that opcode to hex bytes. I would consider this to be programming in assembly language. But I never had such a tool back in the day.

In a response to my comment on the video, the author clarified thusly:

when authors (or speakers) use both terms with intention, there's definitely a trend to using "machine language" to mean the mnemonic representation and "machine code" to mean the numeric/hex representation. The term "code" comes from the cryptic numbers that represent the machine instructions

Interestingly, "machine language" was favoured in the US while while "machine code" was favoured in the UK. In both cases by a factor of two, and both peaked about 1985.

9
  • 10
    So what are these three different demonstrated methods then, or the difference between the two? Imagine the video does not exist forever so please make the question standalone.
    – Justme
    Jul 3, 2023 at 5:14
  • 1
    @Justme: Done. Let me know if it's not good enough. Jul 3, 2023 at 6:47
  • 1
    An assembler typically includes labels and equates and allows them to be referenced in instructions and directives. Perhaps they mean machine language as using mnemonic instructions but without labels?
    – ecm
    Jul 3, 2023 at 7:09
  • 7
    Unfortunately there is no (ISO or other) standard defining these terms. I'm afraid that the understanding depends not really on the community, but on the group of persons talking to each other. As such, this question might not be answerable satisfyingly. Jul 3, 2023 at 8:17
  • 2
    In my experience, there is no consistent use of those terms; different people use it differently. So I don't think you'll find any universally accepted definition anywhere.
    – dirkt
    Jul 3, 2023 at 9:22

3 Answers 3

23

That video probably tries to add a bit too much definition into blurry terminology, at least my opinion.

In fact, all three ways he describes are ways of creating machine code, and, at the same time, programming in assembly - He just uses different tools.

Classically, people used the term machine code to denote inputting hex (or, more rarely, decimal or octal) binary representations into a computer to generate programs. In order to determine what bytes make up the program, they would have used an assembler to make sense what the instructions actually are.

Here, it doesn't really make a difference whether you make up the instructions in your head, on paper, or in a text file that's run through a program - Somehow, everyone building a machine code program tends to think in assembly language, whether the actual translation takes place in a computer (the "assembler") or in your head doesn't make much of a difference (the latter one simply takes up more calories...). While I still remember that "0c9h" is "ret" on a Z80 and will probably never forget, most of the other opcode-to-instruction translations were forgotten once I used assemblers regularly - and is probably useless knowledge today anyhow. More complicated Z80 instructions (like LD A, (IX+7), for example), I never even tried to "head-assemble".

So, in my mind, you're always programming in assembly, regardless of whether you use your in-built (gray-matter), notes on paper, a machine code monitor, or an external (silicon-based) assembler. If you're simply inputting hex numbers from somewhere, well you're not programming.

Unless you're doing very weird stuff like self-modifying code (somewhat low on that scale, at least on 8-bit CPUs) or jumping into the middle of another multibyte instruction to have the CPU re-interpret already existing code (pretty much top of weirdness scale). These "dirty tricks" would be very much discouraged today and would probably be considered rather a "puzzle than a program" because they lead to heavily un-readable code. Back in the day, they were, however, relatively more common. But even then, you would have thought in assembly, and rather have the opcodes as a second thought "overlay".

9
  • 1
    I'm going to guess ld a, (ix+7) is 0ddh 07eh 007h.
    – Neil
    Jul 3, 2023 at 13:02
  • @Neil I'm going to guess: You cheated ;)
    – tofro
    Jul 3, 2023 at 15:05
  • 6
    Sadly when I was a kid I used to hand assemble large programs which I would run on my ZX81 and later ZX Spectrum, so no cheating necessary. I eventually wrote my own assembler, although obviously did I have to assemble it by hand first...
    – Neil
    Jul 3, 2023 at 17:07
  • 3
    @Neil Nothing sad about that, that's real nerd cred! I wrote numerous disassemblers on my Speccy but always in BASIC and never wrote a disassembler. Of course I never had any storage other than cassette tape so every crash was s.l.o.w. Jul 4, 2023 at 5:18
  • 2
    Hell0 W0rld! scored by ASCII values was scored based on the byte values of the machine code (since that's the "language" I answered in), so that was a case of thinking about the byte values while making programming choices. Determine your language's version involved knowing how stuff decoded in different modes, and Find an Illegal String required knowing about instruction-encoding details. Jul 5, 2023 at 12:39
13

An assembler actually does two important but separate things to help the programmer. One, which you mentioned, is to convert instruction mnemonics into opcodes, based on the addressing mode (e.g., LDA #3 to A9 03 or LDA $1005 to AD 05 10—note the different opcodes for loading an immediate value versus loading a value from a memory address).

But the other, which actually saves a lot more work, is to assign addresses to code and data and do address calculations based on those assignments. So in the following example:

        ORG $1000

        LDX #$FF
loop:   STX myvar
        DEX
        BNE loop
        RTS

myvar   DB  $00

the assembler is calculating the addresses which the programmer refers to as loop and myvar, so that the programmer doesn't have to do this himself. In this example, loop will be at $1002 and myvar will be at $100A, but both of those would change if the programmer added another instruction between the start of the program and loop. Further, some of the calculations are not as easy to do as the one above: the BNE loop is translated to D0 FA where the FA is a negative offset from the start of the location after the BNE and its argument.

So 8-Bit Show And Tell making a distinction between:

  • assembly: computer-calculation of addresses and opcodes (STX myvar);
  • machine language: hand-calculation of addresses with mnemonic translation (STX $100A); and
  • machine code: hand-calculation of addresses and opcodes (8E 0A 10).

Because this three-part distinction isn't so often made, many people use "machine language or machine code" interchangeably for the last one, or perhaps either of the two. The middle one is sometimes referred to as a form of "assembly": on the Apple II with original ROMs, for example, you use the "mini-assembler" for that. Given what 8-Bit Show and Tell is trying to demonstrate, I find his terms reasonable; he just would have done better to explain that when using a "full" assembler, it's not the mnemonic translation that (though useful) is the most important thing, but the address assignments and calculations.

8
  • 3
    I've definitely heard the term "symbolic assembler" which makes it seem like that was an improvement over previous assemblers at some point? I suppose the next advance after that would've been the "macro assembler", which is surely a more common term. True though when I used to hand assemble Z80 code, getting the offsets right hurt my head in a way opcodes never did. Jul 3, 2023 at 11:32
  • 3
    @hippietrail Yes, I've heard the term "symbolic assembler," too, implying that earlier there were "non-symbolic" assemblers. But by the 1970s no serious developer would have accepted an assembler that did not equate labels and addresses and do address calculations; it would have been very little improvement over programming directly in machine code.
    – cjs
    Jul 3, 2023 at 11:36
  • 5
    I've got a moderate amount of experience programming directly in machine code on 6502 and 6800, and as you start working with things like A9 03 versus AD 0A 10 you fairly quickly memorise the opcodes for the various different addressing modes for the instructions you commonly use; it's the address calculations that really are most of the work.
    – cjs
    Jul 3, 2023 at 11:36
  • 2
    @hippietrail yes, symbolic assemblers were an important step, but it was as well a step already taken with the very first what assemblers that lifted programming from code. Regarding micros, it may help to remember that their development happened after the assembler word was already way past those baby steps.
    – Raffzahn
    Jul 3, 2023 at 13:03
  • 2
    Symbolic assemblers also helped cleaning up code: Without them, you would really hesitate inserting or deleting code somewhere and having to go through the chore of re-calculating all jump targets - You'd rather patch some jump to the end, place your extension code there and jump back.
    – tofro
    Jul 3, 2023 at 18:24
5

Short Answer:

He 'adapts' his own terms to distinguish between the different 'styles' of programming he wants to show in this video.


Long Answer:

There is No Simple Answer

Well, as so often in real life terms are used overlapping and interchangeable depending on point of view as well as on upbringing, meaning what terms one was exposed to first (*1). Any answer will thus have a hard stand to provide definitive guidelines. Even more when, like here, terms are crafted in a way to bring forth the narrative of different levels of low level programming.

But what can be done is taking a step back and look at the logic behind terms used and their relation:

Look at the Beautiful Words

  • Machine

    Back when computers were devices of sensible size Machine was an all encompassing term without much separation between parts. What historical and in this context is a machine is nowadays rather called a CPU.

  • Assembler

    An Assembler is a generic term for a tool to write programs with high control over the resulting binary. Like most tools it needs as input information about what it has to create, plus directions how to do it.

    For the definition of an Assembler it does not matter how comfortable it supports program generation but only that it does not act on code level.

  • Code

    The (more or less) binary representation of what a CPU (should) execute. No matter if human readable or not.

One and a Half More:

To complete the list and look at the relations, we may have to add another term:

  • Instruction Set

    The collection of all instructions a given CPU can execute ('understand').

The instruction set may be the single most important term here, as it's what all this is about, all the other set the stage to debate the instruction set.

An instruction set is CPU specific and documented in an often big manual. Each instruction initiates some workings and is (usually) named accordingly. Let's take the beautiful /370 instruction Compare Double and Swap a staple in concurrent programming. While the name is mostly self explanatory, and a one on one relation to what the CPU can do, it's rather unwieldy in common use, so a very important intermediate step is added:

  • Mnemonics

    Instead of saying Compare Double and Swap, CDS can be used as a more compact term.

Sounds at first like a big word for what otherwise is known as an abbreviation to step down from lengthy word clouds to short synonyms - except, it wasn't developed as such, but the other way around: As a step up to name code items (in this case X'BB') in an easy to memorize way. Coming from Greek Mnemonika for (human) memory.

It's Full of Stars

With above terms one can easy see that in everyday language a lot of overlapping usage can be found - all depending what to say.

For a more exact usage one can go along a few guiderails:

  • Assembly Language per se does not exist.

It is, for the ISA part, always tied to a specific CPU with its specific instruction set and (usual) specific syntax - no matter if an assembler is made for a single CPU or multiple or configurable.

In addition the directives how to build a program with and beside the ISA are specific to the tool (Assembler) used. E.g. NASM and MASM as x86 assembler understand the same ISA but are not 1:1 compatible by differing how x86 instructions are controlled.

For being an assembler and thus assembler language it doesn't matter how great this additional support is or how much the programmer has to do on his own.

  • Machine Language is a sloppy every day term and usually used interchangeable with assembler language. It

  • Machine Code is when raw instruction representation is handled - by CPU or human.

So in the end, the language as well as the machine part in either terms are redundant - including their combination.


The Details

[...] he's using the C64 monitor "Supermon64" [...] I would consider this to be programming in assembly language.

Well, it is, and he even calls it so - right 9 seconds before your second link at 971:

"Now we can write our machine language program. And there is a simple assembler, non symbolic it's called, [...]. So we're going to assemble ..." followed by him entering the command A for assemble.

So he's very much is aware that he is using an assembler.

After all, noone would call Wozniak's Mini-Assembler for the Apple II anything other than an assembler - despite being even less confortable than Supermon's A command.

"when authors (or speakers) use both terms with intention, there's definitely a trend to using "machine language" to mean the mnemonic representation and "machine code" to mean the numeric/hex representation."

Which in turn would mean that machine language is the same as assembly language.

"The term "code" comes from the cryptic numbers that represent the machine instructions"

Code is a term used for any kind of formal, non casual information. No matter if it's about how pilots communicate or every generation creates their own youth language. Beside those numbers are not more cryptic to the general public than mnemonics - and not cryptic at all to anyone doing low level programming.


*1 - One may not go into a rant about home grown terms in the C64 community - except it wouldn't help any further for this.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .