Introduction to the COSMAC Processor Stack Operation
The COSMAC Processor Stack Operation will allow us to store data on the fly that we need to retrieve later. This will usually be an address contained in a register. Examples would be a program counter, or a memory location that contains data for a subroutine to operate on. Technically, we are really just emulating a stack in the COSMAC by the use of it’s existing instructions.
By default, the stack pointer is at register #2. On my CDP1802 unit, register 2 points to $FFD4 by default. We can change this. In this post, I’ll change this address to $9120. Be sure the stack pointer is high enough as to not interfere with your program. As we perform stack operations we will decrease, or increase this pointer. As we add data to the stack (push data), we’ll usually decrease this pointer. Likewise as we pull data from the stack (pop), we will increase the stack pointer. In other words, the stack operates from the top down.
In those post, we’ll perform several experiments to see the stack data, and the stack pointer.
Initial values for the COSMAC Processor Stack Operation
At this point, we’ll take a look at some of the registers. I’ve declared the following aliases at the beginning of each of these examples. Assume that these aliases are at the top of every project in this post.
STACKP: EQU 9120H
GPIO1: EQU 7000H
BREAK: EQU 2756H
org 8000H ;have to start somewhere ...
R0 EQU 0
R1 EQU 1
R2 EQU 2
R3 EQU 3
R4 EQU 4
R5 EQU 5
R6 EQU 6
R7 EQU 7
R8 EQU 8
R9 EQU 9
RA EQU 10
RB EQU 11
RC EQU 12
RD EQU 13
RE EQU 14
RF EQU 15
At this point, let’s enter some simple logic to see what the initial value of the stack pointer is. It’s important to realize that I’m using the COSMAC CDP1802 Microprocessor kit. The break routine will store the values of each register to a memory location where I can access their values. I can only access scratchpad registers R3 to RF (R15), though. So let’s just load the value of Register 2 into register 3. Remeber, Register 2 is our Stack Pointer. After that, we’ll break, and see what the value of register 3 contains. Additionally, we’ll take a look at the memory locations in the vicinity of the cell the stack pointer points to.
LOAD R2, STACKP
START: GLO R2
PLO R3
GHI R2
PHI R3
LBR BREAK
END
Remember each scratchpad register is 16 bits wide. Since this is an 8 bit processor, we will move 8 bits at a time (1 byte).
With this code, we’ll load STACKP into R2. Remember, this is $9120. Next, we’ll get the low byte of the stack pointer (R2) with the GLO (Get Low) instruction. We place that into the low byte of R3 with the PLO (Put Low) instruction. Likewise, we get the high byte of R2, and place this into the high byte of R3.
I’m going to use the A18 assembler to convert this code to an Intel Hex file. After that, I’ll send the file to the unit. Keep in mind that we need to connect to our processor through a terminal for this. The character and line delays are at 10ms.
Here is the output of the assembler in Intel hex file format:
:0D800000F891B2F820A282A392B3C02756D7
:00800D0172
At this point, I’ll run the code, and see what our initial values are:
Register 3 contains the value of the stack pointer, which is currently at $9120 (Copied from R2).
Now, let’s look at the values in the vicinity of this address:
$911C FF
$911D FE
$911E EF
$911F 0F
$9120 00
$9121 FB
As you can see, this is basically random data.
Pushing a Register onto the Stack
At this point, let’s modify our program. We’ll start by loading register RE with GPIO1. Recall from our aliases at the top of this post that GPIO1 resides at address $7000. We’ll do this by using the STXD instruction. This will store data to the stack, and decrement the stack pointer. Remember, each register contains 16 bits of data. Our memory locations, however, are only 8 bits. Therefore, we’ll need to do this in 2 steps.
Let’s look at our code:
LOAD R2, STACKP
LOAD RE, GPIO1
START: GHI RE
STXD
GLO RE
STXD
GLO R2
PLO R3
GHI R2
PHI R3
LBR BREAK
END
:17800000F891B2F820A2F870BEF800AE9E738E7382A392B3C02756EF
:0080170168
As you can see, at first, we are loading register RE with GPIO1 ($7000). After that, we get the high byte from register RE. Then we store this to the stack, and decrement the stack pointer. We do the same thing with the low byte. At this point, we’ll load register R2 into register R3, so we can see what location the stack pointer is at.
Once again, I’ll send this code to the processor, and we’ll see where our values are.
Register R2, our stack pointer is at $911E. Decreased by 2
$911C FF (UNCHANGED)
$911D FE (UNCHANGED)
$911E EF (UNCHANGED)
$911F 00 (LOW BYTE OF RE)
$9120 70 (HIGH BYTE OF RE)
$9121 FB (UNCHANGED)
As you can see, we load the high byte first (70H), and decrement the address in R2. Then we load the low byte to the stack, and decrement the pointer again. At this point, the stack holds the current value of RE. I’ve heard of a bug in the 1802 processor where STXD does not decrement the pointer, but I’m not seeing this bug happen here.
Popping a Value from the Stack
At this point, we’ll pull (pop) the register address from the stack. To demonstrate, we’ll place this value into register (RF). Before we begin, we need to execute the IRX instruction. This advances the stack pointer to where the data is. Let’s see what happens to the stack pointer when we use this instruction:
LOAD R2, STACKP
LOAD RE, GPIO1
START: GHI RE
STXD
GLO RE
STXD
IRX
GLO R2
PLO R3
GHI R2
PHI R3
LBR BREAK
END
:18800000F891B2F820A2F870BEF800AE9E738E736082A392B3C027568E
:0080180167
As you can see, the stack pointer was copied into R3, and is currently at $911F, which is the beginning of our data.
At this point, we’ll execute the LDXA command, and LDX. LDXA will pull data from the stack, and advance the stack pointer. When we pull the high byte from the stack at $9120, we are at the top of the stack. We do not need to advance the pointer beyond this, so we just use the LDX command.
Let’s add these commands, and re-run our logic.
LOAD R2, STACKP
LOAD RE, GPIO1
START: GHI RE
STXD
GLO RE
STXD
IRX
LDXA
PLO RF
LDX
PHI RF
GLO R2
PLO R3
GHI R2
PHI R3
LBR BREAK
END
:1C800000F891B2F820A2F870BEF800AE9E738E736072AFF0BF82A392B3C02756BA
:00801C0163
At this point, let’s take a look at our registers:
R3 contains $9120
RF contains $7000
The “Stack” contains the same values as before, however, since we’ve already recovered this data, we are free to overwrite it.
For more information, visit the COSMAC category page!
— Ricky Bryce