Machine Code vs Assembly and the difference on a C64


If you wonder what the difference between the terms Machine Code vs Assembly Language is, especially on a C64, you could be surprised. Well, at least a bit.

In General, Assembly Language is a low level programming language that is translated into Machine Code by an Assembler. Machine Code itself consists of binaries and is executed directly by the machine. On a C64 however, the term Machine Code is also used as a substitute for Assembly Language.

The following article gives you examples of Assembly Language and Machine Code. It also explains why the terms Machine Code and Assembly Language are interchangeable on a C64.

Machine Code vs Assembly Language Examples

Machine Code and Assembly Language differ obviously in its syntax. Besides this, there is another distinction between the two. The assembler language example can be valid on different machines, like the C64 or the Apple II. The Machine Code is only valid on a specific instruction set like the one of the CPU 6510. The reason for that is because an assembler on the would translate the instructions into the CPU 6510 Machine Code on the one machine and into CPU 65816 Machine Code on another machine. It is therefore hardware dependent.

The best way to understand the differences between Machine Code and Assembly language is by example. Imagine that you would want to add the numbers 2 and 3 on a Commodore 64. As a Assembly Language programmer would then come up with something like the following:

Now an assembler translates this code into the Machine Code. An processor instruction in Machine Code is called Opcode (which short for Operation Code). The CPU 6510 knows 256 Opcodes, but only 151 of them are officially documented and reliable. So the Opcodes for the instructions above are the following:

What if we change the Assembly Language example just a bit. Instead of loading and adding in immediate addressing mode, we load these numbers from a memory address. We also write the result in a Zeropage address.

The mnemonics of the assembly instructions did not change. But now look exactly what we get as Machine Code for this example:

The Opcode for clc stays the same, but the other ones changed. There are clearly different Opcodes for the “same” Assembly Instructions.

Opcodes and Addressing Modes

Why does the same operation have several codes, although there is just one corresponding Assembly instruction. The truth is that although the mnemonic is the same, the format also changes for the different addressing modes. These different addressing modes lead to different storage sizes and to a different number of cycles.

Illegal Opcodes are undocumented commands that exist as a side-effect of the hardwired circuit design. They are called “illegal” because they are not guaranteed to work reliably. (Definition is taken from C64-Wiki)

Size matters, especially on a C64 where you are out of space in just a blink of an eye. Every operation has a size in bytes and sometimes the developer has to be creative to save some bytes by clever usage of assembly instructions.

The same is true for speed. Generally you want your programs to run fast. Every instruction needs a certain number of cycles for the CPU. The less cycles it needs, the faster the program will run because the CPU needs less time to actually do the operations.

Let’s take assembly instruction STA as example. Its purpose is to write the content of the Accumulator into a memory address. Depending on the addressing mode, there are seven different opcodes:

OpcodeAddressing ModeAssembler InstructionSize in BytesNumber of Cycles
$8DAbsoluteSTA nnnn34
$9DAbsolute, XSTA nnnn, X35
$99Absolute, YSTA nnnn, Y35
$85ZeropageSTA nn23
$95Zeropage, XSTA nn, X24
$81Indexed IndirectSTA (nn, X)26
$91Indirect IndexedSTA (nn), Y26
Different Opcodes for STA Assembly Instruction

Machine Code vs Assembly Language Summary

The following is a quick summary of the content we have covered so far.

Machine CodeAssembly Language
Operation Codes that are understood by the CPULow-Level Programming Language that has to be translated
Contains of binaries which can be represented by HexadecimalsUses mnemonics which are abbreviations for words from the english language
Harder to read for humansBetter human readability
Depends on the platform or operation systemStandard instructions are understood by many systems
Directly executed by the CPU to perform the task at handTranslated (assembled) into Machine Code by an Assembler
Summary of differences Machine Code vs Assembly Language

It is possible for a developer to write a program directly in Machine Code. But the fact that this would only be valid on one specific instruction set, paired with much less human readability, renders this possibility obsolete.

Why do they call it Machine Code on a C64 although it is Assembly Language

It is the year 1983 and you want to write a program on the C64, which options do you have? The correct answer is two, you can write BASIC code or you can write Machine Code. Commodore decided to call it that way, regardless if you put the machine code itself directly into memory or if you use an assembler to generate the machine code. The community of that time adopted the terminology and so it is until present day.

Another Fun Fact: According to the book On The Edge: The Spectacular Rise and Fall of Commodore, the KERNAL of the C64 (and other Commodore machines) is called that way because the engineer Robert Russell misspelled the word Kernel in his notebooks. The technical writers took these notebooks as basis for the VIC-20 Programmers Manual. Since then it stuck within the community.

Marco Lieblang

Professional Programmer since 2003, passionate Programmer since the mid 90's. Developing in many languages from C/C++ to Java, C#, Python and some more. And I also may know a bit about Assembly Languages and Retro Systems.

Recent Posts