COSMAC 1802 Subtract Instructions


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.

COSMAC 1802 Subtract Instructions

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

Leave a comment

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