Loading a program from tape - Part 3: Loading the Absolute Loader
This post describes the process by which the bootstrap loader loads the absolute loader. It is part of a series of posts, so it won't make much sense unless you read Part 1 and Part 2 first.
The code of the absolute loader is read byte-by-byte by the bootstrap loader and placed into memory. For the purposes of explaining the loading of the absolute loader, I will distinguish three parts to the process of loading the absolute loader, which I refer to as the beginning, the middle and the end.
The first part of the loading process sets up the address into which the absolute loader will be loaded. Here are the first few octal values of the absolute loader:
351 351 351 075 000 000 306 021 246 051
Note that the first three octets have the same value, 351. This is called the tape leader. Let's take a look at what happens when these bytes are read in.
The key thing to watch when figuring out the operation of the bootstrap loader is the value contained in memory address "157752", which is the address offset, added to the base value of "157400", to determine the location to store the byte read from tape.
Initially this has the value 352, so when the first byte is read from tape (octal 351), the value is stored in the location 157752 (which is 157400 + 352). In other words, the value 352 at address 157752 in the bootstrap loader program is overwritten with 351. After reading and storing a value, the next instruction in the bootstrap loader program increments the value at address 157752, restoring the value to 352 again.
The same cycle is repeated for the other two leader bytes.
The next byte (octal 075) is read in and replaces the value 352 at address 157752. After reading and storing the value, the next instruction in the bootstrap loader increments the value at address 157752, resulting in the value 76. At this point, the operation of the bootstrap loader changes.
The next byte is read in (octal 000) and stored at address 157476 (which is 157400 + 76). The value at address 157752 is incremented and now has the value 77.
The next byte is read in (another octal 000) and stored at address 157477 (which is 157400 + 77). The value at address 157752 is again incremented and now has the value 100 (octal remember!).
We have now read in one full instruction; address 157476 contains the word "000 000", which is the HALT instruction.
Notice when we read in the two bytes that made up the HALT instruction, the bytes are read in little endian order. In other words, the least significant byte is read in first and the most significant byte second.
Let's do one more example. Remember that the value in 157752 is now 100.
The next byte read in is octal 306. This is stored at address 157500 (157400 + 100) and the value at 157752 is incremented to 101. The next byte read in is octal 021, which is stored in address 157501, and the value in 157752 is incremented to 102.
We have now read in another full instruction. Let's work out what it is.
We read 306 (binary 1100 0110) into the low byte and 021 (0001 0001) into the high byte. Merging these into a single word in binary, and arranging into sets of three bits we get "0 001 000 111 000 110", which in octal is 010706.
The first two octal digits ("01") represent the MOV instruction. The source operand can be found in the second two octal digits ("07"), which represents register 7, or the PC. The destination operand is found in the final two octets ("06"), which represent register 6, or the SP.
In summary, this instruction is "MOV PC, SP".
This process is repeated for almost all of the remaining bytes on the paper tape, representing the middle section of the loading process. The last few bytes have a different meaning, which will be discussed in the final section.
Skipping ahead to the last few bytes in the absolute loader, we find:
301 035 026 000 302 025 373 353 000 000 000 000 000
At this point in the load, the value in memory address 157752 is 344, which means that the next byte will be written to address 157744 (which is 157400 + 344). Note that this address overlaps with the memory location where the bootstrap loader is stored, so these remaining bytes are going to overwrite some of the bootstrap loader.
301 035 026 000 302 025
These six bytes represent three word instructions that will overwrite the first three words of the bootstrap loader as follows:
157744 016701 157776 000026 157750 012702
If you refer back to the listing of the bootstrap loader program you will see that these are identical to the first three words of the bootstrap loader, so these bytes are overwritten with identical values.
Having replaced these values, the value in address 157752 is now 352, meaning that the next byte value is going to be read into address 157752. So, the next byte, 373, is read in and replaces the value 352 at address 157752. The next instruction in the bootstrap loader then increments this value, increasing it to 374.
The bootstrap loader loops again and reads in the final byte, with the value 353. This value is stored at address 157774 (157400+374). This is the location of the branch instruction at the end of the bootstrap loader program.
If we take a look at the structure of the unconditional branch instruction, the high byte consists of the value 0000 0001 in binary and the low byte consists of the offset to branch by. The offset value is a signed 2's complement value so that branches can branch forward with a positive offset or backwards with a negative offset.
So, when the low byte at address 157774 is overwritten, the branch instruction remains but the offset is changed. The value 353 is a negative offset of -25, which means that the bootstrap loader will branch backwards by 25 words, to address 177724.
This is how the bootstrap loader infinite loop is ended.
Restoring the bootstrap loader
When control jumps out of the bootstrap loader loop, a couple of instructions are executed to restore the bootstap loader program so it can be used again if needed.
These are the instructions, starting at address 157724, that restore the bootstrap loader:
157724 012767 157726 000352 157730 000020 157732 012767 157734 000765 157736 000034 157740 000167 157742 177532
The first instruction:
157724 012767 157726 000352 157730 000020
replaces (with a MOV instruction) the value 352 into address 157752 which, as this code is executing is found at address PC+20.
The second instruction:
157732 012767 157734 000765 157736 000034
replaces (again with a MOV instruction) the value 765 into address 175774 which is found at address PC+34.
The final instruction is an unconditional jump:
157740 000167 157742 177532
The jump offset is found in the address 157742. It is a negative value, reflecting an offset of -246 (octal), which will jump to address 157476.
Halting and waiting
When control jumps to 157476, remember this was the very first instruction read from the paper tape, which was a HALT.
The processor now halts and waits for the operator to change the tape and insert the tape that will be loaded by the absolute loader program. When the operator has changed the tape, the press continue on the panel and the absolute loader program will execute and load the program from the tape.
The next post in this series will discuss how the absolute loader works.
The absolute loader tape file is essential if you are trying to recreate this behaviour.