Skip to content

The Program Is Not What Runs

Source is what we write. Machine code is what a processor executes. Follow assembly, compilation and interpretation from one to the other.

  • Foundations

Here is a program in our teaching notation:

Code
LET score = 0
LET score = score + 10
SHOW score

We can follow it: start the score at zero, add ten, show ten. A processor has no instruction called LET score = score + 10. Software must turn that request into work the processor knows how to do.

Source, machine code and the tools between them

Source code is the program we write and edit. It might be BASIC, C or assembly. Assembly source uses names for processor instructions; it is still source.

Machine code is instructions encoded as bytes for a particular kind of processor. The processor fetches those bytes, decodes the instructions and performs them. Code is native to a processor when it uses that processor’s instruction set: Z80 machine code is native to the Spectrum’s Z80.

Both source text and machine code are stored as bytes. So are pictures and sound. Being stored as numbers does not make something machine code. What matters is whether the bytes are being used as processor instructions or read as data.

There are several ways to get from our source to a running program:

Route What the tool does What the processor executes
Assembly source → assembler → machine code Encodes the instructions we selected. The resulting machine instructions.
Higher-level source → native-code compiler → machine code Chooses instructions to implement the operations we described. The resulting machine instructions.
Stored program → interpreter Reads the program and carries out its operations while it runs. The interpreter’s machine instructions, including routines it calls.

Compilation is a process; native machine code can be its result. Compiled code and native code can describe the same program. An assembler and a native-code compiler can both produce instructions for the same processor. The processor does not need to know which tool produced them.

An interpreter is a program too. Its machine instructions do the work of reading our program, finding variables, calculating results and so on. The processor executes the interpreter while the interpreter reads our program as data.

We will examine interpretation in Unit 2 and translation before execution in Unit 3. First, a tiny invented machine lets us see source and instructions side by side.

A machine small enough to see

Real instruction sets contain many operations. To see the idea, we want one with three.

Imagine a machine with a single box in it, starting at 0, and three things it knows how to do:

Name Number What it does
INC 1 add one to the box
DOUBLE 2 double the box
SHOW 3 show what is in the box

The names on the left are for you. The numbers in the middle are what the machine runs. It has never heard of INC. It knows that when it sees a 1, it adds one.

Here is a program for it:

Code
INC
INC
DOUBLE
SHOW

Add one, add one, double it, show it. The box goes 0, 1, 2, 4, and the machine shows 4.

And here is what the machine runs:

Code
1 1 2 3

Those are the same program. The top one is for reading. The bottom one is for running. An assembler can translate the names into these instruction codes before we run them. These are invented codes for our model, not Z80 instruction bytes. On a real target, we must use that processor’s actual encodings.

The names are made up

Those three names belong to no real machine. We invented them so that nothing here depends on which computer you end up with.

When you meet a real machine, it will have names of its own for its own instructions, and real numbers behind each one. The idea will be exactly this. Only the table gets bigger.

Check what the bytes mean

If we store the letters INC as character codes, have we assembled our tiny program?

Are character codes instructions?

No. Our model expects instruction code 1 for INC. Character codes record the letters of its name. A translator or interpreter needs to read those names; storing them as bytes does not perform that job.

What changes between the routes?

We need to ask two questions: what does the tool produce, and what work remains when the program runs?

An assembler can produce our tiny machine’s instructions in advance. An interpreter could instead read each name and perform its operation as it reaches it. Both can show the same answer. The second route includes work to read and handle the stored program during execution.

That difference can affect speed, but it does not settle which game will run smoothly. The instructions, calculations, drawing and hardware all matter.

When it’s wrong, see why

  • You gave the processor source text. It cannot treat those letters as the instructions you intended. The source needs a translation tool or an interpreter.
  • You gave our tiny machine instruction 4. We have defined only 1, 2 and 3. Our model has no rule for 4; real processors have their own rules for unsupported instruction codes.
  • You found source text in memory. Editors and interpreters can keep it there. Its presence does not mean the processor executes the text as instructions.

What you’ve learnt

  • Source is what we write and edit, including assembly source.
  • Machine code encodes instructions for a processor; source is stored as bytes too.
  • Assemblers and native-code compilers can both produce machine code.
  • An interpreter executes as machine code while reading our program as data.

What’s next

In Unit 2 we follow the interpreter through a loop and see which work it repeats. Spectrum BASIC gives us a real example of that route.