COSMAC 1802 Subroutines

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
DELAY:      LDI     FFH
            PHI     R4
            PLO     R4
LOWLOOP:    GLO     R4
            SMI     01H
            PLO     R4
            BNZ     LOWLOOP
            GHI     R4
            SMI     01H
            PHI     R4
            BNZ     HIGHLOOP
            BR      RET_DELAY

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

Leave a comment

Your email address will not be published. Required fields are marked *