Introduction to COSMAC 1802 Subtract Instructions
COSMAC 1802 Subtract Instructions will subtract the accumulator (D Register) from an immediate value, or a memory location (or vice-versa) In this post, we’ll go over each of these instructions, and how you would use them in your logic. There are eight subtract instructions in the COSMAC:
- SD — Subtracts D from a memory location contained in a register that X desginator. (Memory – D)
- SDI — Subtract D from an immediate value (following the instruction) (Value – D)
- SDB — Subtract with borrow. Just like SD, but also subtracts the NOT of the data flag bit (DF). (Memory – D – (NOT DF))
- SDBI — Subtract with borrow (immediate). Just like SDI, but also subtracts the NOT of DF. (Value – D – (NOT DF))
- SM — Subtracts memory from D (Memory – D)
- SMI — Same as SDI, but the operands are opposite. (D – Value)
- SMB — Subtracts memory from D with borrow. Just like SDB, but again, we flip the operands. (D – Memory – (NOT DF). The memory location we get data from is contained in the register that X designates.
- SMBI — Subtracts an immediate value from D, and also subtracts the NOT of DF. (D – Value – (NOT DF)
It’s important to realize that after a subtract, if DF is true, then a borrow did not occur. In other words, when DF is true, the result is positive.
In this post, I’ll be using the A18 Assembler.
SD – COSMAC 1802 Subtract Instructions (Accumulator)
SD (Subtract D) Instruction
Let’s start with the SD instruction. Remember that SD will subtract D from a memory location. Remember, D is the accumulator in the 1802. The memory location that contains the data is in a register that the X designator points to. In the example below, we will load 8200H into the RF register. 8200H is the memory location that we want to subtract from. Our logic places 55H into this memory location.
At this point, we set the X designator to Register 15 (which is RF). After that, we load a 1 into the accumulator, and execute the SD command. The processor subtracts D from the data at memory location 8200H. As a result, we get a value of 54H. Finally, we’ll store the result to the accumulator. Then we will branch to the break routine that is in my ROM. If you don’t have a break routine in your ROM, just idle the processor with the IDL command.
MYMEMORY: EQU 8200H BREAK: EQU 2756H RF EQU 15 ORG 8000H LOAD RF, MYMEMORY ; Load RF with 8200H LDI 55H ; Place 55H into the accumulator STR RF ; then store the value of 55H to 8200H. SEX RF ; Designate RF in the X register. LDI 01H ; Load 01H to the accumulator SD ; Subtract D from 8200H (55H - 01H) STR RF ; Store the new result back to 8200H LBR BREAK ; Stop the program END
Take a look at the data at 8200H. You will see it is now 54H.
SDI (Subtract D from Immediate) Instruction
The SDI instruction subtracts the value of D from an immediate value. In other words, if the immediate value is larger than D, then the result will be positive. Let’s take a look at an example, so we can see how the SDI command operates.
I believe there might be a small error in the COSMAC manual for this instruction.. (At least the one I’m looking at). It operates off an immediate value, and not by a memory location indirectly specified by X as the formula states. Let’s take a look at some logic to verify it’s operation.
MYMEMORY: EQU 8200H BREAK: EQU 2756H RF EQU 15 ORG 8000H LOAD RF, MYMEMORY LDI 02H ; Load Accumulator with 02H SDI 55H ; Subtract the Accumulator from 55H. STR RF ; Store the result to address 8200H LBR BREAK END
Take a look at address 8200H. You will see the value is 53H.
SDB (Subtract D With Borrow) Instruction
When dealing with values larger than 8 bits, we will need to work with multiple bytes. Let’s consider 8200 to be our low byte, and 8201 is the high byte containing a value. We need to do our math on each byte at a time. First, we’ll perform a subtraction on the low byte. After that, we’ll do our subtraction with the high byte. Let’s say the low byte contains 00H, and the high byte contains 01H. Therefore, our starting value is 0100H. We will subtract 0001H from this value.
If we subtract 1 from the low byte (with SD), then we will have a borrow condition. Our DF (Data Flag) bit will equal 0. This is because the low byte went negative, and rolled over to FF. When we perform our math on the high byte, we need to consider this borrow condition from the low byte. With the SDB command we will subtract zero from the high byte, which contains 01H, and we also subtract the NOT (compliment) of the DF flag. Therefore 01H – 00H – (NOT DF) = 00H. Let’s outline this below:
16 bit source: 0100H
we will subtract 0001H
Look at the low byte first (right-most two digits)… This will be 00H – 01H = FFH due to rollover, and DF goes to zero.
Look at the high byte next (left-most two digits)… This will be 01H – 00H – ((NOT DF) (which is 1)) = 00H
Therefore our answer will be 00FFH.
Let’s take a look at the logic:
LOWBYTE: EQU 8200H HIGHBYTE: EQU 8201H BREAK EQU 2756H RE EQU 14 RF EQU 15 ORG 8000H LOAD RE, LOWBYTE LOAD RF, HIGHBYTE LDI 00H STR RE LDI 01H STR RF ; AT THIS POINT 8201 IS 01H, AND 8200 IS 00H (1000H) SEX RE LDI 01H SD ; SUBTRACT 1 FROM LOW BYTE, WE GET FF WITH BORROW (DF=0) STR RE ; STORE FFH TO RE SEX RF LDI 00H SDB ; SUBTRACT 01 - 00 - (NOT DF) = 0 (DF = 0) STR RF ; STORE 00H TO RF. LBR BREAK ; FINAL VALUE OF 8201 AND 8200 IS 00FFH END
SDBI (Subtract with borrow — immediate) — COSMAC 1802 Subtract Instructions
The SDBI instruction subtracts D from an immediate value. It also subtracts the NOT of the borrow bit (DF) In other words, if DF is high, then it will only subtract D from the immediate value. On the other hand, if DF is low, then the SDBI subtracts the accumulator (D) from the immediate value, and subtracts one more due to the borrow bit.
We usually use this instruction to subtract integers which are larger than 8 bits.
For example, let’s say the D register contains (01H) We want to subtract this from a 16 bit value of (0100H). When we subtract 1 from 00, we get an FF with borrow clear. Therefore, when we subtract the high byte with borrow, the high byte will be zero. (01H – 00h – 1) The value we end up with will span across 2 memory calls, and will be 00FFH.
This is similar to the SDB above, but with an immediate value instead of a register. Let’s look at an example:
Now, take a look at addresses 8200H and 8201H. 8201H contains 00, and 8200H contains FF. Your final number consists of 16 bits — 00FFH.
SM – COSMAC 1802 Subtract Instructions (Memory)
SM (Subtract Memory) Instruction
The SM instruction is very similar to the SD instruction above. However, it subtracts memory from the accumulator (D register) instead of the other way around. The memory location where we get data from is in a register designated by X. Therefore, we must make sure X has the correct designation. Here is an example of where we subtract 5H from 9H.
MYMEMORY: EQU 8200H BREAK: EQU 2756H RF EQU 15 ORG 8000H LOAD RF, MYMEMORY LDI 05H STR RF ; LOAD THE VALUE OF 05H INTO 8200H LDI 09H ; SET THE ACCUMULATOR TO THE VALUE OF 05H SEX RF SM STR RF ; STORE THE RESULT OF 04H BACK TO 8200H LBR BREAK END
Take a look at memory cell 8200h. You will see it contains the value of 04H.
SMI (Subtract Memory Immediate) Instruction
This instruction is fairly simple. Let’s say we have a value in the D register such as 08H. With the SMI instruction, we just specify what value to subtract from the accumulator. The result goes back into the accumulator, and we can store this somewhere else in memory. Here is an example where we subtract 5H from 8H:
MYMEMORY: EQU 8200H BREAK: EQU 2756H RF EQU 15 ORG 8000H LOAD RF, MYMEMORY LDI 08H SMI 05H STR RF LBR BREAK; END
Look at cell 8200H. You will find that the value is 03H.
SMB (Subtract Memory and Borrow) Instruction
At this point, we’ll take a look at the SMB instruction. This instruction will subtract a memory location from the D register. If DF=0, it will also subtract an additional count. Again, we usually will use this when we do math on large numbers. Larger numbers span across more than a single byte. Here, we’ll have six bytes, which will effectively be three 16 bit values. We’ll subtract value 1 from value 2. We will place the result into value 3. Value 1 is 8200H and 8201H. Similarly, value 2 is at 8202H, and 8203H. We’ll place the result into 8204H, and 8205H. Low bytes first.
Although there are better ways to perform this logic for memory optimization, I’ll spell this out in the logic to make it more simple to read.
LOWBYTE1: EQU 8200H ; will contain 03H (VALUE 1 LOW) HIGHBYTE1: EQU 8201H ; will contain 00H (VALUE 1 HIGH) LOWBYTE2: EQU 8202H ; will contain 00H (VALUE 2 LOW) HIGHBYTE2: EQU 8203H ; will contain 02H (VALUE 2 HIGH) LOWBYTE3: EQU 8204H ; store low byte (VALUE 3 LOW) HIGHBYTE3: EQU 8205H ; store high byte (VALUE 3 HIGH) BREAK: EQU 2756H ; ; we'll be subtracting low and high bytes 1 from low and high bytes 2 ; the result will go to low and high bytes 3. RA EQU 10 RB EQU 11 RC EQU 12 RD EQU 13 RE EQU 14 RF EQU 15 ORG 8000H LOAD RA, LOWBYTE1 LOAD RB, HIGHBYTE1 LOAD RC, LOWBYTE2 LOAD RD, HIGHBYTE2 LOAD RE, LOWBYTE3 LOAD RF, HIGHBYTE3 LDI 03H STR RA LDI 00H STR RB LDI 00H STR RC LDI 02H STR RD SEX RA ; DEALING WITH LOW BYTES FIRST LDN RC ; LOAD IN VALUE TO SUBTRACT SM ; SUBTRACT MEMORY RA POINTS TO FROM D STR RE ; STORE THE RESULT TO ADDRESS RE POINTS TO SEX RB ; NOW DEALING WITH HIGH BYTES LDN RD ; LOAD HIGH BYTE OF VALUE 2 INTO ACCUMULATOR (CONTAINS 02H) SMB ; SUBTRACT VALUE AT 820AH FROM D (WITH BORROW), SO SUBTRACT AN EXTRA 1. STR RF ; STORE THE RESULT OF 01H TO 8204. LBR BREAK ; FINAL VALUE OF 8201 AND 8200 IS 01FDH END
Test your work. Cell 8204H should contain FDH. Likewise, cell 8205H should contain 01H.
SMBI (Subtract Memory with Borrow Immediate) Instruction — COSMAC 1802 Subtract Instructions
Finally, we’ll discuss the last subtract instruction. The SMBI instruction subtracts a memory location from an immediate value (with borrow). If the result is less than zero, then we have a borrow condition. DF will be 0. This allows us to subtract a memory location from an immediate value on the fly. Here, we’ll simply subtract the value of 0007H from 0205H.
LOWBYTE1: EQU 8200H ; store the low byte here HIGHBYTE1: EQU 8201H ; store the high byte here BREAK: EQU 2756H ; ; we'll be subtracting low and high bytes 1 from low and high bytes 2 ; the result will go to low and high bytes 3. RA EQU 10 RB EQU 11 ORG 8000H LOAD RA, LOWBYTE1 LOAD RB, HIGHBYTE1 LDI 05H ;SUBTRACT 7 FROM 5 SMI 07H ;THE RESULT IS FE AND GOES TO D STR RA ;STORE FEH LDI 02H ; SUBTRACT 0 FROM 2 WITH BORROW. DF1=0 SMBI 00H ; THE RESULT WILL BE 1, AND GOES TO D STR RB ; STORE 01H LBR BREAK ; FINAL VALUE OF 8201 AND 8200 IS 01FEH END
At this point, check 8200, and 8201. 8200 contains the low byte of FEH, and 8201 contains the high byte of 01H.
For more information, please visit the COSMAC Category Page!
— Ricky Bryce