home *** CD-ROM | disk | FTP | other *** search
/ The Unsorted BBS Collection / thegreatunsorted.tar / thegreatunsorted / programming / asm_programming / a05.doc < prev    next >
Text File  |  1994-01-18  |  11KB  |  250 lines

  1. CHAPTER 5   SOME EXCLUSIVE FEATURES OF A86
  2.  
  3.  
  4. The IF Statement
  5.  
  6. As a "nudge" in the direction of structured programming, A86
  7. offers the IF statement.  Suppose you want to conditionally skip
  8. around just one instruction.  Ordinarily, this would require, for
  9. example:
  10.  
  11.   JNZ >L1    ; skip the following move if NZ
  12.   MOV AX,BX  ; make this move only if Z
  13. L1:          ; this label exists only for the above skip
  14.  
  15. You may replace the above code with the single line:
  16.  
  17.   IF Z MOV AX,BX
  18.  
  19. The above line generates exactly the same code as the previous 3
  20. lines-- a conditional jump of the opposite condition, around the
  21. statement given in the tail of the IF statement.  The statement
  22. can be a macro call, giving you the opportunity to skip something
  23. more complicated.
  24.  
  25. You may use any condition that would follow the "J" in a
  26. conditional jump instruction, except CXZ, which does not have a
  27. reverse condition.  The assembler interprets the condition by
  28. appending a "J" to the beginning of the condition; so that the
  29. symbols "C", "NC", "Z", "NZ", etc. are not reserved by the
  30. assembler, and can be defined in other contexts.
  31.  
  32.  
  33. Multiple operands to PUSH, POP, INC, DEC
  34.  
  35. A86 will accept any number of register operands for the
  36. instructions PUSH, POP, INC, and DEC; it will generate the
  37. appropriate machine instruction for each operand.  For example,
  38. the statement PUSH AX,BX is the same as the two statements PUSH
  39. AX and PUSH BX.
  40.  
  41. A numeric operand appearing in an INC or DEC statement will cause
  42. the previous INC(s) or DEC(s) to be propagated that number of
  43. times.  For example, the statement INC AX,4 will generate 4 INC
  44. AX instructions.  The statement DEC AL,BX,2 will generate DEC AL,
  45. DEC BX, DEC AL, DEC BX.  Sorry, numeric operands are not allowed
  46. if any of the operands affected was a forward reference or
  47. relocatable quantity; e.g., INC FOO,2 where FOO is undefined.  In
  48. most such cases, you'll want to code the more efficient ADD FOO,2
  49. anyway.
  50.  
  51.  
  52. Repeat Counts to String Instructions
  53.  
  54. A86 will accept a numeric operand to the string instructions
  55. STOSB, STOSW, MOVSB, and MOVSW.  This causes A86 to generate that
  56. many copies of the given instruction.  For small values (usually
  57. 2 through 4), this is more efficient than loading the number into
  58. CX and using the REP prefix.
  59.                                                               5-2
  60.  
  61. Conditional Return Instructions
  62.  
  63. Programmers accustomed to the conditional return instructions of
  64. the 8080/Z80 will appreciate the following feature: A86 allows
  65. the operand to a conditional jump instruction to be one of the
  66. three RET instructions RET, RETF, or IRET.  The assembler will
  67. find a nearby return instruction of the indicated flavor, and use
  68. that as the target for the conditional jump.  For example, JZ RET
  69. is the replacement for the 8080's RZ return-if-zero instruction.
  70. In other 8086 assembly languages, you have to find the nearby
  71. instruction yourself, attach a label to it, and use that label.
  72. Note that it does not suffice to attach a label to a single RET
  73. instruction and use that label throughout the program: the range
  74. of conditional jumps is only 128 bytes in either direction.
  75.  
  76. What happens if A86 does not find a nearby return instruction? In
  77. that case, A86 issues an error, "02 Jump > 128", for the next
  78. matching return instruction in the program.  If there is no
  79. subsequent return instruction, the return mnemonic will appear as
  80. an undefined symbol at the end of the program.   In either case,
  81. you correct the problem by inserting a free-standing return
  82. instruction at some nearby point in the program, where it will
  83. not affect the existing code (typically following an
  84. unconditional JMP instruction).  If there is no good place to
  85. insert a return instruction, you can always replace the "Jcond
  86. RET" with an "IF cond RET".
  87.  
  88.  
  89. A86 extensions to the MOV and XCHG instructions
  90.  
  91. There are a number of MOV and XCHG instructions available in A86
  92. that are not a part of the machine instruction set.
  93.  
  94. First, moves between segment registers, and of immediate
  95. constants into segment registers are allowed.  For example, if
  96. you code MOV ES,DS , the assembler will generate a PUSH DS
  97. followed by a POP ES; which will effect the move that you
  98. intended.   If you code MOV DS,0 , the assembler will generate
  99. PUSH AX; MOV AX,0; MOV DS,AX; POP AX.  This is mainly a
  100. convenience for D86 users to load segment registers manually.
  101.  
  102. Second, MOV allows 3 operands.  A statement MOV x,y,z is
  103. equivalent to the two statements MOV y,z followed by MOV x,y.
  104. Sorry, but segment overrides are not allowed in conjunction with
  105. 3-operand MOVs.  The override preceding the MOV is ambiguous in
  106. its meaning; and overrides within operands cannot be handled
  107. correctly by A86.  You'll have to code two MOV instructions if
  108. you want either or both to have a segment override.
  109.  
  110. Third, A86 accepts a MOV of a word-sized memory operand into
  111. another word-sized memory operand.  A86 handles this the same way
  112. it handles a MOV of segment registers: it generates a PUSH of the
  113. source followed by a POP of the destination.
  114.                                                               5-3
  115.  
  116. Finally, A86 allows the XCHG of a segment register (except CS)
  117. with any other word-sized quantity, as well as the XCHG of two
  118. word-sized memory quantities.  If there is no machine instruction
  119. available for XCHG a,b, then A86 generates PUSH a followed by MOV
  120. a,b followed by POP b.
  121.  
  122.  
  123. Local Symbols
  124.  
  125. If you examine most assembly language program symbol tables, you
  126. will find that the symbols can be partitioned into two levels of
  127. significance.   About half the symbols are the names of
  128. procedures and variables having global significance.  If the
  129. names of these symbols are chosen intelligently and carefully,
  130. the program's readability improves drastically. (They usually
  131. aren't chosen well, most often because the assembler restricts
  132. symbols to 6 letters, or because the programmer's habits are
  133. influenced by such assemblers.)
  134.  
  135. The other half of the symbols in a program have a much lower,
  136. local significance.  They are only place markers used to
  137. implement small loops and local branching (e.g., "skip the next 2
  138. instructions if the Z-flag is set").  Assigning full-blown names
  139. to these symbols reduces the readability of your program in two
  140. ways:  First, it is harder to recognize local jumps for what they
  141. are-- they are usually the assembly language equivalent of high
  142. level language constructs like IF statements and WHILE loops.
  143.  
  144. Second, it is harder to follow the global, significant symbols
  145. because they are buried in a sea of the place marker symbols in
  146. the symbol table.
  147.  
  148. A86 solves this problem with local symbols.  If a symbol in your
  149. program consists of a single letter followed by one or more
  150. decimal digits (L3, X123, Y37, etc.), then the symbol is a local
  151. symbol.  Local symbols do not appear in the A86 +X
  152. cross-reference listing.  They can also be redefined to something
  153. completely different later in the program.  Local symbols can be
  154. of any type: labels, memory variables, etc.
  155.  
  156. Because local symbols can be redefined, you must take care to
  157. specify which one you are referring to in your program.  If your
  158. reference is a forward reference (the label occurs further down
  159. in the program from the reference), then the reference must be
  160. preceded by a ">".  For example,
  161.  
  162. L2:
  163.   MOVSB
  164.   INC BX
  165.   LOOP L2    ; lack of ">" means L2 is above this statement
  166.   .
  167.   .
  168.   JNZ >L2    ; ">" indicates L2 is below this statement
  169.   .
  170.   JMP >L2    ; JMP L2 is disallowed here: cannot overlap ranges
  171.   .
  172. L2:
  173.                                                               5-4
  174.  
  175. I recommend that you assign all your local labels the names L0
  176. through L9.  If your program is so complex that it needs more
  177. than 10 place holders in any one stretch of code, then that
  178. stretch needs to be rewritten.
  179.  
  180.  
  181.  
  182. Operands to AAM and AAD Instructions
  183.  
  184. Those of you who have examined 86 family opcodes with an eagle
  185. eye will have noticed a somewhat spurious "0A" opcode generated
  186. after every AAM or AAD instruction.  The opcode is there to
  187. provide the constant divisor or multiplicand for the instruction.
  188. Believe it or not, there wasn't enough room in the microcode of
  189. the original 8086 to hold this constant!  Although Intel has
  190. never announced the generality of AAM and AAD, it is there: you
  191. can substitute any other constant for 0A (decimal 10), and that
  192. constant will be used.  A86 supports this by letting you give a
  193. constant byte-sized operand to AAM or AAD.  Particularly useful
  194. are the instructions AAM 16, which unpacks AL into nibbles AH and
  195. AL; and AAD 16, which reverses the process, packing nibbles AH
  196. and AL into AL.
  197.  
  198. WARNING: A couple of my users point out to me that the AAD
  199. instruction with a general operand won't work on the NEC V20 and
  200. V30 chips.  The operand is assumed to be 10 no matter what it
  201. really is.  Since a large number of PC "speed up" kits involve
  202. switching to NEC chips, this will be seen on many PC's.  You
  203. should not use AAD with an operand if you want your program to
  204. run on everybody's machine.  Too bad.  AAM works fine, though.
  205.  
  206.  
  207. Single-Operand Forms of the TEST Instruction
  208.  
  209. A86 allows the TEST instruction to have a single operand, to set
  210. the flags according to the value of the operand.  If the operand
  211. is a register, A86 generates a TEST of the register with itself.
  212. If the operand is a memory quantity, A86 generates a TEST of the
  213. memory with the constant -1 (i.e., the quantity will be ANDed
  214. with an all 1's constant).  For example, instead of TEST DL,DL,
  215. you can code simply TEST DL.  Instead of TEST WVAR,0FFFF, you can
  216. code simply TEST WVAR.
  217.  
  218.  
  219. Optimized LEA Instruction
  220.  
  221. Many assembly-language programmers are in the habit of using, for
  222. example, LEA SI,MEMLOC instead of the equivalent MOV SI,OFFSET
  223. MEMLOC to load an immediate value that represents the pointer to
  224. a memory location.  However, the LEA instruction form generates
  225. one more byte of object code than the MOV form. A86 recognizes
  226. this situation and generates the more-efficient MOV instruction
  227. when it can.  This also applies to register moves: MOV AX,BX
  228. instead of LEA AX,[BX].
  229.                                                               5-5
  230.  
  231. I've gotten a little flak from some users about this feature.
  232. They claim it violates my policy against "behind your back"
  233. actions.  But I feel that this feature is completely equivalent
  234. to code optimizations in other situations: the short JMP form
  235. instead of the equivalent near JMP; a byte operand to ADD SI,4
  236. instead of a word operand; the one-byte XCHG AX,BX instead of the
  237. general XCHG rw,ew form; etc, etc, etc. In situations where there
  238. is absolute functional equivalence between forms, A86 tries to
  239. generate the most efficient form.  But for those who are not
  240. convinced, I offer the +G2 switch, described in Chapter 3.
  241.  
  242. Some users have also gotten the mistaken impression, from reading
  243. Intel's confusing specs, that the longer LEA is sometimes faster
  244. than the shorter MOV.  This is never the case: those users are
  245. reading the clock counts for the memory-fetch forms of MOV, not
  246. the register-only or immediate-value forms.  If you don't believe
  247. it, try timing 1000 consecutive LEA's in a loop that executes
  248. 50000 times, vs. a similar loop with the equivalent MOV.
  249.  
  250.