Im Magazin „BYTE" wurde in der Ausgabe Mai 1977 der folgende Artikel abgedruckt.
Hinweise zur Verwendung von 16 Bits bei der 8080 8 Bit-Maschine

8080 Programming Notes

Paul Krystosek
57 N Lincoln
Lombard IL 60148
 
John McCarty
5412 N Arrow Dr
Peoria IL 61614
 
With a couple of exceptions the 8080 microprocessor instruction set primarily operates on eight bits at a time. But with some imagination several 16 bit operations can be performed by using these exceptions. The basic technique is to use the HL register pair as an accumulator rather than as an address and index register. The simplest 16 bit extension is just a different name for the DAD H instruction. The effect of this operation can be stated in three ways:
  1. Add the HL register pair to itself.
  2. Multiply the HL register pair by two. (We might rename it M2HL.)
  3. Shift the HL register pair left one bit position. (We might rename it ASLHL for "arithmetic shift left HL.")
These three statements are logically equivalent. To multiply by greater powers of two just repeat the operation the required number of times.
So far the DAD H instruction has been referred to as an arithmetic shift rather than a rotate. The carry bit is set as in a rotate, but it does not affect the low order bit. To set up a 16 bit rotate, increment the HL register pair after the shift if the carry bit is set, as shown in listing 1.
Listing 1: Performing a 16 bit rotate left using the HL register pair. The DAD H instruction will shift the 16 bit number 1 bit to the left and determine the value for the overflow flag. If the overftow flag is set, then the HL register pair is incremented by 1. [8080 Quelle und Z80 Quelle]
16 bit addition is of course done by using the DAD B or DAD D instructions which exist in the 8080. In such cases, one number to be added is first loaded into the HL register pair, and then the other number is loaded into the BC or DE register pair and added to the HL register pair. A common use for this instruction is in index address calculation. A special use for this instruction is in looping and comparing. When setting up a loop using a counter which will have a value greater than decimal 256, a multiple precision increment operation using two single independent registers can be used. Note that since the INX instruction does not affect any status bits, it cannot be used by itself as a 16 bit loop control function.
Another approach is shown in listing 2. The -1000 on line n+1 will be stored as a two's complement number hexadezimal FC18. When adding anything less than decimal 1000 in statement n+2 a carry will not result. Statements n+1, n+2, and n+3 could be thought of as "compare the HL register pair to the BC register pair and jump if the BC register pair is less than the HL register pair."
Listing 2: An example of setting up a 16 bit counter using the BC register pair. In this example, a loop willgo through 1000 iterations. [8080 Quelle und Z80 Quelle]
If a compare high, low or equal is needed, the procedure could be extended as in listing 3. A disadvaniage of this technique is that it requires the HL register pair to be loaded with the two's complement of the target number. It is probably casier and certainly takes less execution time if we load the two's complement of a constant during assembly instead of a variable calculated during execution.
Listing 3: This routine is an extension of the testing used by the routine of listing 2. Here, the goal is to pick one of three branch possibilities: less than, egual to, or greater than. This routine is used to test register pair BC's relationship to the integer constant 1000 using DAD H with HL as a 16 bit accumulator. [8080 Quelle und Z80 Quelle]
Another modification of the loop routine, shown in listing 4, can be used when processing or scanning consecutive memory locations where the end of the loop is determined by an address rather than a counter. An example of this is in outputting to a port from one address to anothcr, as would be done when writing a block of data to tape, disk, another machine, or whatever.
Listing 4: This routine is basically the same as listing 2 in determining when to exit the loop. The main difference is that an address is being used instead of an incremcntal or decremental couter. This particular routine outputs data from address ADR1 to address ADR2. [8080 Quelle und Z80 Quelle]
The (-ADR2) on line 7 may look confusing; it is just the two's complement of the address in question. While it would be slow to hand assemble such a statement, a good assembler will do the calculation for you. To have variable start and end addresses the two's complement would have to be calculated by subtracting ADR2 from zero, or by a binary complement operation on the 16 bits followed by a 16 bit increment operation.
Yet another application of the double add instruction with two's complement arithmetic is in decrementing a register pair with an indication of passing zero. The two's complement of the number -1 is all 1 bits regardless of how many bits are in the number. The only number which can be added to -1 without causing a carry is zero. Adding -1 to a number will decrement that number by one and set the carry flag unless the number was zero. Using these facts a loop can be set up as in listing 5.
Listing 5: Here is a loop with a 16 bit counter which, instead of adding and comparing two numbers to find when to exit, decrements the loop counter and checks to see when it goes past zero to negative one. [8080 Quelle und Z80 Quelle]
When using this technique, the decrement and check if zero are done al the beginning of the loop as in languages like PL/I rather than at the end of the loop as in FORTRAN. The reason for this is that we find out when the loop goes from zero to -1 rather than when it is zero. A disadvantage to this technique is that it ties up a register pair to hold the -1 value.
The techniques illustrated here are just a few examples of what one can come up with by using a little imagination and looking very closely at exactly what each instruction does. They are not the most general techniques as far as usefulness in many situations, but used in the right place they can save a few bytes or microseconds. If nothing else, these notes have shown ways to use instructions that may not be immediately obvious.

A Note About "EQU"

Throughout the listings of this article the mnemonic EQU has been usad extensively. The EQU, equate, statement is an assembler instruction or "pseudooperation" rather than a machine instruction. Pseudooperations are common assembler features whieh tell the assembler something about your program or the assembly process but do not necessarily generate machine code. The asterisk (*) or dollar sign ($) (depending on the assembler that is used) indicates "this address." For example:
   1) LOQP EQU *
           .
           .
           .
   n) JMP LOOP
The effect of statement 1 is to equate the address of the next instruction with the label LOOP. The value of the address is then stored in the assembler's symbol table. This may seem like a trivial thiny to do; but if you wanted to use your text editor program to add an instruction at the beginning of the loop as a program patch it can just be put there. Whereas if the label was on the first instruction that line would have to be changed as well as the new line being inserted. [Of course if your text editor is capable of arbitrary insertions this is not a major point.]
Another use of the equate pseudooperation is the following:
   1) CTL EQU 2
   2) DATA EQU CTL+1
The effect of this would be that whenever CTL is encountered it is replaced by the value 2. Statement 2 would equate DATA to 3 wherever it is used. The real usefulness of equates is in their ease of change at the assembly language level. If the IO port address is changed, only the equate for CTL would have to be changed to make the change throughout the program for both CTL and DATA the next time it is assernbled. Table lengths can be handled with a similar ease as shown in the listing below. In this way, if the length of the table is changed, the change will be made throughout the program the next time it is assembled, providing of course that TLEN is used consistently.
Another handy fact is that if you have used two different spellings for the same label or variable, one can be equated to the other rather than changing them all to one.
 line
number   label   mnemonic     commentary

  1      TBL     DW 'BA'      \
  2              DW 'CD'      > define character strings; [misc data for
  3              DW 'FE'      | demonstration]
  4              DW 'HG'      /
  5      TLEN    EQU *-TBL    equates TLEN to the current address -
                               beginning address;

REFERENCE

Intel Corporation: Intel 8080 Microcomputer Systems Users Manual,September 1975.

Eingescanned von Werner Cirsovius
April 2012
© BYTE Publications Inc.