Introduction to COSMAC 1802 Subroutines
We use COSMAC 1802 Subroutines to execute a specific set of instructions. For example, we might have a subroutine that causes a delay every time we execute it. You could also have a subroutine that converts Celsius to Fahrenheit, or vice versa. We might call this subroutine several times through our code.
Branching will also jump to another location in memory. The problem with a simple branch, however, is that we don’t always know what location to go back to. When using code as a subroutine, we can always get back to where we left off in your main logic.
The COSMAC does not officially support a JSR, like you would see in other processors. It does, however, use a program counter to keep track of where it’s executing code. We can change the register on the fly that is acting as our program counter.
Your program counter will usually be at R0, but if we load a location into R3, for example, we can just switch the program counter to Register 3. The COSMAC will jump to that location.
When the subroutine finishes executing, it can just change the program counter back to R0. It will pick up where it left off. Before we do that though, we need to restore R3 to the original value. That way, the next time the program runs, R3 will already be set to the correct address that we need to jump to.
Let’s take a look at how we would do this:
Code Example for COSMAC 1802 Subroutines
Consider the following code:
R3 EQU 3 R4 EQU 4 ORG 8000H LOAD R3, DELAY START: SEQ ; TURN ON Q SEP 3 ; EXECUTE DELAY REQ ; SHUT OFF Q SEP 3 ; EXECUTE DELAY BR START RET_DELAY: SEP 0 DELAY: LDI FFH PHI R4 PLO R4 HIGHLOOP: GHI R4 LOWLOOP: GLO R4 SMI 01H PLO R4 BNZ LOWLOOP GHI R4 SMI 01H PHI R4 BNZ HIGHLOOP BR RET_DELAY END
Right after we declare R3 and being equal to 3 (for clarification), we load the address of our delay loop into R3. After that, we turn on Q with the SEQ instruction.
At this point, we set the program counter to 3. Keep in mind that R3 now contains the address of our delay loop. Therefore the COSMAC jumps down and executes a delay. This loop is 2 levels deep to give us plenty of delay. After the processor executes the loop, it will run to RET_DELAY. This advances R3, and now the program counter is back to 0. The processor resumes where we left off in the main code.
The reason we put the “SEP 0” instruction above the loop is so R3 will be reset to the top of our delay loop. We need to do this before we switch the program counter back to 0. Basically, this program will turn your Q output on for one second. Then, it shuts Q off for about a second. Obviously, for less of a delay, you would lower the values in the delay loop. A lower value means the processor does not need to loop as many times. Your program becomes faster.
Remember, the only purpose of the delay loops is to keep the processor busy for a certain amount of time.
Summary of COSMAC 1802 Subroutines
Although there is no jump to subroutine instruction in the COSMAC, we can emulate this. We just switch to a different program counter that already contains the starting address of your subroutine. Common practice is to place the SEP 0 just before the subroutine executes. When the subroutine finishes, it jumps back to the SEP 0 instruction to reset the subroutine’s program counter. We can now call this delay routine from anywhere in the program without forgetting where we left off in the main logic.
For more information, visit the COSMAC Category Page!
— Ricky Bryce