LMC Machine Level Programming
Machine level processing of instructions involves a systematic and almost mechanical repetition of actions.
Sample Program Execution
Initial Values and Program Dump
- Counter:00 Calculator:472 (random/garbage value)
-
Maibox Number | Mailbox Contents |
00 | 500 |
01 | 211 |
02 | 500 |
03 | 212 |
04 | 111 |
05 | 412 |
06 | 600 |
07 | 700 |
08 | 792 |
09 | 543 |
10 | 081 |
11 | 000 |
12 | 998 |
etc. | etc. |
Step-By-Step Execution
- first instruction cycle
- the "little man" reads the Counter (00), goes over to Mailbox number 00, and reads the contents of that Mailbox (500)
- the "little man" pushes the increment button on the Counter (so it now reads 01)
- comparing the first digit (5) of the number he just read from the Mailbox, the little man discovers that he is to "Input", so
he goes over to the Input basket, reads whatever number was left there by someone outside the computer room, and then goes to the Calculator and enters that number
- second instruction cycle
- the "little man" reads the Counter (01), goes over to Mailbox number 01, and reads the contents of that Mailbox (211)
- the "little man" pushes the increment button on the Counter (so it now reads 02)
- comparing the first digit (2) of the number he just read from the Mailbox, the little man discovers that he is to "Store", so he reads the value currently on the Calculator and then goes over to Mailbox 11 (as indicated by the last 2 digits of the instruction he just read) and replaces the number in Mailbox number 11 with whatever value he just read from the Calculator
- third instruction cycle
- the "little man" reads the Counter (02), goes over to Mailbox number 00, and reads the contents of that Mailbox (500)
- the "little man" pushes the increment button on the Counter (so it now reads 03)
- comparing the first digit (5) of the number he just read from the Mailbox, the little man discovers that he is to "Input", so
he goes over to the Input basket, reads whatever number was left there by someone outside the computer room, and then goes to the Calculator and enters that number
- ......and so on
Encoding a Simple, Linear Program
LMC Flow Control Instructions
Flow control instructions enable machine level execution to perform the standard selection and repetition sequences.
The ability of the LMC to perform non-sequential logic flows is dependant upon the following instructions
- 9xy (JMP xy) which uncoditionally changes where the "little man" will go to look for the next instruction
- 801 (SKZ) which causes the "little man" to ignore the next instruction (typically a JUMP)
and continue processing with the one following it, if the Zero Indicator is "on".
By subtracting one number from another number, this instruction will then enable us to
determine if the two numbers were equal.
- 800 (SKN) which works like the SKZ instruction except that it uses the Negative Indicator. Following a subtraction, this enables testing to determine if the second value was greater than the first.
- 802 (SKP) ...note that despite the 'P" for positive in this mnemonic, the "skip" is performed for this operation if either the Positive or the
Zero Indicator (or both) are "on". SKP is the opposite of SKN and as such is a convenience instead of a necessity since the same effect could be acheived by a suitable combination of SKN and JUMP instructions.
Note that the "skip" instructions do not supply a mailbox to "skip to"; they simple
skip over the next instruction (which is almost always a "jump").
Symbolic Labels
In the same way that mnemonic codes make it easier to write (and think about) instructions,
"symbolic labels" make it easier to work with mailbox addresses. Instead of coding
numeric addresses, it is usually easier to use label "names"; of course, for this to work,
any label "name" which is used in an instruction must be defined as being the identifier
("symbolic label") for a mailbox containing either an instruction or a data value.
IF...THEN...ELSE...ENDIF (Selection)
| LDA val1 | // replace val1 with Mailbox number of first value |
| SUB val2 | // replace val1 with Mailbox number of second value |
| SKZ | ' to test for equality (for example) |
| JMP not_eq | // replace not_eq with Mailbox number of beginning of ELSE block |
| ------- | //--- THEN block |
| ------- | |
| JMP endif | // replace endif with Mailbox number of end of If structure |
not_eq | ------- | //--- ELSE block |
| ------- | |
endif | ------- | // first statement after If structure |
| ------- | |
| ------- | |
val2 | | |
| ------- | |
val1 | | |
| ------- | |
|
WHILE...DO...ENDWHILE (Repetition)
while | LDA var1 | // replace var1 with Mailbox number of first variable |
| SUB var2 | // replace var2 with Mailbox number of second variable |
| SKP | // for example, testing While var1 >= var2 |
| JMP endw | // replace endw with Mailbox number of first instruction after While structure |
| ----- | // ---body of DO |
| ----- | // --presumable contains code to chane either var1 or var2 |
| JMP while | // replace while with Mailbox number of beginning of this structure |
endw | ------ | |
| ------- | |
| ------- | |
| ------- | |
var1 | ------- | |
var2 | ------- | |
|
Sample Program
Statement of Problem
Input two numbers and output all integer values between these two numbers.
Pseudo-Code of Solution
- Input first number as (assumed) smaller
- Input second number as (assumed) larger
- IF larger < smaller
- --- exchange larger and smaller values
- END_IF
- Add 1 to smaller
- WHILE smaller < larger
- --- Output smaller
- --- Add 1 to smaller
- END_WHILE
- Stop
Mnemonic Code Solution
| IN | |
| STO small | |
| IN | |
| STO big | |
| LDA big | |
| SUB small | |
| SKN | // need to exchange |
| JMP ok | // small and big right way around |
| LDA small | // exhange |
| STO temp | |
| LDA big | |
| STO small | |
| LDA temp | |
| STO big | |
ok | LDA small | // add 1 to small |
| ADD one | // constant |
| STO small | |
while | LDA small | // redundant but safe |
| SUB big | |
| SKN | // still smaller |
| JMP endw | // not smaller any more |
| LDA small | // display small |
| OUT | |
| ADD one | // add 1 to small |
| STO small | |
| JMP while | // loop back |
endw | HLT | // stop |
one | DAT 001 | // defining a constant |
small | DAT | // space for data value |
big | DAT | // space for data value |
temp | DAT | // space for data value |
|
Notice the use of the pseudo (that is "not real") mnemonic: DAT to
permit the reservation (and possible initialization) of space for data values.
Subroutine and Function Calls
All practical computer processors provide some method, at a low level,
for using subroutines and functions. Unfortunately, the Little Man
Computer is not a "practical computer processor". We could, however,
imagine a more advanced model of the LMC, the "son of LMC" which would
provide such support.
There are many different ways this support could be implemented even
within a computer architecture as limited as the LMC. Note that
a significant problem in implementing additional instructions to
"call" and "return" from a subroutine involves the fact that almost
all the numeric instruction code values have been used up. It is
possible however to "squeeze" this subroutine handling ability in.
The method described below is by no means "standard" but it will provide the
necessary capabilities.
We will assume that our modified "son of LMC" has an additional
instruction "CALL xy" with a numeric form "0xy". This CALL
instruction will behave very much like the JMP instruction except
that before changing the counter, it will save the contents of
the counter plus "900" (that is a JMP to the counter contents
address) in the mailbox immediately before "xy" (that is in the mailbox
with address xy-1). Notice that at the time this "save" is done, the
counter will already have been incremented and will contain the address
of the instruction serially after the CALL.
Subroutines will always be coded to allow for a mailbox location
immediately before the first instruction of the subroutine. When a
subroutine has finished processing requirements, it will JMP to
that "prefix" mailbox which will, in turn, contain the JMP
instruction (provided by the CALL) back to the instruction
immediately following the CALL.
Example:
MODULE | BOX | LABEL | OPCODE&OPERAND | MACHINE |
Main program | 00 | | IN | 500 |
01 | | CALL RTN | 006 |
02 | | IN | 500 |
03 | | CALL RTN | 006 |
04 | | HLT | 700 |
Sub- rou- tine | 05 | | DAT | 000 |
06 | RTN: | STO X | 210 |
07 | | ADD X | 310 |
08 | | OUT | 600 |
09 | | JMP RTN-1 | 905 |
10 | X: | DAT 000 | 000 |
Label Table |
LABEL | MAILBOX |
RTN: | 06 |
X: | 10 |
The CALL RTN (006) in mailbox 01 will change the contents of mailbox
05 (05 being the mailbox immediately before 06) to contain "902" (a
JMP to the mailbox after this CALL), and then it will change
the contents of the counter to contain "06". The next
instruction to be performed will therefore be the one in mailbox 06.
When execution reached the JMP RTN-1 (905) in mailbox 09,
execution of this instruction will cause the counter to change to 09.
Therefore the next instruction to be performed will be the "902" placed
in mailbox 05 by the earlier CALL RTN. The next instruction
after this will then be the one in mailbox 02, the second IN.
After the second IN, a second CALL RTN is performed, but
this time the contents of mailbox 05 are changed to "904", a JMP
to the instruction following this second CALL RTN.