6. programming techniques - chemeketa community...
TRANSCRIPT
•
•
•
•
6. PROGRAMMING TECHNIQUES
This chapter describes some techniques that may be of help to the programmer.
BRANCH TABLES PSEUDO·SUBROUTINE
Suppose a program consists of several separate routines, any of which may be executed depending upon some
initial condition (such as a number passed in a register). One way to code this would be to check each condition
sequentially and branch to the routines accordingly as follows:
CONDITION = CONDITION 1?
IF YES BRANCH TO ROUTINE 1
CONDITION CONDITION 2?
II:: YES BRANCH TO ROUTINE 2
BRANCH TO ROUTINE N
A sequence as above is inefficient, and can be improved by using a branch table.
The logic at the beginning of the branch table program loads the starting address of the branch table into the H
and L registers. The branch table itself consists of a list of starting addresses for the routines to be branched to.
Using the Hand L registers as a pointer, the branch table program loads the selected routine's starting address
into the program counter, thus effecting a jump to the desired routine. For example, consider a program that
executes one of eight routines depending on which bit of the accumulator is set:
lump to routine 1 if the accumulator holds 00000001
" " 2 " " .. " 00000010 II 3 " " " 00000100
" 4 " " " 00001000
" 5 " " " 00010000
" " 6 " " " 00100000
" 7 " " " " 01000000
" " 8 " " " 10000000
A program that provides such logic follows. The program is termed a 'pseudo·subroutine' because it is treated as a
subroutine by the programmer (i.e., it appears just once in memory), but is entered via a regular 1LIMP instruction
rather than via a CALL instruction.
• 6-1
-- --- --
Chapter 6. Programming Techniques
• Main Program Branch Table Jump
_.......
Program Routines
•
• normal subroutine return
sequence not followed by branch table program •
• 6-2
Chapter 6. Programming Techniques
• Label Code Operand
START: LXI H,BTBL
GTBIT: RAR
JC GETAD INX H INX H
JMP GTBIT GETAD: MOV E,M
INX H
• MOV D,M XCHG
PCHL
• BTBL: OW ROUTt
OW ROUT2 OW ROUT3 OW ROUT4 OW ROUTS OW ROUT6 OW ROUT7 OW ROUTS
;REGISTERS HAND L WILL ;POINT TO BRANCH TABLE
;(H,L)=(H,L)+2 TO ;POINT TO NEXT ADDRESS ;IN BRANCH TABLE
;BIT FOUND ;LOAD JUMP ADDRESS ;INTO 0 AND E REGISTERS
;EXCHANGE 0 AND E ;WITH HAND L ;JUMP TO ROUTINE ;ADDRESS
;BRANCH TABLE. EACH ;ENTRY IS ATWO-BYTE ;ADDRESS ;HELD LEAST SIGNIFICANT ;BYTE FIRST
• The control routine at START uses the Hand L registers as a pointer into the branch table (BTBL) corresponding to the bit of the accumulator that is set. The routine at GETAD then transfers the address held in the corresponding branch table entry to the Hand L registers via the 0 and E registers, and then uses a PCHL instruction, thus transferring control to the selected routine.
TRANSFERRING DATA TO SUBROUTINES
A subroutine typically requires data to perform its operations. In the simplest case, this data may be transferred in one or more registers.
Sometimes it is more convenient and economical to let the subroutine load its own registers. One way to do this is to place a list of the required data (called a parameter list) in some data area of memory, and pass the address of this list to the subroutine in the Hand L registers..
• 6·3
Chapter 6. Programming Techniques
For example, the subroutine ADSUB expects the address of a three-byte parameter list in the Hand L registers. It adds the first and second bytes of the list, and stores the result in the third byte of the list: •
Label Code Operand
LXI H,PLlST
CAll ADSUB RET1:
PUST: DB 6 DB 8
OS 1 LXI H,UST2
CALL ADSUB RET2:
LlST2: DB 10 DB 35 OS
ADSUB: MOV A,M INX H
MOV B,M ADD B INX H
MOV M,A
RET
Comment
;lOAO HAND L WITH
jADDRESSES OF THE PARAM
;ETER LIST ;CALL THE SUBROUTINE
;FIRST NUMBER TO BE ADDED
;SECOND NUMBER TO BE
;ADOEO
iRESUL T WILL BE STORED HERE
;LOAD HAND L REGISTERS
;FOR ANOTHER CALL TO ADSUB
;GET FIRST PARAMETER
;INCREMENT MEMORY
;ADDRESS ;GET SECOND PARAMETER
;ADD FIRST TO SECOND ;INCREMENT MEMORY
;ADDRESS ;STORE RESULT AT THIRD ;PARAMETER STORE ;RETURN UNCONDITIONALLY
•
•
•The first time ADSUB is called, it loads the A and B registers from PUST and PUST+1 respectively, adds them,
and stores the result in PUST +2. Return is then made to the instruction at RETl.
• 6-4
Chapter 6. Programming Techniques
• First call to ADSlIB:
H L
D oADSUB:
06
08
OEH
PLiST
PLlST+l
• PLlST+2
The second time ADSUB is called, the Hand L registers point to the parameter list LlST2. The A and B registers are loaded with 10 and 35 respectively, and the sum is stored at LlST2+2. Return is then made to the instruction at RET2.
Note that the parameter lists PLIST and L1ST2 could appear anywhere in memory without altering the results produced by ADSLIB.
• This approach does have its limitations, however. As coded, ADSUB must receive a list of two and only two numbers to be added, and they must be contiguous in memory. Suppose we wanted a subroutine (GENAD) which would add an arbitrary number of bytes, located anywhere in memory, and leave the sum in the accumulator.
This can be done by passing the subroutine a parameter list which is a list of addresses of parameters, rather than the parameters themselves, and signifying the end of the parameter list be a number whose first byte is FFH (assuming that no parameters will be stored above address FFOOH).
• Call to GENAD:
H L
GENAD: DO PARMlLRl PARM4
ADR2 ADR3 PARM3 ADR4 FFFF PARM2
• As implemented below, GENAD saves the current sum (beginning with zero) in the C register. It then loads the address of the first parameter into the 0 and E registers. If this address is greater than or equal to FFOOH, it reloads the accumulator with the sum held in the C register and returns to the calling routine. Otherwise, it
6-5
Chapter 6. Programming Techniques
loads the parameter into the accumulator and adds the sum in the C register to the accumulator. The routine
then loops back to pick up the remaining parameters. • Label
PUST:
PARM1: PARM4:
PARM3:
PARM2:
GENAD: LOOP:
BACK:
Code
LXI
CALL
HALT DW DW DW DW
DW
DB
DB
DB
DB
XRA MOV MOV
INX
MOV
CPI
IZ MOV LDAX ADD
INX
JMP MOV RET
Operand
H,PLlST GENAD
PARMl PARM2 PARM3 PARM4
OFFFFH
6 16
13
82
A
C,A E,M
H A,M
OFFH
BACK
D,A D
C H
LOOP A,C
Comment
;lOAD ADDRESS OF ;PARAMETER ADDRESS LIST
;LlST OF PARAMETER ADDRESSES
;TERMINATOR •
• ;CLEAR ACCUMULATOR ;SAVE CURRENT TOTAL IN C ;GET LOW ORDER ADDRESS BYTE ;OF FI RST PARAMETER
;GET HIGH ORDER ADDRESS BYTE ;OF FIRST PARAMETER •;COMPARE TO FFH
;IF EQUAL, ROUTINE IS COMPLETE ;D AND E NOW ADDRESS PARAMETER ;lOAD ACCUMULATOR WITH PARAMETER
;ADD PREVIOUS TOTAL
;INCREMENT HAND L TO POINT ;TO NEXT PARAMETER ADDRESS ;GET NEXT PARAMETER ;ROUTINE DONE - RESTORE TOTAL ;RETURN TO CALLING ROUTINE
END
• 6-6
Chapter 6. Programming Techniques
• Note that GENAD could add any combination of the parameters with no change to the parameters themselves.
The sequence:
LXI H,PLlST
CALL GENAO
PUST: OW PARM4 OW PARMl OW OFFFFH
• would cause PARMl and PARM4 to be added, no matter where in memory they might be located (excluding
addresses above FFOOH).
Many variations of parameter passing are possible. For example, if it is necessary to allow parameters to be
stored at any address, a calling program can pass the total number of parameters as the first parameter; the
subroutine then loads this first parameter into a register and uses it as a counter to determine when all param
eters had been accepted.
SOFTWARE MULTIPLY AND DIVIDE
• The mUltiplication of two unsigned 8-bit data bytes may be accomplished by one of two techniques: repetitive
addition, or use of a register shifting operation.
Repetitive addition provides the simplest, but slowest, form of multiplication. For example, 2AH*74H may be
generated by adding 74H to the (initially zeroed) accumulator 2AH times.
Shift operations provide faster multiplication. Shifting a byte left one bit is equivalent to multiplying by 2, and
shifting a byte right one bit is equivalent to dividing by 2. The following process will produce the correct 2-byte
• result of multiplying a one byte multiplicand by a one byte multiplier:
A. Test the least significant bit of mUltiplier. If zero, go to step b. If one, add the
multiplicand to the most significant byte of the result.
B. Shift the entire two-byte result right one bit position.
C Repeat steps a and b until all 8 bits of the multiplier have been tested.
For example, consider the multiplication: 2AH*3CH=908H
Step 1: Test multiplier O-bit; it is 0, so shift 16-bit result right one bit.
Step 2: Test mUltiplier l·bit; it is 0, So shift 16-bit result right one bit.
• Step 3: Test multiplier 2-bit; it is 1, so add 2AH to high-order byte of result and shift 16·bit
result right one bit.
&7
Chapter 6. Programming Techniques
Step 4: Test multiplier 3-bit; it is 1, so add 2AH to high-order byte of result and shift 16-bit
result right one bit. • Step 5: Test multiplier 4·bit; it is 1, so add 2AH to high-order byte of result and shift 16-bit
result right one bit.
Step 6: Test multiplier 5-bit; it is 1, so add 2AH to high-order byte of result and shift 16-bit
result right one bit.
Step 7: Test multiplier 6-bit; it is 0, so shift 16-bit re5ult right one bit.
Step 8: Test multiplier 7-bit; it is 0, 50 shift 16-bit result right one bit.
The result produced is 0908.
HIGH·ORDER BYTE LOW-ORDER BYTE •MULTIPLIER MULTIPLICAND OF RESULT OF RESULT
Start 00111100(3C) 0010101O(2A) 00000000 00000000 Step 1 a .............................. .
b 00000000 00000000 Step 2 a .............................. .
b 00000000 00000000 Step 3 a .............................. . 00101010 00000000
b 00010101 00000000 Step 4 a .............................. . 00111111 00000000 •
b 00011111 10000000 Step 5 a .............................. . 01001001 10000000
b 00100100 11000000 Step 6 a .............................. . 01001110 11000000
b 00100111 01100000 Step 7 a .............................. .
b 00010011 10110000 Step 8 a .......... .
b 00001001 11011000(908) • Since the multiplication routine described above uses a number of important programming techniques, a sample program is given with comments.
The program uses the B register to hold the most significant byte of the result, and the C register to hold the least significant byte of the result. The 16-bit right shift of the result is performed in the accumulator by two rotate·right-through·carry instructions.
• 6·8
Chapter 6. Programming Techniques
• Zero carry and then rotate B:
B C
1---..~0 D I
Then rotate C to complete the shift:
D B C
• Register D holds the multiplicand, and register C originally holds the multiplier.
• MULT: MYI B,O ;INITIALIZE MOST SIGNIFICANT BYTE
;OF RESULT MYI E,9 ;BIT COUNTER
MULTO: MOY A,C ;ROTATE LEAST SIGNIFICANT BIT OF RAR ;MULTIPLIER TO CARRY AND SHIFT MOY C,A ;LOW-ORDER BYTE OF RESULT DCR E
JZ DONE jEXIT IF COMPLETE
MOY A,B
JNC MULTl ADD 0 ;ADD MULTIPLICAND TO HIGH
• ;ORDER BYTE OF RESULT I F BIT ;WAS A ONE
MULTl : RAR ;CARRY=O HERE SHIFT HIGH;ORDER BYTE OF RESULT
MOY B,A JMP MULTO
DONE:
An analogous procedure is used to divide an unsigned 16-bit number by an unsignedl6·bit number. Here, the process involves subtraction rather than addition, and rotate-left instructions instead of rotate-right instructions.
•
Chapter 6. Programming Techniques
The following reentrant program uses the Band C registers to hold the dividend and quotient, and the D and E
register to hold the divisor and remainder. The Hand L registers are used to store data temporarily. • DIV: MOV A,D ;NEGATE THE DIVISOR
CMA MOV D,A MOV A,E CMA
MOV E,A INX D ;FOR TWO'S COMPLEMENT LXI H,O ;INITIAL VALUE FOR REMAINDER MVI A,17 ;INITIALIZE LOOP COUNTER
DVO: PUSH H ;SAVE REMAINDER DAD D ;SUBTRACT DIVISOR (ADD NEGATIVE)
JNC DVl ;UNDER FLOW, RESTORE HL XTHL
OV1: pop H • PUSH PSW ;SAVE LOOP COUNTER (A)
MOV A,C ;4 REGISTER LEFT SHIFT
RAL ;WITH CARRY MOV C,A ;CY-)C->B->L->H MOV A,B RAL MOV B,A MOV A,L RAL •MOV L,A MOV A,H RAL
MOV H,A pop PSW ;RESTORE LOOP COUNTER (A) OCR A ;OECREMENT IT
JNZ ova ;KEEP LOOPING
;POST-DIVIOE CLEAN UP •;SHIFT REMAINDER RIGHT AND RETURN IN DE
ORA A MOV A,H RAR MOV D,A MOV A,L RAR MOV E,A RET END
• 6·10
Chapter 6. Programming Techniques
• MULTIBYTE ADDITION AND SUBTRACTION
The carry flag and the ADC (add with carry) instructions may be used to add unsigned data quantities of arbitrary length. Consider the following addition of two three-byte unsigned hexadecimal numbers:
32AF8A +84BA90
B76A1A
To perform this addition, add to the low-order byte using an ADD instruction. ADD sets the carry flag for use
in subsequent instructions, but does not include the carry flag in the addition. Then use ADC to add to all
higher order bytes .
• 32 AF 8A 84 BA
B7 6A 1S1A 90
"",y=1 S carry
The following routine will perform this multibyte addition, making these assumptions:
• The E register holds the length of each number to be added (in this case, 3).
The numbers to be added are stored from low-order byte to high-order byte beginning at memory locations FI RST and SECND, respectively. .
The result will be stored from low-order byte to high-order byte beginning at memory location FI RST, replacing
90
BA
84• SECND
SECND+l
SECND+2
6-11
Chapter 6. Programming Techniques
The following routine uses an ADC instruction to add the low-order bytes of the operands. This could cause the result to be high by one if the carry flag were left set by some previous instruction. This routine avoids the problem by clearing the carry flag with the XRA instruction just before LOOP.
Label Code Operand Comment
MADD: LXI B,FIRST ;8 AND C ADDRESS FI RST
LXI H,SECND ;H AND L ADDRESS SECND XRA A ;CLEAR CARRY FLAG
LOOP: LDAX B ;LOAD BYTE OF FIRST ADC M ;ADD BYTE OF SECND
;WITH CARRY STAX B ;STORE RESULT AT FIRST DCR E ;DONE IF E 0
JZ DONE INX B ;POINT TO NEXT BYTE OF
;FIRST INX H ;POINT TO NEXT BYTE OF
;SECND
JMP LOOP ;ADD NEXT TWO BYTES DONE:
FIRST: DB 90H DB OBAH DB 84H
SECND: DB 8AH DB OAFH DB 32H
Since none of the instructions in the program loop affect the carry flag except ADC, the addition with carry will
proceed correctly.
When location DONE is reached, bytes FIRST through FIRST+2 will containlA6AB7, which is the sum shown at the beginning of this section arranged from low-order to high-order byte.
In order to create a multibyte subtraction routine, it is necessary only to duplicate the multibyte addition routine of this section, changing the ADC instruction to an SBB instruction. The program wi II then subtract the number beginning at SECND from the number beginning at FIRST, placing the result at FIRST.
DECIMAL ADDITION
Any 4-bit data quantity may be treated as a decimal number as long as it represents one of the decimal digits from 0 through 9, and does not contain any of the bit patterns representing the hexadecimal digits A through F. In order to preserve this decimal interpretation when performing addition, the value 6 must be added to the 4-bit quantity whenever the addition produces a result between 10 and IS. This is because each 4-bit data
•
•
•
•
quantity can hold 6 more combinations of bits than there are decimal digits. • 6-12
Chapter 6. Programming Techniques
• Decimal addition is performed by Jetting each 8-bit byte represent two 4-bit decimal digits. The bytes are summed in the accumulator in standard fashion, and the DAA (decimal adjust accumulator) instruction is then used to convert the 8-bit binary result to the correct representation of 2 decimal digits. For multibyte strings, you must perform the decimal adjust before adding the next higher-order bytes. This is because you need the carry flag setting from the DAA instruction for adding the h igher·order bytes.
To perform the decimal addition:
2985 +4936
7921
• the process works as follows:
1. Clear the Carry and add the two lowest-order digits of each number (remember that each 2 decimal digits are represented by .one byte).
85 = 10000101 B
36'" 001101108 carry o
Q]10111011B
• Carry = 0 ~ '"Auxiliary Carry o
The accumulator now contains OBBH.
2. Perform a DAA operation. Since the rightmost four bits are greater than 9, a 6 is added to the accumulator.
Accumulator = 10111011 B
• 6 = 01108
110000018
Since the leftmost bits are greater than 9, a 6 is added to these bits, thus setting the carry flag_
Accumulator = 11000001 B
6 '" 0110 B
/]001000018
.. Carry flag 1
The accumulator now contains 21 H. Store these two digits.
• 6·13
Chapter 6. Programming Techniques
3. Add the next group of two digits; •29 =00101001 B 49 =01001001B
carry
Ql 0111 0011 B
Carry = 0 ~ 'AUXiliary Carry = 1
The accumulator now contains 73H.
4. Perform a DAA operation. Since the auxiliary carry flag is set, 6 is added to the accumulator.
Accumulator =011100118
6 = 01108
/Ql01111001B • Carry flag =0
Since the leftmost 4 bits are less than 10 and the carry flag is reset, no further action occurs.
Thus, the correct decimal result 7921 is generated in two bytes.
A routine which adds decimal numbers, then, is exactly analogous to the multibyte addition routine MADD of
the last section, and may be produced by inserting the instruction DAA after the ADC M instruction of that •example.
Each iteration of the program loop will add two decimal digits (one byte) of the numbers.
DECIMAL SUBTRACTION
Decimal subtraction is considerably more complicated than decimal addition. In general, the process consists of generating the tens complement of the subtrahend digit, and then adding the result to the minuend digit. For •example, to subtract 34 from 56, form the tens complement of 34 (99-34;:065+1 . Then, 56+66:122. By truncating off the carry out of the high order digit, we get 22, the correct result.
The problem of handling borrows arises in multibyte decimal subtractions. When no borrow occurs from a sub
tract, you want to use the tens complement of the subtrahend for the next operation. If a borrow does occur,
you want to use the nines complement of the subtrahend.
Notice that the meaning of the carry flag is inverted because you are dealing with complemented data. Thus, a
one bit in the carry flag indicates no borrow; a zero bit in the carry flag indicates a borrow. Th is inverted carry
flag setting can be used in an add operation to form either the nines or tens complement of the subtrahend.
• 6-14
Chapter 6. Programming Techniques
• The detailed procedure for subtracting multi-digit decimal numbers is as follows:
1. Set the carry flag = 1 to indicate no borrow.
2. Load the accumulator with 99H, representing the number 99 decimal.
3. Add zero to the accumulator with carry, producing either 99H or 9AH, and resetting the
carry flag.
4. Subtract the subtrahend digits from the accumulator, producing either the nines or tens
complement.
5. Add the minuend digits to the accumulator.
• 6. Use the OAA instruction to make sure the result in the accumulator is in decimal format, and
to indicate a borrow in the carry flag if one occurred.
7. If there are more digits to subtract, go to step 2. Otherwise, stop.
Example:
Perform the decimal subtraction:
• 43580 -13620
29960
1 . Set carry 1 .
2. Load accumulator with 99H.
• 3. Add zero with carry to the accumulator, producing 9AH.
Accumulator = 10011001 B
:: OOOOOOOOB Carry
10011010B:: 9AH
4_ Subtract the subtrahend digits 62 from the accumulator.
Accumulator:: 10011010B 62 :::: 10011110B
]] 00111000B
• 6·15
Chapter 6. Programming Techniques
5. Add the minuend digits 58 to the accumulator.
Accumulator:: 001110008 •58 =. 010110008
g100100008 90H
Carry = a~ 'AUXiliary Carry =1
6. DAA converts accumulator to 96 (since Auxiliary Carry:: 1) and leaves carry flag = a indicating that a borrow occurred.
7. Load accumulator with 99H.
8. Add zero with carry to accumulator, leaving accumulator 99H.
9. Subtract the subtrahend digits 13 from the accumulator. •
Accumulator = 100110018 13 = 11101101 B
]1000011OB
10. Add the minuend digits 43 to the accumulator.
Accumulator = 1000011 OB
43 '" 01000011 B
~:g 11001 001 B =; C9H • Carry'" a 'AUXiliary Carry =0
11. DAA converts accumulator to 29 and sets the carry flag:: 1, indicating no borrow occurred.
Therefore, the result of subtracting 1362 from 4358 is 2996.
The following subroutine will subtract one 16·digit decimal number from another using the follOWing assumptions: •The minuend is stored least significant (2) digits first beginning at location MINU.
The subtrahend is stored least significant (2) digits first beginning at location SBTRA.
The result will be stored least significant (2} digits first, replacing the minuend.
• 6-16
Chapter 6. Programming Techniques
• Label Code Operand Comment
DSUB: LXI D,MINU ;D AND E ADDRESS MINUEND
LXI H,SBTRA ;H AND L ADDRESS SUBTRA;HEND
MVI C,8 ;EACH LOOP SUBTRACTS 2 ~ ;DIGITS (ONE BYTE),
;THEREFORE PROGRAM WILL ;SUBTRACT 16 DIGITS.
• STC ;SET CARRY INDICATING
;NO BORROW LOOP: MV! A,99H ;LOAD ACCUMULATOR
;WITH 99H . ACI 0 ;ADD ZERO WITH CARRY SUB M ;PRODUCE COMPLEMENT
;OF SUBTRAHEND XCHG ;SWITCH D AND E WITH
;H AND L ADD M ;ADD MINUEND DAA ;DECIMAL ADJUST
• ;ACCUMULATOR
MOV M,A ;STORE RESULT
XCHG ;RESWITCH D AND E
;WITH HAND L OCR C ;DONE IF C = 0
JZ DONE INX D ;ADDRESS NEXT BYTE
• ;OF MINUEND
INX H ;ADDRESS NEXT BYTE ;OF SUBTRAHEND
JMP LOOP ;GET NEXT 2 DECIMAL DIGITS DONE: NOP
• 6-17
• '. ,
•
•
•
•