home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / forth / compiler / fpc / doc / chapter8.txt < prev    next >
Text File  |  1989-10-29  |  29KB  |  666 lines

  1. CHAPTER 8.   PASM, THE F-PC ASSEMBLER
  2.  
  3.  
  4.  
  5.  
  6.  
  7. PASM is an assembler which is based on the F83 8088/86 assembler and an
  8. 8086 assembler published in Dr. Dobb's Journal, February 1982, by Ray
  9. Duncan. This assembler was subsequently modified by Robert L. Smith to
  10. repair bugs, and support the prefix assembler notation.  Bob discovered a
  11. very simple method to force a postfix assembler to assemble prefix code,
  12. by deferring assembly until the next assembler command or the end of
  13. line, when all the arguments for the previous assembler command are piled
  14. up on the top of the data stack.  Tom Zimmer has made additional
  15. modifications to allow syntax switching, and to increase compatibility in
  16. postfix mode with the F83 Assembler.
  17.  
  18. Writing assembly programs is black magic.  It is not appropriate to
  19. discuss the joys and frustrations in working at such a low level in this
  20. manual.  However, F-PC provides the best environment for you to do
  21. experiments using assembly language, because you can first verify the
  22. algorithm and methodology in high level Forth code and gradually reduce
  23. the code to the assembly level.  You will find numerous examples in which
  24. the high level code in F83 is recoded in assembly, in addition to many of
  25. the F83 kernel words which were in assembly already.
  26.  
  27. The best way to learn 8086 assembly language is to use PASM, armed with
  28. all the code words in F-PC as templates and examples.  Factor your high
  29. level words carefully so that words at the bottom level can be
  30. conveniently recoded in assembly.  Take the F-PC kernel words as
  31. templates to start with, and modify them so that they will do exactly
  32. what you want them to do.
  33.  
  34.  
  35. 8.1.    PREFIX OR POSTFIX ?
  36.  
  37.  
  38. PASM supports dual syntaxes.  The words PREFIX and POSTFIX switch between
  39. the two supported modes.  The postfix mode is very similar to F83's
  40. CPU8086 Assembler.  Prefix mode, which is the default mode, allows a
  41. syntax which is much closer to MASM used by Intel and MicroSoft.
  42.  
  43. The assembler supports prefix syntax in an attempt to provide a syntax
  44. which is more readable to programmers of other languages.  The use of
  45. sequential text files for source code encourages the programmer to write
  46. programs in the vertical code style with one statement per line.  This
  47. style is what traditional assembler requires.  F-PC works well in this
  48. style, if you choose to do so. However, F-PC does not prevent you from
  49. writing in the horizontal code style, by which you can squeeze many
  50. statements into one line and make you own life miserable.   It supports
  51. postfix syntax to prevent alienating the established base of F83 users.
  52.  
  53. The prefix notation is close to the original Intel assembly syntax, and
  54. certainly will be more familiar to programmers of other languages.  All
  55. the code words defined in F-PC are coded in the prefix notation.  Please
  56. consider writing any new assembly code you need in the prefix mode for
  57. distribution and assimilation with F-PC.
  58.  
  59. The assembly of a machine instruction is generally deferred to the
  60. following three events: when the next assembly mnemonic is encountered,
  61. at the end of a line, or when the command END-CODE or A; is executed.
  62. Therefore, a good style in writing code words in F-PC is to put one
  63. assembly instruction in one line, followed by the parameter specification
  64. or the arguments.  Multiple assembly instructions are allowed in the same
  65. line.  It is a good ideal to put the assembly structure words in separate
  66. lines with proper indentation so that the nested structures in a code
  67. definition can be perceived more readily.
  68.  
  69.  
  70. 8.2.    PASM GLOSSARY
  71.  
  72.  
  73. Here we will only give a small list of PASM words in this glossary.  All
  74. assembly mnemonics are identical to those defined in F83 8086 Assembler.
  75. All the structure directives and test conditions are also identical to
  76. those in F83.  Only the most important FORTH words controlling the
  77. assembler are listed here.
  78.  
  79. PREFIX          ( -- )
  80.         Assert prefix mode for the following code definitions.
  81.  
  82. POSTFIX         ( -- )
  83.         Assert postfix mode for the following code definitions.
  84.  
  85. CODE     <name> ( -- )
  86.         Define a new code definition using the following string as its
  87.         name. Assembly commands follow, terminated by END-CODE.
  88.  
  89. END-CODE                ( -- )
  90.         Terminate a code definition, check error conditions, and make
  91.         the code definition available for searching and execution.
  92.  
  93. LOCAL_REFS      ( -- )
  94.         This mode WILL NOT allow local labels to cross CODE word
  95.         boundaries.  The local label mechanism is cleared each time a
  96.         new CODE word is started. This is the DEFAULT mode.
  97.  
  98. GLOBAL_REFS     ( -- )
  99.         All local labels will be available across all following code
  100.         definitions. The label mechanism is NOT reset at the beginning
  101.         of a CODE definition, so a local label reference can cross CODE
  102.         word boundaries. The local label mechanism MUST be reset before
  103.         use in this mode, with the CLEAR_LABELS word.
  104.  
  105. CLEAR_LABELS    ( -- )
  106.         Clear the local label mechanism, to the unused or clean state,
  107.         in preparation for using local labels.  This word need only be
  108.         used in the GLOBAL_REFS mode. The LOCAL_REFS mode automatically
  109.         performs a CLEAR_LABELS each time a CODE definition is started.
  110.  
  111. A;              ( -- )
  112.         Complete the assembly of the previous machine instruction.
  113.  
  114. BYTE            ( -- )
  115.         Assemble current and subsequent code using byte arguments, if
  116.         register size is not explicitly specified in prefix mode. WORD
  117.         is default in postfix mode.
  118.  
  119. WORD            ( -- )
  120.         Assemble current and subsequent code using 16 bit arguments, if
  121.         register size is not explicitly specified in postfix mode. BYTE
  122.         is default in prefix mode.
  123.  
  124. LABEL           ( -- )
  125.         Start an assembly subroutine or mark the current code address to
  126.         be referenced later.
  127.  
  128.  
  129.  
  130.  
  131. Figure  8.1.    Comparison of assembly syntax
  132.  
  133.  
  134. PREFIX                  POSTFIX                 MASM
  135.  
  136. AAA                     AAA                     AAA
  137. ADC AX, SI              SI AX ADC               ADC AX,SI
  138. ADC DX, 0 [SI]          0 [SI] DX ADC           ADC DX,0[SI]
  139. ADC 2 [BX+SI], DI       DI 2 [BX+SI] ADC        ADC 2[BX][SI],DI
  140. ADC MEM BX              BX MEM #) ADC           ADC MEM,BX
  141. ADC AL, # 5             5 # AL ADC              ADC AL,5
  142. AND AX, BX              BX AX AND               AND AX,BX
  143. AND CX, MEM             CX MEM #) AND           AND CX,MEM
  144. AND DL, # 3             3 # DL AND              AND DL,3
  145. CALL NAME               NAME #) CALL            CALL NAME
  146. CALL FAR [] NAME        FAR [] NAME #) CALL     ?????
  147. CMP DX, BX              BX DX CMP               CMP DX,BX
  148. CMP 2 [BP], SI          SI 2 [BP] CMP           CMP [BP+2],SI
  149. DEC BP                  BP DEC                  DEC BP
  150. DEC MEM                 MEM DEC                 DEC MEM
  151. DEC 3 [SI]              3 [SI] DEC              DEC 3[SI]
  152. DIV CL                  CL DIV                  DIV CL
  153. DIV MEM                 MEM DIV                 DIV MEM
  154. IN PORT# WORD           WORD PORT# IN           IN AX,PORT#
  155. IN PORT#                PORT# IN                IN AL,PORT#
  156. IN AX, DX               DX AX IN                IN AX,DX
  157. INC MEM                 BYTE MEM INC            INC MEM BYTE
  158. INC MEM WORD            MEM #) INC              INC MEM WORD
  159. INT 16                  16 INT                  INT 16
  160. JA NAME                 NAME JA                 JA NAME
  161. JNBE NAME               NAME #) JNBE            JNBE NAME
  162. JMP NAME                NAME #) JMP             JMP
  163. JMP FAR [] NAME         NAME [] FAR JMP         JMP [NAME]
  164. JMP FAR $F000 $E987                             JMP F000:E987
  165. LODSW                   AX LODS                 LODS WORD
  166. LODSB                   AL LODS                 LODS BYTE
  167. LOOP NAME               NAME #) LOOP            LOOP NAME
  168. MOV DX, NAME            NAME #) DX MOV          MOV DX,[NAME]
  169. MOV AX, BX              BX AX MOV               MOV AX,BX
  170. MOV AH, AL              AL AH MOV               MOV AH,AL
  171. MOV BP, 0 [BX]          0 [BX] BP MOV           MOV BP,0[BX]
  172. MOV ES: BP, SI          ES: BP SI MOV           MOV ES:BP,SI
  173. MOVSW                   AX MOVS                 MOVS WORD
  174. POP DX                  DX POP                  POP DX
  175. POPF                    POPF                    POPF
  176. PUSH SI                 SI PUSH                 PUSH SI
  177. REP                     REP                     REP
  178. RET                     RET                     RET
  179. ROL AX, # 1             AX ROL                  ROL AX,1
  180. ROL AX, CL              AX CL ROL               ROL AX,CL
  181. SHL AX, # 1             AX SHL                  SHL AX,1
  182. XCHG AX, BP             BP AX XCHG              XCHG AX,BP
  183. XOR CX, DX              DX, CX XOR              XOR CX,DX
  184.  
  185.  
  186.  
  187. 8.3.    SYNTAX COMPARISON
  188.  
  189.  
  190. The differences among the F-PC prefix mode, the F83 postfix mode, and the
  191. Intel MASM notation are best illustrated by the table in Figure 8.1.
  192. Although the table is not exhaustive, it covers most of the cases useful
  193. in doing PASM programming.  You are welcome to suggest additional cases
  194. to be included in this table.
  195.  
  196.   8.4. USAGE OF 8086 MACHINE REGISTERS IN F-PC
  197.  
  198.  
  199. To write assembly code, you have to know the CPU real well.  Most CPU's
  200. can be understood and programmed using a CPU model, consisting of the
  201. register set and the instructions which manipulate data among the
  202. registers, memory, and external devices.  In F83, only a 64K bytes
  203. segment of memory is used, and all segment registers in 8086 are
  204. generally pointing to the same code segment.  Since F-PC uses many
  205. segments to store code, heads, lists, and other data, you have to know
  206. how these segment registers are used and how information in different
  207. segments can be accessed conveniently.
  208.  
  209. Following is a list of the 8086 registers and their usage in F-PC:
  210.  
  211.         CS      Code seg: used for any code definitions (Must be
  212.                 preserved by code word.)
  213.  
  214.         DS      Data seg: used for data other than ." strings (NOTE:
  215.                 CS=DS and underlying kernel primitives rely on this
  216.                 correspondence!  Must be preserved by code word.)
  217.  
  218.         ES      Extra seg: used as the segment location for the current
  219.                 instruction pointer (IP).  (Must be preserved by code
  220.                 word.)
  221.  
  222.         SS      Stack seg: used as the segment location for the current
  223.                 stack pointer (SP). (Must be preserved by code word.)
  224.  
  225.         BP      Return Pointer (RP).  (Must be preserved by code word.)
  226.  
  227.         SP      Stack Pointer (SP).  (Must be preserved by code word.)
  228.  
  229.         SI      Instruction Pointer (IP).  (Must be preserved by code
  230.                 word.)
  231.  
  232.         AX, BX, CX, DX, & DI    Scratch registers free to use without
  233.                                 restoration.
  234.  
  235.         PC      Program Counter.  Not used by F-PC.
  236.  
  237.         DF      Direction Flag.  Assumed to be 0/increment. Some older FF
  238.                 (or before?) words do an initial CLD (e.g., CMOVE), but
  239.                 this shouldn't be necessary. If you specifically need
  240.                 DF=1, then do:  STD ...code... CLD
  241.  
  242. AX is used as a general purpose accumulator.  BX is most useful as a base
  243. register for indexing into an array.  CX is used to hold a count for
  244. looping and repeating operations.  DX is useful in holding the address of
  245. an I/O port.  DS:SI pair is used to read memory with auto-indexing, and
  246. ES:DI pair is used to write memory with auto-indexing.
  247.  
  248. F-PC uses SP as the data stack pointer and BP as the return stack
  249. pointer.  SP is convenient in the PUSH and POP instructions, while BP is
  250. more convenient in indexing.  There are many occasions that you might
  251. want to swap SP and BP to use the most effective way to address data on
  252. either stack.
  253.  
  254. The F-PC Technical Reference Manual discusses in great details how F-PC
  255. itself is constructed based on the 8086 assembly code.  If you are
  256. interested in squeezing the last drop of blood from PC/XT/AT, be sure to
  257. study carefully  the Technical Reference Manual and the kernel files in
  258. F- PC.
  259.  
  260.  
  261. 8.5.    ADDRESSING MODES
  262.  
  263.  
  264. The most difficult problem in using 8086 assembler is to figure out the
  265. correct addressing mode and code it into an instruction.  You can get a
  266. good ideal and probably figure out most of the addressing mode syntax
  267. from the above table.  However, there are cases where the table falls
  268. short.  Here we will try to summarize the addressing syntax more
  269. systematically to show you how F-PC handles addresses in the prefix mode.
  270.  
  271. Register Mode
  272.  
  273. Source or destination is a register in the CPU.  The source registers
  274. are:
  275.  
  276.         AL  BL  CL  DL  AH  BH  CH  DH
  277.         AX  BX  CX  DX  SP  BP  SI  DI  IP  RP  CS  DS  SS  ES
  278.  
  279. Destination register specifications are:
  280.  
  281.         AL, BL, CL, DL, AH, BH, CH, DH,
  282.         AX, BX, CX, DX, SP, BP, SI, DI, IP, RP, CS, DS, SS, ES,
  283.  
  284. The register name must be followed by a 'comma', to be recognized by PASM
  285. as a destination register.
  286.  
  287. Immediate Mode
  288.  
  289. The argument is assembled as a literal in the instruction.  The immediate
  290. value must be preceded by the symbol #, which is a word and must be
  291. delimited by spaces:
  292.  
  293.         MOV     AX, # 1234
  294.         ADD  CL, # 32
  295.         ROL     AX, # 3
  296.  
  297. Direct Mode
  298.  
  299. An address is assembled into the instruction.  This is used to specify an
  300. address to be jumped to or a memory location for data reference.  The
  301. address is used directly as a 16 bit number.  Depending on the
  302. instruction, the address may be assembled unmodified or assembled as an
  303. eight or 16 bit offset in the branch instructions.  To jump or call
  304. beyond a 64K byte segment, the address must be preceded by FAR [] .
  305. Examples are:
  306.  
  307.         CALL    FAR [] <label>
  308.         JMP     <dest>
  309.         MOV     BX, <source>
  310.         INC     <dest> WORD
  311.         JZ      <label>
  312.  
  313. The destination address may be taken from the data stack directly:
  314.  
  315.         MOV     CX, # 16
  316.         HERE            ( save current code address on stack) ...
  317.         ... LOOPZ       ( loop back to HERE if condition fails)
  318.  
  319. Index Mode
  320.  
  321. One or two registers can be used as index registers to scan through data
  322. arrays.  The contents of the index register or the sum of the contents of
  323. two index registers are used to form a base address. An offset is added
  324. to the base address to form the true address for data reference.
  325. Examples are:
  326.  
  327.         CMP     2 [BP], SI
  328.         DEC  3 [SI]
  329.         MOV     BP, 0 [BX]
  330.  
  331. The following register index specifications are allowed in F-PC:
  332.  
  333.         [SI]  [IP]  [BP]  [RP]  [DI]  [BX]
  334.         [BX+SI]  [SI+BX]  [BX+IP]  [IP+BX]  [BX+DI]  [DI+BX]
  335.         [BP+SI]  [SI+BP]  [BP+IP]  [IP+BP]  [RP+IP]  [IP+RP]
  336.         [BP+DI]  [DI+BP]  [RP+DI]  [DI+RP]
  337.  
  338. There must be an offset number preceding the index register
  339. specification, even if the offset is 0. When the index register is used
  340. as destination, a comma must be appended immediately:
  341.  
  342.         MOV     0 [BX+IP], AX
  343.  
  344. Implied Mode and Segment Override
  345.  
  346. The implied mode is where mistakes are most likely to occur because you
  347. will have to be keenly aware of which segment register is used by the
  348. instruction at any instance.  Since the segment register is implied and
  349. not stated explicitly, the bug generally can hide very securely
  350. underneath laughing at you.  The code works when you test it but fails
  351. when the segment register is modified.
  352.  
  353.         Branch and jump instructions use CS segment register.
  354.         Data movement instructions use DS segment register.
  355.         Stack instructions use SS segment.
  356.         String instructions use DS:SI as source and ES:DI as destination.
  357.  
  358. If you need to specify an address with a segment register other than the
  359. default implied register, use a segment override instruction before the
  360. address specification:
  361.  
  362.         CS:   DS:  ES:
  363.  
  364. Examples are:
  365.  
  366.         MOV     ES: BP, SI
  367.         CMP     CS: 2 [BP], AX
  368.         ADD     AX, ES: 10 [BX+DI]
  369.  
  370. The 8086 addressing modes are so confusing that even experienced
  371. programmers need a good Intel 8086 manual to find the right addressing
  372. mode and the F-PC assembler syntax table to determine the correct
  373. argument list.
  374.  
  375. The best way to write assembly code is still to keep the code short and
  376. simple.  It is very easy in F- PC to break a long CODE definition into
  377. many small fragments which are initially defined as separate CODE
  378. definitions.  After verifying that each fragment works, you can edit out
  379. the CODE, NEXT, and END-CODE lines to combine the fragments into a single
  380. CODE definition.
  381.  
  382. Charles Curley kindly contributed an 8086 disassembler.  It is helpful to
  383. disassemble the code word you defined and see what the computer thinks of
  384. what you mean.  There is always this 'Do what I mean, not what I say'
  385. syndrome.  When everything else has failed, you can jump into DOS and
  386. call up DEBUG and use the facility there to find what goes wrong.  In DOS
  387. DEBUG, you can step through a piece of code one instruction at a time.
  388. This is absolutely the last thing you want to do.
  389.  
  390.  
  391. 8.6.    ASSEMBLY MACROS IN PASM
  392.  
  393.  
  394. Another area of interest is the assembly macros.  Here is the definition
  395. of the NEXT macro:
  396.  
  397.         : NEXT  >PRE    JMP >NEXT A;    PRE> ;
  398.  
  399. The macro itself is simply assembling the sequence JMP >NEXT.  The
  400. surrounding words are used for support.  Since PASM supports both postfix
  401. as well as prefix notation, it is not known on entry to a macro which
  402. mode is in effect.  The words >PRE and PRE> select prefix, and restore
  403. the previous mode so macros will always be in prefix notation.  The A;
  404. after >NEXT, forces the assembling of the JMP instruction before
  405. switching mode.
  406.  
  407. You can find many other examples of assembly macros in PASM.SEQ,  like
  408. 1PUSH, 2PUSH, and all the assembly structure building directives.
  409.  
  410.  
  411. 8.7.    LOCAL LABEL
  412.  
  413.  
  414. To support large code definitions, Bob Smith introduced 'local labels' to
  415. F-PC.  The local labels are place markers $: preceded by a number.  They
  416. are used to mark locations in a large code definition for forward and
  417. backward jumps and branches which uses $ preceded by the number of the
  418. local label as address specification.  They can be used quite freely in a
  419. range of code words and reused to save head space by replacing LABELs
  420. which have global names and cannot be reused.
  421.  
  422. The use of local labels is best demonstrated by an example taken from the
  423. software floating point package SFLOAT.SEQ by Bob Smith, shown in Figure
  424. 8.2.  Up to 32 local labels can be used to mark addresses of assembly
  425. code.  They can be referred to before or after their placements.  They
  426. can be referenced across code word boundaries.
  427.  
  428. Local labels in PASM are useful within a CODE definition, using
  429. LOCAL_REFS as the default label mode. If you need to use local labels
  430. between CODE definitions, you will have to select the GLOBAL_REFS mode,
  431. and use CLEAR_LABELS to initialize the local labels manually each time
  432. you want to start a new set of local labels.
  433.  
  434. This technique is especially useful where the one-entry-one-exit dogma is
  435. very awkward and when a piece of code has multiple entry points and can
  436. be shared among many code word definitions.  It enables us to construct
  437. structured spaghetti code, if there were such thing.
  438.  
  439. Local label allows relative short branches within 127 bytes.  To jump
  440. beyond this range, the long jump label L$ should be used:
  441.  
  442.                 ...
  443.                 ...
  444.                 JMP     L$
  445.                 ...
  446.                 ...
  447.         L$:     ...
  448.                 ...
  449.  
  450. The long jump label can only be used to jump forward.  After L$: is used,
  451. you can do another long forward jump using L$ again.
  452.  
  453.  
  454.  
  455. 8.8.    INLINE CODE
  456.  
  457.  
  458.  
  459. INLINE allows us to include machine code inside a high level colon
  460. definition.  This is easily done in F-PC because it is built on direct
  461. threaded code.  Every word is compiled as a code address in the colon
  462. definition.  The code in the code segment pointed to by the code address
  463. is executed directly because it contains genuine 8086 machine code.
  464. Whether the code belongs to a colon definition or a code definition does
  465. not make any difference.  INLINE only has to compile the address pointing
  466. to the top of the dictionary in the code segment.  The assembler is then
  467. invoked to compile machine code.  If the code is terminated by NEXT or
  468. one of its derivatives, the next word compiled in the colon definition
  469. will be executed after the assembly code is done.  END-INLINE only has to
  470. clean up the assembly environment and return the control back to the
  471. colon compiler.
  472.  
  473. Here is an example on how to use INLINE and END-INLINE to add assembly
  474. code in the middle of a colon definition:
  475.  
  476.         : TEST ( -- )
  477.                 5 0 DO
  478.                         I                       \ Get loop index
  479.                         INLINE
  480.                                 pop ax          \ pop I
  481.                                 add ax, # 23    \ add 23
  482.                                 1push           \ push sum
  483.                         END-INLINE
  484.                         .                       \ print results
  485.                 LOOP
  486.                 ;
  487.  
  488.  
  489. Figure  8.2.    Examples of local labels
  490.  
  491. LABEL DENORM    \ CX = count, BX = Hi, DX = LO, AX = Guard, Round, & Sticky.
  492.         CLEAR_LABELS
  493.         XOR     AX, AX          \ Clear GRS bits
  494.         CMP     CX, # 10        \ Check size of shift
  495.         JL      7 $             \ Branch if shift less than 16
  496.         CMP     CX, # 18        \ Cnt >= 16.  Compare with 24.
  497.         JGE     1 $             \ Branch if shift >= 24
  498.         SUB     CX, # 10        \ 16 <= cnt < 24.  Subtract 16 from cnt.
  499.         MOV     AX, DX          \ Shift by one word.
  500.         MOV     DX, BX
  501.         XOR     BX, BX          \ Clear MS word.
  502.         AND     AL, AL          \ Don't miss any sticky bits.
  503.         JZ      8 $
  504.         OR      AH, # 2         \ Set a sticky bit.
  505.         JMP     8 $             \ Shift from 0 to 7 bits.
  506. 1 $:    CMP     CX, # 20        \ Cnt >= 24.  Compare with 32.
  507.         JGE     3 $             \ Branch if shift >= 32.
  508.         MOV     AH, BL          \ 24 <= cnt < 32, so shift by 3 bytes.
  509.         MOV     AL, DH
  510.         OR      AL, DL          \ OR in the sticky bits.
  511.         JZ      2 $             \ Shall we set a sticky bit?
  512.         OR      AH, # 2         \ Yes.
  513. 2 $:    MOV     DL, BH          \ Continue the 3-byte shift.
  514.         XOR     DH, DH          \ Clear the high 3 bytes.
  515.         XOR     BX, BX
  516.         SUB     CX, # 18        \ Adjust the shift counter.
  517.         JMP     8 $             \ Shift remaining 0 to 7 places.
  518. 3 $:    CMP     CX, # 28        \ Cnt >= 32.  Check against 40.
  519.         JGE     5 $             \ Branch if shift count > 40.
  520.         MOV     AX, BX          \ 32 <= cnt < 40.  Do a 2 word shift.
  521.         OR      AL, DH          \ Check the sticky bits.
  522.         OR      AL, DL
  523.         JZ      4 $             \ If sticky byte not zero,
  524.         OR      AH, # 2         \  then set sticky bit.
  525. 4 $:    XOR     BX, BX          \ Clear high and low words.
  526.         XOR     DX, DX
  527.         SUB     CX, # 20        \ Adjust shift counter.
  528.         JMP     8 $             \ Go to final shift area.
  529. 5 $:    OR      BX, DX          \ Shift count >= 40
  530.         JZ      0A $            \ In theory, this should never jump.
  531.         MOV     AH, # 2         \ So set a sticky bit.
  532.         XOR     BX, BX          \ Clear all the rest.
  533.         XOR     DX, DX
  534.         RET
  535. 7 $:    CMP     CX, # 8         \ Count < 16.  See if less than 8.
  536.         JL      8 $
  537.         MOV     AH, DL          \ 8 <= cnt < 16.
  538.         MOV     DL, DH          \ Move by one byte.
  539.         MOV     DH, BL
  540.         MOV     BL, BH
  541.         XOR     BH, BH          \ Clear high byte.
  542.         SUB     CX, # 8         \ Adjust shift count.
  543. 8 $:    AND     CX, CX          \ Test for zero count.
  544.         JZ      0A $
  545. 9 $:    SHR     BX, # 1         \ Shift right by one bit.
  546.         RCR     DX, # 1
  547.         RCR     AX, # 1
  548.         LOOP    9 $             \ Loop until count is 0.
  549. 0A $:   RET
  550.         END-CODE
  551.  
  552.  
  553.  
  554. 8.9.    ASSEMBLER STYLE
  555.  
  556.  
  557.  
  558. To code 80x86 assembly routines successfully, you have to pay attention
  559. to many things simultaneously, making it very exciting and interesting
  560. occasionally, but frustrating most of the time.  To make it easier for
  561. yourself, you can follow the following coding style to avoid the most
  562. serious pitfalls in writing assembly code:
  563.  
  564. code gizzmo ( input1 input2 input3 ... -- output1 output2 ...)
  565.  
  566.         pop     ax              \ input section
  567.         pop     bx              \ pop everything into registers
  568.         pop     cx
  569.         ...
  570.  
  571.         push    si              \ saving section
  572.         push ds         \ save all registers you will use
  573.         push es
  574.         push cs
  575.  
  576.         ...                     \ code body
  577.         ...                     \ do your creative coding
  578.         ...
  579.  
  580.         pop     cs              \ restoring section
  581.         pop     es              \ restore all saved registers
  582.         pop     ds
  583.         pop     si
  584.  
  585.         push    cx              \ output section
  586.         push dx         \ 2push
  587.         push ax         \ 1push
  588.         next
  589.  
  590.         end-code                \ you can breath now
  591.  
  592. Make a boiler plate code template and delete whatever is not needed.
  593. This style sheet will save you lots of grief if you follow it
  594. religiously, with a prayer, some incense, and a bottle of aspirins.
  595.  
  596. The 8086 registers have their special characteristics.  Counts should be
  597. popped into CX, data into AX or DX, and addresses into BX.  For string
  598. operations, DS:SI is used for source and ES:DI for destination.  Because
  599. F-PC uses ES:SI as its IP, they must be saved and restored.  You should
  600. also constantly remind yourself that F-PC requires that CS, DS, and SS
  601. all point to the Code Segment, and that ES points to the List Segment.
  602. If you do not restore them to this state, NEXT will certainly crash the
  603. system to verify the fact.  However, you should not fear crashing the
  604. system.  It is the daily portion which keeps a Forth programmer alert and
  605. nourished.  It also helps to remind the computer who is the master lest
  606. it forgets, which it often does.
  607.  
  608.  
  609. 8.10.   DEBUGGING CODE WORDS
  610.  
  611.  
  612. Debugging large code words is very difficult.  You are encouraged to
  613. avoid writing large code words for this reason.  The best way to optimize
  614. your  Forth application is first writing everything in high level colon
  615. words.  After you have debugged the application and have a working
  616. system, examine the colon words carefully to identify the 'critical
  617. routines' where the computer spends most of its time.  Only these
  618. routines need to be converted to code words.
  619.  
  620. If a critical routine is a long colon definition, try to break it into
  621. small pieces which can be conveniently converted to code words.  If the
  622. code words are small, coding and testing them will be easy.  If you have
  623. to build a large code word, code it in small pieces anyway.  It is easy
  624. to merge small code words into a large code word.
  625.  
  626. If you take every precaution in writing a code word but it still fails to
  627. work, you have a last chance. Because F-PC has the capability to spawn a
  628. DOS shell, using the command SYS and ` (back tick), you can invoke the
  629. DEBUG program in DOS to step through a code word.  For example, if you
  630. want to debug the code word GIZZMO, load and assemble it into your
  631. dictionary and execute:
  632.  
  633.         '  GIZZMO  HEX  U.
  634.  
  635. to find its address in the dictionary.  You can find the code segment of
  636. your dictionary by
  637.  
  638.         ?CS:  U.
  639.  
  640. Write these numbers on a piece of paper so that you can find the code
  641. after you are in DOS DEBUG.  To invoke DOS DEBUG, type:
  642.  
  643.         SYS  DEBUG      or      `  DEBUG
  644.  
  645. You have to make sure that you have COMMAND.COM and DEBUG.COM in your
  646. current directory or in the PATH before you execute the SYS word.  If
  647. these files are accessible, you will see the DEBUG prompt '-'.  Now you
  648. can use the DEBUG commands to set up registers, disassemble code to see
  649. if the code was assembled correctly, and also step through the code one
  650. instruction at a time.  Go find and dust off your DOS manual.
  651.  
  652. The only other thing you have to be careful about is that DEBUG
  653. initializes the segment registers, the stack pointers, and the CPU
  654. registers in its own way, very different from the way F-PC sets them up.
  655. You must initialize all the registers used by F-PC correctly.  If GISSMO
  656. needs parameters from the data stack, you must push them on the data
  657. stack before stepping through GIZZMO.
  658.  
  659. DEBUG does not  provide the most  friendly  interface to its user.  You
  660. have to be prepared to pay the price before dipping into assembly coding.
  661. Try to minimize the pain by staying in the friendly environment in F-PC
  662. as long as possible, where the interpreter, the compiler, the editor, and
  663. the high level debugger are ready and eager to render their best
  664. services.
  665.  
  666.