home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / utils / asmutl / meyertut.ark / MEYER04.TXT < prev    next >
Encoding:
Text File  |  1987-12-04  |  8.1 KB  |  204 lines

  1.                      CP/M Assembly Language
  2.                          Part IV: Flags
  3.                           by Eric Meyer
  4.  
  5.      Last time we learned how to make an assembly language
  6. program talk. I hope this was entertaining enough to keep your
  7. interest a while. There are many dozen 8080 instructions, and
  8. you'll need to know a lot more of them before you can attempt
  9. more sophisticated tasks.
  10.      This time we'll learn about that mysterious "F" register,
  11. the Flags: what they are, and how to use them to make decisions.
  12. But first (you'll see why) we must learn a little more
  13. arithmetic.
  14.  
  15.  
  16. 1. Addition and Subtraction
  17.      We've already seen the INC and DEC instructions, which add
  18. or subtract 1 from any register. The accumulator ("A" register)
  19. can also do fancier arithmetic.
  20.      The ADI and SUI (add and subtract immediate) instructions
  21. can be used to add or subtract a value from the accumulator. For
  22. example:
  23.  
  24. ADI  12
  25.  
  26. would add 12 to whatever was in "A" before.
  27.      Similarly, the ADD and SUB instructions add or subtract the
  28. contents of any other register from the accumulator; thus:
  29.  
  30. SUB  C
  31.  
  32. would subtract the value in "C" from the value in "A".
  33.      You can even use the instructions ADD A, which adds A to
  34. itself (doubles A), and SUB A, which subtracts it from itself
  35. (leaving, oddly enough, zero).
  36.  
  37.  
  38. 2. The Flags
  39.      The really powerful feature of a computer program is that it
  40. can make decisions; depending on the data you supply, it doesn't
  41. have to execute the same way every time. No doubt you're already
  42. familiar with statements like:
  43.  
  44. 210 IF RESULT<0 THEN GOTO 1000
  45.  
  46.      The same sort of thing can be done in assembly language, but
  47. it's more cumbersome, and it happens in stages. You perform some
  48. operation, like arithmetic or comparison, and one or more flags
  49. are set as a byproduct; then you can JMP or CALL conditionally,
  50. depending on the state of the flags.
  51.      The "F" register contains 8 bits, each of which can be
  52. thought of as a little flag that's either on or off, yes or no.
  53. The two most-commonly used flags are called Zero and Carry, or Z
  54. and C for short.
  55.      Basically, the Zero flag is set when an operation results in
  56. a register going to zero; and the Carry (or borrow) flag is set
  57. when an accumulator operation results in overflow or underflow.
  58. Each flag retains its status until changed by the next operation
  59. that affects it.
  60.    As a result, for each arithmetic operation, you have to learn
  61. exactly how it affects the flags. Here's a summary so far:
  62.  
  63.   INR, DCR -- Z means register is now 0
  64.         C NOT affected
  65.   ADD, ADI -- Z means A is now 0
  66.         C means overflow (>255)
  67.   SUB, SUI -- Z means A is now 0
  68.         C means underflow (<0)
  69.  
  70.      Occasionally this is real confusing. Notice, for example,
  71. that while SUI 1 affects the Carry flag, DCR A (which is
  72. otherwise identical) does not.
  73.      Note also that 16-bit operations INX and DCX do not affect
  74. any of the flags. If you want to know whether a 16-bit number has
  75. been decremented to zero, you have to do something devious, like
  76. add its two bytes together and then look at the Z flag.
  77.  
  78.  
  79. 3. Comparison
  80.      The comparison operation is just like subtraction, but it
  81. doesn't change the accumulator; it only changes the flags. The
  82. instruction is CMP for a register, or CPI for an immediate data
  83. value. Thus, for example,
  84.  
  85. CPI  12
  86.  
  87. affects the flags exactly as SUI 12 would have, but without
  88. actually doing the subtraction. In particular, if the value in A
  89. had actually been 12, the Zero flag would now be set.
  90.      Thus the Z flag tends to mean "Yes, that's it", as well as
  91. literally "Zero". Similarly, if the value in "A" had been less
  92. than 12, the Carry flag would now be set. So the C flag tends to
  93. mean "Less than", as well as literally "Carry/borrow".
  94.  
  95.  
  96. 4. Conditional Branches
  97.      It should now come as no surprise that there's a whole set
  98. of JMP and CALL instructions that execute conditionally,
  99. according to the status of the flags. Some of these are:
  100.  
  101. JZ -- JMP if Z flag set        CZ -- CALL if Z flag set
  102. JNZ -- JMP if Z flag Not set   CNZ -- CALL if Z flag Not set
  103. JC -- JMP if C flag set        CC -- CALL if C flag set
  104. JNC -- JMP if C flag Not set   CNC -- CALL if C flag Not set
  105.  
  106.      In order to illustrate, let's rewrite a program from Part
  107. III to show that your computer really cares:
  108.  
  109. BDOS   EQU     0005H
  110.        ORG     0100H
  111.        MVI     C,9       ;print string
  112.        LXI     D,QUESTN  ;(this one)
  113.        CALL    BDOS
  114.        MVI     C,1       ;get input
  115.        CALL    BDOS      ;character is now in A
  116.        LXI     D,YESMSG  ;start with YESMSG
  117.        CPI     'Y'       ;was input "Y"?
  118.        JZ      YES       ;jump to YES if so
  119.  NO:   LXI     D,NOMSG   ;NO, change to NOMSG
  120.  YES:  MVI     C,9
  121.        CALL    BDOS      ;print the answer
  122.        RET               ;all done
  123.                          ;data
  124.  QUESTN: DB  'Are you excited? (Y/N) $'
  125.  YESMSG: DB  ' Great!$'
  126.  NOMSG:  DB  ' Hm, too bad.$'
  127.        END
  128.  
  129.      As you can see, after asking the question and getting one
  130. character from the keyboard, the program sets up to reply with
  131. YESMSG. It then compares the character to "Y": if it matches, the
  132. Z flag is set, so it JMPs to YES and prints YESMSG. If it doesn't
  133. match, it falls through to NO instead, and switches to NOMSG.
  134.  
  135.  
  136. 5. Loops
  137.      Another very common use of the Z flag is in loops. Suppose
  138. you had expanded the BYTEMOV program of Part III to copy 10
  139. characters; you would have had to write:
  140.  
  141.         CALL MOVBYT, CALL MOVBYT, ...
  142.  
  143. 10 times. Now you have a far better way to do this:
  144.         MVI  B,10      ;do ten times
  145.   LOOP: CALL MOVBYT    ;move a byte
  146.         DCR  B         ;count down
  147.         JNZ  LOOP      ;loop if not zero yet
  148.  
  149.      Obviously, you can have the loop execute as many times as
  150. needed just by changing the value in "B". This is the assembly
  151. language equivalent of a FOR...NEXT or WHILE loop.
  152.  
  153.  
  154. 6. The Carry Flag: 16-bit Arithmetic
  155.      Let's end as we began, learning instructions for arithmetic.
  156. You can also add and subtract 16-bit (word) values, although it's
  157. not quite as simple as with single registers. For addition, the
  158. H-L registers can function as a sort of "accumulator": the
  159. instruction DAD (double add) adds the contents of a register pair
  160. to H-L.
  161.      Thus DAD  B adds B-C to H-L. Similarly DAD D adds D-E. (You
  162. can even use the instruction DAD H, which adds H-L to itself.)
  163.      The DAD instruction does not affect the Z flag; but it does
  164. use the C flag to indicate whether (16-bit) overflow occurred.
  165. There is no "immediate" 16-bit add; you have to load the value
  166. into a register pair, then add it.
  167.      Subtraction is harder; the Z80 CPU has a double-subtract
  168. instruction, but the 8080 does not. You have to do it one byte at
  169. a time, in the accumulator. If you wanted, say, to subtract D-E
  170. from H-L, you might try the following:
  171.  
  172.        MOV  A,L   ;get L (the low byte)
  173.        SUB  E     ;subtract E from it
  174.        MOV  L,A   ;and put it back
  175.        MOV  A,H   ;get H (the high byte)
  176.        SUB  D     ;subtract D from it
  177.        MOV  H,A   ;and put it back
  178.  
  179.      Unfortunately, this would sometimes not work, because it
  180. doesn't allow "borrowing" from the "H" register in the event that
  181. "E" is bigger than "L".
  182.      The second subtraction (SUB D) isn't affected by the outcome
  183. of the first. (Imagine subtracting 9 from 26; if you forget to
  184. borrow, you get 27 instead of 17.)
  185.      This is where the Carry flag comes in. Remember that if "E"
  186. is bigger, the "SUB E" instruction is going to give a result
  187. modulo 256, and the C flag will be set. Then, you need to
  188. remember to subtract an extra 1 from the high byte if the C flag
  189. is set.
  190.      This is where a new set of arithmetic instructions comes in:
  191.  
  192. ADD, ADI ---> ADC, ACI : "add with carry"
  193. SUB, SUI ---> SBB, SBI : "subtract with borrow"
  194.  
  195.      These add (or subtract) 1 more if the C flag is set. If you
  196. change the "SUB D" above to "SBB D", the problem will be solved.
  197. This is why the C flag is called "Carry", and functions as it
  198. does.
  199.  
  200.  
  201. 7. Coming Up . . .
  202.      Next time we'll look at the remaining big mystery: the
  203. stack. Then we can begin to write some useful routines.
  204.